Skip to content

perf: binary splitting for NumericMatrix.walk()#156

Merged
kaminer merged 4 commits intomasterfrom
binary-split-walk
Apr 5, 2026
Merged

perf: binary splitting for NumericMatrix.walk()#156
kaminer merged 4 commits intomasterfrom
binary-split-walk

Conversation

@kaminer
Copy link
Copy Markdown
Contributor

@kaminer kaminer commented Apr 4, 2026

Replace the sequential O(N^2) left-accumulate loop with a balanced divide-and-conquer product tree, reducing complexity to O(N log N).

The speedup grows with N and is largest for rational-entry matrices where numerator/denominator sizes grow fast:

2x2 rational: ~15x at N=1000, ~40x at N=2000, ~160x at N=5000
3x3 rational: ~16x at N=1000, ~46x at N=2000, ~213x at N=5000
5x5 rational: ~31x at N=1000, ~80x at N=2000
2x2 PCF: ~2-3x at N=1000-10000
5x5 polynomial: ~2-6x at N=1000-5000

API and return values are unchanged. All 334 existing tests pass.

Replace the sequential O(N^2) left-accumulate loop with a balanced
divide-and-conquer product tree, reducing complexity to O(N log N).

The speedup grows with N and is largest for rational-entry matrices
where numerator/denominator sizes grow fast:

  2x2 rational:  ~15x at N=1000, ~40x at N=2000, ~160x at N=5000
  3x3 rational:  ~16x at N=1000, ~46x at N=2000, ~213x at N=5000
  5x5 rational:  ~31x at N=1000, ~80x at N=2000
  2x2 PCF:       ~2-3x at N=1000-10000
  5x5 polynomial: ~2-6x at N=1000-5000

API and return values are unchanged. All 334 existing tests pass.
- Removed separate numeric_matrix_benchmark.py
- Added standalone comparison script to existing matrix_benchmark.py
- All benchmarks now test through the public Matrix.walk() API
- Verified similar speedups through the Matrix wrapper:
  * 2x2 PCF: 2-4x
  * 2x2 rational: 13-148x (N=1000-5000)
  * 3x3 rational: 14-170x (N=1000-5000)
  * 5x5 rational: 18x at N=1000
  * 5x5 polynomial: 3-5x
…mark

- Renamed lo/hi to first/last for clarity
- Extracted magic number 8 into SEQUENTIAL_THRESHOLD constant
- Added docstring explaining why balanced splitting matters for FLINT rationals
- No suitable pythonic utility exists for balanced product trees:
  math.prod / functools.reduce are sequential left-folds that lose the
  binary-splitting benefit; python-flint and mpmath have no generic
  matrix product tree
- Removed _compare(), _walk_sequential(), and __main__ block from
  matrix_benchmark.py — benchmarks are now strictly pytest-only
kaminer added a commit that referenced this pull request Apr 4, 2026
- Add style rule: no decorative section separators or redundant comments
- Add testing rule: use @pytest.mark.parametrize for variations
- Both learned from RotemKalisch's review feedback on PR #156
- Removed all decorative # --- section separator comments
- Replaced 5 separate test functions with a single parametrized test:
  @pytest.mark.parametrize over MATRICES x DEPTHS (100, 500, 1000, 2000)
- Now 20 walk benchmark combinations + 1 as_companion = 21 tests
Copy link
Copy Markdown
Member

@RotemKalisch RotemKalisch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@kaminer kaminer added this pull request to the merge queue Apr 5, 2026
Merged via the queue into master with commit 7e319ac Apr 5, 2026
2 checks passed
@kaminer kaminer deleted the binary-split-walk branch April 5, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants