I have to minimize the inventory remaining at end of the period(28 days). Each item would perish after a fixed number of days and we can order items only on certain weekdays(M,T,S,S). Demand is allowed not to be met if not possible. but no stockout situation. The inventory continuity constraint is giving infeasibility to me because of situations when all inventory has perished on a day, we can't order on the same day also so ending inventory equals demand and is conflicting with other equations, how to model the situation when demand may or may not be met? Below is the code. Days are from 241-269. Day 240 is the day of initial on-hand availability. Inv can be continuous but order qty is integer.
Here is formulation:
item=[1...10], days=[241...269]
dvar's --> x(i,d) {Binary} y(i,d) {Integer purchase qty.} I(i,d) {Continuous, >0 inventory at EOD}
Min: lpSum over i,d (I(i,d) if d==269)
s.t. C_1 : x(i,d)=0 if d in {Mon,Thu,Sat,Sun}
C_2 : I(i,d)= On-hand inv at beginning of period(data given) if d=240
C_3 : for all days 80 <= lpSum over i (y(i,d)) <=150
C_4 : I(i,d+s)] <= (1-x(i,d))*M
(Inventory to be salvaged if shelf life days are passed, s is shelf days for each item)
C_5 : y(i,d)<= M*x(i,d)
C_6 : for all i,d
if demand_forcast(i,d) >= I(i,d-1):
I(i,d) == y(i,d)
else:
I(i,d) = I(i,d-1) + y(i,d) -demand_forcast(i,d)
And here is python code:
item = demand['item_code'].unique()
days = range(240,270,1)
item_days = [(i,d) for i in item for d in days]
dmd_forecast = demand.set_index(['item_code','doy']).forecast_quantity.to_dict()
onhand_qty = onhand.set_index(['item_code','doy']).onhand_quantity.to_dict()
no_order = no_purchase_days.set_index(['item_code','doy']).delivery.to_dict() ## list of item-days for no order
shelf_days = shelf_life.set_index(['item_code']).item_shelf_life.to_dict()
#------------------------------------------
prob = LpProblem("Min_wastage",LpMinimize)
x = LpVariable.dicts("Order-y-n",item_days, cat="Binary") ## x at 240 also to be set zero
y = LpVariable.dicts("Order-Qty",item_days,lowBound = 0, cat="Integer")
I = LpVariable.dicts("EOD_Inv",item_days, lowBound = 0, cat="Continuous")
# objective function
## Minimize the inventory left at end of period of 29 days
prob += (
lpSum(I[(i,d)] for i in item for d in days if d == 269 )
)
## Constraint 1: No Delivery on Mon, Thu, Sat, Sun
for i in no_order:
prob += (
y[i] == 0
)
## Also At time period 240 no order
for i in item:
for d in days:
if d==240:
prob += (
y[(i,d)] == 0
)
## Constraint 2: Fix on hand inventory values at start of period, start of day
for i in onhand_qty:
prob += (
I[i] == onhand_qty[i]
)
## Constraint 3 : Inv-continuity Equation
for i in item:
for d in days:
if d>=241:
if dmd_forecast[(i,d)] >= I[(i,d-1)]:
prob += (
I[(i,d)] == dmd_forecast[(i,d)]- I[(i,d-1)] + y[(i,d)]
)
else:
prob += (
I[(i,d)] == I[(i,d-1)] + y[(i,d)] - dmd_forecast[(i,d)]
)
## Constraint 5: Inventory to be salvaged if shelf life days are passed.
## 250 as max. shelf days over all items is 19 days. Also this constraint needs to be written in better way for each item.
for i in item:
for d in days:
if d <= 260:
prob += (
I[(i,d+shelf_days[i])] <= (1-x[(i,d)])*1000
)
## Constraint 6: if x is 1, the order can placed y > 0, 170 is the value of Big-M, when y is zero... x is forced zero.
for i in item:
for d in days:
prob += (
x[(i,d)] <= y[(i,d)]
)