此为对数模一窍不通的海豹重新拾起高数的记忆

lingo的代码主要分为预定义、数据的输入、目标函数、决策变量、约束条件五个板块。

常用符号及语句

算术运算符

5种二元运算符:

^:乘方

*:乘

/:除

+:加

-:减

唯一1种一元运算符:

-:取反

关系运算符

三种关系运算符:=<>

注意:lingo中<>分别表示小于等于和大于等于,如要A严格小于B:那么可以把它变成如下的小于等于表达式:
$$
A+ε<=B
$$

这里ε是一个小的正数,它的值依赖于模型中A小于B多少才算不等

逻辑运算符
1
2
3
4
5
6
7
8
9
#not# ! 否定该操作数的逻辑值;
#eq# ! 若两个运算数相等,则为true,否则为flase(equal);
#ne# ! 若两个运算符不相等,则为true,否则为flase(not equal);
#gt# ! 若左 > 右,则为true,否则为flase(greater than);
#ge# ! 若左 >= 右,则为true,否则为flase(greater than or equal than);
#lt# ! 若左 < 右,则为true,否则为flase(less than);
#le# ! 若左 <= 右,则为true,否则为flase(less than or equal than);
#and# ! 当两个参数都为true时,则为true,否则为flase(并且);
#or# ! 当两个参数都为flase,则为flase,否则为true(或者);

集合

集合部分的语法为:

1
2
3
4
5
sets:
集合名称1/成员列表1/:属性1_1,属性1_2,…,属性1_n1;
集合名称2/成员列表2/:属性2_1,属性2_2,…,属性2_n2;
派生集合名称(集合名称1,集合名称2):属性3_1,…,属性3_n3;
endsets

成员罗列的几种方式:

  1. 显示罗列集成员:把所有成员名列出,用逗号” , “或空格分隔。
  2. 隐式罗列集成员:setname/member1..memberN/[: attribute_list]; !用".."表示省略

派生集的成员列表有两种方式:

  1. 显式罗列,罗列出所有成员名

  2. 设置成员资格过滤器,思想:许多稀疏集的成员都满足一些条件以和非成员相区分。我们可以把这些逻辑条件看作过滤器,在 LINGO生成派生集的成员时把使逻辑条件为假的成员从稠密集中过滤掉

    例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    sets: 
    !学生集:性别属性 sex,1 表示男性,0 表示女性;年龄属性 age. ;
    students/John,Jill,Rose,Mike/:sex,age;
    !男学生和女学生的联系集:友好程度属性 friend,[01]之间的数。 ;
    linkmf(students,students)|sex(&1) #eq# 1 #and# sex(&2) #eq# 0:
    friend;
    !男学生和女学生的友好程度大于 0.5 的集;
    linkmf2(linkmf) | friend(&1,&2) #gt# 0.5 : x;
    endsets
    • 用竖线(|)来标记一个成员资格过滤器的开始
    • &1 可看作派生集的第 1 个原始父集的索引,它取遍该原始父集的所有成员,派生集的索引个数是最终原始父集的个数

数据

数据部分的语法为:

1
2
3
4
data: data:
属性 1= 数据列表; 数据列表; 数据列表;
属性 2= 数据列表; 数据列表; 数据列表;
enddata nddata
  • 属性列表(object_list)包含要指定值的属性名、要设置集成员的集名,用逗号或空格隔开。
  • 数据列表(value_list)包含要分配给对象列中的对象的值,用逗号或空格隔开。注意属性值的个数必须等于集成员的个数。

参数

在数据部分也可以指定一些标量变量(scalar variables)。当一个标量变量在数据部分确定时,称之为参数,例:

1
2
3
data: 
interest_rate,inflation_rate = .085 .03;
enddata

指定属性为一个值

为所有成员的属性指定同一个值,也支持多个属性的情况:

1
2
3
4
5
6
sets: 
days /MO,TU,WE,TH,FR,SA,SU/:needs,cost;
endsets
data:
needs cost = 20 100;
enddata

Lingo函数

函数有很多,在这边仅列出几类常用的,需要用到请自行搜索

数学函数

