2.1 CVXPY 和 SciPy 简介
本节主要介绍如何使用 Python 解决基础的数学优化问题。我们将对比使用两种常见工具:
CVXPY:一个强大的凸优化建模语言。它能让我们以高度接近数学公式的形式直观地建立模型。使用 CVXPY 往往包含以下四个核心步骤:
定义优化变量 (Variables)
设定目标函数 (Objective)
添加严格的约束条件 (Constraints)
构建并求解问题 (Problem)
SciPy (
scipy.optimize):Python 中通用的科学计算与数值优化库。与 CVXPY 的声明式建模略有不同,它需要我们将优化的目标和约束条件分别封装成标准的 Python 函数,并手动提供一个初始猜测值(Initial Guess)以供求解器进行数值迭代寻优。
官方参考资料¶
# 导入cvxpy 和 numpy
import cvxpy as cp
import numpy as np例子1:某个有限制的最小二乘问题¶
# 创建优化变量
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("求解状态:", prob.status)
print("最优值:", f"{prob.value:.4f}" if prob.value is not None else None)
print("最优变量 x, y:",
f"{x.value:.4f}" if x.value is not None else None,
f"{y.value:.4f}" if y.value is not None else None)求解状态: optimal
最优值: 1.0000
最优变量 x, y: 1.0000 0.0000
对于同一个问题,我们可以写成向量的形式¶
# 创建优化变量
x = cp.Variable(2)
# 创建限制条件
a = np.array([1, -1])
b = np.array([1, 1])
constraints2 = [b @ x == 1, a @ x >= 1]
# 创建目标函数
obj2 = cp.Minimize(cp.sum_squares(a @ x))
# 创建优化问题
prob2 = cp.Problem(obj2, constraints2)
prob2.solve()
# 输出结果
print("求解状态:", prob2.status)
print("最优值:", f"{prob2.value:.4f}" if prob2.value is not None else None)
print("最优变量 向量 x:", np.round(x.value, 4) if x.value is not None else None)求解状态: optimal
最优值: 1.0000
最优变量 向量 x: [1. 0.]
例子2:无可行解问题¶
x = cp.Variable()
prob = cp.Problem(cp.Minimize(x), [x >= 1, x <= 0])
prob.solve()
print("求解状态:", prob.status)
print("最优值:", f"{prob.value:.4f}" if isinstance(prob.value, (int, float)) else prob.value)
print("最优变量 x:", f"{x.value:.4f}" if x.value is not None else None)求解状态: infeasible
最优值: inf
最优变量 x: None
例子3:目标函数的值无边界¶
x_unbounded = cp.Variable()
prob = cp.Problem(cp.Minimize(x_unbounded))
prob.solve()
print("求解状态:", prob.status)
print("最优值:", f"{prob.value:.4f}" if isinstance(prob.value, (int, float)) else prob.value)
print("最优变量 x:", f"{x_unbounded.value:.4f}" if x_unbounded.value is not None else None)求解状态: unbounded
最优值: -inf
最优变量 x: None
使用 scipy.optimize 求解上面的问题1¶
除了 CVXPY,我们也可以使用 SciPy 的核心优化模块 scipy.optimize.minimize 来进行同样的求解。由于 scipy.optimize.minimize 是通用的数值优化库(不同于基于建模的凸优化库),我们需要手动将数学模型转化为函数:这包含目标函数、约束函数定义,以及初始猜测值。
from scipy.optimize import minimize
# 1. 定义目标函数:f(x, y) = (x - y)^2
def objective(vars):
x, y = vars
return (x - y)**2
# 2. 定义约束条件
# 等式约束: x + y == 1 => 转为等于0形式: x + y - 1 = 0
def eq_constraint(vars):
x, y = vars
return x + y - 1
# 不等式约束: x - y >= 1 => 转为大于等于0形式: x - y - 1 >= 0
def ineq_constraint(vars):
x, y = vars
return x - y - 1
# 定义 SciPy 求解器所需的约束字典格式
constraints_scipy = [
{'type': 'eq', 'fun': eq_constraint},
{'type': 'ineq', 'fun': ineq_constraint}
]
# 3. 提供迭代搜索的初始猜测值 (Initial guess)
x0 = [0.0, 0.0]
# 4. 求解问题
res = minimize(objective, x0, constraints=constraints_scipy)
# 输出结果
print("求解状态 (成功):", res.success)
print("详细信息:", res.message)
if res.success:
print("最优值:", f"{res.fun:.4f}")
print("最优变量 x:", f"{res.x[0]:.4f}")
print("最优变量 y:", f"{res.x[1]:.4f}")求解状态 (成功): True
详细信息: Optimization terminated successfully
最优值: 1.0000
最优变量 x: 1.0000
最优变量 y: -0.0000