如何在Gurobi中添加取两个连续决策变量乘积下整值的约束
在Gurobi中实现
v = floor(x * y)约束的方法 Gurobi不能直接定义v = floor(x * y)这类约束,因为它同时涉及双非线性项(连续变量x和y的乘积)和不连续的取整函数,属于非凸优化问题,而Gurobi默认只支持凸优化模型。不过你可以通过拆解约束、引入辅助变量的方式,让Gurobi能够处理这类需求。
约束拆解思路
要实现v = floor(x*y),可以把它拆成两个部分处理:
- 先把连续变量的乘积转化为辅助变量
- 再用整数变量和不等式约束表达取整逻辑
1. 引入辅助变量处理乘积项
添加一个连续辅助变量z,让z = x*y。这是双线性约束,Gurobi支持这类约束,但需要开启非凸求解模式(默认关闭)。
2. 用不等式表达取整逻辑
v = floor(z)等价于:
v ≤ z:保证v不大于z的整数部分z < v + 1:保证z小于v的下一个整数
同时要声明v为整数决策变量。
关键注意事项
- 必须开启非凸参数:设置
model.setParam('NonConvex', 2),否则Gurobi会拒绝求解包含双线性约束的非凸模型。 - 非凸问题的局限性:这类问题无法保证找到全局最优解,只能得到局部最优;求解速度会远慢于凸优化问题,变量规模越大越明显。
- 合理设置变量边界:给
x、y、z设置明确的上下界,能帮助Gurobi的分支定界算法更高效地搜索解空间。
示例代码(Python)
import gurobipy as gp from gurobipy import GRB # 创建模型 model = gp.Model("floor_product_example") # 定义决策变量 x = model.addVar(lb=0, ub=5, name="x") # 给x设置0-5的边界 y = model.addVar(lb=0, ub=5, name="y") # 给y设置0-5的边界 v = model.addVar(vtype=GRB.INTEGER, name="v") z = model.addVar(lb=0, ub=25, name="z") # x*y的最大可能值是25 # 添加约束 model.addConstr(z == x * y, "product_eq") model.addConstr(v <= z, "floor_lower_bound") model.addConstr(z < v + 1, "floor_upper_bound") # 开启非凸求解模式 model.setParam('NonConvex', 2) # 设置目标函数(示例:最大化v) model.setObjective(v, GRB.MAXIMIZE) # 求解模型 model.optimize() # 输出结果 if model.status == GRB.OPTIMAL: print(f"最优解:") print(f"x = {round(x.X, 4)}") print(f"y = {round(y.X, 4)}") print(f"z = x*y = {round(z.X, 4)}") print(f"v = floor(z) = {int(v.X)}") else: print("未找到最优解")
内容的提问来源于stack exchange,提问作者bobby
相关产品推荐
相关产品推荐

