@(数模)
1.基本语法
1.1集
1.1.1什么是集
集是一群相联系的对象。其特征称为属性。
LINGO中两种类型的集:
原始集:由一些最基本的对象组成。
派生集:一个或多个其它集来定义的,也就是说,它的成员来自于其它已存在的集。
1.1.2定义集
原始集
语法:
setname[/member_list/][:attribute_list];
注意:用“[ ]”表示该部分内容可选。
Member_list 是集成员列表。可以显示罗列,也可隐式罗列。
显示罗列:每个成员不同名,中间用空格或逗号隔开,允许混合使用。
隐式罗列:采用如下语法:
setname/member1..memberN/[:attribute_list];
特殊的首成员名和末成员名:
隐式成员列表格式 | 示例 | 所产生集成员 |
---|---|---|
1..n | 1..5 | 1,2,3,4,5 |
StringM..StringN | Car2..car14 | Car2,Car3,Car4,...,Car14 |
DayM..DayN | Mon..Fri | Mon,Tue,Web,Thu,Fri |
MonthM..MonthN | Oct..Jan | Oct,Nov,Dec,Jan |
MonthYearM..MonthYearN | Oct2001..Jan2002 | Oct2001,Nov2001,Dec2001,Jan2002 |
示例
sets:
students:sex,age;
endsets
注意:开头用(!),末尾用(;)表示注释,可跨多行。
派生集
必须详细声明:
- 集的名字
- 父集的名字
- 可选,集成员
- 可选,集成员的属性
语法:
setname(parent_set_list)[/member_list/][:attribute_list];
示例
sets:
priduct/A B/;
machine/M N/;
week/1..2/;
allowed(product,machine,week):x;
endsets
1.2数据部分与初始部分
1.2.1数据部分
语法:
obeject_list = value_list;
示例:
data:
X=1,2,3;
Y=4,5,6;
enddata
data:
X,Y=1 4
2 5
3 6;
enddata
实时数据处理
在本该放数的地方输入一个问号(?)。
示例:
data:
interest_rate,inflation_rate = .085 ?;
enddata
每一次求解模型时,LINGO都会提示为参数输入一个值。
指定为同一个值
示例:
sets:
days /MO,TU,WE,TH,FR,SA,SU/:needs;
endsets
data:
needs = 20;
enddata
数据部分的未知数值
在数据声明中输入两个相连的逗号表示该位置对应的集成员的属性值未知。两个逗号间可以有空格。
示例:
sets:
years/1..5/: capacity;
endsets
data:
capacity = ,34,20,,;
enddata
属性capacity 的第2个和第3个值分别为34和20,其余的未知。
1.2.2初始部分
一个初始部分以“init:”开始,以“endinit”结束。可以用问号实现实时数据处理,还可以用逗号指定未知数值。
示例
init:
X, Y = 0, .1;
endinit
Y=@log(X);
X^2+Y^2<=1;
1.3基本运算符
1.3.1算术运算符
LINGO 提供了 5 种二元运算符:
- ^ 乘方
- ﹡ 乘
- / 除
- ﹢ 加
- ﹣ 减
LINGO 唯一的一元算术运算符是取反函数“﹣”。
这些运算符的优先级由高到底为:
高 ﹣(取反)
^
﹡/
低 ﹢﹣
1.3.2逻辑运算符
LINGO 具有9种逻辑运算符:
<table border="1">
<tr> <th>逻辑运算符</th> </tr>
<tr> <td>#not# 否定该操作数的逻辑值 #not#是一个一元运算符</td> </tr>
<tr> <td> #eq# 若两个运算数相等,则为 true;否则为 flase</td> </tr>
<tr> <td> #ne# 若两个运算符不相等,则为 true;否则为 flase </td> </tr>
<tr> <td> #gt# 若左边的运算符严格大于右边的运算符,则为 true;否则为 flase</td> </tr>
<tr> <td> #ge# 若左边的运算符大于或等于右边的运算符,则为 true;否则为 flase</td> </tr>
<tr> <td> #lt# 若左边的运算符严格小于右边的运算符,则为 true;否则为 flase
</td> </tr>
<tr> <td>#le# 若左边的运算符小于或等于右边的运算符,则为 true;否则为 flase</td> </tr>
<tr> <td>#and# 仅当两个参数都为 true 时,结果为 true;否则为 flase</td> </tr>
<tr> <td>#or# 仅当两个参数都为 false 时,结果为 false;否则为 true</td> </tr>
</table>
这些运算符的优先级由高到低为:
高 #not#
#eq# #ne# #gt# #ge# #lt# #le#
低 #and# #or#
1.3.3关系运算符
在 LINGO 中,关系运算符主要是被用在模型中,来指定一个表达式的左边是否等于、小于等于、或者大于等于右边,形成模型的一个约束条件。关系运算符与逻辑运算符#eq#、#le#、#ge#截然不同,前者是模型中该关系运算符所指定关系的为真描述,而后者仅仅判断一个该关系是否被满足:满足为真,不满足为假。
LINGO 有三种关系运算符:“=”、“<=”和“>=”。LINGO 中还能用“<”表示小于等
于关系,“>”表示大于等于关系。LINGO 并不支持严格小于和严格大于关系运算符。
如果需要严格小于和严格大于关系,比如让 A 严格小于 B:
$$A<B$$
那么可以把它变成如下的小于等于表达式:
$$A+ε<=B$$
这里ε是一个小的正数,它的值依赖于模型中 A 小于 B 多少才算不等。
2.常用函数
2.1数学函数
@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.2金融函数
2.2.1 @fpa(I,n)
返回如下情形的净现值:单位时段利率为 I,连续 n 个时段支付,每个时段支付单位费用。若每个时段支付 x 单位的费用,则净现值可用 x 乘以@fpa(I,n)算得。@fpa 的计算公式
$$ \sum^n_{k=1} \frac{1}{(1+I)^k} = \frac{1-(1+I)^{-n}}{I} $$
净现值就是在一定时期内为了获得一定收益在该时期初所支付的实际费用。
例 贷款买房问题 贷款金额 50000 元,贷款年利率 5.31%,采取分期付款方式(每年年末还固定金额,直至还清)。问拟贷款 10 年,每年需偿还多少元?
LINGO 代码如下:
50000 = x * @fpa(.0531,10);
答案是 x=6573.069 元。
2.2.1 @fpl(I,n)
返回如下情形的净现值:单位时段利率为 I,第 n 个时段支付单位费用。@fpl(I,n)的计算公式为 $$ (1+I)^{-n} $$ 这两个函数间的关系:
$$ @fpa(I,n) = \sum^n_{k=1} @fpl(I,k) $$
2.3概率函数
2.3.1 @pbn(p,n,x)
二项分布的累积分布函数。当 n 和(或)x 不是整数时,用线性插值法进行计算。
2.3.2 @pcx(n,x)
自由度为 n 的 $x^2$ 的分布的累积分布函数。
2.3.3 @peb(a,x)
当到达负荷为 a,服务系统有 x 个服务器且允许无穷排队时的 Erlang 繁忙概率。
2.3.4 @pel(a,x)
当到达负荷为 a,服务系统有 x 个服务器且不允许排队时的 Erlang 繁忙概率。
2.3.5 @pfd(n,d,x)
自由度为 n 和 d 的 F 分布的累积分布函数。
2.3.6 @pfs(a,x,c)
当负荷上限为 a,顾客数为 c,平行服务器数量为 x 时,有限源的 Poisson 服务系统的等待或返修顾客数的期望值。a 是顾客数乘以平均服务时间,再除以平均返修时间。当 c 和(或)x 不是整数时,采用线性插值进行计算。
2.3.7 @phg(pop,g,n,x)
超几何(Hypergeometric)分布的累积分布函数。pop 表示产品总数,g 是正品数。从所有产品中任意取出 n(n≤pop)件。pop,g,n 和 x 都可以是非整数,这时采用线性插值
进行计算。
2.3.8 @ppl(a,x)
Poisson 分布的线性损失函数,即返回 max(0,z-x)的期望值,其中随机变量 z 服从均值为 a 的 Poisson 分布。
2.3.9 @pps(a,x)
均值为 a 的 Poisson 分布的累积分布函数。当 x 不是整数时,采用线性插值进行计算。
2.3.10 @psl(x)
单位正态线性损失函数,即返回 max(0,z-x)的期望值,其中随机变量 z 服从标准正态
2.3.11 @psn(x)
标准正态分布的累积分布函数。
2.3.12 @ptd(n,x)
自由度为 n 的 t 分布的累积分布函数。
2.3.13 @qrand(seed)
产生服从(0,1)区间的拟随机数。@qrand 只允许在模型的数据部分使用,它将用拟随机数填满集属性。通常,声明一个 m×n 的二维表,m 表示运行实验的次数,n 表示每次实验所需的随机数的个数。在行内,随机数是独立分布的;在行间,随机数是非常均匀的。这些随机数是用“分层取样”的方法产生的。
示例
model:
data:
M=4; N=2; seed=1234567;
enddata
sets:
rows/1..M/;
cols/1..N/;
table(rows,cols): x;
endsets
data:
X=@qrand(seed);
enddata
end
如果没有为函数指定种子,那么LINGO将用系统时间构造种子。
2.3.14 @rand(seed)
返回 0 和 1 间的伪随机数,依赖于指定的种子。典型用法是$U(I+1)=@rand(U(I))$。注意如果 seed 不变,那么产生的随机数也不变。
2.4 变量界定函数
变量界定函数实现对变量取值范围的附加限制,共 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 的约束。
2.5 集操作函数
2.5.1 @in(set_name,primitive_index_1 [,primitive_index_2,…])
如果元素在指定集中,返回 1;否则返回 0。
2.5.2 @index([set_name,] primitive_set_element)
该函数返回在集 set_name 中原始集成员 primitive_set_element 的索引。如果 set_name被忽略,那么 LINGO 将返回与 primitive_set_element 匹配的第一个原始集成员的索引。如果找不到,则产生一个错误。
2.6 集循环函数
语法:
$$$@function(setname[(set_index_list)[|conditional_qualifier]]:expression_list)$$
2.6.1 @for
示例
model:
sets:
number/1..5/:x;
endsets
@for(number(I): x(I)=I^2);
end
2.6.2 @sum
示例
model:
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);
end
2.6.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);
maxv=@max(number(I) | I #ge# N-2: x);
end
2.7 输入和输出函数
2.7.1 @file 函数
该函数用从外部文件中输入数据,可以放在模型中任何地方。该函数的语法格式为@file(’filename’)。这里 filename 是文件名,可以采用相对路径和绝对路径两种表示方式。@file 函数对同一文件的两种表示方式的处理和对两个不同的文件处理是一样的,这一点必须注意。
示例
model:
!6 发点 8 收点运输问题;
sets:
warehouses/ @file ('1_2.txt') /: capacity;
vendors/ @file ('1_2.txt') /: 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 = @file ('1_2.txt') ;
demand = @file ('1_2.txt') ;
cost = @file ('1_2.txt') ;
enddata
end
2.7.2 @text函数
该函数被用在数据部分用来把解输出至文本文件中。它可以输出集成员和集属性值。
语法:
$$@text([’filename’])$$
示例
model:
sets:
days/mon..sun/: required,start;
endsets
data:
!每天所需的最少职员数;
required = 20 16 13 16 19 14 12;
@text ('d:\out.txt')=days '至少需要的职员数为' start;
enddata
!最小化每周所需职员数;
min=@sum(days: start);
@for(days(J):
@sum(days(I) | I #le# 5:
start(@wrap(J+I+2,7))) >= required(J));
end
2.7.3 @ole函数
@OLE 是从 EXCEL 中引入或输出数据的接口函数。
@OLE 可以同时读集成员和集属性,集成员最好用文本格式,集属性最好用数值格式。原始集每个集成员需要一个单元(cell),而对于 n 元的派生集每个集成员需要 n 个单元,这里第一行的 n 个单元对应派生集的第一个集成员,第二行的 n 个单元对应派生集的第二个集成员,依此类推。
示例
model:
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
我们在模型的数据部分用如下代码从 EXECL 中引入数据:
PRODUCT,MACHINE,WEEK,ALLOWED,x,y=@OLE('D:\IMPORT.XLS');
@OLE('D:\IMPORT.XLS')=rate;
等价的描述为
PRODUCT,MACHINE,WEEK,ALLOWED,x,y
=@OLE('D:\IMPORT.XLS', PRODUCT,MACHINE,WEEK,ALLOWED,x,y);
@OLE('D:\IMPORT.XLS',rate)=rate;
这一等价描述使得变量名和 Ranges 不同亦可。
2.7.4 @ranged(variable_or_row_name)
为了保持最优基不变,变量的费用系数或约束行的右端项允许减少的量。
2.7.5 @rangeu(variable_or_row_name)
为了保持最优基不变,变量的费用系数或约束行的右端项允许增加的量。
2.7.6 @status()
返回 LINGO 求解模型结束后的状态:
0 Global Optimum(全局最优)
1 Infeasible(不可行)
2 Unbounded(无界)
3 Undetermined(不确定)
4 Feasible(可行)
5 Infeasible or Unbounded(通常需要关闭“预处理”选项后重新求解模型,以确
定模型究竟是不可行还是无界)
6 Local Optimum(局部最优)
7 Locally Infeasible(局部不可行,尽管可行解可能存在,但是 LINGO 并没有找到
一个)
8 Cutoff(目标函数的截断值被达到)
9 Numeric Error(求解器因在某约束中遇到无定义的算术运算而停止)
示例
model:
min=@sin(x);
data:
@text()=@status();
enddata
end
2.7.7 @dual
@dual(variable_or_row_name)返回变量的判别数(检验数)或约束行的对偶(影子)价格(dual prices)。
2.8 辅助函数
2.8.1 @if(logical_condition,true_result,false_result)
model:
!求最优解
min=fx+fy;
fx=@if(x #gt# 0, 100,0)+2*x;
fy=@if(y #gt# 0,60,0)+3*y;
x+y>=30;
end
2.8.2 @warn(’text’,logical_condition)
如果逻辑条件 logical_condition 为真,则产生一个内容为’text’的信息框。
示例
model:
x=1;
@warn('x 是正数',x #gt# 0);
end