Commit 0005b49
perf(scm): add FISTA adaptive restart to simplex QP solvers
The inner SCM/SDID QP solver (solve_simplex_qp / solve_simplex_qp_lr)
is first-order FISTA, whose iteration count scales with the condition
number of Q = X0'VX0. Pre-treatment outcome panels are highly collinear
(condition number ~1e6), and the outer V optimisation skews V toward a
few periods, pushing each inner solve from ~0.2ms to ~10ms. With ~10^4
inner solves per fit this produced multi-second runtimes (10-20x slower
than tidysynth, which uses a fixed-iteration interior-point solver).
Add the O'Donoghue & Candes (2015) gradient-scheme adaptive restart:
reset the momentum term t_acc whenever dot(grad, x - x_prev) > 0. This
removes stale momentum on ill-conditioned Q and converges to the same
optimum (verified to match quadprog within 1e-10). Typical SCM fits
speed up 10-20x (e.g. N_co=39, T_pre=40: 2250ms -> 220ms).
Also fix a fragile SDID covariate test that asserted a time-invariant
covariate changes the ATT at tol=1e-6. Time-invariant covariates are
absorbed by the two-way fixed effects, so the true change is ~0; the
test only passed on the old solver's numerical residual. Rewrite it to
use a genuinely time-varying covariate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1 parent ff379c2 commit 0005b49
2 files changed
Lines changed: 30 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
52 | | - | |
| 52 | + | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
| 55 | + | |
56 | 56 | | |
57 | 57 | | |
58 | | - | |
| 58 | + | |
59 | 59 | | |
60 | 60 | | |
61 | | - | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
62 | 72 | | |
63 | 73 | | |
64 | 74 | | |
65 | 75 | | |
66 | | - | |
| 76 | + | |
67 | 77 | | |
68 | 78 | | |
69 | 79 | | |
| |||
97 | 107 | | |
98 | 108 | | |
99 | 109 | | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
100 | 114 | | |
101 | 115 | | |
102 | 116 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1452 | 1452 | | |
1453 | 1453 | | |
1454 | 1454 | | |
1455 | | - | |
1456 | | - | |
1457 | | - | |
| 1455 | + | |
| 1456 | + | |
| 1457 | + | |
| 1458 | + | |
| 1459 | + | |
| 1460 | + | |
| 1461 | + | |
| 1462 | + | |
| 1463 | + | |
| 1464 | + | |
| 1465 | + | |
1458 | 1466 | | |
1459 | 1467 | | |
1460 | 1468 | | |
| |||
0 commit comments