基於數學模型求解的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