ZeroSignRestriction#

class impulso.identification.ZeroSignRestriction(*, shock_names, zero_restrictions=<factory>, sign_restrictions=<factory>, restriction_horizon=0, n_rotations=1000, random_seed=None, on_failure='nan')[source]#

Bases: ImpulsoModel

Combined zero-and-sign restriction identification.

Implements the recursive orthogonalisation of Arias, Rubio-Ramirez & Waggoner (2018). Writing the structural impact matrix as P = L Q with Q orthogonal, a zero restriction “variable i does not respond to shock j on impact” is the linear condition e_i’ L q_j = 0 on the j-th column of Q. Columns are built one at a time, each drawn uniformly from the unit sphere of the null space of

R_k = [ Z_k L ; q_1’ ; … ; q_{k-1}’ ]

where Z_k selects the rows carrying zero restrictions on shock k. The null-space draw imposes the zeros exactly (to SVD precision) and orthogonality to the earlier columns by construction, so no rejection step is needed for the zeros — only the sign restrictions are checked by accept/reject.

Shocks are ordered internally by their number of zero restrictions, descending (ties keep the order given in shock_names; unnamed padding columns go last), because the construction requires it. Rows of the returned matrix are always in data order and columns are permuted back to shock_names order, so the internal ordering is not observable.

Parameters:
shock_names#

Structural shock labels, in the order the columns of the returned matrix should appear. May be shorter than the number of variables — remaining columns are labelled unidentified_1, … and carry no restrictions.

Type:

list[str]

zero_restrictions#

Dict mapping variable -> list of shocks that have zero impact on that variable. Keyed by variable for consistency with sign_restrictions.

Type:

dict[str, list[str]]

sign_restrictions#

Dict mapping variable -> {shock: “+” or “-“}, the same format SignRestriction uses.

Type:

dict[str, dict[str, str]]

restriction_horizon#

Sign restrictions are imposed at horizons 0..restriction_horizon. Zero restrictions are always impact only (h = 0); long-run zeros are not supported.

Type:

int

n_rotations#

Maximum candidate draws per posterior draw.

Type:

int

random_seed#

Seed for reproducibility.

Type:

int | None

on_failure#

What to do for a posterior draw where no candidate satisfies the sign restrictions within n_rotations attempts. “nan” (default) fills that draw with NaN and warns once at the end; “raise” raises immediately.

Type:

Literal[‘nan’, ‘raise’]

Note

Candidates are drawn unweighted: each accepted draw keeps the Q that the recursion produced, with no importance weight correcting for the volume element of the zero-restricted manifold. Arias, Rubio-Ramirez & Waggoner (2018) derive such a weight for their uniform-conditional prior over the identified set. The unweighted draws therefore do not represent that prior exactly when the restrictions leave a set (rather than a point) identified. Two regimes are unaffected: with no zero restrictions the draws are exactly Haar, and when the counting condition holds with equality throughout (z_j = n - j for every shock, shocks ordered by descending zero count) every null space is one-dimensional, so the system is exactly identified — the answer is a point up to column signs and reproduces the Cholesky factor, and no weight can move a point. Anything looser leaves a set rather than a point. See the explanation page for the full caveat.

identify(L, var_names, posterior=None, data=None, n_lags=None)[source]#

Apply zero-and-sign-restriction identification.

Parameters:
  • L (ndarray) – Lower-triangular Cholesky factor, shape (chains, draws, n_vars, n_vars).

  • var_names (list[str]) – Variable names in the data’s natural order.

  • posterior (xr.Dataset | None) – Required when self.restriction_horizon > 0, which needs the VAR coefficients B for the MA recursion. Ignored for impact-only restrictions.

  • data (VARData | None) – Unused. Accepted for Protocol uniformity.

  • n_lags (int | None) – Unused — the lag order is read off B. Accepted for Protocol uniformity.

Returns:

Structural shock matrix, shape (chains, draws, n_vars, n_vars), with columns in shock_names order (padding last). Draws where no candidate satisfied the sign restrictions are NaN. Acceptance diagnostics land on IdentifiedVAR.shock_matrix() attrs under the zero_sign_ prefix.

Raises:

ValueError – If a restriction names an unknown variable, more shocks are named than there are variables, the zero pattern violates the rank condition, restriction_horizon > 0 without a posterior, or on_failure=”raise” and a draw found no admissible candidate.

Return type:

ndarray

property last_diagnostics: dict[str, float]#

Diagnostics from the most recent identify() call.

Scheme-prefixed scalars (see CONTEXT.md “Identification diagnostics”), overwritten per call and surfaced onto IdentifiedVAR.shock_matrix().attrs by the pipeline. Returns a copy.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context, /)#

This function is meant to behave like a BaseModel method to initialize private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Parameters:
  • self (BaseModel) – The BaseModel instance.

  • context (Any) – The context.

Return type:

None

shock_coords(n_vars)[source]#

Named shocks in user order, then rotation-arbitrary padding.

Parameters:

n_vars (int)

Return type:

list[str]