perf(linalg): scores-based CR2 Bell-McCaffrey DOF (algebraic identity; PT2018 §3.1 Satterthwaite)#656
Conversation
|
Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology No blocking findings. Severity: P3 informational Code Quality No findings. Performance Severity: P2 Maintainability No blocking findings. Severity: P3 Tech Debt No new untracked correctness debt found. The old TODO row for CR2-BM dense residual-maker allocation is reasonably removed, subject to the P2 memory follow-up above. Security No findings. Documentation/Tests Severity: P3 |
7bc8d10 to
47d22dd
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology Severity: P3 Severity: P2 Code Quality No findings. Performance Severity: P3 Maintainability No findings. The stale shared-core docstring was corrected. Tech Debt No new untracked correctness debt found. Removing the old CR2-BM dense residual-maker TODO is reasonable given the current implementation. Security No findings. Documentation/Tests Severity: P3 |
47d22dd to
576d070
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology Finding: P3 Code Quality No findings. Performance No findings. The prior Maintainability No findings. Tech Debt No findings. Removing the old CR2-BM dense residual-maker TODO row is appropriate given the new implementation and tests. Security No findings. Documentation/Tests Finding: P3 |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology Finding: P3 informational Code Quality No findings. Performance No findings. The dense Maintainability No findings. Tech Debt No findings. Removing the CR2-BM dense residual-maker TODO row is appropriate for the affected Security No findings. I did not see secret-like material introduced in the changed files. Documentation/Tests Finding: P3 informational Finding: P3 informational |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
MethodologyNo P0/P1 findings. Severity: P3 informational Code QualityNo findings. PerformanceSeverity: P2 MaintainabilityNo findings. Tech DebtNo findings. Removing the completed CR2-BM dense residual-maker TODO row is appropriate for the scoped clustered path. SecurityNo findings. I saw no secret-like material introduced in the changed files. Documentation/TestsSeverity: P3 informational Severity: P3 informational |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
MethodologyNo P0/P1 findings. Severity: P3 informational Code QualityNo findings. PerformanceSeverity: P2 MaintainabilityNo findings. Tech DebtSeverity: P3 informational SecurityNo findings. Secret-pattern scan of the changed files found no credential-like additions. Documentation/TestsSeverity: P3 informational Severity: P3 informational |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
MethodologyNo P0/P1 findings. Severity: P3 informational Code QualityNo findings. Severity: P3 informational PerformanceSeverity: P2 MaintainabilityNo findings. Severity: P3 informational Tech DebtNo untracked blocking tech debt found. Severity: P3 informational SecurityNo findings. Severity: P3 informational Documentation/TestsSeverity: P3 informational |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
MethodologySeverity: P3 Code QualityNo findings. Severity: P3 informational PerformanceNo findings. Severity: P3 informational MaintainabilityNo findings. Severity: P3 informational Tech DebtNo untracked blocking tech debt found. Severity: P3 informational SecurityNo findings. Severity: P3 informational Documentation/TestsSeverity: P3 informational |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
MethodologyNo findings. Severity: P3 informational Code QualityNo findings. Severity: P3 informational PerformanceNo findings. Severity: P3 informational MaintainabilityNo findings. Severity: P3 informational Tech DebtNo untracked blocking tech debt found. Severity: P3 informational SecurityNo findings. Severity: P3 informational Documentation/TestsNo blocking findings. Severity: P3 informational |
4389348 to
be4e5d2
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
MethodologySeverity: P3 informational Code QualitySeverity: P3 informational PerformanceSeverity: P3 informational MaintainabilitySeverity: P3 informational Tech DebtSeverity: P3 informational SecuritySeverity: P3 informational Documentation/TestsSeverity: P3 informational |
The unweighted per-contrast Satterthwaite DOF materialized the dense n x n residual-maker M = I - X(X'X)^-1 X' and contracted it over all cluster pairs (O(n^2) time per contrast, O(n^2) memory — 3.2 GB at n=20k). With Omega the (n, G) matrix stacking omega_g on disjoint cluster supports, B = Omega' M Omega collapses to diag(||omega_g||^2) - P' M_U P with P = X' Omega: O(nk + G^2 k) per contrast, no n x n allocation. ~32x at n=5k/G=50 (0.57s -> 0.018s); n=20k/G=100 in 0.12s. Algebraically identical — frozen pair-loop oracle parity at rtol 1e-10 (balanced, unbalanced, compound contrasts); both NaN-reliability guards unchanged; 432 consumer tests pass unmodified. REGISTRY notes updated (per-fit setup wording + Appendix-B evaluation sentence). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…P2) + doc syncs (P3s) P2: P_all was (G, k, m) — O(G*k^2) on the batched per-coefficient sweep (contrasts=eye(k)), contradicting the stated O(Gk) bound. The per-cluster product buffers are now contrast-chunked under a 64 MB module-constant cap (monkeypatchable); each contrast's B is computed independently so chunking is bit-identical (locked by a forced one-contrast-chunk test with assert_array_equal). P3s: stale residual-maker-M mention removed from the shared-core docstring; CHANGELOG + REGISTRY memory claims updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The accessible PT2018 arXiv text labels Appendix B as simulation-study details; the Satterthwaite DOF is Section 3.1 / Eq. 13. The scores identity B = Omega'M Omega = diag(||omega_g||^2) - P'M_U P is presented as an algebraic identity rather than paper-attributed, across the linalg docstring, oracle-test docstring, CHANGELOG entry, REGISTRY note, and the PR title. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ure fix) CI (linux-arm + Windows) failed test_contrast_chunking_bit_identical at 1-ULP differences: each contrast's B is computed independently, but the per-cluster GEMM X_g' omega_g[:, c0:c1] runs over a width-c slice and BLAS kernels (GEMV vs GEMM, platform-dependent) may accumulate a column differently at width 1 vs width m — exact on Accelerate, 1-ULP drift elsewhere. The documented chunking-reassociation caveat applies: test renamed to test_contrast_chunking_invariant with assert_allclose(rtol=1e-13), and the bit-for-bit claims corrected in the module-constant comment, docstring, CHANGELOG, and REGISTRY. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… P3s) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te cap CI-review P2: B_j was materialized dense (G,G) per contrast, an O(G^2) memory bound the docs understated as O(Gk). trace_B2 (Frobenius sum) and max|B| are row-separable, so B_j now streams in row blocks bounded by _CR2_BM_CONTRAST_CHUNK_BYTES; neither the n x n residual-maker, the O(G*k*m) product buffers, nor O(G^2) pairwise entries are ever held at once. CHANGELOG/REGISTRY memory claims updated to the honest bound; the forced-tiny-cap invariance test now exercises both chunk axes (row_chunk = 6 < G = 10). Also reworded the stale "bit-equal to prior" REGISTRY sentence (review P3) to floating-point-tolerance parity. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
…g docstring claims Review follow-ups on the row-chunk commit: - P2: "memory bounded by the cap" was still too broad — Q (n,m) and the per-cluster omega_all dict (n,m total) were full-width precomputes. Both now compute inside the contrast chunk (same total FLOPs), leaving X_bi and A_g_Xbi (both O(nk), input-scale) as the only full-size arrays; docstring/CHANGELOG/REGISTRY state exactly which arrays are bounded. - P3: one-way BM DOF's "scores-based formulation (tracked in TODO.md)" pointed at the CR2-BM row this PR resolves — added a specific TODO row for the one-way dense-M path and repointed the note. - P3: scoped _compute_cr2_bm's "bit-equal to prior unweighted behavior" claim to the vcov; the DOF evaluation is scores-based (floating-point- tolerance parity). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
…ominator Review round 3 P2: the contrast-chunk denominator only counted the P_all slab (G*k), so Q_chunk (n per width) escaped the cap when n dominates, and the docs' "bounded by the cap" claim ignored the intrinsic one-contrast floor. The denominator now counts all width-scaled buffers (n + n_g_max + G*k + G, in bytes); docstring/CHANGELOG/REGISTRY state the cap is subject to a one-contrast lower bound (a single contrast needs the O(n) q vector and O(G*k) P_j/PB buffers by construction). Default 64 MB cap still yields a single chunk at benchmark sizes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
…n of AHT Eq. 13) Review round 4 P3: the scalar t-test Satterthwaite degrees of freedom are Eq. 11 in PT2018 §3.1; Eq. 13 is the multi-parameter AHT expression that reduces to Eq. 11 at q=1. linalg.py's own citation names only §3.1 (no equation number) and needs no change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
be4e5d2 to
6cf18fc
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
…res-based Review P3: the one-way unweighted helper still builds the dense H/M (tracked in TODO.md); its inline comment wrongly said "scores-based evaluation." Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
The non-clustered unweighted BM DOF computed a'(MoM)a against an
explicit dense M = I - H (O(n^2 k) hat build; ~20 GB at n=50k,
documented "practical for n < 10k"). The Schur-product expansion
den = sum_i a_i^2 (1 - 2 h_ii) + tr((B S_a)^2), S_a = X' diag(a) X
is exact algebra ((MoM)_{il} = delta_{il}(1-2h_ii) + (x_i'B x_l)^2):
O(n k^2 + k^3) per contrast, n=50k/k=20 in ~16 ms. Frozen dense-oracle
parity at rtol 1e-10 (basic/high-leverage/k40 + compound contrast);
R-anchored hc2_bm goldens pass unchanged.
New noise-floor cancellation guard: the dense den >= 0 exactly (MoM is
PSD by the Schur product theorem) but the expanded difference can
collapse below float precision on extreme-leverage contrasts; such
denominators now NaN instead of inflating the DOF arbitrarily (the
same failure mode the clustered scores path guards; the prior dense
den > 0 kept them).
Deletes the one-way TODO row (#656's follow-up). Completes the
scores-evaluation family: clustered CR2-BM (#656), low-rank A_g (#664),
one-way (this PR).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
Summary
n×nresidual-makerM = I − X(X'X)⁻¹X'and contracted it over all cluster pairs —O(n²)time per contrast andO(n²)memory (3.2 GB at n=20k). Per Pustejovsky-Tipton (2018) Appendix B, withΩthe(n, G)matrix stackingω_gon disjoint cluster supports, the pairwise matrix collapses toB = Ω'MΩ = diag(‖ω_g‖²) − P'M_U PwithP = X'Ω—O(nk + G²k)per contrast, non×nallocation.max|B|, cluster-count boundDOF ≤ G) operate unchanged on the sameBvalues.n×nM). All 432 consumer tests (linalg, vcov-type incl. the CI-inversiondof_hc2_bmpins, stacked-DiD methodology, estimators) pass unmodified. REGISTRY: per-fit setup wording updated + an Appendix-B evaluation sentence on the existing unweighted-DOF-guard Note.Methodology references (required if estimator / math changes)
Validation
tests/test_linalg.py::TestCR2BMScoresBasedDOF(3 frozen-oracle parity tests).Security / privacy
Generated with Claude Code