根据另一个变量的值触发一个二元变量

Triggering a Binary Variable based on the values of another Variable

背景:

这是一个相当简单的脚本,旨在实现以下目标:

  1. 对于包含四个项目的列表,每个项目都有一个需求
  2. 对于这四件商品,有四家供应商对这四件商品的价格和数量各不相同,而且运费是固定的
  3. 无论从供应商处订购的商品数量如何,每次结帐时只添加一次运费(尽管如果没有从该供应商处订购任何商品,则不会收取运费)

到目前为止,我已经退回了最低成本和从哪里订购的商品的明细,无需运送。

我目前卡在如何在 SUM(VendorVar[x]{0:1} * ShippingData[x]) 部分工作,因为如果我从中订购的商品数量,我基本上需要一种方法将二进制值切换为 ON/1卖家是 > 0

from pulp import *

items = ["Item1", "Item2", "Item3", "Item4"]
vendors = ["Vendor1", "Vendor2", "Vendor3", "Vendor4"]

# List containing lists for each Vendor and their Item costs for Item1, Item2, Item3, Item4 respectively:           
costData = [[1.00,5.00,10.00,0.15],
            [1.50,2.50,5.00,0.25],
            [0.50,1.00,15.00,0.50],
            [1.75,10.00,2.00,0.10]]

# List containing lists for each Vendor and their Supply for Item1, Item2, Item3, Item4 respectively:
supplyData = [[0,2,4,1],
                [4,0,1,4],
                [1,1,1,1],
                [8,8,8,8]]

# Created nested dictionaries per Item per Vendor for Costs: {Item1: {Vendor1:Cost, Vendor2:Cost...}}   
vendoritemcosts = makeDict([items,vendors],costData)

# Created nested dictionaries per Item per Vendor for Supply: {Item1: {Vendor1:Supply, Vendor2:Supply...}}  
vendoritemsupply = makeDict([items,vendors],supplyData)

# Shipping costs per Vendor:
shippingData = {"Vendor1":0.99,
                "Vendor2":1.99,
                "Vendor3":0.00,
                "Vendor4":2.99}

# Number of items desired:              
demand = {"Item1":4,
            "Item2":4,
            "Item3":4,
            "Item4":8}

# Number of items to purchase for each Vendor/Item combination:                     
vendoritemvar = LpVariable.dicts("item",(items,vendors),0,None,LpInteger)

# Binary flag that (hopefully) will determine if a Vendor is included in the final optimized formula or not:
vendorvar = LpVariable.dicts("vendor",vendors,0,1,LpBinary)

prob = LpProblem("cart",LpMinimize)

# Objective Function: Take the sum of quantity ordered of each unique Vendor+Item combination multiplied by its price
# For every Vendor included in the list, multiple {0:1} to their shipping costs, with 1 being used if they have any items in the first portion of the function above
prob += lpSum([vendoritemvar[a][b] * vendoritemcosts[a][b] for a in vendoritemvar for b in vendoritemvar[a]]) \
        + lpSum(vendorvar[c] * shippingData[c] for c in vendorvar)

for a in vendoritemvar:
    # Sum total of each item must equal Demand
    prob += lpSum(vendoritemvar[a]) == demand[a]
    # Currently testing minimum checkout values which will be a future addition that isn't a fixed value:
    prob += lpSum(vendoritemvar[a][b] * vendoritemcosts[a][b] for b in vendoritemvar[a]) >= 2.00
    for b in vendoritemvar[a]:
        # Non-negativity constraint
        prob += vendoritemvar[a][b] >= 0
        # Can't exceed available supply
        prob += vendoritemvar[a][b] <= vendoritemsupply[a][b]


prob.solve()

print("Status: %s" % LpStatus[prob.status])
for v in prob.variables():
    print("%s = %s" % (v.name,v.varValue))
print("Total cart = %s" % value(prob.objective))

我觉得你只要加上蕴涵就可以了

vendorvar[v] = 0  => vendoritemvar[i,v] = 0

这可以用 big-M 约束建模:

vendoritemvar[i,v] ≤ M * vendorvar[v]

可以从 supplyData/vendoritemsupply 表中得出 M 的良好值:

vendoritemvar[i,v] ≤ vendoritemsupply[i,v] * vendorvar[v]