最优化方法

日常工作中,解决同一个问题往往有多种方案,最优化方法这门数学分支帮助我们从这多种方案中找出最佳方案。本节介绍最优化方法中最基本的单变量最小化和线性规划。[大谦MATLAB,dqmatlab点com]

单变量最小化

单变量最小化可以单独解决对应的最优化问题,但更多的是作为更复杂最优化问题的基础进行使用。常用的单变量最小化算法有黄金分割法和Brent法等。下面结合一个实例介绍在MATLAB和Python中怎样求解单变量最小化问题。

对边长为3m的正方形铁板,在4个角处剪去相等的正方形以制成方形无盖水槽,问如何剪法使水槽的容积最大?

假设剪去的正方形的边长为x,则水槽的容积为

现在要求在区间(0,1.5)上确定一个x,使最大化。

【MATLAB】

MATLAB中使用最优化方法工具箱进行求解。因为优化工具箱中要求目标函数最小化,所以需要对目标函数进行转换,即要求最小化。

首先编写M文件fminbndtest.m:

code.matlab
function f=myfun(x)
f=- (3-2*x).^2 * x;

然后调用fminbnd函数:

在命令窗口键入下面的命令行:

code.matlab
>> x=fminbnd(@fminbndtest,0,1.5)
x =
    0.5000

即剪去的正方形的边长为0.5m时水槽的容积最大。

【Python】

Python中可以使用SciPy包进行求解。使用该包前需要先进行安装。在电脑连接互联网的情况下,在Power Shell窗口键入:

pip install scipy

进行安装。使用SciPy包中的optimize子包进行求解。

在Python IDLE Shell窗口键入下面的命令行,先定义计算目标函数的函数f:

code.python
>>> def f(x):
	return -(3-2*x)**2*x

然后从scipy.optimize子包中导入minimize_scalar函数进行求解。

code.python
>>> from scipy.optimize import minimize_scalar
>>> res=minimize_scalar(f,bounds=(0,1.5),method='bounded')
>>> res
     fun: -1.9999999999962486
 message: 'Solution found.'
    nfev: 10
  status: 0
 success: True
       x: 0.5000007907227136

即剪掉的正方形的边长为0.5m时水槽的容积最大。

线性规划

当描述问题的最优化模型中目标函数和约束函数都为线性时称为线性规划。MATLAB和Python的SciPy包都提供了linprog函数求解线性规划。下面结合两个示例进行介绍。

示例1

某厂生产甲、乙两种产品,已知制成一吨产品甲需用资源A 3吨,资源B 4m3;制成一吨产品乙需用资源A 2吨,资源B 6m3,资源C 7个单位。若一吨产品甲和乙的经济价值分别为7万元和5万元,三种资源的限制量分别为90吨、200m3和210个单位。试决定应生产这两种产品各多少吨才能使创造的总经济价值最高?

令生产产品甲的数量为x1,生产产品乙的数量为x2。由题意可以建立下面的模型:

Document Image

【MATLAB】

该模型要求使目标函数最大化,需要按照MATLAB的要求进行转换,即目标函数为

Document Image

首先输入下列系数,在命令窗口键入下面的命令行:

code.matlab
>> f=[-7; -5];  %目标函数
>> A=[3 2     %系数矩阵
      4 6
      0 7];
>> b=[90; 200; 210];  %右端项
>> lb=zeros(2,1);    %变量下界

然后调用linprog函数进行求解:

code.python
>> [x,fval,exitflag,output,lambda]=linprog(f,A,b,[ ],[ ],lb)
x =
   14.0000
   24.0000
fval =
   -218.0000
exitflag =
     1
output=
      iterations: 5
      algorithm: 'interior-point-legacy'
    cgiterations: 0
       message: 'Optimization terminated.'
    constrviolation: 0
      firstorderopt: 4.3909e-07
lambda=
    ineqlin: [3x1 double]
      eqlin: [0x1 double]
      upper: [2x1 double]
      lower: [2x1 double]

linprog函数返回的结果中,x表示问题的解,即生产产品甲14吨和产品乙24吨时目标最优;fval为最优解时目标函数的值,为218万元;exitflag等于1,表示模型收敛退出,解有效;output结构包含算法的迭代次数、算法名称等信息;lambda提供不等式约束、等式约束、变量上界和下界的大小和数据类型。

【Python】

Python中使用SciPy包optimize子包的linprog函数求解线性规划。在Python IDLE Shell窗口键入下面的命令行:

