设置最低购买限额——及时

问题描述 投票:0回答:1

我正在尝试计算及时购买量。这似乎工作得很好,但我想要

  • 最少购买5个。
  • 最少库存3件。

不幸的是,这个代码确保我每个月都会购买,而且我只想在某些时间购买。我该如何解决这个问题?

model=ConcreteModel(name='Inventory-MIN')
demand=[4,3,2,1,2,3,4]
months=len(demand)

holding_cost=1

purchase_cost=2

model.purchase_qty=Var(range(months), domain=NonNegativeIntegers) # Not NonNegativeReals

# ending quantity of inventory per month
model.end_inventory=Var(range(months), domain=NonNegativeIntegers)

model.cost=Objective(expr=sum(
    model.purchase_qty[month]* # Purchase quantity
    purchase_cost+ # Purchase price
    model.end_inventory[month]* # previous inventory
    holding_cost # Holding cost
    for month in range(1,months,1)), sense=minimize) # start at 1, stop at months, iterate by 1

model.constraints=ConstraintList() # empty list of constraints

model.constraints.add(model.end_inventory[0] == 0)

for month in range(1,months,1):
  next_end_inventory = model.end_inventory[month-1]+model.purchase_qty[month]-demand[month]
  model.constraints.add(model.end_inventory[month] == next_end_inventory)
  # here is where we define a minimum inventory level
  model.constraints.add(model.end_inventory[month]>=3)
  # must buy in bulk
  model.constraints.add(model.purchase_qty[month]>=5) # none of the months have ZERO ORDER !??!?!?!?
# Solve the model
SolverFactory('glpk',executable='/usr/bin/glpsol').solve(model).write()

我明白了,显然 16 个库存太多了。

# How much we purchase every month
purchase_qty : Size=7, Index=purchase_qty_index
    Key : Lower : Value : Upper : Fixed : Stale : Domain
      0 :     0 :  None :  None : False :  True : NonNegativeIntegers
      1 :     0 :   6.0 :  None : False : False : NonNegativeIntegers
      2 :     0 :   5.0 :  None : False : False : NonNegativeIntegers
      3 :     0 :   5.0 :  None : False : False : NonNegativeIntegers
      4 :     0 :   5.0 :  None : False : False : NonNegativeIntegers
      5 :     0 :   5.0 :  None : False : False : NonNegativeIntegers
      6 :     0 :   5.0 :  None : False : False : NonNegativeIntegers
#
# Inventory at end of month
end_inventory : Size=7, Index=end_inventory_index
    Key : Lower : Value : Upper : Fixed : Stale : Domain
      0 :     0 :   0.0 :  None : False : False : NonNegativeIntegers
      1 :     0 :   3.0 :  None : False : False : NonNegativeIntegers
      2 :     0 :   6.0 :  None : False : False : NonNegativeIntegers
      3 :     0 :  10.0 :  None : False : False : NonNegativeIntegers
      4 :     0 :  13.0 :  None : False : False : NonNegativeIntegers
      5 :     0 :  15.0 :  None : False : False : NonNegativeIntegers
      6 :     0 :  16.0 :  None : False : False : NonNegativeIntegers

我尝试将关键约束放入 if 函数中,但收到此错误:

Cannot convert non-constant Pyomo expression (%s) to bool.
pyomo inventory inventory-management
1个回答
0
投票

您走在正确的道路上。这里有一些修复...

您缺少的主要概念是“半连续变量”,这意味着它要么为零,要么在某个范围内。这可以通过“big-M”类型的约束来完成(如下所示)。 (谷歌搜索或查看任何 LP 教科书)

我还对您的目标和约束中的 0 个月逻辑进行了一些更改。在 obj 中,您仍然需要包含第一个月以捕获当月的购买成本。

代码:

from pyomo.environ import *

model=ConcreteModel(name='Inventory-MIN')
demand=[4,3,2,1,2,3,4]
months=len(demand)

holding_cost=1

purchase_cost=2

max_purchase = 50 # some sufficiently large number (big M)

# SETS
model.months = Set(initialize=range(months))

# PARAMS
model.demand = Param(model.months, initialize={m:d for m, d in enumerate(demand)})
model.purchase_cost = Param(model.months, initialize={m: 2 for m in model.months})
model.holding_cost = Param(model.months, initialize={m: 1 for m in model.months})

# VARS
model.make_purchase = Var(model.months, domain=Binary)
model.purchase_qty=Var(model.months, domain=NonNegativeIntegers) # Not NonNegativeReals
# ending quantity of inventory per month
model.end_inventory=Var(model.months, domain=NonNegativeIntegers)

# start at zero...  must pay for purchases, and end inventory is already held at zero, so no holding costs
model.cost=Objective(expr=sum(
    model.purchase_qty[month] * # Purchase quantity
    model.purchase_cost[month] + # Purchase price
    model.end_inventory[month] * # previous inventory
    model.holding_cost[month] # Holding cost
    for month in model.months), sense=minimize)

model.constraints=ConstraintList() # empty list of constraints

for month in model.months:
  if month == model.months.first():
    # handle the first end-of-month inventory separately
    model.constraints.add(model.end_inventory[month] == model.purchase_qty[month] - demand[month])
  else:  # handle the end-of-month inventory relative to prior...
    next_end_inventory = model.end_inventory[month-1] + model.purchase_qty[month] - demand[month]
    model.constraints.add(model.end_inventory[month] == next_end_inventory)
  # here is where we define a minimum inventory level
  model.constraints.add(model.end_inventory[month] >=3 )
  # must buy in bulk
  model.constraints.add(model.purchase_qty[month] >= 5 * model.make_purchase[month])
  model.constraints.add(model.purchase_qty[month] <= max_purchase * model.make_purchase[month])
# Solve the model
# SolverFactory('glpk',executable='/usr/bin/glpsol').solve(model).write()
solver = SolverFactory('cbc')
res = solver.solve(model)
print(res)
model.purchase_qty.display()
model.end_inventory.display()

(截断)输出:

purchase_qty : Size=7, Index=months
    Key : Lower : Value : Upper : Fixed : Stale : Domain
      0 :     0 :   7.0 :  None : False : False : NonNegativeIntegers
      1 :     0 :   6.0 :  None : False : False : NonNegativeIntegers
      2 :     0 :   0.0 :  None : False : False : NonNegativeIntegers
      3 :     0 :   0.0 :  None : False : False : NonNegativeIntegers
      4 :     0 :   5.0 :  None : False : False : NonNegativeIntegers
      5 :     0 :   0.0 :  None : False : False : NonNegativeIntegers
      6 :     0 :   5.0 :  None : False : False : NonNegativeIntegers
end_inventory : Size=7, Index=months
    Key : Lower : Value : Upper : Fixed : Stale : Domain
      0 :     0 :   3.0 :  None : False : False : NonNegativeIntegers
      1 :     0 :   6.0 :  None : False : False : NonNegativeIntegers
      2 :     0 :   4.0 :  None : False : False : NonNegativeIntegers
      3 :     0 :   3.0 :  None : False : False : NonNegativeIntegers
      4 :     0 :   6.0 :  None : False : False : NonNegativeIntegers
      5 :     0 :   3.0 :  None : False : False : NonNegativeIntegers
      6 :     0 :   4.0 :  None : False : False : NonNegativeIntegers
[Finished in 314ms]
© www.soinside.com 2019 - 2024. All rights reserved.