凸优化问题的求解,在实际问题中还是有很多应用场景的,我在CVX,免费开源的凸优化建模MATLAB工具包介绍了其在MATLAB,功能齐全的工程计算软件中的应用. 然而,我发现CVX在python中更新频率很快,而在matlab中的更新却慢太多了,于是就整个cvxpy的介绍.

CVXPY 是一种嵌入在 Python 中的凸优化问题建模语言。
它会自动将问题转换为标准形式,调用求解器,并解包结果。
CVXPY 的官方文档位于 cvxpy.org。
CVXPY 是一个嵌入在 Python 中的凸优化问题建模语言。它允许你以自然的、数学化的方式表达优化问题,而无需受限于求解器要求的标准形式。
例如,以下代码求解一个带上下界约束的最小二乘问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import cvxpy as cpimport numpy# 问题数据m = 30n = 20numpy.random.seed(1)A = numpy.random.randn(m, n)b = numpy.random.randn(m)# 构建问题x = cp.Variable(n)objective = cp.Minimize(cp.sum_squares(A @ x - b))constraints = [0 <= x, x <= 1]prob = cp.Problem(objective, constraints)# prob.solve() 返回最优目标函数值result = prob.solve()# x.value 存储最优解向量print(x.value)# 约束的最优拉格朗日乘子存储在 constraint.dual_value 中print(constraints[0].dual_value)
使用 CVXPY,你可以建模以下类型的优化问题:
值得注意的是,CVXPY 本身不是求解器,它仅仅是提供了一种建模语言,需要依赖以下开源求解器:常用的开源免费求解器
学术授权或购买的商业优化求解器
CVXPY 起源于斯坦福大学的一个研究项目,如今由来自世界各地的研究人员和工程师共同维护和改进。
CVXPY 可在 PyPI 上获取,通过以下命令安装:
1 pip install cvxpy
也可以通过 conda 安装:
1 conda install -c conda-forge cvxpy
CVXPY 依赖以下组件:
详细安装说明请参见官方 Installation Guide(安装指南)[2]。
若你初次接触 CVXPY,可参考以下资源:
CVXPY 社区由来自全球的研究人员、数据科学家、软件工程师和学生组成,诚邀你的加入!
请文明交流,遵守社区的行为准则(code of conduct)[9]。
首先,请通过源码安装 CVXPY。之后,你可以从以下方式开始贡献:
若你希望向示例库添加新示例或实现新功能,请先与我们沟通,以确保方向一致。所有贡献均应以 pull request(拉取请求) 提交。
CVXPY 开发团队成员将审阅并指导你完成。
开始贡献前,请阅读 贡献指南(contributing guide)[10]。
CVXPY 是一个社区驱动的项目,由众多研究者和工程师共同开发、维护与完善。
主要维护者包括:
此外,长期以来对项目有重要贡献的人员还包括:
Stephen Boyd、Eric Chu、Robin Verschueren、Jaehyun Park、Enzo Busseti、AJ Friend、Judson Wilson、Chris Dembia、William Zhang 等。
更多关于团队及管理流程的信息,请参阅 文档governance document[11]。

