Lingo 是一款用于线性规划、整数规划和非线性规划的优化软件。以下是一些常见的 Lingo 语法和写法的笔记,帮助你快速上手。
Lingo 模型通常由以下几个部分组成:
集合用于定义索引,通常用于变量和约束的索引。
SETS:
Warehouse /W1, W2, W3/;
Customer /C1, C2, C3, C4/;
ENDSETS
数据可以通过 DATA
部分输入,或者从外部文件读取。
DATA:
Demand = 100, 200, 150, 300;
Supply = 500, 600, 700;
ENDDATA
变量可以是连续的、整数的或二进制的。
VARIABLES:
X(Warehouse, Customer); ! 连续变量
Y(Warehouse); ! 二进制变量
Z; ! 连续变量
目标函数可以是最大化或最小化。
MIN = @SUM(Warehouse(i): @SUM(Customer(j): Cost(i,j) * X(i,j)));
或者
MAX = @SUM(Warehouse(i): Profit(i) * Y(i));
约束条件使用 @FOR
和 @SUM
等函数来定义。
@FOR(Warehouse(i):
@SUM(Customer(j): X(i,j)) <= Supply(i));
@FOR(Customer(j):
@SUM(Warehouse(i): X(i,j)) >= Demand(j));
在模型定义完成后,使用 SOLVE
命令进行求解。
SOLVE;
可以使用 @WRITE
或 @WRITEFOR
输出结果。
@WRITE('Optimal Objective Value: ', Z, '\n');
@WRITEFOR(Warehouse(i): 'Warehouse ', i, ' ships ', @SUM(Customer(j): X(i,j)), '\n');
@SUM
:求和@FOR
:循环@IF
:条件判断@BIN
:定义二进制变量@GIN
:定义整数变量@FREE
:定义无界变量以下是一个简单的运输问题模型:
MODEL:
SETS:
Warehouse /W1, W2, W3/;
Customer /C1, C2, C3, C4/;
ENDSETS
DATA:
Demand = 100, 200, 150, 300;
Supply = 500, 600, 700;
Cost = 2, 4, 5, 3,
3, 1, 2, 4,
5, 3, 2, 1;
ENDDATA
VARIABLES:
X(Warehouse, Customer);
ENDVARIABLES
MIN = @SUM(Warehouse(i): @SUM(Customer(j): Cost(i,j) * X(i,j)));
@FOR(Warehouse(i):
@SUM(Customer(j): X(i,j)) <= Supply(i));
@FOR(Customer(j):
@SUM(Warehouse(i): X(i,j)) >= Demand(j));
SOLVE;
END
!
开头。希望这些笔记对你使用 Lingo 有所帮助!
瞄准
,即运行按钮。值得注意的是,非线性规划的求解非常困难,基本得不到全局最优解。
做建模的同学建议转化为线性来解,不然速度会很慢,并且很难得到最优解。
sets:
factory/1..6/:a,b;
plant/1..3/:x,y;
endsets
data:
a=1,2,3,4,5,6;
x=1,2,3;
enddata
@for(gc(i):s=a(i)*x(i));
@sum(gc(i):x(i))=5000;
model:
sets:
gc/1..5/:a,x;
endsets
data:
a=1,2,3,4,5;
enddata
max=s;
@for(gc(i):s=a(i)*x(i));
@sum(gc(i):x(i))=5000;
end
sets:
factory/1..6/:a;
plant/1..2/:x;
cooperation(factory,plant):c;
endsets
m i n z = ∑ i = 1 6 ∑ j = 1 8 c i j ⋅ x i j min \quad z=\sum_{i=1}^{6}\sum_{j=1}^{8}c_{ij}\cdot x_{ij} minz=∑i=16∑j=18cij⋅xij
{ ∑ j = 1 8 x i j ≤ a i , i = 1 , 2 , ⋯ , 6 ∑ i = 1 6 x i j = d j , j = 1 , 2 , ⋯ , 8 x i j ≥ 0 , i = 1 , ⋯ , 6 , j = 1 , ⋯ , 8 \begin{cases} \sum_{j=1}^{8}x_{ij} \leq a_{i},i=1,2,\cdots,6 \\ \sum_{i=1}^{6}x_{ij} =d_{j},j=1,2,\cdots,8 \\ x_{ij} \geq 0,i=1,\cdots,6,j=1,\cdots,8 \end{cases} ⎩ ⎨ ⎧∑j=18xij≤ai,i=1,2,⋯,6∑i=16xij=dj,j=1,2,⋯,8xij≥0,i=1,⋯,6,j=1,⋯,8
model:
sets:
factory/1..6/:a;
plant/1..8/:d;
coo(factory,plant):c,x;
endsets
data:
a=60,55,51,43,41,52;
d=35,37,22,32,41,32,43,38;
c=6,2,6,7,4,2,5,8
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;
enddata
min=@sum(coo(i,j):c(i,j)*x(i,j));
@for(factory(i):@sum(plant(j):x(i,j))<=a(i));
@for(plant(j):@sum(factory(i):x(i,j))=d(j));
end
b=10;
e=0.000001;
A-e=b;
因为在求最优化方案时,x>2与x>=2的相差非常小
逻辑运算符
运算符 | 理解 | 作用 |
---|---|---|
#eq# | equal | 相等为真 |
#ne# | not equal | 不相等为真 |
#gt# | greater than | A>B为真 |
#ge# | greater equal | A>=B为真 |
#lt# | less than | A |
#le# | less equal | A<=B为真 |
运算符 | 理解 | 作用 |
---|---|---|
#not# | 非门 | 取反 |
#and# | 与门 | 左右两边均真才真 |
#or# | 或门 | 左右两边均假才假 |
model:
sets:
plant/1..6/:a;
endsets
data:
a=6,5,4,3,2,1;
enddata
y=@sum(plant(i)|i#ge#5 : a(i));
end
@for(plant(i)|
i#le#2 #or# i#ge#5 : d(i)>5);
使用方法:@sum(矩阵工厂 | 判断条件 : 矩阵);
x#ge#0 #and# x#le#500
x#le#500
@if(x#le#500,4*x,@if(x#gt#1000,1500+2*x,500+3*x));
使用方法:@if(判断,成功执行片段,相当于else(f否时执行片段));
特别提醒:else的部分不可省略
函数 | 作用 |
---|---|
@bin(x) | 限制x只能取0或1,0-1规划中有用 |
@gin(x) | 限制x为整数,整数规划中有用 |
@bnd(a,x,b) | 限制a ≤ \leq ≤x ≤ \leq ≤b |
@free(x) | 取消对x非负的默认限制,使其定义域自由 |
类别 | 函数名 | 返回值 |
---|---|---|
三角函数 | @sin(x) | 返回x的正弦值 |
@cos(x) | 返回x的余弦值 | |
@tan(x) | 返回x的正切值 | |
指数函数 | @log(x) | 返回x的自然对数值,其他底数使用换底公式 |
@exp(x) | 返回 e x e^{x} ex的值,因为无法敲出e的值而诞生 | |
其他 | @abs(x) | 返回x的绝对值 |
@sigh(x) | 返回x的符号值,整数为1,负数为-1 | |
@floor(x) | 返回x的整数部分,向下取整 | |
比较大小 | @smax(x1,…,xn) | 返回其中最大值 |
@smin(1,…,xn) | 返回其中最小值 |
类别 | 函数名 | 作用 |
---|---|---|
常用 | @for(factory:a>0) | 循环 |
@sum(factory:a) | 求和 | |
有用 | @prod(factory:a) | 求积 |
@max(factory:a) | 求最大值 | |
@min(factory:a) | 求最小值 | |
很少用 | @in(factory,c) | 判断常数c是否在集合中 |
@size(factory) | 返回可生产矩阵长度 |