GLPK/Scripting plus MathProg

This page covers the use of external scripting languages with MathProg.


Passing values via the command-lineEdit

Please see the section on passing values via the command-line. The method involves a creating a simple shell script (or batch file).

Parametric studies and MathProgEdit

The 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 plus AWKEdit

AWK 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 and then run it from the command-line:

$ awk --file 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 ScriptEdit

Visual 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 ApplicationsEdit

Visual 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 PyMathProgEdit

If 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 SageEdit

Comment: 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 PythonEdit

Terminal 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.

Last modified on 11 May 2012, at 22:56