如何在CVXPY中为布尔变量X设置单一非零值乘积约束?
解决方案
核心需求是让布尔变量数组X与数组B逐元素相乘后,所有非零元素必须等于同一个值p(p是B中的元素)。以下是可行的CVXPY约束编写方案:
方法一:线性化约束(推荐,适配大规模问题)
步骤1:定义辅助变量
- 引入整数变量
p,用于存储选中的目标值; - 设定常数
M,取max(B) - min(B)即可,确保能覆盖B[i]-p的所有可能绝对值。
步骤2:编写约束
import cvxpy as cp import numpy as np n = len(B) X = cp.Variable(n, boolean=True) p = cp.Variable(integer=True) M = max(B) - min(B) constr = [] # 核心约束:X[i]=1时,B[i]必须等于p;X[i]=0时无限制 for i in range(n): constr.append(B[i] - p <= M * (1 - X[i])) constr.append(p - B[i] <= M * (1 - X[i])) # 确保p是B中的元素 unique_B = np.unique(B) y = cp.Variable(len(unique_B), boolean=True) constr.append(p == cp.sum(y * unique_B)) constr.append(cp.sum(y) == 1) # 可选:禁止全0解 constr.append(cp.sum(X) >= 1)
方法二:直接二次约束(适合小规模问题)
利用布尔变量的特性,直接约束X[i]为1时B[i]必须等于p,CVXPY可处理布尔变量的二次项:
import cvxpy as cp import numpy as np n = len(B) X = cp.Variable(n, boolean=True) p = cp.Variable(integer=True) constr = [] for i in range(n): constr.append(X[i] * (B[i] - p) == 0) # 绑定p为B中的元素 unique_B = np.unique(B) y = cp.Variable(len(unique_B), boolean=True) constr.append(p == cp.sum(y * unique_B)) constr.append(cp.sum(y) == 1) # 可选:禁止全0解 constr.append(cp.sum(X) >= 1)
原约束无效的原因
你之前写的constr=[cvxpy.sum(np.multiply(X,B))/sum(X)==max(np.multiply(X,B))]存在两个关键问题:
- 非线性操作无法求解:
max(np.multiply(X,B))属于非线性操作,CVXPY支持的主流求解器仅能处理凸优化问题,这类非线性等式约束不在支持范围内; - 除法风险:当
sum(X)=0(全0解)时,除法无意义,会导致求解报错。
内容的提问来源于stack exchange,提问作者Andrea Montalbani
相关产品推荐
相关产品推荐