code.python
>>> from scipy.optimize import linprog
>>> c=[-7,-5]    #目标函数
>>> A=[[3,2],[4,6],[0,7]]    #不等式约束系数矩阵
>>> b=[90,200,210]    #不等式约束右端项
>>> x1_bounds=(0,None)    #变量1下界
>>> x2_bounds=(0,None)    #变量2下界
>>> linprog(c,A_ub=A,b_ub=b,bounds=[x1_bounds,x2_bounds])
     con: array([], dtype=float64)
     fun: -217.99999999808617
 message: 'Optimization terminated successfully.'
     nit: 5
   slack: array([7.24298843e-10, 3.20360982e-09, 4.20000000e+01])
  status: 0
 success: True
       x: array([14., 24.])

计算结果中,fun为最优解时目标函数的值,x表示最优解,message说明迭代成功收敛,nit表示迭代次数。由上可知,生产甲种产品14吨、乙种产品24吨可使创建的总经济价值最高。最高经济价值为218万元。

示例2

某车间有两台机床甲和乙,可用于加工3种工件。假定这两台机床的可用台时数分别为700和800,3种工件的数量分别为300,500和400,且已知用两台不同机床加工单位数量的不同工件所需的台时数和加工费用(如表18-1所示)。问怎样分配机床的加工任务,才能既满足加工工件的要求,又使总加工费用最低。

表18-1 机床加工情况表

机床类型 单位工作所需加工台时数 单位工作所需加工台时数 单位工作所需加工台时数 单位工件的加工费用 单位工件的加工费用 单位工件的加工费用 可用 台时数
机床类型 工件1 工件2 工件3 工件1 工件2 工件3 可用 台时数
0.4 1.1 1.0 13 9 10 700
0.5 1.2 1.3 11 12 8 800

设在甲机床上加工工件1,2和3的数量分别为x1,x2和x3,在乙机床上加工工件1,2和3的数量分别为x4,x5和x6。根据3种工件的数量限制,有

x1+x4=300 (对工件1)

x2+x5=500 (对工件2)

x3+x6=400 (对工件3)

再根据机床甲和乙的可用总台时限制,可以得到其他约束条件。以总加工费用最少为目标函数,组合约束条件,可以得到下面的数学模型:

Document Image

【MATLAB】

首先输入下列系数,在命令窗口键入下面的命令行:

code.matlab
>> f=[13;9;10;11;12;8];    %目标函数
>> A= [0.4  1.1  1  0  0  0    %不等式约束的系数矩阵
      0  0  0  0.5  1.2  1.3];
>> b=[700; 800];    %不等式约束的右端项
>> Aeq=[1 0 0 1 0 0    %等式约束的系数矩阵
     0 1 0 0 1 0
     0 0 1 0 0 1];
>> beq=[300 500 400];    %等式约束的右端项
>> lb=zeros(6,1);    %变量下界

然后调用linprog函数求解:

code.matlab
>> [x,fval,exitflag,output,lambda]=linprog(f,A,b,Aeq,beq,lb)
x =
    0.0000
  500.0000
    0.0000
  300.0000
    0.0000
  400.0000
fval =
  1.1000e+004
exitflag =
     1
output=
      iterations: 4
     algorithm: 'interior-point-legacy'
    cgiterations: 0
       message: 'Optimization terminated.'
lambda=
    ineqlin: [2x1 double]
      eqlin: [3x1 double]
      upper: [6x1 double]
      lower: [6x1 double]

可见,在甲机床上加工500个工件2,在乙机床上加工300个工件1、加工400个工件3可在满足条件的情况下使总加工费最小。最小费用为11000元。收敛正常。

【Python】

在Python IDLE Shell窗口键入下面的命令行:

code.python
>>> from scipy.optimize import linprog
>>> c=[13,9,10,11,12,8]    #目标函数
>>> A=[[0.4,1.1,1,0,0,0],[0,0,0,0.5,1.2,1.3]]    #不等式约束系数矩阵
>>> b=[700,800]    #不等式约束右端项
>>> Aeq=[[1,0,0,1,0,0],[0,1,0,0,1,0],[0,0,1,0,0,1]]    #等式约束系数矩阵
>>> beq=[300,500,400]    #等式约束右端项
>>> x1=x2=x3=x4=x5=x6=(0,None)    #变量下界
>>> linprog(c,A_ub=A,b_ub=b,A_eq=Aeq,b_eq=beq,bounds=[x1,x2,x3,x4,x5,x6])
     con: array([9.09767550e-09, 1.51902668e-08, 1.21495987e-08])
     fun: 10999.999999672584
 message: 'Optimization terminated successfully.'
     nit: 6
   slack: array([150.00000002, 130.00000002])
  status: 0
 success: True
       x: array([2.99006889e-09, 5.00000000e+02, 2.72538271e-10, 3.00000000e+02,
       1.41237420e-11, 4.00000000e+02])

可见,在甲机床上加工500个工件2,在乙机床上加工300个工件1、加工400个工件3可在满足条件的情况下使总加工费最小。最小费用为11000元。收敛成功。