Matlab与GAMS交互
目的:GAMS處理優(yōu)化問題;MATLAB調(diào)用優(yōu)化結(jié)果數(shù)據(jù),進(jìn)行后處理。
原理:gdx格式文件(兩者的交互工具)
主要參考文獻(xiàn):
步驟:(以下主要來(lái)源于GDXMRW官方文檔的附錄部分)
配置GDXMRW
3.1 創(chuàng)建一個(gè)臨時(shí)文件夾用于執(zhí)行測(cè)試
>> mkdir \dir3.2 從GAMS測(cè)試庫(kù)中提取運(yùn)行測(cè)試模型和支持文件,存放在臨時(shí)文件夾
>> cd \tmp >> testlib gdxmrw03 %測(cè)試rgdx >> testlib gdxmrw04 %測(cè)試wgdx >> testlib gdxmrw05 %gams中的MATLAB路徑 >> testlib gdxmrw06 %測(cè)試irgdx和iwgdx(在執(zhí)行這一步驟時(shí),可能會(huì)出現(xiàn)找不到這幾個(gè)文件的報(bào)錯(cuò),原因是GAMS庫(kù)中的這些文件的格式出現(xiàn)亂碼。解決方法:在GAMS路徑中打開testlib_ml文件夾,找到gdxmrw03.***這幾個(gè)文件,將文件后綴改為.gms)
(出現(xiàn)未定義testlib函數(shù)或變量的報(bào)錯(cuò)。可能解決方法:修改testlib的后綴,或者是因?yàn)楸I版軟件、中文系統(tǒng)導(dǎo)致的部分文件亂碼、丟失?)
?疑惑?:這里的gdxmrw**的例子里,gams文檔里用call語(yǔ)句調(diào)用了MATLAB,最終的結(jié)果卻一直沒能指定在MATLAB的文件夾路徑之下。思路1:是否需要在call語(yǔ)句中指定matlab的路徑或執(zhí)行程序的路徑;思路2:call語(yǔ)句的句法?是否需要特別設(shè)置參數(shù)?
>> testinst /集體測(cè)試如果上面的幾個(gè)testlib測(cè)試都不成功,只有這個(gè)測(cè)試成功,基本也說(shuō)明gdxmrw可用的。
也可以用這個(gè)testinst來(lái)驗(yàn)證測(cè)試rgdx:
>> [x, y] = gams('testinst'); %結(jié)果會(huì)出現(xiàn)兩個(gè)結(jié)構(gòu)體x,y公用函數(shù):gdxWhos和gdxInfo
這兩個(gè)公用程序能使GDXMRW能被MATLAB的命令提示符調(diào)用。gdxWhos函數(shù)是在MATLAB函數(shù)whos查詢過.mat文件之后松弛構(gòu)造的,它提供了指定GDX文件的(符號(hào))信息,唯一的輸入?yún)?shù)就是所指定GDX文件的名稱(可以不加.gdx后綴)。如果gdxWhos沒有指定輸出參數(shù),那么它會(huì)在MATLAB的命令提示符中顯示指定GDX文件的(符號(hào))信息;如果指定一個(gè)輸出參數(shù)的話,GDX的(符號(hào))信息將會(huì)包含在返回的一個(gè)結(jié)構(gòu)體數(shù)組(arrary of structrues)里,這個(gè)元數(shù)據(jù)(meta-data)在編程時(shí)很有用,有多種用途。
一個(gè)沒有返回參數(shù)的gdxWhos調(diào)用:
>> gdxWhos('idx1_.gdx'); Symbol info of GDX idx1_.gdxIndex Type Dim NRecs Name1 Parameter 0 1 a0 2 Parameter 1 3 a1(5) 3 Parameter 2 4 a2(2,2) 4 Parameter 3 6 a3(3,5,2) 5 Parameter 10 256 a10(3,5,2,2,2,2,2,2,2,2)這個(gè)例子中,idx1_gdx有5個(gè)參數(shù),每個(gè)參數(shù)的索引參數(shù)可以在“Name”這一列看到。如果沒有索引數(shù)據(jù),那么參數(shù)將會(huì)作為一個(gè)集合或者顯示一個(gè)'*'符號(hào),下面這個(gè)例子的前三個(gè)參數(shù)沒有索引,最后一個(gè)有索引:
>> gdxWhos('fake.gdx'); Symbol info of GDX fake.gdxIndex Type Dim NRecs Name1 Set 1 3 i(*)2 Parameter 1 3 a(i)3 Set 1 3 d_i_m__3(*)4 Parameter 1 3 aa(3)gdxInfo函數(shù)是在gdxdump公用函數(shù)之后構(gòu)造的,它在MATLAB的命令行窗口列出并消除指定GDX文件每個(gè)符號(hào)的數(shù)據(jù)值。用法同gdxWhos。例如:
>> gdxInfo('idx1_.gdx') * Library in use : F:\GAMS25.1 * Library version: GDX Library 25.1.3 r4e34d435fbd Released Oct 30, 2018 WEI x86 64bit/MS Wi * File version : GDX Library 24.2.0 r42219 ALFA Released 26Sep13 LNX x86/Linux * Producer : GAMS Base Module 24.2.0 r42219 ALFA Released 26Sep13 LNX x86/Linux * Symbols : 5 * Unique Elements: 5//文檔的具體內(nèi)容 $ontext . . . . . . $offempty offembeddedMATLAB調(diào)用GAMS模型
MATLAB通過一個(gè)公用函數(shù)“gams”,使用MATLAB數(shù)據(jù)初始化并運(yùn)行GAMS模型,再將結(jié)果返回給MATLAB。雖然“gams”函數(shù)與“rgdx”和“wgdx”都是基于同樣的設(shè)計(jì),但是它做任何事都只需要調(diào)用一下,這個(gè)函數(shù)是可以多輸入多輸出的,標(biāo)準(zhǔn)語(yǔ)法:
>> [x1, x2, x3] = gams('model', s1, s2.., c1, c2..);其中第一個(gè)參數(shù)是GAMS中model的名稱和用戶任意設(shè)置的命令。例如,用戶可以設(shè)置給定model(下面例子中是qp.gms)的不同求解器(在GAMS model名稱后添加求解器名稱:"qp nlp=baron"),也可以改變模型的執(zhí)行時(shí)間。
GAMS的其他輸入?yún)?shù)都是結(jié)構(gòu)體(structures),它們的位置不重要。這些結(jié)構(gòu)體有兩類:一類是與wgdx的輸入結(jié)構(gòu)體相類似;另一類結(jié)構(gòu)體只有兩個(gè)字符串字段:名稱(name)和值(val)。后一類能夠在GAMS中通過“$set”變量語(yǔ)法來(lái)設(shè)置或者重寫model的值。
一個(gè)二次優(yōu)化的GAMS模型例子:minimizes ? xTQx+cTx subject to Ax≥b and x≥0
$set matout "'matsol.gdx', x, dual, obj, returnStat ";Seti / 1*2 /j / 1*3 /;Alias (j1,j);ParameterQ(j,j1) / 1 .1 1.02 .2 1.03 .3 1.0 /A(i,j) / 1 .1 1.01 .2 1.01 .3 1.02 .1 -1.02 .3 1.0 /b(i) / 1 1.02 1.0 /c(j) / 1 2.0 /;Variable obj;Positive Variable x(j);Equation cost, dual(i);cost.. obj =e= 0.5*sum(j, x(j)*sum(j1, Q(j,j1)*x(j1))) + sum(j, c(j)*x(j));dual(i).. sum(j, A(i,j)*x(j)) =g= b(i);Model qp / cost, dual /;$if exist matdata.gms $include matdata.gmssolve qp using nlp minimizing obj;Set stat / modelStat, solveStat /;Parameter returnStat(stat); returnStat('modelStat') = qp.modelstat; returnStat('solveStat') = qp.solvestat;execute_unload %matout%;如果直接在GAMSIDE中運(yùn)行,優(yōu)化結(jié)果是0.5。
在MATLAB中運(yùn)行:
>> x = gams('qp');這個(gè)命令首先收集輸入的結(jié)構(gòu)體數(shù)據(jù),然后在一個(gè)'matdata.gdx'和能在matdata.gdx文件中創(chuàng)建包含能寫入符號(hào)狀態(tài)描述的'matdata.gms'。在上面這個(gè)例子中,它沒有結(jié)構(gòu)體的輸入,所以創(chuàng)建一個(gè)空的“matdata.gdx”文件,“matdata.gms”將只加載一個(gè)沒有符號(hào)的描述。如果已經(jīng)存在了一個(gè)“matdata.gdx”或者“matdata.gms”文件,這將是為了在主模型中阻止任何不期望的數(shù)據(jù)加載。當(dāng)創(chuàng)建了這兩個(gè)文件后,"gams"程序段將會(huì)使用一個(gè)系統(tǒng)調(diào)用來(lái)執(zhí)行“gams qp”。當(dāng)這個(gè)模型被執(zhí)行過之后,模型最后一行的描述語(yǔ)句“execute_unload”將會(huì)創(chuàng)建另一個(gè)“matsol.gdx”文件。注意,想要使用MATLAB的gams路徑執(zhí)行任何模型,都應(yīng)該包含類似下面這樣的語(yǔ)句(在第一行或者模型文件的開頭部分):
$set matout "'matsol.gdx', x, dual, obj, returnStat ";這是GAMS一個(gè)標(biāo)準(zhǔn)的$set語(yǔ)句,用來(lái)設(shè)置局部變量“matout”的值。GAMS程序會(huì)從gms文件的開頭開始搜索'$set matout',而這些gms文件可能是很大的,所以要把這個(gè)語(yǔ)句放在gms文件開頭附近。在這個(gè)語(yǔ)句中,將會(huì)創(chuàng)建一個(gè)包含'x1''x2'等符號(hào)的文件名為'fileName'的gdx文件,這些符號(hào)隨后可以被輸出至MATLAB。模型的最后一行應(yīng)該總是:
execute_unload %matout%;模型的首行和最后一行設(shè)置這樣語(yǔ)句的原因是,在模型的’header'中明確用戶想要輸出到MATLAB的數(shù)據(jù)。如果MATLAB沒有給除了期望參數(shù)以外的其他輸出參數(shù),我們必須要明確在GAMS中的model輸出什么數(shù)據(jù)到MATLAB。在上面這個(gè)例子中只有一個(gè)輸出參數(shù),因此'gams‘程序?qū)榱怂牡谝粋€(gè)元素,從輸出的gdx文件獲取數(shù)據(jù)并儲(chǔ)存在MATLAB的輸出參數(shù)中。
如果要輸出不止一個(gè)參數(shù),例如:
>> [x, u] = gams('qp');這個(gè)gams程序?qū)?huì)讀取輸出的gdx文件:儲(chǔ)存gdx文件的第一個(gè)元素信息作為MATLAB的第一個(gè)輸出參數(shù),例如'x’;gdx文件的第二個(gè)元素信息作為MATLAB的第二個(gè)輸出參數(shù),例如'u',以此類推。如果MATLAB輸出參數(shù)的數(shù)量多于了gdx文件的元素?cái)?shù)量,gams程序?qū)⑤敵鰁rror。(可以參考datalib的gdxmrw_qp4例子)
(bug: 在GAMS中可以直接運(yùn)行qp.gms得到結(jié)果,但是matlab調(diào)用時(shí)出現(xiàn)“abnormal GAMS termination running F:\GAMS25.1\gams.exe qp lo=0: check listing file”的錯(cuò)誤。debug:原因是文件夾的中文名稱過長(zhǎng),結(jié)果出現(xiàn)ASCII,解決方法為,文件夾名稱精簡(jiǎn)成短英文)
輸入結(jié)構(gòu)體
如前所述,gams程序的輸入?yún)?shù)是結(jié)構(gòu)體的形式。它允許兩種結(jié)構(gòu)體類型,一種是類似于wgdx輸入結(jié)構(gòu)體,它包含符號(hào)數(shù)據(jù)被輸出至gdx文件,另一種只有兩個(gè)字符串字段'name'和'val'。使用示例:
>> s.name = 'Q'; >> s.val = eye(3); >> s.form = 'full'; >> m = struct('name', 'm', 'val', '2'); >> [x] = gams('qpmcp', s, m);在這個(gè)例子中,'s'和'm'都是結(jié)構(gòu)體,但是'm'只有兩個(gè)字符串字段。gams程序?qū)⑹褂?#39;s'結(jié)構(gòu)體創(chuàng)建一個(gè)'matdata.gdx‘文件,使用'm'修改執(zhí)行命令行使得在最后包含"--m=2"。例如一條命令將會(huì)像“gams qpmcp --m=2”這樣執(zhí)行。
雖然's'結(jié)構(gòu)體與wgdx的輸入結(jié)構(gòu)體類似,但還是有兩個(gè)主要的不同。首先,從上面例子也可以看到's'結(jié)構(gòu)體沒有'type'字段,在wgdx中我們默認(rèn)結(jié)構(gòu)體的type為'set',而在gams程序中是被默認(rèn)為'parameter'的;其次,'s'有一個(gè)可選的額外的輸入字段'load'。
關(guān)于‘load’:它是一個(gè)代表相應(yīng)數(shù)據(jù)將如何被加載到GAMS程序的字符串輸入。GAMS讀取的輸入數(shù)據(jù)可以根據(jù)全局選項(xiàng)'gamso.input'的值有不同的方式,加入輸入結(jié)構(gòu)體's'有一個(gè)被稱為'foo'的"name'字段,matdata.gms文件將(在gamso.input = ‘compile’)默認(rèn):
$ loadR fooGAMS中的參數(shù)(或集合)foo將會(huì)被在'matdata.gdx'容器中的'foo'所替代(注:foo在編程中常用于函數(shù)/方法的名稱,此外還有bar、foobar等,像“張三”“李四”一樣,并無(wú)實(shí)際用途和引用意義),如果數(shù)據(jù)已經(jīng)在模型中被初始化了,這將會(huì)用'matdata.gdx'中的新數(shù)據(jù)替代初始化數(shù)據(jù),可以明確的設(shè)置這個(gè)可選項(xiàng):
s.load = 'replace'還有其他兩種編譯時(shí)間加載選項(xiàng),稱為'initialize'和'merge',前者僅在參數(shù)值還沒在GAMS文件中初始化時(shí)有效,否則就會(huì)報(bào)錯(cuò),它的GAMS語(yǔ)法是:
$load foo后者的有效條件是當(dāng)GAMS文件運(yùn)行時(shí)參數(shù)值已經(jīng)被初始化了,MATLAB的's'結(jié)構(gòu)體的新值將與根據(jù)新值重寫的參數(shù)進(jìn)行簡(jiǎn)單合并。明確的說(shuō),'matdat.gms'文件包含
$loadM foo這樣的描述,用來(lái)相應(yīng)地指導(dǎo)GAMS。
最后,如果gamso.input='exec',那么加載將會(huì)出現(xiàn)在運(yùn)行時(shí)間。在這個(gè)例子中,s.load='initialize'不是一個(gè)有效的輸入,默認(rèn)的設(shè)置是s.load='replace',通過執(zhí)行
execute_load "matdata.gdx" foo另一個(gè)設(shè)置s.load='merge'是通過執(zhí)行
execute_loadpoint "matdata.gdx" foo通過這樣的方式,數(shù)據(jù)在運(yùn)行時(shí)間被加載,并做出合適的repalce或者merge。
改變默認(rèn)行為的全局輸入
以上是如何具體規(guī)定gams程序的不同輸入,這一節(jié)是介紹如何改變gams調(diào)用的默認(rèn)行為。它可以通過在工作空間創(chuàng)建一個(gè)'gamso'結(jié)構(gòu)體,并往這個(gè)結(jié)構(gòu)體中添加不同的字段。目前這個(gè)結(jié)構(gòu)體中有9個(gè)能影響程序行為的字段可以被設(shè)置。除了uels字段,所有其他字符串字段都采用不區(qū)分大小寫的字段。這些可選項(xiàng)都是面向全局的。
- gamso.output
- gamso.input
- gamso.write_data
- gamso.show
- gamso.path
- gamso.compress
- gamso.form
- gamso.uels
- gamso.fields
總結(jié)
1. 對(duì)于GAMS文件
在文件開始部分加上
$set matout "'***.gdx', *, *, ...";在文件末尾加上
execute_unload %matout%2.對(duì)于MATLAB文件
調(diào)用語(yǔ)法格式為
[*, *, ...] = gams('***.gms', *, *, ...)?
?
?
總結(jié)
以上是生活随笔為你收集整理的Matlab与GAMS交互的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用java把中文小写数字转化为阿拉伯数
- 下一篇: 如何手动下载最新的 macOS Beta