lingo的代码主要分为预定义、数据的输入、目标函数、决策变量、约束条件五个板块。
注:
1、lingo代码需要以model开始,以end作为结束,但是在简单的模型中,这两个语句都可以省略。
2、每行代码后面都需要一个英文状态下的分号。
3、lingo中不区分大小写,变量名可以超过8个,但是不能超过32个,命名方式与其他编程语言要求一样,必须以字母开头,由字母、数字、和下划线组成,代码中的命名以清晰作为要求,即看到名称就可以辨认出这个变量所代表的意义。
4、lingo中的注释需要用“!”,并且在最后也需要加上分号。
5、lingo解优化模型时已经假定所有变量非负,如果想解除限制需要使用函数@free(x),这样x可以取到任意实数。
6、lingo的每个语句可以加标号,例如[OBJ],这样在输出的时候也会输出,使得我们便于识别输出结果的含义。
'''
#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(或者);'''
例如这种情况中,i本身的范围是1 ~ 20,而此处需要将其限制在1 ~ 2的范围内:
'''
@sum(link(i,j)|i#le#2:x(i,j))=1000;'''
关系运算符分为三种“=”, “<=”,“>=”。这三种运算符,也就是数学含义。
注:lingo中“<”,“>”分别表示小于等于和大于等于,如果需要严格小于或者严格大于,例如A < B,可以表达成
A + x <= B的形式,此处x是一个很小的正数,它的值依赖于模型中A小于B多少才符合要求。
数学函数有很多,在这边仅列出几个常用的,在实际操作过程中如果有需要的可以自行上网查询
'''
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、@text函数:该函数用于把数据部分分解输出到文本文件中。
'''
@text(['filename'])'''
filename是文件名,可以采用相对路径和绝对路径两种表达方式,如果忽略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
运行该代码可以在lingo所在的位置得到如下一个名为“out”的文本文件
2、@ole函数:从excel中引入或输出数据的接口函数
'''
x = @ole('路徑', '表格中的名字');'''
这边需要讲一下“表格中的名字”是什么意思,以excel为例,选中需要导入的数字,然后点击“公式”-“定义名称”,最后把名称改为你希望的名称即可。单击“名称管理器”可以查看所有的名称,并对其进行统一操作。
用法实例:
x = @OLE('D:/cost.xls',f)
这个代码意思是从D盘名为“cost”的excel表格中,获取表格名为“f”的数据,并将其赋值给x。
sets:
supply/1..2/:s;
demand/1..3/:d;
link(supply, demand):road, g;
endsets
初始集合分别为一维数组supply和demand,其中取值范围分别为1 ~ 2和1 ~ 3,supply和deman分别为数组的类型名,后面代表变量名。
link:衍生集合将两个集合合起来形成一个二维集合,可以理解成表格的形式,例如此题中的road和g的形式就是一个2行3列的表格。
@sum(数组类型名(下标) : 计算公式)
首先要知道在第一部分我们可以知道,求和是对i的求值,并且i为数组supply的下标范围,所以为
@sum(supply(i) : g(i, j))
@sum(link(i, j) : g(i, j) * L(i, j))
@for(数组类型名(下标) : 具体操作)
在j分别=1、2、3的时候,对i = 1,2的情况进行累加求和判断达到相等的要求。
@for(demand(j) : @sum(supply(i) : g(i, j)) = d(j))
整个代码运行2次得到了如下结果
目标函数的最值,也就是运行结果为29000.00
两个变量的值分别取到100.0000, 和30.00000的时候得到上面所说的目标函数的值。
Reduced cost:缩减成本系数,表示变量有微小变动的时候,目标函数的变化率,如果是最优解那就自动取零。
Slack or Surplus:松弛或者剩余,约束条件为“<=”时,右边减左边的差值称为松弛,对于“>=”的不等式,左边减右边的差值称为剩余,当约束条件的左右两边相等,也就是理想状态时,松弛或剩余的值为0,如果约束条件无法满足,则松弛或剩余的值为0。
Dual price:影子价格,表示对应约束有微小变动的时候,目标函数的变化率。
比如说第二行:因为松弛或者剩余的值为0,所以影子价格才有意义(如果不为0,那本身都不紧,十分松的情况下+1, -1就没有这个必要),假设第二行代表的不等式是:x2 <= 10,那影子价格50的含义就是,如果把10变成11,目标函数的结果就会+50。