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

时间:2018-03-29 13:20:04

标签: python linear-programming pulp

背景:

这是一个非常简单的脚本,希望实现以下目标:

  1. 有关四个项目的列表,每个项目都有一个需求
  2. 对于这些项目中的每一项,有四家供应商对这四项中的每一项都有不同的价格和数量以及固定运费
  3. 每次结账时只发送一次,无论从供应商订购的商品数量是多少(如果从该供应商处订购任何商品,将不会收取运费)
  4. 到目前为止,我已经完成了从没有发货的地方返回最低成本和订购内容的细分。

    我目前仍然坚持如何在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))
    

1 个答案:

答案 0 :(得分:1)

我认为你只需要添加含义

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

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

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

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

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