The previous post considered using SciPy to solve a simple optimisation problem.
Install CVXPY
Use pip
to install the cvxpy
package. I suggest doing this in a virtual environment.
pip install cvxpy
You can also install support for various additional solvers. For example:
pip install "cvxpy[CVXOPT,GLPK,GUROBI,MOSEK]"
📢 You’ll need to get licenses to use the GUROBI and MOSEK solvers.
Solvers
I tried the following solvers and all produced reasonable results:
CLARABEL
CVXOPT
(rather slow!)GLPK
MOSEK
(see my installation notes for the MOSEK optimiser)OSQP
(which was used for the results reported here)SCS
andSCIPY
.
Optimisation with CVXPY
I set up the reference problem for CVXPY in a Jupter notebook. Here are the key components:
- Import a collection of packages.
- Specify the problem via a set of constants.
- Create CVXPY
Variable
objects for inflow, outflow and tank level. - Set up constraints (as a list of relationships on the
Variable
objects, which is intuitive). - Set up the objective function using the CVXPY
Minimize
class, specifying a term for the difference between outflow and demand, and smoothing terms for inflow and outflow. - Create a CVXPY
Problem
object, supplying the objective function object and the list of constraints. - Run the
solve()
method on theProblem
object.
Results
I ran the problem using three optimisers: SCS, OSQP and MOSEK. The results are presented below.
SCS
The SCS (Splitting Conic Solver) solver is nominally for solving large-scale convex quadratic cone problems. The solver is Open Source, with code available on GitHub.
The tank is initially a quarter full and the optimised solution has the inflow pump working hard to fill the tank at the start. The demand kicks in shortly after the start and is immediately satisfied. After the first demand cycle the inflow drops sharply to a lower rate that can satisfy all subsequent demand cycles. There is some (seemingly random) variability in the inflow rate during this second phase.
The SCS optimiser took 3.467 seconds to converge and the final value of the objective function was 7.279.
OSQP
The OSQP (Operator Splitting Quadratic Programming) solver is developed at the University of Oxford and is intended for solving quadratic programming problems. The solver is Open Source, with code available on GitHub.
The solution from the OSQP solver looks similar to that from the SCS solver.
The OSQP optimiser took 2.046 seconds to converge and the final value of the objective function was 7.515.
MOSEK
MOSEK provides a powerful and versatile optimisation package designed to solve a range of problem types. It is fast and reliable. The package is supported on Windows, macOS and Linux, and has interfaces for various other programming languages (notably both Python and R). It’s commercial software with academic and trial licenses available.
You can find my notes on installing the MOSEK solver here.
The results from the MOSEK solver are grossly similar to those from the previous two solvers, however, after the rapid drop in inflow the rate during the second phase is essentially constant (whereas there was some apparently random variability produced by the other solvers).
The OSQP optimiser took 0.485 seconds to converge and the final value of the objective function was 7.143.
Summary
Here’s a summary of results for a selection of optimisers:
Optimiser | Objective | Time (s) | Timestamp |
---|---|---|---|
The MOSEK optimiser achieved the best solution (lowest value of the objective function) and did so in the least time. For the purpose of comparison all of the optimisers have been run using their default values and no effort has been made to tune their performance (although in some cases the maximum number of iterations allowed was increased to ensure convergence).
The following post will use Pyomo to solve the same problem.