跳转到内容

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。此外,可以将命令行参数传递给最终的调用以提高灵活性。

华夏公益教科书