问题:

已知6种国家排放标准的汽车目前的保有量、排放因子和升级成本(升级成本指的是低于该标准的每辆汽车升级到该标准的成本,例如:国6的升级成本为15000元,意味着国1到国5标准的车升级到国6标准每辆车需要15000元)如下表所示,计算在该情况下,达到减排55%目标的升级改造成本最低的升级方案(不改变汽车保有量)。

国家排放标准

国1

国2

国3

国4

国5

国6

保有量

706

28111

52352

100804

756007

259006

排放因子(吨/量)

0.029008549

0.005805108

0.005980677

0.002081344

0.000424764

0.000283176

升级成本

0

3000

6000

9000

11000

15000

解题思路(1):

采用非线性规划,设定升级后的国1~国6的保有量为x1~x6,设定约束条件,求解合适的x1~x6。

clear,clc
%% MATLAB非线性规划求解方法
global x0 
% 由于 matlab非线性规划函数 fmincon要求目标函数只能有一个输入和一个输出,
% 所以,其他影响目标函数值计算的变量需要通过定义为全局变量(global)实现传值
reduction=0.55;     % 减排比例
x0=[706;28111;52352;100804;756007;259006];  % 汽车保有量
A=[0.029008549,0.005805108,0.005980677,0.002081344,0.000424764,0.000283176];  % 排放因子 (吨/辆)
b=A*x0.*(1-reduction);   
% 在减排比例限制下的最大允许排放量
% 因为 MATLAB 规定线性不等式约束条件必须为 A*x<=b的形式,故采取了(1-reduction)的形式
Aeq=[1,1,1,1,1,1];
beq=Aeq*x0;
% Aeq和beq表示等式约束条件(Aeq*x=beq)
% 该处的含义为升级前后汽车总保有量不变
lb = [0,0,0,0,0,0];             % 解空间下限
ub = [beq,beq,beq,beq,beq,beq]; % 解空间上限
[x,fval,exitflag,output]= fmincon(@ObjFun,x0,A,b,Aeq,beq,lb,ub);
% fmincon 为MATLAB求解线性规划的函数
% x为规划结果(升级之后的各标准汽车的保有量),fval为规划结果对应的目标函数值
% @ObjFun为目标函数

%% 后处理方法(取得类似于整数规划的效果)
% 解释一下为什么要进行后处理以取得似于整数规划的效果
% 因为题目最终需要的求解的是车辆的升级方案,但是车辆的数量是整数,需要采用整数规划
% 但是目前 matlab 无法进行非线性的整数规划,所以只能采取变通的方式,即:
% 先使用非线性规划求解连续结果,对其结果向下取整之后,求解总量差额,将差额分别
% 添加至x的各个元素中,从新得到的解中选择效果最好的作为最终答案。
xfloor=floor(x);       % 向下取整
xfsum=sum(floor(x));
reduce=beq-xfsum;      % 计算取整之后的损失差额
cost=ones(length(A),1)*inf;
for i=1:length(A)      % 将差额分别添加至x的各个元素中,计算每种情况对应的目标函数值
    x1=xfloor;
    x1(i)=x1(i)+reduce;  
    if A*x1<=b
        [cost(i)]=ObjFun(x1);
    end
end
upIndex=find(cost==min(cost));   % 选取目标各种情况中效果最好的解作为最终结果
xfinal=xfloor;
xfinal(upIndex)=xfloor(upIndex)+reduce;  % xfinal为最终结果
sum(xfinal)

function [cost]=ObjFun(x)
global x0
x1=(x-x0);   
x1(x1<0)=0;
% 由于最终解x是升级之后的各标准汽车的保有量,故计算升级成本时需要先减去x0(初始保有量)
% 得出各标准车辆的变动量,并且由于变动量为正的代表有车辆升级为该标准,会计算成本
% 反之,变得量为负的,说明该标准车辆升级为更高标准,该变化不计算成本,故变动量(x1)
% 小于0的元素会被设置为0。
% 特别的 x1(x1<0)=0; 这步计算本身是非线性计算,所以,带有这一判断会使整个问题变为
% 非线性规划问题
c=[0;3000;6000;9000;11000;15000];  % 升级成本
cost=x1'*c;
end

分析:

非线性规划的思路简洁明了,借助MATLAB代码进行实现也并不困难,但是该技术路线并不完美,主要的存在以下三个问题:

(1)非线性规划的求解难度远高于线性规划,并且非线性规划本身不能完全保证其结果的全局最优性。在复杂问题背景下,非线性规划的求解难度会很高,所得出的解的质量也难以保证。

(2)MATLAB求解非线性规划的函数fmincon为其专有方法,也就意味着,该解题思路几乎仅能通过MATLAB实现,而不容易向其他平台(如C#、python等)迁移。

(3)该问题本身为整数规划问题,而MATLAB无法直接处理目标函数或约束条件为非线性的整数规划问题,不能保证其得出的连续解与题目要求的离散解(整数解)在全局最优处的一致性,并且后处理过程使用的贪心算法在面临复杂情况(例如:解空间很大,取整差额较多时)难以保证得出全局最优解(一定要尽可能取得全局最优的话可以考虑进行穷举,但是在解空间很大,取整差额较多时,穷举法并不适用)。

所以,需要转变思路并设计一种方法,将非线性规划问题转变为线性规划问题,并且能够进行整数规划。

解题思路(2):

一般情况下,将非线性问题转换为线性规划问题都是比较困难的。该问题显示为非线性规划的核心原因是在计算车辆的变动差额时,需要判断差额的正负性,并且将负值置为0,该过程为非线性过程,正是该过程的存在使得目标函数变为非线性函数。一种可行的方法是,将各排放标准车辆之间的变动量作为求解变量,即问题变为达到减排55%目标时,求解出国1升级为国2、国3、国4、国5和国6的车辆数目(分别为x12、x13、x14、x15、x16)、国2升级为国3、国4、国5和国6的车辆数目(分别为x23、x24、x25、x26)等,如图所示:

非线性整数规划python 非线性整数规划例题_线性规划

整数规划问题可以通过使用Lingo进行解决,Lingo代码如下:

model:
sets:
demand/1..6/:x0,A,c;
supply/1..1/:allcar,reduction;
endsets
data:
x0=706 28111 52352 100804 756007 259006;
A=0.029008549 0.005805108 0.005980677 0.002081344 0.000424764 0.000283176;
c=0 3000 6000 9000 11000 15000;
allcar=1196986;
reduction=0.55;
enddata

!目标函数;
min=(x16+x26+x36+x46+x56)*c(6)+(x15+x25+x35+x45)*c(5)+(x14+x24+x34)*c(4)+(x13+x23)*c(3)+x12*c(2);

!第一约束条件(减排量要符合要求);
(x0(1)-(x12+x13+x14+x15+x16))*A(1)+(x0(2)-(x23+x24+x25+x26)+x12)*A(2)+(x0(3)-(x34+x35+x36)+x13+x23)*A(3)+(x0(4)-(x45+x46)+x14+x24+x34)*A(4)+(x0(5)-(x56)+x15+x25+x35+x45)*A(5)+(x0(6)+x16+x26+x36+x46+x56)*A(6)<=1101.044469866*(1-reduction(1));

!第二约束条件(某标准的升级车辆不能超过该标准目前的保有量);
(x12+x13+x14+x15+x16)<=x0(1);
(x23+x24+x25+x26)<=x0(2);
(x34+x35+x36)<=x0(3);
(x45+x46)<=x0(4);
x56<=x0(5);

!第三约束条件(车辆保有量不能为负);
x12>=0;
x13>=0;
x14>=0;
x15>=0;
x16>=0;
x23>=0;
x24>=0;
x25>=0;
x26>=0;
x34>=0;
x35>=0;
x36>=0;
x45>=0;
x46>=0;
x56>=0;
!进行整数规划;
@gin(x12);
@gin(x13);
@gin(x14);
@gin(x15);
@gin(x16);
@gin(x23);
@gin(x24);
@gin(x25);
@gin(x26);
@gin(x34);
@gin(x35);
@gin(x36);
@gin(x45);
@gin(x46);
@gin(x56);

end

参照Lingo的求解逻辑,可以设计MATLAB代码进行混合整数线性规划求解。但要注意,MATLAB的混合整数线性规划函数(intlinprog)以及线性规划函数(linprog)均需要自行编制约束条件矩阵(A,b),解向量以及约束条件设置方式如图所示:

非线性整数规划python 非线性整数规划例题_非线性整数规划python_02

clear,clc
%% MATLAB 混合整数线性规划求解方法
reduction=0.55;
x0=[706;28111;52352;100804;756007;259006];  % 汽车保有量
A0=[0.029008549,0.005805108,0.005980677,0.002081344,0.000424764,0.000283176];  % 排放因子 (吨/辆)
c=[0;3000;6000;9000;11000;15000];  % 升级成本
xRank=length(x0)-1;
pRank=xRank:-1:1;
qRank=1:xRank;
xNum=sum(pRank);
%% 计算第一约束条件(减排量要符合要求)
A1=zeros(1,xNum);
n=1;
m=1;
p=pRank(n);
for i=1:xNum
    if i>p
        qRank=1+n:xRank;
        n=n+1;
        p=p+pRank(n);        
        m=1;
    end
%     disp([num2str(qRank(m)+1),'_',num2str(n)])
    A1(i)=A0(qRank(m)+1)-A0(n);
    m=m+1;
end
b1=A0*x0.*(-1).*reduction;
%% 计算第二约束条件(某标准的升级车辆不能超过该标准目前的保有量)
A2=zeros(xRank,xNum);
n=1;
p=pRank(n);
for i=1:xNum
    if i>p
        n=n+1;
        p=p+pRank(n);
    end
    A2(n,i)=1;
end
b2=x0(1:xRank);
%% 计算第三约束条件(车辆保有量不能为负)
A3=eye(xNum,xNum);
A3=-1.*A3;
b3=zeros(xNum,1);

A=[A1;A2;A3];
b=[b1;b2;b3];

%% 计算目标函数(成本最低)
f=zeros(1,xNum);
n=1;
m=1;
p=pRank(n);
qRank=1:xRank;
for i=1:xNum
    if i>p
        qRank=1+n:xRank;
        n=n+1;
        p=p+pRank(n);        
        m=1;
    end
%     disp(num2str(qRank(m)+1))
    f(i)=c(qRank(m)+1);
    m=m+1;
end
% x=linprog(f,A,b); % 常规线性规划
intcon=1:xNum;      % 用于标记解向量xfinal中哪些自变量为整数,例如:intcon=[2,5];则解向量中排序第2和第5的自变量限定为整数
[xfinal,fval]=intlinprog(f,intcon,A,b); % 混合整数线性规划

从求解结果来看,三种求解方法所得方案差异很小(仅国4和国5标准的汽车数目存在少量差异),目标函数值差异也很小。但是Lingo的求解效果最好,其次是MATLAB非线性规划,最后是MATLAB混合整数线性规划。

 

非线性整数规划python 非线性整数规划例题_MATLAB_03

 

非线性整数规划python 非线性整数规划例题_非线性整数规划python_04

 

参考资料:

混合整数线性规划 (MILP) - MATLAB intlinprog - MathWorks 中国

 

特别感谢:

龙老师,贺玉瑶