Skip to content

Add Matrix::transpose - #175

Open
JoeyBF wants to merge 1 commit into
SpectralSequences:masterfrom
JoeyBF:transpose
Open

Add Matrix::transpose#175
JoeyBF wants to merge 1 commit into
SpectralSequences:masterfrom
JoeyBF:transpose

Conversation

@JoeyBF

@JoeyBF JoeyBF commented Oct 21, 2024

Copy link
Copy Markdown
Collaborator

Matrix had no transpose. This adds one, blocked at p = 2.

Entry (i, j) of a p = 2 matrix is bit j % 64 of limb j / 64 of row i, so a 64-square block
of entries is exactly one limb from each of 64 consecutive rows. blas::block::transpose_lanes
moves such a block with six masked shift-and-XOR passes — the recursive delta swap of Hacker's
Delight 7-3 — rather than the 4096 single-bit extractions an entry-at-a-time transpose performs.

Two things beyond the swap itself matter about as much again:

  • Filling cache lines. Each source block contributes one limb to each of 64 destination rows, so
    a block at a time touched 64 cache lines to deposit 8 useful bytes each. Taking 8 blocks at a time
    makes those contributions 8 consecutive limbs of each destination row — one whole line.
  • One block per lane. Every lane then runs the same swap on the same row indices, so nothing
    moves between lanes and the inner loop is a straight elementwise operation. This is adapted from
    mkarppa/matmul (MIT; Karppa & Kaski,
    arXiv:1909.01554), which transposes bit blocks over uint4
    rather than one word at a time; one block per lane is the CPU form of that width.

Matrix::transpose works an 8×8 tile of blocks through a 32 KB scratch, so both trips to main
memory are contiguous and the shuffling stays in L1. Odd primes keep the entry-at-a-time path.

Against that path, on square matrices:

size blocked naive speedup
512² 0.008 ms 1.23 ms 156×
1024² 0.036 ms 4.46 ms 125×
2048² 0.111 ms 18.90 ms 170×
4096² 0.499 ms 90.20 ms 181×
8192² 2.162 ms 388.02 ms 180×

Effective bandwidth is flat at 7.4–9.4 GB/s across that range. Measured on one dev box; it is a
cache-sensitive routine, so expect the numbers to move with the machine — beyond ~8192² the working
set leaves L3 and throughput falls off.

Tests

  • transpose_lanes against an entry-at-a-time oracle: random blocks, involution, and every
    single-bit block.
  • Matrix::transpose under proptest at all primes (via the existing Arbitrary for Matrix), plus
    64 hand-picked shapes straddling block boundaries in each dimension independently — 1, 63, 64, 65,
    127, 128, 129, 200 in each axis.

History

This branch previously held a naive entry-at-a-time transpose. It has been rewritten rather than
built on: the old implementation predates the Matrix rewrite and assumed vectors: Vec<FpVector>,
where Matrix now stores data: AVec<Limb> with a stride, which is what makes the blocked form
possible at all.

Split out of the work in #285; the GPU half is a separate PR and does not depend on
this one.

Summary by CodeRabbit

  • New Features

    • Added matrix transposition support.
    • Binary-field matrices now use an optimized transposition approach for improved performance.
    • Transposition works correctly across supported matrix sizes and can be applied repeatedly.
  • Tests

    • Added coverage for boundary dimensions, repeated transposition, single-bit behavior, and comparisons against a reference implementation.

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@JoeyBF, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 56 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3c944fac-017e-41ee-9d14-71924a8538cb

📥 Commits

Reviewing files that changed from the base of the PR and between 04e2a36 and 9b5058b.

📒 Files selected for processing (1)
  • ext/crates/fp/src/matrix/matrix_inner.rs

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f5103bc8-8ef0-45bf-ba33-b466ff100cdc

📥 Commits

Reviewing files that changed from the base of the PR and between 03d9b82 and 04e2a36.

📒 Files selected for processing (1)
  • ext/crates/fp/src/matrix/matrix_inner.rs

Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Adds a reusable 64×64 lane-wise bit transpose. Matrix::transpose uses blocked transposition for binary-field matrices and entry-wise copying for other primes. Tests cover boundaries, naive equivalence, bit placement, and involution.

Changes

Binary Matrix Transpose

Layer / File(s) Summary
Lane transpose primitive
ext/crates/fp/src/blas/block.rs
Adds transpose_lanes with masked delta swaps. Tests verify naive equivalence, bit placement, and double application.
Matrix transpose implementation
ext/crates/fp/src/blas/block.rs, ext/crates/fp/src/matrix/matrix_inner.rs
Adds Matrix::transpose. Binary matrices use padded 64×64 blocked tiles. Other primes use entry-wise copying.
Matrix transpose validation
ext/crates/fp/src/matrix/matrix_inner.rs
Adds boundary, property-based equivalence, and involution tests against a naive transpose.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 04e2a

This PR adds matrix transposition with a localized implementation and documented coverage across supported primes and boundary shapes; no actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant Matrix
  participant ScratchTiles
  participant transpose_lanes
  Matrix->>ScratchTiles: Gather padded binary matrix tiles
  ScratchTiles->>transpose_lanes: Transpose each 64×64 tile
  transpose_lanes-->>ScratchTiles: Return transposed tile
  ScratchTiles-->>Matrix: Write valid destination rows
Loading

Poem

A rabbit tests each bit and lane,
Rows become columns once again.
Padded tiles turn in place,
Prime-field entries keep their space.
Twice transposed, the shape comes back. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: adding the public Matrix::transpose method.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Entry (i, j) of a p = 2 matrix is bit j % 64 of limb j / 64 of row i, so a
64-square block of entries is one limb from each of 64 consecutive rows.
`blas::block::transpose_lanes` moves such a block with six masked
shift-and-XOR passes (the recursive delta swap of Hacker's Delight 7-3)
instead of 4096 single-bit extractions.

Two things beyond the swap matter about as much again. Taking 8 blocks at a
time gives each destination row 8 consecutive limbs — a whole cache line,
where a block at a time deposited 8 useful bytes per line touched. And holding
one block per lane means every lane runs the same swap on the same row
indices, so nothing moves between lanes and the inner loop is elementwise; that
is adapted from mkarppa/matmul (MIT; Karppa & Kaski, arXiv:1909.01554), which
transposes over uint4 rather than a word at a time.

`Matrix::transpose` works an 8x8 tile of blocks through a 32 KB scratch, so
both trips to main memory are contiguous and the shuffling stays in L1. Odd
primes use the entry-at-a-time path.

Against that path: 156x/125x/170x/181x/180x at 512/1024/2048/4096/8192 square,
effective bandwidth flat at 7.4-9.4 GB/s. Measured on a dev box, not the
machine in the benchmark suite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EFfXYt9zvAvHWhNHnULe6r
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.

1 participant