戰(zhàn):從基礎(chǔ)語(yǔ)法到排產(chǎn)模型調(diào)試全攻略)
簡(jiǎn)介L(zhǎng)INGO是一款專業(yè)求解線性、非線性及整數(shù)規(guī)劃問(wèn)題的數(shù)學(xué)建模軟件廣泛服務(wù)于工程管理、經(jīng)濟(jì)分析和運(yùn)籌決策等場(chǎng)景。這份資源包面向需要快速搭建優(yōu)化計(jì)算環(huán)境的工程師、在校學(xué)生及數(shù)學(xué)建模參賽者尤其適合已經(jīng)了解LINGO基本語(yǔ)法、希望直接上手練習(xí)的進(jìn)階用戶。壓縮包為RAR格式整體約15.9MB內(nèi)含LINGO 11版本核心組件及相關(guān)文本說(shuō)明用戶解壓后即可開(kāi)始定義變量、目標(biāo)函數(shù)和約束條件。軟件內(nèi)置高效求解器能處理大規(guī)?;旌险麛?shù)規(guī)劃問(wèn)題并支持敏感性分析、多模型比較與報(bào)告生成結(jié)合物流調(diào)度、投資組合、能源分配等典型案例可顯著減少建模入門所花費(fèi)的配置時(shí)間。該資源已有650人瀏覽學(xué)習(xí)從基礎(chǔ)框架搭建到實(shí)際求解演示均便于參考適合配套教材或自學(xué)課程反復(fù)使用。1. 搜索LINGO破解版的人十個(gè)里有八個(gè)卡在建模上LINGO破解版是很多人優(yōu)化入門時(shí)的第一反應(yīng)但絕大多數(shù)下載來(lái)的安裝包要么帶著捆綁要么注冊(cè)信息早就失效真正能讓你跑通問(wèn)題的不是那個(gè)破解補(bǔ)丁而是LINGO這套建模語(yǔ)法和排錯(cuò)思路。LINGO本質(zhì)上是一個(gè)集成了建模語(yǔ)言和求解器的優(yōu)化工具專門處理線性、非線性、整數(shù)規(guī)劃這類問(wèn)題適合運(yùn)籌學(xué)課程設(shè)計(jì)、企業(yè)排產(chǎn)、物流配送方案驗(yàn)證的場(chǎng)景。與其在破解版上反復(fù)翻車不如先把模型骨架搭對(duì)——這篇文章會(huì)帶你從語(yǔ)法、實(shí)例到調(diào)試完整走一遍并說(shuō)清楚哪些地方最容易掉坑。2. LINGO建模語(yǔ)法先把模型骨架搭對(duì)再談求解參數(shù)2.1 MODEL / SETS / DATA集合是LINGO的第一公民LINGO跟C語(yǔ)言、Python的思維不一樣。你不需要寫循環(huán)去遍歷數(shù)據(jù)而是先聲明集合再在集合上做運(yùn)算。一個(gè)最基礎(chǔ)的模型分三段MODEL開(kāi)頭、SETS段聲明集合、DATA段賦值最后END收尾。MODEL: SETS: WH /W1..W6/: CAPACITY; SELL /S1..S8/: DEMAND; ENDSETS DATA: CAPACITY 60 55 51 43 41 52; DEMAND 35 37 22 32 41 32 43 38; ENDDATA END這里WH是倉(cāng)庫(kù)集合W1到W6六個(gè)元素CAPACITY是跟這個(gè)集合綁定的屬性SELL是銷地集合DEMAND是對(duì)應(yīng)的需求量。LINGO里所有變量和常量都必須附著在集合上單獨(dú)站在外面的變量雖然允許但在復(fù)雜模型里會(huì)亂成一團(tuán)。我一般會(huì)建議新手先把這個(gè)骨架寫出來(lái)哪怕數(shù)據(jù)不全先用隨機(jī)值占位。因?yàn)榧蠈懬宄蠛竺娴哪繕?biāo)函數(shù)和約束條件只需要照著集合循環(huán)邏輯會(huì)清晰很多。2.2 派生集合和循環(huán)函數(shù)把求和與重復(fù)約束寫進(jìn)聲明里實(shí)際優(yōu)化問(wèn)題很少只有一個(gè)維度的集合。運(yùn)輸問(wèn)題、生產(chǎn)計(jì)劃問(wèn)題天然是兩維的這時(shí)候需要派生集合。派生集合的意思是由兩個(gè)基礎(chǔ)集合聯(lián)合生成一個(gè)新集合屬性定義在聯(lián)合集合上。MODEL: SETS: PLANT /P1..P3/: PROD; WAREHOUSE /W1..W4/: STORE; LINK(PLANT, WAREHOUSE): COST, VOLUME; ENDSETS DATA: PROD 30 20 25; STORE 15 20 25 15; COST 5 3 8 6 4 7 2 9 6 5 4 7; ENDDATA MIN SUM(LINK(I,J): COST(I,J) * VOLUME(I,J)); FOR(PLANT(I): SUM(WAREHOUSE(J): VOLUME(I,J)) PROD(I) ); FOR(WAREHOUSE(J): SUM(PLANT(I): VOLUME(I,J)) STORE(J) ); ENDSUM和FOR是LINGO最常用的兩個(gè)集合循環(huán)函數(shù)。SUM(LINK(I,J): ...) 表示對(duì)LINK集合的所有元素求和I和J是循環(huán)下標(biāo)FOR(PLANT(I): ...) 表示對(duì)每個(gè)工廠都生成一條約束。這里沒(méi)有寫VOLUME的上限LINGO默認(rèn)變量是非負(fù)的所以不需要額外聲明。這段代碼解決的是運(yùn)輸問(wèn)題三個(gè)工廠往四個(gè)倉(cāng)庫(kù)送貨每噸運(yùn)費(fèi)COST求運(yùn)費(fèi)最低的調(diào)運(yùn)方案。第一條約束限制工廠出貨量不能超過(guò)產(chǎn)量第二條約束保證每個(gè)倉(cāng)庫(kù)的需求量被滿足。2.3 變量類型聲明BIN / GIN / FREE 到底改了什么LINGO默認(rèn)所有變量都是連續(xù)非負(fù)變量但現(xiàn)實(shí)中很多決策變量不能取小數(shù)。比如產(chǎn)線上生產(chǎn)多少件產(chǎn)品只能是整數(shù)某個(gè)倉(cāng)庫(kù)建不建只能取0或1。LINGO提供了三個(gè)最常用的變量限定函數(shù)GIN表示整數(shù)變量BIN表示0-1變量FREE表示取消變量非負(fù)限制。MODEL: SETS: PROJECT /A B C D/: INVEST, RETURN; CHOOSE(PROJECT): X; ENDSETS DATA: INVEST 60 50 40 30; RETURN 12 10 8 6; BUDGET 100; ENDDATA MAX SUM(PROJECT(I): RETURN(I) * X(I)); SUM(PROJECT(I): INVEST(I) * X(I)) BUDGET; FOR(PROJECT(I): BIN(X(I))); END這是一個(gè)經(jīng)典的項(xiàng)目選擇問(wèn)題。X(I)取1表示選擇這個(gè)項(xiàng)目取0表示不選。BIN(X(I)) 把X限定成0-1變量這跟普通整數(shù)變量有本質(zhì)區(qū)別——0-1變量對(duì)應(yīng)的是“是/否”決策整數(shù)變量對(duì)應(yīng)的是“多少個(gè)”決策。注意BIN和GIN不能混用一個(gè)變量要么是0-1要么是一般整數(shù)。這里有一個(gè)新手常犯的錯(cuò)誤以為在目標(biāo)函數(shù)里把X聲明成BIN就夠了但FOR循環(huán)是必須的。LINGO只對(duì)出現(xiàn)在FOR里的集合元素逐個(gè)執(zhí)行限定不寫FOR約束就不生效求解結(jié)果可能完全是小數(shù)。3. 紙上談兵不解決問(wèn)題一個(gè)排產(chǎn)模型從寫代碼到出報(bào)告3.1 場(chǎng)景需求與數(shù)據(jù)某工廠有兩條產(chǎn)線要生產(chǎn)三種產(chǎn)品每件產(chǎn)品在不同產(chǎn)線上的加工工時(shí)不同產(chǎn)線每月可用工時(shí)有限產(chǎn)品有市場(chǎng)需求上限目標(biāo)是最大化總毛利。這個(gè)問(wèn)題看起來(lái)簡(jiǎn)單但把工時(shí)、需求、產(chǎn)品分配組合起來(lái)手工算就會(huì)亂。這里給出完整數(shù)據(jù)結(jié)構(gòu)產(chǎn)品產(chǎn)線1工時(shí)/件產(chǎn)線2工時(shí)/件單件毛利市場(chǎng)需求上限P12.01.530100P21.82.24080P31.00.825120產(chǎn)線1每月可用工時(shí)260小時(shí)產(chǎn)線2每月可用工時(shí)240小時(shí)。決策變量是每個(gè)產(chǎn)品在各產(chǎn)線的產(chǎn)量必須是非負(fù)整數(shù)。這個(gè)模型的關(guān)鍵是同一產(chǎn)品可以在兩條產(chǎn)線分?jǐn)偵a(chǎn)但總產(chǎn)量不能超過(guò)市場(chǎng)需求每條產(chǎn)線的總工時(shí)消耗不能超過(guò)可用工時(shí)。3.2 完整LINGO代碼與執(zhí)行說(shuō)明MODEL: SETS: PRODUCT /P1, P2, P3/: DEMAND, PROFIT; LINE /L1, L2/: HOURS_AVAIL; PLAN(PRODUCT, LINE): TIME, VOLUME; ENDSETS DATA: PROFIT 30 40 25; DEMAND 100 80 120; TIME 2.0 1.5 1.8 2.2 1.0 0.8; HOURS_AVAIL 260 240; ENDDATA MAX SUM(PLAN(I,J): PROFIT(I) * VOLUME(I,J)); FOR(PRODUCT(I): SUM(LINE(J): VOLUME(I,J)) DEMAND(I) ); FOR(LINE(J): SUM(PRODUCT(I): TIME(I,J) * VOLUME(I,J)) HOURS_AVAIL(J) ); FOR(PLAN(I,J): GIN(VOLUME(I,J))); END數(shù)據(jù)段里TIME的寫法需要注意。LINGO按行列順序填充二維數(shù)據(jù)PLAN(PRODUCT, LINE)里面PRODUCT是行、LINE是列所以TIME里第一行是P1在兩條產(chǎn)線的工時(shí)第二行是P2以此類推。寫成一行之后順序錯(cuò)一個(gè)數(shù)字結(jié)果就完全變樣。MAX 那一行是目標(biāo)函數(shù)SUM(PLAN(I,J): ...) 把九種產(chǎn)品—產(chǎn)線組合的毛利全部加起來(lái)。下面兩個(gè)FOR段分別生成市場(chǎng)需求約束和產(chǎn)線工時(shí)約束。最后的GIN保證VOLUME是整數(shù)不會(huì)出現(xiàn)生產(chǎn)0.6件產(chǎn)品這種荒謬結(jié)果。3.3 看報(bào)告、改參數(shù)、定方案求解之后LINGO會(huì)彈出一份Solution Report新手最常看的是Objective Value那一行。但真正做決策時(shí)還需要看另外三列Value是決策變量的最終取值Slack or Surplus是約束的剩余量Dual Price是對(duì)偶價(jià)格。比如產(chǎn)線1的工時(shí)約束如果Slack是0說(shuō)明產(chǎn)線1滿負(fù)荷這時(shí)候想多賺錢就得優(yōu)先給產(chǎn)線1加產(chǎn)能或調(diào)整產(chǎn)品結(jié)構(gòu)。Dual Price如果是正數(shù)表示每增加一個(gè)單位對(duì)應(yīng)資源的產(chǎn)能目標(biāo)函數(shù)能增加多少這是調(diào)參數(shù)時(shí)最有價(jià)值的信息。我自己一般會(huì)先把需求上限調(diào)大再看結(jié)果目的是判斷當(dāng)前瓶頸到底在產(chǎn)線還是市場(chǎng)。如果需求翻一倍但目標(biāo)值幾乎沒(méi)漲說(shuō)明兩條產(chǎn)線都卡死了如果目標(biāo)值跟著漲說(shuō)明市場(chǎng)端還有空間。這一步比盲目改系數(shù)有用得多。4. 第一次跑模型就翻車的避坑清單從安裝到調(diào)試的5個(gè)現(xiàn)實(shí)問(wèn)題4.1 破解版安裝包帶來(lái)的三種麻煩現(xiàn)象從網(wǎng)上找的LINGO安裝包解壓后運(yùn)行時(shí)報(bào)缺少DLL文件或者每次啟動(dòng)都彈出注冊(cè)提示更糟的是電腦開(kāi)始彈廣告。原因所謂破解版大多是重新打包過(guò)的安裝程序除了主程序還夾帶了其他內(nèi)容或者注冊(cè)信息在打包時(shí)就已經(jīng)失效。解決先卸載干凈重點(diǎn)清理注冊(cè)表殘留和殘留目錄然后換用官方試用版或者直接在配置好環(huán)境變量的機(jī)器上安裝教學(xué)版。破解版并不比試用版多解決你的實(shí)質(zhì)問(wèn)題——模型寫不對(duì)裝一百個(gè)破解版也跑不出結(jié)果。4.2 SETS段和數(shù)據(jù)段順序?qū)戝e(cuò)現(xiàn)象模型里約束寫得很完整但一求解就報(bào)錯(cuò)提示某個(gè)屬性未定義或數(shù)據(jù)長(zhǎng)度不匹配。原因LINGO的SECTS段必須在DATA段之前而且數(shù)據(jù)段里每個(gè)屬性的取值個(gè)數(shù)必須跟集合元素個(gè)數(shù)嚴(yán)格相等。少一個(gè)數(shù)、多一個(gè)數(shù)甚至逗號(hào)換成空格后多敲了一個(gè)回車都會(huì)導(dǎo)致解析失敗。解決寫完SETS段先檢查集合元素個(gè)數(shù)再回頭數(shù)DATA里的數(shù)據(jù)個(gè)數(shù)。我習(xí)慣把數(shù)據(jù)排成一行數(shù)字之間用空格分隔這樣一眼能數(shù)清個(gè)數(shù)比多行書(shū)寫更不容易錯(cuò)。4.3 非線性問(wèn)題收斂在局部最優(yōu)解現(xiàn)象同一個(gè)模型用不同初值求解得到的目標(biāo)函數(shù)值每次都不一樣。原因LINGO默認(rèn)的求解器處理非線性問(wèn)題時(shí)可能只找到局部最優(yōu)解。整數(shù)變量帶來(lái)的非凸性也會(huì)加劇這個(gè)問(wèn)題破解版或老版本尤其明顯。解決在LINGO菜單的Options里開(kāi)啟Global Solver。注意開(kāi)啟后求解時(shí)間會(huì)成倍增加需要給求解器足夠的耐心。另一種常見(jiàn)做法是手動(dòng)給變量賦一組合理的初始值這能幫助求解器避開(kāi)明顯不合理的區(qū)域。4.4 OLE取Excel數(shù)據(jù)時(shí)文件被占用現(xiàn)象模型里用OLE讀數(shù)據(jù)運(yùn)行時(shí)報(bào)無(wú)法打開(kāi)文件或者讀出來(lái)的數(shù)據(jù)全是0。原因OLE需要Excel文件保持關(guān)閉狀態(tài)。如果Excel進(jìn)程還駐留在后臺(tái)或者文件被其他程序鎖定LINGO讀取數(shù)據(jù)就會(huì)失敗。解決把數(shù)據(jù)文件單獨(dú)復(fù)制到一個(gè)目錄確保沒(méi)有打開(kāi)著同名的Excel窗口。LINGO工作目錄和Excel文件路徑要一致我一般把LINGO項(xiàng)目目錄和Excel數(shù)據(jù)文件放在同一個(gè)文件夾里然后只寫文件名不寫絕對(duì)路徑。4.5 演示版規(guī)模限制導(dǎo)致求解失敗現(xiàn)象模型在別人電腦上能跑通換到另一臺(tái)機(jī)器上就提示問(wèn)題規(guī)模超出許可限制。原因演示版或教育版對(duì)變量數(shù)、約束數(shù)有上限。模型本身沒(méi)問(wèn)題但規(guī)模超過(guò)當(dāng)前許可允許的邊界求解器直接拒絕工作。解決先縮小模型規(guī)模驗(yàn)證邏輯是否正確比如只保留兩個(gè)產(chǎn)品、一條產(chǎn)線跑一遍。確認(rèn)無(wú)誤后再恢復(fù)完整數(shù)據(jù)到正式授權(quán)的環(huán)境里求解。這個(gè)習(xí)慣能幫你把“模型錯(cuò)誤”和“規(guī)模超限”這兩類問(wèn)題徹底分開(kāi)不至于排錯(cuò)排到一半才發(fā)現(xiàn)是許可問(wèn)題。5. 驗(yàn)證模型比解模型更重要用診斷報(bào)表和靈敏度分析收尾5.1 用不可行性分析找出約束沖突模型求解失敗時(shí)LINGO會(huì)提示Infeasible。很多人的第一反應(yīng)是回去改目標(biāo)函數(shù)這方向錯(cuò)了。不可行意味著約束之間互相矛盾比如某個(gè)需求上限設(shè)定為80但所有產(chǎn)線加起來(lái)的最大產(chǎn)量只有60這組數(shù)字永遠(yuǎn)無(wú)解。LINGO的某些版本提供Debug工具可以定位到是哪個(gè)約束導(dǎo)致的沖突。我拿到不可行模型時(shí)會(huì)先把所有等式約束改成不等式或者把上下限暫時(shí)放寬到非常大然后逐個(gè)恢復(fù)。這種二分排查法比盯著代碼找有效得多。5.2 用Range報(bào)告判斷哪些參數(shù)值得改求解成功后在Reports菜單里選RangeLINGO會(huì)輸出目標(biāo)函數(shù)系數(shù)變化范圍和約束右端項(xiàng)變化范圍。簡(jiǎn)單說(shuō)它告訴你每個(gè)參數(shù)在什么范圍內(nèi)變化當(dāng)前最優(yōu)解保持不變。如果某個(gè)產(chǎn)品毛利的允許增加范圍是無(wú)窮大而某個(gè)產(chǎn)線工時(shí)的影子價(jià)格很高管理者就應(yīng)該優(yōu)先處理產(chǎn)線能力問(wèn)題而不是產(chǎn)品定價(jià)問(wèn)題。對(duì)于排產(chǎn)模型我??吹氖枪r(shí)約束的Dual Price和對(duì)應(yīng)允許增加范圍。允許增加范圍小表示資源約束很緊擴(kuò)產(chǎn)能的邊際收益高范圍大表示當(dāng)前資源相對(duì)充裕擴(kuò)產(chǎn)能的錢可以先省下。5.3 一個(gè)堅(jiān)持了三年的調(diào)試習(xí)慣從那以后我每次寫LINGO模型都強(qiáng)制走一遍固定流程先單獨(dú)驗(yàn)證SETS和DATA段能正常解析再寫目標(biāo)函數(shù)然后逐條添加約束每加一條就求解一次。這樣哪一步出錯(cuò)立刻能定位。模型跑通后再做靈敏度分析最后才調(diào)整數(shù)據(jù)做方案對(duì)比。這套流程看起來(lái)慢實(shí)際上是最快的——跳過(guò)任何一步后面都會(huì)用更折騰的方式來(lái)償還。如果你手頭還沒(méi)有一份可以直接套用的LINGO模型模板建議先把我上面給出的排產(chǎn)和運(yùn)輸模型原樣復(fù)現(xiàn)一遍再改你的業(yè)務(wù)數(shù)據(jù)。模型調(diào)試一旦建立起節(jié)奏你會(huì)覺(jué)得LINGO本身并不難難的是靜下心去拆解問(wèn)題結(jié)構(gòu)。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取