【问题标题】:How can I model `if` conditionals in Gurobi Python Objective Function?如何在 Gurobi Python 目标函数中对“if”条件进行建模?
【发布时间】:2019-11-06 09:30:19
【问题描述】:

我有一个目标函数,其中有一个if 条件。我无法在 Gurobi Python 中实现它。

背景

s 供应商和p 工厂。 x[s][p] 是一个变量,表示从supplier-x 流向plant-p 的项目数。 c[s][p] 表示从供应商向中心供应一件商品的成本。

此外,每个供应商都有固定成本t[s]。如果供应商向任何中心供货,就会产生这个固定成本(这个固定成本不取决于物品的数量)。

我想使用像这样的目标函数来最小化成本 -

第一部分很容易建模,如sum(x[s, p] * spc[s, p] for s in range(num_suppliers) for p in range(num_center))

对于第二个术语,我该如何建模? (第二部分基本上意味着只有当供应商实际上是任何工厂的供应商时才添加供应商的固定成本)。

编辑

这是我现在拥有的代码。注意:这不会产生最小值 -

from gurobipy import *

supplier_capacity = [
    5, 10
]
plant_demand = [
    2, 4
]
num_suppliers = len(supplier_capacity)
num_plants = len(plant_demand)
t = [
    100, 1
]

c = {
    (0, 0): 1,
    (0, 1): 4,

    (1, 0): 4,
    (1, 1): 2
}

x = {}  # flow between each supplier to plant

m = Model()
xl = [(s, p) for s in range(num_suppliers) for p in range(num_plants)]
x = m.addVars(xl, vtype=GRB.INTEGER, lb=0, name='flow')

for s in range(num_suppliers):
    m.addConstr(x.sum(s, '*') <= supplier_capacity[s])
for p in range(num_plants):
    m.addConstr(x.sum('*', p) >= plant_demand[p])

m.setObjective(
    (
        sum(x[s, p] * c[s, p] for s in range(num_suppliers) for p in range(num_plants)) +
        sum(t[s] for s in range(num_suppliers) if x.sum(s, '*') >= 0)
    ), GRB.MINIMIZE
)
m.update()
m.optimize()

if m.status == GRB.Status.OPTIMAL:
    print('==== RESULTS ====')
    print('Min Cost: {}'.format(m.ObjVal))
    for v in m.getVars():
        print('{} = {}'.format(v.VarName, v.X))
else:
    print('Infeasible model')

【问题讨论】:

  • 我们可以将s 视为二维数组中的行数,将p 视为列数吗?
  • @Buckeye14Guy 是的,这就是它的概念。但我已将xc 建模为以元组为键的字典。

标签: python mathematical-optimization linear-programming gurobi


【解决方案1】:

由于 x 是一个决策变量,您可以 not 将它与标准 python if 语句一起使用。相反,您需要添加一个二进制 indicator 变量 (y_s),只要任何装运变量 (x_sp) 非零,该变量就会被强制为值 1。然后将指标变量添加到系数为 t_s 的目标函数中。

y = [m.addVar(vtype='B', obj=t_s) for t_s in t]
for s, y_s in enumerate(y):
    for p in range(num_plants):
         big_M = min(supplier_capacity[s], plant_demand[p])
         m.addConstr(big_M * y_s >= x[(s, p)]

限制条件迫使每个供应商在向任何工厂运送任何东西时都必须“开工”。 big_M 值是供应商可以运送到工厂的数量的上限。由于 y 是一个二进制变量,因此如果任何相关的 x 变量不为零,则它必须为 1。相反,如果 y 为 1,则任何或所有相关的 x 变量将有效地不受约束。由于 y 变量的系数都是正数,并且您正在最小化,因此如果所有 x 都为零,则不需要 y 为 0 的显式约束。

【讨论】:

  • 您的意思是 - m.addConstr(big_m * y[s] &gt;= x[(s, p)]?我尝试添加此约束(并且不更改目标函数),并且 y 具有所有 1s,即使 x[0, 0]x[0, 1] 都是零。
  • 我说得太早了。如果我将sum(y[s] * t[s] for s in range(num_suppliers)) 添加到目标函数(除了我现在拥有的),这似乎会产生正确的答案。谢谢!
【解决方案2】:

你会寻找这样的东西吗?在这里,您只需要看起来像这样的数组的第一个和最后一个元素。那么只有第一行和最后一行的逐行总和> = 1。

array([[ 0,  1,  2,  3],
       [ 4,  -5,  -6,  -7],
       [ 8,  9, 10, 11]])
num_suppliers, num_center = 3, 4

t = [1,2,3]
x = {
     (0, 0): 0,
     (0, 1): 1,
     (0, 2): 2,
     (0, 3): 3,
     (1, 0): 4,
     (1, 1): -5,
     (1, 2): -6,
     (1, 3): -7,
     (2, 0): 8,
     (2, 1): 9,
     (2, 2): 10,
     (2, 3): 11
     }

sum(t[s] for s in range(num_suppliers) if sum(x[s, p] for p in range(num_center)) >= 1)

输出:4

【讨论】:

  • x 也是一个模型变量。用我现在所拥有的内容更新了问题。
  • 我明白了。恐怕我无法回答这个问题
猜你喜欢
  • 1970-01-01
  • 2019-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多