Model#
The model class is used to collect equations into groups and to label them so that they can be solved. It also allows specifying the problem type (e.g. LP, MIP etc.), sense of the problem (MIN, MAX, FEASIBILITY) and the objective of the problem at hand.
The overall syntax of a model is as follows:
from gamspy import Container, Variable, Equation, Model, Sense, Problem
m = Container()
z = Variable(m, "z") # objective variable
e1 = Equation(m, "e1")
e1[...] = <definition_of_the_equation>
e2 = Equation(m, "e2")
e2[...] = <definition_of_the_equation>
example_model = Model(m, name="dummy", equations=[e1,e2], problem=Problem.LP, sense=Sense.Max, objective=z)
Note
In case the name is not provided, it will be autogenerated.
Classification of Models#
Various types of problems can be solved with GAMS. Note that the type of the model must be known before it may be solved. The model types are briefly discussed in this section. GAMS checks that the model is in fact the type the user thinks it is, and issues explanatory error messages if it discovers a mismatch  for instance, that a supposedly linear model contains nonlinear terms. Some problems may be solved in more than one way, and the user has to choose which way to use. For instance, if there are binary or integer variables in the model, it can be solved either as a MIP or as a RMIP.
Model Type 
Model Type Description 

LP 
Linear Program 
NLP 
Nonlinear Program 
QCP 
Quadratically Constrained Program 
DNLP 
Discontinuous Nonlinear Program 
MIP 
Mixed Integer Program 
RMIP 
Relaxed Mixed Integer Program 
MINLP 
Mixed Integer Nonlinear Program 
RMINLP 
Relaxed Mixed Integer Nonlinear Program 
MIQCP 
Mixed Integer Quadratically Constrained Program 
RMIQCP 
Relaxed Mixed Integer Quadratically Constrained Program 
MCP 
Mixed Complementarity Problem 
CNS 
Constrained Nonlinear System 
MPEC 
Mathematical Programs with Equilibrium Constraints 
RMPEC 
Relaxed Mathematical Program with Equilibrium Constraints 
EMP 
Extended Mathematical Program 
MPSGE 
General Equilibrium 
All model types are exposed with Problem
enum but the problem type
can be specified as a string as well.
Also the direction types of the optimization (MIN, MAX, or FEASIBILITY) are
exposed with Sense
enum but it can be specified as a string similarly.
Matches for MCP Models#
Mixed Complementarity Problem (MCP) models can be defined as pairwise complementarities between
variables and equations. Model
accepts these pairwise complementarities through its matches
argument in its constructor.
p = Variable(m, "p", type=VariableType.POSITIVE, domain=c)
y = Variable(m, "y", type=VariableType.POSITIVE, domain=s)
i = Variable(m, "i", type=VariableType.POSITIVE, domain=h)
mkt = Equation(m, "mkt", domain=c)
profit = Equation(m, "profit", domain=s)
income = Equation(m, "income", domain=h)
mkt[c] = Sum(s, a[c, s] * y[s]) + Sum(h, e[c, h]) >= Sum(
h.where[esub[h] != 1],
(i[h] / Sum(cc, alpha[cc, h] * p[cc] ** (1  esub[h])))
* alpha[c, h]
* (1 / p[c]) ** esub[h],
) + Sum(h.where[esub[h] == 1], i[h] * alpha[c, h] / p[c])
profit[s] = Sum(c, a[c, s] * p[c]) >= 0
income[h] = i[h] >= Sum(c, p[c] * e[c, h])
hansen = Model(
m,
"hansen",
problem=Problem.MCP,
matches={mkt: p, profit: y, income: i},
)
One does not have to provide equations that are provided in the matches in the equations argument. An example MCP model can be found in the model library: HANSMCP.
Model Attributes#
Models have attributes that hold a variety of information, including
information about the results of a solve performed, a solve statement, the solution of a model,
information about certain features to be used by GAMS or the solver,
information passed to GAMS or the solver specifying various settings that are also subject to option statements.
Model Attribute 
Description 

num_domain_violations 
Number of domain violations 
algorithm_time 
Solver dependent timing information 
total_solve_time 
Elapsed time it took to execute a solve statement in total 
total_solver_time 
Elapsed time taken by the solver only 
num_iterations 
Number of iterations used 
marginals 
Indicator for marginals present 
max_infeasibility 
Maximum of infeasibilities 
mean_infeasibility 
Mean of infeasibilities 
status 
Integer number that indicates the model status 
num_nodes_used 
Number of nodes used by the MIP solver 
num_dependencies 
Number of dependencies in a CNS model 
num_discrete_variables 
Number of discrete variables 
num_infeasibilities 
Number of infeasibilities 
num_nonlinear_insts 
Number of nonlinear instructions 
num_nonlinear_zeros 
Number of nonlinear nonzeros 
num_nonoptimalities 
Number of nonoptimalities 
num_nonzeros 
Number of nonzero entries in the model coefficient matrix 
num_mcp_redefinitions 
Number of MCP redefinitions 
num_variables 
Number of variables 
num_bound_projections 
Number of bound projections during model generation 
objective_estimation 
Estimate of the best possible solution for a mixedinteger model 
objective_value 
Objective function value 
used_model_type 
Integer number that indicates the used model type 
model_generation_time 
Time GAMS took to generate the model in wallclock seconds 
solve_model_time 
Time the solver used to solve the model in seconds 
sum_infeasibilities 
Sum of infeasibilities 
solve_status 
Indicates the solver termination condition 
solver_version 
Solver version 
Solving a Model#
Model has a function named solve
that allows user to solve the specified model.
from gamspy import Container, Variable, Equation, Model, Sense, Problem, Options
m = Container()
z = Variable(m, "z") # objective variable
e1 = Equation(m, "e1")
e1[...] = <definition_of_the_equation>
e2 = Equation(m, "e2")
e2[...] = <definition_of_the_equation>
model = Model(m, "dummy", equations=[e1,e2], problem=Problem.LP, sense=Sense.Max, objective=z)
model.solve(solver="CONOPT", options=Options(iteration_limit=2), solver_options={"rtmaxv": "1.e12"})
In most cases, calling the solve
function of your model without any parameters is sufficient.
In this scenario, the default solver depending on the problem type, default options will be used. But for users
who requires a higher level of control can set the solver
to be used, general options and solver
specific options. All installed solvers on your system can be queried by running the following command:
gamspy list solvers
If you want to get all available solvers that you can install and use, the following command would give you the list of solvers that are available.:
gamspy list solvers a
Redirecting Output#
The output of GAMS after solving the model can be redirected to a file or to standard input by
specifying the output parameter of the solve
.:
from gamspy import Container, Variable, Equation, Model, Sense, Problem
import sys
m = Container()
z = Variable(m, "z") # objective variable
e1 = Equation(m, "e1")
e1[...] = <definition_of_the_equation>
e2 = Equation(m, "e2")
e2[...] = <definition_of_the_equation>
model = Model(m, "dummy", equations=[e1,e2], problem=Problem.LP, sense=Sense.Max, objective=z)
# redirect output to stdout
model.solve(output=sys.stdout)
# redirect output to a file
with open("my_out_file", "w") as file:
model.solve(output=file)
Solving Locally#
Models are solved locally (on your machine) by default.
Solving with GAMS Engine#
Synchronous Solve#
In order to send your model to be solved to GAMS Engine, you need to define the configuration of GAMS Engine.
This can be done by importing EngineClient
and creating an instance. Then, the user can pass it to the
solve
method and specify the backend as engine
.
from gamspy import Container, Variable, Equation, Model, Sense, Problem, EngineClient
m = Container()
z = Variable(m, "z") # objective variable
e1 = Equation(m, "e1")
e1[...] = <definition_of_the_equation>
e2 = Equation(m, "e2")
e2[...] = <definition_of_the_equation>
model = Model(m, "dummy", equations=[e1,e2], problem=Problem.LP, sense=Sense.Max, objective=z)
client = EngineClient(
host=os.environ["ENGINE_URL"],
username=os.environ["ENGINE_USER"],
password=os.environ["ENGINE_PASSWORD"],
namespace=os.environ["ENGINE_NAMESPACE"],
)
model.solve(solver="CONOPT", backend="engine", client=client)
Note
Extra model file paths that are provided through extra_model_files argument of EngineClient must be relative to the working directory. For example, if your working directory is “/foo/bar”, your extra model file path cannot be “/foo”.
Asynchronous Solve#
If you just want to send your jobs to GAMS Engine without blocking until the results are received, is_blocking parameter can be set to False in EngineClient.
Tokens of the submitted jobs are stored in client.tokens
from gamspy import Container, Variable, Equation, Model, Sense, Problem, EngineClient
m = Container()
...
...
<define_your_model>
...
...
client = EngineClient(
host=os.environ["ENGINE_URL"],
username=os.environ["ENGINE_USER"],
password=os.environ["ENGINE_PASSWORD"],
namespace=os.environ["ENGINE_NAMESPACE"],
)
for _ in range(3):
...
...
<changes_in_your_model>
...
...
model.solve(backend="engine", client=client)
print(client.tokens) # This prints all tokens for the submitted jobs
The results of the nonblocking jobs can be retrieved later. For example if want to retrieve the results of the last submitted job, we can do that following:
token = client.tokens[1]
client.job.get_results(token, working_directory="out_dir")
The results would be downloaded to the given working directory. The downloaded gdx file will have the same name with m.gdxOutputPath(). Then, if one wants to read the results, they can simply create a new Container and read the results from the downloaded gdx file:
gdx_out_path = os.path.join("out_dir", os.path.basename(m.gdxOutputPath()))
container = Container(load_from=gdx_out_path)
# or
container = Container()
container.read(gdx_out_path)
Solving with NEOS Server#
Synchronous Solve#
In order to send your model to be solved to NEOS Server, you need to create a NeosClient.
This can be done by importing NeosClient
and creating an instance. Then, the user can pass it to the
solve
method and specify the backend as neos
.
from gamspy import Container, Variable, Equation, Model, Sense, Problem, NeosClient
m = Container()
z = Variable(m, "z") # objective variable
e1 = Equation(m, "e1")
e1[...] = <definition_of_the_equation>
e2 = Equation(m, "e2")
e2[...] = <definition_of_the_equation>
model = Model(m, "dummy", equations=[e1,e2], problem=Problem.LP, sense=Sense.Max, objective=z)
client = NeosClient(
email=os.environ["NEOS_EMAIL"],
username=os.environ["NEOS_USER"],
password=os.environ["NEOS_PASSWORD"],
)
model.solve(backend="neos", client=client)
Defining your username and password is optional for NEOS Server backend but it is recommended since it allows you to investigate your models on NEOS web client. The environment variables can be set in a .env file or with export statements in command line. Example to run your model on NEOS Server without authentication:
NEOS_EMAIL=<your_email> python <your_script>
If one wants to investigate the results later on NEOS Server web client, they can provide the username and password in the same way:
NEOS_EMAIL=<your_email> NEOS_USER=<your_username> NEOS_PASSWORD=<your_password> python <your_script>
Asynchronous Solve#
If you just want to send your jobs to NEOS server without blocking until the results are received, is_blocking parameter can be set to False in NeosClient.
All submitted jobs are stored in client.jobs in case you want to reach to the job numbers and job passwords you already sent to the server.
from gamspy import Container, Variable, Equation, Model, Sense, Problem, NeosClient
m = Container()
...
...
<define_your_model>
...
...
client = NeosClient(
email=os.environ["NEOS_EMAIL"],
username=os.environ["NEOS_USER"],
password=os.environ["NEOS_PASSWORD"],
)
for _ in range(3):
...
...
<changes_in_your_model>
...
...
model.solve(backend="neos", client=client)
print(client.jobs) # This prints all job numbers and jon passwords as a list of tuples
The results of the nonblocking jobs can be retrieved later. For example if want to retrieve the results of the last submitted job, we can do that following:
job_number, job_password = client.jobs[1]
client.get_final_results(job_number, job_password)
client.download_output(
job_number, job_password, working_directory="my_out_directory"
)
The results would be downloaded to the given working directory. The downloaded gdx file will always have name “output.gdx”. Then, if one wants to read the results, they can simply create a new Container and read the results from the downloaded gdx file:
container = Container(load_from="my_out_directory/output.gdx")
# or
container = Container()
container.read("my_out_directory/output.gdx")
Terms of use for NEOS can be found here: Terms of use.
Solve Options#
Solve options can be specified as an gamspy.Options()
class. For example:
from gamspy import Container, Variable, Equation, Model, Sense, Problem, Options
m = Container()
...
...
Definition of your model
...
...
model = Model(m, "my_model", equations=m.getEquations(), problem=Problem.LP, sense=Sense.Max, objective=z)
model.solve(options=Options(iteration_limit=2))
Here is the list of options and their descriptions:
Option 
Description 
Possible Values 

cns 
Default cns solver 
Any solver installed in your system that can solve cns 
dnlp 
Default dnlp solver 
Any solver installed in your system that can solve dnlp 
emp 
Default emp solver 
Any solver installed in your system that can solve emp 
lp 
Default lp solver 
Any solver installed in your system that can solve lp 
mcp 
Default mcp solver 
Any solver installed in your system that can solve mcp 
minlp 
Default minlp solver 
Any solver installed in your system that can solve minlp 
mip 
Default mip solver 
Any solver installed in your system that can solve mip 
miqcp 
Default miqcp solver 
Any solver installed in your system that can solve miqcp 
mpec 
Default mpec solver 
Any solver installed in your system that can solve mpec 
nlp 
Default nlp solver 
Any solver installed in your system that can solve nlp 
qcp 
Default qcp solver 
Any solver installed in your system that can solve qcp 
rminlp 
Default rminlp solver 

rmip 
Default rmip solver 
Any solver installed in your system that can solve rmip 
rmiqcp 
Default rmiqcp solver 

rmpec 
Default rmpec solver 
Any solver installed in your system that can solve rmpec 
allow_suffix_in_equation 
Allow variables with suffixes in model algebra 
bool 
allow_suffix_in_limited_variables 
Allow domain limited variables with suffixes in model 
bool 
basis_detection_threshold 
Basis detection threshold 
float 
compile_error_limit 
Compile time error limiy 
int 
domain_violation_limit 
Domain violation limit solver default 
int 
gdx_file 
Name of the gdx file with all symbols 
str 
job_time_limit 
Elapsed time limit in seconds 
float 
job_heap_limit 
Maximum Heap size allowed in MB 
float 
hold_fixed_variables 
Treat fixed variables as constants 
bool 
integer_variable_upper_bound 
Set mode for default upper bounds on integer variables 
0: Set to +INF 1: Set to 100. 2: Set to 100 and write to the log if the level > 100 3: Same as 2 but issues an error if the level > 100 
iteration_limit 
Iteration limit of solver 
int 
keep_temporary_files 
Controls keeping or deletion of process directory and scratch files 
bool 
license 
Use alternative license file 
Path to the alternative license 
listing_file 
Listing file name 
Name of the listing file 
log_file 
Log file name 
Name of the log file 
variable_listing_limit 
Maximum number of columns listed in one variable block 
int 
equation_listing_limit 
Maximum number of rows listed in one equation block 
int 
node_limit 
Node limit in branch and bound tree 
int 
absolute_optimality_gap 
Absolute Optimality criterion solver default 
float 
relative_optimality_gap 
Relative Optimality criterion solver default 
float 
profile 
Execution profiling 
0: No profiling 1: Minimum profiling 2: Profiling depth for nested control structures 
profile_tolerance 
Minimum time a statement must use to appear in profile generated output 
float 
time_limit 
Wallclock time limit for solver 
float 
savepoint 
Save solver point in GDX file 
0: No point GDX file is to be saved 1: A point GDX file from the last solve is to be saved 2: A point GDX file from every solve is to be saved 3: A point GDX file from the last solve is to be saved 4: A point GDX file from every solve is to be saved 
seed 
Random number seed 
int 
report_solution 
Solution report print option 
0: Remove solution listings following solves 1: Include solution listings following solves 2: Suppress all solution information 
show_os_memory 
0: Show memory reported by internal accounting 1: Show resident set size reported by operating system 2: Show virtual set size reported by operating system 

