基于数学模型求解的LINGO使用(一):认识LINGO以及变量的定义


本文为作者原创,若需转载使用请注明来源https://www.cnblogs.com/sangxuuan/p/12246622.html

1、这篇帖子适合你么?(必读)

这学期的一门课上接触了LINGO的使用,得益于老师超前的教学理念,我们用不多的课堂时间掌握了第一门像样的求解器语言。对于我们专业来说,第一次使用LINGO是在运筹学课上,作为上机实验求解线性规划模型、目标规划、整数规划等简单的经典模型,一开始认为只要把一些模型简单的输入求解器按下Undo就可以,后来发现求解一些复杂的模型时,简单的誊抄是远远不够的,复杂的逻辑关系表示需要自己进行开发。

这个记录的帖子,是回顾了这一学期我学习LINGO的轨迹,直接从对于数学模型的理解入手,基于对模型的充分理解进行LINGO的使用。

如果你是本科生,这一系列的帖子足够对LINGO进行初步的了解,想要熟练掌握还需要自己进行练习和总结。以下是我的心得和我认为在学习过程中最重要的理念:

最重要的理解数学模型!最重要的理解数学模型!最重要的理解数学模型!

如果在阅读或者编译的过程中出现问题,欢迎和我交流!评论区也好,邮箱也行!

2、先看一个TSP问题吧!

 

假设一艘船必须访问n个港口(PORT),这n个港口是一个完全图,船需要恰好访问所有港口一次,并且回到起点。

问题的背景就是这样,对于TSP问题,建模的类型以及求解方法在这里先不谈,刚学习LINGO先从标准的问题模型入手:

 

 

 在这里,i,j表示港口所在的城市

具体的代码如下(没有对应的语言类型,故没有Highlight显示,以加粗代替):

 1 data:  2       n=……;
 3 enddata  4 sets:  5     city/1..n/;
 6     link1(city,city):x,d;
 7     link2(city):u;
 8 endsets  9 
10 data: 11        d=
12       (对d(i,j)进行赋值,可以复制粘贴表格)
13        ;
14 enddata 15 min=@sum(
16          city(i):
17  @sum(
18                city(j):
19                     d(i,j)*x(i,j)
20                   )
21          );
22 
23 @for(city(j):
24       @sum(city(i)|i#NE#j:
25            x(i,j)
26            )=1  
27      );
28 @for(city(i):
29       @sum(city(j)|i#NE#j:
30            x(i,j)
31              )=1  
32      );
33 @for(city(i):
34  @for(city(j):
35            @bin(x(i,j))       !@gin整型;@free大于等于零的实数; 36           )
37      );
38 
39 
40 @for(city(i):
41  @for(
42       
43            city(j)|(i#GT#1)#AND#(i#LE#n)#AND#(i#NE#j)#AND#(i#NE#1)#AND#(j#NE#1):
44                       u(i)+u(j)-x(i,j)*n<=4
45             )
46             
47      );

可以看出,LINGO中可以用函数来进行求和的操作,并且可以对变量进行约束,解决了有些特殊的运算符号无法通过键盘直接输入的问题(很有用啊,不用挠头了,直接掉头发就是了)。具体的每一块怎么使用,我会在这个系列下的随笔慢慢更新。如果哪位朋友看到了这个帖子,想用代码,最好自己打一下,我怕会有小的错误,导致运行不了(问题应该不大,这些例题我都运行通过了)。当然,复制粘贴也是可以的,谁不爱这种方式呢。

在这篇帖子接下来的部分中,我要给大家分享的是如何定义变量,以及在编程过程中会出现的小问题。

3、如何在LINGO中定义变量?

在LINGO中定义变量和常见的计算机编程语言略有不同。一是你可以直接输入,在你的模型规模特别小,能够手动输入的情况下;二是声明一个集合,给集合取个名字,定义好集合内变量的个数,当你需要进行运算时,调用你之前声明过的集合,从里面“拿”。

1 sets: 2     city/1..n/; 3     link1(city,city):x,d;
4     link2(city):u;
5 endsets

定义变量的框架为黄色高亮部分,在LINGO的编辑页面会变成蓝色,仔细观察,如果没变化,你可能是输入错了

第二行是定义了一个城市的集合,当然City你可以进行替换,只要你能记住你定义的集合是代表什么的就行,如果变量数量增加,见名知意很重要。另说明一下,我在完整的程序代码中声明过n=?,所以这里可以写n,不进行全局变量n的赋值,这里请换成具体的数字。

下面说一下3、4两行我干了啥。我们从数学模型可以看出,x&d都是双下标变量,都有i&j,而且i&j都是代表港口所在地城市,故可以从同一个集合City中调用i&j,不要担心重复取值,我们后面会有约束对i&j进行限制。这里需要强调,一定要理清变量角标(甚至是上标)的意义是什么,这里举个例子,多个角标来自于不同的集合,如何对变量进行声明:

1 sets:
2     harbor/1..3/;
3     country/1..5/;
4     months/1..12/;
5     sangxuan1(harbor,country,months):z;
6     sangxuan2(country,harbor):d;
7 endsets

这个例子中,我们不难看出,角标数量的多少决定了你调用集合的多少,不同的关系要在声明中理顺清楚,不然会报错。这里的 z 显然是有三个下标的,分别代表港口、城市、月份(顺序不要搞错!)d有两个下标,一个代表城市,一个代表港口。

以上就是最基本的定义变量的方法。后续如果出现特殊情况,我会另作说明进行补充。

4、常见的小问题

常见的小问题大多具有共性,每种编程语言我们多多少少都会遇见,以下是我在学习过程中总结的一点小经验,大家可以参考(LINGO的报错功能没有那么强,所以在使用的时候要非常仔细才行!)

  1. 输入法要使用英文输入法
  2. 注释的符号在这里是“!;”组成的,在LINGO编译器界面会变成亮绿色
  3. “;”结束一段完整的语义
  4. 使用括号要对齐,检查括号和最后一句话的分号(不能自动缩进,用空格调整,Tab调整的范围太大了)
  5. 变量角标的逻辑关系要注意,不能大意
  6. ……(想不起来了,后面慢慢补充,这一部分我会每一期的后面加上这个部分)


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM