Split the secondary layer + add SecondaryExtModule::secondary_massey - #278
Open
JoeyBF wants to merge 6 commits into
Open
Split the secondary layer + add SecondaryExtModule::secondary_massey#278JoeyBF wants to merge 6 commits into
JoeyBF wants to merge 6 commits into
Conversation
|
Warning Review limit reachedNext included review available in 43 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (16)
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. Comment |
JoeyBF
force-pushed
the
claude/259-phase3-secondary
branch
from
August 1, 2026 06:29
89d131d to
e3c76df
Compare
Generalize the `Algebra` trait family to be multigrading-capable, as the foundation for treating Ext(k,k) as a genuine bigraded algebra (issue SpectralSequences#259). - `Algebra<const N: usize = 1>`: degree *inputs* now take `impl Into<MultiDegree<N>>`, so singly-graded callers keep passing bare `i32`s (via new `From<i32> for MultiDegree<1>`). The default `N = 1` keeps every existing `A: Algebra` bound and `dyn` usage working unchanged. - `enum_dispatch` cannot handle a generic trait, so `Algebra` is removed from `SteenrodAlgebra`'s dispatch list and hand-rolled via `dispatch_steenrod!` (the pattern already used for `PairAlgebra`). `UnstableAlgebra`, `GeneratedAlgebra`, and `MuAlgebra` stay singly-graded and keep enum_dispatch. - Milnor, Adem, and Field implement `Algebra` (default `N = 1`), converting the incoming degree to `i32` at each method boundary. - Degree-returning methods stay `i32` (the distinguished filtration direction), so the resolution engine's degree arithmetic is untouched. - `algebra` now depends on `sseq` for `MultiDegree` (no dependency cycle). Behavior is unchanged for the singly-graded path; all 51 algebra tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nk9J57zb6GpvZxrduhGSdY
JoeyBF
force-pushed
the
claude/259-phase3-secondary
branch
2 times, most recently
from
August 1, 2026 07:32
8be224f to
cbdd6d7
Compare
- Remove 'Grading' section header and condense explanation - Simplify steenrod_algebra.rs enum comment - Preserve essential information about genericity and dispatch strategy Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nk9J57zb6GpvZxrduhGSdY
…equences#259) Split the conflated `ExtAlgebra` into two objects that match the two things a resolution computes: - `ExtAlgebra` is the ring `Ext(k, k)`, backed by a resolution of `k`. It owns the ring-product cache (`res(k) -> res(k)`) and is the single home for the multiply-by-a-class maps Massey products need (`ExtAlgebra::class_product_map`), fixing the awkwardness noted in SpectralSequences#258 where `massey_b_hom` rebuilt that map from scratch each call. - `ExtModule` is a module `Ext(M, k)` over that ring, backed by a resolution of `M`. It holds a shared `Arc<ExtAlgebra>` (so all modules over the same `k` reuse one ring cache) and its own module-action cache (`res(M) -> res(k)`). `M == k` collapses to "a module over itself": `ExtModule` shares its resolution `Arc` with the ring, so `is_unit` is now a structural `ptr_eq` (`ExtModule::is_unit`) rather than a stored flag. `without_unit` is replaced by `ExtModule::intrinsic` for the resolution-intrinsic `d2` path. `ExtAlgebra` implements `algebra::Algebra<2>` and `ExtModule` implements `algebra::module::Module<2>` (with `Algebra = ExtAlgebra`), realising the "resolving an algebra yields an Algebra, resolving a module yields a Module" correspondence on the real trait family. The trait product/action methods are total; the inherent `multiply_into`/`try_multiply` keep their `Option`-returning out-of-range ergonomics. The shared product core lives in module-level helpers (`cached_generator_product_map`, `products_into`, `combine_product`) so ring and module products do not duplicate logic. Massey products move to `ExtModule` (a, b in the ring; c in the module), with `massey_b_hom` now sourced from the shared ring cache via `class_product_map`. `SecondaryExtAlgebra` wraps an `ExtModule`; the four examples and in-module tests are updated. Behaviour is unchanged: the three Massey regression tests (SpectralSequences#116), the product test, and the d2 test all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nk9J57zb6GpvZxrduhGSdY
Add `ResolutionHomomorphism::linear_combination`, which builds the chain map `∑ cᵢ·fᵢ` from maps sharing a source, target, and shift by summing their generator images directly — no quasi-inverse lift. `ExtAlgebra::class_product_map` now uses it for multi-generator classes: a single generator returns the cached per-generator map, and a general class *adds* the cached generator maps instead of re-solving the class from scratch via `from_class`. This realises the "storing lifts per generator, adding maps is cheap" design and gives the shared ring cache a real payoff for the multiply-by-a-class maps Massey products consume. A new regression test cross-checks the two independent linear-combination strategies at the first two-generator bidegree of Ext(F₂,F₂) — (n=15, s=5): `class_product_map` sums maps at the chain level, `multiply_into` sums them at the hom_k level, and the induced products must agree. They do. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nk9J57zb6GpvZxrduhGSdY
…tModule Mirror the SpectralSequences#259 primary split one level up. The old `SecondaryExtAlgebra` was misnamed — it wrapped an `ExtModule` and conflated the module-`M` secondary data (d2, module secondary products) with the ring-`k` secondary data (unit secondary resolution + E3 page), joined by `is_unit` branching. Now: - `SecondaryExtAlgebra` is the ring secondary layer over `k` (wraps `ExtAlgebra`, owns k's secondary resolution + E3 page + `page_data`). - `SecondaryExtModule` is the module secondary layer over `M` (wraps `ExtModule`, shares an `Arc<SecondaryExtAlgebra>`, owns M's secondary resolution + E3 page, `d2`/`survives`, the module secondary-product cache, and `secondary_multiply_into`). `M == k` shares the secondary resolution and E3 page `Arc`s between module and ring (`SecondaryExtModule::is_unit` = the primary `ExtModule::is_unit`), so the `is_unit` branches collapse into structural `Arc` sharing — `extend_all` computes k's E3 once and installs it on the ring in the shared case. The `secondary` and `secondary_product` examples and the `test_sphere_d2` regression move onto `SecondaryExtModule::from_module`; `unit_page_data` becomes `algebra().page_data`. Behaviour is unchanged (d2 test passes). This is the structural half; the ring secondary class-product cache and the `secondary_massey` method that consumes it follow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nk9J57zb6GpvZxrduhGSdY
…o it
The secondary Massey example hand-rolled ~500 lines of Z/p² + λ bookkeeping —
building the two secondary lifts, the chain homotopy, the E3 kernel, and the
Mod_{Cλ²} read-off — the same plumbing SpectralSequences#247 abstracted for primary Massey.
Encapsulate it as `SecondaryExtModule::secondary_massey(a, b, job)`, the
Mod_{Cλ²} analogue of `ExtModule::massey_iter_a`. `a ∈ Ext(M, k)` comes from the
module side, `b, - ∈ Ext(k, k)` from the shared ring side; both are
`SecondaryClass`es (an Ext part plus an optional λ part, since secondary Massey
needs non-standard lifts). A new `SecondaryClass` input type and a shared
`build_secondary_hom` helper (generalising the example's `get_hom`) construct the
secondary lift + optional λ chain map from coordinates. `job = Some(s)` shards the
chain-homotopy computation, matching the other secondary scripts.
The read-off is ported verbatim, so behaviour is unchanged: a new regression test
(`test_sphere_secondary_massey`) pins `<-, h_0, h_1>` on S_2 against the exact
bracket family the pre-refactor example printed, and the refactored example
reproduces that output byte-for-byte. `secondary_massey.rs` is now just the
interactive front-end (querying classes, formatting output).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nk9J57zb6GpvZxrduhGSdY
JoeyBF
force-pushed
the
claude/259-phase3-secondary
branch
from
August 26, 2026 19:03
cbdd6d7 to
5a8af60
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A follow-up to #259 that applies the same ring/module split, one level up, to the secondary ($d_2$ / $\mathrm{Mod}_{C\lambda^2}$ ) layer — and gives secondary Massey products a real home instead of a hand-rolled example.
What
secondary.rshad a singleSecondaryExtAlgebrathat was misnamed: it wrapped anExtModuleand owned both the module-Msecondary data and the ring-ksecondary data, joined by the sameis_unitbranching #259 removed from the primary layer. This PR splits it, mirroringExtAlgebra/ExtModule:SecondaryExtAlgebra— the ring secondary layer overk: the secondary resolution ofkand itsSecondaryExtModule— the module secondary layer overM: the secondary resolution ofM, itsd2/survives, and theArc<SecondaryExtAlgebra>; whenM == kit shares the ring's secondary resolution and page (is_unit=Arc::ptr_eq), retiring the branches.secondary_massey
examples/secondary_massey.rspreviously hand-built the ring-side secondary multiply-by-bmap and hand-rolled the entire ~500-line bracket computation — the secondary analogue of theclass_product_mapgap #259 filled. That logic now lives inSecondaryExtModule::secondary_massey, which computesa ∈ Ext(M,k)(module side) andb, - ∈ Ext(k,k)(ring side). A smallSecondaryClass { degree, ext, lambda }input type carries the non-standard-lift classes (Notes for review
test_sphere_secondary_massey) before the inline version was deleted — behaviour is unchanged up to the documented sign.build_secondary_homnow asserts theSecondaryClassStacking
Built on #268 (multigrade traits) + #277 (the primary ext split). Its diff currently includes both and will shrink to just the secondary commits as those merge and I rebase.
Testing
cargo test -p ext ext_algebra(test_sphere_d2,test_sphere_secondary_massey, plus the primary suite), fulljust lint/just testCI-parity matrix, and--examples --features concurrentbuild — all green.🤖 Generated with Claude Code
https://claude.ai/code/session_01Nk9J57zb6GpvZxrduhGSdY
Generated by Claude Code