perf(bootstrap): fused column-tiled scatter-GEMM multiplier bootstrap (CS + EfficientDiD)#622
Conversation
… (CS + EfficientDiD) Replace the per-cell weight-matrix slicing loop in the CallawaySantAnna multiplier bootstrap (two fancy-index copies + two GEMVs per (g,t) cell per weight block - 95% of bootstrap wall-time as pure memory traffic) with one column-tiled BLAS GEMM over a fused influence matrix [cell IFs | overall combined IF | event-study combined IFs]. EfficientDiD's per-cell full-width GEMV loop routes through the same kernel via lazy scaled-EIF columns. New in bootstrap_chunking.py: - ReplayableWeightStream: weight-block stream re-iterable bit-identically via rng state snapshot/restore (rust per-row seeding, numpy stream, and the stratified survey eager-generation branch all replay exactly). - tiled_if_matmul: column tiles under a call-time byte cap (_TARGET_TILE_BYTES, 128MB); each tile scattered once (assignment-scatter contract: unique, disjoint index arrays per column) and consumed by one GEMM per weight block; loud ValueError if a single-pass iterator meets multiple tiles. psu_ids and the G<2 guards now resolve rng-free (np.unique/np.arange) outside the replay factories, so the state snapshot precedes every draw. CS group aggregation moves post-loop (reads only completed perturbed cell draws). Point estimates are bit-identical; bootstrap SEs/CIs/p-values match the old loop to BLAS reassociation (<~1e-15 rel, far below Monte-Carlo error). Tests: kernel oracle vs old per-column GEMV semantics, replay determinism (3 weight types, both backends), multi-tile-actually-ran counting guard, tile-forced end-to-end invariance twins (CS unit/cluster/survey-PSU/ stratified-survey; EfficientDiD unit/cluster/survey-PSU/weights-only), and a NaN-cell bootstrap isolation test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X4AzrFUMqJxcUumSH31mSr
…tical-stage TODO CHANGELOG Changed entry with measured before/after; performance-plan.md Phase 2 section (stage split, kernel design, A/B table, rejected sparse variant); TODO row for the pre-existing EfficientDiD analytical-stage scaling pathology found while benchmarking; doc-deps note for the shared kernel; refresh a stale staggered_bootstrap.py line reference in REGISTRY. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X4AzrFUMqJxcUumSH31mSr
|
Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology No blocking findings. The PR preserves the documented CS contract that bootstrap perturbs per-cell IFs and combined IF/WIF aggregations, and preserves the EfficientDiD documented multiplier-on-EIF implementation choice. The new Code Quality No findings. The replayable stream design is explicit and guarded for single-pass iterators in Performance No blocking findings. The performance-oriented rewrite is consistent with the stated goal. The new EfficientDiD analytical hot-loop concern is not introduced by this PR’s bootstrap rewrite. Maintainability No findings. The shared kernel reduces duplicate bootstrap matmul logic across CS and EfficientDiD. Tech Debt
Security No findings. No suspicious secret patterns were found in the changed files. Documentation/Tests
Validation note: |
…ding CI review P3s: add a panel=False tile-forced invariance test (observation-level IFs through the same tiled kernel) and distinguish the draw-block chunking (shared with HAD) from the fused tiled kernel (CS + EfficientDiD only) in the doc-deps note. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X4AzrFUMqJxcUumSH31mSr
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
MethodologyNo blocking findings. Affected source contracts checked: CS bootstrap/WIF contract in
The new CS path builds perturbation columns for per-cell IFs, overall combined IF, and event-study combined IFs in Code QualityNo findings. The reusable kernel documents the assignment-scatter contract and guards multi-tile use with single-pass iterators in PerformanceNo blocking findings. The change is performance-oriented and avoids the previous per-cell weight slicing loop. The remaining MaintainabilityNo findings. The shared Tech Debt
SecurityNo findings. No suspicious secret patterns were found in the changed files. Documentation/TestsNo blocking findings. Prior review items are resolved: RCS forced-tile coverage is now present in Validation note: |
Summary
bootstrap_chunking.py:tiled_if_matmul(column tiles under a call-time byte cap; assignment-scatter contract documented; loudValueErrorif a single-pass iterator meets multiple tiles) +ReplayableWeightStream(weight-block stream re-iterable bit-identically via RNG state snapshot/restore - rust per-row seeding, numpy stream, and the stratified-survey eager-generation branch all replay exactly).psu_ids+ the G<2 guards now resolve rng-free (np.unique/np.arange) outside the replay factories; CS group aggregation moves post-loop (reads only completed perturbed cell draws).docs/performance-plan.md.W @ (eif/n)vs(W @ eif)/n) - same reassociation-level equivalence, called out in comments/CHANGELOG.Methodology references (required if estimator / math changes)
Validation
tests/test_bootstrap_chunking.py(kernel oracle vs the old per-column GEMV semantics; replay determinism across rademacher/mammen/webb; counting guard proving multi-tile actually replays; single-pass-iterator guard; tile-forced end-to-end invariance twins for CS unit/cluster/survey-PSU/STRATIFIED-survey and all four EfficientDiD weight paths),tests/test_staggered.py(NaN-cell bootstrap isolation). Targeted sweep 951 passed on BOTH backends (rust + DIFF_DIFF_BACKEND=python); full suite 8405 passed with one known pre-existing order-dependent dCDH failure (passes standalone; tracked in TODO.md since fix(staggered): CS panel reg/ipw influence functions + per-cell SEs to DRDID parity #619). No existing test expectation changed or weakened.docs/performance-plan.md(Phase 2 section), including the stage-level split that motivated the rewrite and a measured-and-rejected scipy-sparse variant.Security / privacy
Generated with Claude Code