如何在Gurobi中实现含求和项的二次优化目标函数?
如何在Gurobi目标函数中加入含整数变量的求和项?
我尝试使用Python的Gurobi库优化含求和项的二次方程,但求和项报错,推测原因是其无法接受整数变量,仅支持常量整数。请问如何在目标函数中加入求和项?
我的代码如下:
from gurobipy import * import sympy as sy op1=sy.Symbol('op1') op2=sy.Symbol('op2') # Create a model quadratic_model = Model('quadratic') # Define decision variables n = quadratic_model.addVar(vtype=GRB.INTEGER, lb=0, name='n') t = quadratic_model.addVar(vtype=GRB.INTEGER, lb=0, name='t') temp = quadratic_model.addVar(vtype=GRB.INTEGER, lb=0, name='temp') # Define objective function obj_fn = (1256*80/12.5)*n*t + 25*5*n*t + sy.summation(5*t*50*(365//n)*op1,(op1,1,n)) + sy.summation(5*24*op2,(op2,1,365)) quadratic_model.setObjective(obj_fn, GRB.MINIMIZE) # Add constraints quadratic_model.addConstr(50*n*t >= 4320) quadratic_model.addConstr(n>=1) quadratic_model.addConstr(t>=1) quadratic_model.addConstr(n<=6*30/4) # Solve model quadratic_model.setParam('NonConvex', 2) quadratic_model.optimize() # Print results for v in quadratic_model.getVars(): print('---------------------------------------') print('%s : %g' % (v.varName, v.x)) print("minimized solution for the equation is:", quadratic_model.objVal)
我尝试了两种方案仍未解决问题:
- 使用temp变量替代
365//n并添加约束temp == 365//n,但仍无法解决; - 使用for循环,却出现‘module 'gurobipy' has no attribute 'INTEGER'’的异常,此前使用Gurobi求解二次问题时未出现该问题。
问题分析与解决方法
核心问题
- SymPy求和不兼容Gurobi变量:SymPy的
sy.summation是符号计算工具,仅能处理常量上限的求和,无法识别Gurobi变量n作为求和上限,且Gurobi不能直接接受SymPy表达式作为目标函数。 - 整数除法的非线性限制:
365//n属于非线性操作,Gurobi默认不支持直接建模,需转化为线性约束。 - for循环报错原因:大概率是导入方式冲突,
from gurobipy import *可能导致GRB.INTEGER未被正确加载,建议显式导入GRB类。
具体解决方案
1. 手动展开求和项,替换为代数表达式
直接推导求和结果,不再依赖SymPy:
sy.summation(op1, (op1,1,n))的求和结果为n*(n+1)/2,因n是整数,可直接写入目标函数;sy.summation(op2, (op2,1,365))是常量求和,直接计算为5*24*(365*366//2)。
2. 用线性约束实现整数除法
引入整数变量k替代365//n,通过以下线性约束定义k:
k * n ≤ 365 < (k+1)*n k ≥ 0
3. 修正后的完整代码
from gurobipy import Model, GRB # 创建模型 quadratic_model = Model('quadratic') # 定义决策变量 n = quadratic_model.addVar(vtype=GRB.INTEGER, lb=1, name='n') # 直接设lb=1,避免n=0报错 t = quadratic_model.addVar(vtype=GRB.INTEGER, lb=1, name='t') k = quadratic_model.addVar(vtype=GRB.INTEGER, lb=0, name='k') # 替代365//n # 预计算常量求和项 sum_op2 = 5 * 24 * (365 * 366 // 2) # 定义目标函数 obj_fn = (1256*80/12.5)*n*t + 25*5*n*t + 5*t*50*k*(n*(n+1)//2) + sum_op2 quadratic_model.setObjective(obj_fn, GRB.MINIMIZE) # 添加约束 quadratic_model.addConstr(50*n*t >= 4320, name='demand_constraint') quadratic_model.addConstr(k * n <= 365, name='div_constraint_lower') quadratic_model.addConstr((k + 1) * n > 365, name='div_constraint_upper') quadratic_model.addConstr(n <= 6*30//4, name='n_upper_limit') # 转为整数上限,避免浮点误差 # 求解模型 quadratic_model.setParam('NonConvex', 2) quadratic_model.optimize() # 输出结果 for v in quadratic_model.getVars(): print('---------------------------------------') print('%s : %g' % (v.varName, v.x)) print("minimized solution for the equation is:", quadratic_model.objVal)
4. 关键说明
- 显式导入
Model和GRB可避免INTEGER属性找不到的问题,规避from gurobipy import *的导入冲突; - 所有求和项均转化为Gurobi支持的变量表达式或常量,不再依赖SymPy;
- 整数除法通过辅助变量
k和线性约束实现,符合Gurobi的建模规则。
内容的提问来源于stack exchange,提问作者Karas0u
相关产品推荐
相关产品推荐

