一小時學會用LINGO求解優化模型

Lingo是學習成本最低的,求解各種規模規劃問題的神器。本文用一個例子讓你快速上手Lingo。

優化問題

現實生活中,遇到的很多問題可以轉換到某個優化問題,并給出某種優化模型。優化問題是指求滿足一定約束條件下的決策變量,使得目標函數最大或最小的問題。

小紅想買若干個茄子、黃瓜和香蕉,每樣最多買5斤,總共至少買10斤。茄子10元,黃瓜20元,香蕉30元。問怎樣買最省錢。

這個優化問題的各個元素如下

  • 決策變量,茄子、黃瓜和香蕉每一種買的斤數。
  • 約束條件,每樣最多買5斤,至少買10斤水果。
  • 目標函數,購買每種用具所花的費用之和。

優化問題的可行解指的是滿足約束條件的決策變量,比如每樣來4斤。最優解指的是使得目標函數取得最大或最小的可行解。

按照決策變量和約束條件的性質,可以把優化問題分為很多種。比如整數規劃、線性規劃等等。你只需要知道Lingo都可以解決即可。

Lingo

簡介

Lingo由美國芝加哥(Chicago)大學的Linus Schrage教授于1980年前后開發,按照求解的規模,分為演示版、學生版、高級版、工業版等等不同的版本。

本文使用的軟件,來自于網絡上流傳已久的版本, LINGO_11.0

使用這個版本是為了方便學習和演示,若要用于商業,還請購買最新的軟件。

開始

直接下載并解壓,找到解壓后的文件夾中的lingo11.exe即可運行。

軟件界面是英文,而且據筆者了解暫時沒有漢化。默認打開后就是一個標題為LINGO MODEL - LINGO 1的文本輸入頁面,這是模型頁面。我們所有的工作就從這個頁面開始。

第一個模型

在模型頁面中,復制下列代碼。

由于編碼的問題,直接復制之后的所有中文字符會無法識別。但lingo支持中文,所以將?刪去,改為該有的中文即可。

!模型1:小紅買水果;
title: 買用具;
!目標函數;
min = 10*x1+20*x2+30*x3;
!約束條件;
x1<=5;
x2<=5;
x3<=5;
x1+x2+x3>=10;

依次點擊菜單欄LINGO->solve ,彈出了求解狀態窗口(solver status}和求解報告窗口(solution report).

回顧一下問題。小紅想買若干個茄子、黃瓜和香蕉,每樣最多買5斤,總共至少買10斤。茄子10元,黃瓜20元,香蕉30元。問怎樣買最省錢。

在求解報告窗口中,我們發現找到了全局最優解,目標函數最少為150,也就是最少花150元。在報告中部,變量和值的部分中,看到茄子和香蕉各買5斤。

也許上面一串代碼只想讓你砸了電腦,放輕松,Lingo不是一門編程語言,只是將我們日常鼠標的操作轉化成了命令而已。

基本元素

語句

Lingo的模型文件由一行行語句組成,Lingo在開始求解模型后,會先分析每行語句,并知道自己該干什么。

每行語句必須以英文分號結尾,事實上所有的符號都必須在英文狀態下輸入。這是因為lingo一般會忽略空格和換行符,所以在Lingo看來

x1
<
=
5;

x1<=5;沒什么區別。

值得一提的是,若語法錯誤,比如輸入了中文的分號,Lingo會提示

Incalid input: A syntax error has occurred

并且指出錯誤的符號。

Lingo中允許注釋,并且注釋中可以添加中文,就像第一個實例中的一樣。注釋語句可以出現在任何地方,以!起始,末尾;結束,Lingo會忽略掉這兩個符號間的所有內容。就像這樣

!ingnoreAnything;

我們推薦模型的每一行都給出注釋,因為也許幾天后你自己也不知道當初的想法。

變量

Lingo不區分大小寫字母, 忽略掉這一點會導致令人沮喪的行為,就像Lingo的腦子突然短路了一樣。

