目录
1.简单介绍
2.求解方法
3.适用赛题
4.典型例题及相关分析
(1)问题引入
(2)决策变量&约束条件
(3)确定目标函数
(4)建立数学模型
5.MATLAB代码祝逐字句讲解
1.简单介绍
非线性规划,要想深刻的理解并且运用这个模型,我们学习者必须要了解什么是线性,什么是非线性,简单的来讲:数学里面的一次函数关系就是线性的关系,其他的函数关系就是非线性的关系,例如,我们平常常见的x^2,logx,sinx这些都是非线性的,我们的这个非线性规划模型要解决的就是这样的问题,这个是我们从宏观上对于我们要学习的非线性规划问题做一个大致的了解。
2.求解方法
下面的图片里面的函数就是我们进行求解非线性规划模型的函数fmincon函数,下面的左下方就是一个常见的非线性规划问题,一个目标函数,带平方显然不是我们之前提到的线性的模型,约束条件(中括号里面的内容)同样是带平方的非线性规划类的问题,我们现在只需要大概了解一下即可,下面我们会全面的介绍这个函数的应用场景以及求解的方法。
3.适用赛题
(1)空间运动类的问题,下面也提到了三角函数以及指数函数,这些函数的图像就是典型的非线性的函数图像,我们就需要使用非线性规划的方法解决这类问题。
(2)选地址的这类问题,显然就要求解函数的极值最值,这里就要使用两点之间的距离公式,这个公式里面既要平方运算,又含有根号运算,显然就已经属于我们的非线性的研究的范畴了;
(3)选地址类的问题就是我们的选取的经典例题,我们就以这类问题作为引例,详细的介绍非线性规划类的问题,下面是我们进行的一些假设,这些假设可以简化我们的模型,我们都知道两点之间的距离计算的肯定是直线的,但是实际的生活里面,我们遇到的各种工程问题怎么可能会是直的呢?难免会出现无法直达的情况,
这个时候我们的模型的假设就很有必要了,我们的模型假设所有的情况都是两点之间的直线距离,那种不是直线的情况我们不进行考虑。
4.典型例题及相关分析
(1)问题引入
我们的问题是两个料场,6个工厂,问题里面的吨千米数就是指距离乘以材料的重量,两者的乘积就是我们的决策变量,我们要求的是这个变量的最小值;
(2)决策变量&约束条件
下面我们是确定目标函数和约束条件:这里出现了对个自变量,i,j等等,而且求和的时候会出现一个变量改变,另外的一个变量不改变的情况,然后进行求和,我们只有先清楚的理解这个求和式子的含义是什么,才可以在MATLAB里面根据它的含义去进行运算,初学者这个地方理解起来会有些吃力,但是这个是我们必须要进行面对的,我们在数学建模的过程中会遇到大量的这种数据多,交叉进行求和的情况,我们必须要逐渐的适应,去理解,去尝试;
以上面的变量含义和求和运算的符号为例子,我们简单的了解一下表示的几何意义:我们使用i表示的是6个工厂,i的取值范围就是123456,我们使用j代表的是两个料场,料场的j取值范围就是12,e表示的是料场里面每天的材料储备量,e1就表示第一个料场的材料储备量,e2就表示第二个料场的原料储备量;d表示的就是day每天的意思,意思就是说1号工厂的每天的水泥用量d1就是两个水泥原料厂输送的水泥量的总和;
下面我们来了解一下下面的约束条件里面的两个求和运算的式子究竟是什么含义:第一个约束条件就是水泥运输的总量不能超过每天的储备量,这个里面的ij都在改变,我们理解的时候要使用我们耳熟能详的控制变量法,就是我们先看j=1的时候,就是第一个料场,他向6个工厂输送的水泥量的总和不能超过他的日储备量,j=2时候,就表示第二个料场向6个工厂输送的水泥量的总和不超过自己的日水泥储备量;
第二个约束条件就是说:第一个水泥工厂的水泥日使用量就是两个原料厂的运送给他的水泥的总量,使用数学语言进行表示就是d1=x11+x12,x11表示第一个原料厂向第一个工厂的运送量(这里四从后向前理解)Xij就表示第j个原料厂向第i个工厂运送的水泥的量。
(3)确定目标函数
这个里面有像个求和的符号,含义我们前面已经说过,相信你可以理解(这种的求和我们可以先对一个求和,再对另外的一个求和),具体就是我们先让j=1,也就是我们只看第一个原料厂,计算这个原料厂和其他的6个工厂的距离的总和,再让j=2,计算第二个原料厂和这6个工厂的总和,我们这两个求和符号相当于是计算了12个距离的总和,希望你能够理解。
(4)建立数学模型
模型包括我们上面提到的目标函数(12个距离的总和),约束条件(料场向工厂运送的水泥量不超过其储备量,以及每个工厂的水泥日用量di等于两个原料厂向他输送的水泥的和);
这个就是我们对于模型的问题分析:我们这个问题有2个小问:第一小问料场的位置确定,虽然涉及到距离的求解,但是这个距离我们可以直接求出来,是常数,这个就是典型的线性规划类问题;但是第二问的料场的位置不确定,我们需要使用坐标进行表示,这个时候根号,以及平方运算不是具体的数,这个就是典型的非线性规划的问题了;
由此可见,对于模型的识别很重要,我们只有分析之后得到模型的类别,才能使用对应的方法函数对于问题进行求解,这个也提醒我们同学们在学习的时候,不能一味学习模型,却不了解模型的适用场景,这个就得不偿失了。
下面的是我们对于为了方便写代码进行的一些操作(请理解,后续的代码会使用到),就是X的角标原来是两个数字,我们现在使用一个数字具体代替,我们要了解这1~12这12个角标的具体含义,举例说明一下:X12就代表第二个原料厂向第一个工厂运送的水泥量;
5.MATLAB代码祝逐字句讲解
(1)准备工作
我们先是把题目里面的已知信息转换成为数学语言,请根据注释进行理解,sqrt是求算数平方根的函数,这个里面是一个双重的循环,对于这个xy,我们应该正确的进行理解,对应的两个原料厂的坐标分别是(5,1)(2,7),我们这里是把两个横坐标放到了一起,两个纵坐标放到一起,希望读者正确的理解;
最后我们可以尝试打印输入l,可以看出来l是一个6*2的矩阵;这个矩阵的坐标值表示的就是原料厂和工厂之间的距离;
(2)因为我们的第一问是线性规划问题,就要用到我们之前介绍的linprog函数(不理解的伙伴可到我的主页数学建模专栏进行阅读)
这个函数的第一个参数代表的含义就是约束条件的变量的系数,第一个约束条件j可以取的值是1和2,所以有2个约束,有2个约束就有2行,我们一共有12个变量(x1~x12),所以矩阵的每一行就有12个数字,虽然某些没有用到,但是我们也要使用0进行代替;例如i=1是,我们的求和是1*x1+1*x2+1*x3+1*x4+1*x5+1*x6+0*x7+0*x8…………0*x12,因为j=1时,我们的第一个原料厂只能向6个工厂送原料,也就是x11 x21 x31 x41 x51 x61,我们的x7~x12代表的是x12 x22 x32 x42 x52 x62,这六个也是变量只不过是第二个原料厂的,我们现在考虑的是第一个原料厂,所以系数是0,同理,第二行表示的是j=2的时候的情况;希望你能够理解为什么第一行前六项是1,第二行后6项是1;
我们的代码里除了A这个矩阵,还有一行代码f,这个代码什么意思呢?我们前面已经看到,我们自己计算的两个点之间的距离是6*2的矩阵,我们的MATLAB进行运算的时候,不可以是这样的形式,必须是一行或者是一列才可以,我们需要把这个矩阵进行转化,我们这个地方转换成了1列,这一列是12个数,我们的l(:,1)表示的是取出第一列,后面有一个冒号表示的是换行;l(:,2)表示取出第二列的全部元素;
上面的A是我们的约束条件里面的不等式的系数,下面的Aeq是约束条件里面的等式的系数,第二个约束条件就是每个工厂每天的水泥用量就是两个原料厂的运送量之和;
这个地方的处理就非常的巧妙,可能初学者很难想到,我们理解即可:
eye函数是生成单位矩阵,我们的参数是6,表示的是生成6*6的单位矩阵,对角线的元素是1,其他的元素是0,然后两个拼接在一起,我们观察下面的6*12矩阵就可以发现,第一行的第1列和第7列是1,这个不正好可以表示X1和X7吗,也就是第一个水泥厂和第二个水泥厂向第一个工厂输送水泥的意义,以此类推,我们就理解了其他的五个工厂;这里更深入的理解应该是X11+0*X21+…………X21+0*X22+…………0*X62,我们的Aeq里面放的是系数,所以就是我们的矩阵第一行的元素,我们发现,eye函数组成的两个单位矩阵的拼接正好可以达到这个效果;
beq就是我们前面已经表示好的水泥的日用量,这个里面的123456就是行向量d里面对应的索引
接下来就可以直接使用函数进行求解了:
lb表示的是运输量的最小值,肯定是0啊,就是什么也不运输,
完整代码:
clear;clc;%清空工作区
a=[1.25 8.75 0.5 5.75 3 7.25];%工厂位置的横坐标
b=[1.25 0.75 4.75 5 6.5 7.75];%纵坐标
x=[5 2];%原料厂的位置横坐标
y=[1 7];%原料厂的位置纵坐标
d=[3 5 4 7 6 11];%每个工厂的日用水泥量
for i=1:6
for j=1:2
l(i,j)=sqrt((x(j)-a(i))^2+(y(j)-b(i))^2);
end
end
f=[l(:,1);l(:,2)];
A=[1 1 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 1 1];
b=[20;20];
Aeq=[eye(6),eye(6)];
beq=[d(1);d(2);d(3);d(4);d(5);d(6)];
lb=[0 0 0 0 0 0 0 0 0 0 0 0];
[x,fval]=linprog(f,A,b,Aeq,beq,lb);
x,fval
我们的输出结果可以在命令行的窗口里面进行查看:x fval
如果你理解了前面的思路,相信你可以明白这个12*1的矩阵里面的每个数字的几何意义,例如3表示的就是第一个料场向第一个工厂运输的原料等等
fval:吨千米数
(3)接下来我们讨论的就是第二问的非线性规划问题,因为这个里面料场的位置是不确定的,所以我们要加上4个变量,分别表示两个料场的横纵坐标;
其次,因为是非线性规划,我们要使用这个求解2个点之间的距离的函数,我们需要把这个表达式告诉MATLAB,这个时候我们要写一个函数,最后在我们的代码里面区调用这个函数即可;
接下来我们看一下函数怎么写:
function表示的就是我们的自定义的函数,x13是第一个原料厂的横坐标,x14是第一个原料厂的纵坐标,x15就是第二个原料厂的横坐标,x16就是第二个原料厂的纵坐标f1最后的累加的结果就是我们的第一个原料厂的吨千米数,f2就是第二个原料厂的吨千米数,ff就是两个原料厂和6个工厂对应之后的总的吨千米数;
下面的就是我们的代码部分,我们在调用函数的时候就要使用@函数名进行调用,x0就是初始值,这个值可以是任意的,我们这里是用第一问的结果作为前面的12个元素的初始值,后面的4个元素的初始值使用第一问的原料厂的坐标值代替,这里读者可以自行设置;
我们的Aeq2原来是6行12列,现在我们加入了原料厂的坐标,我们需要补齐,就是增加4列,每列和原来的一样都是6行,我们把这24个元素全部初始化为0,让后添加进去即可;
lb2就是最小值,我们的4个坐标(原料厂的)是使用-inf代替,这里的-inf就是负无穷的意思,非线性规划的fmincon函数参数和我们的线性规划的linprog函数的函数参数基本一样,就是添加了前面的两项,第一项就是非线性的函数,第二项就是我们赋的初始值;
最后的打印结果x2就是我们的运送方案和对应的两个原料厂的坐标,X15就是第2个原料厂的横坐标,X16就是第二个原料厂的纵坐标,x13 x14就是对应的第一个原料厂的横纵坐标;
通过对比,我们发现改变料场位置之后,吨千米数从原来的136到现在90,可见大大提高效率
代码展示(小伙伴可在自己的电脑端运行):
clear;clc;%清空工作区
%f=[l(:,1);l(:,2)];
A2=[1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0];
b2=[20;20];
Aeq2=[eye(6),eye(6),zeros(6,4)];
beq2=[3 5 4 7 6 11]';
lb2=[zeros(12,1);-inf;-inf;-inf;-inf];
x0=[3 5 0 7 0 1 0 0 4 0 6 10 5 1 2 7]';
[x2,fval]=fmincon(@obj_f,x0,A2,b2,Aeq2,beq2,lb2);
x2,fval
%下面是自定义函数部分,就是我们的求解距离的函数
function ff=obj_f(x)
a1=[1.25 8.75 0.5 5.75 3 7.25];%工厂位置的横坐标
b1=[1.25 0.75 4.75 5 6.5 7.75];%纵坐标
f1=0;
for i=1:6
s(i)=sqrt((x(13)-a1(i))^2+(x(14)-b1(i))^2);
f1=s(i)*x(i)+f1;
end
f2=0;
for i=7:12
s(i)=sqrt((x(15)-a1(i-6))^2+(x(16)-b1(i-6))^2); % 第二个料场到各工地的距离
f2=s(i)*x(i)+f2; % 第二个料场给各工地的吨千米数
end
ff=f1+f2;
end
以上均是自己的理解,不足之处请多指正,有任何不理解的地方请在评论区留言,笔者会尽己所能给你一个满意的答复 !