You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Gurobi编写Python优化模型时的报错排查求助

回收优化模型Gurobi代码错误排查与修正

错误原因分析及修正步骤

1. KeyError: (0, 0)(原目标函数)

  • 原因:变量Z的定义与使用不匹配。根据注释,Z是标记客户是否处理某类材料的二元变量,但代码中定义为Z = model.addVars(M, T, vtype=GRB.BINARY, name="Z")(维度为材料×天数),但目标函数中却用Z[c, 0](客户索引作为第一个维度),导致索引不存在。
  • 修正:重新定义Z为客户×材料的维度,修改为:
    Z = model.addVars(C, M, vtype=GRB.BINARY, name="Z")
    
    同时目标函数对应调整为:
    (q_p * Z[c, 'plastic'] + q_v * Z[c, 'glass']) * B[c,t]
    

2. TypeError: unsupported operand type(s) for -: 'gurobipy.LinExpr' and 'tupledict'

  • 原因:变量命名冲突。代码中先定义了卡车容量常量V = 130,之后又定义了工厂丢弃材料的变量V = model.addVars(M, T, ...),导致约束中的<= V实际指向变量而非常量,引发类型错误。
  • 修正:重命名工厂丢弃材料的变量为V_factory,并更新所有引用处:
    V_factory = model.addVars(M, T, lb=0, vtype=GRB.CONTINUOUS, name="V_factory")
    
    约束(1)改为:
    model.addConstrs(gp.quicksum(R[c, t] for c in range(C)) <= 130 for t in range(T))
    

3. KeyError: 'Missing constraint index'

  • 原因:使用model.addConstrs时未提供有效约束索引。第二个约束的工厂存储总和限制是单一约束,不需要用addConstrs(用于批量生成约束),导致Gurobi无法生成索引。
  • 修正:改用model.addConstr定义单一约束:
    model.addConstr(gp.quicksum(J[m, t] for m in M for t in range(T)) <= K, name="FactoryWarehouseCapacity")
    

其他逻辑问题修正

除上述错误外,代码还有多处逻辑不一致:

  • 客户存储约束原逻辑是总和不超过容量,通常应改为每日存储量不超过容量:G[c,t] <= A_c[c]
  • 工厂存储的约束(3)和起始点(4)重复定义J[m,0],需删除其中一个
  • 约束(4)中range(1, t-1)索引错误,应改为range(t)来累加之前所有天数的存储量

修正后的完整代码

import gurobipy as gp
from gurobipy import GRB

# 问题数据
T = 6  # 天数
C = 5  # 客户数

M = ['plastic', 'glass']  # 材料类型
C_p = [0, 1, 2]  # 处理塑料的客户(Python索引从0开始)
C_v = [3, 4]     # 处理玻璃的客户

# 每个客户每天收到的材料量(行=客户,列=天数)
P_ct = [[35, 28, 25, 30, 53, 24],
        [27, 33, 29, 24, 45, 21],
        [39, 32, 31, 27, 38, 22],
        [40, 35, 48, 30, 18, 32],
        [48, 22, 44, 37, 21, 31]]

q_p = 2  # 塑料丢弃成本
q_v = 3  # 玻璃丢弃成本
Q = 50   # 工厂切换配置的固定成本

A_c = [50, 45, 50, 65, 65]  # 客户仓库容量
V_truck = 130  # 卡车总容量
K = 250  # 工厂仓库容量

U_m = {'plastic': 110, 'glass': 90}  # 每日处理上限

alpha = 1/2  # 系数

# 创建模型
model = gp.Model("RecyclingProblem")

# 变量定义
# 从客户c在t天运走的材料量
R = model.addVars(C, T, lb=0, vtype=GRB.CONTINUOUS, name="R") 
# 客户c在t天丢弃的材料量
B = model.addVars(C, T, lb=0, vtype=GRB.CONTINUOUS, name="B")
# 客户c在t天存储的材料量
G = model.addVars(C, T, lb=0, vtype=GRB.CONTINUOUS, name="G")
# 工厂在t天处理材料m的量
H = model.addVars(M, T, lb=0, vtype=GRB.CONTINUOUS, name="H")  
# 工厂在t天丢弃材料m的量
V_factory = model.addVars(M, T, lb=0, vtype=GRB.CONTINUOUS, name="V_factory")  
# 工厂在t天存储材料m的量
J = model.addVars(M, T, lb=0, vtype=GRB.CONTINUOUS, name="J") 

