1. 程式人生 > >LINGO使用指南(轉載)

LINGO使用指南(轉載)

LINGO是用來求解線性和非線性優化問題的簡易工具。LINGO內建了一種建立最優化模型的語言,可以簡便地表達大規模問題,利用LINGO高效的求解器可快速求解並分析結果。

§1  LINGO快速入門

當你在windows下開始執行LINGO系統時,會得到類似下面的一個視窗:

外層是主框架視窗,包含了所有選單命令和工具條,其它所有的視窗將被包含在主視窗之下。在主視窗內的標題為LINGO Model – LINGO1的視窗是LINGO的預設模型視窗,建立的模型都都要在該視窗內編碼實現。下面舉兩個例子。

例1.1 如何在LINGO中求解如下的LP問題:

 

在模型視窗中輸入如下程式碼:

min=2*x1+3*x2;

x1+x2>=350;

x1>=100;

2*x1+x2<=600;

然後點選工具條上的按鈕    即可。

例1.2 使用LINGO軟體計算6個發點8個收點的最小費用運輸問題。產銷單位運價如下表。

銷地

產地 B1 B2 B3 B4 B5 B6 B7 B8 產量

A1 6 2 6 7 4 2 5 9 60

A2 4 9 5 3 8 5 8 2 55

A3 5 2 1 9 7 4 3 3 51

A4 7 6 7 3 9 2 7 1 43

A5 2 3 9 5 7 2 6 5 41

A6 5 5 2 2 8 1 4 3 52

銷量 35 37 22 32 41 32 43 38 

使用LINGO軟體,編制程式如下:

model:

!6發點8收點運輸問題;

sets:

  warehouses/wh1..wh6/: capacity;

  vendors/v1..v8/: demand;

  links(warehouses,vendors): cost, volume;

endsets

!目標函式;

 
[email protected](links
: cost*volume);

!需求約束;

  @for(vendors(J):

    @sum(warehouses(I): volume(I,J))=demand(J));

!產量約束;

  @for(warehouses(I):

    @sum(vendors(J): volume(I,J))<=capacity(I));

!這裡是資料;

data:

  capacity=60 55 51 43 41 52;

  demand=35 37 22 32 41 32 43 38;

  cost=6 2 6 7 4 2 9 5

       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

end

然後點選工具條上的按鈕    即可。

為了能夠使用LINGO的強大功能,接著第二節的學習吧。

§2  LINGO中的集

對實際問題建模的時候,總會遇到一群或多群相聯絡的物件,比如工廠、消費者群體、交通工具和僱工等等。LINGO允許把這些相聯絡的物件聚合成集(sets)。一旦把物件聚合成集,就可以利用集來最大限度的發揮LINGO建模語言的優勢。

現在我們將深入介紹如何建立集,並用資料初始化集的屬性。學完本節後,你對基於建模技術的集如何引入模型會有一個基本的理解。

2.1 為什麼使用集

集是LINGO建模語言的基礎,是程式設計最強有力的基本構件。藉助於集,能夠用一個單一的、長的、簡明的複合公式表示一系列相似的約束,從而可以快速方便地表達規模較大的模型。

2.2 什麼是集

集是一群相聯絡的物件,這些物件也稱為集的成員。一個集可能是一系列產品、卡車或僱員。每個整合員可能有一個或多個與之有關聯的特徵,我們把這些特徵稱為 屬性。屬性值可以預先給定,也可以是未知的,有待於LINGO求解。例如,產品集中的每個產品可以有一個價格屬性;卡車集中的每輛卡車可以有一個牽引力屬 性;僱員集中的每位僱員可以有一個薪水屬性,也可以有一個生日屬性等等。

LINGO有兩種型別的集:原始集(primitive set)和派生集(derived set)。

一個原始集是由一些最基本的物件組成的。

一個派生集是用一個或多個其它集來定義的,也就是說,它的成員來自於其它已存在的集。

2.3 模型的集部分

集部分是LINGO模型的一個可選部分。在LINGO模型中使用集之前,必須在集部分事先定義。集部分以關鍵字“sets:”開始,以“endsets” 結束。一個模型可以沒有集部分,或有一個簡單的集部分,或有多個集部分。一個集部分可以放置於模型的任何地方,但是一個集及其屬性在模型約束中被引用之前 必須定義了它們。

2.3.1 定義原始集

為了定義一個原始集,必須詳細宣告:

?集的名字

?可選,集的成員

?可選,整合員的屬性

定義一個原始集,用下面的語法:

setname[/member_list/][:attribute_list];

注意:用“[]”表示該部分內容可選。下同,不再贅述。

Setname是你選擇的來標記集的名字,最好具有較強的可讀性。集名字必須嚴格符合標準命名規則:以拉丁字母或下劃線(_)為首字元,其後由拉丁字母(A—Z)、下劃線、阿拉伯數字(0,1,…,9)組成的總長度不超過32個字元的字串,且不區分大小寫。

注意:該命名規則同樣適用於整合員名和屬性名等的命名。

Member_list是整合員列表。如果整合員放在集定義中,那麼對它們可採取顯式羅列和隱式羅列兩種方式。如果整合員不放在集定義中,那麼可以在隨後的資料部分定義它們。

① 當顯式羅列成員時,必須為每個成員輸入一個不同的名字,中間用空格或逗號擱開,允許混合使用。

例2.1 可以定義一個名為students的原始集,它具有成員John、Jill、Rose和Mike,屬性有sex和age:

sets:

  students/John  Jill, Rose  Mike/: sex, age;

endsets

② 當隱式羅列成員時,不必羅列出每個整合員。可採用如下語法:

setname/member1..memberN/[: attribute_list];

這裡的member1是集的第一個成員名,memberN是集的最末一個成員名。LINGO將自動產生中間的所有成員名。LINGO也接受一些特定的首成員名和末成員名,用於建立一些特殊的集。列表如下:

隱式成員列表格式 示例 所產生整合員

1..n 1..5 1,2,3,4,5

StringM..StringN Car2..car14 Car2,Car3,Car4,…,Car14

DayM..DayN Mon..Fri Mon,Tue,Wed,Thu,Fri

MonthM..MonthN Oct..Jan Oct,Nov,Dec,Jan

MonthYearM..MonthYearN Oct2001..Jan2002 Oct2001,Nov2001,Dec2001,Jan2002

③ 整合員不放在集定義中,而在隨後的資料部分來定義。

例2.2

!集部分;

sets:

  students:sex,age;

endsets

!資料部分;

data:

  students,sex,age= John 1 16

                    Jill 0 14

                    Rose 0 17

                    Mike 1 13;

