非线性规划
原创
发布时间:2026-06-15 | 更新时间:2026-06-15
现实生活中,有些问题是非线性的,这就是非线性规划(Nonlinear Programming)
(关于基础概念和符号定义请看前文线性规划(Linear Programming))
现实例子#
老王是一名农夫,他想紧靠着屋墙围出一块长方形的地方养鸡。
他想围出尽可能大的地方,而手头上只有 8 米的篱笆,靠墙一侧不需要围栏。
请问他该如何设计长方形的边长才能围出最大面积的围栏?
数学表达#
问题拆解如下:
-
决策变量:设长方形靠墙的一边为长,长为 $x$ 米,宽为 $y$ 米,因为面积为 $xy$,所求就是 $argmax_{x,y}\left(xy\right)$
-
目标函数:求面积的最大值(max),即 $max(xy)$
-
约束条件:$x+2y=8$,$x \gt 0$,$y \gt 0$
完整的数学表达为:$argmax_{x,y} \left(xy\right) \quad s.t. \quad x+2y=8, x>0, y>0$
因为目标函数为 $xy$,次数高于1,所以是非线性规划
数学求解#
整理约束条件 $x+2y=8$ 得
\[ x=8-2y \]代入目标函数得
\[ xy=(8-2y)y=-2y^2+8y \]函数 $f(y)=-2y^2+8y$ 的图像是一条开口向下的抛物线
求这个函数的导数并让其等于 0 即可计算出抛物线的最值(因为开口向下,所以一定是最大值)
$f^’(y)=-2 \times 2y+8=0$ 得 $y=2$
当 $y=2$ 时,
$f(y) = -2y^2 + 8y = 8$
$x=8-2y=4$
也就是当长方形的长为 4 米,宽为 2 米时,鸡圈可达到最大面积 8 平方米。
程序求解#
方法一:利用 Scipy#
Scipy 有一个 minimize 模块,可以很方便计算出非线性规划的最优解
# pip install scipy
from scipy.optimize import minimize
import numpy as np
# 最小化目标函数:我们要最大化 xy,等价于最小化 -xy
def objective(x):
return - (x[0] * x[1]) # x[0]=x, x[1]=y
# 等式约束:x + 2y = 8
def constraint(x):
return x[0] + 2 * x[1] - 8
# 约束条件定义
cons = ({'type': 'eq', 'fun': constraint})
# 变量边界:x>0, y>0
bounds = ((1e-6, None), (1e-6, None)) # 用极小值代替严格>0
# 初始值(随便给一个满足约束的点)
x0 = np.array([2, 3])
# 求解
result = minimize(objective, x0, method='SLSQP', bounds=bounds, constraints=cons)
# 输出结果
print("求解状态:", result.success)
print("最优解 x =", round(result.x[0], 4))
print("最优解 y =", round(result.x[1], 4))
print("最大值 xy =", round(-result.fun, 4))输出
求解状态: True
最优解 x = 4.0
最优解 y = 2.0
最大值 xy = 8.0方法一:利用 CVXPY#
通过 CVXPY 库也可以计算这种非线性规划问题,以更直观的方式通过表达式描述问题
# pip install cvxpy
import cvxpy as cp
# 定义变量
x = cp.Variable(nonneg=True)
y = cp.Variable(nonneg=True)
# 目标函数
objective = cp.Maximize(x * y)
# 约束
constraints = [x + 2*y == 8]
# 构建问题
prob = cp.Problem(objective, constraints)
# 必须指定 solver=cp.SCS 且 qcp=True
prob.solve(qcp=True, solver=cp.SCS)
# 输出结果
print("最优解 x =", round(x.value, 4))
print("最优解 y =", round(y.value, 4))
print("最大值 xy =", round(prob.value, 4))输出
最优解 x = 4.0
最优解 y = 2.0
最大值 xy = 8.0