Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
29e111c
refactor: convert to cargo workspace with lib and py crates
events555 Apr 4, 2026
bdd8468
refactor: extract pure Rust lib crate from PyO3 bindings
events555 Apr 4, 2026
4b5cb61
feat: add PyO3 wrapper crate delegating to modularsnf lib
events555 Apr 4, 2026
c4803f4
build: point maturin at py crate and bump version to 0.4.0
events555 Apr 4, 2026
bbaac9d
ci: add crates.io publish job for modularsnf lib crate
events555 Apr 4, 2026
15c5f50
build: use workspace version inheritance and add version parity check
events555 Apr 4, 2026
18f915d
feat: add CRT-style non-recursive SNF path
claude Jun 3, 2026
504364f
chore: add CRT SNF prototype and profiling scripts
claude Jun 3, 2026
d9f6358
docs: replace PLAN.md with CRT optimization roadmap
events555 Jun 3, 2026
9089563
perf(crt): i64 fast-path reduction in local_snf hot loops (Phase 1)
events555 Jun 3, 2026
b4b06e0
perf(crt): split local_snf into two-phase column/row elimination (Pha…
events555 Jun 3, 2026
beb7d79
docs: record Phase 2a done + detailed Phase 2b blocked-GEMM design
events555 Jun 3, 2026
71fd991
perf(crt): blocked right-looking LU with GEMM trailing update (Phase 2b)
events555 Jun 3, 2026
328f6c8
docs: mark Phase 2b done; note tiled/BLAS GEMM kernel as Phase 2c
events555 Jun 3, 2026
86a36d7
perf(crt): packed cache-friendly i64 GEMM micro-kernel (Phase 2c)
events555 Jun 3, 2026
624e165
docs: mark Phase 2c done (packed i64 GEMM kernel)
events555 Jun 3, 2026
fc02385
fix(snf): keep transforms unimodular for tall rank-deficient inputs
events555 Jun 6, 2026
fd39340
refactor(crt): remove dev scaffolding and tidy the implementation
events555 Jun 6, 2026
72f0aa0
refactor: collapse the Python package into a thin Rust binding
events555 Jun 6, 2026
079d53e
test: replace Python correctness suite with PyO3 boundary tests
events555 Jun 6, 2026
d7b662a
docs: position CRT as experimental fast path; reflect thin wrapper
events555 Jun 6, 2026
8b517e3
build: bump version to 0.5.0
events555 Jun 6, 2026
60aaec9
merge: reconcile main into dev for v0.5.0 release
events555 Jun 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 20 additions & 18 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,27 @@ Use `modularsnf.ring` primitives: `gcdex`, `div`, `quo`, `stab`, `ann`.

## Testing

* Structural assertions (`S = U A V`, diagonal shape, divisibility chain,
unimodularity) over hardcoded array equality.
* Validate against SymPy integer-domain projection where feasible.
* Run `just check` (or individually: `just lint`, `just typecheck`, `just test`) before finalizing.
* Algorithm correctness lives in the Rust crate (`cargo test`): structural
assertions (`S = U A V`, diagonal shape, divisibility chain, unimodularity)
over random inputs, plus a Storjohann-vs-CRT cross-check.
* The Python suite (`tests/`) covers only the PyO3 boundary: input validation,
type/shape marshalling, and the public-API contract on small cases.
* Run `cargo test` and `just check` (`just lint`, `just typecheck`, `just test`)
before finalizing.

## File Structure

* `modularsnf/ring.py` — ring primitives (Gcdex, Stab, Div, Ann).
The SNF algorithms live in the Rust workspace; the Python package is a thin
wrapper over the `modularsnf._rust` extension.

* `crates/modularsnf/` — Rust lib crate: ring primitives, echelon/band
reduction, diagonalization (`snf.rs`/`band.rs`/`echelon.rs`/`diagonal.rs`),
and the CRT fast path (`crt.rs`).
* `crates/modularsnf-py/` — PyO3 bindings exposed as `modularsnf._rust`.
* `modularsnf/ring.py` — `RingZModN`, forwarding ring primitives to Rust.
* `modularsnf/matrix.py` — `RingMatrix` data structure.
* `modularsnf/echelon.py` — triangularization (Lemma 3.1).
* `modularsnf/band.py` — band reduction (Lemmas 7.3, 7.4, Prop 7.1).
* `modularsnf/diagonal.py` — diagonalization (Prop 7.7, Theorem 7.11).
* `modularsnf/snf.py` — master pipeline (Lemma 7.14) + public
`smith_normal_form_mod` API.
* `docs/algorithm.md` — mathematical foundation and algorithm description.
* `docs/PLAN.md` — current ExecPlan.

## ExecPlans

For work spanning multiple modules or changing public APIs, write a plan in
`docs/PLAN.md` before implementing. Users may say "use an ExecPlan" as
shorthand.
* `modularsnf/diagonal.py` — diagonalization wrappers.
* `modularsnf/snf.py` — public `smith_normal_form_mod` API (default path).
* `modularsnf/crt.py` — public `crt_snf` API (experimental fast path).
* `docs/algorithm.md` — default algorithm (Storjohann band reduction).
* `docs/crt.md` — CRT fast path design and correctness basis.
81 changes: 79 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = ["crates/modularsnf", "crates/modularsnf-py"]
resolver = "2"

[workspace.package]
version = "0.4.0"
version = "0.5.0"

[profile.release]
debug = true
34 changes: 21 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Smith Normal form of Integer matrices mod N (Storjohann)

This is a Python module that follows the deterministic algorithms presented in Arne Storjohann's PhD Dissertation *Algorithms for Matrix Canonical Forms* (ETH No. 13922, 2000).
A Rust implementation (with a thin Python binding) of the deterministic algorithms presented in Arne Storjohann's PhD Dissertation *Algorithms for Matrix Canonical Forms* (ETH No. 13922, 2000).

It implements the Lemmas and subsequent subroutines that are necessary for calculating the SNF without exponential intermediate values.
It implements the Lemmas and subsequent subroutines that are necessary for calculating the SNF without exponential intermediate values. The algorithms live in the Rust `modularsnf` crate; the Python package is a thin wrapper over the native extension.

It validates against SymPy using a known equivalence between calculating the Smith Normal form of an integer matrix, and then taking mod N, compared to solving it natively in the ring.
Correctness is validated in the Rust test suite: random inputs are checked against the Smith form contract ($S = UAV$, divisibility chain, unimodular transforms), and the default Storjohann path is cross-checked against the independent CRT path.

## Quick Start

Expand All @@ -28,22 +28,30 @@ A matrix is **unimodular** over $\mathbb{Z}/N\mathbb{Z}$ when
$\gcd(\det(M),\, N) = 1$, the modular analogue of $|\det(U)| = 1$
over $\mathbb{Z}$.

### Lower-level API
For details on the default algorithm (band reduction, diagonalization,
Storjohann's lemmas), see [docs/algorithm.md](docs/algorithm.md).

For direct access to `RingMatrix` objects:
## Alternative: CRT fast path (experimental)

`smith_normal_form_mod` uses Storjohann's band reduction, which works for any
modulus `N >= 2`. For the **small-modulus, large-matrix** regime there is a
second, experimental algorithm that is several times faster: a CRT-based path
that factors `N = prod p^e`, solves the SNF over each local ring `Z/p^e` by
valuation-pivoted elimination, and recombines via the Chinese Remainder Theorem.

```python
from modularsnf.ring import RingZModN
from modularsnf.matrix import RingMatrix
from modularsnf.snf import smith_normal_form
from modularsnf import crt_snf

ring = RingZModN(12)
A = RingMatrix(ring, [[2, 4], [6, 8]])
U, V, S = smith_normal_form(A) # note: (U, V, S) order
S, U, V = crt_snf([[2, 4, 0],
[6, 8, 3],
[0, 3, 9]], modulus=36)
# Same (S, U, V) contract as smith_normal_form_mod; S = U @ A @ V (mod 36).
```

For details on the algorithm (band reduction, diagonalization, Storjohann's
lemmas), see [docs/algorithm.md](docs/algorithm.md).
It requires the prime factorization of `N`; pass it explicitly as
`factors=[(p, e), ...]` to amortize factoring across many calls with the same
modulus. Prefer `smith_normal_form_mod` for general moduli. See
[docs/crt.md](docs/crt.md) for the design and correctness basis.

## Development Workflow (modern Python)

Expand Down
Loading
Loading