9. Time-varying transition probabilities

By default, a Markov chain’s transition probabilities are constant parameters – declared as chain_tp_<i>_<j> and bound to a numeric value. RISE also supports endogenous transition probabilities, where each off-diagonal probability is a function of endogenous variables, parameters, or an observed exogenous variable (a deterministic regressor carried in the data).

The mechanism is the @transition_functions block in the model file. This chapter is the entry-point reference; the block grammar itself is documented in Model file language under Markov chains.

9.1. When to use TVTP

Constant transition probabilities are the right model when regime switches are driven by forces outside the model’s variables – a policymaker’s preference shift, a structural break, an exogenous volatility regime.

Time-varying transition probabilities are the right model when the regime switches should depend on the state of the economy. The classical examples:

  • Endogenous ZLB switching – the probability of moving into the bound regime depends on the natural rate.

  • State-contingent reform probability – the probability of a policy regime change depends on debt-to-GDP.

  • Volatility regimes triggered by recession – the probability of entering the high-volatility regime depends on the output gap.

The cost is that the regime probabilities are now part of the solution and must be evaluated at each iteration of the solver. The TVTP-aware solvers (mn, mfi) handle this transparently.

9.2. The @transition_functions block

Each off-diagonal probability you want to make endogenous gets one equation in the block. The right-hand side is whatever expression you write – a parameter, a linear function of a state, a logistic, a quantile of a continuous-state distribution, etc. RISE evaluates the expression as-is. The shape of the function – including whether it is bounded – is entirely your choice:

@parameters theta_zlb "sensitivity to log(B)"

@transition_functions

    "Probability normal -> bound"
    zlb_tp_1_2 = 1 / (1 + exp(-theta_zlb * (B - B_star)));

    "Probability bound -> normal"
    zlb_tp_2_1 = 1 / (1 + exp( theta_zlb * (B - B_star)));

The right-hand side may reference any endogenous variable, parameter, or steady-state value (var{stst}). The example above uses a logistic for [0, 1] containment, but any expression is accepted; the user decides what the function does at the edges of the state space.

The name pattern is the same as for constant transition parameters: <chain>_tp_<i>_<j>. The parser distinguishes them from constant transition parameters by the presence of a defining equation in @transition_functions. The diagonal probabilities are still inferred – you only write the off-diagonals.

9.3. Driving the transition with an observed exogenous variable

A transition function may depend on an observed exogenous variable – a deterministic regressor that you supply in the data rather than a variable the model solves for. This is common in reduced-form work: the probability of switching regimes is driven by an external indicator (a financial-conditions index, a foreign interest rate, a commodity price) that enters the model only through the transition.

In a model file, declare the driver on both the @exogenous and @observables lines – so RISE knows it is supplied as data – and reference it in @transition_functions:

@exogenous EPS Z

@observables Y Z

@transition_functions

    "Probability calm -> turbulent"
    vol_tp_1_2 = 1 / (1 + exp(-(g * Z - c)));

    "Probability turbulent -> calm"
    vol_tp_2_1 = 1 / (1 + exp( (g * Z - c)));

For the VAR families the same idea is expressed through the factory: list the driver under deterministic_vars and write the probabilities in markov_chains.endogenous_probabilities:

markov_chains = struct( ...
    'name', 'mstvt', 'number_of_states', 2, ...
    'controlled_parameters', {{'c'}}, ...
    'endogenous_probabilities', ...
        {{'mstvt_tp_1_2 = logistic(IDX_LAG, g12, c12)', ...
          'mstvt_tp_2_1 = logistic(IDX_LAG, g21, c21)'}}, ...
    'probability_parameters', {{'g12','c12','g21','c21'}});

m = rfvar_model('Y', 'lag_length', 4, 'constant_term', true, ...
    'deterministic_vars', {'IDX_LAG'}, ...
    'markov_chains', markov_chains);

9.3.1. How it is evaluated

The observed exogenous is exactly that – data. At each date RISE evaluates the transition matrix on the full vector of variables, endogenous and exogenous together, taking the exogenous at its observed value. No auxiliary variable is created, and the exogenous driver never enters the covariance of the structural shocks: it is a conditioning regressor, not an innovation.

Two paths follow automatically from how much of the model is observed:

  • Fully observed (the usual reduced-form case): no continuous-state filtering is required, so RISE uses the closed-form likelihood. The regimes are still latent, so the Hamilton filter and smoother run and return the smoothed_regime_probabilities path shaped by the observed driver.

  • Latent states present (for example a DSGE with unobserved states): the regime-switching Kalman filter runs, and the observed driver is fed into the transition matrix at each date alongside the filtered state.

The driver must be observed. A transition that depends on an unobserved structural shock cannot be evaluated this way – there is no data value to supply – and RISE stops with a clear error rather than silently substituting a zero. If you need a latent driver, model it as an endogenous state and reference that state in the transition function instead.

9.4. Mixing constant and endogenous chains

A model may freely mix:

  • Constant-TP chains – declared via chain_tp_i_j ordinary parameters, with no entries in @transition_functions.

  • TVTP chains – with one equation per off-diagonal probability in @transition_functions.

The joint composite transition matrix is built from the per-chain matrices at every state, so constant-TP chains contribute their constant factor while TVTP chains contribute their state-evaluated factor.

9.5. Estimation under TVTP

When the parameters appearing inside the transition functions are estimated, the prior is declared as usual:

priors.theta_zlb = {2.00,  0.50,  5.00,  'gamma_pdf(0.9)',  1e-6, 20};
priors.B_star    = {0.0,  -1.0,   1.0,   'normal_pdf(0.9)'};

and passed through estim_priors. The estimator runs the regime-conditional Kalman filter and uses the state-dependent transition matrix at each date. See Estimation.

9.6. @epilogue for diagnostics

The @epilogue block, documented in Model file language under Epilogue, is the natural place to expose the realized transition probabilities as named variables for plotting and diagnostics:

@epilogue

    "Realized probability normal -> bound"
    p_to_bound = 1 / (1 + exp(-theta_zlb * (B - B_star)));

The epilogue is evaluated after solve and filter; it does not affect the solution, so it is the right place for derived quantities you want to look at later but not pin down.

9.7. Where to look next

  • Model file language – the @transition_functions block grammar and the @epilogue block grammar.

  • Solving – the solvers that handle TVTPs cleanly (mn and mnk Newton solvers, plus the default mfi with the usual retcode discipline).

  • Optimal policy – when the commitment chain’s transitions are themselves endogenous (stochastic replanning).

  • Storytelling – the smoothed_regime_probabilities output of filter shows the TVTP-implied probability path the data actually realized.