The increasing sophistication of optimization technologies has led to the widespread adoption of commercial solvers in various industries. These commercial solutions offer advanced features like presolve techniques, warm starting capabilities, and distributed solving, making them more suitable for complex optimization models compared to their open-source counterparts.
Gurobi, a leading commercial solver developed by optimization pioneers Zonghao Gu, Edward Rothberg, and Robert Bixby, has been instrumental in solving many high-impact optimization problems, including the FCC’s bandwidth allocation project and Pennsylvania State Prison’s prisoner reassignment project.
This article explores how HorusLP, a software package designed for high-level declarative optimization modeling, seamlessly integrates with Gurobi’s API. This integration empowers users with an intuitive modeling experience while leveraging the advanced capabilities of Gurobi.
Understanding Optimization
For those unfamiliar with optimization or operations research, it involves using mathematical techniques to determine the optimal values of variables within a system of equations and constraints. To illustrate, consider the classic knapsack problem.
Imagine having a knapsack with a 15-pound weight limit. You have several items, each with its own weight and monetary value:
- Camera: 2 lbs, $5
- Figurine: 4 lbs, $7
- Cider: 7 lbs, $2
- Horn: 10 lbs, $10.
The goal is to maximize the total value of items carried in the knapsack without exceeding its weight limit. Feel free to create a story around this scenario!
Mathematically, this problem can be represented as:
| |
We can then apply optimization techniques to determine the best combination of items to carry. Examples of solving this problem using Python and the core HorusLP API are available in my previous articles.
While the underlying mathematical concepts are fascinating, they fall outside the scope of this article. For those interested in delving deeper, I recommend exploring resources like here and here, both provided by Gurobi.
Exploring Gurobi
Specialized software known as solvers are now used to tackle most optimization problems, replacing manual calculations. While many solvers effectively handle well-defined linear and integer programming problems, some stand out with advanced capabilities. These solvers can handle more complex problem classes, utilize cutting-edge mathematics for faster solutions, or employ distributed computing for large-scale problems. Such advanced features are often found in commercial solvers developed by companies specializing in high-performance optimization tools.
Gurobi is a prime example, widely adopted by governments, academic institutions, and companies across various sectors like finance and logistics. It consistently outperforms competitors in numerous benchmarks commonly used to benchmark commercial and open-source solvers.
Furthermore, Gurobi’s powerful Python API enables model construction directly within Python, granting modelers access to Python’s rich data manipulation libraries for enhanced efficiency. To illustrate, here’s how the knapsack problem can be modeled using the Gurobi Python API:
| |
Executing this code will yield the following output:
| |
Introducing HorusLP
HorusLP, born out of experiences in developing optimization algorithms, is an optimization modeling library addressing the shortcomings of existing libraries in handling complex, real-world optimization problems.
As opposed to the low-level imperative interfaces prevalent in most libraries, HorusLP provides higher-level tools to manage the intricacies of increasingly complex optimization models. This simplifies development and iteration with its powerful debugging and reporting features.
At its core, HorusLP employs an object-oriented architecture, leveraging Python’s object-oriented syntax to structure optimization models. This results in a more organized, modular, and readable codebase.
A more in-depth introduction to the core HorusLP library, including code examples, is available in this tutorial.
Bridging the Gap: HorusLP-Gurobi Integration
While HorusLP’s core API offers a user-friendly, high-level interface for building optimization models, its reliance on PuLP limits its access to some of Gurobi’s advanced functionalities.
This is where HorusLP-Gurobi comes in. Built using Gurobi’s Python API, it allows users to directly leverage Gurobi’s advanced features while maintaining consistency with the familiar HorusLP API.
One of the key principles guiding HorusLP-Gurobi’s development is maintaining consistency with the core HorusLP API. This ensures that users of open-source solvers can easily transition to Gurobi by simply installing the Gurobi API and adjusting import statements.
While simple models might require slightly more code in HorusLP-Gurobi compared to using the Python API imperatively, the object-oriented and declarative nature of HorusLP becomes increasingly beneficial as models grow in complexity. It enhances code readability, simplifies debugging, and promotes modularity.
Now, let’s dive into some code examples to illustrate the power of HorusLP-Gurobi.
Code Examples: Bringing It All Together
Basic HorusLP API
Thanks to the consistent API design, code from the HorusLP core tutorial can be easily ported over to HorusLP-Gurobi by simply changing the import statements. However, using HorusLP-Gurobi requires the installation of both the Gurobi optimizer and the Gurobi Python interface. You can obtain Gurobi by contacting them here.
Once Gurobi is installed, we can begin coding with HorusLP-Gurobi by installing the necessary package:
| |
With the installation complete, let’s revisit the knapsack problem and model it using HorusLP-Gurobi:
First, import the required libraries:
| |
Next, define the variables:
| |
Define the constraints using the constraints class:
| |
Define the objective in a similar manner:
| |
Define the problem:
| |
Instantiate the problem and call the solve function:
| |
Running this code should produce the following output:
| |
The output consists of two parts: the Gurobi solver output followed by the HorusLP output. The algorithm suggests taking the figurine and horn, resulting in a total weight of 14 pounds and a combined value of $17.
One advantage of using HorusLP with Gurobi is the automatic calculation and presentation of valuable information, including variable values, final objective value, and constraint values, in an easy-to-understand format.
Readers familiar with the previous article on HorusLP core will notice the near-identical API. This consistency is intentional, with the differences between solvers abstracted away in the superclass implementation.
This simple example serves as an introduction to HorusLP. More complex examples showcasing advanced features of HorusLP can be found in the previous article.
Unlocking Advanced Gurobi Features
Gurobi offers a plethora of advanced features for solving intricate problems, mostly accessible through the Model object. To ensure full compatibility with the Gurobi API, the model object is easily accessible from the problem class as model.
For instance, to write the MPS file of the knapsack model in Gurobi, you might use m.write('knapsack.mps'). With HorusLP-Gurobi, you can simply use:
| |
This will generate the MPS file in your working directory.
This interface grants access to other advanced Gurobi features such as IIS calculation, callback creation, and providing variable hints.
Empowering Optimization with HorusLP-Gurobi
In this article, we explored HorusLP-Gurobi, an integration of the HorusLP library with the Gurobi Python API. This combination empowers users with the debugging and reporting capabilities of HorusLP while unlocking the advanced features of Gurobi.
Whether you’re an existing Gurobi user or someone looking to leverage Gurobi’s optimization power, I encourage you to give HorusLP-Gurobi a try! You can find code examples, provide feedback, or contribute to the project on GitHub.