GLPK/指令碼和 MathProg
值不能作為命令列引數傳遞給 glpsol。相反,可以使用指令碼將命令列引數寫入資料檔案。該資料檔案可以與模型一起載入。
以下 Bash 指令碼 test.sh 獲取第一個命令列引數並將其寫入資料檔案 test.dat,然後為模型 test.mod 和資料檔案 test.dat 呼叫 glpsol
#!/bin/sh
echo data\; > test.dat
echo param p := \'$1\'\; >> test.dat
echo end\; >> test.dat
glpsol -m test.mod -d test.dat
您可以使用以下模型檔案 test.mod 測試指令碼
param p, symbolic; printf "%s\n", p; end;
透過執行
/test.sh 'Hello world'
建立的資料檔案 test.dat 將包含以下行
data; param p := 'Hello world'; end;
為了簡單和高效,MathProg 語言不提供 控制結構(此限制不適用於使用 GLPK API 進行的 編譯語言 程式設計)。這種缺乏控制結構阻止了在 MathProg 中直接實現 引數研究——在這種情況下,人們希望對一系列 引數 值執行簡單的 迴圈,其中 MathProg 的求解語句巢狀在其中。引數研究與敏感度分析相同。
一種解決方法是使用指令碼語言來 生成和執行 許多 GLPK 模型例項。更復雜的方法是使用 關係資料庫 來儲存中間解決方案。
AWK 是一種成熟的指令碼語言,具有類似 C 的語法。大多數 Linux 發行版預設情況下都包含 GNU AWK,否則請安裝gawk包。 Windows 使用者可以從 gnuwin32.sourceforge.net/packages/gawk.htm 獲取 GNU AWK 二進位制檔案。
AWK 使得建立 GMPL 資料檔案然後對這些新建立的檔案呼叫 glpsol 成為可能。這意味著 AWK 是進行與 GMPL 相關的引數研究的不錯選擇。通常最好使用一個易失性資料檔案來存放您掃描的引數,以及另一個穩定資料檔案來存放模型資料的其餘部分(glpsol 支援多個數據檔案)。
以下基本示例作為開發您自己的引數掃描指令碼的存根。此示例反覆將引數iter寫入易失性資料檔案test.dat然後呼叫 glpsol 來顯示此引數的值。此指令碼還在開始時生成模型檔案test.mod但通常您的模型檔案會預先存在。 Windows 使用者需要將 Linux 刪除 命令 rm --force 替換為 del。
# AWK script
# provides a starting point for developing custom parameter scanning scripts
BEGIN {
modfile = "test.mod";
datfile = "test.dat";
system("rm --force " modfile); # Linux remove call
printf ("Writing model file\n");
printf ("# model file\n") > modfile;
printf ("param iter;\n") > modfile;
printf ("solve;\n") > modfile;
printf ("display iter;\n") > modfile;
printf ("end;\n") > modfile;
close(modfile);
for (i = 1; i <= 5; i++) {
system("rm --force " datfile); # Linux remove call
printf("\n\nIteration %i\n", i);
printf ("Writing data file\n");
printf("# data file %i\n", i) > datfile;
printf("data;\n") > datfile;
printf("param iter := %i;\n", i) > datfile;
printf("end;\n") > datfile;
close(datfile);
system("glpsol --model " modfile " --data " datfile);
}
exit;
}
將此指令碼儲存為文字檔案scan.awk.
確保行之間用換行符(0x0A)隔開。注意,一些 OS X 編輯器使用回車符(0x0D)。
從命令列執行指令碼
$ awk -f scan.awk
來自迭代 2 的編輯後的終端輸出如下
Iteration 2 Writing data file GLPSOL: GLPK LP/MIP Solver, v4.44 Reading model section from test.mod... Reading data section from test.dat... Model has been successfully generated GLPK Simplex Optimizer, v4.44 0 rows, 0 columns, 0 non-zeros ~ 0: obj = 0.000000000e+00 infeas = 0.000e+00 OPTIMAL SOLUTION FOUND Display statement at line 4 iter = 2 Model has been successfully processed
幾乎所有指令碼語言都可以實現相同的基本思路,從 bash 向上。此外,敏銳的讀者可能會注意到,使用類似的指令碼方法也可以在執行時構建修改後的模型(而不是資料)檔案。
Visual Basic Script 是與 Microsoft Windows 一起提供的程式語言。
Visual Basic Script 使得建立 GMPL 資料檔案然後對這些新建立的檔案呼叫 glpsol 成為可能。
以下示例演示瞭如何執行此操作。
建立一個模型檔案test.mod它只打印引數p.
param p;
printf "Parameter p = %d\n", p;
end;
建立一個指令碼test.vbs
Const ForWriting = 2
Set wshShell = WScript.CreateObject ("WSCript.shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set sout = WScript.StdOut
For i = 1 To 3
'Write data file
Set MyFile = fso.OpenTextFile("test.dat", ForWriting, True)
MyFile.WriteLine "data;"
MyFile.WriteLine "param p := " & i & ";"
MyFile.WriteLine "end;"
MyFile.Close
'Execute glpsol
Set oExec = wshShell.exec("glpsol -m test.mod -d test.dat")
'Copy output of glpsol to console used by script
While Not oExec.StdOut.AtEndOfStream
sout.Write oExec.StdOut.Read(1)
Wend
Next
使用以下命令執行指令碼
cscript test.vbs
Visual Basic Script 是與 Microsoft Office 一起提供的程式語言。
VBA 使得建立 GMPL 檔案然後對這些新建立的檔案呼叫 glpsol 成為可能。
以下示例演示瞭如何執行此操作。
Option Explicit
Private Declare Function WaitForSingleObject Lib "kernel32" ( _
ByVal hHandle As Long, _
ByVal dwMilliseconds As Long) As Long
Private Declare Function OpenProcess Lib "kernel32.dll" ( _
ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" ( _
ByVal hObject As Long) As Long
Private Const SYNCHRONIZE = &H100000
Private Const INFINITE = -1&
Private Const MinimizedNoFocus = 6
' Model file
Private Const modfile = "C:\TEMP\test.mod"
' Result file
Private Const resfile = "C:\TEMP\test.res"
Public Sub parametricStudy()
Dim p As Double
Dim r As String
For p = 0.5 To 2.5 Step 0.2
r = r & runGLPK(p) & vbCrLf
Next p
MsgBox r, vbOKOnly, "Result"
End Sub
Private Function runGLPK(p As Double) As String
Dim f As Integer
Dim s As String
Dim pid As Long
Dim h As Long
Dim x As String
Dim y As String
' Convert double to string
s = p
s = Replace(s, ",", ".")
' Create model file
f = FreeFile()
Open modfile For Output As f
Print #f, "param f, symbolic := """ & resfile & """;"
Print #f, "var x, >=0;"
Print #f, "var y, >=0;"
Print #f, "maximize obj : x + "; s; " * y; "
Print #f, "s.t. c1 : x + y <= 4;"
Print #f, "s.t. c2 : x + 2 * y <= 6;"
Print #f, "solve;"
Print #f, "printf ""%f\n"", x > f;"
Print #f, "printf ""%f\n"", y >> f;"
Print #f, "end;"
Close f
' Delete result fle
If Dir(resfile) <> "" Then
Kill resfile
End If
' Start glpsol
pid = Shell("""C:\Program Files\GLPK\glpk-4.47\w32\glpsol.exe"" -m " & modfile, MinimizedNoFocus)
If pid = 0 Then
MsgBox "Failure to start glpsol.exe", vbCritical, "Error"
Exit Function
End If
' Wait for glpsol to end
h = OpenProcess(SYNCHRONIZE, 0, pid)
If h <> 0 Then
WaitForSingleObject h, INFINITE
CloseHandle h
End If
' Check if result file written
If Dir(resfile) = "" Then
MsgBox "No result from glpsol.exe", vbCritical, "Error"
Exit Function
End If
' Output result
Open resfile For Input As f
Line Input #f, x
Line Input #f, y
Close f
runGLPK = "p = " & s & " => x = " & x & ", y = " & y
End Function
如果基於 shell 命令的指令碼(使用 AWK)不夠靈活,那麼 Python 語言和 PyMathProg 包提供了一個更強大的替代方案。 PyMathProg 允許使用 Python 以非常類似於 GMPL 的形式編寫線性規劃和混合整數規劃模型。關於如何使用 PyMathProg 實現子巡迴消除啟發式的簡明示例見 此處。
評論:此材料應擴充套件。
Sage 是一種開源數學環境,提供符號計算和數值計算以及良好的視覺化功能。Sage 支援 Python 語言,GLPK 可透過 Sage 最佳化模組 使用。
首先使用類例項構建混合整數模型MixedIntegerLinearProgram——然後使用其求解方法求解,將求解器設定為 GLPK
sage: p = MixedIntegerLinearProgram(maximization=True) sage: x = p.new_variable() ... sage: p.solve(solver="GLPK", log="filename.log")
安裝 Sage 的開銷顯然很高,但該環境執行良好。
可以按如下方式抑制終端輸出
import subprocess
capture = subprocess.check_output(["glpsol", "--math", "noisy.mod", "--output", "noisy.out"])
print ("complete")
將上述指令碼儲存到名為quiet.py的檔案中,然後執行它
> python quiet.py complete
GLPSOL 的正常輸出儲存在capture中,以便以後使用。模型的解儲存為檔案noisy.out。只有明確的列印語句被髮送到控制檯。
類似的技術可以應用於其他指令碼語言,包括 Bash 和 Perl。此外,可以將命令列引數傳遞給最終的呼叫以提高靈活性。