数学软件Lingo部分.docx
- 文档编号:7828932
- 上传时间:2023-01-26
- 格式:DOCX
- 页数:33
- 大小:139.40KB
数学软件Lingo部分.docx
《数学软件Lingo部分.docx》由会员分享,可在线阅读,更多相关《数学软件Lingo部分.docx(33页珍藏版)》请在冰豆网上搜索。
数学软件Lingo部分
Lingo部分
Lingo是LinearInteractiveandGeneralOptimizer的缩写,即“交互式线性和通用优化求解器”,由美国LINDO系统公司(LindoSystemInc.)推出。
Lingo可以用于求解线性规划、非线性规划、整数规划、0-1整数规划等,也可以用于一些线性和非线性方程组的求解。
功能十分强大,是求解优化模型的最佳选择。
其特色在于内置建模语言,提供十几个内部函数,方便灵活,而且执行速度非常快。
能方便与EXCEL,数据库等其他软件交换数据,本节以13.0版本为例。
目前版本为14.0。
一、Lingo入门
在windows下运行Lingo,会得到下面的一个窗口:
图1Lingo程序界面
外层是主框架窗口,包含了所有菜单命令和工具条,其它所有的窗口将被包含在主窗口之下。
在主窗口内的标题为Lingo13.0–LingoModel–Lingo1的窗口是Lingo的默认模型窗口,建立的模型都要在该窗口内编码实现。
下面举两个例子。
例如,在Lingo中求解如下的LP问题:
在模型窗口中输入如下代码:
max=80*x1+45*x2;
20*x1+5*x2<=400;
15*x1+10*x2<=450;
然后点击工具条上的按钮即可。
例如,使用Lingo软件计算6个发点8个收点的最小费用运输问题。
产销单位运价如下表。
表1单位运价表
销地
产地
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
设从发点
到收点
的运输量为
,单位运价为
。
本问题的决策变量为
,可建立如下的线性规划模型:
使用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=605551434152;
demand=3537223241324338;
cost=62674295
49538582
52197433
76739271
23957265
55228143;
Enddata
end
然后点击工具条上的按钮即可。
开头用感叹号(!
),末尾用分号(;)表示注释,可跨多行。
从上例可以看出,Lingo编写程序非常简洁,
二、Lingo使用简介
下面主要介绍Lingo中的集、数据和函数。
1.Lingo模型中的集
集是Lingo建模语言的基础,是程序设计最强有力的基本构件。
借助于集,能够用一个单一的、长的、简明的复合公式表示一系列相似的约束,从而可以快速方便地表达规模较大的模型。
集是一群相联系的对象,这些对象也称为集的成员。
一个集可能是一系列产品、卡车或雇员。
每个集成员可能有一个或多个与之有关联的特征,我们把这些特征称为属性。
属性值可以预先给定,也可以是未知的,有待于Lingo求解。
Lingo有两种类型的集:
原始集(primitiveset)和派生集(derivedset)。
一个原始集是由一些最基本的对象组成的。
一个派生集是用一个或多个其它集来定义的,也就是说,它的成员来自于其它已存在的集。
集是Lingo模型的一个可选部分。
在Lingo模型中使用集之前,必须在集部分事先定义。
集部分以关键字“sets:
”开始,以“endsets”结束。
一个模型可以没有集部分,或有一个简单的集部分,或有多个集部分。
一个集部分可以放置于模型的任何地方,但是一个集及其属性在模型约束中被引用之前必须定义了它们。
(1)原始集
定义原始集的语法为:
setname[/member_list/][:
attribute_list]
其中setname为集的名称,以字母(A-Z)或下划线(_)为首字符,其后由字母、下划线、阿拉伯数字(0,1,…,9)组成的总长度不超过32个字符的字符串,且不区分大小写。
member_list为集的成员列表,可以采取显式罗列和隐式罗列两种方式。
如果集成员不放在集定义中,那么可以在随后的数据部分定义它们。
显式罗列成员时,必须为每个成员输入一个不同的名字,中间用空格或逗号搁开,允许混合使用。
例如,可以定义一个名为students的原始集,它具有成员John、Jill、Rose和Mike,属性有sex和age:
sets:
students/JohnJill,RoseMike/:
sex,age;
endsets
当隐式罗列成员时,不必罗列出每个集成员。
可采用如下语法:
setname/member1..memberN/[:
attribute_list];
这里的member1是集的第一个成员名,memberN是集的最末一个成员名。
Lingo将自动产生中间的所有成员名。
Lingo也接受一些特定的首成员名和末成员名,用于创建一些特殊的集。
列表如下:
表2隐式成员列表
隐式成员列表格式
示例
所产生集成员
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..MonthYearN
Oct2001..Jan2002
Oct2001,Nov2001,Dec2001,Jan2002
在集的定义中,斜线(/)之间给出的是集的成员,冒号(:
)后跟的是集成员的属性,这两部分在集的定义中可以省略,只保留集的名称。
(2)派生集
定义一个派生集的语法为:
setname(parent_set_list)[/member_list/][:
attribute_list];
setname是派生集的名字。
parent_set_list是已定义的集的列表,在此称为父集,多个时必须用逗号隔开。
如果没有指定成员列表,那么Lingo会自动创建父集成员的所有组合作为派生集的成员。
派生集的父集既可以是原始集,也可以是其它的派生集。
例如,定义如下的集
sets:
product/AB/;
machine/MN/;
week/1..2/;
allowed(product,machine,week):
x;
endsets
Lingo生成了三个父集的所有组合共八组作为allowed集的成员。
成员列表被忽略时,派生集成员由父集成员所有的组合构成,这样的派生集称为稠密集(有时也称为父集的笛卡尔乘积)。
如果限制派生集的成员,使它成为父集成员所有组合构成的集合的一个子集,这样的派生集称为稀疏集。
同原始集一样,派生集成员的声明也可以放在数据部分。
一个派生集的成员列表有两种方式生成:
显式罗列和设置成员资格过滤器。
如上例,可以显式罗列派生集的成员:
allowed(product,machine,week)/AM1,AN2,BN1/;
如果需要生成一个大的、稀疏的集,那么显式罗列就很麻烦。
幸运地是许多稀疏集的成员都满足一些条件以和非成员相区分。
我们可以把这些逻辑条件看作过滤器,在Lingo生成派生集的成员时把使逻辑条件为假的成员从稠密集中过滤掉。
用竖线(|)来标记一个成员资格过滤器的开始。
#eq#是逻辑运算符,用来判断是否“相等”。
&1可看作派生集的第1个原始父集的索引,它取遍该原始父集的所有成员;&2可看作派生集的第2个原始父集的索引,它取遍该原始父集的所有成员;&3,&4,……,以此类推。
注意如果派生集B的父集是另外的派生集A,那么上面所说的原始父集是集A向前回溯到最终的原始集,其顺序保持不变,并且派生集A的过滤器对派生集B仍然有效。
因此,派生集的索引个数是最终原始父集的个数,索引的取值是从原始父集到当前派生集所作限制的总和。
例如,定义如下的集
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=116
014
017
013;
friend=0.30.50.6;
enddata
2.模型的数据部分
(1)赋值
数据部分以关键字“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
在集set1中定义了两个属性X和Y。
X的三个值是1、2和3,Y的三个值是4、5和6。
也可采用如下两个属性一起赋值来实现同样的功能。
sets:
set1/A,B,C/:
X,Y;
endsets
data:
X,Y=14
25
36;
enddata
(2)参数
在数据部分也可以指定一些标量变量(scalarvariables)。
当一个标量变量在数据部分确定时,称之为参数。
假设模型中用利率8.5%作为一个参数,另一个参数为3%,则可如下输入:
data:
interest_rate,inflation_rate=.085.03;
enddata
(3)实时数据处理
有时候,模型中的某些数据并不是定值,需要从键盘实时输入,我们把这种情况称为实时数据处理。
Lingo在本该放数的地方输入一个问号(?
),即可引出LingoRuntimeInput对话框(如图2),等待用户从键盘为变量赋值。
图2等待用户赋值窗口
例如,
data:
interest_rate,inflation_rate=.085?
;
enddata
每一次求解模型时,Lingo都会提示为参数inflation_rate输入一个值。
在对话框中输入一个值再点击OK按钮,Lingo就会把输入的值赋给inflation_rate,然后继续求解模型。
(4)指定属性为一个值
可以在数据声明的右边输入一个值来把所有的成员的该属性指定为一个值。
例如
sets:
days/MO,TU,WE,TH,FR,SA,SU/:
needs,cost;
endsets
data:
needscost=20100;
enddata
Lingo将用20指定给days集的所有成员的needs属性,把100指定给所有成员的costs值。
(5)数据部分的未知数值
有时只想为一个集的部分成员的某个属性指定值,而让其余成员的该属性保持未知,以便让Lingo去求出它们的最优值。
在数据声明中输入两个相连的逗号表示该位置对应的集成员的属性值未知。
两个逗号间可以有空格。
例如
sets:
years/1..5/:
capacity;
endsets
data:
capacity=,34,20,,;
enddata
属性capacity的第2个和第3个值分别为34和20,其余的未知。
3.模型的初始部分
初始部分是Lingo提供的另一个可选部分。
在初始部分中,可以输入初始声明(initializationstatement),和数据部分中的数据声明相同。
对实际问题的建模时,初始部分并不起到描述模型的作用,在初始部分输入的值仅被Lingo求解器当作初始点来用,并且仅仅对非线性模型有用。
和数据部分指定变量的值不同,Lingo求解器可以自由改变初始部分初始化的变量的值。
一个初始部分以“init:
”开始,以“endinit”结束。
初始部分的初始声明规则和数据部分的数据声明规则相同。
也就是说,我们可以在声明的左边同时初始化多个集属性,可以把集属性初始化为一个值,可以用问号实现实时数据处理,还可以用逗号指定未知数值。
例如
init:
X,Y=0,.1;
endinit
Y=@log(X);
X^2+Y^2<=1;
一般而言,好的初始点会减少模型的求解时间。
4.Lingo函数
(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
关系运算符
在Lingo中,关系运算符主要是被用在模型中,来指定一个表达式的左边是否等于、小于等于、或者大于等于右边,形成模型的一个约束条件。
关系运算符与逻辑运算符#eq#、#le#、#ge#截然不同,前者是模型中该关系运算符所指定关系的为真描述,而后者仅仅判断一个该关系是否被满足:
满足为真,不满足为假。
Lingo有三种关系运算符:
“=”、“<=”和“>=”。
Lingo中还能用“<”表示小于等于关系,“>”表示大于等于关系。
Lingo并不支持严格小于和严格大于关系运算符。
然而,如果需要严格小于和严格大于关系,比如让A严格小于B:
A
A+ε<=B,这里ε是一个小的正数,它的值依赖于模型中A小于B多少才算不等。
(2)数学函数
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中的最小值
(3)金融函数
Lingo提供了两个金融函数。
@fpa(I,n)
返回如下情形的净现值:
单位时段利率为I,连续n个时段支付,每个时段支付单位费用。
若每个时段支付x单位的费用,则净现值可用x乘以@fpa(I,n)算得。
@fpa的计算公式为
。
净现值就是在一定时期内为了获得一定收益在该时期初所支付的实际费用。
@fpl(I,n)
返回如下情形的净现值:
单位时段利率为I,第n个时段支付单位费用。
@fpl(I,n)的计算公式为
。
这两个函数间的关系:
(4)概率函数
@pbn(p,n,x):
二项分布的累积分布函数。
当n和(或)x不是整数时,用线性插值法进行计算。
@pcx(n,x):
自由度为n的χ2分布的累积分布函数。
@peb(a,x):
当到达负荷为a,服务系统有x个服务器且允许无穷排队时的Erlang繁忙概率。
@pel(a,x):
当到达负荷为a,服务系统有x个服务器且不允许排队时的Erlang繁忙概率。
@pfd(n,d,x):
自由度为n和d的F分布的累积分布函数。
@pfs(a,x,c):
当负荷上限为a,顾客数为c,平行服务器数量为x时,有限源的Poisson服务系统的等待或返修顾客数的期望值。
a是顾客数乘以平均服务时间,再除以平均返修时间。
当c和(或)x不是整数时,采用线性插值进行计算。
@phg(pop,g,n,x):
超几何(Hypergeometric)分布的累积分布函数。
pop表示产品总数,g是正品数。
从所有产品中任意取出n(n≤pop)件。
pop,g,n和x都可以是非整数,这时采用线性插值进行计算。
@ppl(a,x):
Poisson分布的线性损失函数,即返回max(0,z-x)的期望值,其中随机变量z服从均值为a的Poisson分布。
@pps(a,x):
均值为a的Poisson分布的累积分布函数。
当x不是整数时,采用线性插值进行计算。
@psl(x):
单位正态线性损失函数,即返回max(0,z-x)的期望值,其中随机变量z服从标准正态分布。
@psn(x):
标准正态分布的累积分布函数。
@ptd(n,x):
自由度为n的t分布的累积分布函数。
@qrand(seed):
产生服从(0,1)区间的拟随机数。
@qrand只允许在模型的数据部分使用,它将用拟随机数填满集属性。
通常,声明一个m×n的二维表,m表示运行实验的次数,n表示每次实验所需的随机数的个数。
在行内,随机数是独立分布的;在行间,随机数是非常均匀的。
这些随机数是用“分层取样”的方法产生的。
@rand(seed):
返回0和1间的伪随机数,依赖于指定的种子。
典型用法是U(I+1)=@rand(U(I))。
注意如果seed不变,那么产生的随机数也不变。
(5)变量界定函数
变量界定函数实现对变量取值范围的附加限制,共4种:
@bin(x)限制x为0或1
@bnd(L,x,U)限制L≤x≤U
@free(x)取消对变量x的默认下界为0的限制,即x可以取任意实数
@gin(x)限制x为整数
在默认情况下,Lingo规定变量是非负的,也就是说下界为0,上界为+∞。
@free取消了默认的下界为0的限制,使变量也可以取负值。
@bnd用于设定一个变量的上下界,它也可以取消默认下界为0的约束。
例如,求函数
的最小值。
显见当
时
取最小值0,由于允许取负值,可用如下Lingo程序求解。
min=(x+2)^2+(y-2)^2;
@free(x);
(6)集操作函数
Lingo提供了几个函数帮助处理集。
@in(set_name,primitive_index_1[,primitive_index_2,…])
如果元素在指定集中,返回1;否则返回0。
@index([set_name,]primitive_set_element)
该函数返回在集set_name中原始集成员primitive_set_element的索引。
如果set_name被忽略,那么Lingo将返回与primitive_set_element匹配的第一个原始集成员的索引。
如果找不到,则产生一个错误。
@wrap(index,limit)
该函数返回j=index-k*limit,其中k是一个整数,取适当值保证j落在区间[1,limit]内。
该函数在循环、多阶段计划编制中特别有用。
@size(set_name)
该函数返回集set_name的成员个数。
在模型中明确给出集大小时最好使用该函数。
它的使用使模型更加数据中立,集大小改变时也更易维护。
(7)集循环函数
集循环函数遍历整个集进行操作。
其语法为
@function(setname[(set_index_list)[|conditional_qualifier]]:
expression_list);
@function相应于下面罗列的四个集循环函数之一;setname是要遍历的集;set_index_list是集索引列表;conditional_qualifier是用来限制集循环函数的范围,当集循环函数遍历集的每个成员时,Lingo都要对conditional_qualifier进行评价,若结果为真,则对该成员执行@function操作,否则跳过,继续执行下一次循环。
expression_list是被应用到每个集成员的表达式列表,当用的是@for函数时,expression_list可以包含多个表达式,其间用逗号隔开。
这些表达式将被作为约束加到模型中。
当使用其余的三个集循环函数时,expression_list只能有一个表达式。
如果省略set_index_list,那么在expression_list中引用的所有属性的类型都是setname集。
@for
该函数用来产生对集成员的约束。
基于建模语言的标量需要显式输入每个约束,不过@for函数允许只输入一个约束,然后Lingo自动产生每个集成员的约束。
例如,产生序列{1,4,9,16,25}
sets:
number/1..5/:
x;
endsets
@for(number(I):
x(I)=I^2);
end
@sum
该函数返回遍历指定的集成员的一个表达式的和。
例如,求向量[5,1,3,4,6,10]前5个数的和。
sets:
number/1..6/:
x;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数学 软件 Lingo 部分
![提示](https://static.bdocx.com/images/bang_tan.gif)