enddata

注意:開頭用感嘆號(!),末尾用分號(;)表示註釋,可跨多行。

在集部分只定義了一個集students,並未指定成員。在資料部分羅列了整合員John、Jill、Rose和Mike,並對屬性sex和age分別給出了值。

整合員無論用何種字元標記,它的索引都是從1開始連續計數。在attribute_ list可以指定一個或多個整合員的屬性,屬性之間必須用逗號隔開。

可以把集、整合員和集屬性同C語言中的結構體作個類比。如下圖:

集  ←→  結構體

整合員  ←→  結構體的域

集屬性  ←→  結構體例項

LINGO內建的建模語言是一種描述性語言,用它可以描述現實世界中的一些問題,然後再借助於LINGO求解器求解。因此,集屬性的值一旦在模型中被確 定,就不可能再更改。在LINGO中,只有在初始部分中給出的集屬性值在以後的求解中可更改。這與前面並不矛盾,初始部分是LINGO求解器的需要,並不 是描述問題所必須的。

2.3.2 定義派生集

為了定義一個派生集,必須詳細宣告:

?集的名字

?父集的名字

?可選,整合員

?可選,整合員的屬性

可用下面的語法定義一個派生集:

setname(parent_set_list)[/member_list/][:attribute_list];

setname是集的名字。parent_set_list是已定義的集的列表,多個時必須用逗號隔開。如果沒有指定成員列表,那麼LINGO會自動建立父整合員的所有組合作為派生集的成員。派生集的父集既可以是原始集,也可以是其它的派生集。

例2.3

sets:

  product/A B/;

  machine/M N/;

  week/1..2/;

  allowed(product,machine,week):x;

endsets

LINGO生成了三個父集的所有組合共八組作為allowed集的成員。列表如下:

編號         成員

1        (A,M,1)

2 2                            (A,M,2)

3 3                            (A,N,1)

4 4                            (A,N,2)

5 5                            (B,M,1)

6 6                            (B,M,2)

7 7                            (B,N,1)

8 8                            (B,N,2)

成員列表被忽略時,派生整合員由父整合員所有的組合構成,這樣的派生整合為稠密集。如果限制派生集的成員,使它成為父整合員所有組合構成的集合的一個子 集,這樣的派生整合為稀疏集。同原始集一樣,派生整合員的宣告也可以放在資料部分。一個派生集的成員列表有兩種方式生成:①顯式羅列;②設定成員資格過濾 器。當採用方式①時,必須顯式羅列出所有要包含在派生集中的成員,並且羅列的每個成員必須屬於稠密集。使用前面的例子,顯式羅列派生集的成員:

allowed(product,machine,week)/A M 1,A N 2,B N 1/;

如果需要生成一個大的、稀疏的集,那麼顯式羅列就很討厭。幸運地是許多稀疏集的成員都滿足一些條件以和非成員相區分。我們可以把這些邏輯條件看作過濾器,在LINGO生成派生集的成員時把使邏輯條件為假的成員從稠密集中過濾掉。

例2.4

sets:

  !學生集:性別屬性sex,1表示男性,0表示女性;年齡屬性age.  ;

  students/John,Jill,Rose,Mike/:sex,age;

  !男學生和女學生的聯絡集:友好程度屬性friend,[0,1]之間的數。 ;

  linkmf(students,students)|sex(&1) #eq# 1 #and# sex(&2) #eq# 0: friend;

  !男學生和女學生的友好程度大於0.5的集;

  linkmf2(linkmf) | friend(&1,&2) #ge# 0.5 : x;

endsets

data:

  sex,age = 1 16

            0 14

            0 17

            0 13;

  friend = 0.3 0.5 0.6;

enddata

用豎線(|)來標記一個成員資格過濾器的開始。#eq#是邏輯運算子,用來判斷是否“相等”,可參考§4. &1可看作派生集的第1個原始父集的索引,它取遍該原始父集的所有成員;&2可看作派生集的第2 個原始父集的索引,它取遍該原始父集的所有成員;&3,&4,……,以此類推。注意如果派生集B的父集是另外的派生集A,那麼上面所說的 原始父集是集A向前回溯到最終的原始集,其順序保持不變,並且派生集A的過濾器對派生集B仍然有效。因此,派生集的索引個數是最終原始父集的個數,索引的 取值是從原始父集到當前派生集所作限制的總和。

總的來說,LINGO可識別的集只有兩種型別:原始集和派生集。

在一個模型中,原始集是基本的物件,不能再被拆分成更小的組分。原始集可以由顯式羅列和隱式羅列兩種方式來定義。當用顯式羅列方式時,需在整合員列表中逐個輸入每個成員。當用隱式羅列方式時,只需在整合員列表中輸入首成員和末成員,而中間的成員由LINGO產生。

另一方面,派生集是由其它的集來建立。這些集被稱為該派生集的父集(原始集或其它的派生集)。一個派生集既可以是稀疏的,也可以是稠密的。稠密集包含了父 整合員的所有組合(有時也稱為父集的笛卡爾乘積)。稀疏集僅包含了父集的笛卡爾乘積的一個子集,可通過顯式羅列和成員資格過濾器這兩種方式來定義。顯式羅 列方法就是逐個羅列稀疏集的成員。成員資格過濾器方法通過使用稀疏整合員必須滿足的邏輯條件從稠密整合員中過濾出稀疏集的成員。不同集型別的關係見下圖。

§3  模型的資料部分和初始部分

   在處理模型的資料時,需要為集指派一些成員並且在LINGO求解模型之前為集的某些屬性指定值。為此,LINGO為使用者提供了兩個可選部分:輸入整合員和資料的資料部分(Data Section)和為決策變數設定初始值的初始部分(Init Section)。

    3.1 模型的資料部分

    3.1.1 資料部分入門

資料部分提供了模型相對靜止部分和資料分離的可能性。顯然,這對模型的維護和維數的縮放非常便利。

資料部分以關鍵字“data:”開始,以關鍵字“enddata”結束。在這裡,可以指定整合員、集的屬性。其語法如下:

object_list = value_list;

物件列(object_list)包含要指定值的屬性名、要設定整合員的集名,用逗號或空格隔開。一個物件列中至多有一個集名,而屬性名可以有任意多。如果物件列中有多個屬性名,那麼它們的型別必須一致。如果物件列中有一個集名,那麼物件列中所有的屬性的型別就是這個集。

數值列(value_list)包含要分配給物件列中的物件的值,用逗號或空格隔開。注意屬性值的個數必須等於整合員的個數。看下面的例子。

例3.1

sets:

  set1/A,B,C/: X,Y;

