System Module

Constraints in PyMacroFin can be used in different ways depending on the solver selected [1]. First, with the 'newton-raphson' option (macro_model.options.inner_solver = 'newton-raphson'), when a constraint is binding while solving the core system [2] of endogenous equations using the Newton-Raphson method for a grid point, the binding value is given to the variable and the corresponding endogenous equation is removed to solve a system of n-1 equations and n-1 unknowns (starting originally with n endogenous equations and n endogenous variables). For example, consider a system with m.endog = ['a','b','c] and endogenous equations 1, 2, and 3. If we set m.constraint('b','<',10), then if in the process of solving for the endogenous variables we reach b >= 10, then we set b = 10 and remove equation 2 from the endogenous equations and continue to solve with 2 equations and 2 unknowns.

When using the least_squares solver options, a constrained least squares method is used to solve the endogenous system of equations at each grid point. You may also specify systems to use with the least_squares solver. A system consists of another set of endogenous equations, separate from the core set of endogenous equations, and a set of constraints. When the set of constraints corresponding to a system is binding, the solver will switch from the core (or current) set of endogenous equations to the set specified by the system activated by the constraints. This module documents how to use systems of equations [3].

Consider the following over-simplified expository example:

from PyMacroFin.model import macro_model
from PyMacroFin.system import system

m = macro_model(name='simple-example')

m.set_endog(['x','y'],init=[5,5])

m.endog_equation('y - (x - 10)')
m.endog_equation('y - (-2*x + 20)')

m.constraint('x','<',9,label='upper')

s = system(['upper'],m)
s.endog_equation('y - x')
s.endog_equation('y - 9')
m.systems.append(s)

In the example, the obvious solution to the core system of equations is x = 10 and y = 0. However, the constraint for x < 9 creates an infeasible system. However, when the constraint becomes binding in the course of solving the core system, the system defined as s becomes active and the solution is found at y = x = 9. Although this example is far from what an example would look like in an actual model, it illustrates the functionality and flexibility provided by system. To see an example of systems used to replicate published results, see the one-dimensional example.

It is important to note that in the current release, switching more than once is not supported. The active system will only switch at most once for each grid point. After switching to a system, the constraints will not be checked again. This lends to simplicity and avoids the possibility of infinite loops alternating between systems at a given grid point. Further support for switching may be added in a future release.

class PyMacroFin.system.system(constraint_trigger, m)

A system of equations to solve when a set of constraints is binding.

Parameters:
constraint_trigger: list(str)

List of labels corresponding to constraints which, when all binding, will trigger this system to become active when solving for endogenous variable values.

m: macro_model

Model object to which the system will be attached.

Methods

endog_equation(eq) Add an equation to the system to solve for endogenous variable values.
equation(eq) Define a new intermediate variable with an equation (specific to this system).
endog_equation(eq)

Add an equation to the system to solve for endogenous variable values. This equation will be solved to be equal to zero to find the values of the endogenous variables at each grid point where the constraints corresonding to this system are binding.

Parameters:
eq: str

This string should be of the form f(<previously defined variables>). For example, if b and c are already defined as parameters, endogenous variables, value variables, or defined in previous equations, then eq='b + c' is acceptable. At equilibrium, the expression given by eq should be equal to zero.

Notes

  1. There should be as many endog_equation calls as there are endogenous equations. For a variable (i.e. x) that is set to a known value (i.e. c) in this system, simply write system.endog_equation('c - x').
equation(eq)

Define a new intermediate variable with an equation (specific to this system).

Parameters:
eq: str

This string should be of the form newvar = f(<previously defined variables>). For example, if b and c are already defined as parameters, endogenous variables, value variables, or defined in previous equations, then eq='a = b + c' is acceptable.

Notes

  1. It is important to note that you may re-define intermediate variables from the core set of equations in the system.
  2. See the derivatives section for using derivatives in equations.
  3. As of the current release, system specific intermediate variables may not be plotted. However, if the equation re-defines a core equation variable then it will be plotted based on the plot input in the core system.
  4. To re-define HJB variables such as the drift and volatility of state variables in a constraint system, simply define intermediates that are referenced in the macro_model.hjb_equation calls, then re-define those intermediates in the constraint system.

Footnotes

[1]The solver is used to solve the system of endogeonus equations provided by the user. This occurs in the inner static loop. For descriptions of loops used in the solution procedure, please see the notes in the options documentation and the solution method paper.
[2]The core system of endogenous equations is the system defined at the base level of the macro_model class. In other words, any endogenous equation defined by macro_model.endog_equation rather than by macro_model.system.endog_equation is considered to be part of the core system.
[3]Systems are not supported for the macro_model.options.inner_solver = 'fsolve' solver option.