docs(design): document traits 2 refactor - #184
Draft
Roger-luo wants to merge 10 commits into
Draft
Conversation
|
Extend the traits-2 proposal with a batch-first map contract that frames the branch-staging merge as a hash join with aggregation, specified for memory prefetching, SIMD, multi-threading, and GPU offload. - Reframe the merge as build/probe-with-group-by and pin its cost model to memory latency at out-of-cache sizes. - Cite Chen, Ailamaki, Gibbons & Mowry, "Improving Hash Join Performance through Prefetching" (ICDE 2004; TODS 2007), as the origin of group and software-pipelined prefetching and the cost model the contract serves. - Add a structure-of-arrays batch contract: KeyBatch/TermBatch split into key, precomputed-hash, and coefficient columns; ACMapBatch upsert/probe over columns; a KeyColumn capability behind a new Columnar trait that is kept separate from the minimal Indexable (no cache/column type leaks through the hashing contract). - Separate term production from insertion so gates emit a TermBatch rather than mutating through a per-element closure, enabling prefetch, SIMD, radix partitioning, and device offload. - Document the concrete packed-Pauli/LossyPauliWord plane layout, alignment/padding, hash_into agreement, and gather semantics in word-data-structures.md, per the docs' layout-lives-with-the- representation rule. - Update the compatibility table, non-goals, and open questions (plane granularity and per-target alignment remain open). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ndle Address the Step 2 (type-composition) design gaps surfaced in review: - Split the Coefficient god-trait: cutoff moves to Policy (value type now exposes only magnitude()), sin_cos moves to a separate Angle<C> domain so the rotation angle is no longer welded to the coefficient. RotationOne gains a defaulted angle parameter (A = C). - Give SumStorage associated Word/Coeff types, collapsing the engine to Sum<S, P> and removing the phantom word parameter. - Rename OperatorSum -> Sum; reintroduce ergonomics as a defaulted type-alias family (PauliSum/LossyPauliSum/FermionSum) that is explicitly not load-bearing at the trait level, so it avoids Config's two sins. - Drop the Policy: Copy bound (contradicted the proposal's own non-goal). - Document the n_sites width invariant with a debug_assert. - Update the LossChannel specialization to select on S::Word. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve the Step 3 (Word / Site) design gaps from review:
- Make Word a read-only inspection trait (n_sites, get, weight, iter);
remove set. This stops Word from overclaiming as the propagation
interface (the real kernels are sub-site) and lets ordered algebras
implement it honestly, where in-place positional set is ill-defined.
- Relocate mutation to Pauli-specific traits, decomposed along the
Clifford = Sp(2n,2) join phase structure:
- PauliBits: mutable single-vector X/Z access; hosts rotation kernels.
- SymplecticColumns (role-independent-semantics bit-plane column ops)
and PhaseTrack (role-dependent Z4-word vs Z2+g-tableau phase),
kept separate to mirror Sp and its extension.
- Clifford: blanket impl over the two primitives — one audited copy of
the symplectic sign logic, shared by PhasedPauliWord and Tableau.
- StabilizerFrame: role-exclusive tableau ops (measure, row_multiply).
- PauliSum consumes the one-row action pointwise (Clifford re-keys the
map); word-side Mul / key identity stay inherent.
- Update the compatibility table, trait admission rule, batch-contract
note, and the word/tableau data-structure docs to match.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve the Step 4 (Indexable / hashing) design gaps from review: - Replace `type BuildHasher` with `Indexable::key_hash() -> u64`, the one load-bearing value the whole design depends on. Scalar `Hash`, the map's hasher, and batch `hash_into` are all defined in terms of it, collapsing three implicit contracts into one explicit method with three equations. - Drop the per-key `BuildHasher`: the direct-digest model leaves the map no hasher to choose, so the internal digest algorithm becomes a private representation parameter of the concrete key (the `H` in PauliWord<A, H>), on the same footing as the storage array `A`. - Retain HashFinalize but relocate it to a private ppvm-pauli-word helper; the per-algorithm/per-width avalanche fold runs inside key_hash(), and the public contract is only "key_hash() is well distributed" (property-tested). - Add the pass-through storage contract: provided SumStorage backends consume key_hash() directly via an IdentityBuildHasher, guaranteed rather than left to the user, so no second hash re-correlates the folded bits. - Document that SumStorage's `&Word` (not `&mut Word`) closure signatures are the structural half of the key-mutation-invariant enforcement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Recast the storage/ACMap layer from the algebraic structure (Step 5): - Replace the flat ACMapBase/Iter/AddAssign/Insert/Retain/Consume split with layers graded by algebraic strength over the free module C[W]: L0 Support, L1 Accumulate+Reduce, L2 Scale, L3 Pair, L4 Multiply. The minimum is L0+L1 (a finitely-supported W->C you accumulate and reduce). Each layer names a distinct algebraic property and consumer. - Add L4 Multiply (the group-algebra product / convolution), bounded on ComplexCoefficient since the Pauli product injects phase. - Truncation leaves the algebra: it breaks module exactness, so it is a non-algebraic Retain capability consumed by Policy, not part of ACMap. - Make reduce() first-class: exact-zero pruning is canonicalization to finite-support form, run only at finalize after all coefficients for a word are accumulated (never inline) — correctness by construction, and a bulk stream-compaction each backend specializes. - Design columnar from day one: two backends (HashStore AoS, ColumnStore SoA) over the same graded traits, with four no-AoS-leak rules so the SIMD/GPU store is expressible immediately. Each layer maps to a bulk data-parallel primitive (scale=vector map, reduce=prefix-sum compaction, accumulate=hash-join build, pair=probe, multiply=outer product). - Unify map_add/map_insert into one SumStorage::apply(producer): Clifford, rotation, and multiply are TermProducers feeding accumulate; the Vec staging leak is gone, and the Step 6 batch types become the columnar spelling of Accumulate/Pair. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve Step 7 (tableau) and unify the tableau side with Pauli propagation: - Relax the graded algebra from C[Word] to C[Key] over any Indexable key. The Word bound leaked Pauli-specificity; C[K] is the free module over any index set. Pauli propagation re-adds Word/PauliBits on its own methods. This makes PauliSum and the stabilizer mixture the SAME Sum engine: PauliSum = Sum<HashStore<PauliWord, C>>, TableauMixture = Sum<HashStore<Tableau, C>> (replacing GeneralizedTableauSum). A gate is a TermProducer that re-keys each key via the key's own Clifford impl. This is the "smallest common factor" the prior iteration deferred. - Add TermProducer/RekeyProducer with the zero-overhead guarantees the hot loop needs: generic (never dyn), #[inline] produce, pre-sized sink, so the gate body folds into the accumulate loop with no per-term allocation. - Add KeyProduct (the L4 key-product capability) and Multiply's bound. - Commit to the inverse tableau: measurement becomes a row read in the gate's column-major orientation, eliminating per-measurement transpose; the inverse is a private representation of Tableau (traits unchanged). - Hoist the RNG out of Tableau: inject at measure(&mut, q, rng); clone is pure data, so mixture branches get independent streams (fixes the correlated-sampling bug); Tableau is trivially Send + Sync. - StabilizerFrame holds frame primitives (pivot/row_multiply/canonicalize); Measure is the public algorithm built on them. - State that bulk hash/compare requires canonical orientation, enforced by the transposition guard's &mut borrow; budget the non-square transpose's square-block padding + scratch rather than assuming it away. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Correct two over-designs surfaced while checking the generalized tableau: - No SumStorage trait and no owned workspace. The reusable auxiliary map was an artifact of the old mutate-while-iterate model; the producer/TermBatch model reads the map through & and writes into a separate TermSink, so no aux map is needed. Bundling one into storage would double every sum's allocation and clone it on every mixture branch. `Sum<S: Accumulate, P>` now owns only storage + policy + n_sites; `apply` is a thin method producing into a transient batch, with reuse an opt-in driver optimization (PauliSum), never forced on the frequently-cloned tableau side. - Backends are the containers themselves. The graded algebra traits are impl'd directly on Vec<(K,C)> (small support) and HashMap<K,C,IdentityBuildHasher> (large) — no VecStore/HashStore newtypes, only type aliases for readability. ColumnStore is the one backend that must be a new struct (SoA planes). - Add the generalized tableau as the third instantiation: C[Bitstring]. Its current SparseVector trait is already a second hand-rolled copy of the algebra (add_or_insert = accumulate, retain = Retain, iter = Support); the amplitude vector is Sum<Vec<(Bitstring, Complex)>, CoefficientThreshold>, Clifford gates hit the frame, non-Clifford gates branch the amplitudes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve the key_hash/Indexable over-requirement surfaced by the Vec backend: - The universal key bound (Support::Key, all containers) is now just Eq + Clone — what a linear-scan Vec needs to find and store a key. It never hashes. - Indexable (the digest-bearing hash key) is unchanged but required only where hashing happens: the HashMap and ColumnStore Accumulate impls, and Columnar. - Consequence: a Bitstring used only in a Vec-backed GeneralizedTableau is Eq + Clone and provides no key_hash() it would never use; PauliWord / LossyPauliWord / Tableau, used in hash backends, remain Indexable. - Relax KeyProduct to Eq + Clone (the multiply's backend adds Indexable). No new trait; Indexable keeps its meaning, the digest requirement just lands where the cost is paid. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
ppvm-traits-2configuration boundary around direct type compositionWordand separateIndexablehashing capabilityACMap,PauliWord,GeneralizedTableauSum, andEntryStorewhere their concepts remain unchangedMotivation
The current
Configbundle mixes coefficient, word representation, hashing, map, and truncation choices. These design notes separate algorithm policy and storage from quantum-data representations while retaining established terminology unless an abstraction materially changes.Impact
This PR adds design documentation only. It does not modify the current implementation or public API. The documents are intended to guide a later
ppvm-traits-2prototype and further design iteration.Validation
git diff --cached --check