用LINGO做整数规划

由于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单位效益的增量

参考资料

  1. Lingo超经典案例大全
  2. 《优化模型与LINDO/LINGO优化软件》PPT by 谢金星