Skip to content

Genericize the algebra crate and resolution engine over the ground ring - #263

Closed
JoeyBF wants to merge 7 commits into
SpectralSequences:masterfrom
JoeyBF:claude/algebra-generic-base-ring
Closed

Genericize the algebra crate and resolution engine over the ground ring#263
JoeyBF wants to merge 7 commits into
SpectralSequences:masterfrom
JoeyBF:claude/algebra-generic-base-ring

Conversation

@JoeyBF

@JoeyBF JoeyBF commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

The algebra crate and the ext resolution engine hardcoded the coefficient
field 𝔽ₚ throughout. This PR makes them generic over an arbitrary graded
ground ring, introducing a small trait tower so the same engine can resolve
over rings other than a field — while keeping the classical 𝔽ₚ path
behavior-preserving and bit-identical.

No new coefficient ring beyond 𝔽ₚ is added here; this is the abstraction layer
that a follow-up (C-motivic Ext over 𝔽₂[τ]) builds on.

Design

A coefficient ring is folded into the existing algebra hierarchy as a sub-trait,
and the "solving" linear algebra is split off into its own trait so it can be
required only where a resolution actually needs it:

  • Ring: Algebra (algebra/base_ring.rs) — a coefficient ring is an
    algebra, plus a scalar type (Ring::Element), a representation of finite free
    modules over it (Ring::Vector and slices), and by-value arithmetic. This is
    enough to define an algebra and act on its modules.
  • Solvable: Ring (linear_algebra/, new module) — the harder linear
    algebra a free resolution needs: images, kernels, quasi-inverses, and the
    resolution-step machinery. It is bounded only at ModuleHomomorphism /
    FreeModuleHomomorphism / ChainComplex, so an algebra can be defined over
    a ring whose solving linear algebra isn't implemented yet.
  • Algebra gains type BaseRing: Ring + base_ring(), and a
    module_at(t) -> GradedPiece accessor exposing each graded piece as a
    Module<Algebra = BaseRing>.

Coefficients and vectors are threaded generically via the aliases Scalar<A>,
VectorOf<A>, BaseSliceOf<A>, SubmoduleOf<A>, QuasiInverseOf<A> (all
projected through A::BaseRing). The module actions, free modules, module
homomorphisms, chain complexes, and resolution steps are rewritten against these
aliases instead of concrete fp types.

Field (= 𝔽ₚ) is the reference implementer of both Ring (Element = u32,
Vector = FpVector) and Solvable (every operation forwards to fp).

Compatibility & validation

  • Behavior-preserving for the classical path. With BaseRing = Field
    everything monomorphizes to the same fp code as before. All 69 resolution
    benchmarks are bit-identical
    , and the full test suite passes.
  • cargo fmt --check, clippy (both --no-default-features and --all-targets
    profiles), and cargo doc under -D warnings are all green.
  • The change is additive: no public classical API is removed; existing
    Algebra<BaseRing = Field> code is unaffected.

Out of scope

  • No motivic / non-field coefficient ring is introduced here. The 𝔽₂[τ] ground
    ring, its solving linear algebra, and the C-motivic Steenrod algebra are a
    follow-up that depends on this PR.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added generic base-ring support across algebras, modules, module homomorphisms, and chain complexes.
    • Introduced ring-aware linear-algebra abstractions for vectors/slices, kernels/images, quasi-inverses, and resolution stages.
    • Exposed graded-piece access for supported algebras (including classical (\mathbb{F}_p) pieces).
  • Improvements

    • Updated algebraic operations to use the appropriate scalar behavior for each base ring.
    • Resolution and homotopy-related computations now leverage the new linear-algebra workflow, with improved internal consistency and tests for graded pieces/linear algebra.

claude added 6 commits July 10, 2026 03:52
The homological algebra was hardcoded to coefficients in the field F_p via the
bit-packed `fp` crate. Introduce a base-ring abstraction so it can later run
over any graded coefficient ring (e.g. F_2[tau] for C-motivic Ext) while
keeping the classical F_p path bit-identical.

Two coefficient-ring traits, cut so that defining an algebra needs strictly
less than resolving over it:

