如何在 Gurobi Python Objective 函数中对 `if` 条件进行建模?
How can I model `if` conditionals in Gurobi Python Objective Function?
我有一个 objective 函数,其中有一个 if
条件。我在 Gurobi Python.
中实施时遇到问题
背景
有 s
个供应商和 p
个工厂。 x[s][p]
是一个变量,表示从 supplier-x
流向 plant-p
的项目数。 c[s][p]
表示从供应商向中心供应一件商品的成本。
此外,每个供应商都有固定成本 t[s]
。如果一个供应商供应给任何一个中心,都会产生这个固定成本(这个固定成本不依赖于物品的数量)。
我想使用 objective 函数来最小化成本 -
第一部分很容易建模,如 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')
您会寻找这样的东西吗?在这里,您只需要看起来像这样的数组的第一个和最后一个元素。那么只有第一行和最后一行的跨列总和 >= 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 是一个决策变量,您可以 not use it with a standard python if statement. Instead, you need to add a binary indicator 变量 (y_s),只要任何装运变量 (x_sp) 在 non-zero。然后将指标变量添加到系数为 t_s.
的 objective 函数
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)]
约束条件迫使每个供应商 "on" 如果它向任何工厂运送任何东西。 big_M 值是供应商可以运送到工厂的数量的上限。由于 y 是二进制变量,如果任何相关的 x 变量为 non-zero,则它必须为 1。相反,如果 y 为 1,则任何或所有相关的 x 变量将有效地不受约束。由于 y 变量的系数都是正的,并且您正在最小化,因此如果所有 x 都为零,则不需要明确约束 y 为 0。
我有一个 objective 函数,其中有一个 if
条件。我在 Gurobi Python.
背景
有 s
个供应商和 p
个工厂。 x[s][p]
是一个变量,表示从 supplier-x
流向 plant-p
的项目数。 c[s][p]
表示从供应商向中心供应一件商品的成本。
此外,每个供应商都有固定成本 t[s]
。如果一个供应商供应给任何一个中心,都会产生这个固定成本(这个固定成本不依赖于物品的数量)。
我想使用 objective 函数来最小化成本 -
第一部分很容易建模,如 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')
您会寻找这样的东西吗?在这里,您只需要看起来像这样的数组的第一个和最后一个元素。那么只有第一行和最后一行的跨列总和 >= 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 是一个决策变量,您可以 not use it with a standard python if statement. Instead, you need to add a binary indicator 变量 (y_s),只要任何装运变量 (x_sp) 在 non-zero。然后将指标变量添加到系数为 t_s.
的 objective 函数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)]
约束条件迫使每个供应商 "on" 如果它向任何工厂运送任何东西。 big_M 值是供应商可以运送到工厂的数量的上限。由于 y 是二进制变量,如果任何相关的 x 变量为 non-zero,则它必须为 1。相反,如果 y 为 1,则任何或所有相关的 x 变量将有效地不受约束。由于 y 变量的系数都是正的,并且您正在最小化,因此如果所有 x 都为零,则不需要明确约束 y 为 0。