非线性规划——凸优化、凸函数、凸规划(二)
凸规划是指若最优化问题的目标函数为凸函数,不等式约束函数也为凸函数,等式约束函数是线性的。凸规划的可行域为凸集,因而凸规划的局部最优解就是它的全局最优解。当凸规划的目标函数为严格凸函数时,若存在最优解,则这个最优解一定是唯一的最优解。
一、凸集
凸集:设为维欧式空间的一个集合,若内任意两点间的线段也均在内,则称集合为凸集。即
凸组合(convex combination):
其中,,二元 就是一个凸组合。

凸集有良好的运算性质:(1) 交集为凸集。(2) 和集为凸集。(3) 直和为凸集。
超平面hyperplane:;
半平面halfspace:;
多面体polyhedra:多个线性不等式所刻画的集合:
注:线性等式刻画的集合也是多面体!(可以将等式转换为两个不等式,线性规划里称为单纯形)
椭球(Ellipsoid):
二、凸函数
设为定义在区间上的函数,若对上的任意两点和任意有
将""换成""也成立则就是严格凸函数。
性质1: 设 ,是凸集,若是凸函数,则对于任意的,水平集是凸集。
性质2 : 凸优化问题的局部极小值是全局极小值。
性质3: 若一阶可微,则函数为凸函数当且仅当的定义域为凸集,且。
性质4:若二阶可微,则函数为凸函数当且仅当的定义域为凸集,且。
正定:,(所有的二次齐次式都可以写成这个形式)如果对任意的,则称为正定二次型,同时称为正定矩阵。
[定理] 设是在凸集上二阶可微。是凸函数的充分必要条件是的二阶海塞矩阵是半正定的;是凹函数的充分必要条件是的二阶海塞矩阵是半负定的。
例1:判断下述函数的凸凹性:
(1)
(2)
(3)
解:
(1) , 所以 函数是凸集 上的的凸函数.
(2) , 所以 函数是凸集 上的的凹函数.
(3) 的 Hessian 矩阵为:
为了判断 的半正 (负) 定性, 计算:
那么, , 所以矩阵 为负定矩阵, 为凸集 上的凹函数.
三、凸规划
基本形式:
[定理] 上面规划是凸规划的充分条件为:(1)是凸函数;(2), 都是线性函数;(3), 都是凸函数(是凹函数)。
例2:判断下述规划是否为凸规划
解:
该问题是凸规划,有最小值,,参看下图。
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
# 定义目标函数
def objective(X):
x1, x2 = X
return x1**2 + x2**2 - 4*x1 + 4
# 定义约束函数
def constraint1(X):
return -X[0] + X[1] - 2
def constraint2(X):
return X[0]**2 - X[1] + 1
# 初始猜测值
initial_guess = [0.5, 0.5]
# 定义约束
constraints = [
{'type': 'ineq', 'fun': constraint1},
{'type': 'ineq', 'fun': constraint2},
{'type': 'ineq', 'fun': lambda X: X[0]}, # x1 >= 0
{'type': 'ineq', 'fun': lambda X: X[1]} # x2 >= 0
]
# 记录迭代点
history = []
def callback(X):
history.append(np.copy(X))
# 进行优化
result = minimize(objective, initial_guess, method='SLSQP', constraints=constraints, callback=callback)
# 打印优化结果
print("Optimization Result:")
print(f"Success: {result.success}")
print(f"Minimum Value of the Function: {result.fun:.2f}")
print(f"Point at which Minimum Occurs: x1 = {result.x[0]:.2f}, x2 = {result.x[1]:.2f}")
print(f"Number of Iterations: {result.nit}")
# 生成等高线图
x1 = np.linspace(-1, 3, 400)
x2 = np.linspace(-1, 5, 600)
X1, X2 = np.meshgrid(x1, x2)
Z = X1**2 + X2**2 - 4*X1 + 4
plt.figure(figsize=(15, 9))
cp = plt.contour(X1, X2, Z, levels=np.logspace(-1, 3, 20), cmap='jet', linewidths=1.5)
plt.colorbar(cp)
# 绘制约束边界
x1_vals = np.linspace(0, 3, 400)
x2_g1 = x1_vals + 2
x2_g2 = x1_vals**2 + 1
plt.plot(x1_vals, x2_g1, 'r--', label='$g_1(x_1, x_2) = 0$', linewidth=1.5)
plt.plot(x1_vals, x2_g2, 'g--', label='$g_2(x_1, x_2) = 0$', linewidth=1.5)
# 绘制可行域
plt.fill_between(x1_vals, np.maximum(x2_g1, 0), 5, color='gray', alpha=0.3)
# 绘制优化路径
history = np.array(history)
plt.plot(history[:, 0], history[:, 1], 'ro-', label='Optimization Path', markersize=5, linewidth=1.5)
plt.plot(result.x[0], result.x[1], 'wo', label='Minimum', markersize=14, markeredgewidth=3, markeredgecolor='black')
# 设置图形参数
plt.title("Contour Plot with Optimization Path")
plt.xlabel('$x_1$')
plt.ylabel('$x_2$')
plt.legend()
plt.xlim(-1, 3)
plt.ylim(-1, 5)
plt.grid()
plt.show()
Optimization Result:
Success: True
Minimum Value of the Function: 13.24
Point at which Minimum Occurs: x1 = 1.62, x2 = 3.62
Number of Iterations: 7
例3:判断下述规划是否为凸规划
目标函数的凸性
一个函数是凸的,当且仅当其 Hessian 矩阵(即二阶偏导数矩阵)是半正定的。计算目标函数的 Hessian 矩阵:
计算各二阶偏导数:
因此,Hessian 矩阵为:
计算 Hessian 矩阵的特征值来判断其是否为半正定。使用 NumPy 进行计算:
import numpy as np
H = np.array([
[4, -1, 1],
[-1, 2, 0],
[1, 0, 4]
])
# 计算特征值
eigenvalues = np.linalg.eigvals(H)
print("Hessian Matrix Eigenvalues:", eigenvalues)
如果所有特征值均为非负,则 Hessian 矩阵为半正定,即目标函数为凸函数。
约束条件的凸性
约束条件为等式约束,需要检查其是否为仿射函数(即线性函数和常数项的和)。一个仿射函数既是凸函数也是凹函数。
—— 非线性函数,不是仿射函数,因此可能不是凸函数。
—— 线性函数,是仿射函数,因此是凸函数。
—— 线性函数,是仿射函数,因此是凸函数。
由于 是非线性函数,我们需要检查其 Hessian 矩阵是否为半正定。计算 的 Hessian 矩阵:
这个矩阵的特征值是 ,均为非负,因此 也是凸函数。
结论
- 目标函数的 Hessian 矩阵是否为半正定需要通过特征值检查。
- 约束条件 为凸函数(Hessian 矩阵半正定)。
- 约束条件 和 为仿射函数,因此是凸函数。
通过上述分析,目标函数和所有约束条件均为凸函数,这意味着该非线性规划问题是一个凸规划问题。
#求解x1 = 2.67;x2 = 2.67;x3 = 5.33,最小化目标函数值: 93.33
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from scipy.optimize import minimize
# 定义目标函数
def objective(x):
x1, x2, x3 = x
return 2*x1**2 + x2**2 + 2*x3**2 + x1*x3 - x1*x2 + x1 + 2*x2
# 定义约束条件
def constraint1(x):
x1, x2, x3 = x
return x1**2 + x2**2 - x3
def constraint2(x):
x1, x2, x3 = x
return x1 + x2 + 2*x3 - 16
def constraint3(x):
x1, x2, x3 = x
return -x1 - x2 + x3
# 初始猜测
x0 = [0, 0, 0]
# 约束条件字典
cons = [{'type': 'eq', 'fun': constraint1},
{'type': 'eq', 'fun': constraint2},
{'type': 'eq', 'fun': constraint3}]
# 运行优化
solution = minimize(objective, x0, constraints=cons)
# 提取优化结果
x1_opt, x2_opt, x3_opt = solution.x
# 打印结果
print("最优解:")
print("x1 =", x1_opt)
print("x2 =", x2_opt)
print("x3 =", x3_opt)
print("最小化目标函数值:", objective(solution.x))
# 准备数据以进行绘制
x1 = np.linspace(-100, 100, 200)
x2 = np.linspace(-100, 100, 200)
x1, x2 = np.meshgrid(x1, x2)
x3 = (x1**2 + x2**2) # 从constraint1求解x3
# 计算目标函数值
h = 2*x1**2 + x2**2 + 2*x3**2 + x1*x3 - x1*x2 + x1 + 2*x2
h1 = x1**2 + x2**2 - x3
h2 = x1 + x2 + 2*x3 - 16
h3 = -x1 - x2 + x3
# 绘制图像
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# 绘制目标函数值
ax.plot_surface(x1, x2, h, color='r', alpha=0.3)
# 绘制约束条件
ax.plot_surface(x1, x2, h1, color='b', alpha=0.3)
ax.plot_surface(x1, x2, h2, color='g', alpha=0.3)
ax.plot_surface(x1, x2, h3, color='y', alpha=0.3)
# 标记最优解
ax.scatter(x1_opt, x2_opt, objective([x1_opt, x2_opt, x3_opt]), color='k', marker='o', s=100)
ax.set_xlabel('x1')
ax.set_ylabel('x2')
ax.set_zlabel('Objective function value')
plt.show()
例4:求Rosenbrock 香蕉函数的最小值
- 一阶偏导数
函数的梯度为:
其中:
将这些导数设为零得到临界点:
解这些方程得到:
- 海森矩阵
函数的海森矩阵为:
其中:
代入我们得到:
- 判断其是否为正定矩阵
首先,我们检查海森矩阵是否对称,它是。然后我们检查它是否满足正定矩阵的任意一个定理。对于2x2矩阵,我们可以通过行列式来判断:
- 求最小值
上面求了半天只求了局部极小值。
局部极小值并不一定是最小值,极大值也不一定大于极小值,可以通过求出所有的极值,选择其中最小的就是最小值。
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
# 定义Rosenbrock's banana function
def rosenbrock_banana(x):
return (2 - x[0])**2 + 100 * (x[1] - x[0]**2)**2
# 定义函数以记录每次迭代的点
history = []
def callback(xk):
history.append(np.copy(xk))
# 初始猜测值
initial_guess = [0, 0]
# 使用BFGS算法进行优化,并记录迭代过程
result = minimize(rosenbrock_banana, initial_guess, method='BFGS', callback=callback)
# 打印优化结果
print("Optimization Result:")
print(f"Success: {result.success}")
print(f"Minimum Value of the Function: {result.fun:.2f}")
print(f"Point at which Minimum Occurs: x = {result.x[0]:.2f}, y = {result.x[1]:.2f}")
print(f"Number of Iterations: {result.nit}")
# 生成函数的等高线图
x = np.linspace(-1, 3, 400)
y = np.linspace(-1, 5, 600)
X, Y = np.meshgrid(x, y)
Z = rosenbrock_banana([X, Y])
plt.figure(figsize=(10, 6))
cp = plt.contour(X, Y, Z, levels=np.logspace(-1, 3, 20), cmap='jet')
plt.colorbar(cp)
plt.plot([x[0] for x in history], [x[1] for x in history], 'ro-', label='Optimization Path', markersize=5)
plt.plot(result.x[0], result.x[1], 'wo', label='Minimum', markersize=12, markeredgewidth=2, markeredgecolor='black')
plt.title("Contour Plot of Rosenbrock's Banana Function with Optimization Path")
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.xlim(-1, 3)
plt.ylim(-1, 5)
plt.show()
Optimization Result:
Success: True
Minimum Value of the Function: 0.00
Point at which Minimum Occurs: x = 2.00, y = 4.00
Number of Iterations: 30
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!