一、先以一个小示例入门

下面是我们常见的线性规划模型。

目标函数: min \sum_{j=1}^{2}{\sum_{i=1}^{6}{c_{ij}\sqrt{(x_{j}-a_{i})^{2}-(y_{j}-b_{i})^{2}}}}

决策变量: c_{ij}

约束条件:

已知参数:

a=1.25, 8.75 ,0.5, 5.75 ,3 ,7.25

b=1.25, 0.75 ,4.75 ,5,6.5, 7.75

d=3 ,5 ,4, 7, 6 ,11

e=20, 20

x=5, 2

y=1, 7

那我们怎么在lingo中表达出上面的数学规划模型呢?

1、首先定义指标的集合、决策变量和已知变量

sets:
S/1..6/: a,b,d ;
T/1..2/: e,x,y ;
U(S,T): c ;
endsets

定义集合以 sets: endsets 关键字开始,S代表i=1,2,...,6的下标集合,T代表j=1,2的下标集合,U作为S,T的派生集合为 c_{ij} 的集合。

lingo语句结尾以分号 ;结束

2、对于变量已知的数据输入

data:
a=1.25 8.75 0.5 5.75 3 7.25;
b=1.25 0.75 4.75 5 6.5 7.75;
d=3 5 4 7 6 11;
e=20 20;
x=5 2;
y=1 7;
enddata

已知参数的数据输入以 data: enddata 关键字开始,多个数值间用空格隔开。

3、目标函数编写

min= @sum(T(j):@sum(S(i):
	c(i,j)*@sqrt(( x(j) -a(i) )^2 + ( y(j) - b(i) )^2 ) 
	));

模型中求和符号用 @sum 函数表示,求和个数用相应下标的集合表示,如T(j)表示j=1,2。

4、约束条件编写

@for(S(i):
	@sum(T(j): c(i,j))=d(i)
	);
@for(T(j):
	@sum(S(i): c(i,j))<= e(j)
	);

这样整个模型就写完了,接下来点击运行便可以了。

二、LINGO中的集

集是一群相互联系的对象,这些对象也称为集的成员,每个集成员可能有一个或多个与之有关联的特征,我们把这些特征称为属性。属性值可以预先给定,也可以是未知的,有待于LINGO求解。借助于集,能够用一个单一的、长的、简明的复合公式表示一系列相似的约束,从而可以快速方便地表达规模较大的模型。

集以关键字“sets:”开始,以“endsets”结束。

原始集:由一些最基本的对象组成的,如上例的S、T。

派生集:用一个或多个其它集来定义的,也就是说,它的成员来自于其它已存在的集,如U。

定义原始集:setname[/member_list/][:attribute_list];

sets:
students/John  Jill, Rose  Mike/: sex, age;
endsets

定义派生集:setname(parent_set_list)[/member_list/][:attribute_list];

sets:
product/A B/;
machine/M N/;
week/1..2/;
allowed(product,machine,week):x;
endsets

稠密集:派生集成员由父集成员所有的组合构成。

稀疏集:如果限制派生集的成员,使它成为父集成员所有组合构成的集合的一个子集。

显式罗列:

allowed(product,machine,week)/A M 1,A N 2,B N 1/;

如果需要生成一个大的、稀疏的集,则利用过滤器:

sets:
!学生集:性别属性sex,1表示男性,0表示女性;年龄属性age.  ;
students/John,Jill,Rose,Mike/:sex,age;
!男学生和女学生的联系集:友好程度属性friend,[0,1]之间的数。;
linkmf(students,students)|sex(&1) #eq# 1 #and# sex(&2) #eq# 0: friend;
!男学生和女学生的友好程度大于0.5的集;
linkmf2(linkmf) | friend(&1,&2) #ge# 0.5 : x;
endsets

data:
sex,age = 1 16
	0 14
	0 17
	0 13;
friend = 0.3 0.5 0.6;
enddata

用竖线(|)来标记过滤器的开始,&1可看作派生集的第1个原始父集的索引,它取遍该原始父集的所有成员。

三、逻辑运算符

LINGO具有9种逻辑运算符:

  • #not# 否定该操作数的逻辑值,#not#是一个一元运算符
  • #eq# 若两个运算数相等,则为true;否则为flase
  • #ne# 若两个运算符不相等,则为true;否则为flase
  • #gt# 若左边的运算符严格大于右边的运算符,则为true;否则为flase
  • #ge# 若左边的运算符大于或等于右边的运算符,则为true;否则为flase
  • #lt# 若左边的运算符严格小于右边的运算符,则为true;否则为flase
  • #le# 若左边的运算符小于或等于右边的运算符,则为true;否则为flase
  • #and# 仅当两个参数都为true时,结果为true;否则为flase
  • #or# 仅当两个参数都为false时,结果为false;否则为true

四、数据输入

数据部分:输入集成员和数据。数据部分以关键字“data:”开始,以关键字“enddata”结束。

object_list = value_list

对象列(object_list)包含要指定值的属性名、要设置集成员的集名,用逗号或空格隔开。

数值列(value_list)包含要分配给对象列中的对象的值,用逗号或空格隔开。

sets:
set1/A,B,C/: X,Y;
endsets

data:
X=1,2,3;
Y=4,5,6;
enddata

复合数据声明:

sets:
set1/A,B,C/: X,Y;
endsets

data:
X,Y=	1 4
	2 5
	3 6;
enddata

可以在数据声明的右边输入一个值来把所有的成员的该属性指定为一个值。

sets:
days /MO,TU,WE,TH,FR,SA,SU/:needs;
endsets

data:
needs = 20;
enddata

实时数据处理:

在某些情况,对于模型中的某些数据并不是定值。在本该放数的地方输入一个问号(?)。

data:
interest_rate,inflation_rate = .085  ?;
enddata

数据部分的未知数值:

有时只想为一个集的部分成员的某个属性指定值,而让其余成员的该属性保持未知,以便让LINGO去求出它们的最优值。

sets:
years/1..5/: capacity;
endsets

data:
capacity =  ,34,20 , , ;
enddata

初始部分:决策变量设置初始值。

对实际问题的建模时,初始部分并不起到描述模型的作用,在初始部分输入的值仅被LINGO求解器当作初始点来用,并且仅仅对非线性模型有用。

初始部分以“init:”开始,以“endinit”结束。

init:
X, Y = 0, .1;
endinit
Y=@log(X);
X^2+Y^2<=1;

数据输入和输出函数:

输入和输出函数可以把模型和外部数据比如文本文件、数据库和电子表格等连接起来。

@file函数:

该函数用从外部文件中输入数据,可以放在模型中任何地方。该函数的语法格式为@file(’filename’)

sets:
warehouses/ @file('1_2.txt')/: capacity;
vendors/ @file('1_2.txt')/: demand;
links(warehouses,vendors): cost, volume;
endsets

data:
capacity = @file('1_2.txt');
demand = @file('1_2.txt') ;
cost = @file('1_2.txt');
enddata

1_2.txt文件。其内容如下:记录结束标记(~)之间的数据文件部分称为记录。

!warehouses成员;
WH1 WH2 WH3 WH4 WH5 WH6 ~
!vendors成员;
V1 V2 V3 V4 V5 V6 V7 V8 ~
!产量;
60 55 51 43 41 52 ~
!销量;
35 37 22 32 41 32 43 38 ~
!单位运输费用矩阵;
6 2 6 7 4 2 5 9
4 9 5 3 8 5 8 2
5 2 1 9 7 4 3 3
7 6 7 3 9 2 7 1
2 3 9 5 7 2 6 5
5 5 2 2 8 1 4 3

@text函数:

该函数被用在数据部分用来把解输出至文本文件中。它可以输出集成员和集属性值。

@text([’filename’]


sets:
days/mon..sun/: required,start;
endsets

data:
!每天所需的最少职员数;
required = 20 16 13 16 19 14 12;
@text('d:\out.txt')=days '至少需要的职员数为' start;
enddata

@ole函数:

@OLE是从EXCEL中输入或输出数据的接口函数。

当使用@OLE时,LINGO先加载EXCEL工作簿,再通知EXCEL加载指定的sheet表,最后从电子数据表中获得范围Ranges。

集成员最好用文本格式,集属性最好用数值格式。

@OLE只能读一维或二维的Ranges(在单个的EXCEL工作表(sheet)中),但不能读间断的或三维的Ranges。Ranges是自左而右、自上而下来读。

sets:
PRODUCT;  !产品;
MACHINE;  !机器;
WEEK;!周;
ALLOWED(PRODUCT,MACHINE,WEEK):x,y;   !允许组合及属性;
endsets

data:
rate=0.01;
PRODUCT,MACHINE,WEEK,ALLOWED,x,y=@OLE('D:\IMPORT.XLS');
@OLE('D:\IMPORT.XLS')=rate;
enddata

(1)定义Ranges名称

定义名称      单元格范围
PRODUCT       B3:B4
MACHINE       C3:C4
WEEK          D3:D5
ALLOWED       B8:D10
X             F8:F10
Y             G8:G10
rate           C13

五、LINGO函数

1、算术运算符

^ 乘方
﹡ 乘
/ 除
﹢ 加
﹣ 减

2、关系运算符

=
<=
>=

LINGO中还能用“<”表示小于等于关系,“>”表示大于等于关系。LINGO并不支持严格小于和严格大于关系运算符。

如让A严格小于B:A+ε<=B,这里ε是一个小的正数。

3、数学函数

@abs(x)             返回x的绝对值
@sin(x)             返回x的正弦值,x采用弧度制
@cos(x)             返回x的余弦值
@tan(x)             返回x的正切值
@exp(x)             返回常数e的x次方
@log(x)             返回x的自然对数
@lgm(x)             返回x的gamma函数的自然对数
@sign(x)            如果x<0返回-1;否则,返回1
@floor(x)           返回x的整数部分。当x>=0时,返回不超过x的最大整数;当x<0时,返回不低于x的最大整数。
@smax(x1,x2,„,xn)   返回x1,x2,„,xn中的最大值
@smin(x1,x2,„,xn)   返回x1,x2,„,xn中的最小值

4、变量界定函数

变量界定函数实现对变量取值范围的附加限制,共4种:

@bin(x)        限制x为0或1
@bnd(L,x,U)    限制L≤x≤U
@free(x)       取消对变量x的默认下界为0的限制,即x可以取任意实数
@gin(x)        限制x为整数

5、集操作函数

@in(set_name,primitive_index_1 [,primitive_index_2,„]

如果元素在指定集中,返回1;否则返回0

sets:
I/x1..x4/;
B(I)/x2/;
C(I) | #not# @in(B,&1): ;
endsets

返回在集set_name中原始集成员primitive_set_element的索引:

@index([set_name,] primitive_set_element)


sets:
S1/A B C/;
S2/X Y Z/;
S3(S1,S2)/A X, A Z, B Y, C X/;
endsets
X=@in(S3,@index(S1,B),@index(S2,Y));

6、集循环函数

集循环函数遍历整个集进行操作。

@function(setname[(set_index_list)[|conditional_qualifier]]:expression_list);
  • setname: 是要遍历的集;
  • set_ index_list: 是集索引列表;
  • conditional_qualifier: 是用来限制集循环函数的范围;
  • expression_list: 是被应用到每个集成员的表达式列表。

@for函数

产生序列{1,4,9,16,25}

sets:
number/1..5/:x;
endsets

@for(number(I): x(I)=I^2);

@sum函数

该函数返回遍历指定的集成员的一个表达式的和。

求向量[5,1,3,4,6,10]前5个数的和。

data:
N=6;
enddata

sets:
number/1..N/:x;
endsets

data:
x = 5 1 3 4 6 10;
enddata

s=@sum(number(I) | I #le# 5: x);

@min和@max

返回指定的集成员的一个表达式的最小值或最大值

求向量[5,1,3,4,6,10]前5个数的最小值,后3个数的最大值

data:
N=6;
enddata

sets:
number/1..N/:x;
endsets

data:
x = 5 1 3 4 6 10;
enddata

minv=@min(number(I) | I #le# 5: x);
maxv=@max(number(I) | I #ge# N-2: x);

7、判断函数

@if(logical_condition,true_result,false_result)

@if函数将评价一个逻辑表达式logical_condition,如果为真,返回true_ result,否则返回false_result

min=fx+fy;
fx=@if(x #gt# 0, 100,0)+2*x;
fy=@if(y #gt# 0,60,0)+3*y;
x+y>=30;