1.6. Optimal policy

When the model file contains an @optimization_problem block, one or more of the policy equations is replaced by the planner’s first-order conditions. RISE supports:

  • commitment (Ramsey policy), with or without regime switching;

  • discretion, linear-quadratic or nonlinear, with or without regime switching;

  • loose commitment – switching between commitment and discretion with a constant probability, in a linear-quadratic system;

  • stochastic replanning – switching between commitment and discretion with possibly time-varying probabilities, in a nonlinear system;

  • non-cooperative games with multiple policymakers, Nash or Stackelberg, with a further choice between open-loop equilibrium (OLE, the historical default) and Markov-perfect equilibrium (MPE) at solve time.

If you instead want to keep all the model equations and only pick the coefficients of a given (e.g. Taylor) rule optimally, see Optimized simple rules in the legacy chapter – the surface is unchanged.

1.6.1. The modern distinctive

In the legacy toolbox, commitment vs discretion was pinned via a @commitment marker inside the @optimization_problem block and via a commitment parameter declared alongside the calibration. The two paths could disagree silently.

In the modern toolbox, the model file declares the game; the solve call selects the equilibrium concept. There is no @commitment marker in the model file, and there is no commitment parameter to set in your calibration (except in the specific loose-commitment / stochastic-replanning cases that genuinely need a switching commitment indicator). The relevant options live on solve:

  • solve_policy_type selects commitment vs discretion;

  • solve_policy_equilibrium selects OLE vs MPE for multi-player games.

The model file does not change when you flip from commitment to discretion. See Modern architecture for the broader pattern.

1.6.2. Declaring the planner’s problem

The grammar is documented in Model file language under Optimal policy. The skeletal forms:

Single player:

@optimization_problem{
    @objective = -0.5*(pi^2 + lambda_y*y^2 + lambda_i*i^2),
    @discount  = beta
}

When the block is present, the model must have strictly fewer equations than endogenous variables. The missing equations are the planner’s first-order conditions, generated by RISE. The instrument is inferred as whichever endogenous variable does not appear on the left-hand side of any equation in @model.

Multi-player Nash:

@optimization_problem[@no_u_turn=false]{
    Monetary:
        @order      = 1
        @discount   = beta
        @objective  = -0.5*(pi^2 + lambda_y*y^2 + lambda_i*i^2)
        @instrument = i ;
    Fiscal:
        @order      = 1
        @discount   = beta
        @objective  = -0.5*(tau^2 + lambda_b*b^2)
        @instrument = tau ;
}

When every player has the same @order, the game is Nash.

Multi-player Stackelberg:

@optimization_problem[@no_u_turn=false]{
    Monetary:
        @order      = 1
        @objective  = ... @instrument = i ;
    Fiscal:
        @order      = 2
        @objective  = ... @instrument = tau ;
}

When the orders differ, the game is a Stackelberg cascade with the lower @order as the leader.

@no_u_turn = true asks RISE to skip the discretion-derivative pipeline in exchange for a cheaper parse. Set it only if you will only ever solve commitment / loose-commitment problems and will not need MPE.

The grammar continues to support the legacy bracket options (@commitment, @markov_process); they remain parseable but the modern convention pushes commitment selection out to the solve call.

1.6.3. Solve-time choices

Two orthogonal options on solve:

Option

Values

Default

solve_policy_type

'ramsey', 'discretion' (case-insensitive)

'ramsey'

solve_policy_equilibrium

'OLE', 'MPE' (case-insensitive)

'OLE'

solve_policy_type:

  • 'ramsey' – full commitment; the planner re-optimises at t = 0 and not again.

  • 'discretion' – time-consistent / Markov-perfect policy; the planner re-optimises every period.

solve_policy_equilibrium matters only for multi-player games:

  • 'OLE' – open-loop equilibrium. Each player optimises against the opponent’s path. The forward-shadow row of each FOC is the classical forward-multiplier term.

  • 'MPE' – Markov-perfect equilibrium. Each player optimises against the opponent’s policy function. The forward-shadow row picks up an additional cross-player chain-rule term that captures how the opponent’s instrument responds to the predetermined state.

All four combinations are supported:

m = solve(m, solve_policy_type = "ramsey",     solve_policy_equilibrium = "OLE");
m = solve(m, solve_policy_type = "ramsey",     solve_policy_equilibrium = "MPE");
m = solve(m, solve_policy_type = "discretion", solve_policy_equilibrium = "OLE");
m = solve(m, solve_policy_type = "discretion", solve_policy_equilibrium = "MPE");

Restrictions on solve_policy_equilibrium

  • Stochastic-replanning models reject the option. Loose-commitment and stochastic-replanning models are managed through the commitment switching parameter and a Markov chain. Calling solve_policy_equilibrium = ... on such a model errors. These model classes retain their OLE-equivalent behavior.

  • ``@no_u_turn = true`` silently degenerates MPE to OLE. The flag asks RISE to skip the discretion-derivative pipeline, which the MPE chain-rule contribution is built from; under @no_u_turn = true the cross-chain is zero by construction. If you want MPE, leave @no_u_turn at its default (false).

  • Single-player consistency. With one player, MPE = OLE exactly. Toggling the option has no observable effect.

  • Stackelberg. The follower’s set of differentiation variables already includes the leader’s instruments and multipliers, so the cross-chain is correctly built over the same-level Nash opponents only. No user action is required.

1.6.4. Solver selection

