Python中使用docplex求解混合整数非线性规划遇非凸目标函数错误的修复方案及优化方法咨询
解决MINLP中非凸目标函数的报错问题
你遇到的这个错误本质上是因为目标函数里存在二进制变量(x[i,j]、y[i,aa])和连续变量(dist[i,j]、dis[i,aa])的乘积项,这种交叉乘积属于非凸非线性项,而CPLEX默认的求解逻辑是针对凸优化问题的,所以直接求解会触发这个报错。下面给你两种可行的修复思路:
思路1:线性化乘积项,将模型转为MILP
因为你的二进制变量只有0和1两种取值,我们可以通过引入新的连续变量来线性化这些乘积项,把原本的MINLP问题转化为混合整数线性规划(MILP)——这是CPLEX最擅长处理的问题类型,求解效率和稳定性都会更好。
具体做法如下:
- 为每个乘积项引入新的连续变量,比如用
z[i,j]代替x[i,j]*dist[i,j],用w[i,aa]代替y[i,aa]*dis[i,aa]; - 添加约束来保证新变量和原变量的等价性(需要先估算连续变量的上界
M,比如根据你的坐标范围估算最大可能的曼哈顿距离); - 修改目标函数,用新变量替换原乘积项。
修改后的代码示例:
from docplex.mp.model import Model m = Model(name='opt') cx = m.continuous_var_list(n+1,name="cx", lb=0) cy = m.continuous_var_list(n+1,name="cy", lb=0) x = m.binary_var_matrix(n+1,n+1, name="x") y = m.binary_var_matrix(n+1,a+1, name="y") dis = m.continuous_var_matrix(n+1,a+1, name="distanceofindividual", lb=0) dist = m.continuous_var_matrix(n+1,n+1, name="distanceofclusters", lb=0) # 引入线性化用的新变量 z = m.continuous_var_matrix(n+1,n+1, name="z", lb=0) w = m.continuous_var_matrix(n+1,a+1, name="w", lb=0) # 估算连续变量的上界M:根据你的px、py的实际范围调整,这里假设坐标最大为100 max_coord = 100 M_dist = 2 * max_coord # 聚类中心之间的最大曼哈顿距离 M_dis = 2 * max_coord # 个体到聚类中心的最大曼哈顿距离 # 线性化x[i,j] * dist[i,j]的约束 for i in C: for j in C: if i != j: m.add_constraint(z[i,j] <= dist[i,j]) m.add_constraint(z[i,j] <= M_dist * x[i,j]) m.add_constraint(z[i,j] >= dist[i,j] - M_dist * (1 - x[i,j])) # 线性化y[i,aa] * dis[i,aa]的约束 for i in C: for aa in V: m.add_constraint(w[i,aa] <= dis[i,aa]) m.add_constraint(w[i,aa] <= M_dis * y[i,aa]) m.add_constraint(w[i,aa] >= dis[i,aa] - M_dis * (1 - y[i,aa])) # 修改目标函数:用线性化后的变量替代乘积项 m.set_objective("min", sum(z[i,j] for i in C for j in C if i!=j) + sum(w[i,aa] for i in C for aa in V)) # 原有的约束(注意修正了dist约束的笔误,原代码里的aa应该是j) m.add_constraints(dis[i,aa]== m.abs(px[aa]-cx[i]) + m.abs(py[aa]-cy[i]) for i in C for aa in V) m.add_constraints(dist[i,j]== m.abs(cx[j]-cx[i]) + m.abs(cy[j]-cy[i]) for i in C for j in C) m.add_constraints(m.sum(x[i,j] for i in C if i!=j)==1 for j in C)
注意:M的取值要合理——不能太小(否则会排除可行解),也不能太大(否则会降低求解效率),最好根据你的实际数据范围来计算。
思路2:启用求解器的非凸MINLP支持
如果你不想做线性化,也可以直接让CPLEX支持非凸MINLP的求解。只需要在求解前设置对应的参数,允许求解非凸问题:
# 在求解前添加这一行,允许CPLEX处理非凸MINLP m.parameters.mip.strategy.nonconvex = 2 # 然后正常求解 solution = m.solve()
不过要注意:非凸MINLP的求解难度远高于MILP,求解时间可能会很长,而且通常只能找到局部最优解,需要根据你的问题规模和求解需求来选择这种方式。
另外提个小细节:你原代码里的dist[i,aa]约束应该是笔误,聚类之间的距离应该是dist[i,j]对应cx[j]和cy[j],我在示例代码里已经修正了这个问题。
内容的提问来源于stack exchange,提问作者Ebru Pekel




