pyperfectforesight.solve_perfect_foresight_expectation_errors#

pyperfectforesight.solve_perfect_foresight_expectation_errors(T, params_dict, ss, model_funcs, vars_dyn, news_shocks, X0=None, initial_state=None, ss_initial=None, stock_var_indices=None, constant_simulation_length=False, solver_options=None, sub_x0=None, compiled_ss=None)[source]#

Solve a perfect foresight model with multiple surprise (MIT) shocks.

Replicates Dynare’s perfect_foresight_with_expectation_errors_setup / perfect_foresight_with_expectation_errors_solver. At each learnt_in period agents receive a surprise update to their information set and re-solve the perfect foresight problem from that point forward. The full simulation path is stitched from the sub-simulations.

Parameters:
  • T (int) – Total simulation length (number of periods in the stitched output).

  • params_dict (dict) – Parameter values.

  • ss (ndarray, shape (n_endo,)) – Default terminal steady state (initial right BVP boundary), used unless overridden by an endval provided in a news_shocks 3-tuple.

  • model_funcs (dict) – Output of process_model().

  • vars_dyn (list of str) – Endogenous variable names (may be extended by process_model).

  • news_shocks (list of tuples) –

    Each entry is either a 2-tuple (learnt_in, exog_path) or a 3-tuple (learnt_in, exog_path, endval) where

    • learnt_in is the period at which agents receive new information (1-indexed, must be in [1, T]).

    • exog_path is either an array with at least T_sub rows and n_exo columns, representing the agents’ full belief about the shock path from learnt_in onward (row 0 is the shock at period learnt_in, row 1 at period learnt_in + 1, etc.), or None to pass an all-zero exogenous path to the sub-solver. Note: None is only correct when the exogenous steady state is zero; for level exogenous variables (e.g. z = 1) you must supply an explicit path including the steady-state level, otherwise the simulation will be incorrect. Only the first T_sub rows are used internally (T_sub = T when constant_simulation_length=True; otherwise T_sub = T - learnt_in + 1); extra rows are ignored.

    • endval (optional) overrides the terminal BVP boundary (right-hand steady state) for this sub-solve and all subsequent ones. Use this to replicate Dynare’s endval(learnt_in=k) block, which signals a permanent shock that changes the terminal steady state. If omitted and compiled_ss is provided, the terminal steady state is automatically computed from the last row of that segment’s exog_path (the long-run exogenous level). If neither is given, the current endval (initialised to ss) is reused.

    The list must be sorted by learnt_in and the first entry must have learnt_in == 1.

  • X0 (ndarray, shape (T, n_endo), or None, optional) –

    Initial guess for the endogenous path, used as the warm-start for the first sub-solve. Subsequent sub-solves are warm-started from the previous sub-solve’s solution. If None (the default), the path is tiled from the effective terminal steady state for the first segment, determined by the following priority order:

    1. The explicit endval in the first news_shocks 3-tuple.

    2. Auto-computed from compiled_ss at the last row of the first segment’s exog_path (when compiled_ss is provided and the first segment has a non-None exog_path).

    3. ss (the steady state passed as the second positional argument).

  • initial_state (ndarray, optional) – Pre-period-0 stock variable values (k_{-1} in Dynare notation). Defaults to ss_initial[stock_var_indices].

  • ss_initial (ndarray, optional) – Initial steady state. Defaults to ss.

  • stock_var_indices (list of int, optional) – Inferred from incidence if not provided.

  • constant_simulation_length (bool, default False) – If False (Dynare’s default), each sub-solve uses the shrinking remaining horizon T - learnt_in + 1. If True (Dynare’s constant_simulation_length option), every sub-solve runs for the full T periods.

  • solver_options (dict, optional) – Forwarded unchanged to each solve_perfect_foresight sub-solve. Recognised keys: maxiter, maxfev, ftol, xtol.

  • sub_x0 (list or tuple, optional) –

    Per-sub-solve initial guesses, one entry per element of news_shocks. Each entry is either:

    • None — use the automatic warm-start (previous sub-solve’s tail, or X0 for the first sub-solve).

    • an ndarray of shape (T_sub, n_endo) — use this array as the warm-start for that sub-solve. T_sub is T - learnt_in + 1 (or T when constant_simulation_length=True); the array will be trimmed or padded to T_sub rows if necessary, matching the behaviour applied to the automatic warm-start.

    If sub_x0 is None (the default) the automatic warm-start is used for every sub-solve.

  • compiled_ss (dict, optional) –

    Pre-compiled steady-state bundle returned by compile_steady_state_funcs(equations, vars_dyn, vars_exo). When provided, the terminal steady state for each sub-solve is automatically computed from the last row of that segment’s exog_path (i.e. exog_path[-1] before trimming to T_sub), unless the news_shocks entry already supplies an explicit endval in a 3-tuple. This ensures every sub-solve’s terminal boundary is a true steady state consistent with the agents’ long-run exogenous beliefs.

    The computed endval persists to subsequent segments (same semantics as an explicit 3-tuple endval): if segment k auto-computes an endval and segment k+1 provides neither an explicit endval nor an exog_path, segment k+1 reuses the value from segment k.

    Compile the bundle once and reuse across many simulations:

    >>> compiled_ss = compile_steady_state_funcs(equations, vars_dyn, vars_exo)
    >>> result = solve_perfect_foresight_expectation_errors(
    ...     T, params, ss_initial, model_funcs, vars_dyn,
    ...     news_shocks=[(1, exog_path_1), (6, exog_path_2)],
    ...     compiled_ss=compiled_ss,
    ... )
    

Returns:

sol.xndarray, shape (T * n_endo,)

Stitched endogenous path, reshape to (T, n_endo). n_endo is len(model_funcs.get('vars_dyn', vars_dyn)), i.e. the effective variable count after process_model (same ordering as vars_dyn used internally).

sol.successbool

True if every sub-solve converged.

sol.statusint

1 if all sub-solves converged, 0 otherwise.

sol.messagestr

Human-readable summary; lists failing segments on failure.

sol.sub_resultslist of OptimizeResult

Per-sub-solve results (one per entry in news_shocks).

sol.x_auxndarray or None

Stitched auxiliary variable path, shape (T, n_aux), or None.

sol.vars_auxlist of str

Names of auxiliary variables (empty list if none).

Return type:

OptimizeResult