GLPK/Scripting plus MathProg
This page covers the use of external scripting languages with MathProg.
Passing values via the command-line
editValues cannot be passed as command line parameters to glpsol. Instead a script can be used to write command line parameters to a data file. This data file can be loaded together with the model.
The following Bash script test.sh takes the first command line parameter and writes it to a data file test.dat and then calls glpsol for model test.mod and data file test.dat:
#!/bin/sh
echo data\; > test.dat
echo param p := \'$1\'\; >> test.dat
echo end\; >> test.dat
glpsol -m test.mod -d test.dat
You can test the script with the following model file test.mod
param p, symbolic; printf "%s\n", p; end;
by executing
/test.sh 'Hello world'
The data file created test.dat will contain the following lines:
data; param p := 'Hello world'; end;
Parametric studies and MathProg
editThe MathProg language does not offer control structures in the interests of simplicity and efficiency (a restriction that does not apply to compiled language programming with the GLPK API). This lack of control structures prevents the direct implementation of parametric studies within MathProg — where one would like to perform a simple loop over a range of parameter values with the MathProg solve statement nested inside. A parametric study is the same as a sensitivity analysis.
One work-around is to use a scripting language to generate and run a number of GLPK model instances. A more sophisticated approach would be to use a relational database for the storage of interim solutions.
GLPSOL and AWK
editAWK is a well-established scripting language with a C-like syntax. GNU AWK is present by default on most Linux distros, otherwise install the gawk package. Windows users can obtain GNU AWK binaries from gnuwin32.sourceforge.net/packages/gawk.htm.
AWK makes it possible to create GMPL data files and then invoke glpsol on these newly-created files. This means AWK is a good choice for undertaking parametric studies in association with GMPL. It is normally better to use one volatile data file for your scanned parameters and another stable data file for the rest of your model data (glpsol supports multiple data files).
The rudimentary example below is presented as a stub for developing your own parameter scanning scripts. This example repeatedly writes the parameter iter to a volatile data file test.dat and then calls glpsol to display the value of this parameter. This script also generates the model file test.mod at the outset, but normally your model file would preexist. Windows users will need to replace the Linux remove command rm --force with 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;
}
Save this script as text file scan.awk.
Ensure that lines are separated by line feeds (0x0A). Beware, some OS X editors use carriage returns (0x0D).
Run the script from the command-line:
$ awk -f scan.awk
Edited terminal output from iteration 2 is as follows:
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
The same basic idea can be implemented in virtually any scripting language, from bash upwards. In addition, astute readers may notice that altered model (as opposed to data) files can also be constructed on-the-fly using similar scripting methods.
GLPSOL and Visual Basic Script
editVisual Basic Script is programming language delivered with Microsoft Windows.
Visual Basic Script makes it possible to create GMPL data files and then invoke glpsol on these newly-created files.
The example below demonstrates how this can be done.
Create a model file test.mod which will only print parameter p.
param p;
printf "Parameter p = %d\n", p;
end;
Create a script 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
Run the script with
cscript test.vbs
GLPSOL and Visual Basic for Applications
editVisual Basic Script is programming language delivered with Microsoft Office.
VBA makes it possible to create GMPL files and then invoke glpsol on these newly-created files.
The example below demonstrates how this can be done.
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 and PyMathProg
editIf shell-command-based scripting (using AWK) is not flexible enough, then the Python language and the PyMathProg package provide a more powerful alternative. PyMathProg allows one to write linear and mixed-integer programming models — in a form very much like GMPL — using Python. A succinct example of how PyMathProg can be used to implement a subtour elimination heuristic is given here.
Python and Sage
editComment: this material should be extended.
Sage is an open source mathematics environment, offering both symbolic and numerical calculation and good visualization. Sage supports the Python language and GLPK is available through the Sage optimization module.
A mixed-integer model is first built using an instance of class MixedIntegerLinearProgram — and then solved using its solve method, with the solver set to GLPK:
sage: p = MixedIntegerLinearProgram(maximization=True) sage: x = p.new_variable() ... sage: p.solve(solver="GLPK", log="filename.log")
The overhead for installing Sage is apparently quite high, but the environment works well.
Suppressing terminal output under Python
editTerminal output may be suppressed as follows:
import subprocess
capture = subprocess.check_output(["glpsol", "--math", "noisy.mod", "--output", "noisy.out"])
print ("complete")
Save the above scripting to a file named quiet.py and then execute it:
> python quiet.py complete
GLPSOL's normal output is stored in capture for later use. The model's solution is saved as file noisy.out. And only the explicit print statement is sent to the console.
Similar techniques could be applied to other scripting languages, including Bash and Perl. Moreover, command-line arguments could be passed through to the final call to aid flexibility.