perf: replace np.vectorize with vectorized string ops for label names#617
perf: replace np.vectorize with vectorized string ops for label names#617MaykThewessen wants to merge 2 commits intoPyPSA:masterfrom
Conversation
Replace np.vectorize(print_variable/print_constraint) calls in
to_highspy(), to_gurobipy(), and to_mosek() with a vectorized_label_names()
helper that uses np.char.add for simple prefix-based names (the common case).
np.vectorize is a Python-level loop wrapper that calls a scalar function
per element. For the default (non-explicit-coordinate-names) path, the
printer is just f"x{var}" / f"c{cons}" — pure string concatenation that
can be expressed as np.char.add(prefix, labels.astype(str)).
For explicit_coordinate_names mode (which requires per-label lookups via
get_label_position()), the function falls back to np.vectorize.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
for more information, see https://pre-commit.ci
Benchmark ResultsTested on Python 3.14, numpy 2.x, macOS ARM64 with realistic LP sizes (593K variable labels + 1.38M constraint labels): The speedup is modest (~1.2x) because:
The bigger performance win comes from PR #616 (caching This PR is still worthwhile for code clarity ( |
|
@MaykThewessen Thanks for your contribution. |
Summary
vectorized_label_names()helper that usesnp.char.add()for simple prefix-based label namesnp.vectorize(print_variable/print_constraint)into_highspy(),to_gurobipy(), andto_mosek()np.vectorizeforexplicit_coordinate_names=Truemode (which requires per-label lookups)Motivation
np.vectorizeis documented as a convenience wrapper, not a performance tool — it calls a Python function per element. For the default (non-explicit-names) path, the printer functions are trivial string concatenation (f"x{var}",f"c{cons}") that can be expressed asnp.char.add(prefix, labels.astype(str)).The improvement is modest on modern numpy/Python (~1.2x for 2M labels), but the vectorized approach is also cleaner and avoids the
np.vectorizefootgun for future maintainers.Context
See discussion in #198 (comment) for the broader performance analysis.
Test plan
test_io.py::test_to_highspypasses (verifies HiGHS direct API export)test_optimization.pyhighs-direct tests pass (24/25 — one pre-existing failure)🤖 Generated with Claude Code