變量不必預先定義,直接在語句中出現即可。決策變量也沒有特殊的標記,沒有賦予初值的變量都作為可變得決策變量。所以不要給決策變量賦初值

變量名必須用字母開頭,其后可以是其他字符、數字或下劃線。變量名不能超過32個字符。

就像我們在第一個模型中,語句

min = 10*x1+20*x2+30*x3;

創造了x1、x2和x3三個變量,代表茄子、黃瓜和香蕉的購買量。

運算符

Lingo支持所有的數學運算,以及常見的函數。所有支持的函數以及調用的命令,讀者可以去查閱Lingo的幫助文檔。當然也可以看文末的參考文獻。

直接在模型頁面輸入這個例子,求解試一試

x1+1=1;
x2*1=1;
x3/2=1;
x4-2=1;
x5^2=1;
(x6+x7)^2=1;

有一類特殊的運算符被用在條件判斷中,被稱為條件和邏輯運算符。在提到集合以及集合函數后,我們會繼續介紹。

集合

基本集合

集合是Lingo非常強大的功能。因為我們一般涉及到的數據不會只有兩三鐘,而是成百上千的數據,以及他們之間彼此構成的百萬計的矩陣。

還是從第一個模型開始。

小紅看到水果生意這么好做,決定前去批發水果倒賣。假設她要買編號從1到10共10種水果,我們設x(j)為編號為j的水果的購買量,那么j的取值范圍就是1到10,這一百個整數。

于是我們建立了一個擁有10個元素的集合。在Lingo中,用集合域來定義集合。

將下面的代碼復制到空白的模型文件中,并求解。

!下面sets:和endsets之間的部分被稱為集合域;
sets:
!fruit表示一個索引范圍,從1到10。x為水果購買量;
fruit/1..10/:x;
!集合域的結束;
endsets

集合使用前,必須在集合域定義。集合域可以出現在模型文件的任意部分,但不能嵌套在其他域中。

一個集合的定義語句包括三個部分:指標集名稱、指標范圍、集合名稱。

fruit/1..10/:x;

其中fruit 為指標集名稱,/1..10/ 表示指標范圍,x表示擁有指標fruit 的集合。

在一個集合定義語句中,可以一次定義多個擁有相同指標的集合,之間用, 隔開。也可以把集合名留空,表示給一個指標集名稱指定了一個指標范圍。

fruit/1..100/:x,y;!定義了兩個有10個元素的集合;

要想引用集合中的變量,使用

x(1);

這種集合名后附一個括號表示元素的坐標。

派生集合

我們更常用的是派生集合,即有雙下標的集合,就是我們日常所說的矩陣。

小紅可以從80個供應商手中拿貨,將供應商按1到8編號。第i號供應商可以提供的第j號水果的量設為c(ij)。則c(ij)構成的集合共有80個元素,并用兩個指標i,j索引。

在Lingo中,使用派生集合來定義這種兩個指標集生成的矩陣。

sets:
fruit/1..10/:x;
supplier/1..8/;
supply(supplier,fruit):c;
endsets

上述語句中,先定義了兩個指標集fruitsupplier,范圍分別是1到10和1到8. 隨后用新的語法定義了前面提到的供應量c(ij)

supply(supplier,fruit):c;

這行語句表示定義行坐標為supplier,列坐標為fruit 的新指標集supply ,并且說明變量c 擁有指標集supply. 換句話說,集合c 是一個行坐標為supplier,列坐標為fruit 的矩陣。

引用派生集合中元素的語法為

c(1,1)

這句引用了第一行第一列的元素。

也可以從三個或多個指標集中派生集合。

數據域

定義集合之后,若集合中的元素本身不是決策變量,我們需要對集合中的元素進行賦值。

小紅需要知道10種水果的詳細價錢,以及8個供應商提供的80個供應量數據。Lingo同樣也要知道這些。

sets:
!增加了price集合;
fruit/1..10/:x,price;
supplier/1..8/;
supply(fruit,supplier):c;
endsets

