使用Clarabel作为CVXPY后端求解最小二乘问题为何显示原问题不可行?
三变量最小二乘优化问题:CVXPY调用Clarabel报错但直接调用正常的原因分析
问题背景
针对三变量三测量的最小二乘优化问题,分别采用两种方式求解,结果不一致:
- 通过CVXPY调用Clarabel后端:构建带变量上下界及线性约束的优化问题后,调用
prob.solve(solver="CLARABEL")返回PrimalInfeasible,无法得到解; - 直接调用Clarabel:手动构建二次规划问题的
P、q、Ac、bc矩阵及锥约束,求解后可正常得到结果。
疑惑:是CVXPY使用存在认知缺失,还是CVXPY存在bug?
复现代码
import scipy import numpy as np import cvxpy as cvx import clarabel A = np.array([[-43.83695965, 0.34990409, -1.32935518], [-48.86811152, 0.57411847, -1.38219424], [-49.25621142, 0.75738835, -1.2979702 ]]) b = np.array([ 53897.91898074, -159390.11128713, -62013.59835614]) bounds_arr = np.array([[-1., -1., -1.], [ 1., 1., 1.]]) #------- 使用CVXPY调用CLARABEL后端--------------- x = cvx.Variable(A.shape[1]) cost = cvx.sum_squares(A @ x - b) constraints = [] constraints += [xv >= bnd for (xv, bnd) in zip(x, bounds_arr[0])] constraints += [xv <= bnd for (xv, bnd) in zip(x, bounds_arr[1])] constraints += [x[0] + x[1] + x[2] >= -np.sqrt(3)] # constraints += [cvx.sum(x) >= -np.sqrt(3)] # 这种写法也无效 prob = cvx.Problem(cvx.Minimize(cost), constraints) prob.solve(solver="CLARABEL", verbose=True) # 返回'PrimalInfeasible' print("x: ", x.value) #------- 直接调用CLARABEL--------------- P = A.T @ A P = scipy.sparse.triu(P).tocsc() q = -b.T @ A # 注:常数项不影响优化解,故忽略 Ac = scipy.sparse.vstack([-scipy.sparse.identity(A.shape[1]), scipy.sparse.identity(A.shape[1]), np.array([[-1.0, -1.0, -1.0]])]).tocsc() bc = np.concat([-bounds_arr[0], bounds_arr[1], [np.sqrt(3)]], axis=0) cones = [clarabel.NonnegativeConeT(A.shape[1]), clarabel.NonnegativeConeT(A.shape[1]), clarabel.NonnegativeConeT(1)] settings = clarabel.DefaultSettings() solver = clarabel.DefaultSolver(P, q, Ac, bc, cones, settings) solution = solver.solve() # 正常求解 print("x: ", solution.x)
问题分析与解决方案
核心结论
两种实现的约束逻辑完全一致,目标函数仅存在缩放差异(不影响可行性判断),因此问题大概率出在CVXPY与Clarabel的接口转换环节,而非用户的使用错误。
排查与解决步骤
对比问题转换结果
开启verbose=True查看CVXPY生成的Clarabel问题参数(P、q、Ac、bc),与手动构建的逐一对比,重点检查线性约束行的符号、数值是否完全匹配。若存在差异,说明CVXPY的约束转换存在bug。调整求解器参数
手动传递Clarabel的配置参数,放宽可行性容忍度,尝试规避数值精度问题:settings = clarabel.DefaultSettings() settings.feasibility_tolerance = 1e-6 # 可根据情况调整 prob.solve(solver="CLARABEL", verbose=True, settings=settings)交叉验证求解器
使用其他CVXPY支持的求解器(如ECOS、OSQP)运行同一问题:prob.solve(solver="ECOS", verbose=True)- 若其他求解器能得到解,说明CVXPY与Clarabel的接口存在bug,建议更新CVXPY和Clarabel到最新版本;
- 若其他求解器也报不可行,则需重新检查手动构建的Clarabel问题是否存在约束转换错误(从当前代码看,手动转换逻辑是正确的)。
临时替代方案
若确认是接口bug,可暂时采用手动构建Clarabel问题的方式实现,或等待CVXPY/Clarabel修复对应问题。
内容的提问来源于stack exchange,提问作者Charlie
相关产品推荐
相关产品推荐

