前言
1.使用MatLab求解线性规划需要安装Optimization Toolbox附加功能
2.本文总结了教材《数学建模算法与应用(司守奎)》第1章的内容,详情请参考教材
3.本文总结了二维线性规划问题,如何使用MatLab快速解决,教材对于这部分问题推荐使用Lingo,但其实MatLab也可以解决
如果不需要复习教材《数学建模算法与应用(司守奎)》第1章,请直接跳到目录最后一节
MatLab线性规划标准形式
min f(x)
A·x <= b
Aeq·x = beq
lb <= x <= ub
对标准形式的解释
x:决策变量,所有直接或间接影响"价值"的变量都是决策变量
f:价值向量,描述决策变量对"价值"影响权重的变量
A和b:线性不等式约束,A是一个矩阵,b是一个列向量
Aeq和beq:线性等式约束,Aeq是一个矩阵,beq是一个列向量
lb和ub:决策变量的下界向量和上界向量,代表决策变量的取值范围,为列向量
对于最大化价值的线性规划问题max f(x),有以下转化公式:
max f(x) = min -f(x)
例:求x + 3y的最大值,相当于求-x - 3y的最小值
MatLab求解线性规划的函数
>> linprog(f, A, b, Aeq, beq, lb, ub);
linprog()函数返回最佳决策变量和最佳决策变量对应的最小价值
该函数的参数可以不写完整,以下都是合法的调用格式
[x, fval] = linprog(f, A, b);
[x, fval] = linprog(f, A, b, Aeq, beq);
[x, fval] = linprog(f, A, b, Aeq, beq, lb, ub);
注意:
1.当没有线性不等式约束,但有线性等式约束时,要在A和b位置传入空矩阵
[x, fval] = linprog(f, [], [], Aeq, beq);
2.如果决策变量下界为0,使用zeros()函数快速生成下界向量lb
zeros(m, n) 生成m * n的全0矩阵
lb = zeros(n, 1);
[x, fval] = linprog(f, A, b, Aeq, beq, lb, ub);
3.使用inf()函数快速生成上界向量ub
inf(m, n) 生成m * n的全inf矩阵
Inf是正无穷大
ub = inf(n, 1);
[x, fval] = linprog(f, A, b, Aeq, beq, lb, ub);
带有绝对值的线性规划
min f(|x|)
A · x <= b
对于带有绝对值的线性规划,需要去绝对值,转换为等价的线性规划
去绝对值的方法
对决策变量作线性变换:
x = u - v
|x| = u + v
(u, v >= 0)
线性变换后得到的新决策变量:
x’ = [u; v]
转化后的等效线性规划:
min f(u + v) = [f, f] x’
A · (u - v) <= b即[A, -A] · x’ <= b
x’ >= 0
解决带绝对值的线性规划的伪码描述
设有n个决策变量,去绝对值后的新决策变量有2n个,且新决策变量必有下界0(u, v >= 0)
f = [...]; //初始化价值向量
A = [...]; b = [...] //初始化线性不等式约束
Aeq = [...]; beq = [...] //初始化线性不等式约束
f = [f; f]; //价值向量被延长一倍
A = [A, -A];
Aeq = [Aeq, -Aeq]; //约束矩阵被延长一倍
//为什么延长的价值向量不带符号,而延长的约束矩阵带符号,这是由上文"转化后的等效线性规划"决定的
lb = zeros(2n, 1); //新决策变量必有下界0,注意新决策变量有2n个
二维线性规划
形式如下的线性规划,被称为二维线性规划
min ∑xij, i <= m && j <= n
对于二维动态规划,决策变量是二维的,所以价值向量变成了价值矩阵,约束矩阵等也相应地进行了升维
Lingo可以很方便对二维动态规划进行处理,MatLab不行,所以要把m * n的二维线性规划,转换成等价的l(l = m * n)变量的一维线性规划(保持决策变量数量不变)
MatLab处理时可以使用以下技巧,把二维线性规划转化为一维线性规划:
前文提到:数学建模第二天,MatLab矩阵入门
矩阵元素的编址有下标编址和序号编址两种,实际上序号编址方式,就是在逻辑上对矩阵降维打击,把矩阵当成向量进行访问,矩阵的下标编址和序号编址是一一对应的,这使我们可以很方便进行转换
例:把2 * 3的价值矩阵A转换成等价价值向量
>> A = A(:);
同理,对于每一个线性不等式约束和线性等式约束,我们都采用A = A( : );指令,进行降维
当数据量不大时,也可以手动输入线性约束矩阵
注意:要降维的矩阵,初始化时要初始化成矩阵的转置
例:某线性规划有决策变量有5 * 4 =20个,初始化其价值矩阵max z = 1.15x(4, 1) + 1.4x(2, 3) + 1.25x(3, 2) + 1.06x(5, 4),并将其转换为价值向量
>> f = zeros(4, 5);
>> f(1, 4) = 1.15;
>> f(3, 2) = 1.4;
>> f(2, 3) = 1.25;
>> f(4, 5) = 1.06;
>> f = f(:);
可以看出,价值矩阵应该是5 * 4的,但我们将其初始化为4 * 5的转置矩阵,这样做是因为MatLab中的矩阵是以列向量为单位进行存储和寻访的,初始化为转置矩阵保证了寻访顺序的一致
对于约束矩阵,对每一行都进行一次降维处理,具体的处理方式和价值矩阵同理
例:初始化m * n个决策变量的约束矩阵,设一共有c个约束方程
伪码描述:
//初始化约束矩阵
>> A = zeros(c, m * n);
//对每个约束方程对应的行向量都要进行降维
for cnt = 1:c
//初始化行向量
>> row = zeros(n, m);
//赋初值
>> row(j1, i1) = ...;
>> row(j2, i2) = ...;
...
//降维行向量
>> row = row(:);
//更新约束矩阵第cnt行的系数
A(cnt, :) = row;
end
虽然写的是循环结构,但实际上row赋初值的过程是没办法用循环结构实现的
当线性规划的所有参数都降维后就可以直接调用linprog()函数了
最后,如果想让最佳决策值向量恢复为矩阵,则需要进行升维:
>> mat = zeros(m, n);
>> row = zeros(1, n);
>> for i = 1:m
>> for j = 1:n
>> row(j) = x((i - 1) * n + j);
>> end
>> mat(i, :) = row;
>> end
>> mat
或者调用reshape函数进行向量升维:
>> mat = reshape(mat, m, n);