Skip to content

Speed up direct solver handoff by dropping explicit zeros from the constraint matrix #814

Description

@FBumann

Intent placeholder — @FBumann to replace with your own words.

Note

The following was generated by AI (found while investigating #813).

Motivation

The direct solver handoff hands HiGHS a constraint matrix full of explicitly stored zeros. Models whose expressions broadcast against a dense coordinate (e.g. a bus × line incidence block) store one coefficient per coordinate pair, most of them zero. For the sparse_network(250) benchmark:

  • model.matrices.A: 1,506,000 stored entries, 18,000 structural nonzeros → 98.8% explicit zeros.

highspy.Highs.addRows cost scales with stored nnz, so we spend the handoff describing zeros (and materialise them in the solver — the peak-memory column below). This is independent of the highspy version regression in #813 — it's pure wasted work on every version.

Proposal

Drop explicit zeros before the direct handoff. Minimal version in linopy/solvers.py (Highs._build_solver_model, ~L1668):

A = A.tocsr()
A.eliminate_zeros()
...
h.addRows(num_cons, lower, upper, A.nnz, A.indptr, A.indices, A.data)

Mathematically identical — a zero coefficient doesn't change the constraint.

Better still, consider eliminating zeros centrally in model.matrices.A (or when the coefficient array is assembled) so the LP/MPS writers and the other direct backends (gurobi, xpress, …) all benefit, not just HiGHS.

Impact

Measured with the repro in #813 (dev-scripts/highs-addrows-repro/, runnable via uv run). Timings via pytest-benchmark; peak memory via pytest-benchmem (memray). Effect of eliminate_zeros() on the addRows handoff:

highspy explicit zeros (1.5M nnz) eliminate_zeros() (18k nnz) speedup
1.13.1 ~13 ms ~1.6 ms
1.15.0 ~51 ms ~1.7 ms 30×

Peak memory for the handoff also drops (currently ~65 MiB, dominated by the ~1.5M redundant coefficients). As a side effect this makes linopy insensitive to the #813 highspy regression.

Notes / to check

  • Confirm no backend relies on structural zeros being present.
  • Decide the right layer (per-backend vs central in matrices).
  • Add a regression benchmark on stored-vs-structural nnz.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestperformanceThis improves performance while not (meaningfully) altering behaviour for users

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions