随着建模培训的进程,越来越发现自己所知有限。这里记录下自己学习LINGO的过程,一点一点来呗!
1 模型的集部分
集部分是LINGO模型的可选部分。在使用LINGO模型中使用集之前,必须在集部分事先定义。集部分以关键字“sets:”开始,以“endsets”结束。一个模型可以没有集部分。
1.1 定义原始集
定义一个原始集。用下面的语法:
setname[/member_list/][:attribute_list]; 注意:用"[ ]"表示部分内容可选
setname是你选择标记集的名字,最好具有较强的可读性。member_list是集成员列表。如果集成员放在集定义中,那么可以对他们进行显示罗列和隐式罗列,也可以在随后的数据本分定义它们。当显示罗列成员时,用逗号或者是空格来隔开,如:
sets:
students/John Jill,Rose,Mike/:sex,age;
endsets
当隐式显示成员是,则可采用下面的语法:
setname/membew1..memberN/[:attribute_list];
此时LINGO将自动产生member1到memberN中间的所有成员名。
另外,我也可以这样定义数据:
sets:
products/A B/;
machine/M N/;
week/1..2/;
allowed(product,machine,week):x;
endsets
1.2派生集
另外,除了原始集外还有派生集
students/Jhon,Jill,Rose,Mike/:sex,age;
linkmf(students,students)|sex(&1)#eq#1and#sex(&2)#eq#0:friend;
用竖线(|)表示成员资格过滤器的开始。
2.模型的数据部分和初始部分
2.1模型的数据部分
数据部分以关键字“data:”开始,以关键字“enddata”结束,在这里可以指定集成员,集的属性。其语法如下
object_list=value_list;
这里给出例子
sets:
set1/A,B,C/:X<Y;
endsets
data: !这里也可以这样复制赋值
X=1,2,3; X,Y=1 4
Y=4,5,6; 2 5
enddata 3 6;
另外,我们也可以指定参数
data:
interest_rate,inflation_rate=.085
2.2 模型的初始部分
一个初始部分以“init:”开始,以“endinit”结束。初始部分的初始声明规则和数据部分的数据声明的规则相同。也就是说,我们可以再声明的左边同时初始化多个集属性,可以吧集属性初始化为一个值,可以用问号实现实时数据处理,还可以用逗号指定未知数据。
init:
X,Y=0,.1;
endinit
Y=@log(X);
X^2+Y^2<=1;
3. LINGO函数
3.1 逻辑运算符
#not# 否定该操作数的逻辑值
#eq# 若两个运算数相等,则为true,否则false;
#ne# 若两个运算符不相等,则为true,否则为false
#gt# 若左边的运算符严格大于右边的运算符,则为true,否则为false
#ge# 若左边的运算符严格大于或等于右边的运算符,则为true,否则为false
#lt# 若左边的运算符严格小于右边的运算符,则为true,否则为false
#lg# 若左边的运算符严格大于右边或等于的运算符,则为true,否则为false
#and# 即逻辑且
#or# 逻辑或
优先级由高到低
高 #not#
#eq# #ne# #gt# #ge# #lt# #le#
低 #and# #or#
3.2 数学函数
@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) 返回x1x2…,xn中的最大值
@smin(x1,x2,…,xn) 返回x1,x2,…,xn中的最小值
这里给出一个例子
model:
sets:
object/1..3/:f;
endsets
data:
a,b=3,4;
enddata
f(1)=a*@sin(x);
f(2)=b*@cos(x);
f(3)=a*@cos(x)+b*@sin(x);
min=@smax(f(1),f(2),f(3));
@bnd(0,x,1.57);
end
3.3变量界定函数
变量界定函数实现对变量取值范围附加限制,共4中:
@bin(x) 限制x为0或1
@bnd(L,x,U) 限制L<=x<<U
@free(x) 取消变量x的默认下届为0的限制,即x可以为任意数
@gin(x) 限制x为整数
3.4 集操作函数
(1)@in(set_name,primitive_index_1[,primitive_index_2,...])
如果元素在指定集内则返回1,否则返回0;
sets: 全集为I,C为B的补集
I/x1..x4/;
B(I)/x2/;
C(I)|#not#@in(B&1):;
endsets
(2) @index([set_name,]primitive_set_element)
该函数返回在集set_name中原是集成员primitive_set_element的索引。如果set_name被忽略,那么它将返回第一个原是集成员的索引。
sets: 如何确定集成员(B,Y)属于派生集S3
S1/A B C/;
S2/X Y Z/;
S3(S1,S2)/A X,A Z,B,Y,C X/;
endsets
<a target=_blank href="mailto:X=@in(S3,@index(S1,B),@index(S2,Y));">X=@in(S3,@index(S1,B),@index(S2,Y));
</a>
3.5集循环函数
集循环函数整个集进行操作。其语法是
@function(setname[(set_index_list))[|conditional_qualifier]]:expression_list);</span>
其中@function是对应的四个集循环之一;setname是要遍历的集;set_index_list是集索引列表;conditional_qualifier是用来限制集循环函数范围,当集循环函数遍历集的每个成员时,LINGO都要对其进行评价,只有当结果为真时,才会执行@function操作,否则跳过,进行到下一次循环。expression_list是被应用到每个及成员函数的表达式列表。当是@for时,它可以包含多个表达式,用逗号隔开;否则其只能含有一个函数。这些表达式将被作为约束加到模型中去。
下面使用例子依次介绍四个集循环函数
(1)@for
该函数用来产生对集成员的约束。@for函数允许只输入一个约束,然后LINGO自动产生每个集成员的约束。
例:产生序列{1,4,9,16,25}
model:
sets:
number/1..5/:x;
endsets
@for(number(I):x(I)=I^2);
end
(2)@sum
该函数返回遍历指定集成员的一个表达式的和
例:求向量【5,1,3,4,6,10】前五个数的和。
model:
data:
N=6;
enddata
sets:
number/1..N/:x;
endsets
data:
x=5 1 3 4 6 10;
enddata
<a target=_blank href="mailto:s=@sum(number(I)|I#le#5:x);end">s=@sum(number(I)|I#le#5:x);
end</a>
(3)@min和@max
该函数返回指定的集成员的一个表达式的最小值或者是最大值
model:
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"; <span style="color:#000000;"> </span> <a target=_blank href="mailto:maxv=@max(number(I)|I#ge#N-2:x);end"> maxv=@max(number(I)|I#ge#N-2:x);
end</a>
(4)检测
下面来看一个稍微复杂一点的例子
例:职员时序安排模型 一项工作一周七天都需要有人,每天(周一至周日)所需的最少职员数位20,16,13,19,14和12,并要求每个职员一周连续工作5天,试求每周所需最少的职员数,并给出安排。注意这里我们考虑稳定后的情况。
model:
sets:
days/mon..sun/:required,start;
endsets
data:
!每天所需的最少职员数;
required=20 16 13 16 19 14 12;
enddata
!最小化每周所需职员数;
min=@sum(days:start);
@for(days(J):
@sum(days(I)|I#le#5:
start(@wrap(J+I+2,7)))>=required(J)); !@WRAP(INDEX, LIMIT)返回的是 INDEX - K * LIMIT 其中K是一个整数 它使得返回值落到[1,LIMIT]上;
end