endsets

data:

  X=1,2,3;

  Y=4,5,6;

enddata

在集set1中定義了兩個屬性X和Y。X的三個值是1、2和3,Y的三個值是4、5和6。也可採用如下例子中的複合資料宣告(data statement)實現同樣的功能。

例3.2

sets:

  set1/A,B,C/: X,Y;

endsets

data:

  X,Y=1 4

      2 5

      3 6;

enddata

看到這個例子,可能會認為X被指定了1、4和2三個值,因為它們是數值列中前三個,而正確的答案是1、2和3。假設物件列有n個物件,LINGO在為物件 指定值時,首先在n個物件的第1個索引處依次分配數值列中的前n個物件,然後在n個物件的第2個索引處依次分配數值列中緊接著的n個物件,……,以此類 推。

模型的所有資料——屬性值和整合員——被單獨放在資料部分,這可能是最規範的資料輸入方式。

3.1.2 引數

在資料部分也可以指定一些標量變數(scalar variables)。當一個標量變數在資料部分確定時,稱之為引數。看一例,假設模型中用利率8.5%作為一個引數,就可以象下面一樣輸入一個利率作為引數。

例3.3

data:

  interest_rate = .085;

enddata

也可以同時指定多個引數。

例3.4

data:

  interest_rate,inflation_rate = .085 .03;

enddata

3.1.3 實時資料處理

在某些情況,對於模型中的某些資料並不是定值。譬如模型中有一個通貨膨脹率的引數,我們想在2%至6%範圍內,對不同的值求解模型,來觀察模型的結果對通 貨膨脹的依賴有多麼敏感。我們把這種情況稱為實時資料處理(what if analysis)。LINGO有一個特徵可方便地做到這件事。

在本該放數的地方輸入一個問號(?)。

例3.5

data:

  interest_rate,inflation_rate = .085  ?;

enddata

每一次求解模型時,LINGO都會提示為引數inflation_rate輸入一個值。在WINDOWS作業系統下,將會接收到一個類似下面的對話方塊:

直接輸入一個值再點選OK按鈕,LINGO就會把輸入的值指定給inflation_rate,然後繼續求解模型。

    除了引數之外,也可以實時輸入集的屬性值,但不允許實時輸入整合員名。

    3.1.4 指定屬性為一個值

可以在資料宣告的右邊輸入一個值來把所有的成員的該屬性指定為一個值。看下面的例子。

例3.6

sets:

  days /MO,TU,WE,TH,FR,SA,SU/:needs;

endsets

data:

  needs = 20;

enddata

LINGO將用20指定days集的所有成員的needs屬性。對於多個屬性的情形,見下例。

例3.7

sets:

  days /MO,TU,WE,TH,FR,SA,SU/:needs,cost;

endsets

data:

  needs cost = 20 100;

enddata

    3.1.5 資料部分的未知數值

有時只想為一個集的部分成員的某個屬性指定值,而讓其餘成員的該屬性保持未知,以便讓LINGO去求出它們的最優值。在資料宣告中輸入兩個相連的逗號表示該位置對應的整合員的屬性值未知。兩個逗號間可以有空格。

例3.8

sets:

  years/1..5/: capacity;

endsets

data:

  capacity = ,34,20,,;

enddata

屬性capacity的第2個和第3個值分別為34和20,其餘的未知。

    3.2 模型的初始部分

初始部分是LINGO提供的另一個可選部分。在初始部分中,可以輸入初始宣告(initialization statement),和資料部分中的資料宣告相同。對實際問題的建模時,初始部分並不起到描述模型的作用,在初始部分輸入的值僅被LINGO求解器當作 初始點來用,並且僅僅對非線性模型有用。和資料部分指定變數的值不同,LINGO求解器可以自由改變初始部分初始化的變數的值。

一個初始部分以“init:”開始,以“endinit”結束。初始部分的初始宣告規則和資料部分的資料宣告規則相同。也就是說,我們可以在宣告的左邊同時初始化多個集屬性,可以把集屬性初始化為一個值,可以用問號實現實時資料處理,還可以用逗號指定未知數值。

例3.9

init:

  X, Y = 0, .1;

endinit

[email protected](X
);

X^2+Y^2<=1;

好的初始點會減少模型的求解時間。

在這一節中,我們僅帶大家接觸了一些基本的資料輸入和初始化概念,不過現在你應該可以輕鬆的為自己的模型加入原始資料和初始部分啦。

§4  LINGO函式

    有了前幾節的基礎知識,再加上本節的內容,你就能夠藉助於LINGO建立並求解複雜的優化模型了。

LINGO有9種類型的函式:

1. 1.基本運算子:包括算術運算子、邏輯運算子和關係運算符

2. 2.數學函式:三角函式和常規的數學函式

3. 3.金融函式:LINGO提供的兩種金融函式

4. 4.概率函式:LINGO提供了大量概率相關的函式

5. 5.變數界定函式:這類函式用來定義變數的取值範圍

6. 6.集操作函式:這類函式為對集的操作提供幫助

7. 7.集迴圈函式:遍歷集的元素,執行一定的操作的函式

8. 8.資料輸入輸出函式:這類函式允許模型和外部資料來源相聯絡,進行資料的輸入輸出

9. 9.輔助函式:各種雜類函式

4.1 基本運算子

這些運算子是非常基本的,甚至可以不認為它們是一類函式。事實上,在LINGO中它們是非常重要的。

4.1.1 算術運算子

算術運算子是針對數值進行操作的。LINGO提供了5種二元運算子:

^ 乘方

﹡ 乘

/ 除

﹢ 加

﹣ 減

LINGO唯一的一元算術運算子是取反函式“﹣”。

這些運算子的優先順序由高到底為:

高 ﹣(取反)

      ^

    ﹡/

  低 ﹢﹣

運算子的運算次序為從左到右按優先順序高低來執行。運算的次序可以用圓括號“()”來改變。

例4.1 算術運算子示例。

2﹣5/3,(2﹢4)/5等等。

4.1.2 邏輯運算子

在LINGO中,邏輯運算子主要用於集迴圈函式的條件表示式中,來控制在函式中哪些整合員被包含,哪些被排斥。在建立稀疏集時用在成員資格過濾器中。

LINGO具有9種邏輯運算子:

#not#  否定該運算元的邏輯值,#not#是一個一元運算子

#eq#  若兩個運算數相等,則為true;否則為flase

#ne#    若兩個運算子不相等,則為true;否則為flase

#gt#    若左邊的運算子嚴格大於右邊的運算子,則為true;否則為flase

#ge#   若左邊的運算子大於或等於右邊的運算子,則為true;否則為flase