- `Ring` (algebra/base_ring.rs): the coefficient ring -- scalars, their
  arithmetic, `embed_field` for the F_p inclusion, and the representation of
  finite free modules over the ring (the `Vector`/`Slice`/`SliceMut` types and
  their ops). This is enough to define an algebra and act on its modules.
- `GradedDvr` (linear_algebra/mod.rs): extends `Ring` with the linear algebra
  of *solving* -- images, kernels and quasi-inverses -- which is tractable
  precisely because the ring is a graded DVR (graded Nakayama). It is the
  base-ring-generic replacement for the `fp` row reduction the engine hardcodes.

`Algebra` requires only `type BaseRing: Ring`, so an algebra can be defined over
a ring whose solving linear algebra is not yet implemented; the stronger
`GradedDvr` bound is imposed where resolution actually happens
(`ModuleHomomorphism`, `FreeModuleHomomorphism`, and the types that store them).
`Field` implements both traits by forwarding to `fp`, bottoming the recursion
at itself.

Module and homomorphism signatures are threaded over the base-ring scalar and
the `BaseSlice` projections. `FreeModule`/`FreeModuleHomomorphism` store their
outputs/kernels/images/quasi-inverses generically over the base ring; the
remaining fp-matrix-backed module types stay pinned with `BaseRing = Field` and
use the scalar coefficient directly, so relaxing a pin becomes a compile error
to resolve rather than a silent bug.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JNkiiZghHggyMwDWfDn1y5
Lift the resolution step's inline linear algebra -- building the differential
matrix, computing its kernel, and constructing the next stage -- onto the
`GradedDvr` base-ring trait, and dispatch `step_resolution` through those
methods instead of calling `fp` directly.

`ChainComplex::Algebra` is bounded `BaseRing = Field`, so the classical engine
monomorphizes to the existing `fp` code path (benchmarks are bit-identical);
relaxing that single bound is the entry point for a non-field base ring. The
base-ring scalar is threaded through the chain-complex, chain-homotopy, Yoneda
and secondary layers, the resolution homomorphism, and the examples; the generic
secondary-homotopy type carries the `GradedDvr` bound it needs to store a
free-module homomorphism.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JNkiiZghHggyMwDWfDn1y5
A coefficient ring is itself an algebra over itself, so fold Ring into
the Algebra hierarchy: Ring: Algebra. This makes Algebra::BaseRing:
Algebra hold transitively (since BaseRing: Ring), so each graded piece
of an algebra can be viewed as a module over its base ring — the basis
for exposing motivic weight as the internal grading of the coefficient
module. The coefficient capacity (scalar, vector, arithmetic) stays
confined to the Ring sub-trait, keeping Algebra lean for the Steenrod,
Milnor, Adem, and module algebras that are never coefficient rings.

Pure supertrait addition: Field already implements Algebra, so this is
a bound, not new boilerplate; all call sites and the monomorphized Field
path are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JNkiiZghHggyMwDWfDn1y5
The trait bounding a ring on which a free resolution can solve (compute
images, kernels, quasi-inverses) is renamed GradedDvr -> Solvable, moving
the emphasis from the sufficient condition (being a graded DVR) to the
capability it grants. Pure identifier rename across the algebra and ext
crates; no behavior change, all tests pass. The doc prose still explains
that solvability requires a graded DVR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JNkiiZghHggyMwDWfDn1y5
Give Algebra a concrete associated type GradedPiece: Module<Algebra =
Self::BaseRing> and an accessor fn module_at(&self, t) -> Self::GradedPiece,
so each graded piece of an algebra can be viewed as a module over its
coefficient ring. Since BaseRing is itself an Algebra (the Ring: Algebra
fold), "an R-module" is just Module<Algebra = R>, reusing the Module trait.

The type is concrete (not -> impl Module) so the hand-rolled SteenrodAlgebra
dispatch forwards it. For every classical algebra BaseRing = Field, and since
every module over a field is free, the piece is simply a FreeModule<Field>
with dimension(t) generators in degree 0 (weight-0 internal grading) -- no
bespoke type needed, and it matches the plan's framing that free grades are
free modules and non-free grades (motivic) are presentations. This is
additive, engine-unused structural access; dimension(t) stays load-bearing.

