Friday, October 2, 2026

What Makes a Solver API Worth Copying?

 Imitation is the sincerest form of flattery.

Recently, a new open-source optimization solver called PRIMAL caught our attention. Not only because it was generated using coding agents, or because it supports an ambitious range of optimization problems — LP, MIP, QP, SOCP, SDP, and more — but also because parts of its API looked remarkably familiar. Replace “MSK_” with “PRIMAL_,” and you can adopt the MOSEK examples quickly.

PRIMAL itself documents that its test suite contains 48 C ports of MOSEK examples and that it performs compatibility validation against the publicly available MOSEK examples. Looking more closely, however, raises a more interesting question than simply whether one API resembles the other:

Why would somebody designing a new optimization solver choose the MOSEK C API as a blueprint?

Many mature solver APIs offer inspiration, including SCIP, HiGHS, and a rich set of open-source and commercial APIs such as CPLEX.

So perhaps this is a good opportunity to look at something we rarely talk about: the design philosophy behind the MOSEK C API. We focus on the low-level C API, which is what you need in the first place to design an optimization solver. Users should be aware of MOSEK’s higher-level constructs across various languages, such as the Fusion API for C++, Python, Java, and .NET.

1. A small and consistent vocabulary

At its core, the MOSEK C API uses a rather small collection of verbs:

Append, put, get, remove

These are then combined systematically with the objects being manipulated:

Var, con, aij, bound, c, solution


This produces functions such as:

MSK_appendvars(...), MSK_appendcons(...), MSK_putcj(...), MSK_putaij(...), MSK_putvarbound(...)

MSK_putconbound(...) 

MSK_getnumvar(...), MSK_getnumcon(...), MSK_getxx(...)

The important part is not any individual function name. It is the regularity of the language. Once you understand the naming convention, you can frequently predict what another function will be called.

This is one characteristic of a good API: users spend less time memorizing names and more time understanding the optimization problem.

2. The API closely follows the mathematics

Consider variable bounds. A variable can be
Free
x >= l
x <= u
l <= x <= u
x = a

Rather than providing a collection of unrelated functions for these cases, the MOSEK API represents them with a bound key and lower and upper bounds. The corresponding C function is:

MSK_putvarbound(task, j, bkx, blx, bux)

Similarly, a constraint has a bound key and lower and upper bounds:

MSK_putconbound(task, i, bkc, blc, buc)

The API therefore mirrors the mathematical representation of the optimization problem. You do not have to think primarily in terms of software objects. You can think in terms of variables, constraints, bounds, and coefficients.

3. Separate the structure from the data

Another characteristic of the MOSEK C API is the separation between creating mathematical objects and specifying their properties. A typical model starts with:

MSK_appendcons(task, numcon)
MSK_appendvars(task, numvar)

We have now created the mathematical structure. Then we populate it:

MSK_putcj(...), MSK_putvarbound(...), MSK_putconbound(...), MSK_putaij(...)

Conceptually, the workflow becomes:

Create task → Create variables and constraints → Populate coefficients, bounds, and objective → Optimize

This may appear almost trivial. That is precisely the point. A good API makes the underlying concepts appear obvious.

4. Scalability: One or ten million coefficients

Designing an optimization API is an interesting challenge. It should be convenient enough to teach with a model containing three variables, while still being suitable for applications containing millions of variables and nonzeros.

For example, the simplest way of changing one element of the constraint matrix is:

MSK_putaij(task, i, j, value);


For larger amounts of data, the same API provides list, row, column and slice operations. The same pattern occurs elsewhere. There are operations for an individual variable bound as well as operations on collections or slices of variable bounds. This gives the API an important property:

The conceptual API used in a small tutorial is also the API used to construct very large optimization models.

Users do not have to abandon the original mental model when their problems become large.

5. An API that survived the evolution from LP to conic optimization

MOSEK has existed for decades, with the first release in 1999. Since then, mathematical optimization software has changed substantially. An API originally dealing with linear and quadratic optimization eventually had to accommodate, among other things:

  • second-order cones,

  • semidefinite optimization,

  • exponential cones,

  • power cones,

  • affine conic constraints,

  • mixed-integer conic optimization.

Yet the fundamental concept of a MOSEK Task has remained. That is important. A software API that works well for today's features is useful. An API whose basic abstractions can accommodate mathematical capabilities that were not anticipated when it was originally designed is something else entirely.

6. Other solvers made different — and perfectly reasonable — choices

This is not to say that there is only one good way to design an optimization API. Consider HiGHS, another optimization solver with a C API. HiGHS exposes a strongly row- and column-oriented interface, with functions such as Highs_addRow and Highs_addCol. MOSEK also provides efficient row- and column-oriented operations, such as MSK_putarow and MSK_putacol, but separates creating mathematical objects (appendvars, appendcons) from populating their coefficients and properties.

MOSEK takes a somewhat different approach. Much of the low-level MOSEK API can be viewed as manipulating a collection of mathematical objects and their properties:

Neither approach is inherently better. HiGHS' terminology maps naturally onto the sparse matrix representation underlying LP and MIP models. MOSEK's abstraction, however, becomes particularly interesting as we move beyond traditional LP and MIP into conic optimization. Variables, constraints, affine expressions, and domains remain mathematical concepts even when the model contains second-order, exponential, power, or semidefinite cones.

This may help explain why the basic vocabulary of the MOSEK API has remained relatively small while the range of optimization problems MOSEK supports has grown substantially.

7. Why not simply copy CPLEX?

CPLEX provides another interesting comparison. Its C API reflects its long history and its row- and column-oriented representation. For example, adding multiple rows involves concepts such as row and nonzero counts, along with sparse-matrix index and value arrays.

That is powerful and efficient. It also exposes more details of how the mathematical matrix is represented.

MOSEK's basic operations (discussed above) provide a somewhat different abstraction. The model looks less like a sparse matrix data structure and more like a collection of mathematical objects whose properties you can query and modify. For a new solver API, that can be an attractive starting point.

8. Wrap-up

This brings us back to PRIMAL. Its developers could have designed an entirely new interface. They could have followed CPLEX's conventions. They could have followed SCIP or HiGHS. Or selected any other solver’s API. So,

What properties of an API make another solver developer want to reproduce its concepts?

Based on the above, our answer would be: 

  • Consistency.

  • A small vocabulary.

  • Predictable naming.

  • A close relationship between API concepts and mathematical concepts.

  • A natural progression from scalar operations to high-performance bulk operations.

  • And abstractions that have remained useful while mathematical optimization has evolved substantially.

After using it for a while, the naming becomes predictable. The abstractions stop attracting attention. You start thinking about the optimization model instead of thinking about the API.

In other words, the API becomes boring. And boring infrastructure is often excellent infrastructure.

To quote MOSEK founder and CEO, Erling D. Andersen: “The mental model and the interface should be as close as possible. At the same time, a low-level API needs to be just generic enough and designed to cover linear, conic, and nonlinear constructs elegantly and extendibly, not being limited to the solution methods such as Simplex or interior point only.”

So when we noticed that a new optimization solver written with an agentic coding assistant had adopted many familiar ideas, our first reaction was naturally curiosity. Our second was perhaps a little bit of pride.

After all, if you are going to take inspiration from a low-level optimization solver API, we are happy ours seems worth studying.


Note that this blog has been written with the support of OpenAI’s ChatGPT 😀