由于python整数规划的包不太好找,所以就用LINGO来完成数模中整数规划的任务。学了一天半LINGO,算是入门了,记下一些笔记,以后好重新上手。
LINGO的程序框架
下面的语法都是LINGO语言(注意!不是LINDO)
LINDO的主要框架由下所示:
model:
sets:
...
endsets
data:
...
enddata
[OBJ]min = ...;
...
end
LINGO中每条语句都需要分号结尾,命令不需要(比如sets:,endsets这些在LINGO中高亮显示的部分)
sets
LINGO中没有向量,矩阵等概念,只有一个集合的概念。
如何输入向量
我要定义$x = (x_1,x_2,x_3,x_4)$,就可以输入在省略号处输入:input_x/1..4/:x;
其中input_x类似于变量类型(可以取其他名字),表明这后面定义的是长度为4的集合;如果我们还要定义$\theta = (\theta_1,\theta_2,\theta_3,\theta_4,\theta_5)$,则可以一次性输入:input_x/1..4/:x,theta;
也就是说,我们可以同时定义同一长度的多个集合。然后,就可以通过x(1)
或theta(2)
等来指代某个元素或数据
如何输入矩阵
要输入如下的表:
$y_1$ | $y_2$ | $y_3$ | |
---|---|---|---|
$x_1$ | 1 | 2 | 3 |
$x_2$ | 5 | 3 | 7 |
$x_3$ | 9 | 8 | 6 |
$x_4$ | 2 | 4 | 1 |
假设已经通过如下代码input_y/1..3/:y;
定义input_y这个类型
要表示矩阵中的元素,我们需要这样定义:matrix(input_x,input_y):c;
类似与上面的,matrix表示这个集合的类型(可以换其他名字),c是一个集合变量名,括号中第一个位置表示行的集合类型(大小),第二个位置表示列的集合类型。同理,就可以通过c(1,2)这样的形式来指代某个位置的数据或元素。
data
在LINGO中,有些变量是我们要去规划的,有些数据是预先给出的,我们可以将这些都在sets中进行定义,然后在data中将给定的数据进行赋值。例如上面的矩阵,在sets中我们只是定义了矩阵的大小,但里面没有数据。
c =
1,2,3
5,3,7
9,8,6
2,4,1;
由于LINGO以分号作为语句结束标志,所以我们可以跨行输入矩阵。实际上,放在一行也是可以的,如下所示:
c = 1,2,3,5,3,7,9,8,6,2,4,1;
[OBJ] min
这不是一条命令,而是一条语句,所以结尾有分号,表示的是我们要优化的目标。
比如 [OBJ]min = x(1)*x(2)*y(3) + y(1)*y(2)*x(3);
当然,如果是最大化的话,可以将min
换成max
常用函数
在介绍约束条件前,先介绍一下LINGO中常用的函数,因为写约束条件或优化目标常常离不开这些函数。LINGO中函数都是以@开头,加上函数名,比如@for,@gin,@sum
循环—–@for
比如,我们要写一条约束条件:对于任意的i=1,2,3,4,x(i)都大于3。则应该这样写:
@for( input_x(i) : x(i) > 3 );
其中,input_x为x的集合类型,它指示了这个循环的次数
再举一个例子:对于任意的i=1,2,3,4和j=1,2,3,x(i)*y(j)大于5
@for ( matrix(i,j): x(i)*y(j) > 5 );
求和—–@sum
比如,我们要写一约束条件:$\sum_{i=1}^4 x_i <10$
@sum(input_x(i): x(i)) < 10;
注意:不等号在括号的外面,相当于只是一条约束条件
再举一个例子,假设我们没有给$c_{ij}$赋值,就可以对$c_{ij}$进行约束,比如:
@sum(matrix(i,j) : c(i,j)) > 20;
限制为整数—–@gin
比如,我们要限制y(1)为整数,则可以写:
@gin(y(1));
也可以将@gin和@for合用,比如用来限制$x_i$都是整数:
@for( input_x(i): @gin(x(i)) );
限制条件
限制条件其实就是若干条语句,在开头的结构中用min下面的三个省略号表示
可以很简单,比如:
x(1) < 5;
也可以很复杂,比如:
@for(input_x(i):@sum(input_y(j):c(i,j)*y(j)) >= theta(i));
求解
全部写完后,就可以点击Solve按钮(一个小靶子的样子)进行求解。
例子
没有什么比一个简单的例子更容易让人上手一门语言
钢管下料问题
某工厂为客户裁切钢管,原料钢管每根长19米。现在有一客户需要50根4米长的钢管,20根6米长的钢管和15根8米长的钢管。问:
(1) 怎样切割产生的余料最少?
(2) 为节省成本,工厂最多只能使用三种切割模式。在这种情况下,求问怎样切割使用的钢管根数最少?
解:
(1) 用枚举法,共有以下7种切割模式:
4米 | 6米 | 8米 | 余料(单位:米) | |
---|---|---|---|---|
模式1 | 4 | 0 | 0 | 3 |
模式2 | 3 | 1 | 0 | 1 |
模式3 | 2 | 0 | 1 | 3 |
模式4 | 1 | 2 | 0 | 3 |
模式5 | 1 | 1 | 1 | 1 |
模式6 | 0 | 3 | 0 | 1 |
模式7 | 0 | 0 | 2 | 3 |
需求 | 50 | 20 | 15 |
model:
min = 3*x1+x2+3*x3+3*x4+x5+x6+3*x7;
4*x1 + 3*x2 + 2*x3 + x4 + x5 >= 50;
x2 + 2*x4 + x5 + 3*x6 >= 20;
x3 + x5 + 2*x7 >= 15;
@gin(x1);@gin(x2);@gin(x3);@gin(x4);@gin(x5);@gin(x6);@gin(x7);
end
求解可得:最小余料为27米,其中按模式二切割12根,按模式5切割15根
(2) 当有4种钢管时,使用枚举法耗时太大。题目限制只能使用3种切割方式,所以将这三种切割方式所切割的钢管根数分别记为$x_1,x_2,x_3$;记$r_{ij}$为使用$j$种切割方式切割所产生的第$i$种钢管的数量,则有以下约束条件:
$r_{11}x_1+r_{12}x_2+r_{13}x_3 \ge 50$
$r_{21}x_1+r_{22}x_2+r_{23}x_3 \ge 10$
$r_{31}x_1+r_{32}x_2+r_{33}x_3 \ge 20$
$r_{41}x_1+r_{42}x_2+r_{43}x_3 \ge 15$
我们假设合理切割模式的余料不超过3米,则有:
$16 \le 4r_{11}+5r_{21}+6r_{31}+8r_{41} \ge 19$
$16 \le 4r_{12}+5r_{22}+6r_{32}+8r_{42} \ge 19$
$16 \le 4r_{13}+5r_{23}+6r_{33}+8r_{43} \ge 19$
另外,$r_{ij}$和$x_j$都必须为整数
除此之外,我们可以可以缩小可行域。原料钢管用量的下界为:$\lceil \frac{4\times50+5\times10+6\times20+8\times15}{19}\rceil =26$
(找出一个特解)如果使用下面的生产计划:
模式1:切割成4根4米的钢管,需13根;
模式2:切割成1根5米和2根6米的钢管,需10根;
模式3:切割成2根8米的钢管,需8根;
故原料钢管的总根数上界为$13+10+8=31$
总的代码如下:
model:
sets:
pattern/1..3/:x;
tube/1..4/:t, demand, meter;
link(tube,pattern):r;
endsets
data:
demand = 50,10,20,15;
meter = 4,5,6,8;
enddata
[OBJ]min = @sum(pattern(i):x(i));
@for(tube(i):@sum(pattern(j):r(i,j)*x(j))>=demand(i));
@for(pattern(j):@sum(tube(i):r(i,j)*meter(i)) >= 16);
@for(pattern(j):@sum(tube(i):r(i,j)*meter(i)) <= 19);
@for(pattern(j):@gin(x(j)));
@for(link(i,j):@gin(r(i,j)));
@sum(pattern(j):(x(j))) <= 31;
@sum(pattern(j):(x(j))) >= 26;
end
其他问题
读入数据
差不多都可以搜索到方法,写一下读取最常用的excel文件的方法。首先,要在excel中选中要读取的数据区,给它定义一个名称(2016版Excel在“公式”选项卡下),此例中选中的数据区的大小为4*3,定义的名称为data_mat,读取代码如下:
sets:
col/1..3/:x;
row/1..4/:y;
cell(row,col):num;
endsets
data:
num=@OLE('C:\Users\MayMoon\Desktop\data.xlsx',data_mat);
enddata
结果分析
- Reduced Cost
指的是该非基变量每增加一个单位(其他非基变量保持不变),目标函数减少的量(对于max问题) - Slack Or Surplus
指的是资源的剩余 - Dual Price(影子价格)
指的是最优解情况下,资源增加1单位效益的增量
参考资料
- Lingo超经典案例大全
- 《优化模型与LINDO/LINGO优化软件》PPT by 谢金星