下面的代码展示了如何在 CVXPY 中求解一个简单的优化问题[3]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import cvxpy as cp# 创建两个标量优化变量x = cp.Variable()y = cp.Variable()# 创建两个约束条件constraints = [x + y == 1, x - y >= 1]# 构造目标函数obj = cp.Minimize((x - y)**2)# 构造并求解问题prob = cp.Problem(obj, constraints)prob.solve() # 返回最优值print("status:", prob.status)print("optimal value", prob.value)print("optimal var", x.value, y.value)
输出:
1 2 3 status: optimaloptimal value 0.999999999761optimal var 1.00000000001 -1.19961841702e-11
由求解方法返回的 status 值为 “optimal”,表示该问题已成功求解。最优值(即这里的 1)表示在遵守约束条件的前提下,目标函数的最小值。最后输出的是实现该最优解的变量值(此例中,x ≈ 1,y ≈ 0)。
prob.solve() 会返回最优值,并更新 prob.status,prob.value,以及问题中所有变量的 value 属性。问题对象是不可变的(immutable),也就是说,一旦创建便不能修改。若要更改目标函数或约束,需要创建一个新的问题对象。
1 2 3 4 5 6 7 8 # 替换目标函数prob2 = cp.Problem(cp.Maximize(x + y), prob.constraints)print("optimal value", prob2.solve())# 替换约束条件 (x + y == 1)constraints = [x + y <= 3] + prob2.constraints[1:]prob3 = cp.Problem(prob2.objective, constraints)print("optimal value", prob3.solve())
输出:
1 2 optimal value 1.0optimal value 3.00000000006
如果问题不可行(infeasible)或无界(unbounded),status 字段分别设为 "infeasible" 或 "unbounded"。在这种情况下,变量的值不会被更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import cvxpy as cpx = cp.Variable()# 一个不可行的问题prob = cp.Problem(cp.Minimize(x), [x >= 1, x <= 0])prob.solve()print("status:", prob.status)print("optimal value", prob.value)# 一个无界的问题prob = cp.Problem(cp.Minimize(x))prob.solve()print("status:", prob.status)print("optimal value", prob.value)
输出:
1 2 3 4 status: infeasibleoptimal value infstatus: unboundedoptimal value -inf
注意,对于一个最小化问题:
inf-inf而对于最大化问题则相反。如果求解器成功但精度低于期望,状态会反映这种“低精度”情形,包括:
optimal_inaccurateunbounded_inaccurateinfeasible_inaccurate对于这些情况,变量仍会被更新为相应的解。
若求解器完全失败,CVXPY 会抛出 SolverError 异常。此时应尝试其他求解器(参见“求解器”部分的详细讨论)。
CVXPY 提供以下常量作为状态字符串的别名:
判断问题是否成功求解,可使用:
1 prob.status == OPTIMAL
INFEASIBLE_OR_UNBOUNDED 状态较罕见,表示求解器只能确定问题要么不可行、要么无界,但无法辨别具体是哪种情况。此时可以通过将目标函数改为常数(例如 cp.Minimize(0))重新求解:
INFEASIBLE_OR_UNBOUNDED,原问题为不可行;OPTIMAL,则原问题为无界。变量可为标量、向量或矩阵,即分别为 0、1、2 维。
1 2 3 4 5 6 7 8 9 10 11 # 标量变量a = cp.Variable()# 向量变量(长度 5)x = cp.Variable(5)# 列向量(维度为 (5, 1))x = cp.Variable((5, 1))# 矩阵变量(维度为 (4, 7))A = cp.Variable((4, 7))
你可以使用任意数值库构造向量与矩阵常量,如 NumPy 的 ndarray 或 SciPy 稀疏矩阵等。
CVXPY 支持下列类型作为常量:
示例如下(带向量和矩阵的优化问题):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 解一个有界最小二乘问题import cvxpy as cpimport numpy as npm = 10n = 5numpy.random.seed(1)A = np.random.randn(m, n)b = np.random.randn(m)x = cp.Variable(n)objective = cp.Minimize(cp.sum_squares(A @ x - b))constraints = [0 <= x, x <= 1]prob = cp.Problem(objective, constraints)print("Optimal objective value", prob.solve())print("Optimal variable value")print(x.value) # 一个 NumPy 向量
输出:
1 2 3 Optimal objective value 4.14133859146Optimal variable value[ -5.11480673e-21 6.30625742e-21 0.134643668 0.124976681 -4.79039542e-21]
如上例所示,你可以用 ==, <=, >= 构造约束。无论是标量、向量还是矩阵,等式与不等式约束皆逐项作用。例如,0 <= x 与 x <= 1 表示 x 的每个元素都在 0 到 1 之间。
若要表示半正定矩阵约束,请参照“半正定矩阵”部分。
不能使用 < 或 > 构造严格不等式,因为在现实问题中没有意义;也不能链式写约束(如 0 <= x <= 1),Python 解释器不会让 CVXPY 捕获该结构。
参数是常量的符号化表示。通过参数能改变问题中常量的值,而无需重建整个问题。这种机制能显著加速重复求解过程(参阅 Disciplined Parametrized Programming 相关教程)。
定义参数时,可指定其属性(非负、非正、对称等)。参数创建后可被赋值,但其维度及属性必须与初始化时一致。
1 2 3 4 5 6 7 8 9 # 非负标量参数m = cp.Parameter(nonneg=True)# 含未知符号的列向量参数c = cp.Parameter(5)# 含非正元素的矩阵参数G = cp.Parameter((4, 7), nonpos=True)G.value = -np.ones((4, 7))
参数可在创建时赋初值:
1 2 3 4 5 # 两种等效方式rho = cp.Parameter(nonneg=True)rho.value = 2rho = cp.Parameter(nonneg=True, value=2)
一个典型用例是计算 LASSO 问题的正则化折衷曲线:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import cvxpy as cpimport numpy as npimport matplotlib.pyplot as pltn = 15m = 10np.random.seed(1)A = np.random.randn(n, m)b = np.random.randn(n)gamma = cp.Parameter(nonneg=True)x = cp.Variable(m)error = cp.sum_squares(A @ x - b)obj = cp.Minimize(error + gamma * cp.norm(x, 1))prob = cp.Problem(obj)sq_penalty = []l1_penalty = []x_values = []gamma_vals = np.logspace(-4, 6)for val in gamma_vals: gamma.value = val prob.solve() sq_penalty.append(error.value) l1_penalty.append(cp.norm(x, 1).value) x_values.append(x.value)plt.figure(figsize=(6,10))plt.subplot(211)plt.plot(l1_penalty, sq_penalty)plt.xlabel(r'\|x\|_1', fontsize=16)plt.ylabel(r'\|Ax-b\|^2', fontsize=16)plt.title('LASSO 折衷曲线', fontsize=16)plt.subplot(212)for i in range(m): plt.plot(gamma_vals, [xi[i] for xi in x_values])plt.xscale('log')plt.xlabel(r'\gamma', fontsize=16)plt.ylabel(r'x_{i}', fontsize=16)plt.title(r'x_i 与 \gamma 的关系', fontsize=16)plt.tight_layout()plt.show()
此外,可使用多进程并行地计算多个参数取值下的解:
1 2 3 4 5 6 7 8 9 from multiprocessing import Pooldef get_x(gamma_value): gamma.value = gamma_value result = prob.solve() return x.valuepool = Pool(processes=1)x_values = pool.map(get_x, gamma_vals)
可以为表达式和约束条件设置自定义标签,以便调试和模型解释。通过 set_label() 或 .label 属性赋予标签。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import cvxpy as cpimport numpy as npweights = cp.Variable(3, name="weights")constraints = [ (weights >= 0).set_label("non_negative_weights"), (cp.sum(weights) == 1).set_label("budget_constraint"), (weights <= 0.4).set_label("concentration_limits")]mu = np.array([0.08, 0.10, 0.07])Sigma = np.array([[0.10, 0.02, 0.01], [0.02, 0.08, 0.03], [0.01, 0.03, 0.09]])expected_return = (mu @ weights).set_label("expected_return")risk = cp.quad_form(weights, Sigma).set_label("risk")objective = cp.Minimize(risk - 0.5 * expected_return)problem = cp.Problem(objective, constraints)print(problem.format_labeled())
输出:
1 2 3 4 minimize risk + -0.5 @ expected_returnsubject to non_negative_weights: 0.0 <= weights budget_constraint: Sum(weights, None, False) == 1.0 concentration_limits: weights <= 0.4
标签是动态的,可在建模后修改:
1 2 risk.label = "portfolio_risk"print(problem.format_labeled())
输出:
1 2 3 4 minimize portfolio_risk + -0.5 @ expected_returnsubject to non_negative_weights: 0.0 <= weights budget_constraint: Sum(weights, None, False) == 1.0 concentration_limits: weights <= 0.4