data:
price=10,20,30,40,50,60,20,10,5,10;
c=
1 2 1 3 1 3 1 4 1 4 
1 2 1 3 1 4 1 3 1 4
1 2 1 3 1 3 1 4 1 4
1 2 1 3 1 3 1 4 1 4
1 2 1 3 1 3 1 4 1 4
1 2 1 3 1 3 1 4 1 4
1 2 1 3 1 3 1 4 1 4;
enddata

對非決策變量進行賦值時,賦值語句必須位于數據域中。數據域以data: 開始,enddata 結束。

賦值時,只需要按照數學中的寫法將元素排列上去即可。一般派生集合我們采用示例代碼中的寫法,讓人一目了然。但是要注意,c中的換行并不是必須的,只是為了方便人去理解。

集合函數

定義集合的一大優勢在于,可以用非常方便的方法遍歷集合。

總共有四個集合函數,包括遍歷函數@for,求和函數@sum , 最小值函數@min和最大值函數@max

你可以像這樣使用集合函數

z=@sum(fruit(j)|j #GE#2 
    :price(j));

上面的語句表示對標號大于等于2的水果的價錢求和。注意其中的換行并不是必須的。

一般語法為

@function(setname(set_index)|conditional_qualifier:

? expression);

其中function 為四種集合函數,setname 為指標集名稱,set_index為指標變量,|conditional_qualifier是條件判斷,用于界定指標變量的范圍, expression 為所要求的表達式。

邏輯運算符

邏輯運算符只能用于條件判斷中,使用條件判斷的場合包括上文提到的集合函數,以及@if 語句中。

常用的邏輯運算符有

運算符 意義
#eq# 相等
#ne# 不相等
#gt# 大于
#ge# 大于等于
#lt# 小于
#le# 小于等于
#and#
#or#
#not#

@if是條件函數,一般用在分段函數中。語法為

@if(條件表達式,真值,假值);

如果條件表達式的結果為真,則這個函數返回真值,表達式結果為假,則返回假值。

變量限制

我們在實際應用中,往往要對決策變量做某些限制。比如小紅買水果,若商家只愿意整斤賣,則水果購買量必須為整數。

Lingo默認的變量取值范圍是大于零的實數,若要指出某個決策變量的限制,需要使用變量限制語句。

變量限制的語法如下

@bin(x);

這行語句表示x只能取0或1.

所有的變量限制語句如下

語句 意義
@bnd(下限,x,上限) x取下限到上限之間的值
@free(x) x取所有實數
@gin(x) x取整數
@bin(x) x取0,1

變量限制語句一般用在@for中。

最終的模型

小紅想從8個供貨商購進10種水果。從第i個供貨商購買第j種水果的購買量為x(ij), 第i個供貨商對第j種水果的供應量為c(j), 每種水果統一市場定價為price(j)。若總共進50斤水果,最多從一個購買手中購進10斤水果。水果必須論整斤賣。問怎樣購買最省錢。

下面是模型文件的內容。

sets:
!price(j)是每種水果的價錢;
fruit/1..10/:price;
supplier/1..8/;
!c(ij)為供貨量,x(ij)為購買量;
supply(supplier,fruit):c,x;
endsets

data:
price=10,20,30,40,50,60,20,10,5,10;
c=
1 2 1 3 1 3 1 4 1 4 
1 2 1 3 1 4 1 3 1 4
1 2 1 3 1 3 1 4 1 4
1 2 1 3 1 3 1 4 1 4
1 2 1 3 1 3 1 4 1 4
1 2 1 3 1 3 1 4 1 4
1 2 1 3 1 3 1 4 1 4
1 2 1 3 1 3 1 4 1 4;
enddata

min = @sum(fruit(J):
        @sum(supplier(I): price(J)*x(I,J)));

!每種水果購買量不超過供應量;
@for(supply(I,J):
    x(I,J) <= c(I,J));

!至少購買50斤水果;
@sum(supply(I,J):
    x(I,J))>=50;

!每種供應商至多購買十斤;
@for(supplier(I):
    @sum(fruit(J):x(I,J))<=10);

!購買量必須為整數;
@for(supply(I,J):
    @gin(x));

Have fun!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容