This section will work through a simple C++ example in order to illustrate the use of the Gurobi C++ interface. The example builds a model, optimizes it, and outputs the optimal objective value. This section assumes that you are already familiar with the C++ programming language. If not, a variety of books are available for learning the language (for example, The C++ Programming Language, by Stroustrup).
Our example optimizes the following model:
maximize | x | + | y | + | 2 z | ||
subject to | x | + | 2 y | + | 3 z | ![]() |
4 |
x | + | y | ![]() |
1 | |||
x, y, z binary |
Example mip1_c++.cpp
This is the complete source code for our example (also available in <installdir>/examples/c++/mip1_c++.cpp)...
#include "gurobi_c++.h" using namespace std; int main(int argc, char *argv[]) { try { GRBEnv env = GRBEnv(); GRBModel model = GRBModel(env); // Create variables GRBVar x = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "x"); GRBVar y = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "y"); GRBVar z = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "z"); // Integrate new variables model.update(); // Set objective: maximize x + y + 2 z model.setObjective(x + y + 2 * z, GRB_MAXIMIZE); // Add constraint: x + 2 y + 3 z <= 4 model.addConstr(x + 2 * y + 3 * z <= 4, "c0"); // Add constraint: x + y >= 1 model.addConstr(x + y >= 1, "c1"); // Optimize model model.optimize(); cout << x.get(GRB_StringAttr_VarName) << " " << x.get(GRB_DoubleAttr_X) << endl; cout << y.get(GRB_StringAttr_VarName) << " " << y.get(GRB_DoubleAttr_X) << endl; cout << z.get(GRB_StringAttr_VarName) << " " << z.get(GRB_DoubleAttr_X) << endl; cout << "Obj: " << model.get(GRB_DoubleAttr_ObjVal) << endl; } catch(GRBException e) { cout << "Error code = " << e.getErrorCode() << endl; cout << e.getMessage() << endl; } catch(...) { cout << "Exception during optimization" << endl; } return 0; }
Example details
Let us now walk through the example, line by line, to understand how it achieves the desired result of optimizing the indicated model.
The example begins by including file gurobi_c++.h. Gurobi C++ applications should always start by including this file.
Creating the environment
The first executable statement in our example obtains a Gurobi environment (using the GRBEnv() constructor):
GRBEnv env = GRBEnv();Later calls to create an optimization model will always require an environment, so environment creation is typically the first step in a Gurobi application.
Creating the model
Once an environment has been created, the next step is to create a model. A Gurobi model holds a single optimization problem. It consists of a set of variables, a set of constraints, and the associated attributes (variable bounds, objective coefficients, variable integrality types, constraint senses, constraint right-hand side values, etc.). The first step towards building a model that contains all of this information is to create an empty model object:
GRBModel model = GRBModel(env);The constructor takes the previously created environment as its argument.
Adding variables to the model
The next step in our example is to add variables to the model.
// Create variables GRBVar x = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "x"); GRBVar y = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "y"); GRBVar z = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "z");Variables are added through the addVar() method on the model object. A variable is always associated with a particular model.
The first and second arguments to the addVar() call are the variable lower and upper bounds, respectively. The third argument is the linear objective coefficient (zero here - we'll set the objective later). The fourth argument is the variable type. Our variables are all binary in this example. The final argument is the name of the variable.
The addVar() method has been overloaded to accept several different argument lists. Please refer to the Gurobi Reference Manual for further details.
Updating the model - lazy modification
Model modifications in the Gurobi optimizer are done in a lazy fashion, meaning that the effects of the modifications are not seen immediately. This approach makes it easier to perform a sequence of model modifications, since the model doesn't change while it is being modified. However, lazy modifications do require you to manually integrate model changes when needed. This is done with the update method:
// Integrate new variables model.update();
Setting the objective
The next step in the example is to set the optimization objective:
// Set objective: maximize x + y + 2 z model.setObjective(x + y + 2 * z, GRB_MAXIMIZE);
The objective is built here using overloaded operators. The C++ API overloads the arithmetic operators to allow you to build linear and quadratic expression involving Gurobi variables.
The second argument indicates that the sense is maximization.
Adding constraints to the model
The next step in the example is to add the constraints. The first constraint is added here:
// Add constraint: x + 2 y + 3 z <= 4 model.addConstr(x + 2 * y + 3 * z <= 4, "c0");As with variables, constraints are always associated with a specific model. They are created using the addConstr() or addConstrs() methods on the model object.
We again use overloaded arithmetic operators to build the linear expression. The comparison operators are also overloaded to make it easy to build linear constraints.
The second argument to addConstr gives the (optional) constraint name.
The second constraint in our model is added with this similar call:
// Add constraint: x + y >= 1 model.addConstr(x + y >= 1, "c1");
Optimizing the model
Now that the model has been built, the next step is to optimize it:
// Optimize model model.optimize();This routine performs the optimization and populates several internal model attributes (including the status of the optimization, the solution, etc.).
Reporting results - attributes
Once the optimization is complete, we can query the values of the attributes. In particular, we can query the VarName and X attributes to obtain the name and solution value of each variable:
cout << x.get(GRB_StringAttr_VarName) << " " << x.get(GRB_DoubleAttr_X) << endl; cout << y.get(GRB_StringAttr_VarName) << " " << y.get(GRB_DoubleAttr_X) << endl; cout << z.get(GRB_StringAttr_VarName) << " " << z.get(GRB_DoubleAttr_X) << endl;
We can also query the ObjVal attribute on the model to obtain the objective value for the current solution:
cout << "Obj: " << model.get(GRB_DoubleAttr_ObjVal) << endl;
The names and types of all model, variable, and constraint attributes can be found in the Attributes section of the Gurobi Reference Manual.
Error handling
Errors in the Gurobi C++ interface are handled through the C++ exception mechanism. In the example, all Gurobi statements are enclosed inside a try block, and any associated errors would be caught by the catch block.
Building and running the example
To build and run the example, we refer the user to the files in <installdir>/examples/build. For Windows platforms, this directory contains C++_examples_2008.sln and C++_examples_2010.sln (Visual Studio 2008 and 2010 solution files for the C++ examples). Double-clicking on the solution file will bring up Visual Studio. Clicking on the 'mip1_c++' project, and then selecting Run from the Build menu will compile and run the example. For Linux or Mac OS platforms, the <installdir>/examples/build directory contains an example Makefile. Typing make mip1_c++ will build and run this example.
The C++ example directory <installdir>/examples/c++ contains a number of examples. We encourage you to browse and modify them in order to become more familiar with the Gurobi C++ interface. We also encourage you to read the Gurobi Example Tour for more information.