Skip to content

FabianHofmann/crs2lp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lp-writer

Fast LP file writer for scipy CSR matrices, implemented in Rust with Python bindings via PyO3.

Designed as a prototype for linopy integration, where LP file serialization is a bottleneck for large energy system models (10M+ nonzeros).

Performance

Benchmarked on random sparse matrices written to /tmp/ (median of 3 runs):

vs Linopy total (model creation + file write)

Size NNZ Rust (s) Linopy total (s) Speedup
small 20K 0.001 0.062 62×
medium 1M 0.049 0.220 4.5×
large 10M 0.224 1.728 7.7×
xlarge 20M 0.402 3.539 8.8×

vs Linopy write only

Size NNZ Rust (s) Linopy write (s) Speedup
small 20K 0.001 0.022 22×
medium 1M 0.049 0.156 3.2×
large 10M 0.224 1.436 6.4×
xlarge 20M 0.402 2.999 7.5×

Rust throughput peaks at ~50M NNZ/s (~1.3 GB/s).

Key optimizations: ryu for float formatting, itoa for integer formatting, row-buffered writes, prefix-based name generation (no Python string copies), 4MB BufWriter.

Installation

Requires Python ≥ 3.10 and a Rust toolchain.

uv venv
uv pip install maturin numpy scipy
maturin develop --release

Usage

import numpy as np
from scipy.sparse import csr_matrix
from lp_writer import write_lp_constraints

A = csr_matrix([[1.0, -2.5, 0, 3.0],
                [0, 1.0, -1.0, 0],
                [4.0, 0, 1.0, -7.0]])
rhs = np.array([10.0, 20.0, 30.0])
senses = ["<=", ">=", "="]

write_lp_constraints("model.lp", A, rhs, senses)

Output:

\\ Problem
Minimize
 obj: x0
Subject To
 c0: x0 - 2.5 x1 + 3.0 x3 <= 10.0
 c1: x1 - x2 >= 20.0
 c2: 4.0 x0 + x2 - 7.0 x3 = 30.0
Bounds
-inf <= x0 <= +inf
-inf <= x1 <= +inf
-inf <= x2 <= +inf
-inf <= x3 <= +inf
End

API

def write_lp_constraints(
    path: str,
    A: csr_matrix,
    rhs: np.ndarray,
    senses: list[str] | np.ndarray,  # "<=", ">=", "="
    var_prefix: str = "x",
    con_prefix: str = "c",
) -> None
  • path — output file path
  • A — constraint matrix (scipy CSR)
  • rhs — right-hand side values
  • senses — constraint senses, either list[str] or np.ndarray of uint8 (ord('<'), ord('>'), ord('='))
  • var_prefix / con_prefix — name prefixes; variables are named {var_prefix}{col_index}, constraints {con_prefix}{row_index}

Development

uv venv
uv pip install -e ".[dev]" linopy
maturin develop --release

# tests
pytest tests/

# benchmark
python bench/benchmark.py

Project structure

├── Cargo.toml
├── pyproject.toml
├── src/lib.rs                  # Rust extension (PyO3)
├── python/lp_writer/
│   ├── __init__.py             # Python wrapper
│   └── py.typed
├── tests/test_lp_writer.py
└── bench/benchmark.py

About

Experiments for fast writing CRS constraint matrix to LP files

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors