LINGO快速入门
LINGO是用来求解线性和非线性优化问题的简易工具,包含了 lindo的全部功能。
LINGO内置了一种建立最优化模型的语言,
可以简便地表达大规模问题,利用 LINGO高效的求解器可快速求解并分析结果。
运行 lingo
当你在 windows下开始运行 LINGO系统时,会得到类似下面的一个窗口:
在主窗口内的标题为 LINGO Model – LINGO1的窗口是 LINGO的默认模型窗口,建立的模型都都要在该窗口内编码实现。
外层是主框架窗口,包含了所有菜单命令和工具条,其它所有的窗口将被包含在主窗口之下。
下面是输入一个简单程序后的情况,
例 1 奶制品的生产与销售一奶制品加工厂用牛奶生产 A,B两种奶制品,
1桶牛奶可以在甲类设备上用 12小时加工成 3公斤的 A,
或者在乙类设备上用 8小时加工成 4公斤的 B.
根据市场需求,生产的 A,B全部能售出,且每公斤 A获利
24元,每公斤 B获利 16元,
现在加工厂每天能得到 50桶牛奶的供应,每天正式工人总的劳动时间为 480小时,并且甲类生产设备每天至多能加工 100公斤的 A,乙类设备的生产能力没有限制,
试为该加工厂制订一个生产计划,使每天的获利最大,
回顾解,设每天用于生产 A,B两种产品的牛奶分别为 x,y桶,
加工厂可获利 Z元,于是模型为
yxZ 6472m a x


,0,
,1003
,480812
,50
..
yx
x
yx
yx
ts
Lindo程序,
max 72x+64y
st
x+y<50
12x+8y<480
3x<100
end
lindo程序与线性规划数学模型的形式几乎相同,
yxZ 6472m a x


,0,
,1003
,480812
,50
..
yx
x
yx
yx
ts
Lindo程序,
max 72x+64y
st
x+y<50
12x+8y<480
3x<100
end
Lingo程序,
Model:
max=72*x+64*y;
x+y<50;
12*x+8*y<480;
3*x<100;
end
对于简单线性规划,
lindo比 lingo方便些,
然后点击工具条上的按钮 即可。
例 2 使用 LINGO软件计算 6个发点 8个收点的最小费用运输问题。
产销单位运价如下表。
单 销地位运产地 价
B1 B2 B3 B4 B5 B6 B7 B8 产量
A1 6 2 6 7 4 2 5 9 60
A2 4 9 5 3 8 5 8 2 55
A3 5 2 1 9 7 4 3 3 51
A4 7 6 7 3 9 2 7 1 43
A5 2 3 9 5 7 2 6 5 41
A6 5 5 2 2 8 1 4 3 52
销量 35 37 22 32 41 32 43 38
解,设从产地 Ai到销地 Bj的运输量为 xij,记从产地 Ai到销地
Bj的单位运价为 cij,产地 Ai的产量为 yi,销地 Bj的需求量为
dj,则此问题的模型为




0
6,,2,1,
8,,2,1,
..
m i n
8
1
6
1
6
1
8
1
ij
i
j
ij
j
i
ij
ij
i j
ij
x
iyx
jdx
ts
xcZ
这里决策变量为 xij,而 cij,yi,dj已知,
这个模型具有推广性使用 LINGO软件,编制程序如下:
model:
!6发点 8收点运输问题 ;
sets:
warehouses/wh1..wh6/,capacity;
vendors/v1..v8/,demand;
links(warehouses,vendors),cost,
volume;
endsets
min=@sum(links,cost*volume);
@for(vendors(J):
@sum(warehouses(I),
volume(I,J))=demand(J));
@for(warehouses(I):
@sum(vendors(J),
volume(I,J))<=capacity(I));
定义集目标函数需求约束产量约束
data:
capacity=60 55 51 43 41 52;
demand=35 37 22 32 41 32 43 38;
cost=6 2 6 7 4 2 9 5
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;
enddata
end
数据段这里 cost就是二维数表从上面可知,这个 lingo程序同样具有推广性,
model:
!6发点 8收点运输问题 ;
sets:
warehouses/wh1..wh6/,capacity;
vendors/v1..v8/,demand;
links(warehouses,vendors),cost,
volume;
endsets
min=@sum(links,cost*volume);
@for(vendors(J):
@sum(warehouses(I),
volume(I,J))=demand(J));
@for(warehouses(I):
@sum(vendors(J),
volume(I,J))<=capacity(I));
定义 Ai以及与之相关的产量记号
Bj dj
定义派生集及其属性 cij,xij
ij
i j
ij xcZ

6
1
8
1
m i n
8,,2,1,
6
1

jdx j
i
ij
6,,2,1,
8
1

iyx i
j
ij
LINGO中的集对实际问题建模的时候,总会遇到一群或多群相联系的对象,比如工厂、消费者群体、交通工具和雇工等等。
LINGO允许把这些相联系的对象聚合成集( sets)。一旦把对象聚合成集,就可以利用集来最大限度的发挥 LINGO
建模语言的优势。
现在我们将深入介绍如何创建集,并用数据初始化集的属性。学完本节后,你对基于建模技术的集如何引入模型会有一个基本的理解。
为什么使用集?
集是 LINGO建模语言的基础,是程序设计最强有力的基本构件。借助于集,能够用一个单一的、长的、简明的复合公式表示一系列相似的约束,从而可以快速方便地表达规模较大的模型。
什么是集集 是一群相联系的对象,这些对象也称为 集的成员 。一个集可能是一系列产品、卡车或雇员。每个集成员可能有一个或多个与之有关联的特征,我们把这些特征称为 属性 。
属性值可以预先给定,也可以是未知的,有待于 LINGO求解。例如,产品集中的每个产品可以有一个价格属性;卡车集中的每辆卡车可以有一个牵引力属性;雇员集中的每位雇员可以有一个薪水属性,也可以有一个生日属性等等。
LINGO有两种类型的集,原始集 (primitive set)和 派生集 (derived set)。
一个原始集是由一些最基本的对象组成的。
一个派生集是用一个或多个其它集来定义的,也就是说,
它的成员来自于其它已存在的集。
lingo模型的集部分集部分 是 LINGO模型的一个可选部分。在 LINGO
模型中使用集之前,必须在集部分事先定义。 集部分以关键字,sets:”开始,以,endsets”结束 。一个模型可以没有集部分,或有一个简单的集部分,或有多个集部分。一个集部分可以放置于模型的任何地方,但是一个集及其属性在模型约束中被引用之前必须定义了它们。
定义原始集为了定义一个原始集,必须详细声明:
·集的名字
·可选,集的成员
·可选,集成员的属性定义一个原始集,用下面的语法:
setname[/member_list/][:attribute_list];
Setname是你选择的来标记集的名字,最好具有较强的可读性。集名字必须严格符合标准命名规则:以拉丁字母或下划线
( _)为首字符,其后由拉丁字母( A—Z)、下划线、阿拉伯数字( 0,1,…,9)组成的总长度不超过 32个字符的字符串,
且不区分大小写。
注意:该命名规则同样适用于集成员名和属性名等的命名。
Member_list是集成员列表。如果集成员放在集定义中,那么对它们可采取显式罗列和隐式罗列两种方式。如果集成员不放在集定义中,那么可以在随后的数据部分定义它们。
注意:用,[]”
表示该部分内容可选。下同。
① 当 显式罗列成员 时,必须为每个成员输入一个不同的名字,中间用空格或逗号搁开,允许混合使用。
例 可以定义一个名为 students的原始集,它具有成员
John,Jill,Rose和 Mike,属性有 sex和 age:
sets:
students/John Jill,Rose Mike/,sex,age;
endsets
② 当 隐式罗列成员 时,不必罗列出每个集成员。可采用如下语法:
setname/member1..memberN/[,attribute_list];
这里的 member1是集的第一个成员名,memberN是集的最末一个成员名。 LINGO将自动产生中间的所有成员名。
LINGO也接受一些特定的首成员名和末成员名,用于创建一些特殊的集。列表如下:
隐式成员列表格式 示例 所产生集成员
1..n 1..5 1,2,3,4,5
StringM..StringN Car2..car14 Car2,Car3,Car4,…,Car14
DayM..DayN Mon..Fri Mon,Tue,Wed,Thu,Fri
MonthM..MonthN Oct..Jan Oct,Nov,Dec,Jan
MonthYearM..Mont
hYearN Oct2001..Jan2002
Oct2001,Nov2001,Dec
2001,Jan2002
③ 集成员不放在集定义中,而在随后的数据部分来定义。
例 2.2
!集部分 ;
sets:
students:sex,age;
endsets
!数据部分 ;
data:
students,sex,age= John 1 16
Jill 0 14
Rose 0 17
Mike 1 13;
enddata
集成员无论用何种字符标记,它的索引都是从 1开始连续计数。在 attribute_ list可以指定一个或多个集成员的属性,属性之间必须用逗号隔开。
可以把集、集成员和集属性同 C语言中的结构体作个类比。如下图:
集 ←→ 结构体集成员 ←→ 结构体的域集属性 ←→ 结构体实例
LINGO内置的建模语言是一种描述性语言,用它可以描述现实世界中的一些问题,然后再借助于 LINGO求解器求解。因此,集属性的值一旦在模型中被确定,
就不可能再更改。 在 LINGO中,只有在 初始部分 中给出的集属性值在以后的求解中可更改。这与前面并不矛盾,初始部分是 LINGO求解器的需要,并不是描述问题所必须的。
定义派生集为了定义一个派生集,必须详细声明:
·集的名字
·父集的名字
·可选,集成员
·可选,集成员的属性可用下面的语法定义一个派生集:
setname(parent_set_list)[/member_list/][:attribut
e_list];
setname是集的名字。 parent_set_list是已定义的集的列表,多个时必须用逗号隔开。如果没有指定成员列表,那么 LINGO会自动创建父集成员的所有组合作为派生集的成员。 派生集的父集既可以是原始集,也可以是其它的派生集 。
sets:
product/A B/;
machine/M N/;
week/1..2/;
allowed(product,machine,week):x;
endsets

LINGO生成了三个父集的所有组合共八组作为 allowed集的成员。列表如下:
编号 成员
1 (A,M,1)
2 (A,M,2)
3 (A,N,1)
4 (A,N,2)
5 (B,M,1)
6 (B,M,2)
7 (B,N,1)
8 (B,N,2)
data:
x=2 3 4 5 6 7 8 9;
enddata
Variable Value
X( A,M,1) 2.000000
X( A,M,2) 3.000000
X( A,N,1) 4.000000
X( A,N,2) 5.000000
X( B,M,1) 6.000000
X( B,M,2) 7.000000
X( B,N,1) 8.000000
X( B,N,2) 9.000000
成员列表被忽略时,派生集成员由父集成员所有的组合构成,
这样的派生集成为 稠密集 。如果限制派生集的成员,使它成为父集成员所有组合构成的集合的一个真子集,这样的派生集成为 稀疏集 。同原始集一样,派生集成员的声明也可以放在数据部分。一个派生集的成员列表有两种方式生成:
①显式罗列;②设置成员资格过滤器。当采用方式①时,必须显式罗列出所有要包含在派生集中的成员,并且罗列的每个成员必须属于稠密集。使用前面的例子,显式罗列派生集的成员:
allowed(product,machine,week)/A M 1,A N 2,B N 1/;
如果需要生成一个大的、稀疏的集,那么显式罗列就很讨厌。
幸运地是许多稀疏集的成员都满足一些条件以和非成员相区分。我们可以把这些逻辑条件看作过滤器,在 LINGO生成派生集的成员时把使逻辑条件为假的成员从稠密集中过滤掉。
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
用竖线
( |)来标记一个成员资格过滤器的开始。
注意如果派生集 B的父集是另外的派生集 A,那么上面所说的原始父集是集 A向前回溯到最终的原始集,其顺序保持不变,并且派生集 A的过滤器对派生集 B仍然有效。因此,
派生集的索引个数是最终原始父集的个数,索引的取值是从原始父集到当前派生集所作限制的总和。
总的来说,LINGO可识别的集只有两种类型:原始集和派生集。 不同集类型的关系见下图。
集稠密集原始集显式罗列稀疏集过滤器派生集
LINGO集类型
LINGO函数
LINGO有 9种类型的函数:
1,基本运算符:包括算术运算符、逻辑运算符和关系运算符
2,数学函数:三角函数和常规的数学函数
3,金融函数,LINGO提供的两种金融函数
4,概率函数,LINGO提供了大量概率相关的函数
5,变量界定函数:这类函数用来定义变量的取值范围
6,集操作函数:这类函数为对集的操作提供帮助
7,集循环函数:遍历集的元素,执行一定的操作的函数
8,数据输入输出函数:这类函数允许模型和外部数据源相联系,进行数据的输入输出
9,辅助函数:各种杂类函数基本运算符
1 算术运算符算术运算符是针对数值进行操作的。 LINGO提供了 5种二元运算符:
^ 乘方
﹡ 乘
/ 除
﹢ 加
﹣ 减
LINGO唯一的一元算术运算符是取反函数,﹣,。
这些运算符的优先级由高到底为:
高 ﹣ (取反)

﹡ /
低 ﹢ ﹣
运算符的运算次序为从左到右按优先级高低来执行。运算的次序可以用圆括号“()”来改变。
在 LINGO中,逻辑运算符主要用于集循环函数的条件表达式中,来控制在函数中哪些集成员被包含,哪些被排斥。在创建稀疏集时用在成员资格过滤器中。
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
3 关系运算符在 LINGO中,关系运算符主要是被用在模型中,来指定一个表达式的左边是否等于、小于等于、或者大于等于右边,形成模型的一个约束条件。关系运算符与逻辑运算符
#eq#,#le#,#ge#截然不同,前者是模型中该关系运算符所指定关系的为真描述,而后者仅仅判断一个该关系是否被满足:满足为真,不满足为假。
LINGO有三种关系运算符:,=”、,<=”和,>=”。
LINGO中还能用,<”表示小于等于关系,,>”表示大于等于关系。 LINGO并不支持严格小于和严格大于关系运算符。
然而,如果需要严格小于和严格大于关系,比如让 A严格小于 B:
A<B,
那么可以把它变成如下的小于等于表达式:
A+ε<=B,
这里 ε是一个小的正数,它的值依赖于模型中 A小于 B多少才算不等。
下面给出以上三类操作符的优先级:
高 #not# ﹣ (取反)

﹡ /
﹢ ﹣
#eq# #ne# #gt# #ge# #lt# #le#
#and# #or#
低 <= = >=
LINGO提供了大量的标准数学函数:
@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中的最小值
2 数学函数其它的就不介绍了,
建模时需注意的几个基本问题
1.尽量使变量实数化,减少整数变量和整数约束,
2.尽量使用光滑化,减少非光滑约束的个数,如少用绝对值,符号函数,取整函数,多个变量求最大最小,四舍五入等等,
3.尽量使用线性模型,减少非线性约束和非线性变量的个数,
4.合理设定变量的上下界,尽可能给出变量的初始值,
5.模型中使用的参数数量级要适当 (一般 10-2到 103级 )