# 工厂t天是否处理材料m的二元变量
X = model.addVars(M, T, vtype=GRB.BINARY, name="X") 
# 工厂t天是否切换配置的二元变量
Y = model.addVars(T, vtype=GRB.BINARY, name="Y")
# 客户c是否处理材料m的二元变量
Z = model.addVars(C, M, vtype=GRB.BINARY, name="Z")   

# 目标函数:最小化总成本
objective = sum(
    sum((q_p * Z[c, 'plastic'] + q_v * Z[c, 'glass']) * B[c,t] for c in range(C)) 
    + alpha * sum((q_p if m == 'plastic' else q_v) * V_factory[m,t] for m in M)
    + Q * Y[t] 
    for t in range(T)
)

model.setObjective(objective, GRB.MINIMIZE)

# 约束条件
# (1) 每日运走材料总量不超过卡车容量
model.addConstrs(
    gp.quicksum(R[c, t] for c in range(C)) <= V_truck 
    for t in range(T)
)

# (2) 仓库容量限制
# 客户仓库:每日存储量不超过容量
model.addConstrs(
    G[c, t] <= A_c[c] 
    for c in range(C) for t in range(T)
)
# 工厂仓库:总存储量不超过容量
model.addConstr(
    gp.quicksum(J[m, t] for m in M for t in range(T)) <= K,
    name="FactoryWarehouseTotalCapacity"
)

# (3) 客户存储平衡:当日存储 = 前日存储 + 当日到货 - 当日运走 - 当日丢弃
model.addConstrs(
    G[c, 0] == P_ct[c][0] - R[c, 0] - B[c, 0] 
    for c in range(C)
)
for c in range(C):
    for t in range(1, T):
        model.addConstr(
            G[c, t] == G[c, t-1] + P_ct[c][t] - R[c, t] - B[c, t],
            name=f"ClientStorageBalance_{c}_{t}"
        )

# (4) 工厂存储平衡:当日存储 = 前日存储 + 当日收到材料 - 当日处理 - 当日丢弃
model.addConstrs(
    J[m, 0] == gp.quicksum(R[c, 0] for c in (C_p if m == 'plastic' else C_v)) 
    - H[m, 0] - V_factory[m, 0]
    for m in M
)
for m in M:
    for t in range(1, T):
        model.addConstr(
            J[m, t] == J[m, t-1] + gp.quicksum(R[c, t] for c in (C_p if m == 'plastic' else C_v)) 
            - H[m, t] - V_factory[m, t],
            name=f"FactoryStorageBalance_{m}_{t}"
        )

# (5) 处理量上限:只有开启处理时才能生产
model.addConstrs(
    H[m,t] <= U_m[m] * X[m,t] 
    for m in M for t in range(T)
)

# (6) 每日最多处理一种材料
model.addConstrs(
    gp.quicksum(X[m, t] for m in M) <= 1 
    for t in range(T)
)

# 求解模型
model.optimize()

# 输出结果
if model.status == GRB.OPTIMAL:
    print("找到最优解:")
    print(f"目标函数值: {model.objVal:.2f}")
    print("变量值(仅非零值):")
    for var in model.getVars():
        if abs(var.x) > 1e-6:
            print(f"{var.varName}: {var.x:.2f}")
else:
    print("无法找到最优解。")

补充说明

  • 修正了客户索引问题(Python从0开始,原代码中C_p/C_v的1-5改为0-4)
  • 补充了工厂材料区分逻辑(塑料客户的运量仅进入塑料存储,玻璃同理)
  • 完善了存储平衡逻辑,加入前日存储累积(原代码未考虑,导致逻辑缺失)
  • 添加了处理开关变量X和处理量H的关联约束,确保逻辑自洽

内容的提问来源于stack exchange,提问作者aaaaaaaa2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 10:29:53