You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 4037712
Browse filesBrowse the repository at this point in the historyBrowse files
| Reuse the demeaner's factorized codes in `absorbed_fe_rank`/`absorbed_fe_cr1_k_increment` instead of re-factorizing: at 186k rows the rank helper adds ~1.9 ms per absorbed fit (7.7% of the fastest Rust-served TWFE fit) and the K_reference increment ~3.2 ms per clustered-hc1 absorbed fit (~13%; see `docs/performance-plan.md` "Component-aware absorbed-FE rank"), and the helpers and `demean_by_groups` factorize the same group columns. Threading the codes through the call sites halves the factorize work; the `connected_components` call itself is ~1.1 ms. Deliberately not done in the correctness PRs. |`diff_diff/utils.py`| #variance-inventory | Quick | Low |
81
81
|`EfficientDiD` conditional path: the largest remaining O(n) stage is the sieve/nuisance construction outside the tiled pass (~9s at 10k). (The `_ridge_solve_weights` Python-prep shave landed 2026-07-07 — the `omega_stack[rest]` fancy-index copy and tail scatter are skipped when no row is zero-masked, byte-identical outputs; the `zero_mask` abs scan itself remains, needed for correctness.) |`efficient_did_covariates.py`| CS-scaling | Mid | Low |
82
82
|`_rq_fit` LP assembly is dense (`A_eq = [X, I, -I]` with dense identity blocks, rebuilt per cell fit): a `scipy.sparse` construction would cut memory and likely HiGHS time for large cells / bootstrap-heavy covariate CiC/QDiD fits. CAVEAT before doing it: a different matrix representation can change HiGHS's vertex selection at degenerate/tied QR optima - end-to-end covariate goldens are tie-selection-gated (fine), but the `qr_cases` tight coefficient matches may shift to the equal-loss branch; re-run the parity suite and re-calibrate if needed. |`diff_diff/changes_in_changes.py::_rq_fit`| covariates PR | Quick | Low |
83
-
| Evaluate flipping `DIFF_DIFF_SOLVE_OLS_FASTPATH` default-ON after an opt-in soak (the 2026-07 certified normal-equations Cholesky fast path, both backends). A flip needs: golden/parity-suite recapture at the tol-bounded posture (fitted ~1e-8 abs / SE ~1e-6 rel — the default today is byte-pinned in several benchmark conventions), certification-rate telemetry across real workloads (any decline is silent-correct but forfeits the speedup), and the staged default-flip protocol used for `df_convention` (v4-class change). Lifecycle tracked in docs/v4-deprecations.yaml (M-008). |`diff_diff/linalg.py::_resolve_solve_ols_fastpath`, `rust/src/linalg.rs::solve_ols_chol`| CS-scaling | Mid | Low |
83
+
| Evaluate flipping `DIFF_DIFF_SOLVE_OLS_FASTPATH` default-ON after an opt-in soak (the 2026-07 certified normal-equations Cholesky fast path, both backends). A flip needs: golden/parity-suite recapture at the tol-bounded posture (fitted ~1e-8 abs / SE ~1e-6 rel — the default today is byte-pinned in several benchmark conventions), certification-rate telemetry across real workloads (any decline is silent-correct but forfeits the speedup), and a staged default-flip protocol of its own - a later flip is a major-version change on its own schedule, re-evaluated in 4.x. Decision at the 4.0 cut recorded in docs/v4-deprecations.yaml (M-008). |`diff_diff/linalg.py::_resolve_solve_ols_fastpath`, `rust/src/linalg.rs::solve_ols_chol`| CS-scaling | Mid | Low |
Copy file name to clipboardExpand all lines: docs/methodology/REGISTRY.md
+32-6Lines changed: 32 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2150,6 +2150,11 @@ where `W_it(h) = 1[K_it = h]` are lead indicators, estimated on `Omega_0` only.
2150
2150
- Bootstrap does not update pre-period SEs (they are from the lead regression)
2151
2151
- When `balance_e` is set, lead indicators are restricted to balanced cohorts; the full Omega_0 sample (including never-treated) is kept for within-transformation
2152
2152
- Only affects event study aggregation; overall ATT and group aggregation unchanged
- **Note:** `pretrends=True` with analytical `survey_design` (strata/PSU/FPC) is supported. The lead regression uses survey-weighted demeaning, WLS point estimates, and `compute_survey_vcov()` for design-based VCV. The full survey design is preserved (subpopulation approach): Omega_0 scores are zero-padded back to full-panel length so PSU/strata structure is maintained for variance estimation. The F-test in `pretrend_test()` uses the full-design `df_survey` as denominator df. Replicate-weight survey designs raise `NotImplementedError` with `pretrends=True` because per-replicate lead regression refits are not yet implemented.
as for ImputationDiD, the default `cluster_var = unit` is internal to the unit-level
2239
+
influence-function machinery, so the uniform 4.0 `cluster=False` off-switch is an
2240
+
accepted explicit no-op. Roster in `docs/methodology/variance-conventions.md`.
2232
2241
- **Note (rank-guarded TSL-variance bread):** The Stage-2 variance bread `(X_2'WX_2)^{-1}` is inverted by the shared `_rank_guarded_inv` (`diff_diff/linalg.py`) on BOTH the analytical (`two_stage.py`) and multiplier-bootstrap (`two_stage_bootstrap.py`) surfaces. `np.linalg.solve` raised only on an exactly-singular bread (prior fallback: dense `lstsq`); a **near**-singular `X_2'WX_2` would otherwise flow a garbage inverse (~1e13) into the SE. The rank-guard truncates redundant directions → finite SE on the identified subspace (NaN at rank 0) and warns. A dropped (unidentified) Stage-2 coefficient (event-time / group effect) is reported with **NaN** SE on both the analytical and bootstrap surfaces — not the zero-filled `0`. `X_2` is the Stage-2 indicator design (treatment/event-time/group dummies), not user covariates. See the CallawaySantAnna "rank-guarded IF standard errors" Note. Sibling of axis-A finding #17.
2233
2242
2234
2243
**Key implementation requirements:**
@@ -2430,6 +2439,13 @@ The paper text states a stricter bound (T_min + 1) but the R code by the co-auth
2430
2439
- [x] Anticipation parameter support
2431
2440
- [x] Never-treated encoding (0 and inf)
2432
2441
- [x] Survey design support (Phase 3): Q-weights compose multiplicatively with survey weights; TSL vcov on composed weights; survey design columns propagated through sub-experiments. Replicate weights supported via estimator-level refit with Q-weight composition (see Replicate Weight Variance section).
in `docs/methodology/variance-conventions.md` "Default clustering roster"): the
2444
+
stacked regression clusters by construction and `cluster` accepts only `'unit'` /
2445
+
`'unit_subexp'`; the uniform 4.0 `cluster=False` off-switch is therefore REJECTED
2446
+
here with the existing validator message rather than yielding an unclustered SE
2447
+
(no such variance is defined for the stacked design). The spec's "becomes an
2448
+
instance of the general policy" applies to the default resolution only.
2433
2449
- **Note (intercept SEs excluded from R parity):** for the base StackedDiD `clubSandwich` parity fixture (not the CBWSDID `cbwsdid` fixture below), stacked event-study *interaction* SEs match R at ~2e-13, but the regression *intercept* SE differs from R by a measured ~0.3% — a nuisance-parameter reference-cell/parameterization gap, not machine-precision lockable. Surfacing `se_cr1_intercept`/`se_cr2_intercept` would add an unasserted, R-divergent public field, so intercept SEs are deliberately not exposed and are excluded from the parity lock (`tests/test_methodology_stacked_did.py`; SE-audit C1/(c) decision, 2026-07-09).
2434
2450
- **Note:** Survey weights compose multiplicatively with Q-weights for StackedDiD; only `weight_type="pweight"` (default) is supported — `fweight` and `aweight` are rejected because Q-weight composition changes weight semantics (non-integer for fweight, non-inverse-variance for aweight)
2435
2451
@@ -3068,11 +3084,13 @@ the finite-dimensional `p_0` is handled by the variance correction below.
3068
3084
`cluster=None` IS the per-unit IF variance by definition (see "IF-based
3069
3085
variance estimators vs analytical-sandwich estimators"); the inherited
3070
3086
value is family-consistent and truthful. No vocabulary widening.
3071
-
- **Note:** M-080 position (auto-cluster policy) — DMLDiD's per-unit
3072
-
influence-function variance IS unit-level clustering, so the 4.0
3073
-
auto-cluster DEFAULT flip is inert for it — mirroring how CallawaySantAnna
3074
-
is absent from M-080's `code_refs` and how M-010 pre-empted M-080 for the
3075
-
TWFE event-study mode. COARSER-than-unit clustering ships via the CS-style
3087
+
- **Note:** M-080 position (auto-cluster policy, re-scoped 2026-10-18 -
3088
+
category b in `docs/methodology/variance-conventions.md` "Default clustering
3089
+
roster") — DMLDiD's per-unit influence-function variance IS unit-level
3090
+
clustering, so the 4.0 auto-cluster DEFAULT flip is inert for it, as for
3091
+
CallawaySantAnna and every other by-construction estimator; by decision it
3092
+
carries no auto-cluster metadata (`cluster_name=None`) and the uniform 4.0
3093
+
`cluster=False` off-switch is an accepted explicit no-op. COARSER-than-unit clustering ships via the CS-style
3076
3094
`cluster=` constructor parameter (3.11): the synthesized/injected
3077
3095
`SurveyDesign(psu=...)` drives PSU-cohesive folds, the per-cell CR1 SE,
3078
3096
the bootstrap draw structure and `df_inference`, while the moment kernels
@@ -6078,7 +6096,9 @@ equivalently `p <= alpha`.
6078
6096
would be unreachable) and the constant are library choices — the paper
6079
6097
declines to supply a cutoff (review lines 917-918) — and change no behavior.
6080
6098
- **Note:** M-080 unit auto-cluster is satisfied by construction: the bootstrap
6081
-
resamples individuals. No `cluster=`, `vcov_type=`, survey design, covariates,
6099
+
resamples individuals (decision recorded 2026-10-18: category d in
6100
+
`docs/methodology/variance-conventions.md` - no `cluster` param and no cluster
6101
+
metadata on the container). No `cluster=`, `vcov_type=`, survey design, covariates,
6082
6102
staggered adoption, censoring, or repeated cross-sections in this version
6083
6103
(the review's deferred extensions).
6084
6104
- **Note:** `DiagnosticReport` and `BusinessReport` reject `DurationDiDResults`
@@ -6841,6 +6861,12 @@ should be a deliberate user choice.
6841
6861
6842
6862
**Note:** This estimator is a **documented synthesis** of ingredients — no single published software package implements the exact recipe. `did2s` (R/Stata, Butts & Gardner 2022) implements the Gardner two-stage residualization but does NOT support ring covariates. The Butts (2021/2023) paper proposes the ring estimator in Equations 5/6/8 (non-staggered) and Section 5 / Table 2 (staggered) but does not ship reference software. The diff-diff implementation combines: (a) Butts (2021) Section 5 / Table 2 identification, (b) Gardner (2022) two-stage residualize-then-fit, (c) Wave A's Conley spatial-HAC vcov.
SpilloverDiD is the ONE required-unit estimator still running observation-level HC
6866
+
when `cluster=` is omitted, so its default SE flips to unit clustering at 4.0 with
6867
+
TWFE's carve-outs mirrored (explicit `cluster=` wins; Conley drops the auto-cluster;
6868
+
never injected as a survey PSU). 3.x numbers are reproduced with `cluster=False`.
6869
+
Roster in `docs/methodology/variance-conventions.md` "Default clustering roster".
6844
6870
- **Note (rank-guarded Wave D bread):** The Wave D variance bread `A_22 = (X_2'WX_2)^{-1}` is inverted by the shared `_rank_guarded_inv` (`diff_diff/linalg.py`) on the already-column-dropped kept submatrix. `np.linalg.solve` raised only on an exactly-singular bread (prior fallback: dense `lstsq`); a **near**-singular kept Gram would otherwise flow a garbage inverse (~1e13) into the SE. The rank-guard truncates redundant directions → finite SE on the identified subspace (NaN at rank 0), re-inflated to (k, k) with NaN at the dropped positions, and warns. See the CallawaySantAnna "rank-guarded IF standard errors" Note. Sibling of axis-A finding #17.
0 commit comments