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_probabilitiespath 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_jordinary 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_functionsblock grammar and the@epilogueblock grammar.Solving – the solvers that handle TVTPs cleanly (
mnandmnkNewton solvers, plus the defaultmfiwith the usual retcode discipline).Optimal policy – when the
commitmentchain’s transitions are themselves endogenous (stochastic replanning).Storytelling – the
smoothed_regime_probabilitiesoutput offiltershows the TVTP-implied probability path the data actually realized.