RISE picks an appropriate solver automatically based on the model shape:

  • Constant-parameter problems that eigenvalue methods can handle use the default RISE solver rise_1. Discretion can also be solved with rise_1, conditional on the solution of the forward-looking variables.

  • Regime-switching problems use the functional-iteration solver mfi.

  • When @no_u_turn = true the loose_commitment solver is used; it works well in linear-quadratic setups but is less accurate for nonlinear problems, and higher-order perturbation cannot be used.

You can override the choice with solver = '+name' – per the diagnostic protocol in Solving, this is the right move when the default solver returns retcode 21 on a model you believe is determinate.

1.6.5. Loose commitment and stochastic replanning

These are the cases where a switching commitment parameter does live in the model file – the regime is whether the planner is currently honouring commitment or has re-optimized.

Loose commitment – constant re-optimization probability, linear-quadratic:

@optimization_problem[@no_u_turn = true]{
    @objective = pi^2 + lambda_y*y^2,
    @discount  = beta
}

@parameters(looseCommit, 2) commitment
@parameters looseCommit_tp_1_2 looseCommit_tp_2_1

The chain must have exactly two states; you choose which state has commitment = 1 (commitment-active) vs commitment = 0 (discretion-active).

Stochastic replanning – possibly time-varying probability, nonlinear:

@optimization_problem[@no_u_turn = false]{
    @objective = -0.5*(pi^2 + lambda_y*y^2),
    @discount  = beta
}

@parameters(stochrepl, 2) commitment

The transition probabilities may be exogenous parameters (stochrepl_tp_1_2, stochrepl_tp_2_1) or endogenous via the @transition_functions block – see Time-varying transition probabilities.

To pin looseCommit_tp_1_2 = 1 - looseCommit_tp_2_1 for estimation, use the same linear restriction syntax as for any other parameter pair; see legacy Estimation restrictions.

1.6.6. A worked example: Tatiana’s monetary-fiscal game

The smallest fixture that exercises every (policy, solve_policy_type, solve_policy_equilibrium) cell is Tatiana’s monetary-fiscal game, distributed with the regression suite. It declares four policy branches behind a rise_flags switch – cooperative, nash, M_leader, F_leader – without pinning commitment or the equilibrium concept, so the {ramsey, discretion} x {OLE, MPE} cross-product is selectable on the model object. With four policy branches this yields a 4 x 2 x 2 = 16-cell regression cube.

The model is a three-equation linearised monetary-fiscal model with five endogenous variables (output gap, inflation, the policy rate, a fiscal instrument, government debt), three shocks, and the two players’ objectives written out separately. See the legacy chapter Optimal Policy for the full tatiana.rs listing and its driver, test_tatiana_policy_equilibria.m.

1.6.7. Nonstationary optimal policy: geometric multipliers

On a nonstationary model solved in levels (solve_bgp), the planner’s Lagrange multipliers grow geometrically along the balanced growth path, at heterogeneous rates, and are sign-indefinite – some negative, some exactly zero. The additive steady-state/growth encoding used for level variables cannot represent that, which historically left a structural residual floor on every nonstationary optimal-policy model.

The machinery that handles it is strictly opt-in at parse time:

m = rise('mymodel', 'geometric_multipliers', true);
m = solve(m, 'solve_bgp', true, ...);

Under the option, the multiplier steady-state leads/lags are encoded multiplicatively (lead ss*g, lag ss/g, growth slots holding gross factors with neutral value 1), the BGP shift moves multipliers along the geometric ray level*g^K, and the steady-state stage solves each multiplier group’s levels and growth factors jointly (minimum-norm on the two-point reference/shifted FOC system – the multiplier steady state is only a point on the BGP, so the group Jacobian is singular by construction).

Leave the option off (the default) for stationary models: the additive encoding is what the discretion and loose-commitment machinery is calibrated to, and the two conventions must not be mixed. Like no_u_turn, this is a declared user intention – it is never inferred from the model.

The power-scaling multiplier charts (multiplier_charts)

On top of geometric_multipliers, the parse option multiplier_charts (with multiplier_numeraire, the name of one log-declared nonstationary variable) wraps every multiplier in the dynamic equations as MU_i = ZNUM^{B_i} * mu_i. After the balanced-growth solve the exponents are filled from the solved growth factors, so the scaled multipliers are stationary signed levels – no sign classification, no zero guards; negative and exactly-zero multipliers work natively. The static system stays chart-free by construction, weakly-identified growths are frozen to the identity chart with a loud warning, and the charted solve is typically faster than the uncharted one at the same accuracy. Both representations are exercised by the nonstationary_multipliers unit tests.

1.6.8. Where to look next

  • Optimal Policy (legacy DSGE chapter) – the long-form reference: full @optimization_problem grammar with every bracket option, the multiple-policymakers section, the MPE derivation and its equivalence with the alternative value-function-gradient formulation, the loose-commitment and stochastic-replanning treatment, and the Tatiana worked example. Canonical for the modern toolbox; folding pending review.

  • Optimized simple rules – the alternative that keeps the policy equation and only picks its coefficients optimally.

  • Solving – the option surface for solver, solve_policy_type, and solve_policy_equilibrium, plus the diagnostic protocol when the solver returns retcode 21.

  • Model file language (Optimal policy section) – the grammar reference for @optimization_problem, single-player and multi-player.

  • Time-varying transition probabilities – when the commitment chain’s transitions are endogenous.