#lt#   若左邊的運算子嚴格小於右邊的運算子,則為true;否則為flase

#le#   若左邊的運算子小於或等於右邊的運算子,則為true;否則為flase

#and#  僅當兩個引數都為true時,結果為true;否則為flase

#or#    僅當兩個引數都為false時,結果為false;否則為true

這些運算子的優先順序由高到低為:

高  #not#

    #eq#  #ne#  #gt#  #ge#  #lt#  #le#

低  #and#  #or#

例4.2 邏輯運算子示例

2 #gt# 3 #and# 4 #gt# 2,其結果為假(0)。

    4.1.3 關係運算符

在LINGO中,關係運算符主要是被用在模型中,來指定一個表示式的左邊是否等於、小於等於、或者大於等於右邊,形成模型的一個約束條件。關係運算符與邏 輯運算子#eq#、#le#、#ge#截然不同,前者是模型中該關係運算符所指定關係的為真描述,而後者僅僅判斷一個該關係是否被滿足:滿足為真,不滿足 為假。

 LINGO有三種關係運算符:“=”、“<=”和“>=”。LINGO中還能用“<”表示小於等於關係,“>”表示大於等於關係。LINGO並不支援嚴格小於和嚴格大於關係運算符。然而,如果需要嚴格小於和嚴格大於關係,比如讓A嚴格小於B:A

那麼可以把它變成如下的小於等於表示式:A+ε<=B,

這裡ε是一個小的正數,它的值依賴於模型中A小於B多少才算不等。

下面給出以上三類操作符的優先順序:

高 #not#   ﹣(取反)

      ^

    ﹡ /

  ﹢﹣

#eq#  #ne#  #gt#  #ge#  #lt#  #le#

#and#  #or#

低  <=  =  >=

    4.2 數學函式

LINGO提供了大量的標準數學函式:

@abs(x)             返回x的絕對值

@sin(x)             返回x的正弦值,x採用弧度制

@cos(x)             返回x的餘弦值

@tan(x)             返回x的正切值

@exp(x)             返回常數e的x次方

@log(x)             返回x的自然對數

@lgm(x)             返回x的gamma函式的自然對數

@sign(x)            如果x<0返回-1;否則,返回1

@floor(x)           返回x的整數部分。當x>=0時,返回不超過x的最大整數;當x<0時,返回不低於x的最大整數。

@smax(x1,x2,…,xn)  返回x1,x2,…,xn中的最大值

@smin(x1,x2,…,xn)  返回x1,x2,…,xn中的最小值

    例4.3 給定一個直角三角形,求包含該三角形的最小正方形。

    解:如圖所示。

 

求最小的正方形就相當於求如下的最優化問題:

 

LINGO程式碼如下:

model:

sets:

  object/1..3/: f;

endsets

data:

  a, b = 3, 4; !兩個直角邊長,修改很方便;

enddata

  f(1) = a * @sin(x);

  f(2) = b * @cos(x);

  f(3) = a * @cos(x) + b * @sin(x);

  min = @smax(f(1),f(2),f(3));

  @bnd(0,x,1.57);

end

    在上面的程式碼中用到了函式@bnd,詳情請見4.5節。

4.3 金融函式

目前LINGO提供了兩個金融函式。

1.@fpa(I,n)

返回如下情形的淨現值:單位時段利率為I,連續n個時段支付,每個時段支付單位費用。若每個時段支付x單位的費用,則淨現值可用x乘以@fpa(I,n)算得。@fpa的計算公式為

 。

淨現值就是在一定時期內為了獲得一定收益在該時期初所支付的實際費用。

例4.4 貸款買房問題  貸款金額50000元,貸款年利率5.31%,採取分期付款方式(每年年末還固定金額,直至還清)。問擬貸款10年,每年需償還多少元?

LINGO程式碼如下:

50000 = x * @fpa(.0531,10);

答案是x=6573.069元。

2.@fpl(I,n)

返回如下情形的淨現值:單位時段利率為I,第n個時段支付單位費用。@fpl(I,n)的計算公式為

 。

細心的讀者可以發現這兩個函式間的關係:

 

    4.4 概率函式

1.@pbn(p,n,x)

二項分佈的累積分佈函式。當n和(或)x不是整數時,用線性插值法進行計算。

2.@pcx(n,x)

自由度為n的χ2分佈的累積分佈函式。

3.@peb(a,x)

當到達負荷為a,服務系統有x個伺服器且允許無窮排隊時的Erlang繁忙概率。

4.@pel(a,x)

當到達負荷為a,服務系統有x個伺服器且不允許排隊時的Erlang繁忙概率。

5.@pfd(n,d,x)

自由度為n和d的F分佈的累積分佈函式。

6.@pfs(a,x,c)

當負荷上限為a,顧客數為c,平行伺服器數量為x時,有限源的Poisson服務系統的等待或返修顧客數的期望值。a是顧客數乘以平均服務時間,再除以平均返修時間。當c和(或)x不是整數時,採用線性插值進行計算。

7.@phg(pop,g,n,x)

超幾何(Hypergeometric)分佈的累積分佈函式。pop表示產品總數,g是正品數。從所有產品中任意取出n(n≤pop)件。pop,g,n和x都可以是非整數,這時採用線性插值進行計算。

8.@ppl(a,x)

Poisson分佈的線性損失函式,即返回max(0,z-x)的期望值,其中隨機變數z服從均值為a的Poisson分佈。

9.@pps(a,x)

均值為a的Poisson分佈的累積分佈函式。當x不是整數時,採用線性插值進行計算。

10.@psl(x)

單位正態線性損失函式,即返回max(0,z-x)的期望值,其中隨機變數z服從標準正態分佈。

11.@psn(x)

標準正態分佈的累積分佈函式。

12.@ptd(n,x)

自由度為n的t分佈的累積分佈函式。

13.@qrand(seed)

產生服從(0,1)區間的擬隨機數。@qrand只允許在模型的資料部分使用,它將用擬隨機數填滿集屬性。通常,宣告一個m×n的二維表,m表示執行實驗 的次數,n表示每次實驗所需的隨機數的個數。在行內,隨機數是獨立分佈的;在行間,隨機數是非常均勻的。這些隨機數是用“分層取樣”的方法產生的。

例4.5

model:

data:

  M=4; N=2; seed=1234567;

enddata

sets:

  rows/1..M/;

  cols/1..N/;

  table(rows,cols): x;

endsets

data:

 
[email protected](seed
);

enddata

end

如果沒有為函式指定種子,那麼LINGO將用系統時間構造種子。

14.@rand(seed)

返回0和1間的偽隨機數,依賴於指定的種子。典型用法是U(I+1)[email protected](U(I))。注意如果seed不變,那麼產生的隨機數也不變。

例4.6 利用@rand產生15個標準正態分佈的隨機數和自由度為2的t分佈的隨機數。

model:

!產生一列正態分佈和t分佈的隨機數;

sets:

  series/1..15/: u, znorm, zt;

endsets

   !第一個均勻分佈隨機數是任意的;

  u( 1) = @rand( .1234);

   !產生其餘的均勻分佈的隨機數;

  @for(series( I)| I #GT# 1:

    u( I) = @rand( u( I - 1))

  );

 

  @for( series( I):

    !正態分佈隨機數;

    @psn( znorm( I)) = u( I);

    !和自由度為2的t分佈隨機數;

    @ptd( 2, zt( I)) = u( I);

    !ZNORM 和 ZT 可以是負數;

    @free( znorm( I)); @free( zt( I));

  );

end

4.5 變數界定函式

變數界定函式實現對變數取值範圍的附加限制,共4種:

@bin(x)        限制x為0或1

@bnd(L,x,U)    限制L≤x≤U

@free(x)       取消對變數x的預設下界為0的限制,即x可以取任意實數

@gin(x)        限制x為整數

在預設情況下,LINGO規定變數是非負的,也就是說下界為0,上界為+∞。@free取消了預設的下界為0的限制,使變數也可以取負值。@bnd用於設定一個變數的上下界,它也可以取消預設下界為0的約束。

4.6 集操作函式

LINGO提供了幾個函式幫助處理集。

1.@in(set_name,primitive_index_1 [,primitive_index_2,…])

如果元素在指定集中,返回1;否則返回0。

例4.7 全集為I,B是I的一個子集,C是B的補集。

sets:

  I/x1..x4/;

  B(I)/x2/;

  C(I)|#not#@in(B,&1):;

endsets

2.@index([set_name,] primitive_set_element)

該函式返回在集set_name中原始整合員primitive_set_element的索引。如果set_name被忽略,那麼LINGO將返回與primitive_set_element匹配的第一個原始整合員的索引。如果找不到,則產生一個錯誤。

    例4.8 如何確定整合員(B,Y)屬於派生集S3。

sets:

  S1/A B C/;

  S2/X Y Z/;

  S3(S1,S2)/A X, A Z, B Y, C X/;

endsets

[email protected](S3,@index(S1,B),@index(S2,Y));

看下面的例子,表明有時為@index指定集是必要的。

例4.9

sets:

  girls/debble,sue,alice/;

  boys/bob,joe,sue,fred/;

endsets

[email protected](sue);

[email protected](boys,sue);

I1的值是2,I2的值是3。我們建議在使用@index函式時最好指定集。

3.@wrap(index,limit)

該函式返回j=index-k*limit,其中k是一個整數,取適當值保證j落在區間[1,limit]內。該函式相當於index模limit再加1。該函式在迴圈、多階段計劃編制中特別有用。

4.@size(set_name)

該函式返回集set_name的成員個數。在模型中明確給出集大小時最好使用該函式。它的使用使模型更加資料中立,集大小改變時也更易維護。

    4.7 集迴圈函式

集迴圈函式遍歷整個集進行操作。其語法為

@function(setname[(set_index_list)[|conditional_qualifier]]:

expression_list);

@function相應於下面羅列的四個集迴圈函式之一;setname是要遍歷的集;set_ index_list是集索引列表;conditional_qualifier是用來限制集迴圈函式的範圍,當集迴圈函式遍歷集的每個成員時, LINGO都要對conditional_qualifier進行評價,若結果為真,則對該成員執行@function操作,否則跳過,繼續執行下一次循 環。expression_list是被應用到每個整合員的表示式列表,當用的是@for函式時,expression_list可以包含多個表示式,其 間用逗號隔開。這些表示式將被作為約束加到模型中。當使用其餘的三個集迴圈函式時,expression_list只能有一個表示式。如果省略 set_index_list,那麼在expression_list中引用的所有屬性的型別都是setname集。

1.@for

該函式用來產生對整合員的約束。基於建模語言的標量需要顯式輸入每個約束,不過@for函式允許只輸入一個約束,然後LINGO自動產生每個整合員的約束。

例4.10 產生序列{1,4,9,16,25}

model:

sets:

  number/1..5/:x;

endsets

  @for(number(I): x(I)=I^2);

end

2.@sum

該函式返回遍歷指定的整合員的一個表示式的和。

例4.11 求向量[5,1,3,4,6,10]前5個數的和。

model:

data:

  N=6;

enddata

sets:

  number/1..N/:x;

endsets

data:

  x = 5 1 3 4 6 10;

enddata

  [email protected](number(I) | I #le# 5: x);

end

3.@min和@max

返回指定的整合員的一個表示式的最小值或最大值。

例4.12 求向量[5,1,3,4,6,10]前5個數的最小值,後3個數的最大值。

model:

data:

  N=6;

enddata

sets:

  number/1..N/:x;

endsets

data:

  x = 5 1 3 4 6 10;

enddata

  [email protected](number(I) | I #le# 5: x);

  [email protected](number(I) | I #ge# N-2: x);

end

    下面看一個稍微複雜一點兒的例子。

例4.13 職員時序安排模型  一項工作一週7天都需要有人(比如護士工作),每天(週一至週日)所需的最少職員數為20、16、13、16、19、14和12,並要求每個職員一週連續工作5天,試求每週所需最少職員數,並給出安排。注意這裡我們考慮穩定後的情況。

model:

sets:

  days/mon..sun/: required,start;

endsets

data:

  !每天所需的最少職員數;

  required = 20 16 13 16 19 14 12;

enddata

!最小化每週所需職員數;

  [email protected](days: start);

  @for(days(J):

    @sum(days(I) | I #le# 5:

      start(@wrap(J+I+2,7))) >= required(J));

end

計算的部分結果為

Global optimal solution found at iteration:             0

  Objective value:                                 22.00000

 

                       Variable           Value        Reduced Cost

                 REQUIRED( MON)        20.00000            0.000000

                 REQUIRED( TUE)        16.00000            0.000000

                 REQUIRED( WED)        13.00000            0.000000

                 REQUIRED( THU)        16.00000            0.000000

                 REQUIRED( FRI)        19.00000            0.000000

                 REQUIRED( SAT)        14.00000            0.000000

                 REQUIRED( SUN)        12.00000            0.000000

                    START( MON)        8.000000            0.000000

                    START( TUE)        2.000000            0.000000

                    START( WED)        0.000000           0.3333333

                    START( THU)        6.000000            0.000000

                    START( FRI)        3.000000            0.000000

                    START( SAT)        3.000000            0.000000

                    START( SUN)        0.000000            0.000000

從而解決方案是:每週最少需要22個職員,週一安排8人,週二安排2人,週三無需安排人,週四安排6人,週五和週六都安排3人,週日無需安排人。

    4.8 輸入和輸出函式

輸入和輸出函式可以把模型和外部資料比如文字檔案、資料庫和電子表格等連線起來。

1.@file函式

    該函式用從外部檔案中輸入資料,可以放在模型中任何地方。該函式的語法格式為@file(’filename’)。這裡filename是檔名,可以採 用相對路徑和絕對路徑兩種表示方式。@file函式對同一檔案的兩種表示方式的處理和對兩個不同的檔案處理是一樣的,這一點必須注意。

例4.14 以例1.2來講解@file函式的用法。

注意到在例1.2的編碼中有兩處涉及到資料。第一個地方是集部分的6個warehouses整合員和8個vendors整合員;第二個地方是資料部分的capacity,demand和cost資料。

為了使資料和我們的模型完全分開,我們把它們移到外部的文字檔案中。修改模型程式碼以便於用@file函式把資料從文字檔案中拖到模型中來。修改後(修改處程式碼黑體加粗)的模型程式碼如下:

model:

!6發點8收點運輸問題;

sets:

  warehouses/ @file('1_2.txt') /: capacity;

  vendors/ @file('1_2.txt') /: demand;

  links(warehouses,vendors): cost, volume;

endsets

!目標函式;

  [email protected](links: cost*volume);

!需求約束;

  @for(vendors(J):

    @sum(warehouses(I): volume(I,J))=demand(J));

!產量約束;

  @for(warehouses(I):

    @sum(vendors(J): volume(I,J))<=capacity(I));

 

!這裡是資料;

data:

  capacity = @file('1_2.txt') ;

  demand = @file('1_2.txt') ;

  cost = @file('1_2.txt') ;

enddata

end

模型的所有資料來自於1_2.txt檔案。其內容如下:

!warehouses成員;

WH1 WH2 WH3 WH4 WH5 WH6 ~

!vendors成員;

V1 V2 V3 V4 V5 V6 V7 V8 ~

!產量;

60 55 51 43 41 52 ~

!銷量;

35 37 22 32 41 32 43 38 ~

!單位運輸費用矩陣;

6 2 6 7 4 2 5 9

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

把記錄結束標記(~)之間的資料檔案部分稱為記錄。如果資料檔案中沒有記錄結束標記,那麼整個檔案被看作單個記錄。注意到除了記錄結束標記外,模型的文字和資料同它們直接放在模型裡是一樣的。

我們來看一下在資料檔案中的記錄結束標記連同模型中@file函式呼叫是如何工作的。當在模型中第一次呼叫@file函式時,LINGO開啟資料檔案,然 後讀取第一個記錄;第二次呼叫@file函式時,LINGO讀取第二個記錄等等。檔案的最後一條記錄可以沒有記錄結束標記,當遇到檔案結束標記時, LINGO會讀取最後一條記錄,然後關閉檔案。如果最後一條記錄也有記錄結束標記,那麼直到LINGO求解完當前模型後才關閉該檔案。如果多個檔案保持打 開狀態,可能就會導致一些問題,因為這會使同時開啟的檔案總數超過允許同時開啟檔案的上限16。

當使用@file函式時,可把記錄的內容(除了一些記錄結束標記外)看作是替代模型中@file(’filename’)位置的文字。這也就是說,一條記 錄可以是宣告的一部分,整個宣告,或一系列宣告。在資料檔案中註釋被忽略。注意在LINGO中不允許巢狀呼叫@file函式。

2.@text函式

該函式被用在資料部分用來把解輸出至文字檔案中。它可以輸出整合員和集屬性值。其語法為

@text([’filename’])

這裡filename是檔名,可以採用相對路徑和絕對路徑兩種表示方式。如果忽略filename,那麼資料就被輸出到標準輸出裝置(大多數情形都是屏 幕)。@text函式僅能出現在模型資料部分的一條語句的左邊,右邊是集名(用來輸出該集的所有成員名)或集屬性名(用來輸出該集屬性的值)。

    我們把用介面函式產生輸出的資料宣告稱為輸出操作。輸出操作僅當求解器求解完模型後才執行,執行次序取決於其在模型中出現的先後。

    例4.15 借用例4.12,說明@text的用法。

model:

sets:

  days/mon..sun/: required,start;

endsets

data:

  !每天所需的最少職員數;

  required = 20 16 13 16 19 14 12;

  @text('d:/out.txt')=days '至少需要的職員數為' start;

enddata

!最小化每週所需職員數;

  [email protected](days: start);

  @for(days(J):

    @sum(days(I) | I #le# 5:

      start(@wrap(J+I+2,7))) >= required(J));

end

3.@ole函式

@OLE是從EXCEL中引入或輸出資料的介面函式,它是基於傳輸的OLE技術。OLE傳輸直接在記憶體中傳輸資料,並不藉助於中間檔案。當使用@OLE 時,LINGO先裝載EXCEL,再通知EXCEL裝載指定的電子資料表,最後從電子資料表中獲得Ranges。為了使用OLE函式,必須有EXCEL5 及其以上版本。OLE函式可在資料部分和初始部分引入資料。

@OLE可以同時讀整合員和集屬性,整合員最好用文字格式,集屬性最好用數值格式。原始集每個整合員需要一個單元(cell),而對於n元的派生集每個集 成員需要n個單元,這裡第一行的n個單元對應派生集的第一個整合員,第二行的n個單元對應派生集的第二個整合員,依此類推。

@OLE只能讀一維或二維的Ranges(在單個的EXCEL工作表(sheet)中),但不能讀間斷的或三維的Ranges。Ranges是自左而右、自上而下來讀。

例4.16

sets:

   PRODUCT;  !產品;

   MACHINE;  !機器;

   WEEK;     !周;

   ALLOWED(PRODUCT,MACHINE,WEEK):x,y;   !允許組合及屬性;

endsets

data:

   rate=0.01;

   PRODUCT,MACHINE,WEEK,ALLOWED,x,[email protected]('D:/IMPORT.XLS');

   @OLE('D:/IMPORT.XLS')=rate;

enddata

代替在程式碼文字的資料部分顯式輸入形式,我們把相關資料全部放在如下電子資料表中來輸入。下面是D:/IMPORT.XLS的圖表。

除了輸入資料之外,我們也必須定義Ranges名:PRODUCT,MACHINE,WEEK,ALLOWED,x,y. 明確的,我們需要定義如下的Ranges名:

Name        Range

PRODUCT       B3:B4

MACHINE       C3:C4

WEEK        D3:D5

ALLOWED       B8:D10

X         F8:F10

Y         G8:G10

rate      C13

為了在EXCEL中定義Ranges名:

① 按滑鼠左鍵拖曳選擇Range,

② 釋放滑鼠按鈕,

③ 選擇“插入|名稱|定義”,

④ 輸入希望的名字,

⑤ 點選“確定”按鈕。

我們在模型的資料部分用如下程式碼從EXECL中引入資料:

PRODUCT,MACHINE,WEEK,ALLOWED,x,[email protected]('D:/IMPORT.XLS');

@OLE('D:/IMPORT.XLS')=rate;

等價的描述為

PRODUCT,MACHINE,WEEK,ALLOWED,x,y

[email protected]('D:IMPORT.XLS', PRODUCT,MACHINE,WEEK,ALLOWED,x,y);

@OLE('D:/IMPORT.XLS',rate)=rate;

這一等價描述使得變數名和Ranges不同亦可。

4.@ranged(variable_or_row_name)

為了保持最優基不變,變數的費用係數或約束行的右端項允許減少的量。

5.@rangeu(variable_or_row_name)

為了保持最優基不變,變數的費用係數或約束行的右端項允許增加的量。

6.@status()

返回LINGO求解模型結束後的狀態:

0   Global Optimum(全域性最優)

1   Infeasible(不可行)

2   Unbounded(無界)

3   Undetermined(不確定)

4   Feasible(可行)

5   Infeasible or Unbounded(通常需要關閉“預處理”選項後重新求解模型,以確定模型究竟是不可行還是無界)

6   Local Optimum(區域性最優)

7   Locally Infeasible(區域性不可行,儘管可行解可能存在,但是LINGO並沒有找到一個)

8   Cutoff(目標函式的截斷值被達到)

9   Numeric Error(求解器因在某約束中遇到無定義的算術運算而停止)

    通常,如果返回值不是0、4或6時,那麼解將不可信,幾乎不能用。該函式僅被用在模型的資料部分來輸出資料。

    例4.17

model:

[email protected](x);

data:

  @text()[email protected]();

enddata

end

部分計算結果為:

  Local optimal solution found at iteration:             33

  Objective value:                                -1.000000

                       Variable           Value        Reduced Cost

                              X        4.712388            0.000000

結果中的6就是@status()返回的結果,表明最終解是區域性最優的。

    7.@dual

    @dual(variable_or_row_name)返回變數的判別數(檢驗數)或約束行的對偶(影子)價格(dual prices)。

4.9 輔助函式



1.@if(logical_condition,true_result,false_result)



@if函式將評價一個邏輯表示式logical_condition,如果為真,返回true_ result,否則返回false_result。



    例4.18 求解最優化問題



 



其LINGO程式碼如下:



model:



  min=fx+fy;



  [email protected](x #gt# 0, 100,0)+2*x;



  [email protected](y #gt# 0,60,0)+3*y;



  x+y>=30;



end



    2.@warn(’text’,logical_condition)



如果邏輯條件logical_condition為真,則產生一個內容為’text’的資訊框。



例4.19 示例。



model:



  x=1;



  @warn('x是正數',x #gt# 0);



end



§5  LINGO WINDOWS命令



5.1 檔案選單(File Menu)



1. 新建(New)



從檔案選單中選用“新建”命令、單擊“新建”按鈕或直接按F2鍵可以建立一個新的“Model”視窗。在這個新的“Model”視窗中能夠輸入所要求解的模型。



2. 開啟(Open)



    從檔案選單中選用“開啟”命令、單擊“開啟”按鈕或直接按F3鍵可以開啟一個已經存在的文字檔案。這個檔案可能是一個Model檔案。



3. 儲存(Save)



    從檔案選單中選用“儲存”命令、單擊“儲存”按鈕或直接按F4鍵用來儲存當前活動視窗(最前臺的視窗)中的模型結果、命令序列等儲存為檔案。



4. 另存為...(Save As...)



    從檔案選單中選用“另存為...”命令或按F5鍵可以將當前活動視窗中的內容儲存為文字檔案,其檔名為你在“另存為...”對話方塊中輸入的檔名。利用這種方法你可以將任何視窗的內容如模型、求解結果或命令儲存為檔案。



5. 關閉(Close)



在檔案選單中選用“關閉”(Close)命令或按F6鍵將關閉當前活動視窗。如果這個視窗是新建視窗或已經改變了當前檔案的內容,LINGO系統將會提示是否想要儲存改變後的內容。



6. 列印(Print)



    在檔案選單中選用“列印” (Print)命令、單擊“列印”按鈕或直接按F7鍵可以將當前活動視窗中的內容傳送到印表機。



7. 列印設定(Print Setup...)



    在檔案選單中選用“列印設定...”命令或直接按F8鍵可以將檔案輸出到指定的印表機。



8. 列印預覽(Print Preview)



    在檔案選單中選用“列印預覽...”命令或直接按Shift+F8鍵可以進行列印預覽。



9. 輸出到日誌檔案(Log Output...)



    從檔案選單中選用“Log Output...”命令或按F9鍵開啟一個對話方塊,用於生成一個日誌檔案,它儲存接下來在“命令視窗”中輸入的所有命令。



10.提交LINGO命令指令碼檔案(Take Commands...)



    從檔案選單中選用“Take Commands...”命令或直接按F11鍵就可以將LINGO命令指令碼(command script)檔案提交給系統程序來執行。



11.引入LINGO檔案(Import Lingo File...)



從檔案選單中選用“Import Lingo File...”命令或直接按F12鍵可以開啟一個LINGO格式模型的檔案,然後LINGO系統會盡可能把模型轉化為LINGO語法允許的程式。



12.退出(Exit)



從檔案選單中選用“Exit”命令或直接按F10鍵可以退出LINGO系統。



5.2 編輯選單(Edit Menu)



1. 恢復(Undo)



從編輯選單中選用“恢復”(Undo)命令或按Ctrl+Z組合鍵,將撤銷上次操作、恢復至其前的狀態。



2. 剪下(Cut)



從編輯選單中選用“剪下”(Cut)命令或按Ctrl+X組合鍵可以將當前選中的內容剪下至剪貼簿中。



3. 複製(Copy)



從編輯選單中選用“複製”(Copy)命令、單擊“複製”按鈕或按Ctrl+C組合鍵可以將當前選中的內容複製到剪貼簿中。



4. 貼上(Paste)



從編輯選單中選用“貼上”(Paste)命令、單擊“貼上”按鈕或按Ctrl+V組合鍵可以將貼上板中的當前內容複製到當前插入點的位置。



5. 貼上特定..(Paste Special。。)



與上面的命令不同,它可以用於剪貼簿中的內容不是文字的情形。



6. 全選(Select All)



    從編輯選單中選用“Select All”命令或按Ctrl+A組合鍵可選定當前視窗中的所有內容。



7. 匹配小括號(Match Parenthesis)



    從編輯選單中選用“Match Parenthesis”命令、單擊“Match Parenthesis”按鈕或按Ctrl+P組合鍵可以為當前選中的開括號查詢匹配的閉括號。



8. 貼上函式(Paste Function)



從編輯選單中選用“Paste Function”命令可以將LINGO的內部函式貼上到當前插入點。



5.3 LINGO選單



1. 求解模型(Slove)



    從LINGO選單中選用“求解”命令、單擊“Slove”按鈕或按Ctrl+S組合鍵可以將當前模型送入記憶體求解。



2. 求解結果...(Solution...)



    從LINGO選單中選用“Solution...”命令、單擊“Solution...”按鈕或直接按Ctrl+O組合鍵可以開啟求解結果的對話方塊。這裡可以指定檢視當前記憶體中求解結果的那些內容。



3. 檢視...(Look...)



從LINGO選單中選用“Look...”命令或直接按Ctrl+L組合鍵可以檢視全部的或選中的模型文字內容。



4. 靈敏性分析(Range,Ctrl+R)



用該命令產生當前模型的靈敏性分析報告:研究當目標函式的費用係數和約束右端項在什麼範圍(此時假定其它係數不變)時,最優基保持不變。靈敏性分析是在求 解模型時作出的,因此在求解模型時靈敏性分析是啟用狀態,但是預設是不啟用的。為了啟用靈敏性分析,執行LINGO|Options…,選擇 General Solver Tab, 在Dual Computations列表框中,選擇Prices and Ranges選項。靈敏性分析耗費相當多的求解時間,因此當速度很關鍵時,就沒有必要啟用它。



下面我們看一個簡單的具體例子。



例5.1某傢俱公司製造書桌、餐桌和椅子,所用的資源有三種:木料、木工和漆工。生產資料如下表所示:



  每個書桌 每個餐桌 每個椅子 現有資源總數



木料 8單位 6單位 1單位 48單位



漆工 4單位 2單位 1.5單位 20單位



木工 2單位 1.5單位 0.5單位 8單位



成品單價 60單位 30單位 20單位 



若要求桌子的生產量不超過5件,如何安排三種產品的生產可使利潤最大?



用DESKS、TABLES和CHAIRS分別表示三種產品的生產量,建立LP模型。



max=60*desks+30*tables+20*chairs;



8*desks+6*tables+chairs<=48;



4*desks+2*tables+1.5*chairs<=20;



2*desks+1.5*tables+.5*chairs<=8;



tables<=5;



求解這個模型,並激活靈敏性分析。這時,檢視報告視窗(Reports Window),可以看到如下結果。



Global optimal solution found at iteration:             3



  Objective value:                                 280.0000



                       Variable           Value        Reduced Cost



                          DESKS        2.000000            0.000000



                         TABLES        0.000000            5.000000



                         CHAIRS        8.000000            0.000000



                            Row    Slack or Surplus      Dual Price



                              1        280.0000            1.000000



                              2        24.00000            0.000000



                              3        0.000000            10.00000



                              4        0.000000            10.00000



                              5        5.000000            0.000000



“Global optimal solution found at iteration: 3”表示3次迭代後得到全域性最優解。 “Objective value:280.0000”表示最優目標值為280。 “Value”給出最優解中各變數的值:造2個書桌(desks), 0個餐桌(tables), 8個椅子(chairs)。所以desks、chairs是基變數(非0),tables是非基變數(0)。



“Slack or Surplus”給出鬆馳變數的值:



第1行鬆馳變數 =280(模型第一行表示目標函式,所以第二行對應第一個約束)



第2行鬆馳變數 =24



第3行鬆馳變數 =0



第4行鬆馳變數 =0



第5行鬆馳變數 =5



“Reduced Cost”列出最優單純形表中判別數所在行的變數的係數,表示當變數有微小變動時, 目標函式的變化率。其中基變數的reduced cost值應為0, 對於非基變數 Xj, 相應的 reduced cost值表示當某個變數Xj 增加一個單位時目標函式減少的量( max型問題)。本例中:變數tables對應的reduced cost值為5,表示當非基變數tables的值從0變為 1時(此時假定其他非基變數保持不變,但為了滿足約束條件,基變數顯然會發生變化),最優的目標函式值 = 280 - 5 = 275。



“DUAL PRICE”(對偶價格)表示當對應約束有微小變動時, 目標函式的變化率。輸出結果中對應於每一個約束有一個對偶價格。若其數值為p, 表示對應約束中不等式右端項若增加1 個單位,目標函式將增加p個單位(max型問題)。顯然,如果在最優解處約束正好取等號(也就是“緊約束”,也稱為有效約束或起作用約束),對偶價格值才 可能不是0。本例中:第3、4行是緊約束,對應的對偶價格值為10,表示當緊約束



3) 4 DESKS + 2 TABLES + 1.5 CHAIRS <= 20



變為 3) 4 DESKS + 2 TABLES + 1.5 CHAIRS <= 21



時,目標函式值 = 280 +10 = 290。對第4行也類似。



對於非緊約束(如本例中第2、5行是非緊約束),DUAL PRICE 的值為0, 表示對應約束中不等式右端項的微小擾動不影響目標函式。有時, 通過分析DUAL PRICE, 也可對產生不可行問題的原因有所瞭解。



靈敏度分析的結果是



Ranges in which the basis is unchanged:



                         Objective Coefficient Ranges



                           Current        Allowable        Allowable



         Variable      Coefficient         Increase         Decrease



             DESKS         60.00000              0.0              0.0



            TABLES         30.00000              0.0              0.0



            CHAIRS         20.00000              0.0              0.0



                                     Righthand Side Ranges



                Row          Current      Allowable       Allowable



                                  RHS        Increase        Decrease



                  2         48.00000              0.0              0.0



                  3         20.00000              0.0              0.0



                  4         8.000000              0.0              0.0



                  5         5.000000              0.0              0.0



目標函式中DESKS變數原來的費用係數為60,允許增加(Allowable Increase)=4、允許減少