1
2
3
4
5
6
7
8
9
10
11
12
@sum(x) ! 对集合x的所有成员求和
@abs(x) ! 返回x的绝对值;
@exp(x) ! 返回常数e的x次方;
@sin(x) ! 返回x的正弦值,x采用弧度制;
@log(x) ! 返回x的自然对数;
@cos(x) ! 返回x的余弦值;
@lgm(x) ! 返回x的log的自然对数;
@tan(x) ! 返回x的正切值;
@sign(x) ! 如果x<0,返回-1,否则返回1;
@smax(x1, x2, x3, x4, ...xn) ! 返回xn中的最大值;
@smin(x1, x2, x3, x4, ...xn) ! 返回xn中的最小值;
@floor(x) ! 向接近于0的方向取整;

变量定界函数

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

集合循环函数

集合循环函数是指对集合上的元素(下标)进行循环操作的函数 一般用法如下:

1
@function(set_operator (set_name|condition:expression))

其中set_operator部分是集合函数名(见下),set_name是数据集 合名,expression部分是表达式,|condition部分是条件,用逻辑表达式描述(无条件时可省略).

常见集合函数:

1
2
3
4
5
6
7
8
@FOR (set_name:  constraint_expressions) 
! 对集合(set_name)的每个元素独立地生成约束,约束由约束表达式(constraint_expressions)描述;

@SUM(set_name:expression) ! 返回集合上的表达式(expression)的和;

@MAX(set_name:expression) ! 返回集合上的表达式(expression)的最大值;

@MIN(set_name:expression) ! 返回集合上的表达式(expression)的最小值;

输入和输出函数

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

  1. @file:用来从外部文件中输入数据,可以放在模型中任何地方。该函数的语法格式为@file('filename')。这里 filename 是文件名,可以采用相对路径和绝对路径两种表示方式。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

模型的所有数据来自于 1_2.txt 文件。其内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
!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

把记录结束标记(~)之间的数据文件部分称为记录。如果数据文件中没有记录结束标记,那么整个文件被看作单个记录。注意到除了记录结束标记外,模型的文本和数据同它们直接放在模型里是一样的。

在数据文件中的记录结束标记连同模型中@file函数调用工作过程:当在模型中第一次调用@file 函数时,LINGO 打开数据文件,然后读取第一个记录;第二次调用@file函数时,LINGO 读取第二个记录等等。文件的最后一条记录可以没有记录结束标记。

  1. @text :该函数被用在数据部分用来把解输出至文本文件中。它可以输出集成员和集属性值。其语法为:@text([’filename’])

  2. @OLE(filename):是从 EXCEL 中引入或输出数据的接口函数,它是基于传输的 OLE 技术。OLE传输直接在内存中传输数据,并不借助于中间文件。

    • filename为文件名,可以是相对路径,也可以是绝对路径。
    • @OLE 可以同时读集成员和集属性,集成员最好用文本格式,集属性最好用数值格式。原始集每个集成员需要一个单元(cell),而对于 n 元的派生集每个集成员需要 n个单元,这里第一行的 n 个单元对应派生集的第一个集成员,第二行的 n 个单元对应派生集的第二个集成员,依此类推。
    • @OLE 只能读一维或二维的 Ranges(在单个的 EXCEL 工作表(sheet)中),但不能读间断的或三维的 Ranges。Ranges 是自左而右、自上而下来读。
  3. ‘@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(求解器因在某约束中遇到无定义的算术运算而停止)

辅助函数

1
@if(logical_condition,true_result,false_result) ! 评价一个逻辑表达式 logical_condition,如果为真,返回 true_ esult,否则返回false_result。

Lingo注意事项

1.Lingo中模型以“MODEL:”开始,以“END”结束, 对于简单的模型,这两个语句都可以省略;

2.Lingo中每行后面均增加了一个分号“;”;

3.所有符号都需在英文状态下输入;

4.min=函数、max=函数,表示求函数的最小、最大值;

5.Lingo中变量不区分大小写,变量名可以超过8个,但 不能超过32个,需以字母开头;

6.用Lingo解优化模型时已假定所有变量非负,如果想解除这个限制可以用函数@free(x),这样x可以取到任意实数;

7.变量可以放在约束条件右端,同时数字也可以放在约束条件左边;

8.Lingo模型语句由一系列语句组成,每一个语句都必须 以“;”结尾;

9.Lingo中注释以“!”开始的是,以“;” 结束,可以跨多行。