我如何在Gurobi-Python目标函数中建模'if'条件?

我如何在Gurobi-Python目标函数中建模'if'条件?,python,mathematical-optimization,linear-programming,gurobi,Python,Mathematical Optimization,Linear Programming,Gurobi,我有一个目标函数,其中有一个if条件。我在用Gurobi-Python实现它时遇到了问题 背景 有s供应商和p工厂x[s][p]是一个变量,表示从supplier-x流向plant-p的项目数量c[s][p]表示从供应商向中心供应一个项目的成本 此外,每个供应商都有固定成本t[s]。如果供应商向任何中心供货,则产生该固定成本(该固定成本不取决于项目数量) 我想用一个目标函数来最小化成本,比如—— 第一部分很容易建模,比如sum(x[s,p]*spc[s,p]表示范围内的s(num\u供应商)表

我有一个目标函数,其中有一个
if
条件。我在用Gurobi-Python实现它时遇到了问题

背景

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

此外,每个供应商都有固定成本
t[s]
。如果供应商向任何中心供货,则产生该固定成本(该固定成本不取决于项目数量)

我想用一个目标函数来最小化成本,比如——

第一部分很容易建模,比如
sum(x[s,p]*spc[s,p]表示范围内的s(num\u供应商)表示范围内的p(num\u中心))

对于第二个学期,我如何建模?(第二部分基本上是指仅当供应商实际上是任何工厂的供应商时,才添加供应商的固定成本)

编辑

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

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')
从gurobipy导入*
供应商能力=[
5, 10
]
工厂需求=[
2, 4
]
供应商数量=len(供应商容量)
工厂数量=len(工厂需求)
t=[
100, 1
]
c={
(0, 0): 1,
(0, 1): 4,
(1, 0): 4,
(1, 1): 2
}
x={}#每个供应商与工厂之间的流量
m=模型()
xl=[(s,p)适用于范围内的s(供应商数量)适用于范围内的p(工厂数量)]
x=m.addVars(xl,vtype=GRB.INTEGER,lb=0,name='flow')
对于范围内的s(供应商数量):
m、 addConstr(x.sum(s,“*”)=工厂需求[p])
m、 设定目标(
(
总和(x[s,p]*c[s,p]表示范围内的s(供应商数量)表示范围内的p(工厂数量))+
如果x.sum(s,“*”)>=0,则范围(num_供应商)内s的总和(t[s]
),GRB
)
m、 更新()
m、 优化()
如果m.status==GRB.status.OPTIMAL:
打印('==结果==')
打印('Min Cost:{}'。格式(m.ObjVal))
对于m.getVars()中的v:
打印(“{}={}.”格式(v.VarName,v.X))
其他:
打印(“不可行模型”)

你会找这样的东西吗?这里您只需要数组的第一个和最后一个元素,如下所示。因此,仅第一行和最后一行的逐列总和>=1

数组([[0,1,2,3],
[ 4,  -5,  -6,  -7],
[ 8,  9, 10, 11]])
num\u供应商,num\u中心=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(x[s,p]表示范围内的p(num_中心))>=1,则sum(t[s]表示范围内的s(num_供应商)

输出:4

因为x是一个决策变量,所以可以将它与标准的python if语句一起使用。相反,您需要添加一个二进制变量(y_s),当任何装运变量(x_sp)不为零时,该变量将被强制为值1。然后用系数ts将指标变量添加到目标函数中

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)]

这些限制迫使每个供应商在向任何工厂发货时都必须“打开”。大的M值是供应商可以运送到工厂的数量的上限。由于y是一个二进制变量,因此如果任何相关的x变量都不是零,则y必须为1。相反,如果y为1,则任何或所有相关的x变量将有效地不受约束。因为y变量上的系数都是正的,并且你正在最小化,所以如果所有的x都为零,你不需要一个明确的约束y为0

我们能把
s
看作是二维数组中的行数,把
p
看作是二维数组中的列数吗?@Buckeye14Guy是的,概念上就是这样。但是我将
x
c
建模为dict,以元组为键。
x
也是一个模型变量。用我现在掌握的更新了问题。我明白了。恐怕我当时无法回答这个问题。你是说-
m.addConstr(big\u m*y[s]>=x[(s,p)]
?我尝试添加这个约束条件(并且不改变目标函数),
y
拥有所有
1
s,即使
x[0,0]
x[0,1]
都是零。我说得太早了。如果我添加
sum(y[s]*t[s] 对于目标函数范围内的s(num_suppliers))
(除了我现在拥有的之外),这似乎给出了正确的答案。谢谢!