公众号《博優旮旯-BOYOGALA》[12],致力于让大家更专业、更完整和更系统地获取与了解数学(运筹与优化、数值分析)等相关数学知识分享!
🎯公众号ID:boyogala,🌐网址: www.boyogala.us.kg[13],💬微信: boyougala,📧邮箱: boyogala@qq.com[14].
说明文档:公众号《博優旮旯-boyogala》的使用指南,以下罗列代表作可供查阅.
优化求解器 — 代表作:优化求解器类型总结线性二次和非线性求解器,Ipopt开源免费的非线性求解器,HiGHS开源免费整数线性求解器,SCIP开源免费的优化求解器,Gurobi商业收费全局优化求解器,CPLEX商业收费整数优化求解器,MOSEK商业收费的优化求解器,BARON商业收费的全局优化求解器,LindoAPI商业收费的全局优化求解器,COPT国产自研的优化求解器
三大数学软件 — 代表作:MATLAB工程师的科学计算软件,MATHEMATICA物理的计算软件,MAPLE数学家的数学软件
嵌入式、无人机和机器人 — 代表作:OSQP二次规划求解器
线性方程组的求解软件 — 代表作:PARDISO并行直接求解器,MUMPS高性能并行求解器,SuitSparse稀疏矩阵软件包,SuperLU非对称直接法求解器
基于MATLAB的优化建模工具 — 代表作:CVX免费凸优化建模工具,Yalmip免费的优化建模工具,CasADi开源最优化控制工具
基于Python的优化建模工具 — 代表作:CasADi非线性优化和最优控制,Gekko数值优化和动态系统建模,Pyomo面向对象代数建模语言
科学计算软件 — 代表作:oneAPI统一的异构编程模型,CUDA人工智能时代的基石,OpenFOAM开源的CFD软件,COMSOL业界多物理场仿真软件
全球优化建模平台 — 代表作:AMPL数学规划建模语言,AIMMS快速优化建模工具,GAMS通用代数建模系统,JuMP数学优化建模语言(学习中…)
人类在思考 — 代表作:公众号排版数学公式的经验,200篇论文🆚1个优化求解器,盗版Windows系统🆚破解版LINGO18
数学是第三世界 — 代表作:数学研究需要师徒传承吗?函数梯度的可视化
[1] 国产学术免费的求解器: https://www.shanshu.ai/copt[2] Installation Guide(安装指南): https://www.cvxpy.org/install/index.html[3] 官方 CVXPY 教程(official tutorial): https://www.cvxpy.org/tutorial/index.html[4] 示例库(example library): https://www.cvxpy.org/examples/index.html[5] API 参考文档(API reference): https://www.cvxpy.org/api_reference/cvxpy.html[6] Discord: https://discord.gg/4urRQeGBCr[7] GitHub Discussions: https://github.com/cvxpy/cvxpy/discussions[8] GitHub Issues: https://github.com/cvxpy/cvxpy/issues[9] 行为准则(code of conduct): https://github.com/cvxpy/cvxpy/blob/master/CODE_OF_CONDUCT.md[10] 贡献指南(contributing guide): https://github.com/cvxpy/cvxpy/blob/master/CONTRIBUTING.md[11] 文档governance document: https://github.com/cvxpy/org/blob/main/governance.md[12] 《博優旮旯-BOYOGALA》: https://www.cardopt.cn/api/images/1_1763724698_ce344a.png[13] www.boyogala.us.kg: http://www.boyogala.us.kg[14] boyogala@qq.com: mailto:boyogala@qq.com