简体   繁体   English

在商品贸易问题中错误指定 puLP 中的某些内容(混合整数规划)

[英]Misspecifying something in puLP in trading goods problem (mixed integer programming)

I'm struggling to understand what I'm doing wrong in a toy optimization problem (mixed integer programming).我正在努力理解我在玩具优化问题(混合整数规划)中做错了什么。

Let's say we have three people with different numbers of some good.假设我们有三个人,他们拥有不同数量的商品。 They currently have 10, 0, and 50 units of it, respectively.他们目前分别拥有 10、0 和 50 个单位。 They NEED 15, 0, and 46 units, respectively, and I'm trying to use puLP to come up with the optimal transfers between the people to minimize unmet need (NEED - SUPPLY AFTER REDISTRIBUTING) for all three people.他们分别需要 15、0 和 46 个单位,我正在尝试使用 puLP 提出人们之间的最佳转移,以最大限度地减少所有三个人的未满足需求(需求 - 重新分配后的供应)。

A trivial solution here could be that person 3 could give person 1 a total of 4 units, so that the supplies after redistributing become 14, 0, 46, and now person 1 only has one unit of unmet need (they want 15 units).这里一个简单的解决方案可能是,人 3 可以给人 1 总共 4 个单位,这样重新分配后的供应变为 14、0、46 个,而现在人 1 只有一个单位未满足的需求(他们想要 15 个单位)。

When I run the following puLP code I get the result that person 1 should give person 2 10 units, and that person 3 should give person 1 50 units.当我运行以下 puLP 代码时,我得到的结果是,人 1 应该给人 2 10 个单位,而人 3 应该给人 1 50 个单位。

Clearly I'm doing something wrong, could you help point out my mistake?显然我做错了什么,你能帮我指出我的错误吗?

I didn't use loops or list comprehensions because I wanted to make everything super explicit and clear to find my mistake.我没有使用循环或列表推导式,因为我想让一切都变得非常明确和清晰,以找出我的错误。 The only constraints I have are that people can't give away more units than then currently have.我唯一的限制是人们不能赠送比目前更多的单位。

Thanks!谢谢!

from pulp import *
import pandas as pd


# Creates a list of the unique people
people = ['1','2','3']

# Creates a dictionary for the number of units of units currently in supply
current = {
    '1': 10,
    '2': 0,
    '3': 50
}

# Creates a dictionary for the number of units needed
need = {
    '1': 15,
    '2': 0,
    '3': 46
}


# Creates the prob variable to contain the problem data
prob = LpProblem("Goods redistribution problem", LpMinimize)

# Creates a list of tuples containing all the possible trades
Routes = [(s,t) for s in people for t in people]

# Remove any tuples that are self trades
Routes = [element for element in Routes if (element[0] != element[1])]


# A dictionary called route_vars is created to contain the referenced variables (the routes)
# Make sure there isn't a route to itself
route_vars = {
'1': {'2': LpVariable("1_2",0,None,LpInteger), '3': LpVariable("1_3",0,None,LpInteger)},
'2': {'1': LpVariable("2_1",0,None,LpInteger), '3': LpVariable("2_3",0,None,LpInteger)},
'3': {'1': LpVariable("3_1",0,None,LpInteger), '2': LpVariable("3_2",0,None,LpInteger)}
}


# The objective function is added to prob first
#prob += lpSum([(need[t] - (current[s] + route_vars[t][s])) for (s,t) in Routes]), "Sum of unmet need after trading"
prob += (need['1'] - (current['1'] + route_vars['2']['1'] + route_vars['3']['1'])) \
    + (need['2'] - (current['2'] + route_vars['1']['2'] + route_vars['3']['2'])) \
    + (need['3'] - (current['3'] + route_vars['1']['3'] + route_vars['2']['3'])), "Sum of unmet need after trading"


# The amount each source trades cannot exceed the amount they currently have
prob += (route_vars['1']['2'] + route_vars['1']['3']) <= current['1'], f"Can't trade more than current inventory for person 1"
prob += (route_vars['2']['1'] + route_vars['2']['3']) <= current['2'], f"Can't trade more than current inventory for person 2"
prob += (route_vars['3']['1'] + route_vars['3']['2']) <= current['3'], f"Can't trade more than current inventory for person 3"

prob.solve()

pd.Series({v: int(v.varValue) for v in prob.variables()})

The problem is with the objective function which in this case always will evaluate to 1 which is the total unmet supply.问题出在目标函数上,在这种情况下,目标函数总是评估为 1,即总未满足供应量。 The reason why the model behaves this way is because overstocked demand contributes negatively in the objective function模型之所以如此表现,是因为积压的需求对目标函数有负面影响

As an example we can take your optimal solution which gives us a total balance for each person:例如,我们可以采用您的最佳解决方案,这为我们提供了每个人的总余额:

total = {
'1': 50,
'2': 10,
'3': 0 }

The objective function is essentially giving us lpSum(need[p] - total[p] for p in people) which means目标函数本质上是给我们lpSum(need[p] - total[p] for p in people) ,这意味着

15 - 50 = -35
0 - 10 = -10
46 - 0 = 46

So we have所以我们有

(-35) + (-10) + 46 = 1

What is missing is a term that cancels out the negative contribution of overstocking in the objective function, like so:缺少的是在目标函数中抵消积压的负面影响的术语,如下所示:

lpSum(need[p] - total[p] + overstock[p] for p in people )

Taking kabdulla's comment about multi-hope trading into account and adding decision variables to keep track of overstocking and totals (strictly for convenience and readability), a correct model can be formulated.考虑到Kabdulla关于多希望交易评论并添加决策变量以跟踪库存积压和总数(严格为了方便和可读性),可以制定正确的模型。

Check it out and let me know if you need clarification on anything检查一下,如果您需要澄清任何事情,请告诉我

 from pulp import *
import pandas as pd

# Creates a list of the unique people
people = ['1','2','3']

# Creates a dictionary for the number of units of units currently in supply
current = {
    '1': 10,
    '2': 0,
    '3': 50
}

# Creates a dictionary for the number of units needed
need = {
    '1': 15,
    '2': 0,
    '3': 46
}

# Creates the prob variable to contain the problem data
prob = LpProblem("Goods redistribution problem", LpMinimize)


overstock = LpVariable.dicts("overstock",
                             [p for p in people],
                             lowBound = 0)

route_vars = LpVariable.dicts("Trades",
                     [(i,j) for i in people for j in people if i != j],
                     lowBound = 0, 
                     cat = "Integer")

total = LpVariable.dicts("Total", 
                   [p for p in people],
                   lowBound = 0)

#obj
prob += lpSum(need[p] - total[p] + overstock[p] for p in people )

#s,t
for p in people:
    prob += total[p] - need[p] <= overstock[p] , "overstock definition for person" + str(p)

for p in people:
    prob += lpSum(route_vars[(p,j)] for j in people if p != j) + current[p] - lpSum(route_vars[(i,p)] for i in people if i != p) == total[p], "definition of total stock for person" + str(p)

for i in people:
    prob += lpSum(route_vars[(i,j)] for j in people if i != j) <= current[i] , "trading constraint person" + str(i)

prob.solve()

#Print optimal values in console
for v in prob.variables():
    print(v.name, " = ",  v.varValue)

#Print optimised objective function in console
print("Unmet supply:", prob.objective.value())

#Print solution status in console
print("Status:", LpStatus[prob.status])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM