The Gurobi interactive shell allows you to perform hands-on interaction and experimentation with optimization models. You can read models from files, perform complete or partial optimization runs on them, change parameters, modify the models, reoptimize, and so on. The Gurobi shell is actually a set of extensions to the Python shell. Python is a rich and flexible programming language, and any capabilities that are available from Python are also available from the Gurobi shell. We'll touch on these capabilities here, but we encourage you to explore the help system and experiment with the interface in order to gain a better understanding of what is possible.
Note that we also provide a lightweight command line to allow you to run quick and easy tests.
Important note for AIX users: due to limited Python support on AIX, our AIX port does not include the Interactive Shell or the Python interface. You can use the command line, or the C, C++, or Java interfaces.
We will now work through a few simple examples of how the Gurobi shell might be used, in order to give you a quick introduction to its capabilities. More thorough documentation on this and other interfaces is available in the Gurobi Reference Manual.
Reading and optimizing a model
There are three ways to start the Gurobi Interactive Shell from Windows:
> gurobi.bat (or gurobi.sh for Linux or Mac OS) Gurobi Interactive Shell, Version 5.0.0 Copyright (c) 2012, Gurobi Optimization, Inc. Type "help()" for help gurobi> m = read('c:/gurobi500/win64/examples/data/p0033.mps') Read MPS format model from file c:/gurobi500/win64/examples/data/p0033.mps Reading time = 0.00 seconds P0033: 16 Rows, 33 Columns, 98 NonZeros gurobi> m.optimize() Optimize a model with 16 Rows, 33 Columns and 98 NonZeros Presolve removed 3 rows and 5 columns Presolve time: 0.00s Presolved: 13 Rows, 28 Columns, 91 Nonzeros Objective GCD is 1 Found heuristic solution: objective 3412.0000000 Root relaxation: objective 2.838547e+03, 24 iterations, 0.00 seconds Nodes | Current Node | Objective Bounds | Work Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time 0 0 2838.54674 0 6 3412.00000 2838.54674 16.8% - 0s H 0 0 3347.0000000 2838.54674 15.2% - 0s 0 0 2928.65799 0 8 3347.00000 2928.65799 12.5% - 0s H 0 0 3095.0000000 2928.65799 5.37% - 0s 0 0 2954.18420 0 15 3095.00000 2954.18420 4.55% - 0s 0 0 3008.37500 0 12 3095.00000 3008.37500 2.80% - 0s 0 0 3017.50000 0 10 3095.00000 3017.50000 2.50% - 0s 0 0 3023.52381 0 6 3095.00000 3023.52381 2.31% - 0s 0 0 3023.52381 0 6 3095.00000 3023.52381 2.31% - 0s 0 0 3023.52381 0 6 3095.00000 3023.52381 2.31% - 0s * 3 0 2 3089.0000000 3089.00000 0.0% 3.3 0s Cutting planes: Cover: 5 MIR: 4 Explored 4 nodes (74 simplex iterations) in 0.02 seconds Thread count was 8 (of 8 available processors) Optimal solution found (tolerance 1.00e-04) Best objective 3.0890000000e+03, best bound 3.0890000000e+03, gap 0.0%
The read() command reads a model from a file and returns a Model object. In the example, that object is placed into variable m. There is no need to declare variables in the Python language; you simply assign a value to a variable.
Note that read() accepts wildcard characters, so you could also have said:
gurobi> m = read('c:/gurobi500/win64/*/*/p0033*')
Note also that Gurobi commands that read or write files will also function correctly with compressed files. If gzip, bzip2, or 7zip are installed on your machine and available in your default path, then you simply need to add the appropriate suffix (.gz, .bz2, .zip, or .7z) to the file name to read or write compressed versions.
The next statement in the example, m.optimize(), invokes the optimize method on the Model object (you can obtain a list of all methods on Model objects by typing help(Model) or help(m)). The Gurobi optimization engine finds an optimal solution with objective 3089.
Inspecting the solution
Once a model has been solved, you can inspect the values of the model variables in the optimal solution with the printAttr() method on the Model object:
gurobi> m.printAttr('X') Variable X --------------------- C157 1 C163 1 C164 1 C166 1 C170 1 C174 1 C177 1 C178 1 C180 1 C181 1 C182 1 C183 1 C184 1 C185 1 C186 1This routine prints all non-zero values of the specified attribute X. Attributes play a major role in the Gurobi optimizer. We'll discuss them in more detail shortly.
You can also inspect the results of the optimization at a finer grain by retrieving a list of all the variables in the model using the getVars() method on the Model object (m.getVars() in our example):
gurobi> v = m.getVars() gurobi> print len(v) 33The first command assigns the list of all Var objects in model m to variable v. The Python len() command gives the length of the array (our example model p0033 has 33 variables). You can then query various attributes of the individual variables in the list. For example, to obtain the variable name and solution value for the first variable in list v, you would issue the following command:
gurobi> print v[0].VarName, v[0].X C157 1.0You can type help(Var) or help(v[0]) to get a list of all methods on a Var object. You can type help(GRB.Attr) to get a list of all attributes.
Simple model modification
We will now demonstrate a simple model modification. Imagine that you only want to consider solutions where variable C157 takes value 0.0. You can find a solution that satisfies this additional constraint by tightening the upper bound of the first variable to 0.0. This is done by setting the ub attribute on the variable...
gurobi> v = m.getVars() gurobi> v[0].ub = 0
The Gurobi optimizer keeps track of the state of the model, so it knows that the currently loaded solution is not necessarily optimal for the modified model. When you invoke the optimize() method again, it performs a new optimization on the modified model...
gurobi> m.optimize() Optimize a model with 16 Rows, 33 Columns and 98 NonZeros Presolve removed 3 rows and 6 columns Presolve time: 0.00s Presolved: 13 Rows, 27 Columns, 88 Nonzeros Objective GCD is 1 Root relaxation: objective 2.839492e+03, 21 iterations, 0.00 seconds Nodes | Current Node | Objective Bounds | Work Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time 0 0 2839.49184 0 5 - 2839.49184 - - 0s 0 0 2953.32500 0 2 - 2953.32500 - - 0s 0 0 2994.81212 0 11 - 2994.81212 - - 0s 0 0 3060.38462 0 2 - 3060.38462 - - 0s H 0 0 3095.0000000 3060.38462 1.12% - 0s 0 0 infeasible 0 3095.00000 3094.00310 0.03% - 0s Cutting planes: Gomory: 1 Cover: 5 MIR: 5 Explored 0 nodes (46 simplex iterations) in 0.01 seconds Thread count was 8 (of 8 available processors) Optimal solution found (tolerance 1.00e-04) Best objective 3.0950000000e+03, best bound 3.0950000000e+03, gap 0.0%
When variable C157 is forced to take a value of zero, the minimum possible objective value for the model increases from 3089 to 3095. A simple check confirms that the new upper bound is respected:
gurobi> print v[0].x 0.0
Simple experimentation with a more difficult model
Let us now consider a more difficult model, glass4.mps. Again, we read the model and begin the optimization:
gurobi> m = read('c:/gurobi500/win64/examples/data/glass4') Read MPS format model from file c:/gurobi500/win64/examples/data/glass4.mps Reading time = 0.00 seconds glass4: 396 Rows, 322 Columns, 1815 NonZeros gurobi> m.optimize() Optimize a model with 396 Rows, 322 Columns and 1815 NonZeros Presolve removed 4 rows and 5 columns Presolve time: 0.00s Presolved: 392 Rows, 317 Columns, 1815 Nonzeros Found heuristic solution: objective 3.691696e+09 Root relaxation: objective 8.000024e+08, 72 iterations, 0.00 seconds Nodes | Current Node | Objective Bounds | Work Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time 0 0 8.0000e+08 0 72 3.6917e+09 8.0000e+08 78.3% - 0s 0 0 8.0000e+08 0 72 3.6917e+09 8.0000e+08 78.3% - 0s 0 0 8.0000e+08 0 72 3.6917e+09 8.0000e+08 78.3% - 0s 0 0 8.0000e+08 0 72 3.6917e+09 8.0000e+08 78.3% - 0s 0 2 8.0000e+08 0 72 3.6917e+09 8.0000e+08 78.3% - 0s H 769 732 2.800024e+09 8.0000e+08 71.4% 5.2 0s H 834 781 2.666693e+09 8.0000e+08 70.0% 5.3 0s H 1091 984 2.475023e+09 8.0000e+08 67.7% 5.1 0s H 1092 986 2.400020e+09 8.0000e+08 66.7% 5.1 0s H 1092 984 2.380021e+09 8.0000e+08 66.4% 5.1 0s H 1095 988 2.350020e+09 8.0000e+08 66.0% 5.1 0s * 1845 1543 94 2.316685e+09 8.0000e+08 65.5% 4.9 0s * 2131 1627 126 2.150018e+09 8.0000e+08 62.8% 4.8 0s H 2244 1580 2.100019e+09 8.0000e+08 61.9% 4.8 0s H 2248 1341 1.900018e+09 8.0000e+08 57.9% 5.0 0s H 3345 1816 1.900018e+09 8.0000e+08 57.9% 4.1 0s H 3346 1744 1.900017e+09 8.0000e+08 57.9% 4.1 0s H15979 10383 1.900017e+09 8.0000e+08 57.9% 2.5 1s H19540 13051 1.900016e+09 8.0000e+08 57.9% 2.4 1s *21124 13489 101 1.866683e+09 8.0000e+08 57.1% 2.4 1s *23011 14690 100 1.850015e+09 8.0000e+08 56.8% 2.3 1s *25630 15679 143 1.800016e+09 8.0000e+08 55.6% 2.3 1s *28365 15421 113 1.700015e+09 8.0000e+08 52.9% 2.3 1s H29910 16333 1.700014e+09 8.0000e+08 52.9% 2.3 1s *30582 16765 124 1.700014e+09 8.0000e+08 52.9% 2.3 1s *33238 16251 92 1.677794e+09 8.0000e+08 52.3% 2.3 1s *37319 18258 85 1.633349e+09 8.0000e+08 51.0% 2.2 1s H40623 19584 1.600015e+09 8.0000e+08 50.0% 2.3 2s 81781 42951 1.1000e+09 49 51 1.6000e+09 8.0001e+08 50.0% 2.2 5s 199990 100088 1.6000e+09 82 28 1.6000e+09 8.0001e+08 50.0% 2.3 10s *242810 116891 97 1.600015e+09 8.2001e+08 48.8% 2.3 11s *243703 116786 95 1.600014e+09 8.2001e+08 48.8% 2.3 11s Interrupt request received Explored 255558 nodes (588336 simplex iterations) in 12.36 seconds Thread count was 8 (of 8 available processors) Solve interrupted Best objective 1.6000142000e+09, best bound 8.5000490000e+08, gap 46.8752%
It quickly becomes apparent that this model is quite a bit more difficult than p0033. The optimal solution is actually 1,200,000,000, but finding that solution takes a while. After letting the model run for 10 seconds, we interrupt the run (by hitting CTRL-C, which produces the Interrupt request received message) and consider our options. Typing m.optimize() would resume the run from the point at which it was interrupted.
Changing parameters
Rather than continuing optimization on a difficult model like glass4, it is sometimes useful to try different parameter settings. When the lower bound moves slowly, as it does on this model, one potentially useful parameter is MIPFocus, which adjusts the high-level MIP solution strategy. Let us now set this parameter to value 1, which changes the focus of the MIP search to finding good feasible solutions. There are two ways to change the parameter value. You can either use method m.setParam():
gurobi> m.setParam('MIPFocus', 1) Changed value of parameter MIPFocus to 1 Prev: 0 Min: 0 Max: 3 Default: 0...or you can use the m.Params class...
gurobi> m.params.MIPFocus = 1 Changed value of parameter MIPFocus to 1 Prev: 0 Min: 0 Max: 3 Default: 0Once the parameter has been changed, we call m.reset() to reset the optimization on our model and then m.optimize() to start a new optimization run:
gurobi> m.reset() gurobi> m.optimize() Optimize a model with 396 Rows, 322 Columns and 1815 NonZeros Presolve removed 4 rows and 5 columns Presolve time: 0.00s Presolved: 392 Rows, 317 Columns, 1815 Nonzeros Found heuristic solution: objective 3.691696e+09 Root relaxation: objective 8.000024e+08, 72 iterations, 0.00 seconds Nodes | Current Node | Objective Bounds | Work Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time 0 0 8.0000e+08 0 72 3.6917e+09 8.0000e+08 78.3% - 0s 0 0 8.0000e+08 0 72 3.6917e+09 8.0000e+08 78.3% - 0s 0 0 8.0000e+08 0 72 3.6917e+09 8.0000e+08 78.3% - 0s 0 0 8.0000e+08 0 73 3.6917e+09 8.0000e+08 78.3% - 0s H 0 0 3.075022e+09 8.0000e+08 74.0% - 0s H 0 0 3.020023e+09 8.0000e+08 73.5% - 0s 0 0 8.0000e+08 0 76 3.0200e+09 8.0000e+08 73.5% - 0s 0 0 8.0000e+08 0 75 3.0200e+09 8.0000e+08 73.5% - 0s H 0 0 2.550024e+09 8.0000e+08 68.6% - 0s H 0 2 2.175020e+09 8.0000e+08 63.2% - 0s 0 2 8.0000e+08 0 75 2.1750e+09 8.0000e+08 63.2% - 0s H 95 98 2.150020e+09 8.0000e+08 62.8% 4.6 0s H 96 98 2.120018e+09 8.0000e+08 62.3% 4.6 0s H 101 103 2.116687e+09 8.0000e+08 62.2% 4.5 0s H 110 103 2.100017e+09 8.0000e+08 61.9% 4.3 0s H 352 325 2.000018e+09 8.0000e+08 60.0% 4.2 0s H 406 375 1.991686e+09 8.0000e+08 59.8% 4.0 0s H 1074 888 1.981836e+09 8.0000e+08 59.6% 3.5 0s H 1078 889 1.966686e+09 8.0000e+08 59.3% 3.5 0s H 1107 878 1.900018e+09 8.0000e+08 57.9% 3.5 0s H 1696 1125 1.800017e+09 8.0000e+08 55.6% 3.4 0s H 1845 1146 1.800017e+09 8.0000e+08 55.6% 4.2 1s H 1863 1087 1.733350e+09 8.0000e+08 53.8% 4.3 1s H 2353 1273 1.733350e+09 8.0000e+08 53.8% 4.3 1s H 2517 1299 1.700016e+09 8.0000e+08 52.9% 4.3 1s H 2598 1248 1.666682e+09 8.0000e+08 52.0% 4.3 1s H 2733 1252 1.633349e+09 8.0000e+08 51.0% 4.2 1s 14259 7927 1.5000e+09 85 28 1.6333e+09 8.0000e+08 51.0% 3.5 5s 24846 14278 1.1000e+09 49 55 1.6333e+09 8.0001e+08 51.0% 3.5 10s H25035 13985 1.600016e+09 8.0001e+08 50.0% 3.5 10s H25066 14020 1.600016e+09 8.0001e+08 50.0% 3.5 10s H25072 13532 1.583350e+09 8.0001e+08 49.5% 3.5 10s H26218 14083 1.575016e+09 8.0001e+08 49.2% 3.5 10s H26326 14118 1.566682e+09 8.0001e+08 48.9% 3.5 10s H26577 13650 1.525016e+09 8.0001e+08 47.5% 3.5 10s Interrupt request received Cutting planes: Gomory: 6 Implied bound: 26 MIR: 60 Explored 30546 nodes (107810 simplex iterations) in 11.81 seconds Thread count was 8 (of 8 available processors) Solve interrupted Best objective 1.5250155750e+09, best bound 8.0000520000e+08, gap 47.5412%
Results are consistent with our expectations. We find a better solution sooner by shifting the focus towards finding feasible solutions (objective value 1.525e9 versus 1.6e9).
The setParam() method is designed to be quite flexible and forgiving. It accepts wildcards as arguments, and it ignores character case. Thus, the following commands are all equivalent:
gurobi> m.setParam('NODELIMIT', 100) gurobi> m.setParam('NodeLimit', 100) gurobi> m.setParam('Node*', 100) gurobi> m.setParam('N???Limit, 100)You can use wildcards to get a list of matching parameters:
gurobi> m.setParam('*Cuts', 2) Matching parameters: ['Cuts', 'CliqueCuts', 'CoverCuts', 'FlowCoverCuts', 'FlowP athCuts', 'GUBCoverCuts', 'ImpliedCuts', 'MIPSepCuts', 'MIRCuts', 'ModKCuts', 'NetworkCuts', 'SubMIPCuts', 'ZeroHalfCuts']
Note that Model.Params is a bit less forgiving than setParam(). In particular, wildcards are not allowed with this approach. You don't have to worry about capitalization of parameter names in either approach, though, so m.params.Heuristics and m.params.heuristics are equivalent.
The full set of available parameters can be browsed using the paramHelp() command. You can obtain further information on a specific parameter (e.g., MIPGap) by typing paramHelp('MIPGap').
Working with multiple models
The Gurobi shell allows you to work with multiple models simultaneously. For example...
gurobi> a = read('c:/gurobi500/win64/examples/data/p0033') Read MPS format model from file c:/gurobi500/win64/examples/data/p0033.mps Reading time = 0.00 seconds P0033: 16 Rows, 33 Columns, 98 NonZeros. gurobi> b = read('c:/gurobi500/win64/examples/data/stein9') Read MPS format model from file c:/gurobi500/win64/examples/data/stein9.mps Reading time = 0.00 seconds STEIN9: 13 Rows, 9 Columns, 45 NonZeros.The models() command gives a list of all active models.
gurobi> models() Currently loaded models: a : <gurobi.Model MIP instance P0033: 16 constrs, 33 vars> b : <gurobi.Model MIP instance STEIN9: 13 constrs, 9 vars>
Note that parameters can be set for a particular model with the Model.setParam() method or the Model.Params class, or they can be changed for all models in the Gurobi shell by using the global setParam() method.
Help
The interactive shell includes an extensive help facility. To access it, simply type help() at the prompt. As previously mentioned, help is available for all of the important objects in the interface. For example, as explained in the help facility, you can type help(Model), help(Var), or help(Constr). You can also obtain detailed help on any of the available methods on these objects. For example, help(Model.setParam) gives help on setting model parameters. You can also use a variable, or a method on a variable, to ask for help. For example, if variable m contains a Model object, then help(m) is equivalent to help(Model), and help(m.setParam) is equivalent to help(Model.setParam).
Interface customization
The Gurobi interactive shell lives within a full featured scripting language. This allows you to perform a wide range of customizations to suit your particular needs. Creating custom functions requires some knowledge of the Python language, but you can achieve a lot by using a very limited set of language features.
Let us consider a simple example. Imagine that you store your models in a certain directory on your disk. Rather than having to type the full path whenever you read a model, you can create your own custom read method:
gurobi> def myread(filename): ....... return read('/home/john/models/'+filename)Note that the indentation of the second line is required.
Defining this function allows you to do the following:
gurobi> m = myread('stein9') Read MPS format model from file /home/john/models/stein9.mps
If you don't want to type this function in each time you start the Gurobi shell, you can store it in a file. The file would look like the following:
from gurobipy import * def myread(filename): return read('/home/john/models/'+filename)The from gurobipy import * line is required in order to allow you to use the read method from the Gurobi shell in your custom function. The name of your customization file must end with a .py suffix. If the file is named custom.py, you would then type:
gurobi> from custom import *in order to import this function. One file can contain as many custom functions as you'd like (see custom.py in <installdir>/examples/python for an example). If you wish to make site-wide customizations, you can also customize the gurobi.py file that is included in <installdir>/lib.
Customization through callbacks
Another type of customization we'd like to touch on briefly can be achieved through Gurobi callbacks. Callbacks allow you to track the progress of the optimization process. For the sake of our example, let's say you want the MIP optimizer to run for 10 seconds before quitting, but you don't want it to terminate before it finds a feasible solution. The following callback method would implement this condition:
from gurobipy import * def mycallback(model, where): if where == GRB.Callback.MIP: time = model.cbGet(GRB.Callback.RUNTIME) best = model.cbGet(GRB.Callback.MIP_OBJBST) if time > 10 and best < GRB.INFINITY: model.terminate()
Once you import this function ('from custom import *'), you can then say m.optimize(mycallback) to obtain the desired termination behavior. Alternatively, you could define your own custom optimize method that always invokes the callback:
def myopt(model): model.optimize(mycallback)This would allow you to say myopt(m).
You can pass arbitrary data into your callback through the model object. For example, if you set m._mydata = 1 before calling optimize(), you can query m._mydata inside your callback function. Note that the names of user data fields must begin with an underscore.
This callback example is included in <installdir>/examples/python/custom.py. Type from custom import * to import the callback and the myopt() function.
You can type help(GRB.Callback) for more information on callbacks. You can also refer to the Callback class documentation in the Gurobi Reference Manual.
The Gurobi Python Interface for Python Users
While the Gurobi installation includes everything you need to use Gurobi from within Python, we understand that some users would prefer to use Gurobi from within their own Python environment. To install the gurobipy module directly into your Python environment, open a cmd prompt in Windows or a terminal window in Linux or Mac OS, change your current directory to the Gurobi <installdir> (the directory that contains the file setup.py), and issue the following command:
python setup.py installOn Linux or Mac OS systems, unless you are using your own private Python installation, you will need to run this command as super-user. Once gurobipy is successfully installed, you can type import gurobipy or from gurobipy import * from your Python shell and access all of the Gurobi classes and methods.
Note that for this installation to succeed, your Python environment must be compatible with the Gurobi Python module. You should only install 32-bit Gurobi libraries into a 32-bit Python shell (similarly for 64-bit versions). In addition, your Python version must be compatible. With this release, gurobipy can be used with Python 2.6, or 2.7 on Windows and Linux, and with Python 2.6 on Mac OS.
An interactive interface can be too heavy if you simply want to optimize a model stored in a file. We also provide a simple command-line optimizer, gurobi_cl, for doing quick testing. This program allows you to modify Gurobi parameters and save the solution of the problem to a file.
Parameter changes can be specified in two ways. The first approach is to include one or more ParamName=NewValue commands on the command line. The last argument to gurobi_cl should always be the file name. For example, to solve model stein9.mps on one thread and put the solution to file stein9.sol, you would use the following command:
gurobi_cl Threads=1 ResultFile=stein9.sol stein9.mps.gz
The second approach is to place parameter changes in file gurobi.env in the current working directory. Before performing the optimization, gurobi_cl looks for this file and reads any parameter changes contained therein. Parameter settings are stored one per line, with the parameter name first, followed by at least one space, followed by the desired value. Lines beginning with the # sign are comments and are ignored. To give an example, the following (Linux) commands:
echo "Threads 1" > gurobi.env gurobi_cl stein9.mps.gzwould read the new value of the Threads parameter from file gurobi.env and then optimize model stein9.mps using one thread. Note that if the same parameter is modified on the command line and in gurobi.env, the command line value will be used.
The distribution includes a sample gurobi.env file (in the bin directory). The sample includes every parameter, with the default value for each, but with all settings commented out.