Table of Contents
- Choose the GAMS system
- Export data to GDX
- Import data from GDX
- Run a Job from file
- Retrieve a solution from an output database
- Specify solver using Options
- Run Job with solver option file and capture log
- Use include files
- Set non-default working directory
- Read data from string and export to GDX
- Run Job using data from GDX
- Run Job using implicit database communication
- Define data using Matlab data structures
- Prepare Database from Matlab data structures
- Initialize Checkpoint by running Job
- Initialize Job from Checkpoint
- Create ModelInstance from Checkpoint
- Modify parameter of ModelInstance using Modifier
- Modify variable of ModelInstance using Modifier
- Create and use save/restart file
The goal of this tutorial is to provide a compact overview of the basic functionality of the GAMS Matlab Control API. It allows the user to start immediately working with the API by providing a set of examples based on the well-known transportation problem. Those examples are also part of the GAMS system directory, see [PathToGAMS]/api/matlab/examples/control
. These examples introduce several API features step by step.
We recommend to open the aforementioned files to gain a complete overview of the examples. Down below we explain the examples with the help of selected code snippets.
- Choose the GAMS system
- Export data to GDX
- Import data from GDX
- Run a Job from file
- Retrieve a solution from an output database
- Specify solver using Options
- Run Job with solver option file and capture log
- Use include files
- Set non-default working directory
- Read data from string and export to GDX
- Run Job using data from GDX
- Run Job using implicit database communication
- Define data using Matlab data structures
- Prepare Database from Matlab data structures
- Initialize Checkpoint by running Job
- Initialize Job from Checkpoint
- Create ModelInstance from Checkpoint
- Modify parameter of ModelInstance using Modifier
- Modify variable of ModelInstance using Modifier
- Create and use save/restart file
Choose the GAMS system
Example: transport1
By default the GAMS system is determined automatically. In case of having multiple GAMS systems on your machine, the desired system can be specified via an additional argument when the workspace is created. When running the examples, we can provide an additional command line argument in order to define the GAMS system directory that should be used. By executing transport1
with C:/GAMS/48 we use GAMS 48.2 to run transport1
even if our default GAMS system might be a different one. This is managed by the following code:
- Note
- The API can detect GAMS automatically from the
PATH
environment variable. Please note that this is not theMATLABPATH
. You can inspect thePATH
withgetenv("PATH")
. -
In Matlab you can import the GAMS Control package by
import gams.control.*
. Then, you don't need to call the GAMS classes with the precedinggams.control.
.
Export data to GDX
Example: transport_gdx
Although the Matlab Control API offers much more than exchanging data between Matlab and GDX, a common use case is the export and import of GDX files. The central class for this purpose is Database. We assume that the data to be exported is available in Matlab data structures.
Different type of GAMS symbols are represented using different Matlab data structures. The data for the GAMS sets is represented using a cell of strings (e.g. plants
and markets
). On the other hand, GAMS parameters are represented by a containers.Map
(e.g. capacity
and demand
). Note that the representation of the two dimensional parameter distance
uses a dot notation for storing the keys. The choice of data structures can also be different, but the used structures in this example fit well for representing GAMS data with Matlab data structures.
A new Database instance can be created using Workspace.addDatabase.
We start adding GAMS sets using the method Database.addSet which takes the name and the dimension as arguments. The third argument is an optional explanatory text. A for-loop iterates through plants
and adds new records to the recently created Set instance i
using Set.addRecord.
Parameter instances can be added by using the method Database.addParameter. In this example we use the overloaded method which takes a list of Set instances instead of the dimension for creating a parameter with domain information.
As soon as all data is prepared in the Database, the method Database.export can be used to create a GDX file.
Import data from GDX
Example: transport_gdx
Data can be imported from a GDX file using Workspace.addDatabaseFromGDX. The method takes a path to a GDX file and creates a Database instance.
Reading the data from the Set i
into a cell of strings can be done as follows:
i
is retrieved by calling Database.getSet on gdxdb
. The returned Set object has an attribute records with an cell array of SetRecords. Each record can be asked for its keys.
You can do the same for Parameter. Instead of creating a cell, we want to have the data in the form of a containers.Map
. ParameterRecord can not only be asked for its keys, but also for its value. The following code snippet shows how to read the one dimensional parameter a
into a map.
For a key of multi dimensional symbol, we choose a dot based concatenation of keys.
Scalar can be read into a variable of type double by accessing the value of the first and only record.
Run a Job from file
Example: transport1
At first we create our workspace using Workspace ws = gams.control.Workspace();
. Afterwards, we can create a Job t1
using the Workspace.addJobFromGamsLib method and run it.
Apparently you can create a Job with any other gms file you might have created on your own as long as it is located in the current working directory. Then the Job t1
can be defined using the Workspace.addJobFromFile method.
Retrieve a solution from an output database
Example: transport1
The following lines create the solution output and illustrate the usage of the Job.outDB property to get access to the Database created by the Job.run method. To retrieve the content of variable x
we use the Database.getVariable method and the VariableRecord class.
Specify solver using Options
Example: transport1
The solver can be specified via the Options class and the Workspace.addOptions method. The Options.setAllModelTypes property sets xpress
as default solver for all model types which the solver can handle. Then we run our Job t1
with the new Options.
Run Job with solver option file and capture log
Example: transport1
At first we create the file xpress.opt
with content algorithm=barrier
which will be used as solver option file and is stored in the current working directory. Afterward we use Options just like in the preceding example and Options.optFile property to 1 to tell the solver to look for a solver option file. We specify the argument output
in order to stream the log of the Job into the file transport1_xpress.log
. When the output
argument is omitted then the log will be written to standard output.
Use include files
Example: transport2
In this example, as in many succeeding, the data text and the model text are separated into two different strings. Note that these strings data
and model
are using GAMS syntax.
At first we write an include file tdata.gms
that contains the data but not the model text:
Afterwards we create a Job using the Workspace.addJobFromString method. Options.defines is used like the the 'double dash' GAMS parameters, i.e. it corresponds to --incname=tdata
on the command line where incname is used as name for the include file in the model
string.
The string model contains the following lines to read in the data.
Set non-default working directory
Example: transport3
At first we create a new directory. Once this is done we can use this directory when creating the Workspace and make it the working directory.
Read data from string and export to GDX
Example: transport3
We read the data from the string data. Note that this contains no model but only data definition in GAMS syntax. By running the corresponding Job a Database is created that is available via the Job.outDB property. We can use the Database.export method to write the content of this database to a gdx file tdata.gdx
.
Run Job using data from GDX
Example: transport3
This works quite similar to the usage of an include file explained in transport2
- Use include files .
Note that there are some minor changes in the model due to the usage of a gdx instead of an include file.
Run Job using implicit database communication
Example: transport3
This example does basically the same as the two preceding examples together. We create two Jobs t3a
and t3b
where the first one contains only the data and the second one contains only the model without data. After running t3a
the corresponding Job.outDB can be read in directly just like a gdx file. Note that the database needs to be passed to the Job.run method as additional argument.
Define data using Matlab data structures
Example: transport4
We use cell arrays and containers.Map
to define Matlab data structures that correspond to the sets, parameters and tables used for the data definition in GAMS.
Prepare Database from Matlab data structures
Example: transport4
At first we create an empty Database db
using the Workspace.addDatabase method. Afterwards we prepare the database. To add a set to the database we use the Set class and the Database.addSet method with arguments describing the identifier, dimension and explanatory text. To add the records to the database we iterate over the elements of our Matlab data structure and add them by using the Set.addRecord method.
For parameters the procedure is pretty much the same. Note that the table that specifies the distances in GAMS can be treated as parameter with dimension 2 and that scalars can be treated as parameter with dimension 0.
The Job can be run like explained in the preceding example about implicit database communication.
Initialize Checkpoint by running Job
Example: transport5
The following lines of code conduct several operations. While the first line simply creates a Checkpoint, the second one uses the Workspace.addJobFromString method to create a Job containing the model text and data but no solve statement. Afterwards the run method gets the Checkpoint as argument. That means the Checkpoint cp
captures the state of the Job.
Initialize Job from Checkpoint
Example: transport5
Note that the string returned from function model
contains the entire model and data definition plus an additional demand multiplier and scalars for model and solve status but no solve statement:
In transport5
we create a list with eight different values for this demand multiplier.
For each entry of that list we create a Job t5
using the Workspace.addJobFromString method. Besides another string which resets the demand multiplier bmult
, specifies the solve statement and assigns values to the scalars ms
and ss
we pass the checkpoint cp as additional argument. This results in a Job combined from the checkpoint plus the content provided by the string. We run the Job and echo some interesting data from the Job.outDB using the Database.getParameter and Database.getVariable methods and the Symbol.record attribute plus the ParameterRecord.value and the VariableRecord.level properties.
- Note
- Some of the demand multipliers cause infeasibility. Nevertheless, GAMS keeps the incumbent objective function value. Therefore the model status and the solve status provide important information for a correct solution interpretation.
Create ModelInstance from Checkpoint
Example: transport7
In transport7
the usage of matlab::gams::control::ModelInstance is demonstrated.
At first Checkpoint cp
is created as in the preceding examples. Then we create the ModelInstance mi
using the Checkpoint.addModelInstance method. Note that the Job again contains no solve statement and the demand multiplier is already included with default value 1.
Modify parameter of ModelInstance using Modifier
Example: transport7
A ModelInstance uses a matlab::gams::control::ModelInstance::syncDB ModelInstance.syncDB
to maintain the data. We define bmult
as Parameter using the Parameter method and specify cplex
as solver. Afterwards the ModelInstance is instantiated with 3 arguments, the solve statement, Options opt
and Modifier bmult
. The Modifier means that bmult
is modifiable while all other parameters, variables and equations of ModelInstance mi
stay unchanged. We use the Parameter.addRecord method and the ParameterRecord.value property to assign a value to bmult
. That value can be varied afterwards using the Symbol.record property to reproduce our well-known example with different demand multipliers.
Modify variable of ModelInstance using Modifier
Example: transport7
We create a ModelInstance just like in the next to last example. We define x
as Variable and its upper bound as Parameter xup
. At the following ModelInstance.instantiate method Modifier has 3 arguments. The first one says that x
is modifiable, the second determines which part of the variable (lower bound, upper bound or level) can be modified and the third specifies the Parameter that holds the new value.
In the following loops we set the upper bound of one link of the network to zero, which means that no transportation between the corresponding plant and market is possible, and solve the modified transportation problem.
Create and use save/restart file
Example: transport11
In transport11
we demonstrate how to create and use a save/restart file. Usually such a file should be supplied by an application provider but in this example we create one for demonstration purpose. Note that the restart is launched from a Checkpoint. From the main function we call the function create_save_restart
giving it the current workspace settings and the desired file name as arguments.
In function create_save_restart
we create a workspace with the given workspace settings. Then we create a Job from a string. Note that the string given via basemodel
contains the basic definitions of sets without giving them a content (that is what $onempty
is used for). Afterwards we specify a Options to only compile the job but do not execute it. Then we create a Checkpoint cp
that is initialized by the following run of the Job and stored in the file given as argument to the function, in our case tbase
. This becomes possible because the Workspace.addCheckpoint method accepts identifiers as well as file names as argument.
So what you should keep in mind before we return to further explanations of the main function is, that the file tbase is now in the current working directory and contains a checkpoint. Now in the main function we define some data using Matlab data structures as we already did in transport4
before we create the Workspace and a Database.
Afterwards we set up the Database like we already did in transport4
. Once this is done we run a Job using this data plus the checkpoint stored in file tbase.
Note that the string from which we create Job t11
is different to the one used to prepare the checkpoint stored in tbase
and is only responsible for reading in the data from the Database correctly. The entire model definition is delivered by the Checkpoint cpBase
which is equal to the one we saved in tbase
.