跳轉到內容

GLPK/指令碼和 MathProg

來自華夏公益教科書,開放的書籍,開放的世界

此頁面涵蓋了使用外部 指令碼語言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

[編輯 | 編輯原始碼]

為了簡單和高效,MathProg 語言不提供 控制結構(此限制不適用於使用 GLPK API 進行的 編譯語言 程式設計)。這種缺乏控制結構阻止了在 MathProg 中直接實現 引數研究——在這種情況下,人們希望對一系列 引數 值執行簡單的 迴圈,其中 MathProg 的求解語句巢狀在其中。引數研究與敏感度分析相同。

一種解決方法是使用指令碼語言來 生成和執行 許多 GLPK 模型例項。更復雜的方法是使用 關係資料庫 來儲存中間解決方案。

GLPSOL 和 AWK

[編輯 | 編輯原始碼]

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 向上。此外,敏銳的讀者可能會注意到,使用類似的指令碼方法也可以在執行時構建修改後的模型(而不是資料)檔案。

GLPSOL 和 Visual Basic Script

[編輯 | 編輯原始碼]

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

GLPSOL 和 Visual Basic for Applications

[編輯 | 編輯原始碼]

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

Python 和 PyMathProg

[編輯 | 編輯原始碼]

如果基於 shell 命令的指令碼(使用 AWK)不夠靈活,那麼 Python 語言和 PyMathProg 包提供了一個更強大的替代方案。 PyMathProg 允許使用 Python 以非常類似於 GMPL 的形式編寫線性規劃和混合整數規劃模型。關於如何使用 PyMathProg 實現子巡迴消除啟發式的簡明示例見 此處

Python 和 Sage

[編輯 | 編輯原始碼]

評論:此材料應擴充套件。

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 的開銷顯然很高,但該環境執行良好。

在 Python 中抑制終端輸出

[編輯 | 編輯原始碼]

可以按如下方式抑制終端輸出

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。此外,可以將命令列引數傳遞給最終的呼叫以提高靈活性。

華夏公益教科書