Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

2.1 CVXPY 和 SciPy 简介

本节主要介绍如何使用 Python 解决基础的数学优化问题。我们将对比使用两种常见工具:

  1. CVXPY:一个强大的凸优化建模语言。它能让我们以高度接近数学公式的形式直观地建立模型。使用 CVXPY 往往包含以下四个核心步骤:

    • 定义优化变量 (Variables)

    • 设定目标函数 (Objective)

    • 添加严格的约束条件 (Constraints)

    • 构建并求解问题 (Problem)

  2. 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