This section will work through a simple example in order to illustrate the use of the Gurobi C++ API. The example builds a simple Mixed Integer Programming model, optimizes it, and outputs the optimal objective value.
A variety of books are available for learning the language (for example, The C++ Programming Language, by Stroustrup).
This example builds a trivial MIP model, solves it, and prints the solution.
The example
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 |
In the following sections, we will walk through the example, line by line, to understand how it achieves the desired result of optimizing the above model.
The complete source code for our example can be found in:
- Online: Example mip1_c++.cpp
- Distribution: <installdir>/examples/cpp/mip1_c++.cpp
Importing the Gurobi functions and classes
Creating the environment
The first executable statement in our example obtains a Gurobi environment (using the GRBEnv constructor):
// Create an environment GRBEnv env = GRBEnv(true); env.set("LogFile", "mip1.log"); env.start();
In this example, we requested an empty environment, choose a log file (using GRBEnv::set), and started the environment (using GRBEnv::start).
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 argument for GRBModel() is the environment which we have just created.
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 GRBModel::addVar method on the model object (or GRBModel::addVars if you wish to add more than one at a time). A variable is always associated with a particular model.
The first and second arguments to the GRBModel::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 GRBModel::addVar method has been overloaded to accept several different argument lists. Please refer to the Gurobi Reference Manual for further details.
Adding constraints to the model
The next step in the example is to add the linear 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 GRBModel::addConstr or GRBModel::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 easier to build constraints.
The second argument to GRBModel::addConstr gives the (optional) constraint name.
Again, this simple example builds the linear expression for the constraint in a single statement using an explicit list of terms. More complex programs will typically build the expression incrementally.
The second constraint in our model is added with this similar call:
// Add constraint: x + y >= 1 model.addConstr(x + y >= 1, "c1");
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 and GRBModel::setObjective. The C++ API overloads the arithmetic operators to allow you to build linear and quadratic expressions involving Gurobi variables.
The second argument indicates that the sense is maximization.
Note that while this simple example builds the objective in a single statement using an explicit list of terms, more complex programs will typically build it incrementally. For example:
GRBLinExpr obj = 0.0; obj += x; obj += y; obj += 2*z; model.setObjective(obj, GRB_MAXIMIZE);
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 the results
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 under the Attributes section of the documentation.
Error reporting
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:
try { // Formulate and solve model } catch(GRBException e) { cout << "Error code = " << e.getErrorCode() << endl; cout << e.getMessage() << endl; } catch(...) { cout << "Exception during optimization" << endl; }
Building and running the example
To build and run the example, we refer the user to the files in <installdir>/examples/build. The <installdir>/examples/build directory contains an example Makefile. Typing make mip1_c++ will build and run this example.
If you want to create your own project or makefile to build a C++ program that calls Gurobi, the details will depend on your platform and development environment, but we'd like to point out a few common pitfalls:
- A C++ program that uses Gurobi must link in both the Gurobi C++ library libgurobi_c++.a and the Gurobi C library libgurobi100.so.
- The Gurobi Linux distribution includes multiple C++ libraries. You may need to choose an alternate version (e.g., libgurobi_g++5.2.a), depending on the version of g++ you are using. You should consult the supported platform list for additional information.
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.
Comments
0 comments
Article is closed for comments.