Getting Started with Algebraic Modeling Languages
Algebraic modeling languages like JuMP, gurobipy, Pyomo, CVXPY, and PuLP (among others) are widely used for implementing mathematical models. For newcomers, the wide array of available tools may lead to several questions. Which language is best? How do the languages differ? What are their limitations? In this article, I demonstrate the similarity of several modeling languages by presenting example implementations of the Max-Flow problem. The point of this is to show that there is no need to fret – any tool will suffice for getting started with basic modeling. At the end of the article, I distill my experience with modeling languages into a set of bulleted tips for getting started with small projects and and expanding your repertoire to work on larger, more complex projects.
In this post, we leverage the Max-Flow optimization model as an example. For more details about this model, you may refer to my previous posts on the strong primal-dual relationship between Max-Flow and Min-Cut: formulations and implementations. In the former post, we motivate the following linear programming formulation:
Julia
Independent of the modeling tool, the sets and parameters of the Max-Flow problem may be extracted from a mapping of each edge $(i, j)$ to flow capacity $c_{ij}$ using standard Julia programming tools. Below, we show how this may be accomplished by reading that data from a CSV file.
|
|
JuMP
With the sets and parameters already deifned, implementing this problem in JuMP requires only a
few more lines of code. Much of the JuMP interface is based on macro invocations
(e.g., @JuMP.variable
). The purpose of macros is to manipulate existing code or generate new
code, a form of metaprogramming.
|
|
In the code snippets above, I include comments to indicate where exactly the sets, parameters, variables, constraints, and objective function are defined. As we see in the forthcoming sections, models are all generally implemented in this order regardless of the modeling language. Intuitively, this is because the problems are mathematically formulated in this order. For example, it is impossible to define an indexed variable without first defining the indexing set (both in formulation and implementation).
Python
Again, independent of the specific modeling tool used, the parameters may be defined using standard Python programming tools. This code is designed to precede each of the three Python-based implementations that follow.
|
|
gurobipy
A standard way to implement math programming models in gurobipy is via generator expressions. Below, I use this technique to define the flow balance and flow limit constraints. Also, note that gurobipy’s default behavior when declaring variables is to restrict them to the non-negative reals. In all of the other example implementations, we must explicitly declare that the flow variables are non-negative.
|
|
Pyomo
I leverage Pyomo’s decorator syntax to define the constraints and objective as Python functions.
|
|
CVXPY
CVXPY is a Python-based modeling language specifically for formulating convex optimization
problems that supports numpy
-like syntaxes. Of course, linear programming models are convex,
so CVXPY will work for this application. Compared to the other modeling langauges featured in
this post, CVXPY differs in that it uses 0-based indexing exclusively to index variables. We
circumvent this limitation by defining E_hat_map
, a dictionary that maps each edge
$(i, j)$ to an integer index. Another minor difference is that CVXPY model instantiation
occurs after the variables, constraints, and objective are defined.
|
|
PuLP
The PuLP implementation is similar in nature to that for gurobipy. The main difference is that
the constraints and objective here are added to the model using the addition assignment operator.
Under the hood, however, the operator invokes the maxflow.__iadd__
magic method, which is
not altogether that different from gurobipy’s maxflow.addConstrs
or maxflow.setObjective
method invocation.
|
|
Lessons
Of course, math programming models may be implemented in many other ways using these tools. I chose to present these specific implementations because they are similar in syntax and in style. For small projects, virtually any modeling language will suffice. For tackling larger projects or learning new tools, may advice is as follows.
- For getting acquainted with math modeling implementations, start with a small project and commit to a single modeling tool. Pick a tool that is compatible with a programming language you feel comfortable using. If you are indecisive, roll a die.
- Every modeling language ships with examples that showcase its capabilities. Treat those examples as self-guided tutorials. Experiment, tinker, and seek help as needed. In my experience, math modelers are quite friendly!
- Much of what allows one to be proficient at using a modeling language is first becoming proficient at one of its supported programming languages (e.g., Julia or Python). In my humble opinion, understanding how to massage data into an appropriate format is an undervalued skill, but one that is tremendously useful for efficiently preprocessing and postprocessing model data. Alternate between developing your modeling language and programming language proficiencies.
- If in the future you find yourself working on a project that demands a feature that is not supported by the modeling tool(s) you know, switch to a modeling tool that possesses that feature. In all likelihood, more than 90% of your already-developed skills are readily transferrable, so you should be able to ramp quickly.
- Repeat (2), (3), and (4) as necessary.
Let me know if these tips work for you or if you used another approach in the comments. Best wishes to you on your learning and, as always, happy modeling! 🙂
You May Also Like
Introduction to Pyomo and Gurobipy
This morning, I had the honor of hosting a workshop on behalf of the …
Max-Flow/Min-Cut Duality: Implementation & Visualization
In a previous post, we discussed the strong dual relationship between …
Pyomo: Graphs and Blocks
I had the pleasure yesterday of presenting a follow-up tutorial within …