Behavior-preserving: all 69 resolution benchmarks are bit-identical, all
algebra tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JNkiiZghHggyMwDWfDn1y5
- rustfmt (nightly): order associated type GradedPiece before methods in
  the Algebra impls, and restore alphabetical import ordering disturbed by
  the GradedDvr -> Solvable rename.
- rustdoc (-D warnings): the linear_algebra module doc linked the private
  `algebra` module and used redundant explicit targets on [`Ring`] links;
  make the module reference plain and drop the redundant targets.

just lint and just docs now pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JNkiiZghHggyMwDWfDn1y5
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces generic base-ring and scalar abstractions across algebras, modules, homomorphisms, chain complexes, and resolution construction. It adds field-backed linear-algebra solvers, updates algebra implementations and examples, and replaces literal coefficient handling with typed ring operations.

Changes

Generic algebra and linear algebra

Layer / File(s) Summary
Base-ring contracts and implementations
ext/crates/algebra/src/algebra/*
Algebras now expose typed base rings and graded pieces, with field-backed scalar arithmetic and manual Steenrod dispatch.
Solver abstractions and resolution stages
ext/crates/algebra/src/linear_algebra/mod.rs
Generic slices and solver APIs provide image, kernel, quasi-inverse, differential-matrix, and next-stage operations with field implementations and tests.

Module and resolution migration

Layer / File(s) Summary
Module and homomorphism APIs
ext/crates/algebra/src/module/*
Module actions and homomorphisms use generic scalars, slices, vectors, submodules, and quasi-inverses.
Chain-complex and resolution integration
ext/src/chain_complex/*, ext/src/resolution*.rs, ext/src/secondary.rs
Chain complexes require field base rings; resolution construction uses solver stages, and homotopy computations use typed ring values.
Yoneda and example migrations
ext/src/yoneda.rs, ext/examples/*
Yoneda and example implementations adopt field bounds, generic coefficients, and base-ring identities.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: hoodmane

Poem

I’m a rabbit with rings in my paws,
Making scalars obey algebra’s laws.
Matrices bloom, kernels align,
Resolutions hop down the line.
Thump, thump—typed coefficients shine!

🚥 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 accurately summarizes the main change: genericizing the algebra crate and resolution engine over the ground ring.
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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ext/crates/algebra/src/algebra/field.rs`:
- Around line 47-52: Extract the repeated graded-piece construction from
module_at in the relevant algebra implementations into a shared helper, such as
classical_graded_piece, accepting a Field base ring and generator count. Move
the FreeModule creation, add_generators, and compute_basis sequence into that
helper, then update module_at in field.rs, AdemAlgebra, and MilnorAlgebra to
call it with self.base_ring() and self.dimension(t).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6f10c759-831f-484e-9122-edf3d5c88e20

📥 Commits

Reviewing files that changed from the base of the PR and between a3a63cb and 2e53345.

📒 Files selected for processing (32)
  • ext/crates/algebra/src/algebra/adem_algebra.rs
  • ext/crates/algebra/src/algebra/algebra_trait.rs
  • ext/crates/algebra/src/algebra/base_ring.rs
  • ext/crates/algebra/src/algebra/field.rs
  • ext/crates/algebra/src/algebra/milnor_algebra.rs
  • ext/crates/algebra/src/algebra/mod.rs
  • ext/crates/algebra/src/algebra/steenrod_algebra.rs
  • ext/crates/algebra/src/lib.rs
  • ext/crates/algebra/src/linear_algebra/mod.rs
  • ext/crates/algebra/src/module/finite_dimensional_module.rs
  • ext/crates/algebra/src/module/finitely_presented_module.rs
  • ext/crates/algebra/src/module/free_module.rs
  • ext/crates/algebra/src/module/homomorphism/free_module_homomorphism.rs
  • ext/crates/algebra/src/module/homomorphism/full_module_homomorphism.rs
  • ext/crates/algebra/src/module/homomorphism/generic_zero_homomorphism.rs
  • ext/crates/algebra/src/module/homomorphism/hom_pullback.rs
  • ext/crates/algebra/src/module/homomorphism/mod.rs
  • ext/crates/algebra/src/module/homomorphism/quotient_homomorphism.rs
  • ext/crates/algebra/src/module/module_trait.rs
  • ext/crates/algebra/src/module/quotient_module.rs
  • ext/crates/algebra/src/module/rpn.rs
  • ext/crates/algebra/src/module/suspension_module.rs
  • ext/crates/algebra/src/module/tensor_module.rs
  • ext/examples/sq0.rs
  • ext/examples/steenrod.rs
  • ext/src/chain_complex/chain_homotopy.rs
  • ext/src/chain_complex/finite_chain_complex.rs
  • ext/src/chain_complex/mod.rs
  • ext/src/resolution.rs
  • ext/src/resolution_homomorphism.rs
  • ext/src/secondary.rs
  • ext/src/yoneda.rs

Comment thread ext/crates/algebra/src/algebra/field.rs
JoeyBF pushed a commit that referenced this pull request Jul 10, 2026
Field, AdemAlgebra, and MilnorAlgebra all built their module_at graded
piece with the same three lines (FreeModule::new + add_generators +
compute_basis). Factor that into a pub(crate) classical_graded_piece
helper in field.rs so the three classical impls share one source of
truth. Behavior-identical (module_at is engine-unused); addresses the
CodeRabbit review on #263.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JNkiiZghHggyMwDWfDn1y5
Field, AdemAlgebra, and MilnorAlgebra all built their module_at graded
piece with the same three lines (FreeModule::new + add_generators +
compute_basis). Factor that into a pub(crate) classical_graded_piece
helper in field.rs so the three classical impls share one source of
truth. Behavior-identical (module_at is engine-unused); addresses the
CodeRabbit review on SpectralSequences#263.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JNkiiZghHggyMwDWfDn1y5

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ext/crates/algebra/src/algebra/milnor_algebra.rs (1)

1812-1824: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider testing at an odd prime as well.

The test covers p=2 only. Adding a p=3 case would exercise the generic (non-2-primary) path and provide broader coverage of module_at correctness. This is non-blocking since the existing test suite and benchmarks already pass for odd primes.

💚 Suggested additional test case
     #[test]
     fn module_at_is_the_graded_piece() {
-        let algebra = MilnorAlgebra::new(ValidPrime::new(2), false);
-        algebra.compute_basis(20);
-        for t in 0..=20 {
+        for &p in &[2, 3] {
+            let algebra = MilnorAlgebra::new(ValidPrime::new(p), false);
+            let max_t = if p == 2 { 20 } else { 30 };
+            algebra.compute_basis(max_t);
+            for t in 0..=max_t {
                 let piece = algebra.module_at(t);
                 // The graded piece is a free Field-module concentrated in degree 0, whose dimension
                 // there equals the algebra's dimension in degree t.
                 assert_eq!(piece.dimension(0), algebra.dimension(t), "p = {p}, t = {t}");
             }
+        }
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ext/crates/algebra/src/algebra/milnor_algebra.rs` around lines 1812 - 1824,
Add an odd-prime case, using ValidPrime::new(3), to the
module_at_is_the_graded_piece test or a companion test, compute the basis, and
assert each graded piece’s dimension matches algebra.dimension(t), covering the
generic non-2-primary path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@ext/crates/algebra/src/algebra/milnor_algebra.rs`:
- Around line 1812-1824: Add an odd-prime case, using ValidPrime::new(3), to the
module_at_is_the_graded_piece test or a companion test, compute the basis, and
assert each graded piece’s dimension matches algebra.dimension(t), covering the
generic non-2-primary path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ee68b4fd-5401-4c49-8c16-7af906034f17

📥 Commits

Reviewing files that changed from the base of the PR and between 2e53345 and 70667e9.

📒 Files selected for processing (3)
  • ext/crates/algebra/src/algebra/adem_algebra.rs
  • ext/crates/algebra/src/algebra/field.rs
  • ext/crates/algebra/src/algebra/milnor_algebra.rs

JoeyBF pushed a commit that referenced this pull request Jul 10, 2026
Extend module_at_is_the_graded_piece to loop over p in {2, 3} so the
generic (non-2-primary) Milnor path is exercised as well. Test-only;
addresses a CodeRabbit coverage suggestion on #263.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JNkiiZghHggyMwDWfDn1y5
@JoeyBF

JoeyBF commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator Author

We're exploring a way to handle motivic computations that doesn't depend on more general ground rings. We'll revisit if we need to.

@JoeyBF JoeyBF closed this Jul 11, 2026
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