Skip to content

Support zero-column mutable matrix iterators - #1462

Open
Alex Razumov (arrayka) wants to merge 5 commits into
mainfrom
u/arrayka/zero_column_iterators
Open

Alex Razumov (arrayka) wants to merge 5 commits into
mainfrom
u/arrayka/zero_column_iterators

Conversation

@arrayka

@arrayka Alex Razumov (arrayka) commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Why

N x 0 matrix layouts are valid, but parallel mutable row and window iterators panic instead of preserving the logical shape.

What

Yield empty mutable rows and correctly sized zero-column windows, with regression and strict-provenance Miri coverage.

Benchmarks

There is no evidence that Either introduces a performance regression for the common case (MxN matrices with M an N > 0).

I re-run the benchmarks 10 times - before/after numbers are similar:

Midpoint estimates

Run 5×100 before 5×100 after 1M×100 before 1M×100 after
1 103.880 µs 105.270 µs 8.050 ms 8.108 ms
2 95.580 µs 94.766 µs 8.016 ms 7.909 ms
3 99.888 µs 94.418 µs 7.960 ms 7.962 ms
4 104.710 µs 101.770 µs 8.051 ms 8.054 ms
5 101.170 µs 101.170 µs 8.189 ms 7.916 ms
6 101.840 µs 98.491 µs 7.766 ms 7.942 ms
7 99.997 µs 99.276 µs 7.932 ms 7.959 ms
8 54.311 µs 103.500 µs 8.101 ms 7.806 ms
9 100.220 µs 100.020 µs 7.844 ms 7.747 ms
10 102.590 µs 101.920 µs 7.680 ms 7.794 ms

Stability summary

Shape/implementation Median MAD CV Range
5×100 before 100.695 µs 1.520 µs 15.57%* 54.311–104.710 µs
5×100 after 100.595 µs 1.715 µs 3.49% 94.418–105.270 µs
1M×100 before 7.988 ms 0.088 ms 1.98% 7.680–8.189 ms
1M×100 after 7.929 ms 0.078 ms 1.43% 7.747–8.108 ms

* The before implementation’s CV is distorted by run 8. Criterion marked two samples in that measurement as severe low outliers, producing a very broad 33.907–88.258 µs confidence interval.

Conclusion

  • There is no evidence that Either introduces a performance regression.

Preserve logical rows and windows for N x 0 matrices during parallel mutable iteration instead of panicking.
@arrayka
Alex Razumov (arrayka) requested a balanced review from Copilot October 5, 2026 22:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

Review effort: Lite
Findings: 1 High severity · 2 Medium severity

Open (3)
What changed in this PR

This PR updates parallel mutable iterators for row-major matrices to correctly support N x 0 layouts by yielding empty mutable rows and zero-column windows instead of panicking.

Changes:

  • Add an internal ZeroColumnMut helper to manufacture empty mutable row/window views for zero-column matrices (Rayon-only).
  • Update MatrixMut::{par_rows_mut, par_window_iter_mut} to branch on ncols == 0 and return appropriate parallel iterators via Either.
  • Update and extend Rayon tests to cover the non-empty zero-column case and validate coexistence of the produced views.
File Description
diskann-utils/​src/​views/​rowmajor/​iter.rs Introduces ZeroColumnMut for constructing empty mutable views for zero-column matrices under Rayon.
diskann-utils/​src/​views/​rowmajor.rs Switches parallel iterator implementations to handle ncols == 0 via Either and adds/updates regression tests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread diskann-utils/src/views/rowmajor/iter.rs
Comment thread diskann-utils/src/views/rowmajor.rs
Comment thread diskann-utils/src/views/rowmajor/iter.rs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The implementation preserves matrix shape, maintains zero-element aliasing invariants, and covers the new behavior with targeted tests.

Review effort: Balanced
Findings: None

Resolved since last review (3)

@codecov-commenter

Codecov Comments Bot (codecov-commenter) commented Oct 5, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.88%. Comparing base (31589c3) to head (9d819f4).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1462      +/-   ##
==========================================
- Coverage   91.90%   90.88%   -1.02%     
==========================================
  Files         582      583       +1     
  Lines      114947   115937     +990     
==========================================
- Hits       105640   105374     -266     
- Misses       9307    10563    +1256     
Flag Coverage Δ
miri 90.88% <100.00%> (-1.02%) ⬇️
unittests 90.58% <100.00%> (-1.27%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
diskann-utils/src/views/rowmajor.rs 96.99% <100.00%> (+0.10%) ⬆️
diskann-utils/src/views/rowmajor/iter.rs 100.00% <100.00%> (ø)

... and 57 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@arrayka
Alex Razumov (arrayka) marked this pull request as ready for review October 5, 2026 23:08
@arrayka
Alex Razumov (arrayka) requested a review from a team October 5, 2026 23:08
Alex Razumov (from Dev Box) added 3 commits October 6, 2026 11:41
Compare the original chunk-based par_rows_mut implementation with the current Either-backed implementation for 5x100 and 1,000,000x100 matrices.

Run with:

    cargo bench -p diskann-utils --bench bench_main

Ten-run stability summary (Criterion midpoint estimates):

    Implementation     Median       MAD       CV      Range
    5x100 old          100.695 us   1.520 us  15.57%  54.311-104.710 us
    5x100 current      100.595 us   1.715 us   3.49%  94.418-105.270 us
    1Mx100 old           7.988 ms   0.088 ms   1.98%   7.680-8.189 ms
    1Mx100 current       7.929 ms   0.078 ms   1.43%   7.747-8.108 ms

The old 5x100 CV is inflated by one anomalous 54.311 us run. The ratio of medians is -0.10% for 5x100 and -0.74% for 1Mx100, showing no measurable regression.
matrix.window(window_nrows)
}),
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

After thinking about it more, I still find the use of Either to be deeply unsatisfying. Since ZeroColumnMut is already messing around with some unsafety, what if we went the way of par_rows and par_window_iter and did something like

struct ParMut<'a, T> {
   ptr: NonNull<T>,
   layout: Layout<T>,
   _lifetime: PhantomData<&'a mut T>,
}

impl ParMut<'a, T> {
    fn row_disjoint_unchecked(&self, row: usize) -> &'a mut [T];

    fn window_disjoint_unchecked(&self, rows: Range<usize>) -> Mut<'a, T>;
}

If we use index based parallel iterators, we get the necessary disjointedness.

This branch has not been deployed

No deployments
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.

4 participants