Table of Contents
Some General Comments
Nowadays the objected-oriented APIs are the most efficient and elegant way to interact with the GAMS system. They allow the effective communication of data, and do parameterized runs of GAMS. This whole chapter describes a much more basic interaction of GAMS through calling the GAMS executable from different environments. This still can be useful, e.g. if no object-oriented API is available for the particular target language (e.g. VBA).
While the principle of calling the GAMS executable holds for all operating systems, this chapter often focuses on the Windows platform.
One of the interesting problems one faces when spawning GAMS.EXE in a Windows environment is multi-threading. If one does not take precautions, a call to Shell (VB function) or CreateProcess (Win32 API function) causes GAMS to run asynchronously: the function will return while GAMS is still running. In order to read the results one would need to wait until the GAMS job has finished. The machinery for this requires some Windows trickery, and for Visual Basic version 6 and Delphi version 4 we have implemented some small examples that illustrate how this can be done.
Another issue that needs to be addressed is that GAMS needs a place to put its scratch files. By default this is the current directory, a concept that is not always clear in a windowing environment. A good way of dealing with his is to set both the current drive and the current directory before running the GAMS job. It should be noted that GAMS needs write permission there. In the examples we use the Windows TEMP directory for this, but in a real application you may want to use a designated directory. The Windows TEMP directory is found by calling the API function GetTempPath.
The GAMS architecture
GAMS itself is a console mode application. In fact it is not a single program, but a driver program (GAMS.EXE on Windows, otherwise GAMS) that executes in turn the GAMS language compiler (GAMSCMEX) or one of the solvers. For a model with a single solve statement, GAMS.EXE will first call GAMSCMEX to compile the GAMS model. Then GAMSCMEX will start executing the internal code that was generated by the compiler. As soon as it hits the instructions belonging to a SOLVE statement it will generate model instance, and GAMSCMEX will exit. Then GAMS.EXE will spawn a solver capable of solving the model. As soon as the solver is finished, GAMS.EXE will execute GAMSCMEX again so it can read the solution and can continue with executing instructions.
Spawning GAMS from VBA
Visual Basic for Applications (VBA) is a programming language that is built into most Microsoft Office applications, e.g. Excel and Access. A VBA program may include modules, which can be imported from files, i.e. in the VBA editor you can choose menu “File”→“Import File”. The GAMS distribution includes some VBA modules, which can be found from:
<GAMS System Directory>\apifiles\VBA\api, e.g. "C:\GAMS\win64\24.5\apifiles\VBA\api"
- Attention
- In order to avoid issues, it's recommended to use the latest version of the modules , i.e. the modules found in the latest GAMS release.
For example, the following modules can be found:
- gamsglobals.bas: Global constants that are used in other modules
- gdxvba.bas: GAMS Data Exchange Object
- idxvba.bas: GAMS IDX Object
-
optvba.bas: GAMS Option Object
For more information, see Expert-Level APIs. VBA programs that use the API can be found from:
<GAMS System Directory>\apifiles\VBA, e.g. "C:\GAMS\win64\24.5\apifiles\VBA"
The models can also be retrieved via GAMS Studio -> GAMS --> Model Library Explorer -> GAMS Data Utilities Models.
Spawning GAMS from Excel
Calling GAMS out of Excel requires some more work than just Data Exchange with Microsoft Excel. The application calling GAMS out of Excel has to:
- Locate the GAMS system directory and adjust the system path accordingly.
- Copy the GAMS model into a temporary directory (by default the temporary directory of Windows)
- Extract the model data from the spreadsheet into a GAMS readable format (gdx)
- Execute GAMS (solve the model, write the slution back to gdx file)
- Import the model results back from the gdx files into the spread sheet
- Update the spreadsheet (graphics, tables)
Using VisualBasic for Applications (VBA) this can be implemented with a few lines of code:
For further details, please inspecte the VBA part of the examples below.
A Simple Example
This very simple example shows how GAMS can be invoked from an Excel spreadsheet. The "example spreadsheet" has a button, which will cause GAMS to run the trnsport.gms model stored in c:/tmp. There is no data exchange.
A more complete application will write an include file for a GAMS model, and will import a comma delimited file with results when the run is finished. An example of such a complete application is described in http://www.gams.com/mccarl/excelgams.pdf.
Sudoku Example
This spreadsheet is a complete example that uses GDX files to exchange information solves a 25x25 Sudoku problem using CPLEX. It comes with the GAMS distribution in apifiles/VBA/sudoku.xlsm. You will need a GAMS/CPLEX license to be able to run the spreadsheet. The MIP model solves very easily: the solution is found in the presolve phase.
Note: This spreadsheet requires distribution 22.6 or younger to work properly.
Problem
Solution
Efficient frontier example
This example solves a series of NLPs to create an efficient frontier of a portfolio optimization problem. It comes with the GAMS distribution in apifiles/VBA/portfolio.xlsm.
Note: This spreadsheet requires distribution 22.6 or younger to work properly.
Spawning GAMS from C
The example below shows an absolute minimal version of calling GAMS from a C program:
As can be seen the GAMS executable gams.exe is called via a simple invocation of system(). The extra command line parameter lo=2
indicates that the log file is not written to the screen (this is the default) but to a file model.log
.
If we want to generate some data from the application program (e.g. parameter DEMAND
), we can use an include file which is written by the application. Of the way back results can be read from a PUT file. The GAMS file can now look like:
Sets i canning plants / seattle, san-diego / j markets / new-york, chicago, topeka / ; Parameters a(i) capacity of plant i in cases / seattle 350 san-diego 600 / b(j) demand at market j in cases / $include demand.inc / ; Table d(i,j) distance in thousands of miles new-york chicago topeka seattle 2.5 1.7 1.8 san-diego 2.5 1.8 1.4 ; Scalar f freight in dollars per case per thousand miles /90/ ; Parameter c(i,j) transport cost in thousands of dollars per case ; c(i,j) = f * d(i,j) / 1000 ; Variables x(i,j) shipment quantities in cases z total transportation costs in thousands of dollars ; Positive Variable x ; Equations cost define objective function supply(i) observe supply limit at plant i demand(j) satisfy demand at market j ; cost .. z =e= sum((i,j), c(i,j)*x(i,j)) ; supply(i) .. sum(j, x(i,j)) =l= a(i) ; demand(j) .. sum(i, x(i,j)) =g= b(j) ; Model transport /all/ ; Solve transport using lp minimizing z ; Display x.l, x.m ; file fout /results.txt/; put fout; loop((i,j), put x.l(i,j):17:5/; ); putclose;
The corresponding C program could look like:
Spawning GAMS from Visual Basic
This example shows how GAMS can be invoked from a VB program.
When executed a simple window appears where a GAMS model can be specified and possible other command line options. The [GAMS] button will execute the model.
When the Normal display is used, a console window will be opened. This console window will be closed automatically at the end of the run if the Close process window on completion check box is checked. Minimized does not show a window, but in the taskbar an icon will appear. If the job takes a long time, the user can click on this icon to make the console window visible. The Hidden option prevents any GAMS associated window or icon to appear.
Note: it is required for this program to work, that the GAMS system directory is in the path. If this is not the case, an error code of -1 is returned.
The main program is attached below.
Spawning GAMS from Delphi
This is a Delphi 4 application that has similar features as the Visual Basic application described in the previous paragraph.
Note: it is required for this program to work, that the GAMS system directory is in the path. If this is not the case, an error code of -1 is returned. The main code is attached below.
Spawning GAMS from Visual C++
In "this example" we call GAMS from a simple Visual C++ application.
The additional concern is here that we want to intercept the GAMS screen output so it can be written to a multi-line edit control. For more information about the used technique see the Microsoft publication: [HOWTO: Spawn Console Processes with Redirected Standard Handles (Q190351)] (https://support.microsoft.com/en-us/kb/190351) in the Microsoft Knowledge Base.
Spawning GAMS from C#
Below is a simple example:
The command line formed here is gams modelname LO=0 –runid=xxx
. The option LO
(logoption) will disable writing a log, and the option –runid
passes a parameter to the GAMS model (inside the model you can access this through %runid%
).
Spawning GAMS from Java
Java has a class Runtime that implements spawning of processes using the Exec() method. This is quite trivial to use in applications, but in applets the default security settings don't allow this operation (in general). The problem can be solved by loading the applet from a local drive or by using a signed applet. Similarly if the Java classes are loaded from inside a database, this operation may require additional privileges. For an example see the previous section, where GAMS is called from Oracle using a Java Stored Procedure. The relevant code may look like:
Below another example, which avoids problems, if the model has a long screen log (the buffer gets filled and locks the execution), which could happen if GAMS does not write the log to the file like above. This example is based on suggestion made by Edson Valle.
For an example of GAMS usage from a Java based server environment see Alexander Sokolov, Information environment and architecture of decision support system for nutrient reduction in the Baltic Sea, Department of Systems Ecology, Stockholm University.
Spawning GAMS from a Web Server
Running GAMS remotely using a Web based thin-client architecture requires that GAMS is executed directly or indirectly from the Web server or HTTP server. A simple way of doing this is via a CGI process. Common Gateway Interface (CGI) programs can be written in many languages such as C, Perl or Delphi. CGI is relatively slow, as for each interaction, even the most simple one, a process needs to be started. Alternatives exist in the form of CGI extensions such as FastCGI or using DLLs or shared libraries. A basic algorithm for a CGI script could be:
- Create a unique directory, and CD to that directory.
- Get information from user forms and save it as GAMS readable files.
- Run GAMS making sure it does not write the log to the screen (i.e. use the option LO=2 (log to a file) or LO=3 (log to stdout)).
- Let the model write solution info to text files using the PUT statement.
- Read solution, and create formatted HTML to send back to the user.
- Remove temp files and directory.
Complications arise when there is a need to show graphics (files need to be stored somewhere and discarded after a while), when jobs take a long time to finish (you will need to add a facility where the user can pick up results at a later moment) or when the server resources can be exhausted (e.g. because of a large number of simultaneous users or because of large models).
An important complicating issue in the above list are jobs that take more time to finish: web servers like to respond to the user within a short time, and time out errors will occur if a job takes a long time. The solution is to use a queue based approach. An actual implementation available is the NEOS Server - there is also a GAMS interface to NEOS: KESTREL - Remote Solver Execution on NEOS Servers.
Spawning GAMS from PHP
A minimal example
index.html
calling_gams.php
trnsport_php.gms
Sets i canning plants / seattle, san-diego / j markets / new-york, chicago, topeka / ; Parameters a(i) capacity of plant i in cases / seattle 350 san-diego 600 / b(j) demand at market j in cases / $include demand.inc / ; Table d(i,j) distance in thousands of miles new-york chicago topeka seattle 2.5 1.7 1.8 san-diego 2.5 1.8 1.4 ; Scalar f freight in dollars per case per thousand miles / $include f.inc / ; Parameter c(i,j) transport cost in thousands of dollars per case ; c(i,j) = f * d(i,j) / 1000 ; Variables x(i,j) shipment quantities in cases z total transportation costs in thousands of dollars ; Positive Variable x ; Equations cost define objective function supply(i) observe supply limit at plant i demand(j) satisfy demand at market j ; cost .. z =e= sum((i,j), c(i,j)*x(i,j)) ; supply(i) .. sum(j, x(i,j)) =l= a(i) ; demand(j) .. sum(i, x(i,j)) =g= b(j) ; Model transport /all/ ; Solve transport using lp minimizing z ; Display x.l, x.m ; file fout /results.txt/; put fout; loop((i,j), put i.tl:0 '->' j.tl:0 ': ' x.l(i,j)/; ); put 'cost: 'z.l/; putclose;