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

CVXPY中L1范数约束为何不满足DCP规则?如何解决?

CVXPY中L1范数约束触发DCPError的问题解答

问题场景

执行cp.norm(weights, 1).is_dcp()返回True,但在优化问题中使用cp.norm(weights, 1) == 1.作为约束时触发DCPError,而替换为cp.sum(weights) == 1.则可正常运行。

测试代码:

import numpy as np
import cvxpy as cp

inputs = np.random.normal(0, 1, (100, 300))
inputs_mean = inputs.mean(axis=1) # shape (features,)
inputs_cov = np.asmatrix(np.cov(inputs)) # shape (features, features)

weights = cp.Variable(len(inputs))
risk = cp.quad_form(weights, inputs_cov)

constraints = [
    # cp.norm(weights, 1) == 1.,
    cp.sum(weights) == 1.,
]
problem = cp.Problem(cp.Minimize(risk), constraints)
problem.solve(verbose=True)
weights.value

替换为L1范数约束后报错:

DCPError: Problem does not follow DCP rules. Specifically:
The following constraints are not DCP:
norm1(var456) == 1.0 , because the following subexpressions are not:
|--  norm1(var456) == 1.0

一、为什么cp.norm(weights,1) ==1.不满足DCP规则?

CVXPY的DCP规则对约束有严格要求:

  • 不等式约束必须是凸函数 ≤ 凹函数或凹函数 ≥ 凸函数;
  • 等式约束必须是两个仿射函数相等。

cp.norm(weights,1)是凸函数,但不是仿射函数(仿射函数要求同时满足凸和凹);而常数1.0是仿射函数。凸函数 == 仿射函数不符合DCP的等式约束规则——DCP仅允许仿射函数之间的等式成立。

反观cp.sum(weights) ==1.,cp.sum(weights)是仿射函数,所以这个等式约束符合DCP规则。

二、如何排查DCP合规性问题?

  1. 检查表达式属性:用expr.is_convex()、expr.is_concave()、expr.is_affine()分别验证约束两边的表达式属性:
    • 执行cp.norm(weights,1).is_affine()会返回False,说明它不是仿射函数;
    • 执行(cp.norm(weights,1) ==1.).is_dcp()会直接返回False,确认该约束本身不符合DCP规则。
  2. 明确DCP规则边界:记住DCP的核心要求——所有约束都必须符合凸/凹函数的不等式逻辑,等式只能在仿射函数间成立。如果某个约束触发错误,先拆解成子表达式逐一验证属性。

三、实现权重绝对值和为1的替代方案

要实现sum(|weights|) =1的约束,需要转换成DCP兼容的形式,常见方案有:

方案1:引入辅助变量拆分绝对值约束

通过引入与weights同维度的辅助变量t,用两个不等式约束t >= weights和t >= -weights来表示t_i = |weights_i|,再约束t的和为1。所有约束均符合DCP规则:

import numpy as np
import cvxpy as cp

inputs = np.random.normal(0, 1, (100, 300))
inputs_mean = inputs.mean(axis=1)
inputs_cov = np.asmatrix(np.cov(inputs))

weights = cp.Variable(len(inputs))
t = cp.Variable(len(inputs))  # 辅助变量,t_i >= |weights_i|
risk = cp.quad_form(weights, inputs_cov)

constraints = [
    t >= weights,
    t >= -weights,
    cp.sum(t) == 1.
]
problem = cp.Problem(cp.Minimize(risk), constraints)
problem.solve(verbose=True)
print(weights.value)

方案2:针对非负权重场景简化

如果你的问题允许权重非负,那么sum(|weights|)=1等价于sum(weights)=1且weights >=0,直接用这两个约束即可,无需引入辅助变量。

方案3:调整为不等式约束(按需选择)

如果业务需求可以接受权重的L1范数≤1,那么cp.norm(weights,1) <=1是合法的DCP约束,直接使用即可。但注意这和“等于1”的约束逻辑不同,需根据实际场景判断是否适用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 19:32:47