Pyomo is one of the modeling frameworks that support Gurobi. In this article, we describe how to use Gurobi through Pyomo. For more information, or when you encounter Pyomo-related issues, please have a look at the official Pyomo website.
Interfaces to Gurobi
Pyomo provides more than one interface to Gurobi. These interfaces are responsible for transforming your Pyomo model definition into a Gurobi model. Each interface provides slightly different features and has a different default behaviour. Therefore, picking the right interface is an important first step. These are the main interfaces available; more details are provided below.
-
Direct interface: Translates the model directly to
gurobipywithout generating a temporary file. Does not keep the model in memory after solving. Usually a good general-purpose choice. -
File-based interface: Pyomo generates an MPS or LP file describing your model. It will then read back that model using
gurobipy. -
Persistent interface: Works with
gurobipyas well, but keeps the model in memory after solving. Let's you make changes to your model, mark them explicitly and have Pyomo update the underlyinggurobipymodel object efficiently before resolving. - Auto-persistent interface (APPSI): Similar to the persistent interface, but automatically detects changes to the Pyomo model definition without marking them manually.
In the sections below, we will describe the details of each of those interfaces. All code snippets assume we have already constructed a Pyomo model, e.g.
import pyomo.environ as pyo
model = pyo.ConcreteModel()
model.x = pyo.Var(bounds=(0, None))
model.y = pyo.Var(bounds=(0, None))
model.c = pyo.Constraint(expr = model.x + model.y >= 1)
model.obj = pyo.Objective(expr = 2*model.x + 3*model.y, sense=pyo.minimize)Direct interface
Using the interface
To solve models using the direct interface, use one of the following options:
# Use one of these two options before solving
opt = pyo.SolverFactory("gurobi_direct")
opt = pyo.SolverFactory("gurobi", solver_io="direct")
opt.solve(model)Managing the Gurobi environment
By default, Pyomo relies on the global (default) Gurobi environment object. The downside is that this environment is created automatically upon first use, but not disposed of until your complete Python script finishes. This may lead to issues when other processes depend on the same license.
To solve that, you can ask Pyomo explicitly to dispose of the default environment and release all Pyomo-related resources. Remember, the default environment is shared by all Pyomo models.
opt = pyo.SolverFactory("gurobi_direct")
opt.solve(model)
opt.close_global() # Releases the Gurobi environmentAlternatively, you can ask Pyomo to create a dedicated environment for the Gurobi interface and explicitly release that when the environment is not needed anymore:
opt = pyo.SolverFactory("gurobi_direct", manage_env=True)
opt.solve(model)
opt.close() # Releases the Gurobi environmentSetting environment parameters
You can only set environment parameters when using the manage_env=True scenario. In other scenarios, the default environment is already constructed before parameters can be set. You can provide environment parameters through the options argument when constructing the interface:
opt = pyo.SolverFactory("gurobi_direct", manage_env=True, options={'ComputeServer':'localhost'})Setting model parameters
You can set model parameters (which influence the solver behaviour) through the options parameter of the solve() function:
opt.solve(model, options={'TimeLimit':60})Alternatively, you may set individual options as follows before calling the solve() function:
opt.options['TimeLimit'] = 60Exporting models
Pyomo can generate MPS and LP files without relying on Gurobi. This means the files can be generated already before installing Gurobi. However, the files may not always follow the same conventions that Gurobi applies. By default, variables and constraints get anonymized names with an increasing number. If you want to use the real variable and constraint names from your model, use the symbolic_solver_labels option:
# Generate an LP file; variables/constraints will be numbered x1, x2...
model.write("model.lp")
# Generate an MPS file; variables will have their original name
model.write("model.mps", io_options={"symbolic_solver_labels": True})Alternatively, if you want Gurobi to export the model for you, use the GURO_PAR_DUMP or ResultFile parameters.
Logging
By default, Pyomo captures the Gurobi output. Nothing is printed to the console or a log file.
- To show log output on screen, use
opt.solve(model, tee=True) - To generate a log file, use
opt.solve(model, logfile="test.log", keepfiles=True, tee=True) - Alternatively, call
opt.solve(model, options={"LogFile": "test.log"}, tee=True)
Supported model types
- LP, MIP, QP, QCP, MIQP, MIQCP are supported
- Piecewise-linear constraints are supported but transformed into SOS2 constraints by Pyomo before handing over to Gurobi
- Logical (including indicator) constraints are not supported unless you use the
gdp.bigmtransformations (out of scope for this article) - Non-linear functions like exp, sin, cos, log are not supported
Accessing the underlying Gurobi model object
You can access the underlying model object as follows. The example below computes the IIS.
opt.solve(model)
opt._solver_model.computeIIS()The same trick can be used for features like multi-objective and multi-scenario models. Note that you will need to access the individual gurobipy variables and constraints to request the results of such a call, as this information is not fed back to Pyomo variables and constraints. The interface provides two dict structures that help map Pyomo to Gurobi elements:
-
_pyomo_var_to_solver_var_mapfor variables; as a key, passmodel.x -
_pyomo_con_to_solver_con_mapfor constraints; as a key, passmodel.c
File-based interface
Using the interface
Use the file-based interface as in the example below. The default behaviour is to generate an LP file, but MPS files are supported too. When gurobipy is installed on your machine, it will be used for reading back the generated files and solving them. Otherwise, Pyomo will try to execute gurobi_cl, which will only be available when you have installed the full Gurobi Optimizer package.
# Use the LP file-based interface
opt = pyo.SolverFactory("gurobi")
# Use the MPS file-based interface
opt = pyo.SolverFactory("gurobi", solver_io="mps")Managing the Gurobi environment
This interface always uses the default Gurobi environment. You cannot customize the parameters of the environment. Instead, use a Gurobi license file.
Other notes
Many remarks about the direct interface apply to the file-based interface too:
- To change model parameters, simply pass them to the
solve()function. - You can export the model using
model.write() - Logging can be controlled for console and file output as before
- The same types of models are supported
However, the underlying Gurobi model object cannot be accessed.
Persistent interface
Using the interface
You can use the persistent interface as follows:
opt = pyo.SolverFactory("gurobi_persistent")
opt.set_instance(model)
opt.solve(tee=True)Updating the model
When you change your model after an initial solve, you need to explicitly mark these changes by informing the solver interface about each of them. This will ensure that the underlying Gurobi model is being updated correctly before resolving. The following changes are possible; refer to the Pyomo documentation for more details.
- When adding a variable
model.x, callpt.add_var(model.x)afterwards - When changing a variable bound, fixing or unfixing a particular variable
model.x, callopt.update_var(model.x) - When removing a variable
model.x, callopt.remove_var(model.x)before callingdel model.x - When you add a new constraint
model.c, callopt.add_constraint(model.c) - When you want to update a constraint
model.cusingmodel.c.set_value(), callopt.update_constraint(model.c)afterwards - When you remove a constraint
model.c, callopt.remove_constraint(model.c)before callingdel model.c - To replace the objective function, first call
model.obj.deactivate(). Then construct a new objective and callopt.set_objective(model.obj)afterwards
Other notes
The following functionality works the same as in the direct interface:
- You can let Pyomo manage the environment and provide initialization options
- You can provide model parameters using the
optionsargument of thesolve()function - You can export models to MPS and LP format
- The same notes on logging and supported model types apply
- You can access the underlying Gurobi model object using
opt._solver_modelagain
Auto-persistent interface
Using the interface
You can use the auto-persistent interface in the following way:
from pyomo.contrib.appsi.solvers import Gurobi
solver = Gurobi()
solver.solve(model)
solver.release_license()Managing the Gurobi environment
The interface always uses the default Gurobi environment. You cannot provide parameters for initializing this environment, so please use a license file. Make sure to call release_license() to free up your license; if you don't do this, the environment will stay alive (and block the license) until your Python process ends.
Setting model parameters
You can provide parameters for solving your model through the solver.gurobi_options dictionary:
from pyomo.contrib.appsi.solvers import Gurobi
solver = Gurobi()
solver.gurobi_options = { "TimeLimit": 60 }
solver.solve(model)
solver.release_license()Exporting models
The same methods described above will also work for the auto-persistent interface. Additionally, you can use the solver.write(filename) function, which relies on Gurobi for generating the file. This can be useful for debugging purposes to understand what the model looks like on the Gurobi side.
Logging
By default, Pyomo captures the Gurobi output. Nothing is printed to the console or a log file.
- To show log output on screen, set
solver.config.stream_solver = True - To generate a log file, use
solver.gurobi_options = { "LogFile": "test.log" }
Supported model types
The set of model types supported by this interface is the same as above.
Accessing the underlying Gurobi model object
The underlying Gurobi model is accessible through solver._solver_model as before. The interface provides two dict structures that help map Pyomo to Gurobi elements:
-
_pyomo_var_to_solver_var_mapfor variables; as a key, passid(model.x); note that theid()function is used here but not in the other interfaces -
_pyomo_con_to_solver_con_mapfor constraints; as a key, passmodel.c