solver_link_type 
Solver link option 

multi_solve_strategy 
Multiple solve management 
“replace”  “merge”  “clear” 
step_summary 
Summary of computing resources used by job steps 
bool 
suppress_compiler_listing 
Compiler listing option 
bool 
report_solver_status 
Solver Status file reporting option 
bool 
threads 
Number of threads to be used by a solver 
int 
trace_file 
Trace file name 
Name of the trace file 
trace_level 
Modelstat/Solvestat threshold used in conjunction with action=GT 
int 
trace_file_format 
Trace file format option 
0: Solver and GAMS step trace 1: Solver and GAMS exit trace 2: Solver trace only 3: Trace only in format used for GAMS performance world 5: Gams exit trace with all available trace fields 
write_listing_file 
Controls listing file creation 
bool 
zero_rounding_threshold 
The results of certain operations will be set to zero if abs(result) LE ZeroRes 
float 
report_underflow 
Report underflow as a warning when abs(results) LE ZeroRes and result set to zero 
bool 
Solver Options#
In addition to solve options, user can specify solver options to be used by the solver as a dictionary.:
from gamspy import Container, Variable, Equation, Model, Sense, Problem
m = Container()
...
...
Definition of your model
...
...
model = Model(m, "my_model", equations=m.getEquations(), problem=Problem.LP, sense=Sense.Max, objective=z)
model.solve(solver="CONOPT", solver_options=solver_options={"rtmaxv": "1.e12"})
For all possible solver options, please check the corresponding solver manual