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
Extract MA recursion and time-dim guard helpers #76
Audit reports/audit-2026-05-18.md findings #2 and #3.
#2 — The MA recursion Phi_h = sum_{j=1}^{min(h,p)} A_j @ Phi_{h-j}
is implemented twice with different shapes:
identified._ma_coefficients (src/impulso/identified.py:50-67):
vectorised over (C, D) via einsum.
identification.SignRestriction._check_restrictions_at_horizons
(src/impulso/identification.py:209-225): single (n, n) draw
inside the rotation Python loop, using @.
The math is identical; the two copies will drift when one is fixed.
#3 — _guard_no_time_dim is copy-pasted between IRFResult and FEVDResult (src/impulso/results.py), differing only in the "irf" vs "fevd" literal and the class name in the error message
(~17 lines duplicated exactly).
Resolution
Per plans/2026-05-18-audit-cleanup-plan.md (Decisions ledger Q6, Q7):
New module src/impulso/_ma.py with one function compute_ma_phi(A: list[np.ndarray], horizon: int) -> np.ndarray.
List-of-A_j signature. Numpy @ broadcasts over leading dims so
the helper handles both batched (C, D, n, n) and single-draw (n, n) shapes without branching. Stacks with axis=-3 so the
horizon axis lands just before (n, n) regardless of leading rank.
identified._ma_coefficients splits B_draws into the A list and
delegates. identification._check_restrictions_at_horizons splits B_draw similarly, delegates, then loops over horizons applying
restrictions to Phi[h] @ candidate.
_guard_no_time_dim lifts onto VARResultBase. Each subclass
declares _PRIMARY_KEY: ClassVar[str] ("irf", "fevd"). Base
helper reads it.
Acceptance
make check && make test clean.
No behavioural change visible to tests outside tests/test_ma.py —
pure refactor.
tests/test_ma.py covers single-draw, batched, edge cases
(horizon=0, horizon < n_lags, numerical agreement against the
pre-refactor recursion on a fixed seed).
src/impulso/identified.py and src/impulso/identification.py
each call compute_ma_phi exactly once; the old recursion bodies
are deleted.
Shipping
PR3 of the 4-PR audit stack, stacked on top of #75 (PR2).
Activity
refactor: extract MA recursion + lift time-dim guard to base (closes #76
refactor: extract MA recursion + lift time-dim guard to base (closes #76