如何在Python版Gurobi中实现向量乘法并解决线性约束维度报错问题
问题排查与解决
错误原因
- 变量类型混用:同时使用了
addMVar()创建的矩阵型变量x和addVars()创建的元组字典型变量y/w/gamma,两类变量的运算逻辑、返回结果维度不匹配,直接混合运算会触发维度错误 - 错误使用numpy运算处理Gurobi变量:
w.select(j,'*')返回的是Gurobi变量对象列表,直接转numpy矩阵做dot运算时,numpy无法正确识别Gurobi变量的维度和运算规则,返回的结果维度不符合约束要求 - 约束符号不规范:Gurobi线性约束仅支持非严格不等号
>=/<=,使用严格大于>虽然不会直接触发报错,但不符合求解器规范 - 约束逻辑符号错误:原数学表达式中为
w_j a_i - γ_j,代码中写成了-w_j a_i + γ_j,符号完全相反,会导致约束逻辑不符合预期
修正方案
把所有变量类型统一,内积直接通过Gurobi内置的线性表达式构造,避免用numpy做变量运算,修改后的代码如下:
import numpy as np import gurobipy as gp from gurobipy import GRB A=np.array([[ 7.6 , 8 ], [ 3 , 2.7], [ 0 , 0 ], [ 0.8 , 0.5], [ 6.6, 7.4], [ 6.7, 7.8], [ 1.9 , 2.6], [ 3.2 , 4.6], [ 6.4, 6.3], [10 , 10]]) m = A.shape[0] # A的行数 n = A.shape[1] # A的列数 M = 100000 k=2 # 将数据点聚为k个簇 # 创建模型 model = gp.Model('hyperplane clustering') # 统一使用addVars创建变量,避免类型混用 x = model.addVars(m, k, vtype=GRB.BINARY, name="x") y = model.addVars(m, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="y") w = model.addVars(k, n, lb=0.0, ub=1.0, vtype=GRB.CONTINUOUS, name='w') gamma = model.addVars(k, vtype=GRB.CONTINUOUS, name="gamma") # 构造约束 for i in range(m): for j in range(k): # 直接计算w_j和a_i的内积,不用numpy运算 w_dot_a = gp.quicksum(w[j, t] * A[i, t] for t in range(n)) model.addConstr(y[i] >= (w_dot_a - gamma[j]) - M * (1 - x[i,j])) # 后续可自行添加目标函数、调用solve()求解 model.update()
如果你偏好矩阵变量的写法,可以把所有变量都改成addMVar()类型,直接用矩阵乘法构造约束,运算效率更高:
# 矩阵变量版本实现 import numpy as np import gurobipy as gp from gurobipy import GRB A=np.array([[ 7.6 , 8 ], [ 3 , 2.7], [ 0 , 0 ], [ 0.8 , 0.5], [ 6.6, 7.4], [ 6.7, 7.8], [ 1.9 , 2.6], [ 3.2 , 4.6], [ 6.4, 6.3], [10 , 10]]) m = A.shape[0] # A的行数 n = A.shape[1] # A的列数 M = 100000 k=2 # 将数据点聚为k个簇 # 创建模型 model = gp.Model('hyperplane clustering') # 统一使用addMVar创建矩阵变量 x = model.addMVar((m,k), vtype=GRB.BINARY,name="x") y = model.addMVar(m, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="y") w = model.addMVar((k,n), lb=0.0, ub=1.0, vtype=GRB.CONTINUOUS, name='w') gamma = model.addMVar(k, vtype=GRB.CONTINUOUS, name="gamma") # 批量构造约束,无需循环i for j in range(k): model.addConstr(y >= (A @ w[j,:] - gamma[j]) - M * (1 - x[:,j])) model.update()
内容的提问来源于stack exchange,提问作者TIANMIN Wu
相关产品推荐
相关产品推荐

