Five libraries, three models

Each model is built and handed to a solver — run() and optimize() are never called. Every rival model is hand-written in bench/models/ beside ours and is solved against ours in CI, so nothing here is fast because it built a different model. gurobipy appears twice, the same library written as a loop and as a matrix; the matrix, with highspy-matrix, is drawn as the matrix floor.

Every number here is the median of a measurement's rounds, and every band is the first to the third quartile of the same rounds. Nine rounds is the floor; a quick cell takes many more.

dispatch
meet a demand from a fleet of units — bounds and one balance, the floor
transport
a network of buses and lines — mapping tables, three joins per row
fleet
twelve declarations rather than one big one — cost per declaration, not per row
Show Grown by Axes
Libraries
click to hide

Cost against size

specsolve is the thick violet line. Log–log gives every size equal room, and the slope is the scaling order: a line rising one decade per decade grows in step with the model. Linear–linear draws the gap at the largest size at its real size, and puts the small sizes at the origin. Both axes switch together, because a linear axis over a logarithmic one would draw linear growth as a curve.

The grey line is the matrix floor: a hand-written matrix handed straight to the solver's bulk API — gurobipy-matrix on Gurobi, highspy-matrix on HiGHS. Nobody writes a model this way; it is the limit a modelling library can approach, and the distance from it is what specsolve's modelling layer costs.

The line is the median of the rounds and the band is the middle half of them, first quartile to third. Its height is what the machine did to the same work, not a confidence interval: two lines whose bands overlap are two numbers this run cannot tell apart, and a band you cannot see is a measurement that barely moved. Median rather than the fastest round, because the fastest is a best-of-n and n is not equal — a quick cell here took 84 rounds and a slow one 9; rather than the mean, because one round in forty of a 20 ms measurement took 1.5 s, and one scheduler hiccup should not set a published number.

A dashed line is a projection, not a measurement. It continues a library past the size its budget refused, at the growth rate of its last measured step and never slower than linear. The axes are scaled to the measurements, so a steep projection leaves the top of the panel; the tooltip gives its value.

Against specsolve

The specsolve column is its own cost. Every other cell is that library's cost divided by specsolve's at the same size: green where specsolve is faster, blue where the other library is, grey within ten per cent. The matrix floor's column is not shaded: being faster than specsolve there is the point of a floor. Hover a cell for the library's own number.

>30 s and >16 GB are measurements the harness refused — projected past its time or memory budget and skipped; hover one for the projection. An em dash is a cell with no number for another reason: gurobipy has no HiGHS.