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

Gurobi addConstr约束内距离计算实现问题咨询

问题解答

核心结论

  • 不能直接在addConstr()内部调用sklearn的pairwise_distances函数。该函数仅接受固定数值的numpy数组作为输入,无法识别Gurobi的决策变量对象,也不会生成Gurobi可解析的优化表达式,强行调用要么触发类型错误,要么仅计算变量当前初始值的距离作为常数约束,完全达不到约束优化的效果。
  • 你关于Gurobi不支持直接在约束中使用sqrt类通用非线性函数的认知是正确的,但欧氏、曼哈顿距离约束完全不需要依赖sqrt或第三方计算函数,用Gurobi原生语法即可实现,不存在无法手动实现的问题。

正确实现方式

场景1:X、Y均为预先定义的固定numpy数组

这种场景下点对距离是固定常数,不需要把距离计算放到模型构建环节,提前做预处理计算即可:

from sklearn.metrics import pairwise_distances
import gurobipy as gp
import numpy as np

# 提前计算所有固定点对的距离,这一步可以正常用sklearn
euclidean_dist_matrix = pairwise_distances(X, Y, metric="euclidean")
manhattan_dist_matrix = pairwise_distances(X, Y, metric="manhattan")

m = gp.Model()
N = X.shape[0]
# 根据提前算好的距离值,按业务规则加约束即可
for i in range(N):
    for j in range(N):
        # 例:仅对距离<=50的点对加业务约束
        if euclidean_dist_matrix[i, j] <= 50:
            # 此处写入实际需要的约束逻辑
            pass

注意:如果X、Y都是固定数组,pairwise_distances的输出<=50是恒真或恒假的常数判断,不需要作为优化约束写入模型。

场景2:Y(或X、或两者同时)是Gurobi决策变量

这种场景下不能用sklearn预计算,需要直接用Gurobi的表达式语法写约束,分两种距离类型处理:

欧氏距离约束(两点距离≤50)

欧氏距离公式为 $\sqrt{\sum_{d=0}{D-1}(x_{i,d}-y_{j,d})2} \leq 50$,由于不等号两侧都是非负值,直接对两边平方去掉sqrt,等价于 $\sum_{d=0}{D-1}(x_{i,d}-y_{j,d})2 \leq 50^2$,这是Gurobi原生支持的二次约束,写法如下:

from gurobipy import GRB

m = gp.Model()
N, D = X.shape
# 定义决策变量Y,若X也是决策变量用相同方式定义即可
Y = m.addMVar((N, D), lb=-GRB.INFINITY, name="Y")
threshold = 50

# 逐对添加约束
for i in range(N):
    for j in range(N):
        m.addConstr(
            ((X[i, :] - Y[j, :]) ** 2).sum() <= threshold ** 2,
            name=f"euc_dist_constr_{i}_{j}"
        )

如果需要添加距离≥阈值的欧氏约束,平方后的约束属于非凸二次约束,需要在求解前设置m.Params.NonConvex = 2,Gurobi即可正常求解。

曼哈顿距离约束(两点距离≤50)

曼哈顿距离公式为 $\sum_{d=0}^{D-1}|x_{i,d}-y_{j,d}| \leq 50$,Gurobi原生提供绝对值表达式支持,直接调用gp.abs_()即可,框架会自动将其转换为线性约束求解,写法如下:

for i in range(N):
    for j in range(N):
        m.addConstr(
            gp.abs_(X[i, :] - Y[j, :]).sum() <= threshold,
            name=f"man_dist_constr_{i}_{j}"
        )

如果追求极致求解效率,也可以手动通过非负辅助变量线性化绝对值,逻辑和Gurobi内部自动处理的过程完全一致。

示例代码存在的问题

  • 双层for循环已经遍历了i、j索引,约束内部又写了for i in range(N)的生成器,存在语法冲突。
  • addConstr方法单次仅支持添加单个约束,批量添加约束需要使用addConstrs方法,或像示例中一样通过循环逐次调用addConstr。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:06:20