Commit 1224a19
Close SDID placebo R-parity gap: warm-start + R-anchored fixture + test seam
Closes the last queued SDID R-parity follow-up (per
``project_sdid_pr349_followups.md``, now removed from the memory
index — the work is shipped). Symmetric with the existing
``test_jackknife_se_matches_r`` anchor in TestJackknifeSERParity.
Methodology fix — placebo warm-start:
``synthdid:::placebo_se`` (R/vcov.R) seeds Frank-Wolfe per draw with
``weights.boot$omega = sum_normalize(weights$omega[ind[1:N0_placebo]])``
(fit-time ω subsetted + renormalized) and the fit-time
``weights$lambda``, then re-estimates with ``update.omega=TRUE,
update.lambda=TRUE``. Python's ``_placebo_variance_se`` previously
used uniform cold-start, producing finite-iter convergence-pattern
drift on a handful of draws relative to R's reference SE on the
same panel.
Fix: add ``init_omega`` and ``init_lambda`` kwargs to
``_placebo_variance_se``. The dispatcher now passes ``init_omega=
unit_weights, init_lambda=time_weights`` (fit-time outputs); the
loop seeds ``compute_sdid_unit_weights(init_weights=
_sum_normalize(init_omega[pseudo_control_idx]))`` and
``compute_time_weights(init_weights=init_lambda)`` per draw,
mirroring R's warm-start pattern. At the global FW optimum the
two starts are equivalent (strictly convex objective) — this is
a finite-iter parity fix, not a methodology change.
R-parity fixture + test seam:
* ``benchmarks/R/generate_sdid_placebo_parity_fixture.R`` — R 4.5.2
+ synthdid 0.0.9. Reuses the same Y matrix as
``TestJackknifeSERParity`` (same R_ATT = 4.980848860060929) so
jackknife and placebo R-parity tests share an anchor panel.
Records the 200 per-rep permutations R consumed and the SE from
R's manual ``placebo_se`` loop (which matches
``vcov(method="placebo")`` to machine precision when seeded);
permutations are 0-indexed for direct numpy consumption.
* ``tests/data/sdid_placebo_indices_r.json`` — committed fixture.
* ``_placebo_variance_se`` gains a private ``_placebo_indices``
kwarg (underscore-prefixed, test-only). When supplied, each row
replaces the per-draw ``rng.permutation(n_control)`` so a
Python fit can consume R's exact permutation sequence and
produce a bit-identical SE.
* ``test_placebo_se_matches_r`` (in ``TestJackknifeSERParity``)
intercepts the dispatcher's call to ``_placebo_variance_se`` to
capture the normalized fit-time inputs, then re-invokes the
method with R's permutations through the seam. Asserts
``|py_se - r_se| < 1e-8`` — Rust FW vs R FW differ at sub-ULP
on the same warm-start; tight enough to catch real divergences
without masking BLAS reduction-order tolerance.
Baseline rebase:
``TestScaleEquivariance::test_baseline_parity_small_scale[placebo]``
captured pre-warm-start SE = 0.29385822261006445. New value is
0.293840360160448 (sub-percent shift). The test's bit-identity
contract is preserved per backend; baseline updated with a comment
documenting the warm-start change and pointer to the new R-parity
test that pins the post-fix value to R's reference. p-value (placebo
uses empirical formula, not analytical) is unchanged at
0.004975124378109453.
Verification: ``pytest tests/test_methodology_sdid.py
tests/test_survey_phase5.py -q`` → 230 passed (1 new R-parity
test; existing TestScaleEquivariance baseline rebased; all other
SDID + survey tests unchanged).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 9c908f1 commit 1224a19
6 files changed
Lines changed: 299 additions & 10 deletions
File tree
- benchmarks/R
- diff_diff
- docs/methodology
- tests
- data
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
10 | 13 | | |
11 | 14 | | |
12 | 15 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1153 | 1153 | | |
1154 | 1154 | | |
1155 | 1155 | | |
| 1156 | + | |
| 1157 | + | |
1156 | 1158 | | |
1157 | 1159 | | |
1158 | 1160 | | |
| |||
1695 | 1697 | | |
1696 | 1698 | | |
1697 | 1699 | | |
| 1700 | + | |
| 1701 | + | |
| 1702 | + | |
1698 | 1703 | | |
1699 | 1704 | | |
1700 | 1705 | | |
| |||
1747 | 1752 | | |
1748 | 1753 | | |
1749 | 1754 | | |
| 1755 | + | |
| 1756 | + | |
| 1757 | + | |
| 1758 | + | |
| 1759 | + | |
| 1760 | + | |
| 1761 | + | |
| 1762 | + | |
| 1763 | + | |
| 1764 | + | |
| 1765 | + | |
| 1766 | + | |
| 1767 | + | |
| 1768 | + | |
| 1769 | + | |
1750 | 1770 | | |
1751 | 1771 | | |
1752 | 1772 | | |
| |||
1771 | 1791 | | |
1772 | 1792 | | |
1773 | 1793 | | |
1774 | | - | |
| 1794 | + | |
1775 | 1795 | | |
1776 | | - | |
1777 | | - | |
| 1796 | + | |
| 1797 | + | |
| 1798 | + | |
| 1799 | + | |
| 1800 | + | |
| 1801 | + | |
| 1802 | + | |
| 1803 | + | |
| 1804 | + | |
1778 | 1805 | | |
1779 | 1806 | | |
1780 | 1807 | | |
| |||
1805 | 1832 | | |
1806 | 1833 | | |
1807 | 1834 | | |
1808 | | - | |
1809 | | - | |
1810 | | - | |
1811 | | - | |
| 1835 | + | |
| 1836 | + | |
| 1837 | + | |
| 1838 | + | |
| 1839 | + | |
| 1840 | + | |
| 1841 | + | |
| 1842 | + | |
| 1843 | + | |
| 1844 | + | |
| 1845 | + | |
| 1846 | + | |
| 1847 | + | |
| 1848 | + | |
| 1849 | + | |
| 1850 | + | |
1812 | 1851 | | |
1813 | 1852 | | |
1814 | 1853 | | |
1815 | 1854 | | |
1816 | 1855 | | |
| 1856 | + | |
1817 | 1857 | | |
1818 | 1858 | | |
1819 | 1859 | | |
| |||
1824 | 1864 | | |
1825 | 1865 | | |
1826 | 1866 | | |
1827 | | - | |
| 1867 | + | |
| 1868 | + | |
| 1869 | + | |
| 1870 | + | |
| 1871 | + | |
1828 | 1872 | | |
1829 | 1873 | | |
1830 | 1874 | | |
1831 | 1875 | | |
1832 | 1876 | | |
| 1877 | + | |
1833 | 1878 | | |
1834 | 1879 | | |
1835 | 1880 | | |
| |||
0 commit comments