I read through the code of several solvers before developing Tulip.jl.
To be honest, unless you are yourself developing a solver/interface, or need to reproduce an author's implementation, there is probably a better use of your time than reading solvers' source code.
Reading the user guide or, when applicable, the paper(s) that describe the software's algorithmic components should definitely be your starting point.
In addition, as Kuifje mentions in their comment, begin familiar with a solver's interface makes it easier to understand its inner workings.
That being said, I have found that, at least for linear programming, most of the algorithmic components are, overall, fairly similar.
Differences stem from particular choices of data structures and how modular the code is.
To me, the most important part is knowing what you are looking for in the code.
Is it to understand an algorithm's implementation? Specific data structures? How solvers parameters are handled?
This will help focus your work and not get lost.
Here are another few factors I would take into account (I guess several are not specific to optimization software) when choosing which solvers to look at:
Just don't expect to get much from un-documented source code.
Is the solver maintained?
If a solver is maintained by several people, then those people will have looked at the code. That's a good indication that the source is readable, at least enough so that others have been able to modify it.
It may sound obvious, but reading a language you're familiar with makes the task way easier.
Most solvers are written in C or C++, some old ones are in Fortran, and I know a few in Julia.
Similar paradigms may result in completely different implementations in different languages, though the basic ideas will most likely remain the same.
Which problems are supported?
Data structures (and algorithms) vary widely between a linear programming solver and a non-linear programming one.
The former only needs matrices and vectors, the latter will likely include automatic differentiation tools, appropriate data structures for gradient and hessian computations.
Mixed-integer solvers add a layer of complexity with branching trees, etc...
Constraint Programming are another category altogether.
Thus, know what you're searching for.
As for whether some solvers are more "readable" than others, my experience here is limited to (mixed-integer) linear programming, and a little of conic optimization.
I have found GLPK to be well-written and easy to follow. SCIP and Ipopt have good and extensive documentations, which to me is a requirement. I would not go near Clp's or Cbc's codebase unless you know what you are doing.
For conic optimization, ECOS is a light-weight interior-point solver in C.
HiGHS is a modern simplex solver for linear programming under active development.
Solvers written in higher-level languages such as Julia or Matlab may be easier to follow: Tulip's entire codebase is only ~4000 lines of code (Clp is ~180k, Ipopt ~75k, HiGHS ~50k).
In most solvers' source code, you will find a
src/ directory: this is where the source code will be.
I generally proceed as follows:
- Identify which specific component I want to understand, e.g., how parameters are handled internally
- Make a quick search through the docs. Many times that is enough
- If not, peek at the code that's pointed to by the documentation. I generally start by looking at header files, and rarely look at source files directly.
- If there's anything I don't understand, e.g., some class or I don't know or function whose role is unclear, search where it is defined.