Skip to content

Benchmark comparison vs polar-high (Polars-backed LP/MIP eDSL on HiGHS) — thoughts? #740

@MaykThewessen

Description

@MaykThewessen

A new modelling library, polar-high, was released recently by Juha Kiviluoma (Nodal-Tools Oy). It targets the same niche as linopy: an indexed LP/MIP eDSL on top of HiGHS, but uses a Polars-backed kernel instead of xarray.

The docs include a reproducible build / solve / memory comparison between polar-high, linopy, and Pyomo on indexed linear programs, all using HiGHS as the solver. The dense-LP test follows linopy's own benchmark, restricted to the linear case so polar-high can run it directly.

Dense LP — build-only headline (single-thread, HiGHS time-limited to ~1 µs to isolate modelling-layer cost)

dense LP build-only

At N=3000 (~18M variables):

Tool Total time Peak memory
polar-high (regular) 87 s 16.4 GB
polar-high (save_memory) 131 s 15.1 GB
linopy (io_api="lp") 300 s 23.7 GB

Network LP — irregular topology (N nodes, 5N edges, T=168, build-only, 1 thread)

network LP build-only

At N=10000 (~8.4M variables):

Tool Total time Peak memory
polar-high (regular) 51 s 11.5 GB
polar-high (save_memory) 94 s 12.2 GB
linopy (io_api="lp") 165 s 14.1 GB

Replication: linopy's original benchmark format (3-panel, full HiGHS solve included)

linopy-format replication

The replication is faithful: same dense LP, same closed-form optimum, HiGHS solves the same sparse matrix. linopy's published numbers reproduce within run-to-run noise.

Summary

Reported ~2.3-3.5x faster than linopy on the build path with ~30% lower peak memory. The Polars-backed lazy/columnar internals are the architectural source of the gap; linopy is xarray/dense-numpy by default.

Questions for the maintainers and community

  1. Methodology — The linopy column uses io_api="lp" because the benchmark's time_limit short-circuit interacts cleanly with that path. Would io_api="direct" materially change the picture on the build column?
  2. Architectural direction — Issues Polars support #510 (Polars support) and lp-polars IO API writes different models to lp which are incorrect #484 (lp-polars IO bugs) both touched a Polars path. Given the gap shown here, is a Polars-backed write path inside linopy worth revisiting? Or is the architectural distance from xarray too large?
  3. Cross-tool collaboration — Anyone here in contact with Juha / Nodal-Tools? A shared LP/MIP benchmark suite across linopy / polar-high / Pyomo (and ideally JuMP) would be useful for PyPSA-Eur-class workloads.

Not affiliated with Nodal-Tools, just a downstream PyPSA-Eur user who finds the numbers interesting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    performanceThis improves performance while not (meaningfully) altering behaviour for users

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions