数学规划是运筹学的一个分支,其用来研究在给定约束条件下,如何按照某一目标函数,寻求最优方案,准确地说就是求解目标函数在某一条件下的极值问题,规划类问题是数学建模中很重要的问题,常见的有线性规划,非线性规划,整数规划,0-1规划,最大最小化模型,多目标规划等。
目录
数学规划就可以理解为求目标函数在约束条件下的极值问题,数学规划的一般形式包含目标函数,决策变量和约束条件三部分。
一般将规划类问题分为线性规划,非线性规划,整数规划和0-1规划,具体如下:
我们看一下下面的三个线性规划问题,基本上大同小异,我们可以使用matlab的linprog函数求解。
对于matlab求解线性规划问题,有如下问题需要注意,c表示目标函数,A,b表示不等式约束,Aeq,beq表示等式约束,lb,ub分别表示上下界,x0表示初始。
上面三个题目的matlab求解代码如下:
- c = [-5 -4 -6]'; % 加单引号表示转置
- A = [1 -1 1;
- 3 2 4;
- 3 2 0];
- b = [20 42 30]';
- lb = [0 0 0]';
- [x fval] = linprog(c, A, b, [], [], lb) % ub我们直接不写,则意味着没有上界的约束
- c = [0.04 0.15 0.1 0.125]';
- A = [-0.03 -0.3 0 -0.15;
- 0.14 0 0 0.07];
- b = [-32 42]';
- Aeq = [0.05 0 0.2 0.1];
- beq = 24;
- lb = [0 0 0 0]';
- [x fval] = linprog(c, A, b, Aeq, beq, lb)
- c = [-2 -3 5]';
- A = [-2 5 -1;
- 1 3 1];
- b = [-10 12];
- Aeq = ones(1,3);
- beq = 7;
- lb = zeros(3,1);
- [x fval] = linprog(c, A, b, Aeq, beq, lb)
- fval = -fval % 注意这个fval要取负号(原来是求最大值,我们添加负号变成了最小值问题)
我们看一下下面这个例题,一个生产决策的问题,就是根据决策变量写出目标函数和约束条件,最后求解目标函数的最大值即可。
matlab求解上述线性规划问题的代码如下,就是使用linprog函数求解:
- %% 生产决策问题
- format long g %可以将Matlab的计算结果显示为一般的长数字格式(默认会保留四位小数,或使用科学计数法)
- % (1) 系数向量
- c = zeros(9,1); % 初始化目标函数的系数向量全为0
- c(1) = 1.25 -0.25 -300/6000*5; % x1前面的系数是c1
- c(2) = 1.25 -0.25 -321/10000*7;
- c(3) = -250 / 4000 * 6;
- c(4) = -783/7000*4;
- c(5) = -200/4000 * 7;
- c(6) = -300/6000*10;
- c(7) = -321 / 10000 * 9;
- c(8) = 2-0.35-250/4000*8;
- c(9) = 2.8-0.5-321/10000*12-783/7000*11;
- c = -c; % 我们求的是最大值,所以这里需要改变符号
- % (2) 不等式约束
- A = zeros(5,9);
- A(1,1) = 5; A(1,6) = 10;
- A(2,2) = 7; A(2,7) = 9; A(2,9) = 12;
- A(3,3) = 6; A(3,8) = 8;
- A(4,4) = 4; A(4,9) = 11;
- A(5,5) = 7;
- b = [6000 10000 4000 7000 4000]';
- % (3) 等式约束
- Aeq = [1 1 -1 -1 -1 0 0 0 0;
- 0 0 0 0 0 1 1 -1 0];
- beq = [0 0]';
- %(4)上下界
- lb = zeros(9,1);
-
- % 进行求解
- [x fval] = linprog(c, A, b, Aeq, beq, lb)
- fval = -fval
我们看一下下面的投料问题,我们可以使用matlab和lingo去求解线性规划问题,对于这一题而言,lingo求解更为简单。
如下是matlab求解上述线性规划问题的代码:
- %% 投料问题
- clear,clc
- format long g %可以将Matlab的计算结果显示为一般的长数字格式(默认会保留四位小数,或使用科学计数法)
- % (1) 系数向量
- a=[1.25 8.75 0.5 5.75 3 7.25]; % 工地的横坐标
- b=[1.25 0.75 4.75 5 6.5 7.25]; % 工地的纵坐标
- x = [5 2]; % 料场的横坐标
- y = [1 7]; % 料场的纵坐标
- c = []; % 初始化用来保存工地和料场距离的向量 (这个向量就是我们的系数向量)
- for j =1:2
- for i = 1:6
- c = [c; sqrt( (a(i)-x(j))^2 + (b(i)-y(j))^2)]; % 每循环一次就在c的末尾插入新的元素
- end
- end
- % (2) 不等式约束
- A =zeros(2,12);
- A(1,1:6) = 1;
- A(2,7:12) = 1;
- b = [20,20]';
- % (3) 等式约束
- Aeq = zeros(6,12);
- for i = 1:6
- Aeq(i,i) = 1; Aeq(i,i+6) = 1;
- end
- % Aeq = [eye(6),eye(6)] % 两个单位矩阵横着拼起来
- beq = [3 5 4 7 6 11]'; % 每个工地的日需求量
- %(4)上下界
- lb = zeros(12,1);
-
- % 进行求解
- [x fval] = linprog(c, A, b, Aeq, beq, lb)
- x = reshape(x,6,2)
lingo解决上述线性规划问题的代码如下:
- model:
- sets:
- factory /1..6/ : a,b,d ;
- plant /1..2/ : x,y ;
- coo (factory,plant) : x1 ;
- endsets
-
- data:
- a = 1.25, 8.75, 0.5, 5.75, 3, 7.25 ;
- b = 1.25, 0.75, 4.75, 5, 6.5, 7.25 ;
- d = 3,5,4,7,6,11 ;
- x = 5, 2 ;
- y = 1, 7 ;
- enddata
-
- min = @sum(coo(i,j) : x1(i,j) * @sqrt((a(i)-x(j)) * (a(i)-x(j)) + (b(i) - y(j)) * (b(i) - y(j)))) ;
- @for(factory(i) : @sum(plant(j) : x1(i,j)) = d(i)) ;
- @for(plant(j) : @sum(factory(i) : x1(i,j)) <= 20) ;
- @for(factory(i) : @for(plant(j) : x1(i,j) >= 0)) ;
- end
我们看一下非线性规划的标准型,aeq和b为线性不等式约束,Aeq和beq是线性等式约束,c是非线性不等式约束,ceq是非线性等式约束。
我们先看一下matlab求解上面的函数的思路,可以使用fmincon函数进行求解,非线性规划的需要选取一个很好的初始值,因为非线性规划本来求出来的就是一个局部最优解,我们想求一个相对的全局最优解的话,可以通过尝试大量的解,然后找一个最优的,也可以通过蒙特卡洛模拟出初始解,通过初始解计算最优解。option选项是设置求解非线性规划的算法,不同的算法都可以尝试对比一下。
另外第一个@fun中的fun是目标函数,需要用一个m函数文件来存储,另外的@nonlfun用来表示非线性约束,就是编写一个函数文件来存储非线性约束条件。
我们看一下上面的的三个例题的matlab代码实现,具体如下,先使用蒙特卡洛方法模拟出一个解,然后以该解作为初始值代入fmincon函数对非线性规划进行求解,第一个例题具体如下:
- %% 使用蒙特卡罗的方法来找初始值(推荐)
- clc,clear;
- n=10000000; %生成的随机数组数
- x1=unifrnd(-100,100,n,1); % 生成在[-100,100]之间均匀分布的随机数组成的n行1列的向量构成x1
- x2=unifrnd(-100,100,n,1); % 生成在[-100,100]之间均匀分布的随机数组成的n行1列的向量构成x2
- fmin=+inf; % 初始化函数f的最小值为正无穷(后续只要找到一个比它小的我们就对其更新)
- for i=1:n
- x = [x1(i), x2(i)]; %构造x向量, 这里千万别写成了:x =[x1, x2]
- if ((x(1)-1)^2-x(2)<=0) & (-2*x(1)+3*x(2)-6 <= 0) % 判断是否满足条件
- result = -x(1)^2-x(2)^2 +x(1)*x(2)+2*x(1)+5*x(2) ; % 如果满足条件就计算函数值
- if result < fmin % 如果这个函数值小于我们之前计算出来的最小值
- fmin = result; % 那么就更新这个函数值为新的最小值
- x0 = x; % 并且将此时的x1 x2更新为初始值
- end
- end
- end
- disp('蒙特卡罗选取的初始值为:'); disp(x0)
- A = [-2 3]; b = 6;
- [x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1)
- fval = -fval
使用的目标函数fun1和非线性约束函数nonlfun如下:
- function f = fun1(x)
- % 注意:这里的f实际上就是目标函数,函数的返回值也是f
- % 输入值x实际上就是决策变量,由x1和x2组成的向量
- % fun1是函数名称,到时候会被fmincon函数调用, 可以任意取名
- % 保存的m文件和函数名称得一致,也要为fun1.m
- % max f(x) = x1^2 +x2^2 -x1*x2 -2x1 -5x2
- f = -x(1)^2-x(2)^2 +x(1)*x(2)+2*x(1)+5*x(2) ;
- end
- function [c,ceq] = nonlfun1(x)
- % 注意:这里的c实际上就是非线性不等式约束,ceq实际上就是非线性等式约束
- % 输入值x实际上就是决策变量,由x1和x2组成的一个向量
- % 返回值有两个,一个是非线性不等式约束c,一个是非线性等式约束ceq
- % nonlfun1是函数名称,到时候会被fmincon函数调用, 可以任意取名,但不能和目标函数fun1重名
- % 保存的m文件和函数名称得一致,也要为nonlfun1.m
- % -(x1-1)^2 +x2 >= 0
- c = [(x(1)-1)^2-x(2)]; % 千万別写成了: (x1-1)^2 -x2
- ceq = []; % 不存在非线性等式约束,所以用[]表示
- end
另外使用fmincon求解非线性规划问题可以设置option选项,就是设置求解算法,常见的求解算法有四种,分别如下:
- % 使用interior point算法 (内点法)
- option = optimoptions('fmincon','Algorithm','interior-point')
- [x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1,option)
- fval = -fval
-
- % 使用SQP算法 (序列二次规划法)
- option = optimoptions('fmincon','Algorithm','sqp')
- [x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1,option)
- fval = -fval
-
- % 使用active set算法 (有效集法)
- option = optimoptions('fmincon','Algorithm','active-set')
- [x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1,option)
- fval = -fval
-
- % 使用trust region reflective (信赖域反射算法)
- option = optimoptions('fmincon','Algorithm','trust-region-reflective')
- [x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1,option)
- fval = -fval
第二个非线性规划的例题求解过程如下,先使用蒙特卡洛模拟出一个解作为初始值,然后将初始值代入fmincon函数进行求解,得出结果。
- %% 使用蒙特卡罗的方法来找初始值(推荐)
- clc,clear;
- n=1000000; %生成的随机数组数
- x1= unifrnd(0,2,n,1); % 生成在[0,2]之间均匀分布的随机数组成的n行1列的向量构成x1
- x2 = sqrt(2-x1); % 根据非线性等式约束用x1计算出x2
- x3 = sqrt((3-x2)/2); % 根据非线性等式约束用x2计算出x3
- fmin=+inf; % 初始化函数f的最小值为正无穷(后续只要找到一个比它小的我们就对其更新)
- for i=1:n
- x = [x1(i), x2(i), x3(i)]; %构造x向量, 这里千万别写成了:x =[x1, x2, x3]
- if (-x(1)^2+x(2)-x(3)^2<=0) & (x(1)+x(2)^2+x(3)^2-20<=0) % 判断是否满足条件
- result =sum(x.*x) + 8 ; % 如果满足条件就计算函数值
- if result < fmin % 如果这个函数值小于我们之前计算出来的最小值
- fmin = result; % 那么就更新这个函数值为新的最小值
- x0 = x; % 并且将此时的x1 x2 x3更新为初始值
- end
- end
- end
- disp('蒙特卡罗选取的初始值为:'); disp(x0)
- lb = [0 0 0]; % 决策变量的下界
- [x,fval] = fmincon(@fun2,x0,[],[],[],[],lb,[],@nonlfun2) % 注意 fun2.m文件和nonfun2.m文件都必须在当前文件夹目录下
下面是上述第2个非线性规划的目标函数和非线性约束函数,如下:
- function f = fun2(x)
- % f = x(1)^2+x(2)^2 +x(3)^2+8 ;
- f = sum(x.*x) + 8; % 可别忘了x实际上是一个向量,我们可以使用矩阵的运算符号对其计算
- end
- function [c,ceq] = nonlfun2(x)
- % 非线性不等式约束
- c = [-x(1)^2+x(2)-x(3)^2; % 一定要注意写法的规范,再次强调这里的x是一个向量!不能把x(1)写成x1
- x(1)+x(2)^2+x(3)^2-20];
- % 非线性等式约束
- ceq = [-x(1)-x(2)^2+2;
- x(2)+2*x(3)^2-3];
- end
第三个非线性规划的例题求解过程如下,先使用蒙特卡洛模拟出一个解,用该解作为初始值代入fmincon函数中求解该非线性规划的解。代码如下:
- clear;clc
- n=10000000; %生成的随机数组数
- x1=unifrnd(20,30,n,1); % 生成在[20,30]之间均匀分布的随机数组成的n行1列的向量构成x1
- x2=x1 - 10;
- x3=unifrnd(-10,16,n,1); % 生成在[-10,16]之间均匀分布的随机数组成的n行1列的向量构成x3
- fmax=-inf; % 初始化函数f的最大值为负无穷(后续只要找到一个比它大的我们就对其更新)
- for i=1:n
- x = [x1(i), x2(i), x3(i)]; %构造x向量, 这里千万别写成了:x =[x1, x2, x3]
- if (-x(1)+2*x(2)+2*x(3)>=0) & (x(1)+2*x(2)+2*x(3)<=72) % 判断是否满足条件
- result = x(1)*x(2)*x(3); % 如果满足条件就计算函数值
- if result > fmax % 如果这个函数值大于我们之前计算出来的最大值
- fmax = result; % 那么就更新这个函数值为新的最大值
- X = x; % 并且将此时的x1 x2 x3保存到一个变量中
- end
- end
- end
- disp(strcat('蒙特卡罗模拟得到的最大值为',num2str(fmax)))
- disp('最大值处x1 x2 x3的取值为:')
- disp(X)
- % 蒙特卡罗模拟得到的最大值为3445.6014
- % 最大值处x1 x2 x3的取值为:
- % 22.5823101903968 12.5823101903968 12.1265223966757
- A = [1 -2 -2; 1 2 2]; b = [0 72];
- x0 = [ 22.58 12.58 12.13];
- Aeq = [1 -1 0]; beq = 10;
- lb = [-inf 10 -inf]; ub = [inf 20 inf];
- [x,fval] = fmincon(@fun3,x0,A,b,Aeq,beq,lb,ub,[]) % 注意没有非线性约束,所以这里可以用[]替代,或者干脆不写
- fval = -fval
使用到的目标函数代码如下,由于没有非线性约束,所以不用写非线性函数。
- function f = fun3(x)
- f = -prod(x); % 可别忘了x实际上是一个向量(prod表示连乘符号,用法和sum类似)
- end
我们看一下这个题目的第二问,关于选址问题的,就是现在的临时料场不要了,新建两个料场,使得总的吨千米数最少,由于新料场的位置未知,那么这个题目就变成了一个非线性规划的问题了。决策变量由原来的12个变成了16个。
下面看一下matlab求解上述非线性规划问题的代码如下:
- %% 选址问题
- clear;clc
- format long g %可以将Matlab的计算结果显示为一般的长数字格式(默认会保留四位小数,或使用科学计数法)
- A =zeros(2,16); % 注意这里要改成16
- A(1,1:6) = 1;
- A(2,7:12) = 1;
- b = [20,20]';
- % (3) 等式约束
- Aeq = zeros(6,16); % 注意这里要改成16
- for i = 1:6
- Aeq(i,i) = 1; Aeq(i,i+6) = 1;
- end
- beq = [3 5 4 7 6 11]'; % 每个工地的日需求量
- %(4)上下界
- lb = zeros(16,1);
- % lb = [zeros(12,1); -inf*ones(4,1)]; 两个新料场坐标的下界可以设为-inf
-
- % 进行求解
- % 注意哦,这里我们只尝试了这一个初始值,大家可以试试其他的初始值,有可能能够找到更好的解。
- % 未来我会在遗传算法中再来看这个例题。
- x0 = [3 5 0 7 0 1 0 0 4 0 6 10 5 1 2 7]; % 用第一问的结果作为初始值
- [x,fval] = fmincon(@fun5,x0,A,b,Aeq,beq,lb) % 注意没有非线性约束,所以这里可以用[]替代,或者干脆不写
- reshape(x(1:12),6,2)
- function f = fun5(xx) % 注意为了避免和下面的x同号,我们把决策变量的向量符号用xx表示(注意xx的长度为16)
- a=[1.25 8.75 0.5 5.75 3 7.25]; % 工地的横坐标
- b=[1.25 0.75 4.75 5 6.5 7.25]; % 工地的纵坐标
- x = [xx(13) xx(15)]; % 新料场的横坐标
- y = [xx(14) xx(16)]; % 新料场的纵坐标
- c = []; % 初始化用来保存工地和料场距离的向量 (这个向量就是我们的系数向量)
- for j =1:2
- for i = 1:6
- c = [c; sqrt( (a(i)-x(j))^2 + (b(i)-y(j))^2)]; % 每循环一次就在c的末尾插入新的元素
- end
- end
- % 下面我们要求吨千米数,注意c是列向量,我们计算非线性规划时给定的初始值x0是行向量
- f = xx(1:12) * c;
- end
lingo求解上述非线性规划问题的代码如下:
- model:
- sets:
- factory /1..6/ : a,b,d ;
- plant /1..2/ : x,y ;
- coo (factory,plant) : x1 ;
- endsets
-
- data:
- a = 1.25, 8.75, 0.5, 5.75, 3, 7.25 ;
- b = 1.25, 0.75, 4.75, 5, 6.5, 7.25 ;
- d = 3,5,4,7,6,11 ;
- enddata
-
- min = @sum(coo(i,j) : x1(i,j) * @sqrt((a(i)-x(j))* (a(i)-x(j)) + (b(i) - y(j)) * (b(i) - y(j)))) ;
- @for(factory(i) : @sum(plant(j) : x1(i,j)) = d(i)) ;
- @for(plant(j) : @sum(factory(i) : x1(i,j)) <= 20) ;
- @for(factory(i) : @for(plant(j) : x1(i,j) >= 0)) ;
- end
整数规划问题分为线性整数规划和非线性整数规划问题,我们主要还是考虑线性整数规划,非线性的一般不使用matlab自带的函数求解,一般用蒙特卡洛模拟或者启发式算法求解。
在matlab中求解线性整数规划问题,一般使用intlinprog函数求解,intcon指定决策变量为整数。
我们可以看一下下面的三个简单的例子,intlinprog的用法和linprog的用法很相似,主要是加上了一个整数约束intcon。
我们看一下这个背包问题,就是典型的0-1整数规划问题,目标函数总利润最大,约束条件总重量不超过30.
求解上面整数规划的matlab代码如下:
- %% 背包问题(货车运送货物的问题)
- c = -[540 200 180 350 60 150 280 450 320 120]; % 目标函数的系数矩阵(最大化问题记得加负号)
- intcon=[1:10]; % 整数变量的位置(一共10个决策变量,均为0-1整数变量)
- A = [6 3 4 5 1 2 3 5 4 2]; b = 30; % 线性不等式约束的系数矩阵和常数项向量(物品的重量不能超过30)
- Aeq = []; beq =[]; % 不存在线性等式约束
- lb = zeros(10,1); % 约束变量的范围下限
- ub = ones(10,1); % 约束变量的范围上限
- %最后调用intlinprog()函数
- [x,fval]=intlinprog(c,intcon,A,b,Aeq,beq,lb,ub)
- fval = -fval
求解上面整数规划的lingo代码如下:
- model:
- sets:
- factory /1..10/ : x,p,t ;
-
- endsets
-
- data:
- t = 6,3,4,5,1,2,3,5,4,2;
- p = 540, 200, 180, 350, 60, 150, 280, 450, 320, 120;
- enddata
- max = @sum(factory(i) : (p(i) * x(i)));
- @sum(factory(i) : t(i)*x(i)) <= 30 ;
- @for(factory(i) : @bin(x(i))) ;
-
- end
我们看一下这个指派问题,就是指派队员i参加j种游泳比赛,使得成绩最好,即用时最短,目标函数是用时最小,约束条件是最多只能参加一个比赛,每种比赛有且只有一人参加。参加表示为1,不参加表示为0.
上述的整数规划问题求解的lingo代码如下:
- model:
- sets:
- factory /1..5/ ;
- plant /1..4/ ;
- coo (factory,plant) : t,x ;
- endsets
- data:
- t = 66.8 75.6 87 58.6
- 57.2 66 66.4 53
- 78 67.8 84.6 59.4
- 70 74.2 69.6 57.2
- 67.4 71 83.8 62.4 ;
- enddata
- min = @sum(coo(i,j) : (t(i,j) * x(i,j))) ;
- @for(factory(i) : @sum(plant(j) : x(i,j)) <= 1) ;
- @for(plant(j) : @sum(factory(i) : x(i,j)) = 1) ;
- @for(factory(i) : @for(plant(j) : @bin(x(i,j))));
-
- end
我们看一下下面的钢管切割问题,使得切割使用的原材料最少,具体如下。
求解上述整数规划问题的matlab代码如下:
- %% 钢管切割问题
- %% (1)枚举法找出同一个原材料上所有的切割方法
- for i = 0: 2 % 2.9m长的圆钢的数量
- for j = 0: 3 % 2.1m长的圆钢的数量
- for k = 0:6 % 1m长的圆钢的数量
- if 2.9*i+2.1*j+1*k >= 6 && 2.9*i+2.1*j+1*k <= 6.9
- disp([i, j, k])
- end
- end
- end
- end
- % 有同学使用比较老的MATLAB版本,会出现浮点数计算的误差
- % 只需要将上面的if这一行进行适当的放缩即可。
- % if 2.9*i+2.1*j+1*k >= 6-0.0000001 && 2.9*i+2.1*j+1*k <= 6.9+0.0000001
- % 有兴趣的同学可以百度下:浮点数计算误差
-
- %% (2) 线性整数规划问题的求解
- c = ones(7,1); % 目标函数的系数矩阵
- intcon=[1:7]; % 整数变量的位置(一共7个决策变量,均为整数变量)
- A = -[1 2 0 0 0 0 1;
- 0 0 3 2 1 0 1;
- 4 1 0 2 4 6 1]; % 线性不等式约束的系数矩阵
- b = -[100 100 100]'; % 线性不等式约束的常数项向量
- lb = zeros(7,1); % 约束变量的范围下限
- [x,fval]=intlinprog(c,intcon,A,b,[],[],lb)
我们看一下最大最小化模型的一般形式,除了目标函数之外,其余的和常规的规划问题没啥区别。
我们看一下这个选址问题,其实就是选择一个位置,距离其余位置的总和最小,或者说,距离其它位置的最大值最小。
求解上述最大最小化模型的matlab代码如下:
- %% 最大最小化模型 : min{max[f1,f2,···,fm]}
- x0 = [6, 6]; % 给定初始值
- lb = [3, 4]; % 决策变量的下界
- ub = [8, 10]; % 决策变量的上界
- [x,feval] = fminimax(@fun,x0,[],[],[],[],lb,ub)
- max(feval)
- function f = fun(x)
- a=[1 4 3 5 9 12 6 20 17 8];
- b=[2 10 8 18 1 4 5 10 8 9];
- % 函数向量
- f=zeros(10,1);
- for i = 1:10
- f(i) = abs(x(1)-a(i))+abs(x(2)-b(i));
- end
- % f(1) = abs(x(1)-a(1))+abs(x(2)-b(1));
- % f(2) = abs(x(1)-a(2))+abs(x(2)-b(2));
- % f(3) = abs(x(1)-a(3))+abs(x(2)-b(3));
- % f(4) = abs(x(1)-a(4))+abs(x(2)-b(4));
- % f(5) = abs(x(1)-a(5))+abs(x(2)-b(5));
- % f(6) = abs(x(1)-a(6))+abs(x(2)-b(6));
- % f(7) = abs(x(1)-a(7))+abs(x(2)-b(7));
- % f(8) = abs(x(1)-a(8))+abs(x(2)-b(8));
- % f(9) = abs(x(1)-a(9))+abs(x(2)-b(9));
- % f(10) = abs(x(1)-a(10))+abs(x(2)-b(10));
- end
lingo求解上述最大最小化问题的代码如下:
- model:
- sets:
- factory /1..10/ : a, b;
- endsets
- data:
- a = 1 4 3 5 9 12 6 20 17 8 ;
- b = 2 10 8 18 1 4 5 10 8 9 ;
- enddata
- min = @sum(factory(i):(@abs(x-a(i)) + @abs(y-b(i))));
- x>=3;
- x<=8;
- y>=4;
- y<=10;
- end
多目标规划就是有多个目标函数,我们对多目标规划的解决方法是加权组合转换成单目标规划问题求解,但是需要注意一些事项:比如统一转换成最大化或最小化问题还有就是如果有量纲问题,需要进行消除量纲后 再加权处理。
我们可以看一下这个例题,当然这个例题很简单,直接加权转换成一个线性规划问题,然后求解即可,我们可以考虑改变两个目标函数的权重,然后进行灵敏度分析,这个在建模中也是加分项。
求解上述多目标规划的matlab代码如下:
- %% 多目标规划问题
- clc;
- clear;
- w1 = 0.4; w2 = 0.6; % 两个目标函数的权重 x1 = 5 x2 = 2
- %w1 = 0.5; w2 = 0.5; % 两个目标函数的权重 x1 = 5 x2 = 2
- %w1 = 0.3; w2 = 0.7; % 两个目标函数的权重 x1 = 1 x2 = 6
- c = [w1/30*2+w2/2*0.4 ;w1/30*5+w2/2*0.3]; % 线性规划目标函数的系数
- A = [-1 -1]; b = -7; % 不等式约束
- lb = [0 0]'; ub = [5 6]'; % 上下界
- [x,fval] = linprog(c,A,b,[],[],lb,ub)
- f1 = 2*x(1)+5*x(2)
- f2 = 0.4*x(1) + 0.3*x(2)
通过改变权重进行敏感度分析的模拟,具体的代码如下:
- %% 敏感性分析
- clear;clc
- W1 = 0.1:0.001:0.5; W2 = 1- W1;
- n =length(W1);
- F1 = zeros(n,1); F2 = zeros(n,1); X1 = zeros(n,1); X2 = zeros(n,1); FVAL = zeros(n,1);
- A = [-1 -1]; b = -7; % 不等式约束
- lb = [0 0]; ub = [5 6]; % 上下界
- for i = 1:n
- w1 = W1(i); w2 = W2(i);
- c = [w1/30*2+w2/2*0.4 ;w1/30*5+w2/2*0.3]; % 线性规划目标函数的系数
- [x,fval] = linprog(c,A,b,[],[],lb,ub);
- F1(i) = 2*x(1)+5*x(2);
- F2(i) = 0.4*x(1) + 0.3*x(2);
- X1(i) = x(1);
- X2(i) = x(2);
- FVAL(i) = fval;
- end
-
- % 「Matlab」“LaTex字符汇总”讲解:https://blog.csdn.net/Robot_Starscream/article/details/89386748
- % 在图上可以加上数据游标,按住Alt加鼠标左键可以设置多个数据游标出来。
- figure(1)
- plot(W1,F1,W1,F2)
- xlabel('f_{1}的权重')
- ylabel('f_{1}和f_{2}的取值')
- legend('f_{1}','f_{2}')
-
- figure(2)
- plot(W1,X1,W1,X2)
- xlabel('f_{1}的权重')
- ylabel('x_{1}和x_{2}的取值')
- legend('x_{1}','x_{2}')
-
- figure(3)
- plot(W1,FVAL) % 看起来是两个直线组合起来的下半部分
- xlabel('f_{1}的权重')
- ylabel('综合指标的值')
我们可以看一下敏感度分析的结果,具体如下,通过改变权重,目标函数f1的权重转折点,f1权重越小,说明生成A越大,对污染就越大,那么厂家更倾向于生成B类的。