数学建模系列文章:
以下是个人在准备数模国赛时候的一些模型算法和代码整理,有空会不断更新内容:
评价模型(一)层次分析法(AHP),熵权法,TOPSIS分析 及其对应 PYTHON 实现代码和例题解释
评价模型(二)主成分分析、因子分析、二者对比及其对应 PYTHON 实现代码和例题解释
优化模型(零)总述,分类,解析各类优化模型及普适做题步骤
优化模型(一)线性规划详解,以及例题,用python的Pulp库函数求解线性规划
优化模型(二)非线性规划详解,以及例题,Scipy.optimize 求解非线性规划
3.3 Scipy.optimize 求解非线性规划
非线性规划概述:
当目标函数f(x)或者约束条件中有一个是决策变量X的非线性表达式,那么此时的数学规划问题就属于非线性规划。解决非线性规划要比线性规划困难的多,目前没有通用算法,大多数算法都是在选定决策变量的初始值后,通过一定搜索算法寻求最优的决策变量。而本文使用的方法是基于Scipy库的一些个函数进行求解。
scipy求解流程–编程步骤说明:
- 导入 scipy、numpy 包;
- 定义目标函数 objf3(x),输入变量 x 表示向量,返回值 fx 是目标函数的计算结果 。 默认是min(若求max,加负号,-min)
- 定义边界约束,即优化变量的上下限:
- minimize() 默认无边界约束条件,即各自变量的取值范围没有限制;
- 如果设置边界约束,要对每个自变量(决策变量)定义其上下限,注意定义边界约束的格式;
- 如果某个自变量没有上限(下限),则表示为 None 。
定义 x 的初值。- 求解最小化问题 resRosen,其中目标函数 objf3 和搜索的初值点 xIni 是必需的,指定优化方法和边界条件是可选项。如果优化问题是求最大值 maxFx,可以通过 minFx = - maxFx 的变换来实现。
- 通过调用最小化问题的返回值 resRosen.x 得到最优点 xOpt。
Scipy.optimize
的一些参数解释:
minimize(fun,x0,method,bounds,constraints)
求解最小化函数
fun
: 第一步定义的目标函数;
x0
: 猜测解or初始解,列表或元组形式,一般是N 维数组对象ndarray;;
method
: 一般填’SLSQP’(序贯最小二乘规划);
bounds
: 变量边界/取值范围; b0 = (0.0, None) # 0.0 <= x[0] <= Inf None == 无穷
constraints
: (约束条件)在前面定义,在此处调用。
jac
:可选**,**目标函数的雅可比矩阵(目标函数的一阶偏导)。这些方法会用到: CG, BFGS, Newton-CG, L-BfFGS-B, TNC, SLSQP, dogleg, trust-ncg;
cons
: 限制函数 cons = ({‘type’:‘eq’,‘fun’: lambda x:f(x)})
cons = ({‘type’:‘eq’,‘fun’: lambda x: x[0]*x[1]*x[2]-12})
type
: 约束条件的类型eq
是等式ineq
是不等式 。
lambda
: 是约束函数表达式,默认是将变量提取到左边 ,符号是>=
的不等式 例如lambda x: x[0]*x[1]*x[2]-12
表示x*y*z>=12
;如果需要<=
则提取一个负号即可,比如这个-(x*y*z)>=-12
表示(x*y*z)
<= 12,如果不取等的话,直接加上一个十分小的数即可比如1e-20。比如lambda x:x[0]*x[1]*x[2]-12-1e-20
可约等于x*y*z>12
代码说明一:
from scipy.optimize import brent, fmin, minimize
import numpy as np
# 多变量边界约束优化问题(Scipy.optimize.minimize)
# 定义目标函数
def objf3(x): # Rosenbrock 测试函数
fx = x[0]+2*x[1]+3*x[2]+1
return fx
cons = ({
'type':'eq','fun': lambda x: x[0]*x[1]*x[2]-12})
# 定义没一个变量边界约束(优化变量的上下限)
b0 = (0.0, None) # 0.0 <= x[0] <= Inf
b1 = (0.0, None) # 0.0 <= x[1] <= Inf
b2 = (0.0, None) # 0.0 <= x[2] <= Inf
bnds = (b0, b1, b2) # 边界约束
# 优化计算
xIni = np.array([1., 2., 3.]) # 定义初始值
resRosen = minimize(objf3, xIni, method='SLSQP',constraints = cons ,bounds=bnds)
xOpt = resRosen.x
print("xOpt = {:.4f}, {:.4f}, {:.4f}".format(xOpt[0],xOpt[1],xOpt[2]))
print("min f(x) = {:.4f}".format(objf3(xOpt)))
代码说明二:
求解下列优化函数:
from scipy.optimize import brent, fmin, minimize
import numpy as np
# 约束非线性规划问题(Scipy.optimize.minimize)
def objF6(args): # 定义目标函数
a,b,c,d = args
fx = lambda x: a*x[0]**2 + b*x[1]**2 + c*x[2]**2 + d
return fx
def constraint2(args):
xmin0, xmin1, xmin2 = args
cons = ({
'type': 'ineq', 'fun': lambda x: (x[0]**2 - x[1] + x[2]**2)}, # 不等式约束 f(x)>=0
{
'type': 'ineq', 'fun': lambda x: -(x[0] + x[1]**2 + x[2]**3 - 20)}, # 不等式约束 转换为标准形式
{
'type': 'eq', 'fun': lambda x: (-x[0] - x[1]**2 + 2)}, # 等式约束
{
'type': 'eq', 'fun': lambda x: (x[1] + 2*x[2]**2 - 3)}, # 等式约束
{
'type': 'ineq', 'fun': lambda x: (x[0] - xmin0)}, # x0 >= xmin0
{
'type': 'ineq', 'fun': lambda x: (x[1] - xmin1)}, # x1 >= xmin1
{
'type': 'ineq', 'fun': lambda x: (x[2] - xmin2)}) # x2 >= xmin2
return cons
# 求解优化问题
args1 = (1,2,3,8) # 定义目标函数中的参数
args2 = (0.0, 0.0, 0.0) # xmin0, xmin1, xmin2
cons2 = constraint2(args2)
x0 = np.array([1., 2., 3.]) # 定义搜索的初值
res2 = minimize(objF6(args1), x0, method='SLSQP', constraints=cons2)
print("Optimization problem (res2):\t{}".format(res2.message)) # 优化是否成功
print("xOpt = {}".format(res2.x)) # 自变量的优化值
print("min f(x) = {:.4f}".format(res2.fun)) # 目标函数的优化值
约束条件也可以这样定义:
# 定义约束条件函数
def constraint1(x): # 不等式约束 f(x)>=0
return x[0]** 2 - x[1] + x[2]**2
def constraint2(x): # 不等式约束 转换为标准形式
return -(x[0] + x[1]**2 + x[2]**3 - 20)
def constraint3(x): # 等式约束
return -x[0] - x[1]**2 + 2
def constraint4(x): # 等式约束
return x[1] + 2*x[2]**2 -3
# 定义边界约束
b = (0.0, None)
bnds = (b, b, b)
# 定义约束条件
con1 = {
'type': 'ineq', 'fun': constraint1}
con2 = {
'type': 'ineq', 'fun': constraint2}
con3 = {
'type': 'eq', 'fun': constraint3}
con4 = {
'type': 'eq', 'fun': constraint4}
cons = ([con1, con2, con3,con4]) # 3个约束条件
参考文献: