diff --git a/.gitmodules b/.gitmodules index b2bc1c87d..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "Documentation/submodules/DemARK"] - path = Documentation/submodules/DemARK - url = https://github.com/econ-ark/DemARK diff --git a/Documentation/example_notebooks/ConsPortfolioModelDoc.ipynb b/Documentation/example_notebooks/ConsPortfolioModelDoc.ipynb new file mode 120000 index 000000000..148cec20a --- /dev/null +++ b/Documentation/example_notebooks/ConsPortfolioModelDoc.ipynb @@ -0,0 +1 @@ +../../examples/ConsPortfolioModelDoc/ConsPortfolioModelDoc.ipynb \ No newline at end of file diff --git a/Documentation/example_notebooks/GenIncProcessModel.ipynb b/Documentation/example_notebooks/GenIncProcessModel.ipynb new file mode 120000 index 000000000..95382b26a --- /dev/null +++ b/Documentation/example_notebooks/GenIncProcessModel.ipynb @@ -0,0 +1 @@ +../../examples/GenIncProcessModel/GenIncProcessModel.ipynb \ No newline at end of file diff --git a/Documentation/example_notebooks/Gentle-Intro-To-HARK.ipynb b/Documentation/example_notebooks/Gentle-Intro-To-HARK.ipynb new file mode 120000 index 000000000..85e84e64c --- /dev/null +++ b/Documentation/example_notebooks/Gentle-Intro-To-HARK.ipynb @@ -0,0 +1 @@ +../../examples/Gentle-Intro/Gentle-Intro-To-HARK.ipynb \ No newline at end of file diff --git a/Documentation/example_notebooks/IndShockConsumerType.ipynb b/Documentation/example_notebooks/IndShockConsumerType.ipynb new file mode 120000 index 000000000..2bc279db3 --- /dev/null +++ b/Documentation/example_notebooks/IndShockConsumerType.ipynb @@ -0,0 +1 @@ +../../examples/ConsIndShockModel/IndShockConsumerType.ipynb \ No newline at end of file diff --git a/Documentation/example_notebooks/KinkedRconsumerType.ipynb b/Documentation/example_notebooks/KinkedRconsumerType.ipynb new file mode 120000 index 000000000..fd9844aa1 --- /dev/null +++ b/Documentation/example_notebooks/KinkedRconsumerType.ipynb @@ -0,0 +1 @@ +../../examples/ConsIndShockModel/KinkedRconsumerType.ipynb \ No newline at end of file diff --git a/Documentation/example_notebooks/LifecycleModelExample.ipynb b/Documentation/example_notebooks/LifecycleModelExample.ipynb new file mode 120000 index 000000000..564f6c0d2 --- /dev/null +++ b/Documentation/example_notebooks/LifecycleModelExample.ipynb @@ -0,0 +1 @@ +../../examples/LifecycleModel/LifecycleModelExample.ipynb \ No newline at end of file diff --git a/Documentation/example_notebooks/PerfForesightConsumerType.ipynb b/Documentation/example_notebooks/PerfForesightConsumerType.ipynb new file mode 120000 index 000000000..23345c01c --- /dev/null +++ b/Documentation/example_notebooks/PerfForesightConsumerType.ipynb @@ -0,0 +1 @@ +../../examples/ConsIndShockModel/PerfForesightConsumerType.ipynb \ No newline at end of file diff --git a/Documentation/example_notebooks/README.md b/Documentation/example_notebooks/README.md new file mode 100644 index 000000000..bef0ac27f --- /dev/null +++ b/Documentation/example_notebooks/README.md @@ -0,0 +1,5 @@ +This directory contains symlinks to the notebooks in the top level `examples/` directory. + +These symlinks are referenced in the sphinx documentation, e.g. in `index.rst`. + +`nbsphinx`, the sphinx notebook extension, sees the `.ipynb` extension, and resolves the link, properly converting the notebook into Sphinx themed HTML. \ No newline at end of file diff --git a/Documentation/index.rst b/Documentation/index.rst index 9ca2810b6..b7ae1edc3 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -28,8 +28,13 @@ you might want to look at the `DemARK :maxdepth: 2 :caption: Notebooks - submodules/DemARK/notebooks/Gentle-Intro-To-HARK - submodules/DemARK/notebooks/KinkedRconsumerType + example_notebooks/Gentle-Intro-To-HARK.ipynb + example_notebooks/PerfForesightConsumerType.ipynb + example_notebooks/IndShockConsumerType.ipynb + example_notebooks/KinkedRconsumerType.ipynb + example_notebooks/ConsPortfolioModelDoc.ipynb + example_notebooks/GenIncProcessModel.ipynb + example_notebooks/LifecycleModelExample.ipynb .. toctree:: :maxdepth: 2 diff --git a/Documentation/submodules/DemARK b/Documentation/submodules/DemARK deleted file mode 160000 index ad40b284e..000000000 --- a/Documentation/submodules/DemARK +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ad40b284e3b9320daac0e4b5d75a3335072b4f12 diff --git a/Documentation/submodules/README.rst b/Documentation/submodules/README.rst deleted file mode 100644 index ef4e4f86d..000000000 --- a/Documentation/submodules/README.rst +++ /dev/null @@ -1,11 +0,0 @@ -Adding a submodule ------------------- - -This directory contains submodules that are used for generating docs. - -You can add a new one like this:: - - git submodule add https://github.com/econ-ark/DemARK - -Then when building on Read the Docs, -it should automatically be cloned and included in the build. diff --git a/examples/ConsIndShockModel/IndShockConsumerType.ipynb b/examples/ConsIndShockModel/IndShockConsumerType.ipynb new file mode 100644 index 000000000..868c9f5b4 --- /dev/null +++ b/examples/ConsIndShockModel/IndShockConsumerType.ipynb @@ -0,0 +1,696 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# IndShockConsumerType Documentation\n", + "## Consumption-Saving model with Idiosyncratic Income Shocks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "# Initial imports and notebook setup, click arrow to show\n", + "from HARK.ConsumptionSaving.ConsIndShockModel import IndShockConsumerType\n", + "from HARK.utilities import plotFuncsDer, plotFuncs\n", + "from time import clock\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "mystr = lambda number : \"{:.4f}\".format(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The module $\\texttt{HARK.ConsumptionSaving.ConsIndShockModel}$ concerns consumption-saving models with idiosyncratic shocks to (non-capital) income. All of the models assume CRRA utility with geometric discounting, no bequest motive, and income shocks are fully transitory or fully permanent.\n", + "\n", + "$\\texttt{ConsIndShockModel}$ includes:\n", + "1. A very basic \"perfect foresight\" model with no uncertainty.\n", + "2. A model with risk over transitory and permanent income shocks.\n", + "3. The model described in (2), with an interest rate for debt that differs from the interest rate for savings.\n", + "\n", + "This notebook provides documentation for the second of these models.\n", + "$\\newcommand{\\CRRA}{\\rho}$\n", + "$\\newcommand{\\DiePrb}{\\mathsf{D}}$\n", + "$\\newcommand{\\PermGroFac}{\\Gamma}$\n", + "$\\newcommand{\\Rfree}{\\mathsf{R}}$\n", + "$\\newcommand{\\DiscFac}{\\beta}$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Statement of idiosyncratic income shocks model\n", + "\n", + "Suppose we want to solve a model like the one analyzed in [BufferStockTheory](http://econ.jhu.edu/people/ccarroll/papers/BufferStockTheory/), with all the same features as the perfect foresight consumer, plus idiosyncratic shocks to income each period. Agents with this kind of model are represented by the class $\\texttt{IndShockConsumerType}$.\n", + "\n", + "Specifically, this type of consumer receives two income shocks at the beginning of each period: a completely transitory shock $\\newcommand{\\tShkEmp}{\\theta}{\\tShkEmp_t}$ and a completely permanent shock $\\newcommand{\\pShk}{\\psi}{\\pShk_t}$. Moreover, lenders will not let the agent borrow money such that his ratio of end-of-period assets $A_t$ to permanent income $P_t$ is less than $\\underline{a}$. As with the perfect foresight problem, this model can be framed in terms of *normalized* variables, dividing all real variables by $P_t$:\n", + "\n", + "\\begin{eqnarray*}\n", + "v_t(m_t) &=& \\max_{c_t} {~} u(c_t) + \\DiscFac (1-\\DiePrb_{t+1}) \\mathbb{E}_{t} \\left[ (\\PermGroFac_{t+1}\\psi_{t+1})^{1-\\CRRA} v_{t+1}(m_{t+1}) \\right], \\\\\n", + "a_t &=& m_t - c_t, \\\\\n", + "a_t &\\geq& \\underline{a}, \\\\\n", + "m_{t+1} &=& \\Rfree/(\\PermGroFac_{t+1} \\psi_{t+1}) a_t + \\theta_{t+1}, \\\\\n", + "(\\psi_{t+1},\\theta_{t+1}) &\\sim& F_{t+1}, \\\\\n", + "\\mathbb{E}[\\psi]=\\mathbb{E}[\\theta] &=& 1, \\\\\n", + "u(c) &=& \\frac{c^{1-\\rho}}{1-\\rho}.\n", + "\\end{eqnarray*}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution method for IndShockConsumerType\n", + "\n", + "With the introduction of (non-trivial) risk, the idiosyncratic income shocks model has no closed form solution and must be solved numerically. The function $\\texttt{solveConsIndShock}$ solves the one period problem for the $\\texttt{IndShockConsumerType}$ class. To do so, HARK uses the original version of the endogenous grid method (EGM) first described [here](http://www.econ2.jhu.edu/people/ccarroll/EndogenousGridpoints.pdf) ; see also the [SolvingMicroDSOPs](http://www.econ2.jhu.edu/people/ccarroll/SolvingMicroDSOPs/) lecture notes. \n", + "\n", + "Briefly, the transition equation for $m_{t+1}$ can be substituted into the problem definition; the second term of the reformulated maximand represents \"end of period value of assets\" $\\mathfrak{v}_t(a_t)$ (\"Gothic v\"):\n", + "\n", + "\\begin{eqnarray*}\n", + "v_t(m_t) &=& \\max_{c_t} {~} U(c_t) + \\underbrace{\\DiscFac (1-\\DiePrb_{t+1}) \\mathbb{E}_{t} \\left[ (\\PermGroFac_{t+1}\\psi_{t+1})^{1-\\CRRA} v_{t+1}(\\Rfree/(\\PermGroFac_{t+1} \\psi_{t+1}) a_t + \\theta_{t+1}) \\right]}_{\\equiv \\mathfrak{v}_t(a_t)}.\n", + "\\end{eqnarray*}\n", + "\n", + "The first order condition with respect to $c_t$ is thus simply:\n", + "\n", + "\\begin{eqnarray*}\n", + "U'(c_t) - \\mathfrak{v}'_t(a_t) = 0 \\Longrightarrow c_t^{-\\CRRA} = \\mathfrak{v}'_t(a_t) \\Longrightarrow c_t = \\mathfrak{v}'_t(a_t)^{-1/\\CRRA}.\n", + "\\end{eqnarray*}\n", + "\n", + "Where the marginal value of end-of-period assets can be computed as:\n", + "\n", + "\\begin{eqnarray*}\n", + "\\mathfrak{v}'_t(a_t) = \\DiscFac (1-\\DiePrb_{t+1}) \\mathbb{E}_{t} \\left[ \\Rfree (\\PermGroFac_{t+1}\\psi_{t+1})^{-\\CRRA} v'_{t+1}(\\Rfree/(\\PermGroFac_{t+1} \\psi_{t+1}) a_t + \\theta_{t+1}) \\right].\n", + "\\end{eqnarray*}\n", + "\n", + "To solve the model, we choose an exogenous grid of $a_t$ values that spans the range of values that could plausibly be achieved, compute $\\mathfrak{v}'_t(a_t)$ at each of these points, calculate the value of consumption $c_t$ whose marginal utility is consistent with the marginal value of assets, then find the endogenous $m_t$ gridpoint as $m_t = a_t + c_t$. The set of $(m_t,c_t)$ gridpoints is then interpolated to construct the consumption function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example parameter values to construct an instance of IndShockConsumerType\n", + "\n", + "In order to create an instance of $\\texttt{IndShockConsumerType}$, the user must specify parameters that characterize the (age-varying) distribution of income shocks $F_{t+1}$, the artificial borrowing constraint $\\underline{a}$, and the exogenous grid of end-of-period assets-above-minimum for use by EGM, along with all of the parameters for the perfect foresight model. The table below presents the complete list of parameter values required to instantiate an $\\texttt{IndShockConsumerType}$, along with example values.\n", + "\n", + "| Parameter | Description | Code | Example value | Time-varying? |\n", + "| :---: | --- | --- | --- | --- |\n", + "| $\\DiscFac$ |Intertemporal discount factor | $\\texttt{DiscFac}$ | $0.96$ | |\n", + "| $\\CRRA $ |Coefficient of relative risk aversion | $\\texttt{CRRA}$ | $2.0$ | |\n", + "| $\\Rfree$ | Risk free interest factor | $\\texttt{Rfree}$ | $1.03$ | |\n", + "| $1 - \\DiePrb_{t+1}$ |Survival probability | $\\texttt{LivPrb}$ | $[0.98]$ | $\\surd$ |\n", + "|$\\PermGroFac_{t+1}$|Permanent income growth factor|$\\texttt{PermGroFac}$| $[1.01]$ | $\\surd$ |\n", + "| $\\sigma_\\psi $ | Standard deviation of log permanent income shocks | $\\texttt{PermShkStd}$ | $[0.1]$ |$\\surd$ |\n", + "| $N_\\psi $ | Number of discrete permanent income shocks | $\\texttt{PermShkCount}$ | $7$ | |\n", + "| $\\sigma_\\theta $ | Standard deviation of log transitory income shocks | $\\texttt{TranShkStd}$ | $[0.2]$ | $\\surd$ |\n", + "| $N_\\theta $ | Number of discrete transitory income shocks | $\\texttt{TranShkCount}$ | $7$ | |\n", + "| $\\mho$ | Probability of being unemployed and getting $\\theta=\\underline{\\theta}$ | $\\texttt{UnempPrb}$ | $0.05$ | |\n", + "| $\\underline{\\theta} $ | Transitory shock when unemployed | $\\texttt{IncUnemp}$ | $0.3$ | |\n", + "| $\\mho^{Ret}$ | Probability of being \"unemployed\" when retired | $\\texttt{UnempPrb}$ | $0.0005$ | |\n", + "| $\\underline{\\theta}^{Ret} $ | Transitory shock when \"unemployed\" and retired | $\\texttt{IncUnemp}$ | $0.0$ | |\n", + "| $(none)$ | Period of the lifecycle model when retirement begins | $\\texttt{T_retire}$ | $0$ | |\n", + "| $(none)$ | Minimum value in assets-above-minimum grid | $\\texttt{aXtraMin}$ | $0.001$ | |\n", + "| $(none)$ | Maximum value in assets-above-minimum grid | $\\texttt{aXtraMax}$ | $20.0$ | |\n", + "| $(none)$ | Number of points in base assets-above-minimum grid | $\\texttt{aXtraCount}$ | $48$ | |\n", + "| $(none)$ | Exponential nesting factor for base assets-above-minimum grid | $\\texttt{aXtraNestFac}$ | $3$ | |\n", + "| $(none)$ | Additional values to add to assets-above-minimum grid | $\\texttt{aXtraExtra}$ | $None$ | |\n", + "| $\\underline{a} $ | Artificial borrowing constraint (normalized) | $\\texttt{BoroCnstArt}$ | $0.0$ | |\n", + "| $(none) $ |Indicator for whether $\\texttt{vFunc}$ should be computed | $\\texttt{vFuncBool}$ | $True$ | |\n", + "| $(none)$ |Indicator for whether $\\texttt{cFunc}$ should use cubic splines | $\\texttt{CubicBool}$ | $False$ | |\n", + "|$T$| Number of periods in this type's \"cycle\" |$\\texttt{T_cycle}$| $1$ | |\n", + "|(none)| Number of times the \"cycle\" occurs |$\\texttt{cycles}$| $0$ | |" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "IdiosyncDict={\n", + " # Parameters shared with the perfect foresight model\n", + " \"CRRA\": 2.0, # Coefficient of relative risk aversion\n", + " \"Rfree\": 1.03, # Interest factor on assets\n", + " \"DiscFac\": 0.96, # Intertemporal discount factor\n", + " \"LivPrb\" : [0.98], # Survival probability\n", + " \"PermGroFac\" :[1.01], # Permanent income growth factor\n", + " \n", + " # Parameters that specify the income distribution over the lifecycle\n", + " \"PermShkStd\" : [0.1], # Standard deviation of log permanent shocks to income\n", + " \"PermShkCount\" : 7, # Number of points in discrete approximation to permanent income shocks\n", + " \"TranShkStd\" : [0.2], # Standard deviation of log transitory shocks to income\n", + " \"TranShkCount\" : 7, # Number of points in discrete approximation to transitory income shocks\n", + " \"UnempPrb\" : 0.05, # Probability of unemployment while working\n", + " \"IncUnemp\" : 0.3, # Unemployment benefits replacement rate\n", + " \"UnempPrbRet\" : 0.0005, # Probability of \"unemployment\" while retired\n", + " \"IncUnempRet\" : 0.0, # \"Unemployment\" benefits when retired\n", + " \"T_retire\" : 0, # Period of retirement (0 --> no retirement)\n", + " \"tax_rate\" : 0.0, # Flat income tax rate (legacy parameter, will be removed in future)\n", + " \n", + " # Parameters for constructing the \"assets above minimum\" grid\n", + " \"aXtraMin\" : 0.001, # Minimum end-of-period \"assets above minimum\" value\n", + " \"aXtraMax\" : 20, # Maximum end-of-period \"assets above minimum\" value\n", + " \"aXtraCount\" : 48, # Number of points in the base grid of \"assets above minimum\"\n", + " \"aXtraNestFac\" : 3, # Exponential nesting factor when constructing \"assets above minimum\" grid\n", + " \"aXtraExtra\" : [None], # Additional values to add to aXtraGrid\n", + " \n", + " # A few other paramaters\n", + " \"BoroCnstArt\" : 0.0, # Artificial borrowing constraint; imposed minimum level of end-of period assets\n", + " \"vFuncBool\" : True, # Whether to calculate the value function during solution \n", + " \"CubicBool\" : False, # Preference shocks currently only compatible with linear cFunc\n", + " \"T_cycle\" : 1, # Number of periods in the cycle for this agent type \n", + " \n", + " # Parameters only used in simulation\n", + " \"AgentCount\" : 10000, # Number of agents of this type\n", + " \"T_sim\" : 120, # Number of periods to simulate\n", + " \"aNrmInitMean\" : -6.0, # Mean of log initial assets\n", + " \"aNrmInitStd\" : 1.0, # Standard deviation of log initial assets\n", + " \"pLvlInitMean\" : 0.0, # Mean of log initial permanent income\n", + " \"pLvlInitStd\" : 0.0, # Standard deviation of log initial permanent income\n", + " \"PermGroFacAgg\" : 1.0, # Aggregate permanent income growth factor\n", + " \"T_age\" : None, # Age after which simulated agents are automatically killed\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The distribution of permanent income shocks is specified as mean one lognormal, with an age-varying (underlying) standard deviation. The distribution of transitory income shocks is also mean one lognormal, but with an additional point mass representing unemployment; the transitory shocks are adjusted so that the distribution is still mean one. The continuous distributions are discretized with an equiprobable distribution.\n", + "\n", + "Optionally, the user can specify the period when the individual retires and escapes essentially all income risk as $\\texttt{T_retire}$; this can be turned off by setting the parameter to $0$. In retirement, all permanent income shocks are turned off, and the only transitory shock is an \"unemployment\" shock, likely with small probability; this prevents the retired problem from degenerating into a perfect foresight model.\n", + "\n", + "The grid of assets above minimum $\\texttt{aXtraGrid}$ is specified by its minimum and maximum level, the number of gridpoints, and the extent of exponential nesting. The greater the (integer) value of $\\texttt{aXtraNestFac}$, the more dense the gridpoints will be at the bottom of the grid (and more sparse near the top); setting $\\texttt{aXtraNestFac}$ to $0$ will generate an evenly spaced grid of $a_t$.\n", + "\n", + "The artificial borrowing constraint $\\texttt{BoroCnstArt}$ can be set to $\\texttt{None}$ to turn it off.\n", + "\n", + "It is not necessary to compute the value function in this model, and it is not computationally free to do so. You can choose whether the value function should be calculated and returned as part of the solution of the model with $\\texttt{vFuncBool}$. The consumption function will be constructed as a piecewise linear interpolation when $\\texttt{CubicBool}$ is \\texttt{False}, and will be a piecewise cubic spline interpolator if $\\texttt{True}$." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "heading_collapsed": true + }, + "source": [ + "## Solving and examining the solution of the idiosyncratic income shocks model\n", + "\n", + "The cell below creates an infinite horizon instance of $\\texttt{IndShockConsumerType}$ and solves its model by calling its $\\texttt{solve}$ method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hidden": true, + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "IndShockExample = IndShockConsumerType(**IdiosyncDict)\n", + "IndShockExample.cycles = 0 # Make this type have an infinite horizon\n", + "IndShockExample.solve()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hidden": true + }, + "source": [ + "After solving the model, we can examine an element of this type's $\\texttt{solution}$:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hidden": true + }, + "outputs": [], + "source": [ + "print(vars(IndShockExample.solution[0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hidden": true + }, + "source": [ + "The single-period solution to an idiosyncratic shocks consumer's problem has all of the same attributes as in the perfect foresight model, with a couple additions. The solution can include the marginal marginal value of market resources function $\\texttt{vPPfunc}$, but this is only constructed if $\\texttt{CubicBool}$ is $\\texttt{True}$, so that the MPC can be accurately computed; when it is $\\texttt{False}$, then $\\texttt{vPPfunc}$ merely returns $\\texttt{NaN}$ everywhere.\n", + "\n", + "The $\\texttt{solveConsIndShock}$ function calculates steady state market resources and stores it in the attribute $\\texttt{mNrmSS}$. This represents the steady state level of $m_t$ if *this period* were to occur indefinitely, but with income shocks turned off. This is relevant in a \"one period infinite horizon\" model like we've specified here, but is less useful in a lifecycle model.\n", + "\n", + "Let's take a look at the consumption function by plotting it, along with its derivative (the MPC):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hidden": true + }, + "outputs": [], + "source": [ + "print('Consumption function for an idiosyncratic shocks consumer type:')\n", + "plotFuncs(IndShockExample.solution[0].cFunc,IndShockExample.solution[0].mNrmMin,5)\n", + "print('Marginal propensity to consume for an idiosyncratic shocks consumer type:')\n", + "plotFuncsDer(IndShockExample.solution[0].cFunc,IndShockExample.solution[0].mNrmMin,5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hidden": true + }, + "source": [ + "The lower part of the consumption function is linear with a slope of 1, representing the *constrained* part of the consumption function where the consumer *would like* to consume more by borrowing-- his marginal utility of consumption exceeds the marginal value of assets-- but he is prevented from doing so by the artificial borrowing constraint.\n", + "\n", + "The MPC is a step function, as the $\\texttt{cFunc}$ itself is a piecewise linear function; note the large jump in the MPC where the borrowing constraint begins to bind.\n", + "\n", + "If you want to look at the interpolation nodes for the consumption function, these can be found by \"digging into\" attributes of $\\texttt{cFunc}$:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hidden": true + }, + "outputs": [], + "source": [ + "print('mNrmGrid for unconstrained cFunc is ',IndShockExample.solution[0].cFunc.functions[0].x_list)\n", + "print('cNrmGrid for unconstrained cFunc is ',IndShockExample.solution[0].cFunc.functions[0].y_list)\n", + "print('mNrmGrid for borrowing constrained cFunc is ',IndShockExample.solution[0].cFunc.functions[1].x_list)\n", + "print('cNrmGrid for borrowing constrained cFunc is ',IndShockExample.solution[0].cFunc.functions[1].y_list)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "hidden": true + }, + "source": [ + "The consumption function in this model is an instance of $\\texttt{LowerEnvelope1D}$, a class that takes an arbitrary number of 1D interpolants as arguments to its initialization method. When called, a $\\texttt{LowerEnvelope1D}$ evaluates each of its component functions and returns the lowest value. Here, the two component functions are the *unconstrained* consumption function-- how the agent would consume if the artificial borrowing constraint did not exist for *just this period*-- and the *borrowing constrained* consumption function-- how much he would consume if the artificial borrowing constraint is binding. \n", + "\n", + "The *actual* consumption function is the lower of these two functions, pointwise. We can see this by plotting the component functions on the same figure:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "hidden": true + }, + "outputs": [], + "source": [ + "plotFuncs(IndShockExample.solution[0].cFunc.functions,-0.25,5.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simulating the idiosyncratic income shocks model\n", + "\n", + "In order to generate simulated data, an instance of $\\texttt{IndShockConsumerType}$ needs to know how many agents there are that share these particular parameters (and are thus *ex ante* homogeneous), the distribution of states for newly \"born\" agents, and how many periods to simulated. These simulation parameters are described in the table below, along with example values.\n", + "\n", + "| Description | Code | Example value |\n", + "| :---: | --- | --- |\n", + "| Number of consumers of this type | $\\texttt{AgentCount}$ | $10000$ |\n", + "| Number of periods to simulate | $\\texttt{T_sim}$ | $120$ |\n", + "| Mean of initial log (normalized) assets | $\\texttt{aNrmInitMean}$ | $-6.0$ |\n", + "| Stdev of initial log (normalized) assets | $\\texttt{aNrmInitStd}$ | $1.0$ |\n", + "| Mean of initial log permanent income | $\\texttt{pLvlInitMean}$ | $0.0$ |\n", + "| Stdev of initial log permanent income | $\\texttt{pLvlInitStd}$ | $0.0$ |\n", + "| Aggregrate productivity growth factor | $\\texttt{PermGroFacAgg}$ | $1.0$ |\n", + "| Age after which consumers are automatically killed | $\\texttt{T_age}$ | $None$ |\n", + "\n", + "Here, we will simulate 10,000 consumers for 120 periods. All newly born agents will start with permanent income of exactly $P_t = 1.0 = \\exp(\\texttt{pLvlInitMean})$, as $\\texttt{pLvlInitStd}$ has been set to zero; they will have essentially zero assets at birth, as $\\texttt{aNrmInitMean}$ is $-6.0$; assets will be less than $1\\%$ of permanent income at birth.\n", + "\n", + "These example parameter values were already passed as part of the parameter dictionary that we used to create $\\texttt{IndShockExample}$, so it is ready to simulate. We need to set the $\\texttt{track_vars}$ attribute to indicate the variables for which we want to record a *history*." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "IndShockExample.track_vars = ['aNrmNow','mNrmNow','cNrmNow','pLvlNow']\n", + "IndShockExample.initializeSim()\n", + "IndShockExample.simulate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now look at the simulated data in aggregate or at the individual consumer level. Like in the perfect foresight model, we can plot average (normalized) market resources over time, as well as average consumption:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(np.mean(IndShockExample.mNrmNow_hist,axis=1))\n", + "plt.xlabel('Time')\n", + "plt.ylabel('Mean market resources')\n", + "plt.show()\n", + "\n", + "plt.plot(np.mean(IndShockExample.cNrmNow_hist,axis=1))\n", + "plt.xlabel('Time')\n", + "plt.ylabel('Mean consumption')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We could also plot individual consumption paths for some of the consumers-- say, the first five:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(IndShockExample.cNrmNow_hist[:,0:5])\n", + "plt.xlabel('Time')\n", + "plt.ylabel('Individual consumption paths')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Other example specifications of idiosyncratic income shocks consumers\n", + "\n", + "$\\texttt{IndShockConsumerType}$-- and $\\texttt{HARK}$ in general-- can also represent models that are not infinite horizon. \n", + "\n", + "### Lifecycle example\n", + "\n", + "Suppose we wanted to represent consumers with a *lifecycle*-- parameter values that differ by age, with a finite end point beyond which the individual cannot surive. This can be done very easily by simply specifying the time-varying attributes $\\texttt{PermGroFac}$, $\\texttt{LivPrb}$, $\\texttt{PermShkStd}$, and $\\texttt{TranShkStd}$ as Python *lists* specifying the sequence of periods these agents will experience, from beginning to end.\n", + "\n", + "In the cell below, we define a parameter dictionary for a rather short ten period lifecycle, with arbitrarily chosen parameters. For a more realistically calibrated (and much longer) lifecycle model, see the [SolvingMicroDSOPs REMARK](https://github.com/econ-ark/REMARK/blob/master/REMARKs/SolvingMicroDSOPs.md)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "LifecycleDict={ # Click arrow to expand this fairly large parameter dictionary\n", + " # Parameters shared with the perfect foresight model\n", + " \"CRRA\": 2.0, # Coefficient of relative risk aversion\n", + " \"Rfree\": 1.03, # Interest factor on assets\n", + " \"DiscFac\": 0.96, # Intertemporal discount factor\n", + " \"LivPrb\" : [0.99,0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1],\n", + " \"PermGroFac\" : [1.01,1.01,1.01,1.02,1.02,1.02,0.7,1.0,1.0,1.0],\n", + " \n", + " # Parameters that specify the income distribution over the lifecycle\n", + " \"PermShkStd\" : [0.1,0.2,0.1,0.2,0.1,0.2,0.1,0,0,0],\n", + " \"PermShkCount\" : 7, # Number of points in discrete approximation to permanent income shocks\n", + " \"TranShkStd\" : [0.3,0.2,0.1,0.3,0.2,0.1,0.3,0,0,0],\n", + " \"TranShkCount\" : 7, # Number of points in discrete approximation to transitory income shocks\n", + " \"UnempPrb\" : 0.05, # Probability of unemployment while working\n", + " \"IncUnemp\" : 0.3, # Unemployment benefits replacement rate\n", + " \"UnempPrbRet\" : 0.0005, # Probability of \"unemployment\" while retired\n", + " \"IncUnempRet\" : 0.0, # \"Unemployment\" benefits when retired\n", + " \"T_retire\" : 7, # Period of retirement (0 --> no retirement)\n", + " \"tax_rate\" : 0.0, # Flat income tax rate (legacy parameter, will be removed in future)\n", + " \n", + " # Parameters for constructing the \"assets above minimum\" grid\n", + " \"aXtraMin\" : 0.001, # Minimum end-of-period \"assets above minimum\" value\n", + " \"aXtraMax\" : 20, # Maximum end-of-period \"assets above minimum\" value\n", + " \"aXtraCount\" : 48, # Number of points in the base grid of \"assets above minimum\"\n", + " \"aXtraNestFac\" : 3, # Exponential nesting factor when constructing \"assets above minimum\" grid\n", + " \"aXtraExtra\" : [None], # Additional values to add to aXtraGrid\n", + " \n", + " # A few other paramaters\n", + " \"BoroCnstArt\" : 0.0, # Artificial borrowing constraint; imposed minimum level of end-of period assets\n", + " \"vFuncBool\" : True, # Whether to calculate the value function during solution \n", + " \"CubicBool\" : False, # Preference shocks currently only compatible with linear cFunc\n", + " \"T_cycle\" : 10, # Number of periods in the cycle for this agent type \n", + " \n", + " # Parameters only used in simulation\n", + " \"AgentCount\" : 10000, # Number of agents of this type\n", + " \"T_sim\" : 120, # Number of periods to simulate\n", + " \"aNrmInitMean\" : -6.0, # Mean of log initial assets\n", + " \"aNrmInitStd\" : 1.0, # Standard deviation of log initial assets\n", + " \"pLvlInitMean\" : 0.0, # Mean of log initial permanent income\n", + " \"pLvlInitStd\" : 0.0, # Standard deviation of log initial permanent income\n", + " \"PermGroFacAgg\" : 1.0, # Aggregate permanent income growth factor\n", + " \"T_age\" : 11, # Age after which simulated agents are automatically killed \n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this case, we have specified a ten period model in which retirement happens in period $t=7$. Agents in this model are more likely to die as they age, and their permanent income drops by 30\\% at retirement. Let's make and solve this lifecycle example, then look at the $\\texttt{solution}$ attribute." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "LifecycleExample = IndShockConsumerType(**LifecycleDict)\n", + "LifecycleExample.cycles = 1 # Make this consumer live a sequence of periods -- a lifetime -- exactly once\n", + "LifecycleExample.solve()\n", + "print('First element of solution is',LifecycleExample.solution[0])\n", + "print('Solution has', len(LifecycleExample.solution),'elements.')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This was supposed to be a *ten* period lifecycle model-- why does our consumer type have *eleven* elements in its $\\texttt{solution}$? It would be more precise to say that this specification has ten *non-terminal* periods. The solution to the 11th and final period in the model would be the same for every set of parameters: consume $c_t = m_t$, because there is no future. In a lifecycle model, the terminal period is assumed to exist; the $\\texttt{LivPrb}$ parameter does not need to end with a $0.0$ in order to guarantee that survivors die.\n", + "\n", + "We can quickly plot the consumption functions in each period of the model:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('Consumption functions across the lifecycle:')\n", + "mMin = np.min([LifecycleExample.solution[t].mNrmMin for t in range(LifecycleExample.T_cycle)])\n", + "LifecycleExample.unpackcFunc() # This makes all of the cFuncs accessible in the attribute cFunc\n", + "plotFuncs(LifecycleExample.cFunc,mMin,5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### \"Cyclical\" example\n", + "\n", + "We can also model consumers who face an infinite horizon, but who do *not* face the same problem in every period. Consider someone who works as a ski instructor: they make most of their income for the year in the winter, and make very little money in the other three seasons.\n", + "\n", + "We can represent this type of individual as a four period, infinite horizon model in which expected \"permanent\" income growth varies greatly across seasons." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "CyclicalDict = { # Click the arrow to expand this parameter dictionary\n", + " # Parameters shared with the perfect foresight model\n", + " \"CRRA\": 2.0, # Coefficient of relative risk aversion\n", + " \"Rfree\": 1.03, # Interest factor on assets\n", + " \"DiscFac\": 0.96, # Intertemporal discount factor\n", + " \"LivPrb\" : 4*[0.98], # Survival probability\n", + " \"PermGroFac\" : [1.082251, 2.8, 0.3, 1.1],\n", + " \n", + " # Parameters that specify the income distribution over the lifecycle\n", + " \"PermShkStd\" : [0.1,0.1,0.1,0.1],\n", + " \"PermShkCount\" : 7, # Number of points in discrete approximation to permanent income shocks\n", + " \"TranShkStd\" : [0.2,0.2,0.2,0.2],\n", + " \"TranShkCount\" : 7, # Number of points in discrete approximation to transitory income shocks\n", + " \"UnempPrb\" : 0.05, # Probability of unemployment while working\n", + " \"IncUnemp\" : 0.3, # Unemployment benefits replacement rate\n", + " \"UnempPrbRet\" : 0.0005, # Probability of \"unemployment\" while retired\n", + " \"IncUnempRet\" : 0.0, # \"Unemployment\" benefits when retired\n", + " \"T_retire\" : 0, # Period of retirement (0 --> no retirement)\n", + " \"tax_rate\" : 0.0, # Flat income tax rate (legacy parameter, will be removed in future)\n", + " \n", + " # Parameters for constructing the \"assets above minimum\" grid\n", + " \"aXtraMin\" : 0.001, # Minimum end-of-period \"assets above minimum\" value\n", + " \"aXtraMax\" : 20, # Maximum end-of-period \"assets above minimum\" value\n", + " \"aXtraCount\" : 48, # Number of points in the base grid of \"assets above minimum\"\n", + " \"aXtraNestFac\" : 3, # Exponential nesting factor when constructing \"assets above minimum\" grid\n", + " \"aXtraExtra\" : [None], # Additional values to add to aXtraGrid\n", + " \n", + " # A few other paramaters\n", + " \"BoroCnstArt\" : 0.0, # Artificial borrowing constraint; imposed minimum level of end-of period assets\n", + " \"vFuncBool\" : True, # Whether to calculate the value function during solution \n", + " \"CubicBool\" : False, # Preference shocks currently only compatible with linear cFunc\n", + " \"T_cycle\" : 4, # Number of periods in the cycle for this agent type \n", + " \n", + " # Parameters only used in simulation\n", + " \"AgentCount\" : 10000, # Number of agents of this type\n", + " \"T_sim\" : 120, # Number of periods to simulate\n", + " \"aNrmInitMean\" : -6.0, # Mean of log initial assets\n", + " \"aNrmInitStd\" : 1.0, # Standard deviation of log initial assets\n", + " \"pLvlInitMean\" : 0.0, # Mean of log initial permanent income\n", + " \"pLvlInitStd\" : 0.0, # Standard deviation of log initial permanent income\n", + " \"PermGroFacAgg\" : 1.0, # Aggregate permanent income growth factor\n", + " \"T_age\" : None, # Age after which simulated agents are automatically killed \n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This consumer type's parameter dictionary is nearly identical to the original infinite horizon type we made, except that each of the time-varying parameters now have *four* values, rather than just one. Most of these have the same value in each period *except* for $\\texttt{PermGroFac}$, which varies greatly over the four seasons. Note that the product of the four \"permanent\" income growth factors is almost exactly 1.0-- this type's income does not grow on average in the long run!\n", + "\n", + "Let's make and solve this consumer type, then plot his quarterly consumption functions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "CyclicalExample = IndShockConsumerType(**CyclicalDict)\n", + "CyclicalExample.cycles = 0 # Make this consumer type have an infinite horizon\n", + "CyclicalExample.solve()\n", + "\n", + "CyclicalExample.unpackcFunc()\n", + "print('Quarterly consumption functions:')\n", + "mMin = min([X.mNrmMin for X in CyclicalExample.solution])\n", + "plotFuncs(CyclicalExample.cFunc,mMin,5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The very low green consumption function corresponds to the quarter in which the ski instructors make most of their income. They know that they are about to experience a 70% drop in \"permanent\" income, so they do not consume much *relative to their income this quarter*. In the other three quarters, *normalized* consumption is much higher, as current \"permanent\" income is low relative to future expectations. In *level*, the consumption chosen in each quarter is much more similar" + ] + } + ], + "metadata": { + "@webio": { + "lastCommId": "779f6c5616b04b58baaaa0f6c348270c", + "lastKernelId": "a944b08f-0ae0-4c26-883f-9fab53a82ac3" + }, + "cite2c": { + "citations": { + "6202365/HQ6H9JEI": { + "DOI": "10.1016/j.econlet.2005.09.013", + "URL": "http://econ.jhu.edu/people/ccarroll/EndogenousArchive.zip", + "author": [ + { + "family": "Carroll", + "given": "Christopher D." + } + ], + "container-title": "Economics Letters", + "id": "6202365/HQ6H9JEI", + "issued": { + "month": 9, + "year": 2006 + }, + "page": "312–320", + "page-first": "312", + "title": "The Method of Endogenous Gridpoints for Solving Dynamic Stochastic Optimization Problems", + "type": "article-journal" + } + } + }, + "jupytext": { + "cell_metadata_filter": "collapsed,code_folding", + "formats": "ipynb,py:percent" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.7" + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/ConsIndShockModel/IndShockConsumerType.py b/examples/ConsIndShockModel/IndShockConsumerType.py new file mode 100644 index 000000000..39965b594 --- /dev/null +++ b/examples/ConsIndShockModel/IndShockConsumerType.py @@ -0,0 +1,419 @@ +# --- +# jupyter: +# jupytext: +# cell_metadata_filter: collapsed,code_folding +# formats: ipynb,py:percent +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.2' +# jupytext_version: 1.1.3 +# kernelspec: +# display_name: Python 3 +# language: python +# name: python3 +# --- + +# %% [markdown] +# # IndShockConsumerType Documentation +# ## Consumption-Saving model with Idiosyncratic Income Shocks + +# %% {"code_folding": [0]} +# Initial imports and notebook setup, click arrow to show +from HARK.ConsumptionSaving.ConsIndShockModel import IndShockConsumerType +from HARK.utilities import plotFuncsDer, plotFuncs +from time import clock +import matplotlib.pyplot as plt +import numpy as np +mystr = lambda number : "{:.4f}".format(number) + +# %% [markdown] +# The module $\texttt{HARK.ConsumptionSaving.ConsIndShockModel}$ concerns consumption-saving models with idiosyncratic shocks to (non-capital) income. All of the models assume CRRA utility with geometric discounting, no bequest motive, and income shocks are fully transitory or fully permanent. +# +# $\texttt{ConsIndShockModel}$ includes: +# 1. A very basic "perfect foresight" model with no uncertainty. +# 2. A model with risk over transitory and permanent income shocks. +# 3. The model described in (2), with an interest rate for debt that differs from the interest rate for savings. +# +# This notebook provides documentation for the second of these models. +# $\newcommand{\CRRA}{\rho}$ +# $\newcommand{\DiePrb}{\mathsf{D}}$ +# $\newcommand{\PermGroFac}{\Gamma}$ +# $\newcommand{\Rfree}{\mathsf{R}}$ +# $\newcommand{\DiscFac}{\beta}$ + +# %% [markdown] +# ## Statement of idiosyncratic income shocks model +# +# Suppose we want to solve a model like the one analyzed in [BufferStockTheory](http://econ.jhu.edu/people/ccarroll/papers/BufferStockTheory/), with all the same features as the perfect foresight consumer, plus idiosyncratic shocks to income each period. Agents with this kind of model are represented by the class $\texttt{IndShockConsumerType}$. +# +# Specifically, this type of consumer receives two income shocks at the beginning of each period: a completely transitory shock $\newcommand{\tShkEmp}{\theta}{\tShkEmp_t}$ and a completely permanent shock $\newcommand{\pShk}{\psi}{\pShk_t}$. Moreover, lenders will not let the agent borrow money such that his ratio of end-of-period assets $A_t$ to permanent income $P_t$ is less than $\underline{a}$. As with the perfect foresight problem, this model can be framed in terms of *normalized* variables, dividing all real variables by $P_t$: +# +# \begin{eqnarray*} +# v_t(m_t) &=& \max_{c_t} {~} u(c_t) + \DiscFac (1-\DiePrb_{t+1}) \mathbb{E}_{t} \left[ (\PermGroFac_{t+1}\psi_{t+1})^{1-\CRRA} v_{t+1}(m_{t+1}) \right], \\ +# a_t &=& m_t - c_t, \\ +# a_t &\geq& \underline{a}, \\ +# m_{t+1} &=& \Rfree/(\PermGroFac_{t+1} \psi_{t+1}) a_t + \theta_{t+1}, \\ +# (\psi_{t+1},\theta_{t+1}) &\sim& F_{t+1}, \\ +# \mathbb{E}[\psi]=\mathbb{E}[\theta] &=& 1, \\ +# u(c) &=& \frac{c^{1-\rho}}{1-\rho}. +# \end{eqnarray*} + +# %% [markdown] +# ## Solution method for IndShockConsumerType +# +# With the introduction of (non-trivial) risk, the idiosyncratic income shocks model has no closed form solution and must be solved numerically. The function $\texttt{solveConsIndShock}$ solves the one period problem for the $\texttt{IndShockConsumerType}$ class. To do so, HARK uses the original version of the endogenous grid method (EGM) first described [here](http://www.econ2.jhu.edu/people/ccarroll/EndogenousGridpoints.pdf) ; see also the [SolvingMicroDSOPs](http://www.econ2.jhu.edu/people/ccarroll/SolvingMicroDSOPs/) lecture notes. +# +# Briefly, the transition equation for $m_{t+1}$ can be substituted into the problem definition; the second term of the reformulated maximand represents "end of period value of assets" $\mathfrak{v}_t(a_t)$ ("Gothic v"): +# +# \begin{eqnarray*} +# v_t(m_t) &=& \max_{c_t} {~} U(c_t) + \underbrace{\DiscFac (1-\DiePrb_{t+1}) \mathbb{E}_{t} \left[ (\PermGroFac_{t+1}\psi_{t+1})^{1-\CRRA} v_{t+1}(\Rfree/(\PermGroFac_{t+1} \psi_{t+1}) a_t + \theta_{t+1}) \right]}_{\equiv \mathfrak{v}_t(a_t)}. +# \end{eqnarray*} +# +# The first order condition with respect to $c_t$ is thus simply: +# +# \begin{eqnarray*} +# U'(c_t) - \mathfrak{v}'_t(a_t) = 0 \Longrightarrow c_t^{-\CRRA} = \mathfrak{v}'_t(a_t) \Longrightarrow c_t = \mathfrak{v}'_t(a_t)^{-1/\CRRA}. +# \end{eqnarray*} +# +# Where the marginal value of end-of-period assets can be computed as: +# +# \begin{eqnarray*} +# \mathfrak{v}'_t(a_t) = \DiscFac (1-\DiePrb_{t+1}) \mathbb{E}_{t} \left[ \Rfree (\PermGroFac_{t+1}\psi_{t+1})^{-\CRRA} v'_{t+1}(\Rfree/(\PermGroFac_{t+1} \psi_{t+1}) a_t + \theta_{t+1}) \right]. +# \end{eqnarray*} +# +# To solve the model, we choose an exogenous grid of $a_t$ values that spans the range of values that could plausibly be achieved, compute $\mathfrak{v}'_t(a_t)$ at each of these points, calculate the value of consumption $c_t$ whose marginal utility is consistent with the marginal value of assets, then find the endogenous $m_t$ gridpoint as $m_t = a_t + c_t$. The set of $(m_t,c_t)$ gridpoints is then interpolated to construct the consumption function. + +# %% [markdown] +# ## Example parameter values to construct an instance of IndShockConsumerType +# +# In order to create an instance of $\texttt{IndShockConsumerType}$, the user must specify parameters that characterize the (age-varying) distribution of income shocks $F_{t+1}$, the artificial borrowing constraint $\underline{a}$, and the exogenous grid of end-of-period assets-above-minimum for use by EGM, along with all of the parameters for the perfect foresight model. The table below presents the complete list of parameter values required to instantiate an $\texttt{IndShockConsumerType}$, along with example values. +# +# | Parameter | Description | Code | Example value | Time-varying? | +# | :---: | --- | --- | --- | --- | +# | $\DiscFac$ |Intertemporal discount factor | $\texttt{DiscFac}$ | $0.96$ | | +# | $\CRRA $ |Coefficient of relative risk aversion | $\texttt{CRRA}$ | $2.0$ | | +# | $\Rfree$ | Risk free interest factor | $\texttt{Rfree}$ | $1.03$ | | +# | $1 - \DiePrb_{t+1}$ |Survival probability | $\texttt{LivPrb}$ | $[0.98]$ | $\surd$ | +# |$\PermGroFac_{t+1}$|Permanent income growth factor|$\texttt{PermGroFac}$| $[1.01]$ | $\surd$ | +# | $\sigma_\psi $ | Standard deviation of log permanent income shocks | $\texttt{PermShkStd}$ | $[0.1]$ |$\surd$ | +# | $N_\psi $ | Number of discrete permanent income shocks | $\texttt{PermShkCount}$ | $7$ | | +# | $\sigma_\theta $ | Standard deviation of log transitory income shocks | $\texttt{TranShkStd}$ | $[0.2]$ | $\surd$ | +# | $N_\theta $ | Number of discrete transitory income shocks | $\texttt{TranShkCount}$ | $7$ | | +# | $\mho$ | Probability of being unemployed and getting $\theta=\underline{\theta}$ | $\texttt{UnempPrb}$ | $0.05$ | | +# | $\underline{\theta} $ | Transitory shock when unemployed | $\texttt{IncUnemp}$ | $0.3$ | | +# | $\mho^{Ret}$ | Probability of being "unemployed" when retired | $\texttt{UnempPrb}$ | $0.0005$ | | +# | $\underline{\theta}^{Ret} $ | Transitory shock when "unemployed" and retired | $\texttt{IncUnemp}$ | $0.0$ | | +# | $(none)$ | Period of the lifecycle model when retirement begins | $\texttt{T_retire}$ | $0$ | | +# | $(none)$ | Minimum value in assets-above-minimum grid | $\texttt{aXtraMin}$ | $0.001$ | | +# | $(none)$ | Maximum value in assets-above-minimum grid | $\texttt{aXtraMax}$ | $20.0$ | | +# | $(none)$ | Number of points in base assets-above-minimum grid | $\texttt{aXtraCount}$ | $48$ | | +# | $(none)$ | Exponential nesting factor for base assets-above-minimum grid | $\texttt{aXtraNestFac}$ | $3$ | | +# | $(none)$ | Additional values to add to assets-above-minimum grid | $\texttt{aXtraExtra}$ | $None$ | | +# | $\underline{a} $ | Artificial borrowing constraint (normalized) | $\texttt{BoroCnstArt}$ | $0.0$ | | +# | $(none) $ |Indicator for whether $\texttt{vFunc}$ should be computed | $\texttt{vFuncBool}$ | $True$ | | +# | $(none)$ |Indicator for whether $\texttt{cFunc}$ should use cubic splines | $\texttt{CubicBool}$ | $False$ | | +# |$T$| Number of periods in this type's "cycle" |$\texttt{T_cycle}$| $1$ | | +# |(none)| Number of times the "cycle" occurs |$\texttt{cycles}$| $0$ | | + +# %% {"code_folding": [0]} +IdiosyncDict={ + # Parameters shared with the perfect foresight model + "CRRA": 2.0, # Coefficient of relative risk aversion + "Rfree": 1.03, # Interest factor on assets + "DiscFac": 0.96, # Intertemporal discount factor + "LivPrb" : [0.98], # Survival probability + "PermGroFac" :[1.01], # Permanent income growth factor + + # Parameters that specify the income distribution over the lifecycle + "PermShkStd" : [0.1], # Standard deviation of log permanent shocks to income + "PermShkCount" : 7, # Number of points in discrete approximation to permanent income shocks + "TranShkStd" : [0.2], # Standard deviation of log transitory shocks to income + "TranShkCount" : 7, # Number of points in discrete approximation to transitory income shocks + "UnempPrb" : 0.05, # Probability of unemployment while working + "IncUnemp" : 0.3, # Unemployment benefits replacement rate + "UnempPrbRet" : 0.0005, # Probability of "unemployment" while retired + "IncUnempRet" : 0.0, # "Unemployment" benefits when retired + "T_retire" : 0, # Period of retirement (0 --> no retirement) + "tax_rate" : 0.0, # Flat income tax rate (legacy parameter, will be removed in future) + + # Parameters for constructing the "assets above minimum" grid + "aXtraMin" : 0.001, # Minimum end-of-period "assets above minimum" value + "aXtraMax" : 20, # Maximum end-of-period "assets above minimum" value + "aXtraCount" : 48, # Number of points in the base grid of "assets above minimum" + "aXtraNestFac" : 3, # Exponential nesting factor when constructing "assets above minimum" grid + "aXtraExtra" : [None], # Additional values to add to aXtraGrid + + # A few other paramaters + "BoroCnstArt" : 0.0, # Artificial borrowing constraint; imposed minimum level of end-of period assets + "vFuncBool" : True, # Whether to calculate the value function during solution + "CubicBool" : False, # Preference shocks currently only compatible with linear cFunc + "T_cycle" : 1, # Number of periods in the cycle for this agent type + + # Parameters only used in simulation + "AgentCount" : 10000, # Number of agents of this type + "T_sim" : 120, # Number of periods to simulate + "aNrmInitMean" : -6.0, # Mean of log initial assets + "aNrmInitStd" : 1.0, # Standard deviation of log initial assets + "pLvlInitMean" : 0.0, # Mean of log initial permanent income + "pLvlInitStd" : 0.0, # Standard deviation of log initial permanent income + "PermGroFacAgg" : 1.0, # Aggregate permanent income growth factor + "T_age" : None, # Age after which simulated agents are automatically killed +} + +# %% [markdown] +# The distribution of permanent income shocks is specified as mean one lognormal, with an age-varying (underlying) standard deviation. The distribution of transitory income shocks is also mean one lognormal, but with an additional point mass representing unemployment; the transitory shocks are adjusted so that the distribution is still mean one. The continuous distributions are discretized with an equiprobable distribution. +# +# Optionally, the user can specify the period when the individual retires and escapes essentially all income risk as $\texttt{T_retire}$; this can be turned off by setting the parameter to $0$. In retirement, all permanent income shocks are turned off, and the only transitory shock is an "unemployment" shock, likely with small probability; this prevents the retired problem from degenerating into a perfect foresight model. +# +# The grid of assets above minimum $\texttt{aXtraGrid}$ is specified by its minimum and maximum level, the number of gridpoints, and the extent of exponential nesting. The greater the (integer) value of $\texttt{aXtraNestFac}$, the more dense the gridpoints will be at the bottom of the grid (and more sparse near the top); setting $\texttt{aXtraNestFac}$ to $0$ will generate an evenly spaced grid of $a_t$. +# +# The artificial borrowing constraint $\texttt{BoroCnstArt}$ can be set to $\texttt{None}$ to turn it off. +# +# It is not necessary to compute the value function in this model, and it is not computationally free to do so. You can choose whether the value function should be calculated and returned as part of the solution of the model with $\texttt{vFuncBool}$. The consumption function will be constructed as a piecewise linear interpolation when $\texttt{CubicBool}$ is \texttt{False}, and will be a piecewise cubic spline interpolator if $\texttt{True}$. + +# %% [markdown] {"heading_collapsed": true} +# ## Solving and examining the solution of the idiosyncratic income shocks model +# +# The cell below creates an infinite horizon instance of $\texttt{IndShockConsumerType}$ and solves its model by calling its $\texttt{solve}$ method. + +# %% {"hidden": true} +IndShockExample = IndShockConsumerType(**IdiosyncDict) +IndShockExample.cycles = 0 # Make this type have an infinite horizon +IndShockExample.solve() + + +# %% [markdown] {"hidden": true} +# After solving the model, we can examine an element of this type's $\texttt{solution}$: + +# %% {"hidden": true} +print(vars(IndShockExample.solution[0])) + +# %% [markdown] {"hidden": true} +# The single-period solution to an idiosyncratic shocks consumer's problem has all of the same attributes as in the perfect foresight model, with a couple additions. The solution can include the marginal marginal value of market resources function $\texttt{vPPfunc}$, but this is only constructed if $\texttt{CubicBool}$ is $\texttt{True}$, so that the MPC can be accurately computed; when it is $\texttt{False}$, then $\texttt{vPPfunc}$ merely returns $\texttt{NaN}$ everywhere. +# +# The $\texttt{solveConsIndShock}$ function calculates steady state market resources and stores it in the attribute $\texttt{mNrmSS}$. This represents the steady state level of $m_t$ if *this period* were to occur indefinitely, but with income shocks turned off. This is relevant in a "one period infinite horizon" model like we've specified here, but is less useful in a lifecycle model. +# +# Let's take a look at the consumption function by plotting it, along with its derivative (the MPC): + +# %% {"hidden": true} +print('Consumption function for an idiosyncratic shocks consumer type:') +plotFuncs(IndShockExample.solution[0].cFunc,IndShockExample.solution[0].mNrmMin,5) +print('Marginal propensity to consume for an idiosyncratic shocks consumer type:') +plotFuncsDer(IndShockExample.solution[0].cFunc,IndShockExample.solution[0].mNrmMin,5) + +# %% [markdown] {"hidden": true} +# The lower part of the consumption function is linear with a slope of 1, representing the *constrained* part of the consumption function where the consumer *would like* to consume more by borrowing-- his marginal utility of consumption exceeds the marginal value of assets-- but he is prevented from doing so by the artificial borrowing constraint. +# +# The MPC is a step function, as the $\texttt{cFunc}$ itself is a piecewise linear function; note the large jump in the MPC where the borrowing constraint begins to bind. +# +# If you want to look at the interpolation nodes for the consumption function, these can be found by "digging into" attributes of $\texttt{cFunc}$: + +# %% {"hidden": true} +print('mNrmGrid for unconstrained cFunc is ',IndShockExample.solution[0].cFunc.functions[0].x_list) +print('cNrmGrid for unconstrained cFunc is ',IndShockExample.solution[0].cFunc.functions[0].y_list) +print('mNrmGrid for borrowing constrained cFunc is ',IndShockExample.solution[0].cFunc.functions[1].x_list) +print('cNrmGrid for borrowing constrained cFunc is ',IndShockExample.solution[0].cFunc.functions[1].y_list) + +# %% [markdown] {"hidden": true} +# The consumption function in this model is an instance of $\texttt{LowerEnvelope1D}$, a class that takes an arbitrary number of 1D interpolants as arguments to its initialization method. When called, a $\texttt{LowerEnvelope1D}$ evaluates each of its component functions and returns the lowest value. Here, the two component functions are the *unconstrained* consumption function-- how the agent would consume if the artificial borrowing constraint did not exist for *just this period*-- and the *borrowing constrained* consumption function-- how much he would consume if the artificial borrowing constraint is binding. +# +# The *actual* consumption function is the lower of these two functions, pointwise. We can see this by plotting the component functions on the same figure: + +# %% {"hidden": true} +plotFuncs(IndShockExample.solution[0].cFunc.functions,-0.25,5.) + +# %% [markdown] +# ## Simulating the idiosyncratic income shocks model +# +# In order to generate simulated data, an instance of $\texttt{IndShockConsumerType}$ needs to know how many agents there are that share these particular parameters (and are thus *ex ante* homogeneous), the distribution of states for newly "born" agents, and how many periods to simulated. These simulation parameters are described in the table below, along with example values. +# +# | Description | Code | Example value | +# | :---: | --- | --- | +# | Number of consumers of this type | $\texttt{AgentCount}$ | $10000$ | +# | Number of periods to simulate | $\texttt{T_sim}$ | $120$ | +# | Mean of initial log (normalized) assets | $\texttt{aNrmInitMean}$ | $-6.0$ | +# | Stdev of initial log (normalized) assets | $\texttt{aNrmInitStd}$ | $1.0$ | +# | Mean of initial log permanent income | $\texttt{pLvlInitMean}$ | $0.0$ | +# | Stdev of initial log permanent income | $\texttt{pLvlInitStd}$ | $0.0$ | +# | Aggregrate productivity growth factor | $\texttt{PermGroFacAgg}$ | $1.0$ | +# | Age after which consumers are automatically killed | $\texttt{T_age}$ | $None$ | +# +# Here, we will simulate 10,000 consumers for 120 periods. All newly born agents will start with permanent income of exactly $P_t = 1.0 = \exp(\texttt{pLvlInitMean})$, as $\texttt{pLvlInitStd}$ has been set to zero; they will have essentially zero assets at birth, as $\texttt{aNrmInitMean}$ is $-6.0$; assets will be less than $1\%$ of permanent income at birth. +# +# These example parameter values were already passed as part of the parameter dictionary that we used to create $\texttt{IndShockExample}$, so it is ready to simulate. We need to set the $\texttt{track_vars}$ attribute to indicate the variables for which we want to record a *history*. + +# %% +IndShockExample.track_vars = ['aNrmNow','mNrmNow','cNrmNow','pLvlNow'] +IndShockExample.initializeSim() +IndShockExample.simulate() + +# %% [markdown] +# We can now look at the simulated data in aggregate or at the individual consumer level. Like in the perfect foresight model, we can plot average (normalized) market resources over time, as well as average consumption: + +# %% +plt.plot(np.mean(IndShockExample.mNrmNow_hist,axis=1)) +plt.xlabel('Time') +plt.ylabel('Mean market resources') +plt.show() + +plt.plot(np.mean(IndShockExample.cNrmNow_hist,axis=1)) +plt.xlabel('Time') +plt.ylabel('Mean consumption') +plt.show() + +# %% [markdown] +# We could also plot individual consumption paths for some of the consumers-- say, the first five: + +# %% +plt.plot(IndShockExample.cNrmNow_hist[:,0:5]) +plt.xlabel('Time') +plt.ylabel('Individual consumption paths') +plt.show() + +# %% [markdown] +# ## Other example specifications of idiosyncratic income shocks consumers +# +# $\texttt{IndShockConsumerType}$-- and $\texttt{HARK}$ in general-- can also represent models that are not infinite horizon. +# +# ### Lifecycle example +# +# Suppose we wanted to represent consumers with a *lifecycle*-- parameter values that differ by age, with a finite end point beyond which the individual cannot surive. This can be done very easily by simply specifying the time-varying attributes $\texttt{PermGroFac}$, $\texttt{LivPrb}$, $\texttt{PermShkStd}$, and $\texttt{TranShkStd}$ as Python *lists* specifying the sequence of periods these agents will experience, from beginning to end. +# +# In the cell below, we define a parameter dictionary for a rather short ten period lifecycle, with arbitrarily chosen parameters. For a more realistically calibrated (and much longer) lifecycle model, see the [SolvingMicroDSOPs REMARK](https://github.com/econ-ark/REMARK/blob/master/REMARKs/SolvingMicroDSOPs.md). + +# %% {"code_folding": [0]} +LifecycleDict={ # Click arrow to expand this fairly large parameter dictionary + # Parameters shared with the perfect foresight model + "CRRA": 2.0, # Coefficient of relative risk aversion + "Rfree": 1.03, # Interest factor on assets + "DiscFac": 0.96, # Intertemporal discount factor + "LivPrb" : [0.99,0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1], + "PermGroFac" : [1.01,1.01,1.01,1.02,1.02,1.02,0.7,1.0,1.0,1.0], + + # Parameters that specify the income distribution over the lifecycle + "PermShkStd" : [0.1,0.2,0.1,0.2,0.1,0.2,0.1,0,0,0], + "PermShkCount" : 7, # Number of points in discrete approximation to permanent income shocks + "TranShkStd" : [0.3,0.2,0.1,0.3,0.2,0.1,0.3,0,0,0], + "TranShkCount" : 7, # Number of points in discrete approximation to transitory income shocks + "UnempPrb" : 0.05, # Probability of unemployment while working + "IncUnemp" : 0.3, # Unemployment benefits replacement rate + "UnempPrbRet" : 0.0005, # Probability of "unemployment" while retired + "IncUnempRet" : 0.0, # "Unemployment" benefits when retired + "T_retire" : 7, # Period of retirement (0 --> no retirement) + "tax_rate" : 0.0, # Flat income tax rate (legacy parameter, will be removed in future) + + # Parameters for constructing the "assets above minimum" grid + "aXtraMin" : 0.001, # Minimum end-of-period "assets above minimum" value + "aXtraMax" : 20, # Maximum end-of-period "assets above minimum" value + "aXtraCount" : 48, # Number of points in the base grid of "assets above minimum" + "aXtraNestFac" : 3, # Exponential nesting factor when constructing "assets above minimum" grid + "aXtraExtra" : [None], # Additional values to add to aXtraGrid + + # A few other paramaters + "BoroCnstArt" : 0.0, # Artificial borrowing constraint; imposed minimum level of end-of period assets + "vFuncBool" : True, # Whether to calculate the value function during solution + "CubicBool" : False, # Preference shocks currently only compatible with linear cFunc + "T_cycle" : 10, # Number of periods in the cycle for this agent type + + # Parameters only used in simulation + "AgentCount" : 10000, # Number of agents of this type + "T_sim" : 120, # Number of periods to simulate + "aNrmInitMean" : -6.0, # Mean of log initial assets + "aNrmInitStd" : 1.0, # Standard deviation of log initial assets + "pLvlInitMean" : 0.0, # Mean of log initial permanent income + "pLvlInitStd" : 0.0, # Standard deviation of log initial permanent income + "PermGroFacAgg" : 1.0, # Aggregate permanent income growth factor + "T_age" : 11, # Age after which simulated agents are automatically killed +} + +# %% [markdown] +# In this case, we have specified a ten period model in which retirement happens in period $t=7$. Agents in this model are more likely to die as they age, and their permanent income drops by 30\% at retirement. Let's make and solve this lifecycle example, then look at the $\texttt{solution}$ attribute. + +# %% +LifecycleExample = IndShockConsumerType(**LifecycleDict) +LifecycleExample.cycles = 1 # Make this consumer live a sequence of periods -- a lifetime -- exactly once +LifecycleExample.solve() +print('First element of solution is',LifecycleExample.solution[0]) +print('Solution has', len(LifecycleExample.solution),'elements.') + +# %% [markdown] +# This was supposed to be a *ten* period lifecycle model-- why does our consumer type have *eleven* elements in its $\texttt{solution}$? It would be more precise to say that this specification has ten *non-terminal* periods. The solution to the 11th and final period in the model would be the same for every set of parameters: consume $c_t = m_t$, because there is no future. In a lifecycle model, the terminal period is assumed to exist; the $\texttt{LivPrb}$ parameter does not need to end with a $0.0$ in order to guarantee that survivors die. +# +# We can quickly plot the consumption functions in each period of the model: + +# %% +print('Consumption functions across the lifecycle:') +mMin = np.min([LifecycleExample.solution[t].mNrmMin for t in range(LifecycleExample.T_cycle)]) +LifecycleExample.unpackcFunc() # This makes all of the cFuncs accessible in the attribute cFunc +plotFuncs(LifecycleExample.cFunc,mMin,5) + +# %% [markdown] +# ### "Cyclical" example +# +# We can also model consumers who face an infinite horizon, but who do *not* face the same problem in every period. Consider someone who works as a ski instructor: they make most of their income for the year in the winter, and make very little money in the other three seasons. +# +# We can represent this type of individual as a four period, infinite horizon model in which expected "permanent" income growth varies greatly across seasons. + +# %% {"code_folding": [0]} +CyclicalDict = { # Click the arrow to expand this parameter dictionary + # Parameters shared with the perfect foresight model + "CRRA": 2.0, # Coefficient of relative risk aversion + "Rfree": 1.03, # Interest factor on assets + "DiscFac": 0.96, # Intertemporal discount factor + "LivPrb" : 4*[0.98], # Survival probability + "PermGroFac" : [1.082251, 2.8, 0.3, 1.1], + + # Parameters that specify the income distribution over the lifecycle + "PermShkStd" : [0.1,0.1,0.1,0.1], + "PermShkCount" : 7, # Number of points in discrete approximation to permanent income shocks + "TranShkStd" : [0.2,0.2,0.2,0.2], + "TranShkCount" : 7, # Number of points in discrete approximation to transitory income shocks + "UnempPrb" : 0.05, # Probability of unemployment while working + "IncUnemp" : 0.3, # Unemployment benefits replacement rate + "UnempPrbRet" : 0.0005, # Probability of "unemployment" while retired + "IncUnempRet" : 0.0, # "Unemployment" benefits when retired + "T_retire" : 0, # Period of retirement (0 --> no retirement) + "tax_rate" : 0.0, # Flat income tax rate (legacy parameter, will be removed in future) + + # Parameters for constructing the "assets above minimum" grid + "aXtraMin" : 0.001, # Minimum end-of-period "assets above minimum" value + "aXtraMax" : 20, # Maximum end-of-period "assets above minimum" value + "aXtraCount" : 48, # Number of points in the base grid of "assets above minimum" + "aXtraNestFac" : 3, # Exponential nesting factor when constructing "assets above minimum" grid + "aXtraExtra" : [None], # Additional values to add to aXtraGrid + + # A few other paramaters + "BoroCnstArt" : 0.0, # Artificial borrowing constraint; imposed minimum level of end-of period assets + "vFuncBool" : True, # Whether to calculate the value function during solution + "CubicBool" : False, # Preference shocks currently only compatible with linear cFunc + "T_cycle" : 4, # Number of periods in the cycle for this agent type + + # Parameters only used in simulation + "AgentCount" : 10000, # Number of agents of this type + "T_sim" : 120, # Number of periods to simulate + "aNrmInitMean" : -6.0, # Mean of log initial assets + "aNrmInitStd" : 1.0, # Standard deviation of log initial assets + "pLvlInitMean" : 0.0, # Mean of log initial permanent income + "pLvlInitStd" : 0.0, # Standard deviation of log initial permanent income + "PermGroFacAgg" : 1.0, # Aggregate permanent income growth factor + "T_age" : None, # Age after which simulated agents are automatically killed +} + +# %% [markdown] +# This consumer type's parameter dictionary is nearly identical to the original infinite horizon type we made, except that each of the time-varying parameters now have *four* values, rather than just one. Most of these have the same value in each period *except* for $\texttt{PermGroFac}$, which varies greatly over the four seasons. Note that the product of the four "permanent" income growth factors is almost exactly 1.0-- this type's income does not grow on average in the long run! +# +# Let's make and solve this consumer type, then plot his quarterly consumption functions: + +# %% +CyclicalExample = IndShockConsumerType(**CyclicalDict) +CyclicalExample.cycles = 0 # Make this consumer type have an infinite horizon +CyclicalExample.solve() + +CyclicalExample.unpackcFunc() +print('Quarterly consumption functions:') +mMin = min([X.mNrmMin for X in CyclicalExample.solution]) +plotFuncs(CyclicalExample.cFunc,mMin,5) + +# %% [markdown] +# The very low green consumption function corresponds to the quarter in which the ski instructors make most of their income. They know that they are about to experience a 70% drop in "permanent" income, so they do not consume much *relative to their income this quarter*. In the other three quarters, *normalized* consumption is much higher, as current "permanent" income is low relative to future expectations. In *level*, the consumption chosen in each quarter is much more similar diff --git a/examples/ConsIndShockModel/KinkedRconsumerType.ipynb b/examples/ConsIndShockModel/KinkedRconsumerType.ipynb new file mode 100644 index 000000000..cc57b6c4a --- /dev/null +++ b/examples/ConsIndShockModel/KinkedRconsumerType.ipynb @@ -0,0 +1,369 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# KinkedRconsumerType: Consumption-saving model with idiosyncratic income shocks and different interest rates on borrowing and saving" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "# Initial imports and notebook setup, click arrow to show\n", + "from HARK.ConsumptionSaving.ConsIndShockModel import KinkedRconsumerType\n", + "from HARK.utilities import plotFuncsDer, plotFuncs\n", + "from time import clock\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "mystr = lambda number : \"{:.4f}\".format(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The module $\\texttt{HARK.ConsumptionSaving.ConsIndShockModel}$ concerns consumption-saving models with idiosyncratic shocks to (non-capital) income. All of the models assume CRRA utility with geometric discounting, no bequest motive, and income shocks are fully transitory or fully permanent.\n", + "\n", + "$\\texttt{ConsIndShockModel}$ currently includes three models:\n", + "1. A very basic \"perfect foresight\" model with no uncertainty.\n", + "2. A model with risk over transitory and permanent income shocks.\n", + "3. The model described in (2), with an interest rate for debt that differs from the interest rate for savings.\n", + "\n", + "This notebook provides documentation for the third of these models.\n", + "$\\newcommand{\\CRRA}{\\rho}$\n", + "$\\newcommand{\\DiePrb}{\\mathsf{D}}$\n", + "$\\newcommand{\\PermGroFac}{\\Gamma}$\n", + "$\\newcommand{\\Rfree}{\\mathsf{R}}$\n", + "$\\newcommand{\\DiscFac}{\\beta}$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Statement of \"kinked R\" model\n", + "\n", + "Consider a small extension to the model faced by $\\texttt{IndShockConsumerType}$s: that the interest rate on borrowing $a_t < 0$ is greater than the interest rate on saving $a_t > 0$. Consumers who face this kind of problem are represented by the $\\texttt{KinkedRconsumerType}$ class.\n", + "\n", + "For a full theoretical treatment, this model analyzed in [A Theory of the Consumption Function, With\n", + "and Without Liquidity Constraints](http://www.econ2.jhu.edu/people/ccarroll/ATheoryv3JEP.pdf)\n", + "and its [expanded edition](http://www.econ2.jhu.edu/people/ccarroll/ATheoryv3NBER.pdf).\n", + "\n", + "Continuing to work with *normalized* variables (e.g. $m_t$ represents the level of market resources divided by permanent income), the \"kinked R\" model can be stated as:\n", + "\n", + "\\begin{eqnarray*}\n", + "v_t(m_t) &=& \\max_{c_t} {~} U(c_t) + \\DiscFac (1-\\DiePrb_{t+1}) \\mathbb{E}_{t} \\left[ (\\PermGroFac_{t+1}\\psi_{t+1})^{1-\\CRRA} v_{t+1}(m_{t+1}) \\right], \\\\\n", + "a_t &=& m_t - c_t, \\\\\n", + "a_t &\\geq& \\underline{a}, \\\\\n", + "m_{t+1} &=& \\Rfree_t/(\\PermGroFac_{t+1} \\psi_{t+1}) a_t + \\theta_{t+1}, \\\\\n", + "\\Rfree_t &=& \\cases{\\Rfree_{boro} \\texttt{ if } a_t < 0 \\\\\n", + " \\Rfree_{save} \\texttt{ if } a_t \\geq 0},\\\\\n", + "\\Rfree_{boro} &>& \\Rfree_{save}, \\\\\n", + "(\\psi_{t+1},\\theta_{t+1}) &\\sim& F_{t+1}, \\\\\n", + "\\mathbb{E}[\\psi]=\\mathbb{E}[\\theta] &=& 1.\n", + "\\end{eqnarray*}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solving the \"kinked R\" model\n", + "\n", + "The solution method for the \"kinked R\" model is nearly identical to that of the $\\texttt{IndShockConsumerType}$ on which it is based, using the endogenous grid method; see the notebook for that model for more information. The only significant difference is that the interest factor varies by $a_t$ across the exogenously chosen grid of end-of-period assets, with a discontinuity in $\\Rfree$ at $a_t=0$.\n", + "\n", + "To correctly handle this, the $\\texttt{solveConsKinkedR}$ function inserts *two* instances of $a_t=0$ into the grid of $a_t$ values: the first corresponding to $\\Rfree_{boro}$ ($a_t = -0$) and the other corresponding to $\\Rfree_{save}$ ($a_t = +0$). The two consumption levels (and corresponding endogenous $m_t$ gridpoints) represent points at which the agent's first order condition is satisfied at *exactly* $a_t=0$ at the two different interest factors. In between these two points, the first order condition *does not hold with equality*: the consumer will end the period with exactly $a_t=0$, consuming $c_t=m_t$, but his marginal utility of consumption exceeds the marginal value of saving and is less than the marginal value of borrowing. This generates a consumption function with *two* kinks: two concave portions (for borrowing and saving) with a linear segment of slope 1 in between." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example parameter values to construct an instance of KinkedRconsumerType\n", + "\n", + "The parameters required to create an instance of $\\texttt{KinkedRconsumerType}$ are nearly identical to those for $\\texttt{IndShockConsumerType}$. The only difference is that the parameter $\\texttt{Rfree}$ is replaced with $\\texttt{Rboro}$ and $\\texttt{Rsave}$.\n", + "\n", + "While the parameter $\\texttt{CubicBool}$ is required to create a valid $\\texttt{KinkedRconsumerType}$ instance, it must be set to $\\texttt{False}$; cubic spline interpolation has not yet been implemented for this model. In the future, this restriction will be lifted.\n", + "\n", + "| Parameter | Description | Code | Example value | Time-varying? |\n", + "| :---: | --- | --- | --- | --- |\n", + "| $\\DiscFac$ |Intertemporal discount factor | $\\texttt{DiscFac}$ | $0.96$ | |\n", + "| $\\CRRA $ |Coefficient of relative risk aversion | $\\texttt{CRRA}$ | $2.0$ | |\n", + "| $\\Rfree_{boro}$ | Risk free interest factor for borrowing | $\\texttt{Rboro}$ | $1.20$ | |\n", + "| $\\Rfree_{save}$ | Risk free interest factor for saving | $\\texttt{Rsave}$ | $1.01$ | |\n", + "| $1 - \\DiePrb_{t+1}$ |Survival probability | $\\texttt{LivPrb}$ | $[0.98]$ | $\\surd$ |\n", + "|$\\PermGroFac_{t+1}$|Permanent income growth factor|$\\texttt{PermGroFac}$| $[1.01]$ | $\\surd$ |\n", + "| $\\sigma_\\psi $ | Standard deviation of log permanent income shocks | $\\texttt{PermShkStd}$ | $[0.1]$ |$\\surd$ |\n", + "| $N_\\psi $ | Number of discrete permanent income shocks | $\\texttt{PermShkCount}$ | $7$ | |\n", + "| $\\sigma_\\theta $ | Standard deviation of log transitory income shocks | $\\texttt{TranShkStd}$ | $[0.2]$ | $\\surd$ |\n", + "| $N_\\theta $ | Number of discrete transitory income shocks | $\\texttt{TranShkCount}$ | $7$ | |\n", + "| $\\mho$ | Probability of being unemployed and getting $\\theta=\\underline{\\theta}$ | $\\texttt{UnempPrb}$ | $0.05$ | |\n", + "| $\\underline{\\theta} $ | Transitory shock when unemployed | $\\texttt{IncUnemp}$ | $0.3$ | |\n", + "| $\\mho^{Ret}$ | Probability of being \"unemployed\" when retired | $\\texttt{UnempPrb}$ | $0.0005$ | |\n", + "| $\\underline{\\theta}^{Ret} $ | Transitory shock when \"unemployed\" and retired | $\\texttt{IncUnemp}$ | $0.0$ | |\n", + "| $(none)$ | Period of the lifecycle model when retirement begins | $\\texttt{T_retire}$ | $0$ | |\n", + "| $(none)$ | Minimum value in assets-above-minimum grid | $\\texttt{aXtraMin}$ | $0.001$ | |\n", + "| $(none)$ | Maximum value in assets-above-minimum grid | $\\texttt{aXtraMax}$ | $20.0$ | |\n", + "| $(none)$ | Number of points in base assets-above-minimum grid | $\\texttt{aXtraCount}$ | $48$ | |\n", + "| $(none)$ | Exponential nesting factor for base assets-above-minimum grid | $\\texttt{aXtraNestFac}$ | $3$ | |\n", + "| $(none)$ | Additional values to add to assets-above-minimum grid | $\\texttt{aXtraExtra}$ | $None$ | |\n", + "| $\\underline{a} $ | Artificial borrowing constraint (normalized) | $\\texttt{BoroCnstArt}$ | $None$ | |\n", + "| $(none) $ |Indicator for whether $\\texttt{vFunc}$ should be computed | $\\texttt{vFuncBool}$ | $True$ | |\n", + "| $(none)$ |Indicator for whether $\\texttt{cFunc}$ should use cubic splines | $\\texttt{CubicBool}$ | $False$ | |\n", + "|$T$| Number of periods in this type's \"cycle\" |$\\texttt{T_cycle}$| $1$ | |\n", + "|(none)| Number of times the \"cycle\" occurs |$\\texttt{cycles}$| $0$ | |\n", + "\n", + "These example parameters are almostidentical to those used for $\\texttt{IndShockExample}$ in the prior notebook, except that the interest rate on borrowing is 20% (like a credit card), and the interest rate on saving is 1%. Moreover, the artificial borrowing constraint has been set to $\\texttt{None}$. The cell below defines a parameter dictionary with these example values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "KinkedRdict={ # Click the arrow to expand this parameter dictionary\n", + " # Parameters shared with the perfect foresight model\n", + " \"CRRA\" : 2.0, # Coefficient of relative risk aversion\n", + " \"DiscFac\": 0.96, # Intertemporal discount factor\n", + " \"LivPrb\" : [0.98], # Survival probability\n", + " \"PermGroFac\" :[1.01], # Permanent income growth factor\n", + " \n", + " # New parameters unique to the \"kinked R\" model\n", + " \"Rboro\" : 1.20, # Interest factor on borrowing (a < 0)\n", + " \"Rsave\" : 1.01, # Interest factor on saving (a > 0)\n", + " \n", + " # Parameters that specify the income distribution over the lifecycle\n", + " \"PermShkStd\" : [0.1], # Standard deviation of log permanent shocks to income\n", + " \"PermShkCount\" : 7, # Number of points in discrete approximation to permanent income shocks\n", + " \"TranShkStd\" : [0.2], # Standard deviation of log transitory shocks to income\n", + " \"TranShkCount\" : 7, # Number of points in discrete approximation to transitory income shocks\n", + " \"UnempPrb\" : 0.05, # Probability of unemployment while working\n", + " \"IncUnemp\" : 0.3, # Unemployment benefits replacement rate\n", + " \"UnempPrbRet\" : 0.0005, # Probability of \"unemployment\" while retired\n", + " \"IncUnempRet\" : 0.0, # \"Unemployment\" benefits when retired\n", + " \"T_retire\" : 0, # Period of retirement (0 --> no retirement)\n", + " \"tax_rate\" : 0.0, # Flat income tax rate (legacy parameter, will be removed in future)\n", + " \n", + " # Parameters for constructing the \"assets above minimum\" grid\n", + " \"aXtraMin\" : 0.001, # Minimum end-of-period \"assets above minimum\" value\n", + " \"aXtraMax\" : 20, # Maximum end-of-period \"assets above minimum\" value\n", + " \"aXtraCount\" : 48, # Number of points in the base grid of \"assets above minimum\"\n", + " \"aXtraNestFac\" : 3, # Exponential nesting factor when constructing \"assets above minimum\" grid\n", + " \"aXtraExtra\" : [None], # Additional values to add to aXtraGrid\n", + " \n", + " # A few other paramaters\n", + " \"BoroCnstArt\" : None, # Artificial borrowing constraint; imposed minimum level of end-of period assets\n", + " \"vFuncBool\" : True, # Whether to calculate the value function during solution \n", + " \"CubicBool\" : False, # Preference shocks currently only compatible with linear cFunc\n", + " \"T_cycle\" : 1, # Number of periods in the cycle for this agent type \n", + " \n", + " # Parameters only used in simulation\n", + " \"AgentCount\" : 10000, # Number of agents of this type\n", + " \"T_sim\" : 500, # Number of periods to simulate\n", + " \"aNrmInitMean\" : -6.0, # Mean of log initial assets\n", + " \"aNrmInitStd\" : 1.0, # Standard deviation of log initial assets\n", + " \"pLvlInitMean\" : 0.0, # Mean of log initial permanent income\n", + " \"pLvlInitStd\" : 0.0, # Standard deviation of log initial permanent income\n", + " \"PermGroFacAgg\" : 1.0, # Aggregate permanent income growth factor\n", + " \"T_age\" : None, # Age after which simulated agents are automatically killed\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solving and examining the solution of the \"kinked R\" model\n", + "\n", + "The cell below creates an infinite horizon instance of $\\texttt{KinkedRconsumerType}$ and solves its model by calling its $\\texttt{solve}$ method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "KinkyExample = KinkedRconsumerType(**KinkedRdict)\n", + "KinkyExample.cycles = 0 # Make the example infinite horizon\n", + "KinkyExample.solve()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An element of a $\\texttt{KinkedRconsumerType}$'s solution will have all the same attributes as that of a $\\texttt{IndShockConsumerType}$; see that notebook for details.\n", + "\n", + "We can plot the consumption function of our \"kinked R\" example, as well as the MPC:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('Kinked R consumption function:')\n", + "plotFuncs(KinkyExample.solution[0].cFunc,KinkyExample.solution[0].mNrmMin,5)\n", + "\n", + "print('Kinked R marginal propensity to consume:')\n", + "plotFuncsDer(KinkyExample.solution[0].cFunc,KinkyExample.solution[0].mNrmMin,5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simulating the \"kinked R\" model\n", + "\n", + "In order to generate simulated data, an instance of $\\texttt{KinkedRconsumerType}$ needs to know how many agents there are that share these particular parameters (and are thus *ex ante* homogeneous), the distribution of states for newly \"born\" agents, and how many periods to simulated. These simulation parameters are described in the table below, along with example values.\n", + "\n", + "| Description | Code | Example value |\n", + "| :---: | --- | --- |\n", + "| Number of consumers of this type | $\\texttt{AgentCount}$ | $10000$ |\n", + "| Number of periods to simulate | $\\texttt{T_sim}$ | $500$ |\n", + "| Mean of initial log (normalized) assets | $\\texttt{aNrmInitMean}$ | $-6.0$ |\n", + "| Stdev of initial log (normalized) assets | $\\texttt{aNrmInitStd}$ | $1.0$ |\n", + "| Mean of initial log permanent income | $\\texttt{pLvlInitMean}$ | $0.0$ |\n", + "| Stdev of initial log permanent income | $\\texttt{pLvlInitStd}$ | $0.0$ |\n", + "| Aggregrate productivity growth factor | $\\texttt{PermGroFacAgg}$ | $1.0$ |\n", + "| Age after which consumers are automatically killed | $\\texttt{T_age}$ | $None$ |\n", + "\n", + "Here, we will simulate 10,000 consumers for 500 periods. All newly born agents will start with permanent income of exactly $P_t = 1.0 = \\exp(\\texttt{pLvlInitMean})$, as $\\texttt{pLvlInitStd}$ has been set to zero; they will have essentially zero assets at birth, as $\\texttt{aNrmInitMean}$ is $-6.0$; assets will be less than $1\\%$ of permanent income at birth.\n", + "\n", + "These example parameter values were already passed as part of the parameter dictionary that we used to create $\\texttt{KinkyExample}$, so it is ready to simulate. We need to set the $\\texttt{track_vars}$ attribute to indicate the variables for which we want to record a *history*." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "KinkyExample.track_vars = ['mNrmNow','cNrmNow','pLvlNow']\n", + "KinkyExample.initializeSim()\n", + "KinkyExample.simulate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can plot the average (normalized) market resources in each simulated period:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(np.mean(KinkyExample.mNrmNow_hist,axis=1))\n", + "plt.xlabel('Time')\n", + "plt.ylabel('Mean market resources')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's plot the distribution of (normalized) assets $a_t$ for the current population, after simulating for $500$ periods; this should be fairly close to the long run distribution:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(np.sort(KinkyExample.aNrmNow),np.linspace(0.,1.,KinkyExample.AgentCount))\n", + "plt.xlabel('End-of-period assets')\n", + "plt.ylabel('Cumulative distribution')\n", + "plt.ylim(-0.01,1.01)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see there's a significant point mass of consumers with *exactly* $a_t=0$; these are consumers who do not find it worthwhile to give up a bit of consumption to begin saving (because $\\Rfree_{save}$ is too low), and also are not willing to finance additional consumption by borrowing (because $\\Rfree_{boro}$ is too high).\n", + "\n", + "The smaller point masses in this distribution are due to $\\texttt{HARK}$ drawing simulated income shocks from the discretized distribution, rather than the \"true\" lognormal distributions of shocks. For consumers who ended $t-1$ with $a_{t-1}=0$ in assets, there are only 8 values the transitory shock $\\theta_{t}$ can take on, and thus only 8 values of $m_t$ thus $a_t$ they can achieve; the value of $\\psi_t$ is immaterial to $m_t$ when $a_{t-1}=0$. You can verify this by changing $\\texttt{TranShkCount}$ to some higher value, like 25, in the dictionary above, then running the subsequent cells; the smaller point masses will not be visible to the naked eye." + ] + } + ], + "metadata": { + "@webio": { + "lastCommId": "779f6c5616b04b58baaaa0f6c348270c", + "lastKernelId": "a944b08f-0ae0-4c26-883f-9fab53a82ac3" + }, + "jupytext": { + "cell_metadata_filter": "collapsed,code_folding", + "formats": "ipynb,py:percent" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/ConsIndShockModel/PerfForesightConsumerType.ipynb b/examples/ConsIndShockModel/PerfForesightConsumerType.ipynb new file mode 100644 index 000000000..25bfddfa5 --- /dev/null +++ b/examples/ConsIndShockModel/PerfForesightConsumerType.ipynb @@ -0,0 +1,676 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PerfForesightConsumerType" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "# Initial imports and notebook setup, click arrow to show\n", + "from HARK.ConsumptionSaving.ConsIndShockModel import PerfForesightConsumerType\n", + "from HARK.utilities import plotFuncs\n", + "from time import clock\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "mystr = lambda number : \"{:.4f}\".format(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The module $\\texttt{HARK.ConsumptionSaving.ConsIndShockModel}$ concerns consumption-saving models with idiosyncratic shocks to (non-capital) income. All of the models assume CRRA utility with geometric discounting, no bequest motive, and income shocks that are either fully transitory or fully permanent.\n", + "\n", + "$\\texttt{ConsIndShockModel}$ currently includes three models:\n", + "1. A very basic \"perfect foresight\" model with no uncertainty (shocks are zero).\n", + "2. A model with risk over transitory and permanent income shocks.\n", + "3. The model described in (2), with an interest rate for debt that differs from the interest rate for savings.\n", + "\n", + "This notebook provides documentation for the first of these three models.\n", + "$\\newcommand{\\CRRA}{\\rho}$\n", + "$\\newcommand{\\DiePrb}{\\mathsf{D}}$\n", + "$\\newcommand{\\PermGroFac}{\\Gamma}$\n", + "$\\newcommand{\\Rfree}{\\mathsf{R}}$\n", + "$\\newcommand{\\DiscFac}{\\beta}$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Statement of the model\n", + "\n", + "The $\\texttt{PerfForesightConsumerType}$ class solves the problem of a consumer with Constant Relative Risk Aversion utility \n", + "${\\CRRA}$\n", + "\\begin{equation}\n", + "U(C) = \\frac{C^{1-\\CRRA}}{1-\\rho},\n", + "\\end{equation}\n", + "who has perfect foresight about everything except whether he will die between the end of period $t$ and the beginning of period $t+1$. Permanent labor income $P_t$ grows from period $t$ to period $t+1$ by factor $\\PermGroFac_{t+1}$. The consumer faces no artificial borrowing constraint: He is able to borrow against his entire future stream of income.\n", + "\n", + "At the beginning of period $t$, the consumer has market resources $M_t$ (which includes both market wealth and currrent income) and must choose how much to consume $C_t$ and how much to retain in a riskless asset $A_t$, which will earn return factor $\\Rfree$. The agent's flow of future utility $U(C_{t+n})$ from consumption is geometrically discounted by factor $\\DiscFac$ per period. The consumer only experiences future value if he survives, which occurs with probability $1-\\DiePrb_{t+1}$.\n", + "\n", + "For parallelism with the treatment of more complicated problems, we write the problem rather elaborately in Bellman form as:\n", + "\n", + "\\begin{eqnarray*}\n", + "V_t(M_t,P_t) &=& \\max_{C_t}~U(C_t) ~+ \\DiscFac (1 - \\DiePrb_{t+1}) V_{t+1}(M_{t+1},P_{t+1}), \\\\\n", + "& s.t. & \\\\\n", + "A_t &=& M_t - C_t, \\\\\n", + "M_{t+1} &=& \\Rfree A_t + Y_{t+1}, \\\\\n", + "Y_{t+1} &=& P_{t+1}, \\\\ \n", + "P_{t+1} &=& \\PermGroFac_{t+1} P_t.\n", + "\\end{eqnarray*}\n", + "\n", + "The parameters of the consumer's problem are the coefficient of relative risk aversion $\\CRRA$, the intertemporal discount factor $\\DiscFac$, an interest factor $\\Rfree$, and age-varying sequences of the permanent income growth factor $\\PermGroFac_t$ and survival probability $(1 - \\DiePrb_t)$. [These lecture notes](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA) show that under these assumptions the problem can be transformed into an equivalent problem stated in terms of *normalized* variables (represented in lower case); all real variables are divided by permanent income $P_t$ and value is divided by $P_t^{1-\\CRRA}$. The Bellman form of the normalized model (see the lecture notes for details) is:\n", + "\n", + "\\begin{eqnarray*}\n", + "v_t(m_t) &=& \\max_{c_t}~U(c_t) ~+ \\DiscFac (1 - \\DiePrb_{t+1}) \\PermGroFac_{t+1}^{1-\\CRRA} v_{t+1}(m_{t+1}), \\\\\n", + "& s.t. & \\\\\n", + "a_t &=& m_t - c_t, \\\\\n", + "m_{t+1} &=& a_t (\\Rfree/\\PermGroFac_{t+1} )+ 1.\n", + "\\end{eqnarray*}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution method for PerfForesightConsumerType\n", + "\n", + "Because of the assumptions of CRRA utility, no risk other than mortality, and no artificial borrowing constraint, the problem has a closed form solution in which consumption is a linear function of resources, and the utility-inverse of the value function is also linear (that is, $u^{-1}(v)$ is linear in $m$). Details of the mathematical solution of this model can be found in the lecture notes [PerfForesightCRRA](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA). \n", + "\n", + "The one period problem for this model is solved by the function $\\texttt{solveConsPerfForesight}$, which creates an instance of the class $\\texttt{ConsPerfForesightSolver}$. To construct an instance of the class $\\texttt{PerfForesightConsumerType}$, several parameters must be passed to this constructor. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example parameter values\n", + "\n", + "| Parameter | Description | Code | Example value | Time-varying? |\n", + "| :---: | --- | --- | --- | --- |\n", + "| $\\DiscFac$ |Intertemporal discount factor | $\\texttt{DiscFac}$ | $0.96$ | |\n", + "| $\\CRRA $ |Coefficient of relative risk aversion | $\\texttt{CRRA}$ | $2.0$ | |\n", + "| $\\Rfree$ | Risk free interest factor | $\\texttt{Rfree}$ | $1.03$ | |\n", + "| $1 - \\DiePrb_{t+1}$ |Survival probability | $\\texttt{LivPrb}$ | $[0.98]$ | $\\surd$ |\n", + "|$\\PermGroFac_{t+1}$|Permanent income growth factor|$\\texttt{PermGroFac}$| $[1.01]$ | $\\surd$ |\n", + "|$T$| Number of periods in this type's \"cycle\" |$\\texttt{T_cycle}$| $1$ | |\n", + "|(none)| Number of times the \"cycle\" occurs |$\\texttt{cycles}$| $0$ | |\n", + "\n", + "Note that the survival probability and income growth factor have time subscripts; likewise, the example values for these parameters are *lists* rather than simply single floats. This is because those parameters are in principle *time-varying*: their values can depend on which period of the problem the agent is in (for example, mortality probability depends on age). All time-varying parameters *must* be specified as lists, even when the model is being solved for an infinite horizon case where in practice the parameter takes the same value in every period.\n", + "\n", + "The last two parameters in the table specify the \"nature of time\" for this type: the number of (non-terminal) periods in this type's \"cycle\", and the number of times that the \"cycle\" occurs. *Every* subclass of $\\texttt{AgentType}$ uses these two code parameters to define the nature of time. Here, $\\texttt{T_cycle}$ has the value $1$, indicating that there is exactly one period in the cycle, while $\\texttt{cycles}$ is $0$, indicating that the cycle is repeated in *infinite* number of times-- it is an infinite horizon model, with the same \"kind\" of period repeated over and over.\n", + "\n", + "In contrast, we could instead specify a life-cycle model by setting $\\texttt{T_cycle}$ to $1$, and specifying age-varying sequences of income growth and survival probability. In all cases, the number of elements in each time-varying parameter should exactly equal $\\texttt{T_cycle}$.\n", + "\n", + "The parameter $\\texttt{AgentCount}$ specifies how many consumers there are of this *type*-- how many individuals have these exact parameter values and are *ex ante* homogeneous. This information is not relevant for solving the model, but is needed in order to simulate a population of agents, introducing *ex post* heterogeneity through idiosyncratic shocks. Of course, simulating a perfect foresight model is quite boring, as there are *no* idiosyncratic shocks other than death!\n", + "\n", + "The cell below defines a dictionary that can be passed to the constructor method for $\\texttt{PerfForesightConsumerType}$, with the values from the table here." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "PerfForesightDict = {\n", + " # Parameters actually used in the solution method\n", + " \"CRRA\" : 2.0, # Coefficient of relative risk aversion\n", + " \"Rfree\" : 1.03, # Interest factor on assets\n", + " \"DiscFac\" : 0.96, # Default intertemporal discount factor\n", + " \"LivPrb\" : [0.98], # Survival probability\n", + " \"PermGroFac\" :[1.01], # Permanent income growth factor\n", + " \n", + " # Parameters that characterize the nature of time\n", + " \"T_cycle\" : 1, # Number of periods in the cycle for this agent type\n", + " \"cycles\" : 0 # Number of times the cycle occurs (0 --> infinitely repeated)\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inspecting the solution\n", + "\n", + "With the dictionary we have just defined, we can create an instance of $\\texttt{PerfForesightConsumerType}$ by passing the dictionary to the class (as if the class were a function). This instance can then be solved by invoking its $\\texttt{solve}$ method." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "PFexample = PerfForesightConsumerType(**PerfForesightDict)\n", + "PFexample.cycles = 0\n", + "PFexample.solve()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The $\\texttt{solve}$ method fills in the instance's attribute $\\texttt{solution}$ as a time-varying list of solutions to each period of the consumer's problem. In this case, $\\texttt{solution}$ will be a list with exactly one instance of the class $\\texttt{ConsumerSolution}$, representing the solution to the infinite horizon model we specified." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "print(PFexample.solution)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each element of $\\texttt{solution}$ has a few attributes. To see all of them, we can use the $\\texttt{vars}$ built in function: the consumption functions are instantiated in the attribute $\\texttt{cFunc}$ of each element of $\\texttt{ConsumerType.solution}$. This method creates a (time varying) attribute $\\texttt{cFunc}$ that contains a list of consumption functions by age." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'cFunc': , 'vFunc': , 'vPfunc': , 'vPPfunc': , 'mNrmMin': -50.49994992551661, 'hNrm': 50.49994992551661, 'MPCmin': 0.04428139169919579, 'MPCmax': 0.04428139169919579}\n" + ] + } + ], + "source": [ + "print(vars(PFexample.solution[0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The two most important attributes of a single period solution are the (normalized) consumption function $\\texttt{cFunc}$ and the (normalized) value function $\\texttt{vFunc}$; the marginal value function $\\texttt{vPfunc}$ is also constructed. Let's plot those functions near the lower bound of the permissible state space (the attribute $\\texttt{mNrmMin}$ tells us the lower bound of $m_t$ where the consumption function is defined)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Linear perfect foresight consumption function:\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "print('Linear perfect foresight consumption function:')\n", + "mMin = PFexample.solution[0].mNrmMin\n", + "plotFuncs(PFexample.solution[0].cFunc,mMin,mMin+10.)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Perfect foresight value function:\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "print('Perfect foresight value function:')\n", + "plotFuncs(PFexample.solution[0].vFunc,mMin+0.1,mMin+10.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution Method\n", + "\n", + "\n", + "### Recursive Formula for $\\kappa_{t}$\n", + "\n", + "The paper [BufferStockTheory](https://www.econ2.jhu.edu/people/ccarroll/papers/BufferStockTheory/) has a few other results that are used in the solution code. One is [the recursive formula for the MPC](https://www.econ2.jhu.edu/people/ccarroll/papers/BufferStockTheory/#MPCnvrs). Starting with the last period, in which $\\kappa_{T}=1$, the inverse MPC's (and therefore the MPC's themselves) can be constructed using the recursive formula:\n", + "\n", + "\\begin{align}\n", + "\\kappa_{t}^{-1} & = & 1 + \\kappa_{t+1}^{-1}(\\Rfree \\beta)^{1/\\rho}/G \n", + "\\end{align}\n", + "\n", + "### Consumption Function\n", + "\n", + "For the perfect foresight problem, there is a well-known [analytical solution]( http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA/#cFuncAnalytical) for the consumption function: Calling $o_{t}$ 'overall wealth' (including market wealth plus human wealth $h_{t}$) and designating the marginal propensity to consume in period $t$ by $\\kappa_{t}$:\n", + "\n", + "\\begin{align}\n", + "\\mathrm{c}_{t} & = o_{t}\\kappa_{t}\n", + "\\end{align}\n", + "\n", + "and in our normalized model $o_{t} = m_{t}-1+h_{t}$ (the '-1' term subtracts off the normalized current income of 1 from market resources $m$ which were market wealth plus current income).\n", + "\n", + "### Value Function\n", + "\n", + "A convenient feature of the perfect foresight problem is that the value function has a simple [analytical form](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA/#vFuncAnalytical):\n", + "\n", + "\\begin{align}\n", + "\\mathrm{v}_{t} & = \\mathrm{u}(\\mathrm{c}_{t}(m))\\kappa_{t}^{-1}\\\\\n", + " &= \\mathrm{u}(o_{t} \\kappa_{t}) \\kappa_{t}^{-1} \\\\ \n", + " &= \\mathrm{u}(o_{t})\\kappa_{t}^{1-\\rho} \\kappa_{t}^{-1} \\\\\n", + " &= \\mathrm{u}(o_{t})\\kappa_{t}^{-\\rho}\n", + "\\end{align}\n", + "\n", + "This means that the utility-inverse of the value function, ${\\scriptsize \\Lambda} \\equiv \\mathrm{u}^{-1}(\\mathrm{v})$, is linear:\n", + "\n", + "\\begin{align}\n", + "\\scriptsize \\Lambda_{t} & = o_{t} \\kappa_{t}^{-\\rho/(1-\\rho)}\n", + "\\end{align}\n", + "\n", + "When uncertainty or liquidity constraints are added to the problem, the ${\\scriptsize \\Lambda}$ function is no longer linear. But even in these cases, the utility-inverse of the value function is much better behaved (e.g., closer to linear; bounded over any feasible finite range of $m$) than the uninverted function (which, for example, approaches $-\\infty$ as $m$ approaches its lower bound).\n", + "\n", + "Our procedure will therefore generically be to construct the inverse value function, and to obtain the value function from it by uninverting. That is, we construct an interpolating approximation of $\\scriptsize \\Lambda_{t}$ and compute value on-the-fly from\n", + "\n", + "\\begin{align}\n", + "\\mathrm{v}_{t}(m) & = \\mathrm{u}({\\scriptsize \\Lambda_{t}}(m))\n", + "\\end{align}\n", + "\n", + "In this case, the interpolation is exact, not an approximation: We need only two points to construct a line, so we choose the minimum possible value of normalized market resources, $\\texttt{mNrmMin}$, where $o_{t}=0$ so that $c_{t}=0$, and that minimum plus 1, where the inverted value function will have the value $\\kappa_{t}^{-\\rho/(1-\\rho)}$. From these we construct $vFuncNvrs$ as a linear interpolating function (which automatically extrapolates to the whole number line).\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Checking Solution Conditions\n", + "\n", + "The code performs tests for whether the supplied parameter values meet various conditions that determine the properties of the solution. Some conditions (like the Finite Human Wealth Condition) are required for the model to have a sensible solution, and if these conditions are violated the code generates a warning message. Other conditions govern characteristics of the model like whether consumption is falling (whether the consumer is 'absolutely impatient'). All conditions can manually be performed using the syntax below. The function returns \"False\" if none of the key conditions has been violated." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The value of the absolute impatience factor for the supplied parameter values satisfies the Absolute Impatience Condition. Therefore, the absolute amount of consumption is expected to fall over time.\n", + "\n", + "The value of the growth impatience factor for the supplied parameter values satisfies the Growth Impatience Condition. Therefore, the ratio of individual wealth to permanent income will fall indefinitely.\n", + "\n", + "The return impatience factor value for the supplied parameter values satisfies the Return Impatience Condition. Therefore, the limiting consumption function is not c(m)=0\n", + "\n", + "The Finite Human wealth factor value for the supplied parameter values satisfies the Finite Human Wealth Condition. Therefore, the limiting consumption function is not c(m)=Infinity\n", + "and human wealth normalized by permanent income is 51.50000\n", + "and the PDV of future consumption growth is 22.58285\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "PFexample.checkConditions(verbose=True,public_call=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An element of $\\texttt{solution}$ also includes the (normalized) marginal value function $\\texttt{vPfunc}$, and the lower and upper bounds of the marginal propensity to consume (MPC) $\\texttt{MPCmin}$ and $\\texttt{MPCmax}$. Note that with a linear consumption function, the MPC is constant, so its lower and upper bound are identical." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simulating the model\n", + "\n", + "Suppose we wanted to simulate many consumers who share the parameter values that we passed to $\\texttt{PerfForesightConsumerType}$-- an *ex ante* homogeneous *type* of consumers. To do this, our instance would have to know *how many* agents there are of this type, as well as their initial levels of assets $a_t$ and permanent income $P_t$.\n", + "\n", + "### Setting Parameters\n", + "\n", + "Let's fill in this information by passing another dictionary to $\\texttt{PFexample}$ with simulation parameters. The table below lists the parameters that an instance of $\\texttt{PerfForesightConsumerType}$ needs in order to successfully simulate its model using the $\\texttt{simulate}$ method.\n", + "\n", + "| Description | Code | Example value |\n", + "| :---: | --- | --- |\n", + "| Number of consumers of this type | $\\texttt{AgentCount}$ | $10000$ |\n", + "| Number of periods to simulate | $\\texttt{T_sim}$ | $120$ |\n", + "| Mean of initial log (normalized) assets | $\\texttt{aNrmInitMean}$ | $-6.0$ |\n", + "| Stdev of initial log (normalized) assets | $\\texttt{aNrmInitStd}$ | $1.0$ |\n", + "| Mean of initial log permanent income | $\\texttt{pLvlInitMean}$ | $0.0$ |\n", + "| Stdev of initial log permanent income | $\\texttt{pLvlInitStd}$ | $0.0$ |\n", + "| Aggregrate productivity growth factor | $\\texttt{PermGroFacAgg}$ | $1.0$ |\n", + "| Age after which consumers are automatically killed | $\\texttt{T_age}$ | $None$ |\n", + "\n", + "We have specified the model so that initial assets and permanent income are both distributed lognormally, with mean and standard deviation of the underlying normal distributions provided by the user.\n", + "\n", + "The parameter $\\texttt{PermGroFacAgg}$ exists for compatibility with more advanced models that employ aggregate productivity shocks; it can simply be set to 1.\n", + "\n", + "In infinite horizon models, it might be useful to prevent agents from living extraordinarily long lives through a fortuitous sequence of mortality shocks. We have thus provided the option of setting $\\texttt{T_age}$ to specify the maximum number of periods that a consumer can live before they are automatically killed (and replaced with a new consumer with initial state drawn from the specified distributions). This can be turned off by setting it to $\\texttt{None}$.\n", + "\n", + "The cell below puts these parameters into a dictionary, then gives them to $\\texttt{PFexample}$. Note that all of these parameters *could* have been passed as part of the original dictionary; we omitted them above for simplicity." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "# Create parameter values necessary for simulation\n", + "SimulationParams = {\n", + " \"AgentCount\" : 10000, # Number of agents of this type\n", + " \"T_sim\" : 120, # Number of periods to simulate\n", + " \"aNrmInitMean\" : -6.0, # Mean of log initial assets\n", + " \"aNrmInitStd\" : 1.0, # Standard deviation of log initial assets\n", + " \"pLvlInitMean\" : 0.0, # Mean of log initial permanent income\n", + " \"pLvlInitStd\" : 0.0, # Standard deviation of log initial permanent income\n", + " \"PermGroFacAgg\" : 1.0, # Aggregate permanent income growth factor\n", + " \"T_age\" : None, # Age after which simulated agents are automatically killed\n", + "}\n", + "\n", + "PFexample(**SimulationParams) # This implicitly uses the assignParameters method of AgentType" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To generate simulated data, we need to specify which variables we want to track the \"history\" of for this instance. To do so, we set the $\\texttt{track_vars}$ attribute of our $\\texttt{PerfForesightConsumerType}$ instance to be a list of strings with the simulation variables we want to track.\n", + "\n", + "In this model, valid elments of $\\texttt{track_vars}$ include $\\texttt{mNrmNow}$, $\\texttt{cNrmNow}$, $\\texttt{aNrmNow}$, and $\\texttt{pLvlNow}$. Because this model has no idiosyncratic shocks, our simulated data will be quite boring.\n", + "\n", + "### Generating simulated data\n", + "\n", + "Before simulating, the $\\texttt{initializeSim}$ method must be invoked. This resets our instance back to its initial state, drawing a set of initial $\\texttt{aNrmNow}$ and $\\texttt{pLvlNow}$ values from the specified distributions and storing them in the attributes $\\texttt{aNrmNow_init}$ and $\\texttt{pLvlNow_init}$. It also resets this instance's internal random number generator, so that the same initial states will be set every time $\\texttt{initializeSim}$ is called. In models with non-trivial shocks, this also ensures that the same sequence of shocks will be generated on every simulation run.\n", + "\n", + "Finally, the $\\texttt{simulate}$ method can be called." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [], + "source": [ + "# Create PFexample object\n", + "PFexample.track_vars = ['mNrmNow']\n", + "PFexample.initializeSim()\n", + "PFexample.simulate()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each simulation variable $\\texttt{X}$ named in $\\texttt{track_vars}$ will have the *history* of that variable for each agent stored in the attribute $\\texttt{X_hist}$ as an array of shape $(\\texttt{T_sim},\\texttt{AgentCount})$. To see that the simulation worked as intended, we can plot the mean of $m_t$ in each simulated period:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Plot market resources over time\n", + "plt.plot(np.mean(PFexample.mNrmNow_hist,axis=1))\n", + "plt.xlabel('Time')\n", + "plt.ylabel('Mean normalized market resources')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A perfect foresight consumer can borrow against the PDV of his future income-- his human wealth-- and thus as time goes on, our simulated impatient agents approach the (very negative) steady state level of $m_t$ while being steadily replaced with consumers with roughly $m_t=1$.\n", + "\n", + "The slight wiggles in the plotted curve are due to consumers randomly dying and being replaced; their replacement will have an initial state drawn from the distributions specified by the user. To see the current distribution of ages, we can look at the attribute $\\texttt{t_age}$." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the CDF\n", + "N = PFexample.AgentCount\n", + "F = np.linspace(0.,1.,N)\n", + "plt.plot(np.sort(PFexample.t_age),F)\n", + "plt.xlabel('Current age of consumers')\n", + "plt.ylabel('Cumulative distribution')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The distribution is (discretely) exponential, with a point mass at 120 with consumers who have survived since the beginning of the simulation.\n", + "\n", + "One might wonder why HARK requires users to call $\\texttt{initializeSim}$ before calling $\\texttt{simulate}$: Why doesn't $\\texttt{simulate}$ just call $\\texttt{initializeSim}$ as its first step? We have broken up these two steps so that users can simulate some number of periods, change something in the environment, and then resume the simulation.\n", + "\n", + "When called with no argument, $\\texttt{simulate}$ will simulate the model for $\\texttt{T_sim}$ periods. The user can optionally pass an integer specifying the number of periods to simulate (which should not exceed $\\texttt{T_sim}$).\n", + "\n", + "In the cell below, we simulate our perfect foresight consumers for 80 periods, then seize a bunch of their assets (dragging their wealth even more negative), then simulate for the reamining 40 periods." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "code_folding": [ + 0 + ] + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# The final resulting distribution is reasonably coherent\n", + "PFexample.initializeSim()\n", + "PFexample.simulate(80)\n", + "PFexample.aNrmNow += -5. # Adjust all simulated consumers' assets downward by 5\n", + "PFexample.simulate(40)\n", + "\n", + "plt.plot(np.mean(PFexample.mNrmNow_hist,axis=1))\n", + "plt.xlabel('Time')\n", + "plt.ylabel('Mean normalized market resources')\n", + "plt.show()" + ] + } + ], + "metadata": { + "@webio": { + "lastCommId": "779f6c5616b04b58baaaa0f6c348270c", + "lastKernelId": "a944b08f-0ae0-4c26-883f-9fab53a82ac3" + }, + "jupytext": { + "cell_metadata_filter": "collapsed,code_folding", + "formats": "ipynb,py:percent" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/ConsIndShockModel/PerfForesightConsumerType.py b/examples/ConsIndShockModel/PerfForesightConsumerType.py new file mode 100644 index 000000000..3b7eeea69 --- /dev/null +++ b/examples/ConsIndShockModel/PerfForesightConsumerType.py @@ -0,0 +1,319 @@ +# --- +# jupyter: +# jupytext: +# cell_metadata_filter: collapsed,code_folding +# formats: ipynb,py:percent +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.2' +# jupytext_version: 1.2.1 +# kernelspec: +# display_name: Python 3 +# language: python +# name: python3 +# --- + +# %% [markdown] +# # PerfForesightConsumerType + +# %% {"code_folding": [0]} +# Initial imports and notebook setup, click arrow to show +from HARK.ConsumptionSaving.ConsIndShockModel import PerfForesightConsumerType +from HARK.utilities import plotFuncs +from time import clock +import matplotlib.pyplot as plt +import numpy as np +mystr = lambda number : "{:.4f}".format(number) + +# %% [markdown] +# The module $\texttt{HARK.ConsumptionSaving.ConsIndShockModel}$ concerns consumption-saving models with idiosyncratic shocks to (non-capital) income. All of the models assume CRRA utility with geometric discounting, no bequest motive, and income shocks that are either fully transitory or fully permanent. +# +# $\texttt{ConsIndShockModel}$ currently includes three models: +# 1. A very basic "perfect foresight" model with no uncertainty (shocks are zero). +# 2. A model with risk over transitory and permanent income shocks. +# 3. The model described in (2), with an interest rate for debt that differs from the interest rate for savings. +# +# This notebook provides documentation for the first of these three models. +# $\newcommand{\CRRA}{\rho}$ +# $\newcommand{\DiePrb}{\mathsf{D}}$ +# $\newcommand{\PermGroFac}{\Gamma}$ +# $\newcommand{\Rfree}{\mathsf{R}}$ +# $\newcommand{\DiscFac}{\beta}$ + +# %% [markdown] +# ## Statement of the model +# +# The $\texttt{PerfForesightConsumerType}$ class solves the problem of a consumer with Constant Relative Risk Aversion utility +# ${\CRRA}$ +# \begin{equation} +# U(C) = \frac{C^{1-\CRRA}}{1-\rho}, +# \end{equation} +# who has perfect foresight about everything except whether he will die between the end of period $t$ and the beginning of period $t+1$. Permanent labor income $P_t$ grows from period $t$ to period $t+1$ by factor $\PermGroFac_{t+1}$. The consumer faces no artificial borrowing constraint: He is able to borrow against his entire future stream of income. +# +# At the beginning of period $t$, the consumer has market resources $M_t$ (which includes both market wealth and currrent income) and must choose how much to consume $C_t$ and how much to retain in a riskless asset $A_t$, which will earn return factor $\Rfree$. The agent's flow of future utility $U(C_{t+n})$ from consumption is geometrically discounted by factor $\DiscFac$ per period. The consumer only experiences future value if he survives, which occurs with probability $1-\DiePrb_{t+1}$. +# +# For parallelism with the treatment of more complicated problems, we write the problem rather elaborately in Bellman form as: +# +# \begin{eqnarray*} +# V_t(M_t,P_t) &=& \max_{C_t}~U(C_t) ~+ \DiscFac (1 - \DiePrb_{t+1}) V_{t+1}(M_{t+1},P_{t+1}), \\ +# & s.t. & \\ +# A_t &=& M_t - C_t, \\ +# M_{t+1} &=& \Rfree A_t + Y_{t+1}, \\ +# Y_{t+1} &=& P_{t+1}, \\ +# P_{t+1} &=& \PermGroFac_{t+1} P_t. +# \end{eqnarray*} +# +# The parameters of the consumer's problem are the coefficient of relative risk aversion $\CRRA$, the intertemporal discount factor $\DiscFac$, an interest factor $\Rfree$, and age-varying sequences of the permanent income growth factor $\PermGroFac_t$ and survival probability $(1 - \DiePrb_t)$. [These lecture notes](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA) show that under these assumptions the problem can be transformed into an equivalent problem stated in terms of *normalized* variables (represented in lower case); all real variables are divided by permanent income $P_t$ and value is divided by $P_t^{1-\CRRA}$. The Bellman form of the normalized model (see the lecture notes for details) is: +# +# \begin{eqnarray*} +# v_t(m_t) &=& \max_{c_t}~U(c_t) ~+ \DiscFac (1 - \DiePrb_{t+1}) \PermGroFac_{t+1}^{1-\CRRA} v_{t+1}(m_{t+1}), \\ +# & s.t. & \\ +# a_t &=& m_t - c_t, \\ +# m_{t+1} &=& a_t (\Rfree/\PermGroFac_{t+1} )+ 1. +# \end{eqnarray*} + +# %% [markdown] +# ## Solution method for PerfForesightConsumerType +# +# Because of the assumptions of CRRA utility, no risk other than mortality, and no artificial borrowing constraint, the problem has a closed form solution in which consumption is a linear function of resources, and the utility-inverse of the value function is also linear (that is, $u^{-1}(v)$ is linear in $m$). Details of the mathematical solution of this model can be found in the lecture notes [PerfForesightCRRA](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA). +# +# The one period problem for this model is solved by the function $\texttt{solveConsPerfForesight}$, which creates an instance of the class $\texttt{ConsPerfForesightSolver}$. To construct an instance of the class $\texttt{PerfForesightConsumerType}$, several parameters must be passed to this constructor. + +# %% [markdown] +# ## Example parameter values +# +# | Parameter | Description | Code | Example value | Time-varying? | +# | :---: | --- | --- | --- | --- | +# | $\DiscFac$ |Intertemporal discount factor | $\texttt{DiscFac}$ | $0.96$ | | +# | $\CRRA $ |Coefficient of relative risk aversion | $\texttt{CRRA}$ | $2.0$ | | +# | $\Rfree$ | Risk free interest factor | $\texttt{Rfree}$ | $1.03$ | | +# | $1 - \DiePrb_{t+1}$ |Survival probability | $\texttt{LivPrb}$ | $[0.98]$ | $\surd$ | +# |$\PermGroFac_{t+1}$|Permanent income growth factor|$\texttt{PermGroFac}$| $[1.01]$ | $\surd$ | +# |$T$| Number of periods in this type's "cycle" |$\texttt{T_cycle}$| $1$ | | +# |(none)| Number of times the "cycle" occurs |$\texttt{cycles}$| $0$ | | +# +# Note that the survival probability and income growth factor have time subscripts; likewise, the example values for these parameters are *lists* rather than simply single floats. This is because those parameters are in principle *time-varying*: their values can depend on which period of the problem the agent is in (for example, mortality probability depends on age). All time-varying parameters *must* be specified as lists, even when the model is being solved for an infinite horizon case where in practice the parameter takes the same value in every period. +# +# The last two parameters in the table specify the "nature of time" for this type: the number of (non-terminal) periods in this type's "cycle", and the number of times that the "cycle" occurs. *Every* subclass of $\texttt{AgentType}$ uses these two code parameters to define the nature of time. Here, $\texttt{T_cycle}$ has the value $1$, indicating that there is exactly one period in the cycle, while $\texttt{cycles}$ is $0$, indicating that the cycle is repeated in *infinite* number of times-- it is an infinite horizon model, with the same "kind" of period repeated over and over. +# +# In contrast, we could instead specify a life-cycle model by setting $\texttt{T_cycle}$ to $1$, and specifying age-varying sequences of income growth and survival probability. In all cases, the number of elements in each time-varying parameter should exactly equal $\texttt{T_cycle}$. +# +# The parameter $\texttt{AgentCount}$ specifies how many consumers there are of this *type*-- how many individuals have these exact parameter values and are *ex ante* homogeneous. This information is not relevant for solving the model, but is needed in order to simulate a population of agents, introducing *ex post* heterogeneity through idiosyncratic shocks. Of course, simulating a perfect foresight model is quite boring, as there are *no* idiosyncratic shocks other than death! +# +# The cell below defines a dictionary that can be passed to the constructor method for $\texttt{PerfForesightConsumerType}$, with the values from the table here. + +# %% {"code_folding": [0]} +PerfForesightDict = { + # Parameters actually used in the solution method + "CRRA" : 2.0, # Coefficient of relative risk aversion + "Rfree" : 1.03, # Interest factor on assets + "DiscFac" : 0.96, # Default intertemporal discount factor + "LivPrb" : [0.98], # Survival probability + "PermGroFac" :[1.01], # Permanent income growth factor + + # Parameters that characterize the nature of time + "T_cycle" : 1, # Number of periods in the cycle for this agent type + "cycles" : 0 # Number of times the cycle occurs (0 --> infinitely repeated) +} + +# %% [markdown] +# ## Inspecting the solution +# +# With the dictionary we have just defined, we can create an instance of $\texttt{PerfForesightConsumerType}$ by passing the dictionary to the class (as if the class were a function). This instance can then be solved by invoking its $\texttt{solve}$ method. + +# %% +PFexample = PerfForesightConsumerType(**PerfForesightDict) +PFexample.cycles = 0 +PFexample.solve() + +# %% [markdown] +# The $\texttt{solve}$ method fills in the instance's attribute $\texttt{solution}$ as a time-varying list of solutions to each period of the consumer's problem. In this case, $\texttt{solution}$ will be a list with exactly one instance of the class $\texttt{ConsumerSolution}$, representing the solution to the infinite horizon model we specified. + +# %% +print(PFexample.solution) + +# %% [markdown] +# Each element of $\texttt{solution}$ has a few attributes. To see all of them, we can use the $\texttt{vars}$ built in function: the consumption functions are instantiated in the attribute $\texttt{cFunc}$ of each element of $\texttt{ConsumerType.solution}$. This method creates a (time varying) attribute $\texttt{cFunc}$ that contains a list of consumption functions by age. + +# %% +print(vars(PFexample.solution[0])) + +# %% [markdown] +# The two most important attributes of a single period solution are the (normalized) consumption function $\texttt{cFunc}$ and the (normalized) value function $\texttt{vFunc}$; the marginal value function $\texttt{vPfunc}$ is also constructed. Let's plot those functions near the lower bound of the permissible state space (the attribute $\texttt{mNrmMin}$ tells us the lower bound of $m_t$ where the consumption function is defined). + +# %% +print('Linear perfect foresight consumption function:') +mMin = PFexample.solution[0].mNrmMin +plotFuncs(PFexample.solution[0].cFunc,mMin,mMin+10.) + +# %% +print('Perfect foresight value function:') +plotFuncs(PFexample.solution[0].vFunc,mMin+0.1,mMin+10.1) + +# %% [markdown] +# ## Solution Method +# +# +# ### Recursive Formula for $\kappa_{t}$ +# +# The paper [BufferStockTheory](https://www.econ2.jhu.edu/people/ccarroll/papers/BufferStockTheory/) has a few other results that are used in the solution code. One is [the recursive formula for the MPC](https://www.econ2.jhu.edu/people/ccarroll/papers/BufferStockTheory/#MPCnvrs). Starting with the last period, in which $\kappa_{T}=1$, the inverse MPC's (and therefore the MPC's themselves) can be constructed using the recursive formula: +# +# \begin{align} +# \kappa_{t}^{-1} & = & 1 + \kappa_{t+1}^{-1}(\Rfree \beta)^{1/\rho}/G +# \end{align} +# +# ### Consumption Function +# +# For the perfect foresight problem, there is a well-known [analytical solution]( http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA/#cFuncAnalytical) for the consumption function: Calling $o_{t}$ 'overall wealth' (including market wealth plus human wealth $h_{t}$) and designating the marginal propensity to consume in period $t$ by $\kappa_{t}$: +# +# \begin{align} +# \mathrm{c}_{t} & = o_{t}\kappa_{t} +# \end{align} +# +# and in our normalized model $o_{t} = m_{t}-1+h_{t}$ (the '-1' term subtracts off the normalized current income of 1 from market resources $m$ which were market wealth plus current income). +# +# ### Value Function +# +# A convenient feature of the perfect foresight problem is that the value function has a simple [analytical form](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA/#vFuncAnalytical): +# +# \begin{align} +# \mathrm{v}_{t} & = \mathrm{u}(\mathrm{c}_{t}(m))\kappa_{t}^{-1}\\ +# &= \mathrm{u}(o_{t} \kappa_{t}) \kappa_{t}^{-1} \\ +# &= \mathrm{u}(o_{t})\kappa_{t}^{1-\rho} \kappa_{t}^{-1} \\ +# &= \mathrm{u}(o_{t})\kappa_{t}^{-\rho} +# \end{align} +# +# This means that the utility-inverse of the value function, ${\scriptsize \Lambda} \equiv \mathrm{u}^{-1}(\mathrm{v})$, is linear: +# +# \begin{align} +# \scriptsize \Lambda_{t} & = o_{t} \kappa_{t}^{-\rho/(1-\rho)} +# \end{align} +# +# When uncertainty or liquidity constraints are added to the problem, the ${\scriptsize \Lambda}$ function is no longer linear. But even in these cases, the utility-inverse of the value function is much better behaved (e.g., closer to linear; bounded over any feasible finite range of $m$) than the uninverted function (which, for example, approaches $-\infty$ as $m$ approaches its lower bound). +# +# Our procedure will therefore generically be to construct the inverse value function, and to obtain the value function from it by uninverting. That is, we construct an interpolating approximation of $\scriptsize \Lambda_{t}$ and compute value on-the-fly from +# +# \begin{align} +# \mathrm{v}_{t}(m) & = \mathrm{u}({\scriptsize \Lambda_{t}}(m)) +# \end{align} +# +# In this case, the interpolation is exact, not an approximation: We need only two points to construct a line, so we choose the minimum possible value of normalized market resources, $\texttt{mNrmMin}$, where $o_{t}=0$ so that $c_{t}=0$, and that minimum plus 1, where the inverted value function will have the value $\kappa_{t}^{-\rho/(1-\rho)}$. From these we construct $vFuncNvrs$ as a linear interpolating function (which automatically extrapolates to the whole number line). +# +# + +# %% [markdown] +# ## Checking Solution Conditions +# +# The code performs tests for whether the supplied parameter values meet various conditions that determine the properties of the solution. Some conditions (like the Finite Human Wealth Condition) are required for the model to have a sensible solution, and if these conditions are violated the code generates a warning message. Other conditions govern characteristics of the model like whether consumption is falling (whether the consumer is 'absolutely impatient'). All conditions can manually be performed using the syntax below. The function returns "False" if none of the key conditions has been violated. + +# %% +PFexample.checkConditions(verbose=True,public_call=True) + +# %% [markdown] +# An element of $\texttt{solution}$ also includes the (normalized) marginal value function $\texttt{vPfunc}$, and the lower and upper bounds of the marginal propensity to consume (MPC) $\texttt{MPCmin}$ and $\texttt{MPCmax}$. Note that with a linear consumption function, the MPC is constant, so its lower and upper bound are identical. + +# %% [markdown] +# ## Simulating the model +# +# Suppose we wanted to simulate many consumers who share the parameter values that we passed to $\texttt{PerfForesightConsumerType}$-- an *ex ante* homogeneous *type* of consumers. To do this, our instance would have to know *how many* agents there are of this type, as well as their initial levels of assets $a_t$ and permanent income $P_t$. +# +# ### Setting Parameters +# +# Let's fill in this information by passing another dictionary to $\texttt{PFexample}$ with simulation parameters. The table below lists the parameters that an instance of $\texttt{PerfForesightConsumerType}$ needs in order to successfully simulate its model using the $\texttt{simulate}$ method. +# +# | Description | Code | Example value | +# | :---: | --- | --- | +# | Number of consumers of this type | $\texttt{AgentCount}$ | $10000$ | +# | Number of periods to simulate | $\texttt{T_sim}$ | $120$ | +# | Mean of initial log (normalized) assets | $\texttt{aNrmInitMean}$ | $-6.0$ | +# | Stdev of initial log (normalized) assets | $\texttt{aNrmInitStd}$ | $1.0$ | +# | Mean of initial log permanent income | $\texttt{pLvlInitMean}$ | $0.0$ | +# | Stdev of initial log permanent income | $\texttt{pLvlInitStd}$ | $0.0$ | +# | Aggregrate productivity growth factor | $\texttt{PermGroFacAgg}$ | $1.0$ | +# | Age after which consumers are automatically killed | $\texttt{T_age}$ | $None$ | +# +# We have specified the model so that initial assets and permanent income are both distributed lognormally, with mean and standard deviation of the underlying normal distributions provided by the user. +# +# The parameter $\texttt{PermGroFacAgg}$ exists for compatibility with more advanced models that employ aggregate productivity shocks; it can simply be set to 1. +# +# In infinite horizon models, it might be useful to prevent agents from living extraordinarily long lives through a fortuitous sequence of mortality shocks. We have thus provided the option of setting $\texttt{T_age}$ to specify the maximum number of periods that a consumer can live before they are automatically killed (and replaced with a new consumer with initial state drawn from the specified distributions). This can be turned off by setting it to $\texttt{None}$. +# +# The cell below puts these parameters into a dictionary, then gives them to $\texttt{PFexample}$. Note that all of these parameters *could* have been passed as part of the original dictionary; we omitted them above for simplicity. + +# %% {"code_folding": [0]} +# Create parameter values necessary for simulation +SimulationParams = { + "AgentCount" : 10000, # Number of agents of this type + "T_sim" : 120, # Number of periods to simulate + "aNrmInitMean" : -6.0, # Mean of log initial assets + "aNrmInitStd" : 1.0, # Standard deviation of log initial assets + "pLvlInitMean" : 0.0, # Mean of log initial permanent income + "pLvlInitStd" : 0.0, # Standard deviation of log initial permanent income + "PermGroFacAgg" : 1.0, # Aggregate permanent income growth factor + "T_age" : None, # Age after which simulated agents are automatically killed +} + +PFexample(**SimulationParams) # This implicitly uses the assignParameters method of AgentType + +# %% [markdown] +# To generate simulated data, we need to specify which variables we want to track the "history" of for this instance. To do so, we set the $\texttt{track_vars}$ attribute of our $\texttt{PerfForesightConsumerType}$ instance to be a list of strings with the simulation variables we want to track. +# +# In this model, valid elments of $\texttt{track_vars}$ include $\texttt{mNrmNow}$, $\texttt{cNrmNow}$, $\texttt{aNrmNow}$, and $\texttt{pLvlNow}$. Because this model has no idiosyncratic shocks, our simulated data will be quite boring. +# +# ### Generating simulated data +# +# Before simulating, the $\texttt{initializeSim}$ method must be invoked. This resets our instance back to its initial state, drawing a set of initial $\texttt{aNrmNow}$ and $\texttt{pLvlNow}$ values from the specified distributions and storing them in the attributes $\texttt{aNrmNow_init}$ and $\texttt{pLvlNow_init}$. It also resets this instance's internal random number generator, so that the same initial states will be set every time $\texttt{initializeSim}$ is called. In models with non-trivial shocks, this also ensures that the same sequence of shocks will be generated on every simulation run. +# +# Finally, the $\texttt{simulate}$ method can be called. + +# %% {"code_folding": [0]} +# Create PFexample object +PFexample.track_vars = ['mNrmNow'] +PFexample.initializeSim() +PFexample.simulate() + +# %% [markdown] +# Each simulation variable $\texttt{X}$ named in $\texttt{track_vars}$ will have the *history* of that variable for each agent stored in the attribute $\texttt{X_hist}$ as an array of shape $(\texttt{T_sim},\texttt{AgentCount})$. To see that the simulation worked as intended, we can plot the mean of $m_t$ in each simulated period: + +# %% {"code_folding": [0]} +# Plot market resources over time +plt.plot(np.mean(PFexample.mNrmNow_hist,axis=1)) +plt.xlabel('Time') +plt.ylabel('Mean normalized market resources') +plt.show() + +# %% [markdown] +# A perfect foresight consumer can borrow against the PDV of his future income-- his human wealth-- and thus as time goes on, our simulated impatient agents approach the (very negative) steady state level of $m_t$ while being steadily replaced with consumers with roughly $m_t=1$. +# +# The slight wiggles in the plotted curve are due to consumers randomly dying and being replaced; their replacement will have an initial state drawn from the distributions specified by the user. To see the current distribution of ages, we can look at the attribute $\texttt{t_age}$. + +# %% {"code_folding": [0]} +# Plot the CDF +N = PFexample.AgentCount +F = np.linspace(0.,1.,N) +plt.plot(np.sort(PFexample.t_age),F) +plt.xlabel('Current age of consumers') +plt.ylabel('Cumulative distribution') +plt.show() + +# %% [markdown] +# The distribution is (discretely) exponential, with a point mass at 120 with consumers who have survived since the beginning of the simulation. +# +# One might wonder why HARK requires users to call $\texttt{initializeSim}$ before calling $\texttt{simulate}$: Why doesn't $\texttt{simulate}$ just call $\texttt{initializeSim}$ as its first step? We have broken up these two steps so that users can simulate some number of periods, change something in the environment, and then resume the simulation. +# +# When called with no argument, $\texttt{simulate}$ will simulate the model for $\texttt{T_sim}$ periods. The user can optionally pass an integer specifying the number of periods to simulate (which should not exceed $\texttt{T_sim}$). +# +# In the cell below, we simulate our perfect foresight consumers for 80 periods, then seize a bunch of their assets (dragging their wealth even more negative), then simulate for the reamining 40 periods. + +# %% {"code_folding": [0]} +# The final resulting distribution is reasonably coherent +PFexample.initializeSim() +PFexample.simulate(80) +PFexample.aNrmNow += -5. # Adjust all simulated consumers' assets downward by 5 +PFexample.simulate(40) + +plt.plot(np.mean(PFexample.mNrmNow_hist,axis=1)) +plt.xlabel('Time') +plt.ylabel('Mean normalized market resources') +plt.show() diff --git a/examples/GenIncProcessModel/GenIncProcessModel.ipynb b/examples/GenIncProcessModel/GenIncProcessModel.ipynb new file mode 100644 index 000000000..503dcddf6 --- /dev/null +++ b/examples/GenIncProcessModel/GenIncProcessModel.ipynb @@ -0,0 +1,539 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Permanent versus Persistent Income Shocks\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ], + "collapsed": true + }, + "outputs": [], + "source": [ + "# Initial imports and notebook setup\n", + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import sys\n", + "import os\n", + "from copy import copy\n", + "from HARK.utilities import plotFuncs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from HARK.ConsumptionSaving.ConsGenIncProcessModel import *\n", + "import HARK.ConsumptionSaving.ConsumerParameters as Params" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`ConsIndShockModel` assumes that income has a permanent component $p$ which is subject to \"permanent\" shocks:\n", + "\n", + " $\\log p_{t+1} = \\log p_{t} + \\log \\psi_{t+1}$\n", + "\n", + "Many papers in the literature instead examine models in which shocks merely have some persistence,\n", + "\n", + "$\\log p_{t+1} = \\gamma \\log p_{t} + \\log \\psi_{t+1}$\n", + "\n", + "where if $0 < \\gamma < 1$ then $\\lim_{n \\uparrow \\infty} \\mathbb{E}_{t}[\\log p_{t+n}]=0$ (which means that the level of $p$ reverts to its mean of $p=1$. The two models become identical as $\\gamma$ approaches 1.\n", + "\n", + "This notebook describes HARK's tools to solve models with persistent shocks.\n", + "\n", + "1. `ConsGenIncProcessModel` extends `ConsIndShockModel` by explicitly tracking persistent income $p_t$ as a state variable.\n", + "1. `IndShockExplicitPermIncConsumerType` is a type of consumer created for comparison and for whom we know for sure that their income process is one in which $\\gamma=1$\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## General Income Process model\n", + "In `ConsGenIncProcessModel` the user can define a generic function $G$ that translates current $p_{t}$ into expected next period persistent income $p_{t+1}$ (subject to shocks). \n", + "\n", + "\n", + "The agent's problem can be written in Bellman form as:\n", + "\n", + "\\begin{eqnarray*}\n", + "v_t(M_t,p_t) &=& \\max_{c_t} U(c_t) + \\beta (1-\\mathsf{D}_{t+1}) \\mathbb{E}_{t} [v_{t+1}(M_{t+1}, p_{t+1}) ], \\\\\n", + "a_t &=& M_t - c_t, \\\\\n", + "a_t &\\geq& \\underline{a}, \\\\\n", + "M_{t+1} &=& R a_t + \\theta_{t+1}, \\\\\n", + "p_{t+1} &=& G_{t+1}(p_t)\\psi_{t+1}, \\\\\n", + "\\psi_t \\sim F_{\\psi t} &\\qquad& \\theta_t \\sim F_{\\theta t} \\\\\n", + " \\mathbb{E} [F_{\\psi t}] = 1 & & \\mathbb{E} [F_{\\psi t}] =1 \\\\\n", + "U(c) &=& \\frac{c^{1-\\rho}}{1-\\rho}.\n", + "\\end{eqnarray*}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The one-period problem for this model is solved by the function $\\texttt{solveConsGenIncProcess}$, which creates an instance of the class $\\texttt{ConsGenIncProcessSolver}$. The class $\\texttt{GenIncProcessConsumerType}$ extends $\\texttt{IndShockConsumerType}$ to represent agents in this model. To construct an instance of this class, several parameters must be passed to the constructor, as shown in the table below (parameters can be either \"primitive\" or \"constructed\" if they have already built-in capabilities from previous models).\n", + "\n", + "### Example parameter values to solve GenIncProcess model\n", + "\n", + "| Param | Description | Code | Value | Constructed |\n", + "| :---: | --- | --- | --- | :---: |\n", + "| $\\beta$ |Intertemporal discount factor | $\\texttt{DiscFac}$ | 0.96 | |\n", + "| $\\rho $ |Coefficient of relative risk aversion | $\\texttt{CRRA}$ | 2.0 | |\n", + "| $R $ | Risk free interest factor | $\\texttt{Rfree}$ | 1.03 | |\n", + "| $1 - \\mathsf{D}$ |Survival probability | $\\texttt{LivPrb}$ | [0.98] | |\n", + "| $\\underline{a} $ |Artificial borrowing constraint | $\\texttt{BoroCnstArt}$ | 0.0 | | \n", + "| $(none) $ |Indicator of whether $\\texttt{vFunc}$ should be computed | $\\texttt{vFuncBool}$ | 'True' | |\n", + "| $(none)$ |Indicator of whether $\\texttt{cFunc}$ should use cubic lines | $\\texttt{CubicBool}$ | 'False' | |\n", + "|$F $ |A list containing three arrays of floats, representing a discrete
approximation to the income process:
event probabilities, persistent shocks, transitory shocks | $\\texttt{IncomeDstn}$ | - |$\\surd$ |\n", + "| $G$ |Expected persistent income next period | $\\texttt{pLvlNextFunc}$ | - | $\\surd$ |\n", + "| $ (none) $ |Array of time-varying persistent income levels | $\\texttt{pLvlGrid}$ | - |$\\surd$ |\n", + "| $ (none) $ | Array of \"extra\" end-of-period asset values | $\\texttt{aXtraGrid}$ | - |$\\surd$ |\n", + "\n", + "### Constructed inputs to solve GenIncProcess\n", + "The \"constructed\" inputs above are using expected attributes and are drawn on various methods as explained below.\n", + "\n", + "\n", + "* The input $\\texttt{IncomeDstn}$ is created by the method $\\texttt{updateIncomeProcess}$ which inherits from $\\texttt{IndShockConsumerType}$. (*hyperlink to that noteboook*)\n", + "\n", + "* The input $\\texttt{pLvlNextFunc}$ is created by the method $\\texttt{updatepLvlNextFunc}$ which uses the initial sequence of $\\texttt{pLvlNextFunc}$, the mean and standard deviation of the (log) initial permanent income, $\\texttt{pLvlInitMean}$ and $\\texttt{pLvlInitStd}$. \n", + "In this model, the method creates a trivial $\\texttt{pLvlNextFunc}$ attribute with no persistent income dynamics. But we can overwrite it by subclasses in order to make an AR1 income process for example. \n", + "\n", + "\n", + "* The input $\\texttt{pLvlGrid}$ is created by the method $\\texttt{updatepLvlGrid}$ which updates the grid of persistent income levels for infinite horizon models (cycles=0) and lifecycle models (cycles=1). This method draws on the initial distribution of persistent income, the $\\texttt{pLvlNextFuncs}$, $\\texttt{pLvlInitMean}$, $\\texttt{pLvlInitStd}$ and the attribute $\\texttt{pLvlPctiles}$ (percentiles of the distribution of persistent income). It then uses a simulation approach to generate the $\\texttt{pLvlGrid}$ at each period of the cycle.\n", + "\n", + "\n", + "* The input $\\texttt{aXtraGrid}$ is created by $\\texttt{updateAssetsGrid}$ which updates the agent's end-of-period assets grid by constructing a multi-exponentially spaced grid of aXtra values, based on $\\texttt{aNrmInitMean}$ and $\\texttt{aNrmInitStd}$. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Consumer with Explicit Permanent Income\n", + "\n", + "Let's make an example of our generic model above with an \"explicit permanent income\" consumer who experiences idiosyncratic shocks to permanent and transitory, and faces permanent income growth.\n", + "\n", + "The agent's problem can be written in Bellman form as:\n", + "\n", + "\\begin{eqnarray*}\n", + "v_t(M_t,p_t) &=& \\max_{c_t} U(c_t) + \\beta (1-\\mathsf{D}_{t+1}) \\mathbb{E} [v_{t+1}(M_{t+1}, p_{t+1}) ], \\\\\n", + "a_t &=& M_t - c_t, \\\\\n", + "a_t &\\geq& \\underline{a}, \\\\\n", + "M_{t+1} &=& R/(\\Gamma_{t+1} \\psi_{t+1}) a_t + \\theta_{t+1}, \\\\\n", + "p_{t+1} &=& G_{t+1}(p_t)\\psi_{t+1}, \\\\\n", + "\\psi \\sim F_{\\psi}, \\mathbb{E} [F_{\\psi t}] = 1 &\\qquad& \\theta_t \\sim F_{\\theta}, \\mathbb{E} [F_{\\psi}] = 1, \\\\\n", + "U(c) &=& \\frac{c^{1-\\rho}}{1-\\rho}.\n", + "\\end{eqnarray*}\n", + "\n", + "\n", + "This agent type is identical to an $\\texttt{IndShockConsumerType}$ but for explicitly tracking $\\texttt{pLvl}$ as a state variable during solution as shown in the mathematical representation of GenIncProcess model. \n", + "\n", + "To construct $\\texttt{IndShockExplicitPermIncConsumerType}$ as an instance of $\\texttt{GenIncProcessConsumerType}$, we need to pass additional parameters to the constructor as shown in the table below.\n", + "\n", + "### Additional parameters to solve ExplicitPermInc model\n", + "\n", + "| Param | Description | Code | Value | Constructed |\n", + "| :---: | --- | --- | --- | :---: |\n", + "|(none)|percentiles of the distribution of persistent income|$\\texttt{pLvlPctiles}$|||\n", + "| $G$ |Expected persistent income next period | $\\texttt{pLvlNextFunc}$ | - | $\\surd$ |\n", + "|$\\Gamma $|Permanent income growth factor|$\\texttt{PermGroFac}$|[1.0]| |\n", + "\n", + "\n", + "### Constructed inputs to solve ExplicitPermInc\n", + "\n", + "* In this \"explicit permanent income\" model, we overwrite the method $\\texttt{updatepLvlNextFunc}$ to create $\\texttt{pLvlNextFunc}$ as a sequence of linear functions, indicating constant expected permanent income growth across permanent income levels. This method uses the attribute $\\texttt{PermGroFac}$, and installs a special retirement function when it exists.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ], + "collapsed": true + }, + "outputs": [], + "source": [ + "# This cell defines a dictionary to make an instance of \"explicit permanent income\" consumer.\n", + "GenIncDictionary = { \n", + " \"CRRA\": 2.0, # Coefficient of relative risk aversion\n", + " \"Rfree\": 1.03, # Interest factor on assets\n", + " \"DiscFac\": 0.96, # Intertemporal discount factor\n", + " \"LivPrb\" : [0.98], # Survival probability\n", + " \"AgentCount\" : 10000, # Number of agents of this type (only matters for simulation)\n", + " \"aNrmInitMean\" : 0.0, # Mean of log initial assets (only matters for simulation)\n", + " \"aNrmInitStd\" : 1.0, # Standard deviation of log initial assets (only for simulation)\n", + " \"pLvlInitMean\" : 0.0, # Mean of log initial permanent income (only matters for simulation)\n", + " \"pLvlInitStd\" : 0.0, # Standard deviation of log initial permanent income (only matters for simulation)\n", + " \"PermGroFacAgg\" : 1.0, # Aggregate permanent income growth factor (only matters for simulation)\n", + " \"T_age\" : None, # Age after which simulated agents are automatically killed\n", + " \"T_cycle\" : 1, # Number of periods in the cycle for this agent type\n", + "# Parameters for constructing the \"assets above minimum\" grid\n", + " \"aXtraMin\" : 0.001, # Minimum end-of-period \"assets above minimum\" value\n", + " \"aXtraMax\" : 30, # Maximum end-of-period \"assets above minimum\" value \n", + " \"aXtraExtra\" : [0.005,0.01], # Some other value of \"assets above minimum\" to add to the grid\n", + " \"aXtraNestFac\" : 3, # Exponential nesting factor when constructing \"assets above minimum\" grid\n", + " \"aXtraCount\" : 48, # Number of points in the grid of \"assets above minimum\"\n", + "# Parameters describing the income process\n", + " \"PermShkCount\" : 7, # Number of points in discrete approximation to permanent income shocks\n", + " \"TranShkCount\" : 7, # Number of points in discrete approximation to transitory income shocks\n", + " \"PermShkStd\" : [0.1], # Standard deviation of log permanent income shocks\n", + " \"TranShkStd\" : [0.1], # Standard deviation of log transitory income shocks\n", + " \"UnempPrb\" : 0.05, # Probability of unemployment while working\n", + " \"UnempPrbRet\" : 0.005, # Probability of \"unemployment\" while retired\n", + " \"IncUnemp\" : 0.3, # Unemployment benefits replacement rate\n", + " \"IncUnempRet\" : 0.0, # \"Unemployment\" benefits when retired\n", + " \"tax_rate\" : 0.0, # Flat income tax rate\n", + " \"T_retire\" : 0, # Period of retirement (0 --> no retirement)\n", + " \"BoroCnstArt\" : 0.0, # Artificial borrowing constraint; imposed minimum level of end-of period assets\n", + " \"CubicBool\" : False, # Use cubic spline interpolation when True, linear interpolation when False\n", + " \"vFuncBool\" : True, # Whether to calculate the value function during solution \n", + "# More parameters specific to \"Explicit Permanent income\" shock model\n", + " \"cycles\": 0,\n", + " \"pLvlPctiles\" : np.concatenate(([0.001, 0.005, 0.01, 0.03], np.linspace(0.05, 0.95, num=19),[0.97, 0.99, 0.995, 0.999])),\n", + " \"PermGroFac\" : [1.0], # Permanent income growth factor - long run permanent income growth doesn't work yet \n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's now create an instance of the type of consumer we are interested in and solve this agent's problem with an infinite horizon (cycles=0)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Make and solve an example \"explicit permanent income\" consumer with idiosyncratic shocks\n", + "ExplicitExample = IndShockExplicitPermIncConsumerType(**GenIncDictionary)\n", + " \n", + "print('Here, the lowest percentile is ' + str(GenIncDictionary['pLvlPctiles'][0]*100))\n", + "print('and the highest percentile is ' + str(GenIncDictionary['pLvlPctiles'][-1]*100) + '.\\n')\n", + " \n", + "ExplicitExample.solve()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the cell below, we generate a plot of the consumption function for explicit permanent income consumer at different income levels." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ], + "collapsed": true + }, + "outputs": [], + "source": [ + "# Plot the consumption function at various permanent income levels.\n", + "print('Consumption function by pLvl for explicit permanent income consumer:')\n", + "pLvlGrid = ExplicitExample.pLvlGrid[0]\n", + "mLvlGrid = np.linspace(0,20,300)\n", + "for p in pLvlGrid:\n", + " M_temp = mLvlGrid + ExplicitExample.solution[0].mLvlMin(p)\n", + " C = ExplicitExample.solution[0].cFunc(M_temp,p*np.ones_like(M_temp))\n", + " plt.plot(M_temp,C)\n", + "plt.xlim(0.,20.)\n", + "plt.xlabel('Market resource level mLvl')\n", + "plt.ylabel('Consumption level cLvl')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Permanent income normalized\n", + "\n", + "An alternative model is to normalize it by dividing all variables by permanent income $p_t$ and solve the model again." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Make and solve an example of normalized model\n", + "NormalizedExample = IndShockConsumerType(**GenIncDictionary)\n", + "NormalizedExample.solve()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Compare the normalized problem with and without explicit permanent income and plot the consumption functions\n", + "print('Normalized consumption function by pLvl for explicit permanent income consumer:')\n", + "pLvlGrid = ExplicitExample.pLvlGrid[0]\n", + "mNrmGrid = np.linspace(0,20,300)\n", + "for p in pLvlGrid:\n", + " M_temp = mNrmGrid*p + ExplicitExample.solution[0].mLvlMin(p)\n", + " C = ExplicitExample.solution[0].cFunc(M_temp,p*np.ones_like(M_temp))\n", + " plt.plot(M_temp/p,C/p)\n", + "\n", + "plt.xlim(0.,20.)\n", + "plt.xlabel('Normalized market resources mNrm')\n", + "plt.ylabel('Normalized consumption cNrm')\n", + "plt.show()\n", + "\n", + "print('Consumption function for normalized problem (without explicit permanent income):')\n", + "mNrmMin = NormalizedExample.solution[0].mNrmMin\n", + "plotFuncs(NormalizedExample.solution[0].cFunc,mNrmMin,mNrmMin+20.)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "The figures above show that the normalized consumption function for the \"explicit permanent income\" consumer is almost identical for every permanent income level (and the same as the normalized problem's $\\texttt{cFunc}$), but is less accurate due to extrapolation outside the bounds of $\\texttt{pLvlGrid}$. \n", + "\n", + "The \"explicit permanent income\" solution deviates from the solution to the normalized problem because of errors from extrapolating beyond the bounds of the $\\texttt{pLvlGrid}$. The error is largest for $\\texttt{pLvl}$ values near the upper and lower bounds, and propagates toward the center of the distribution.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Plot the value function at various permanent income levels\n", + "if ExplicitExample.vFuncBool:\n", + " pGrid = np.linspace(0.1,3.0,24)\n", + " M = np.linspace(0.001,5,300)\n", + " for p in pGrid:\n", + " M_temp = M+ExplicitExample.solution[0].mLvlMin(p)\n", + " C = ExplicitExample.solution[0].vFunc(M_temp,p*np.ones_like(M_temp))\n", + " plt.plot(M_temp,C)\n", + " plt.ylim([-200,0])\n", + " plt.xlabel('Market resource level mLvl')\n", + " plt.ylabel('Value v')\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Simulate many periods to get to the stationary distribution\n", + "ExplicitExample.T_sim = 500\n", + "ExplicitExample.track_vars = ['mLvlNow','cLvlNow','pLvlNow']\n", + "ExplicitExample.initializeSim()\n", + "ExplicitExample.simulate()\n", + "plt.plot(np.mean(ExplicitExample.mLvlNow_hist,axis=1))\n", + "plt.xlabel('Simulated time period')\n", + "plt.ylabel('Average market resources mLvl')\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## 2. Persistent income shock consumer\n", + "\n", + "\n", + "Class to solve consumption-saving models with idiosyncratic shocks to income in which shocks are persistent and transitory. This model extends $\\texttt{ConsGenIndShockModel}$ by allowing (log) persistent income to follow an AR(1) process.\n", + "\n", + "The agent's problem can be written in Bellman form as:\n", + "\n", + "\\begin{eqnarray*}\n", + "v_t(M_t,p_t) &=& \\max_{c_t} U(c_t) + \\beta (1-\\mathsf{D}_{t+1}) \\mathbb{E} [v_{t+1}(M_{t+1}, p_{t+1}) ], \\\\\n", + "a_t &=& M_t - c_t, \\\\\n", + "a_t &\\geq& \\underline{a}, \\\\\n", + "M_{t+1} &=& R a_t + \\theta_{t+1}, \\\\\n", + "log(p_{t+1}) &=& \\varphi log(p_t)+(1-\\varphi log(\\overline{p}_{t+1} ) +log(\\Gamma_{t+1})+log(\\psi_{t+1}), \\\\\n", + "\\\\\n", + "\\psi_t \\sim F_{\\psi t} &\\qquad& \\theta_t \\sim F_{\\theta t}, \\mathbb{E} [F_{\\psi t}] = 1 \\\\\n", + "\\end{eqnarray*}\n", + "\n", + "### Additional parameters to solve PersistentShock model\n", + "\n", + "| Param | Description | Code | Value | Constructed |\n", + "| :---: | --- | --- | --- | :---: |\n", + "|$\\varphi$|Serial correlation coefficient for permanent income|$\\texttt{PrstIncCorr}$|0.98||\n", + "||||||\n", + "\n", + "### Constructed inputs to solve PersistentShock\n", + "\n", + "* For this model, we overwrite the method $\\texttt{updatepLvlNextFunc}$ to create the input $\\texttt{pLvlNextFunc}$ as a sequence of AR1-style functions. The method uses now the attributes $\\texttt{PermGroFac}$ and $\\texttt{PrstIncCorr}$. If cycles=0, the product of $\\texttt{PermGroFac}$ across all periods must be 1.0, otherwise this method is invalid.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [ + 0 + ], + "collapsed": true + }, + "outputs": [], + "source": [ + "# Make a dictionary for the \"persistent idiosyncratic shocks\" model\n", + "PrstIncCorr = 0.98 # Serial correlation coefficient for persistent income\n", + "\n", + "persistent_shocks = copy(GenIncDictionary)\n", + "persistent_shocks['PrstIncCorr'] = PrstIncCorr\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "The $\\texttt{PersistentShockConsumerType}$ class solves the problem of a consumer facing idiosyncratic shocks to his persistent and transitory income, and for which the (log) persistent income follows an AR1 process rather than random walk." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Make and solve an example of \"persistent idisyncratic shocks\" consumer\n", + "PersistentExample = PersistentShockConsumerType(**persistent_shocks)\n", + "PersistentExample.solve()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Plot the consumption function at various levels of persistent income pLvl\n", + "print('Consumption function by persistent income level pLvl for a consumer with AR1 coefficient of ' + str(PersistentExample.PrstIncCorr) + ':')\n", + "pLvlGrid = PersistentExample.pLvlGrid[0]\n", + "mLvlGrid = np.linspace(0,20,300)\n", + "for p in pLvlGrid:\n", + " M_temp = mLvlGrid + PersistentExample.solution[0].mLvlMin(p)\n", + " C = PersistentExample.solution[0].cFunc(M_temp,p*np.ones_like(M_temp))\n", + " plt.plot(M_temp,C)\n", + "plt.xlim(0.,20.)\n", + "plt.xlabel('Market resource level mLvl')\n", + "plt.ylabel('Consumption level cLvl')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Plot the value function at various persistent income levels\n", + "if PersistentExample.vFuncBool:\n", + " pGrid = PersistentExample.pLvlGrid[0]\n", + " M = np.linspace(0.001,5,300)\n", + " for p in pGrid:\n", + " M_temp = M+PersistentExample.solution[0].mLvlMin(p)\n", + " C = PersistentExample.solution[0].vFunc(M_temp,p*np.ones_like(M_temp))\n", + " plt.plot(M_temp,C)\n", + " plt.ylim([-200,0])\n", + " plt.xlabel('Market resource level mLvl')\n", + " plt.ylabel('Value v')\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Simulate some data\n", + "PersistentExample.T_sim = 500\n", + "PersistentExample.track_vars = ['mLvlNow','cLvlNow','pLvlNow']\n", + "PersistentExample.initializeSim()\n", + "PersistentExample.simulate()\n", + "plt.plot(np.mean(PersistentExample.mLvlNow_hist,axis=1))\n", + "plt.xlabel('Simulated time period')\n", + "plt.ylabel('Average market resources mLvl')\n", + "plt.show()" + ] + } + ], + "metadata": { + "jupytext": { + "formats": "ipynb,py", + "metadata_filter": {"cells": "collapsed"} + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/Gentle-Intro/Gentle-Intro-To-HARK.ipynb b/examples/Gentle-Intro/Gentle-Intro-To-HARK.ipynb new file mode 100644 index 000000000..4f90992c9 --- /dev/null +++ b/examples/Gentle-Intro/Gentle-Intro-To-HARK.ipynb @@ -0,0 +1,576 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# A Gentle Introduction to HARK\n", + "\n", + "This notebook provides a simple, hands-on tutorial for first time HARK users -- and potentially first time Python users. It does not go \"into the weeds\" - we have hidden some code cells that do boring things that you don't need to digest on your first experience with HARK. Our aim is to convey a feel for how the toolkit works.\n", + "\n", + "For readers for whom this is your very first experience with Python, we have put important Python concepts in **boldface**. For those for whom this is the first time they have used a Jupyter notebook, we have put Jupyter instructions in _italics_. Only cursory definitions (if any) are provided here. If you want to learn more, there are many online Python and Jupyter tutorials." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [] + }, + "outputs": [], + "source": [ + "# This cell has a bit of initial setup. You can click the triangle to the left to expand it.\n", + "# Click the \"Run\" button immediately above the notebook in order to execute the contents of any cell\n", + "# WARNING: Each cell in the notebook relies upon results generated by previous cells\n", + "# The most common problem beginners have is to execute a cell before all its predecessors\n", + "# If you do this, you can restart the kernel (see the \"Kernel\" menu above) and start over\n", + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "from tqdm import tqdm\n", + "import numpy as np\n", + "import HARK \n", + "from time import clock\n", + "from copy import deepcopy\n", + "mystr = lambda number : \"{:.4f}\".format(number)\n", + "from HARK.utilities import plotFuncs" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Your First HARK Model: Perfect Foresight\n", + "\n", + "$$\\newcommand{\\CRRA}{\\rho}\\newcommand{\\DiscFac}{\\beta}$$\n", + "We start with almost the simplest possible consumption model: A consumer with CRRA utility \n", + "\n", + "\\begin{equation}\n", + "U(C) = \\frac{C^{1-\\CRRA}}{1-\\rho}\n", + "\\end{equation}\n", + "\n", + "has perfect foresight about everything except the (stochastic) date of death, which occurs with constant probability implying a \"survival probability\" $\\newcommand{\\LivPrb}{\\aleph}\\LivPrb < 1$. Permanent labor income $P_t$ grows from period to period by a factor $\\Gamma_t$. At the beginning of each period $t$, the consumer has some amount of market resources $M_t$ (which includes both market wealth and currrent income) and must choose how much of those resources to consume $C_t$ and how much to retain in a riskless asset $A_t$ which will earn return factor $R$. The agent's flow of utility $U(C_t)$ from consumption is geometrically discounted by factor $\\beta$. Between periods, the agent dies with probability $\\mathsf{D}_t$, ending his problem.\n", + "\n", + "The agent's problem can be written in Bellman form as:\n", + "\n", + "\\begin{eqnarray*}\n", + "V_t(M_t,P_t) &=& \\max_{C_t}~U(C_t) + \\beta \\aleph V_{t+1}(M_{t+1},P_{t+1}), \\\\\n", + "& s.t. & \\\\\n", + "%A_t &=& M_t - C_t, \\\\\n", + "M_{t+1} &=& R (M_{t}-C_{t}) + Y_{t+1}, \\\\\n", + "P_{t+1} &=& \\Gamma_{t+1} P_t, \\\\\n", + "\\end{eqnarray*}\n", + "\n", + "A particular perfect foresight agent's problem can be characterized by values of risk aversion $\\rho$, discount factor $\\beta$, and return factor $R$, along with sequences of income growth factors $\\{ \\Gamma_t \\}$ and survival probabilities $\\{\\mathsf{\\aleph}_t\\}$. To keep things simple, let's forget about \"sequences\" of income growth and mortality, and just think about an $\\textit{infinite horizon}$ consumer with constant income growth and survival probability.\n", + "\n", + "## Representing Agents in HARK\n", + "\n", + "HARK represents agents solving this type of problem as $\\textbf{instances}$ of the $\\textbf{class}$ $\\texttt{PerfForesightConsumerType}$, a $\\textbf{subclass}$ of $\\texttt{AgentType}$. To make agents of this class, we must import the class itself into our workspace. (Run the cell below in order to do this)." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from HARK.ConsumptionSaving.ConsIndShockModel import PerfForesightConsumerType" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The $\\texttt{PerfForesightConsumerType}$ class contains within itself the python code that constructs the solution for the perfect foresight model we are studying here, as specifically articulated in [these lecture notes](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA/). \n", + "\n", + "To create an instance of $\\texttt{PerfForesightConsumerType}$, we simply call the class as if it were a function, passing as arguments the specific parameter values we want it to have. In the hidden cell below, we define a $\\textbf{dictionary}$ named $\\texttt{PF_dictionary}$ with these parameter values:\n", + "\n", + "| Param | Description | Code | Value |\n", + "| :---: | --- | --- | :---: |\n", + "| $\\rho$ | Relative risk aversion | $\\texttt{CRRA}$ | 2.5 |\n", + "| $\\beta$ | Discount factor | $\\texttt{DiscFac}$ | 0.96 |\n", + "| $R$ | Risk free interest factor | $\\texttt{Rfree}$ | 1.03 |\n", + "| $\\newcommand{\\LivFac}{\\aleph}\\LivFac$ | Survival probability | $\\texttt{LivPrb}$ | 0.98 |\n", + "| $\\Gamma$ | Income growth factor | $\\texttt{PermGroFac}$ | 1.01 |\n", + "\n", + "\n", + "For now, don't worry about the specifics of dictionaries. All you need to know is that a dictionary lets us pass many arguments wrapped up in one simple data structure." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "code_folding": [] + }, + "outputs": [], + "source": [ + "# This cell defines a parameter dictionary. You can expand it if you want to see what that looks like.\n", + "PF_dictionary = {\n", + " 'CRRA' : 2.5,\n", + " 'DiscFac' : 0.96,\n", + " 'Rfree' : 1.03,\n", + " 'LivPrb' : [0.98],\n", + " 'PermGroFac' : [1.01],\n", + " 'T_cycle' : 1,\n", + " 'cycles' : 0,\n", + " 'AgentCount' : 10000\n", + "}\n", + "\n", + "# To those curious enough to open this hidden cell, you might notice that we defined\n", + "# a few extra parameters in that dictionary: T_cycle, cycles, and AgentCount. Don't\n", + "# worry about these for now." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's make an **object** named $\\texttt{PFexample}$ which is an **instance** of the $\\texttt{PerfForesightConsumerType}$ class. The object $\\texttt{PFexample}$ will bundle together the abstract mathematical description of the solution embodied in $\\texttt{PerfForesightConsumerType}$, and the specific set of parameter values defined in $\\texttt{PF_dictionary}$. Such a bundle is created passing $\\texttt{PF_dictionary}$ to the class $\\texttt{PerfForesightConsumerType}$:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "PFexample = PerfForesightConsumerType(**PF_dictionary) \n", + "# the asterisks ** basically say \"here come some arguments\" to PerfForesightConsumerType" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In $\\texttt{PFexample}$, we now have _defined_ the problem of a particular infinite horizon perfect foresight consumer who knows how to solve this problem. \n", + "\n", + "## Solving an Agent's Problem\n", + "\n", + "To tell the agent actually to solve the problem, we call the agent's $\\texttt{solve}$ **method**. (A *method** is essentially a function that an object runs that affects the object's own internal characteristics -- in this case, the method adds the consumption function to the contents of $\\texttt{PFexample}$.)\n", + "\n", + "The cell below calls the $\\texttt{solve}$ method for $\\texttt{PFexample}$" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "PFexample.solve()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Running the $\\texttt{solve}$ method creates the **attribute** of $\\texttt{PFexample}$ named $\\texttt{solution}$. In fact, every subclass of $\\texttt{AgentType}$ works the same way: The class definition contains the abstract algorithm that knows how to solve the model, but to obtain the particular solution for a specific instance (paramterization/configuration), that instance must be instructed to $\\texttt{solve()}$ its problem. \n", + "\n", + "The $\\texttt{solution}$ attribute is always a $\\textit{list}$ of solutions to a single period of the problem. In the case of an infinite horizon model like the one here, there is just one element in that list -- the solution to all periods of the infinite horizon problem. The consumption function stored as the first element (element 0) of the solution list can be retrieved by:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "PFexample.solution[0].cFunc" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One of the results proven in the associated [the lecture notes](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA/) is that, for the specific problem defined above, there is a solution in which the _ratio_ $c = C/P$ is a linear function of the _ratio_ of market resources to permanent income, $m = M/P$. \n", + "\n", + "This is why $\\texttt{cFunc}$ can be represented by a linear interpolation. It can be plotted between an $m$ ratio of 0 and 10 using the command below." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "mPlotTop=10\n", + "plotFuncs(PFexample.solution[0].cFunc,0.,mPlotTop)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The figure illustrates one of the surprising features of the perfect foresight model: A person with zero money should be spending at a rate more than double their income (that is, $\\texttt{cFunc}(0.) \\approx 2.08$ - the intersection on the vertical axis). How can this be?\n", + "\n", + "The answer is that we have not incorporated any constraint that would prevent the agent from borrowing against the entire PDV of future earnings-- human wealth. How much is that? What's the minimum value of $m_t$ where the consumption function is defined? We can check by retrieving the $\\texttt{hNrm}$ **attribute** of the solution, which calculates the value of human wealth normalized by permanent income:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This agent's human wealth is 50.49994992551661 times his current income level.\n", + "This agent's consumption function is defined (consumption is positive) down to m_t = -50.49994992551661\n" + ] + } + ], + "source": [ + "humanWealth = PFexample.solution[0].hNrm\n", + "mMinimum = PFexample.solution[0].mNrmMin\n", + "print(\"This agent's human wealth is \" + str(humanWealth) + ' times his current income level.')\n", + "print(\"This agent's consumption function is defined (consumption is positive) down to m_t = \" + str(mMinimum))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Yikes! Let's take a look at the bottom of the consumption function. In the cell below, set the bounds of the $\\texttt{plotFuncs}$ function to display down to the lowest defined value of the consumption function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# YOUR FIRST HANDS-ON EXERCISE!\n", + "# Fill in the value for \"mPlotBottom\" to plot the consumption function from the point where it is zero.\n", + "plotFuncs(PFexample.solution[0].cFunc,mPlotBottom,mPlotTop)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Changing Agent Parameters\n", + "\n", + "Suppose you wanted to change one (or more) of the parameters of the agent's problem and see what that does. We want to compare consumption functions before and after we change parameters, so let's make a new instance of $\\texttt{PerfForesightConsumerType}$ by copying $\\texttt{PFexample}$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "NewExample = deepcopy(PFexample)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In Python, you can set an **attribute** of an object just like any other variable. For example, we could make the new agent less patient:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "NewExample.DiscFac = 0.90\n", + "NewExample.solve()\n", + "mPlotBottom = mMinimum\n", + "plotFuncs([PFexample.solution[0].cFunc,NewExample.solution[0].cFunc],mPlotBottom,mPlotTop)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(Note that you can pass a **list** of functions to $\\texttt{plotFuncs}$ as the first argument rather than just a single function. Lists are written inside of [square brackets].)\n", + "\n", + "Let's try to deal with the \"problem\" of massive human wealth by making another consumer who has essentially no future income. We can virtually eliminate human wealth by making the permanent income growth factor $\\textit{very}$ small.\n", + "\n", + "In $\\texttt{PFexample}$, the agent's income grew by 1 percent per period -- his $\\texttt{PermGroFac}$ took the value 1.01. What if our new agent had a growth factor of 0.01 -- his income __shrinks__ by 99 percent each period? In the cell below, set $\\texttt{NewExample}$'s discount factor back to its original value, then set its $\\texttt{PermGroFac}$ attribute so that the growth factor is 0.01 each period.\n", + "\n", + "Important: Recall that the model at the top of this document said that an agent's problem is characterized by a sequence of income growth factors, but we tabled that concept. Because $\\texttt{PerfForesightConsumerType}$ treats $\\texttt{PermGroFac}$ as a __time-varying__ attribute, it must be specified as a **list** (with a single element in this case)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Revert NewExample's discount factor and make his future income minuscule\n", + "# print(\"your lines here\")\n", + "\n", + "# Compare the old and new consumption functions\n", + "plotFuncs([PFexample.solution[0].cFunc,NewExample.solution[0].cFunc],0.,10.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now $\\texttt{NewExample}$'s consumption function has the same slope (MPC) as $\\texttt{PFexample}$, but it emanates from (almost) zero-- he has basically no future income to borrow against!\n", + "\n", + "If you'd like, use the cell above to alter $\\texttt{NewExample}$'s other attributes (relative risk aversion, etc) and see how the consumption function changes. However, keep in mind that \\textit{no solution exists} for some combinations of parameters. HARK should let you know if this is the case if you try to solve such a model.\n", + "\n", + "\n", + "## Your Second HARK Model: Adding Income Shocks\n", + "\n", + "Linear consumption functions are pretty boring, and you'd be justified in feeling unimpressed if all HARK could do was plot some lines. Let's look at another model that adds two important layers of complexity: income shocks and (artificial) borrowing constraints.\n", + "\n", + "Specifically, our new type of consumer receives two income shocks at the beginning of each period: a completely transitory shock $\\theta_t$ and a completely permanent shock $\\psi_t$. Moreover, lenders will not let the agent borrow money such that his ratio of end-of-period assets $A_t$ to permanent income $P_t$ is less than $\\underline{a}$. As with the perfect foresight problem, this model can be framed in terms of __normalized__ variables, e.g. $m_t \\equiv M_t/P_t$. (See [here](http://econ.jhu.edu/people/ccarroll/papers/BufferStockTheory/) for all the theory).\n", + "\n", + "\\begin{eqnarray*}\n", + "v_t(m_t) &=& \\max_{c_t} ~ U(c_t) ~ + \\phantom{\\LivFac} \\beta \\mathbb{E} [(\\Gamma_{t+1}\\psi_{t+1})^{1-\\rho} v_{t+1}(m_{t+1}) ], \\\\\n", + "a_t &=& m_t - c_t, \\\\\n", + "a_t &\\geq& \\underset{\\bar{}}{a}, \\\\\n", + "m_{t+1} &=& R/(\\Gamma_{t+1} \\psi_{t+1}) a_t + \\theta_{t+1}, \\\\\n", + "\\mathbb{E}[\\psi]=\\mathbb{E}[\\theta] &=& 1, \\\\\n", + "u(c) &=& \\frac{c^{1-\\rho}}{1-\\rho}.\n", + "\\end{eqnarray*}\n", + "\n", + "HARK represents agents with this kind of problem as instances of the class $\\texttt{IndShockConsumerType}$. To create an $\\texttt{IndShockConsumerType}$, we must specify the same set of parameters as for a $\\texttt{PerfForesightConsumerType}$, as well as an artificial borrowing constraint $\\underline{a}$ and a sequence of income shocks. It's easy enough to pick a borrowing constraint -- say, zero -- but how would we specify the distributions of the shocks? Can't the joint distribution of permanent and transitory shocks be just about anything?\n", + "\n", + "_Yes_, and HARK can handle whatever correlation structure a user might care to specify. However, the default behavior of $\\texttt{IndShockConsumerType}$ is that the distribution of permanent income shocks is mean one lognormal, and the distribution of transitory shocks is mean one lognormal augmented with a point mass representing unemployment. The distributions are independent of each other by default, and by default are approximated with $N$ point equiprobable distributions.\n", + "\n", + "Let's make an infinite horizon instance of $\\texttt{IndShockConsumerType}$ with the same parameters as our original perfect foresight agent, plus the extra parameters to specify the income shock distribution and the artificial borrowing constraint. As before, we'll make a dictionary:\n", + "\n", + "\n", + "| Param | Description | Code | Value |\n", + "| :---: | --- | --- | :---: |\n", + "| \\underline{a} | Artificial borrowing constraint | $\\texttt{BoroCnstArt}$ | 0.0 |\n", + "| $\\sigma_\\psi$ | Underlying stdev of permanent income shocks | $\\texttt{PermShkStd}$ | 0.1 |\n", + "| $\\sigma_\\theta$ | Underlying stdev of transitory income shocks | $\\texttt{TranShkStd}$ | 0.1 |\n", + "| $N_\\psi$ | Number of discrete permanent income shocks | $\\texttt{PermShkCount}$ | 7 |\n", + "| $N_\\theta$ | Number of discrete transitory income shocks | $\\texttt{TranShkCount}$ | 7 |\n", + "| $\\mho$ | Unemployment probability | $\\texttt{UnempPrb}$ | 0.05 |\n", + "| $\\underset{\\bar{}}{\\theta}$ | Transitory shock when unemployed | $\\texttt{IncUnemp}$ | 0.3 |" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "code_folding": [] + }, + "outputs": [], + "source": [ + "# This cell defines a parameter dictionary for making an instance of IndShockConsumerType.\n", + "\n", + "IndShockDictionary = {\n", + " 'CRRA': 2.5, # The dictionary includes our original parameters...\n", + " 'Rfree': 1.03,\n", + " 'DiscFac': 0.96,\n", + " 'LivPrb': [0.98],\n", + " 'PermGroFac': [1.01],\n", + " 'PermShkStd': [0.1], # ... and the new parameters for constructing the income process. \n", + " 'PermShkCount': 7,\n", + " 'TranShkStd': [0.1],\n", + " 'TranShkCount': 7,\n", + " 'UnempPrb': 0.05,\n", + " 'IncUnemp': 0.3,\n", + " 'BoroCnstArt': 0.0,\n", + " 'aXtraMin': 0.001, # aXtra parameters specify how to construct the grid of assets.\n", + " 'aXtraMax': 50., # Don't worry about these for now\n", + " 'aXtraNestFac': 3,\n", + " 'aXtraCount': 48,\n", + " 'aXtraExtra': [None],\n", + " 'vFuncBool': False, # These booleans indicate whether the value function should be calculated\n", + " 'CubicBool': False, # and whether to use cubic spline interpolation. You can ignore them.\n", + " 'aNrmInitMean' : -10.,\n", + " 'aNrmInitStd' : 0.0, # These parameters specify the (log) distribution of normalized assets\n", + " 'pLvlInitMean' : 0.0, # and permanent income for agents at \"birth\". They are only relevant in\n", + " 'pLvlInitStd' : 0.0, # simulation and you don't need to worry about them.\n", + " 'PermGroFacAgg' : 1.0,\n", + " 'T_retire': 0, # What's this about retirement? ConsIndShock is set up to be able to\n", + " 'UnempPrbRet': 0.0, # handle lifecycle models as well as infinite horizon problems. Swapping\n", + " 'IncUnempRet': 0.0, # out the structure of the income process is easy, but ignore for now.\n", + " 'T_age' : None,\n", + " 'T_cycle' : 1,\n", + " 'cycles' : 0,\n", + " 'AgentCount': 10000,\n", + " 'tax_rate':0.0,\n", + "}\n", + " \n", + "# Hey, there's a lot of parameters we didn't tell you about! Yes, but you don't need to\n", + "# think about them for now." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As before, we need to import the relevant subclass of $\\texttt{AgentType}$ into our workspace, then create an instance by passing the dictionary to the class as if the class were a function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from HARK.ConsumptionSaving.ConsIndShockModel import IndShockConsumerType\n", + "IndShockExample = IndShockConsumerType(**IndShockDictionary)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can solve our new agent's problem just like before, using the $\\texttt{solve}$ method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "IndShockExample.solve()\n", + "plotFuncs(IndShockExample.solution[0].cFunc,0.,10.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Changing Constructed Attributes\n", + "\n", + "In the parameter dictionary above, we chose values for HARK to use when constructing its numeric representation of $F_t$, the joint distribution of permanent and transitory income shocks. When $\\texttt{IndShockExample}$ was created, those parameters ($\\texttt{TranShkStd}$, etc) were used by the **constructor** or **initialization** method of $\\texttt{IndShockConsumerType}$ to construct an attribute called $\\texttt{IncomeDstn}$.\n", + "\n", + "Suppose you were interested in changing (say) the amount of permanent income risk. From the section above, you might think that you could simply change the attribute $\\texttt{TranShkStd}$, solve the model again, and it would work.\n", + "\n", + "That's _almost_ true-- there's one extra step. $\\texttt{TranShkStd}$ is a primitive input, but it's not the thing you _actually_ want to change. Changing $\\texttt{TranShkStd}$ doesn't actually update the income distribution... unless you tell it to (just like changing an agent's preferences does not change the consumption function that was stored for the old set of parameters -- until you invoke the $\\texttt{solve}$ method again). In the cell below, we invoke the method $\\texttt{updateIncomeProcess}$ so HARK knows to reconstruct the attribute $\\texttt{IncomeDstn}$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "OtherExample = deepcopy(IndShockExample) # Make a copy so we can compare consumption functions\n", + "OtherExample.PermShkStd = [0.2] # Double permanent income risk (note that it's a one element list)\n", + "OtherExample.updateIncomeProcess() # Call the method to reconstruct the representation of F_t\n", + "OtherExample.solve()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the cell below, use your blossoming HARK skills to plot the consumption function for $\\texttt{IndShockExample}$ and $\\texttt{OtherExample}$ on the same figure." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "# Use the line(s) below to plot the consumptions functions against each other" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "collapsed,code_folding", + "formats": "ipynb,py:percent" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/Gentle-Intro/Gentle-Intro-To-HARK.py b/examples/Gentle-Intro/Gentle-Intro-To-HARK.py new file mode 100644 index 000000000..698543675 --- /dev/null +++ b/examples/Gentle-Intro/Gentle-Intro-To-HARK.py @@ -0,0 +1,305 @@ +# --- +# jupyter: +# jupytext: +# cell_metadata_filter: collapsed,code_folding +# formats: ipynb,py:percent +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.2' +# jupytext_version: 1.2.3 +# kernelspec: +# display_name: Python 3 +# language: python +# name: python3 +# --- + +# %% [markdown] +# # A Gentle Introduction to HARK +# +# This notebook provides a simple, hands-on tutorial for first time HARK users -- and potentially first time Python users. It does not go "into the weeds" - we have hidden some code cells that do boring things that you don't need to digest on your first experience with HARK. Our aim is to convey a feel for how the toolkit works. +# +# For readers for whom this is your very first experience with Python, we have put important Python concepts in **boldface**. For those for whom this is the first time they have used a Jupyter notebook, we have put Jupyter instructions in _italics_. Only cursory definitions (if any) are provided here. If you want to learn more, there are many online Python and Jupyter tutorials. + +# %% {"code_folding": []} +# This cell has a bit of initial setup. You can click the triangle to the left to expand it. +# Click the "Run" button immediately above the notebook in order to execute the contents of any cell +# WARNING: Each cell in the notebook relies upon results generated by previous cells +# The most common problem beginners have is to execute a cell before all its predecessors +# If you do this, you can restart the kernel (see the "Kernel" menu above) and start over +# %matplotlib inline +import matplotlib.pyplot as plt +from tqdm import tqdm +import numpy as np +import HARK +from time import clock +from copy import deepcopy +mystr = lambda number : "{:.4f}".format(number) +from HARK.utilities import plotFuncs + +# %% [markdown] +# ## Your First HARK Model: Perfect Foresight +# +# $$\newcommand{\CRRA}{\rho}\newcommand{\DiscFac}{\beta}$$ +# We start with almost the simplest possible consumption model: A consumer with CRRA utility +# +# \begin{equation} +# U(C) = \frac{C^{1-\CRRA}}{1-\rho} +# \end{equation} +# +# has perfect foresight about everything except the (stochastic) date of death, which occurs with constant probability implying a "survival probability" $\newcommand{\LivPrb}{\aleph}\LivPrb < 1$. Permanent labor income $P_t$ grows from period to period by a factor $\Gamma_t$. At the beginning of each period $t$, the consumer has some amount of market resources $M_t$ (which includes both market wealth and currrent income) and must choose how much of those resources to consume $C_t$ and how much to retain in a riskless asset $A_t$ which will earn return factor $R$. The agent's flow of utility $U(C_t)$ from consumption is geometrically discounted by factor $\beta$. Between periods, the agent dies with probability $\mathsf{D}_t$, ending his problem. +# +# The agent's problem can be written in Bellman form as: +# +# \begin{eqnarray*} +# V_t(M_t,P_t) &=& \max_{C_t}~U(C_t) + \beta \aleph V_{t+1}(M_{t+1},P_{t+1}), \\ +# & s.t. & \\ +# %A_t &=& M_t - C_t, \\ +# M_{t+1} &=& R (M_{t}-C_{t}) + Y_{t+1}, \\ +# P_{t+1} &=& \Gamma_{t+1} P_t, \\ +# \end{eqnarray*} +# +# A particular perfect foresight agent's problem can be characterized by values of risk aversion $\rho$, discount factor $\beta$, and return factor $R$, along with sequences of income growth factors $\{ \Gamma_t \}$ and survival probabilities $\{\mathsf{\aleph}_t\}$. To keep things simple, let's forget about "sequences" of income growth and mortality, and just think about an $\textit{infinite horizon}$ consumer with constant income growth and survival probability. +# +# ## Representing Agents in HARK +# +# HARK represents agents solving this type of problem as $\textbf{instances}$ of the $\textbf{class}$ $\texttt{PerfForesightConsumerType}$, a $\textbf{subclass}$ of $\texttt{AgentType}$. To make agents of this class, we must import the class itself into our workspace. (Run the cell below in order to do this). + +# %% +from HARK.ConsumptionSaving.ConsIndShockModel import PerfForesightConsumerType + +# %% [markdown] +# The $\texttt{PerfForesightConsumerType}$ class contains within itself the python code that constructs the solution for the perfect foresight model we are studying here, as specifically articulated in [these lecture notes](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA/). +# +# To create an instance of $\texttt{PerfForesightConsumerType}$, we simply call the class as if it were a function, passing as arguments the specific parameter values we want it to have. In the hidden cell below, we define a $\textbf{dictionary}$ named $\texttt{PF_dictionary}$ with these parameter values: +# +# | Param | Description | Code | Value | +# | :---: | --- | --- | :---: | +# | $\rho$ | Relative risk aversion | $\texttt{CRRA}$ | 2.5 | +# | $\beta$ | Discount factor | $\texttt{DiscFac}$ | 0.96 | +# | $R$ | Risk free interest factor | $\texttt{Rfree}$ | 1.03 | +# | $\newcommand{\LivFac}{\aleph}\LivFac$ | Survival probability | $\texttt{LivPrb}$ | 0.98 | +# | $\Gamma$ | Income growth factor | $\texttt{PermGroFac}$ | 1.01 | +# +# +# For now, don't worry about the specifics of dictionaries. All you need to know is that a dictionary lets us pass many arguments wrapped up in one simple data structure. + +# %% {"code_folding": []} +# This cell defines a parameter dictionary. You can expand it if you want to see what that looks like. +PF_dictionary = { + 'CRRA' : 2.5, + 'DiscFac' : 0.96, + 'Rfree' : 1.03, + 'LivPrb' : [0.98], + 'PermGroFac' : [1.01], + 'T_cycle' : 1, + 'cycles' : 0, + 'AgentCount' : 10000 +} + +# To those curious enough to open this hidden cell, you might notice that we defined +# a few extra parameters in that dictionary: T_cycle, cycles, and AgentCount. Don't +# worry about these for now. + +# %% [markdown] +# Let's make an **object** named $\texttt{PFexample}$ which is an **instance** of the $\texttt{PerfForesightConsumerType}$ class. The object $\texttt{PFexample}$ will bundle together the abstract mathematical description of the solution embodied in $\texttt{PerfForesightConsumerType}$, and the specific set of parameter values defined in $\texttt{PF_dictionary}$. Such a bundle is created passing $\texttt{PF_dictionary}$ to the class $\texttt{PerfForesightConsumerType}$: + +# %% +PFexample = PerfForesightConsumerType(**PF_dictionary) +# the asterisks ** basically say "here come some arguments" to PerfForesightConsumerType + +# %% [markdown] +# In $\texttt{PFexample}$, we now have _defined_ the problem of a particular infinite horizon perfect foresight consumer who knows how to solve this problem. +# +# ## Solving an Agent's Problem +# +# To tell the agent actually to solve the problem, we call the agent's $\texttt{solve}$ **method**. (A *method** is essentially a function that an object runs that affects the object's own internal characteristics -- in this case, the method adds the consumption function to the contents of $\texttt{PFexample}$.) +# +# The cell below calls the $\texttt{solve}$ method for $\texttt{PFexample}$ + +# %% +PFexample.solve() + +# %% [markdown] +# Running the $\texttt{solve}$ method creates the **attribute** of $\texttt{PFexample}$ named $\texttt{solution}$. In fact, every subclass of $\texttt{AgentType}$ works the same way: The class definition contains the abstract algorithm that knows how to solve the model, but to obtain the particular solution for a specific instance (paramterization/configuration), that instance must be instructed to $\texttt{solve()}$ its problem. +# +# The $\texttt{solution}$ attribute is always a $\textit{list}$ of solutions to a single period of the problem. In the case of an infinite horizon model like the one here, there is just one element in that list -- the solution to all periods of the infinite horizon problem. The consumption function stored as the first element (element 0) of the solution list can be retrieved by: + +# %% +PFexample.solution[0].cFunc + +# %% [markdown] +# One of the results proven in the associated [the lecture notes](http://econ.jhu.edu/people/ccarroll/public/lecturenotes/consumption/PerfForesightCRRA/) is that, for the specific problem defined above, there is a solution in which the _ratio_ $c = C/P$ is a linear function of the _ratio_ of market resources to permanent income, $m = M/P$. +# +# This is why $\texttt{cFunc}$ can be represented by a linear interpolation. It can be plotted between an $m$ ratio of 0 and 10 using the command below. + +# %% +mPlotTop=10 +plotFuncs(PFexample.solution[0].cFunc,0.,mPlotTop) + +# %% [markdown] +# The figure illustrates one of the surprising features of the perfect foresight model: A person with zero money should be spending at a rate more than double their income (that is, $\texttt{cFunc}(0.) \approx 2.08$ - the intersection on the vertical axis). How can this be? +# +# The answer is that we have not incorporated any constraint that would prevent the agent from borrowing against the entire PDV of future earnings-- human wealth. How much is that? What's the minimum value of $m_t$ where the consumption function is defined? We can check by retrieving the $\texttt{hNrm}$ **attribute** of the solution, which calculates the value of human wealth normalized by permanent income: + +# %% +humanWealth = PFexample.solution[0].hNrm +mMinimum = PFexample.solution[0].mNrmMin +print("This agent's human wealth is " + str(humanWealth) + ' times his current income level.') +print("This agent's consumption function is defined (consumption is positive) down to m_t = " + str(mMinimum)) + +# %% [markdown] +# Yikes! Let's take a look at the bottom of the consumption function. In the cell below, set the bounds of the $\texttt{plotFuncs}$ function to display down to the lowest defined value of the consumption function. + +# %% +# YOUR FIRST HANDS-ON EXERCISE! +# Fill in the value for "mPlotBottom" to plot the consumption function from the point where it is zero. +plotFuncs(PFexample.solution[0].cFunc,mPlotBottom,mPlotTop) + +# %% [markdown] +# ## Changing Agent Parameters +# +# Suppose you wanted to change one (or more) of the parameters of the agent's problem and see what that does. We want to compare consumption functions before and after we change parameters, so let's make a new instance of $\texttt{PerfForesightConsumerType}$ by copying $\texttt{PFexample}$. + +# %% +NewExample = deepcopy(PFexample) + +# %% [markdown] +# In Python, you can set an **attribute** of an object just like any other variable. For example, we could make the new agent less patient: + +# %% +NewExample.DiscFac = 0.90 +NewExample.solve() +mPlotBottom = mMinimum +plotFuncs([PFexample.solution[0].cFunc,NewExample.solution[0].cFunc],mPlotBottom,mPlotTop) + +# %% [markdown] +# (Note that you can pass a **list** of functions to $\texttt{plotFuncs}$ as the first argument rather than just a single function. Lists are written inside of [square brackets].) +# +# Let's try to deal with the "problem" of massive human wealth by making another consumer who has essentially no future income. We can virtually eliminate human wealth by making the permanent income growth factor $\textit{very}$ small. +# +# In $\texttt{PFexample}$, the agent's income grew by 1 percent per period -- his $\texttt{PermGroFac}$ took the value 1.01. What if our new agent had a growth factor of 0.01 -- his income __shrinks__ by 99 percent each period? In the cell below, set $\texttt{NewExample}$'s discount factor back to its original value, then set its $\texttt{PermGroFac}$ attribute so that the growth factor is 0.01 each period. +# +# Important: Recall that the model at the top of this document said that an agent's problem is characterized by a sequence of income growth factors, but we tabled that concept. Because $\texttt{PerfForesightConsumerType}$ treats $\texttt{PermGroFac}$ as a __time-varying__ attribute, it must be specified as a **list** (with a single element in this case). + +# %% +# Revert NewExample's discount factor and make his future income minuscule +# print("your lines here") + +# Compare the old and new consumption functions +plotFuncs([PFexample.solution[0].cFunc,NewExample.solution[0].cFunc],0.,10.) + +# %% [markdown] +# Now $\texttt{NewExample}$'s consumption function has the same slope (MPC) as $\texttt{PFexample}$, but it emanates from (almost) zero-- he has basically no future income to borrow against! +# +# If you'd like, use the cell above to alter $\texttt{NewExample}$'s other attributes (relative risk aversion, etc) and see how the consumption function changes. However, keep in mind that \textit{no solution exists} for some combinations of parameters. HARK should let you know if this is the case if you try to solve such a model. +# +# +# ## Your Second HARK Model: Adding Income Shocks +# +# Linear consumption functions are pretty boring, and you'd be justified in feeling unimpressed if all HARK could do was plot some lines. Let's look at another model that adds two important layers of complexity: income shocks and (artificial) borrowing constraints. +# +# Specifically, our new type of consumer receives two income shocks at the beginning of each period: a completely transitory shock $\theta_t$ and a completely permanent shock $\psi_t$. Moreover, lenders will not let the agent borrow money such that his ratio of end-of-period assets $A_t$ to permanent income $P_t$ is less than $\underline{a}$. As with the perfect foresight problem, this model can be framed in terms of __normalized__ variables, e.g. $m_t \equiv M_t/P_t$. (See [here](http://econ.jhu.edu/people/ccarroll/papers/BufferStockTheory/) for all the theory). +# +# \begin{eqnarray*} +# v_t(m_t) &=& \max_{c_t} ~ U(c_t) ~ + \phantom{\LivFac} \beta \mathbb{E} [(\Gamma_{t+1}\psi_{t+1})^{1-\rho} v_{t+1}(m_{t+1}) ], \\ +# a_t &=& m_t - c_t, \\ +# a_t &\geq& \underset{\bar{}}{a}, \\ +# m_{t+1} &=& R/(\Gamma_{t+1} \psi_{t+1}) a_t + \theta_{t+1}, \\ +# \mathbb{E}[\psi]=\mathbb{E}[\theta] &=& 1, \\ +# u(c) &=& \frac{c^{1-\rho}}{1-\rho}. +# \end{eqnarray*} +# +# HARK represents agents with this kind of problem as instances of the class $\texttt{IndShockConsumerType}$. To create an $\texttt{IndShockConsumerType}$, we must specify the same set of parameters as for a $\texttt{PerfForesightConsumerType}$, as well as an artificial borrowing constraint $\underline{a}$ and a sequence of income shocks. It's easy enough to pick a borrowing constraint -- say, zero -- but how would we specify the distributions of the shocks? Can't the joint distribution of permanent and transitory shocks be just about anything? +# +# _Yes_, and HARK can handle whatever correlation structure a user might care to specify. However, the default behavior of $\texttt{IndShockConsumerType}$ is that the distribution of permanent income shocks is mean one lognormal, and the distribution of transitory shocks is mean one lognormal augmented with a point mass representing unemployment. The distributions are independent of each other by default, and by default are approximated with $N$ point equiprobable distributions. +# +# Let's make an infinite horizon instance of $\texttt{IndShockConsumerType}$ with the same parameters as our original perfect foresight agent, plus the extra parameters to specify the income shock distribution and the artificial borrowing constraint. As before, we'll make a dictionary: +# +# +# | Param | Description | Code | Value | +# | :---: | --- | --- | :---: | +# | \underline{a} | Artificial borrowing constraint | $\texttt{BoroCnstArt}$ | 0.0 | +# | $\sigma_\psi$ | Underlying stdev of permanent income shocks | $\texttt{PermShkStd}$ | 0.1 | +# | $\sigma_\theta$ | Underlying stdev of transitory income shocks | $\texttt{TranShkStd}$ | 0.1 | +# | $N_\psi$ | Number of discrete permanent income shocks | $\texttt{PermShkCount}$ | 7 | +# | $N_\theta$ | Number of discrete transitory income shocks | $\texttt{TranShkCount}$ | 7 | +# | $\mho$ | Unemployment probability | $\texttt{UnempPrb}$ | 0.05 | +# | $\underset{\bar{}}{\theta}$ | Transitory shock when unemployed | $\texttt{IncUnemp}$ | 0.3 | + +# %% {"code_folding": []} +# This cell defines a parameter dictionary for making an instance of IndShockConsumerType. + +IndShockDictionary = { + 'CRRA': 2.5, # The dictionary includes our original parameters... + 'Rfree': 1.03, + 'DiscFac': 0.96, + 'LivPrb': [0.98], + 'PermGroFac': [1.01], + 'PermShkStd': [0.1], # ... and the new parameters for constructing the income process. + 'PermShkCount': 7, + 'TranShkStd': [0.1], + 'TranShkCount': 7, + 'UnempPrb': 0.05, + 'IncUnemp': 0.3, + 'BoroCnstArt': 0.0, + 'aXtraMin': 0.001, # aXtra parameters specify how to construct the grid of assets. + 'aXtraMax': 50., # Don't worry about these for now + 'aXtraNestFac': 3, + 'aXtraCount': 48, + 'aXtraExtra': [None], + 'vFuncBool': False, # These booleans indicate whether the value function should be calculated + 'CubicBool': False, # and whether to use cubic spline interpolation. You can ignore them. + 'aNrmInitMean' : -10., + 'aNrmInitStd' : 0.0, # These parameters specify the (log) distribution of normalized assets + 'pLvlInitMean' : 0.0, # and permanent income for agents at "birth". They are only relevant in + 'pLvlInitStd' : 0.0, # simulation and you don't need to worry about them. + 'PermGroFacAgg' : 1.0, + 'T_retire': 0, # What's this about retirement? ConsIndShock is set up to be able to + 'UnempPrbRet': 0.0, # handle lifecycle models as well as infinite horizon problems. Swapping + 'IncUnempRet': 0.0, # out the structure of the income process is easy, but ignore for now. + 'T_age' : None, + 'T_cycle' : 1, + 'cycles' : 0, + 'AgentCount': 10000, + 'tax_rate':0.0, +} + +# Hey, there's a lot of parameters we didn't tell you about! Yes, but you don't need to +# think about them for now. + +# %% [markdown] +# As before, we need to import the relevant subclass of $\texttt{AgentType}$ into our workspace, then create an instance by passing the dictionary to the class as if the class were a function. + +# %% +from HARK.ConsumptionSaving.ConsIndShockModel import IndShockConsumerType +IndShockExample = IndShockConsumerType(**IndShockDictionary) + +# %% [markdown] +# Now we can solve our new agent's problem just like before, using the $\texttt{solve}$ method. + +# %% +IndShockExample.solve() +plotFuncs(IndShockExample.solution[0].cFunc,0.,10.) + +# %% [markdown] +# ## Changing Constructed Attributes +# +# In the parameter dictionary above, we chose values for HARK to use when constructing its numeric representation of $F_t$, the joint distribution of permanent and transitory income shocks. When $\texttt{IndShockExample}$ was created, those parameters ($\texttt{TranShkStd}$, etc) were used by the **constructor** or **initialization** method of $\texttt{IndShockConsumerType}$ to construct an attribute called $\texttt{IncomeDstn}$. +# +# Suppose you were interested in changing (say) the amount of permanent income risk. From the section above, you might think that you could simply change the attribute $\texttt{TranShkStd}$, solve the model again, and it would work. +# +# That's _almost_ true-- there's one extra step. $\texttt{TranShkStd}$ is a primitive input, but it's not the thing you _actually_ want to change. Changing $\texttt{TranShkStd}$ doesn't actually update the income distribution... unless you tell it to (just like changing an agent's preferences does not change the consumption function that was stored for the old set of parameters -- until you invoke the $\texttt{solve}$ method again). In the cell below, we invoke the method $\texttt{updateIncomeProcess}$ so HARK knows to reconstruct the attribute $\texttt{IncomeDstn}$. + +# %% +OtherExample = deepcopy(IndShockExample) # Make a copy so we can compare consumption functions +OtherExample.PermShkStd = [0.2] # Double permanent income risk (note that it's a one element list) +OtherExample.updateIncomeProcess() # Call the method to reconstruct the representation of F_t +OtherExample.solve() + +# %% [markdown] +# In the cell below, use your blossoming HARK skills to plot the consumption function for $\texttt{IndShockExample}$ and $\texttt{OtherExample}$ on the same figure. + +# %% +# Use the line(s) below to plot the consumptions functions against each other + diff --git a/examples/HowWeSolveIndShockConsumerType/HoweWeSolveIndShockConsumerType.ipynb b/examples/HowWeSolveIndShockConsumerType/HoweWeSolveIndShockConsumerType.ipynb new file mode 100644 index 000000000..0ad325026 --- /dev/null +++ b/examples/HowWeSolveIndShockConsumerType/HoweWeSolveIndShockConsumerType.ipynb @@ -0,0 +1,466 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How we solve a model defined by the `IndShockConsumerType` class\n", + "The IndShockConsumerType reprents the work-horse consumption savings model with temporary and permanent shocks to income, finite or infinite horizons, CRRA utility and more. In this DemARK we take you through the steps involved in solving one period of such a model. The inheritance chains can be a little long, so figuring out where all the parameters and methods come from can be a bit confusing. Hence this map! The intention is to make it easier to know how to inheret from IndShockConsumerType in the sense that you know where to look for specific solver logic, but also so you know can figure out which methods to overwrite or supplement in your own `AgentType` and solver!\n", + "## The `solveConsIndShock` function\n", + "In HARK, a period's problem is always solved by the callable (function or callable object instance) stored in the field `solveOnePeriod`. In the case of `IndShockConsumerType`, this function is called `solveConsIndShock`. The function accepts a number of arguments, that it uses to construct an instance of either a `ConsIndShockSolverBasic` or a `ConsIndShockSolver`. These solvers both have the methods `prepareToSolve` and `solve`, that we will have a closer look at in this notebook. This means, that the logic of `solveConsIndShock` is basically:\n", + "\n", + " 1. Check if cubic interpolation (`CubicBool`) or construction of the value function interpolant (`vFuncBool`) are requested. Construct an instance of `ConsIndShockSolverBasic` if neither are requested, else construct a `ConsIndShockSolver`. Call this `solver`.\n", + " 1. Call `solver.prepareToSolve()`\n", + " 1. Call `solver.solve()` and return the output as the current solution." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Two types of solvers\n", + "As mentioned above, `solveOnePeriod` will construct an instance of the class `ConsIndShockSolverBasic`or `ConsIndShockSolver`. The main difference is whether it uses cubic interpolation or if it explicitly constructs a value function approximation. The choice and construction of a solver instance is bullet 1) from above.\n", + "\n", + "#### What happens in upon construction\n", + "Neither of the two solvers have their own `__init__`. `ConsIndShockSolver` inherits from `ConsIndShockSolverBasic` that in turn inherits from `ConsIndShockSetup`. `ConsIndShockSetup` inherits from `ConsPerfForesightSolver`, which itself is just an `Object`, so we get the inheritance structure\n", + "\n", + "- `ConsPerfForesightSolver` $\\leftarrow$ `ConsIndShockSetup` $\\leftarrow$ `ConsIndShockSolverBasic` $\\leftarrow$ `ConsIndShockSolver`\n", + "\n", + "When one of the two classes in the end of the inheritance chain is called, it will call `ConsIndShockSetup.__init__(args...)`. This takes a whole list of fixed inputs that then gets assigned to the object through a\n", + "```\n", + "ConsIndShockSetup.assignParameters(solution_next,IncomeDstn,LivPrb,DiscFac,CRRA,Rfree,PermGroFac,BoroCnstArt,aXtraGrid,vFuncBool,CubicBool)\n", + "```\n", + "call, that then calls\n", + "```\n", + "ConsPerfForesightSolver.assignParameters(self,solution_next,DiscFac,LivPrb,CRRA,Rfree,PermGroFac)\n", + "```\n", + "We're getting kind of detailed here, but it is simply to help us understand the inheritance structure. The methods are quite straight forward, and simply assign the list of variables to self. The ones that do not get assigned by the `ConsPerfForesightSolver` method gets assign by the `ConsIndShockSetup` method instead.\n", + "\n", + "\n", + "After all the input parameters are set, we update the utility function definitions. Remember, that we restrict ourselves to CRRA utility functions, and these are parameterized with the scalar we call `CRRA` in HARK. We use the two-argument CRRA utility (and derivatives, inverses, etc) from `HARK.utilities`, so we need to create a `lambda` (an anonymous function) according to the fixed `CRRA` we have chosen. This gets done through a call to\n", + "\n", + "```\n", + "ConsIndShockSetup.defUtilityFuncs()\n", + "```\n", + "that itself calls\n", + "```\n", + "ConsPerfForesightSolver.defUtilityFuncs()\n", + "```\n", + "Again, we wish to emphasize the inheritance structure. The method in `ConsPerfForesightSolver` defines the most basic utility functions (utility, its marginal and its marginal marginal), and `ConsIndShockSolver` adds additional functions (marginal of inverse, inverse of marginal, marginal of inverse of marginal, and optionally inverse if `vFuncBool` is true).\n", + "\n", + "To sum up, the `__init__` method lives in `ConsIndShockSetup`, calls `assignParameters` and `defUtilityFuncs` from `ConsPerfForesightSolver` and defines its own methods with the same names that adds some methods used to solve the `IndShockConsumerType` using EGM. The main things controlled by the end-user are whether cubic interpolation should be used, `CubicBool`, and if the value function should be explicitly formed, `vFuncBool`.\n", + "### Prepare to solve\n", + "We are now in bullet 2) from the list above. The `prepareToSolve` method is all about grabbing relevant information from next period's solution, calculating some limiting solutions. It comes from `ConsIndShockSetup` and calls two methods:\n", + "\n", + "1. `ConsIndShockSetup.setAndUpdateValues(self.solution_next,self.IncomeDstn,self.LivPrb,self.DiscFac)`\n", + "2. `ConsIndShockSetup.defBoroCnst(self.BoroCnstArt)`\n", + "\n", + "First, we have `setAndUpdateValues`. The main purpose is to grab the relevant vectors that represent the shock distributions, the effective discount factor, and value function (marginal, level, marginal marginal depending on the options). It also calculates some limiting marginal propensities to consume and human wealth levels. Second, we have `defBoroCnst`. As the name indicates, it calculates the natural borrowing constraint, handles artificial borrowing constraints, and defines the consumption function where the constraint binds (`cFuncNowCnst`).\n", + "\n", + "To sum, `prepareToSolve` sets up the stochastic environment an borrowing constraints the consumer might face. It also grabs interpolants from \"next period\"'s solution.\n", + "\n", + "### Solve it!\n", + "The last method `solveConsIndShock` will call from the `solver` is `solve`. This method essentially has four steps:\n", + " 1. Pre-processing for EGM: solver.prepareToCalcEndOfPrdvP\n", + " 1. First step of EGM: solver.calcEndOfPrdvP\n", + " 1. Second step of EGM: solver.makeBasicSolution\n", + " 1. Add MPC and human wealth: solver.addMPCandHumanWealth\n", + "\n", + "#### Pre-processing for EGM `prepareToCalcEndOfPrdvP`\n", + "Find relevant values of end-of-period asset values (according to `aXtraGrid` and natural borrowing constraint) and next period values implied by current period end-of-period assets and stochastic elements. The method stores the following in `self`:\n", + "\n", + " 1. values of permanent shocks in `PermShkVals_temp`\n", + " 1. shock probabilities in `ShkPrbs_temp`\n", + " 1. next period resources in `mNrmNext`\n", + " 1. current grid of end-of-period assets in `aNrmNow`\n", + "\n", + "The method also returns `aNrmNow`. The definition is in `ConsIndShockSolverBasic` and is not overwritten in `ConsIndShockSolver`.\n", + "\n", + "#### First step of EGM `calcEndOfPrdvP`\n", + "Find the marginal value of having some level of end-of-period assets today. End-of-period assets as well as stochastics imply next-period resources at the beginning of the period, calculated above. Return the result as `EndOfPrdvP`.\n", + "\n", + "#### Second step of EGM `makeBasicSolution`\n", + "Apply inverse marginal utility function to nodes from about to find (m, c) pairs for the new consumption function in `getPointsForInterpolation` and create the interpolants in `usePointsForInterpolation`. The latter constructs the `ConsumerSolution` that contains the current consumption function `cFunc`, the current marginal value function `vPfunc`, and the smallest possible resource level `mNrmMinNow`.\n", + "\n", + "#### Add MPC and human wealth `addMPCandHumanWealth`\n", + "Add values calculated in `defBoroCnst` now that we have a solution object to put them in.\n", + "\n", + "#### Special to the non-Basic solver\n", + "We are now done, but in the `ConsIndShockSolver` (non-`Basic`!) solver there are a few extra steps. We add steady state m, and depending on the values of `vFuncBool` and `CubicBool` we also add the value function and the marginal marginal value function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Let's try it in action!\n", + "First, we define a standard lifecycle model, solve it and then" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import HARK.ConsumptionSaving.ConsumerParameters as Params\n", + "from HARK.ConsumptionSaving.ConsIndShockModel import IndShockConsumerType\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "LifecycleExample = IndShockConsumerType(**Params.init_lifecycle)\n", + "LifecycleExample.cycles = 1 # Make this consumer live a sequence of periods exactly once\n", + "LifecycleExample.solve()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's have a look at the solution in time period second period. We should then be able to" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAD4CAYAAADiry33AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3deXyU5b338c8vC0tYwhLCkmQSVgFRRCJB3CiCC1WxVquIa6u01npq9ZzzdDmn7Wl7nnP6nNbWVk8tKioKqEWrqNQNrQhCYkD2NYRsJBCSQAIJWed6/kisaQjNAEnumcn3/Xrlxcw998x8XyP5enHPdd+XOecQEZHwFeF1ABER6VgqehGRMKeiFxEJcyp6EZEwp6IXEQlzUV69cVxcnEtJSfHq7UVEQtL69etLnHODTuU5nhV9SkoKmZmZXr29iEhIMrPcU32ODt2IiIQ5Fb2ISJhT0YuIhDkVvYhImFPRi4iEORW9iEiYU9GLiIS5NovezHqYWYaZbTKzbWb2H63s093MXjKzLDNLN7OUjggrItJVVdc18OqGgtN6biAnTNUAM5xzx8wsGlhtZn9xzq1rts83gMPOuVFmdgvwS+Dm00okIiJ/s/vgUZak5/HqhgIqqutP6zXaLHrXuDLJsaa70U0/LVcrmQP8tOn2MuAxMzOnVU1ERE5ZdV0Db20uYklGHutzD9MtMoKrJgxh7hQf03556q8X0CUQzCwSWA+MAh53zqW32CUByAdwztWbWTkwEChp8TrzgfkAPp/v1NOKiISxlqP3EXG9+NHscXx1ciIDenU77dcNqOidcw3AeWbWD/izmU1wzm1ttou19rRWXmcBsAAgNTVVo30R6fKq6xpYsaWIJel5ZOYeJjrSuGrCUG6d4mPqiAGYtVavp+aULmrmnDtiZn8FrgKaF30BkAQUmFkUEAuUnXE6EZEwlVV8lCXp+byyoYDy43WkDIzhB1eP5cbJiQzs3b1d36vNojezQUBdU8n3BGbS+GVrc8uBO4G1wI3ABzo+LyLy96rrGnh76wGWZOSRsa+M6EjjirOHMG+Kj6kjBhIRceaj99YEMqIfCjzXdJw+AnjZOfemmf0MyHTOLQeeBp43sywaR/K3dEhaEZEQtPfQMZam5/HKhgIOV9XhGxDD/7lqLDelJhLXzqP31gQy62YzMKmV7T9udrsauKl9o4mIhK6a+sbR+9KMPNZllxEVYVxx9mBunZLMtJEdN3pvjWcLj4iIhKN9JZUszchj2foCyiprSRrQk3+58ixuSk0kvk8PTzKp6EVEzlBtvZ93tjWO3j/ZW0pkhDFr3GBuTfNx8ai4Th29t0ZFLyJymnJLK1mSkceyzAJKK2tJ6NeTf75iDF9LTSK+rzej99ao6EVETkFtvZ/3dxxkSXoeq7NKiIwwLh8bz61pPi4ZPYhIj0fvrVHRi4gEIK+0iqWf5vGnzAJKjtUwLLYHD81qHL0PiQ2e0XtrVPQiIidR1+Bn5Y6DLE7P4+M9JUQYzBg7mHlpPi4dE5yj99ao6EVEWsgvq+KlT/N5KTOfQ0drGBrbgwdnjubmC5IYGtvT63inTEUvIgLUN/hZubOYJel5rNpzCAO+dFY8c6f4mH7WIKIiQ3edJhW9iHRphUeO8+Kn+bz0aR4HK2oY3Lc7D8xoHL0n9Au90XtrVPQi0uU0+B2r9hxi8bo8Pth5EAdcNmYQP5/jY8bY+JAevbdGRS8iXcahozW8nJnP0ow8Cg4fJ653N+6bPpJbLvCRNCDG63gdRkUvImHNOcfa7FIWp+fxztYD1Psd00YO5AdXj2PW+MF0iwqv0XtrVPQiEpaOVNWybH0BS9LzyC6pJLZnNHdNS2Fumo+Rg3p7Ha9TqehFJGw459iQd4TF6bm8ubmI2no/k5P788iMUcw+Zyg9oiO9jugJFb2IhLyj1XW8trGQxety2XngKL27R3FzahK3pvkYN7Sv1/E8p6IXkZC1dX85SzLyeP2z/VTWNnD2sL7836+cw5zzhtGru+rtc/okRCSkHK9t4M3NhSxOz2Nj/hF6REdw7bnDmDc1mYmJse2ymHa4UdGLSEjIKj7K4vQ8XllfQEV1PaPie/OTa8dzw6REYmOivY4X1FT0IhK0auobeGfbQRavyyW9aTHtqycMZV6ajynDB2j0HiAVvYgEnbzSKpZk5PGnzHxKK2vxDYjh+1eP5cbJnbOYdrhR0YtIUPj8omKL0/NYtfsQkRHGzHHxzEtLDorl+EKZil5EPFVcUc3SjHxe/DSPovJqhvTtwfdmjuHmC4J/QY9QoaIXkU73+WUJXliXy7vbDlLvd1wyOo6fXnc2l4fhRcW81mbRm1kSsAgYAviBBc65R1vsMx14HdjXtOlV59zP2jeqiIS68uN1vLK+gMXpuew9VEm/mGi+fvFwbp3iIyWul9fxwlYgI/p64GHn3AYz6wOsN7P3nHPbW+z3sXPumvaPKCKhbktBOS+sy+X1TfuprvMzydePX980kS+f23UvS9CZ2ix651wRUNR0+6iZ7QASgJZFLyLyN9V1DbyxqZAX0vPYlH+EntGRfGVSAvPSkpmQEOt1vC7llI7Rm1kKMAlIb+XhC81sE1AI/LNzbtsZpxORkLOvpJLF63L50/oCyo/XMSq+N/9x3dl85fwE+vbQiU1eCLjozaw38ArwoHOuosXDG4Bk59wxM5sNvAaMbuU15gPzAXw+32mHFpHgUt/g5/0dxSxOz+XjPSVERRhXThjC7VOTSdOJTZ4z51zbO5lFA28C7zjnHglg/xwg1TlXcrJ9UlNTXWZm5ilEFZFgc7CimhczGldsOlBRzbDYHtya5uNrFyQR30dTIzuCma13zqWeynMCmXVjwNPAjpOVvJkNAQ4655yZTQEigNJTCSIiocE5x9q9pTy/Lpd3tx+kwe8a11u9fgJfOmuQpkYGoUAO3VwE3A5sMbONTdt+CPgAnHNPADcC95lZPXAcuMUF8k8FEQkZ5VV1LNvQODUy+1Al/WOiuefi4dya5iN5oKZGBrNAZt2sBv7hATbn3GPAY+0VSkSCx9b95Ty/9oupkef7+vHI1yZ26RWbQo3OjBWRE1TXNbBiSxGL1uay8W9TIxO5baqPs4dpamSoUdGLyN/kl1WxOD2PlzPzKausZcSgXvzk2vF8dXKipkaGMBW9SBfn9ztW7TnEC+tyWbmzGANmjR/MHRemMG3kQE2NDAMqepEu6khVLcvWF/DCulxySquI692d73xpFHOn+BjWr6fX8aQdqehFupit+8tZtDaH5ZsKqa7zc0FKf743awxXTxhKtyhNjQxHKnqRLuBkX67ePjWZ8cP6eh1POpiKXiSMnezL1RvOTyS2p75c7SpU9CJhRl+uSksqepEwUV5Vx5/W5zf7crUb908fxa1p+nK1q1PRi4S4HUUVLFqbw58/azxzNTVZX67K31PRi4SgugY/7247yHOf5JCRU0aP6AiuPy+B2y9M1pmrcgIVvUgIKT7aeFngxem5HKyoIWlAT340exw3pSbSL6ab1/EkSKnoRYKcc44NeUdYtDaHFVuKqGtovCzwf92QzGVj4omM0Jer8o+p6EWCVHVdA8s3FbJobQ5b91fQp3sUt01N5vapyYwY1NvreBJCVPQiQSa/rIoX0nN56dN8jlTVMWZwb35x/QS+MimBXt31KyunTn9rRIKAc441WaU8tzaHlTsOYmZc0TT3feoIrbkqZ0ZFL+KhYzX1vLK+gEVrc9h7qJIBvbpx3/SRzEtL1tx3aTcqehEP5JRU8uwnOSxbX8CxmnomJmnVJuk4KnqRTuKcY3VWCc+uyeGDXcVERRhfPmcod100nPOS+nkdT8KYil6kg1XV1vPqhv08+0kOWcXHiOvdjQdmjOa2NB/xfXt4HU+6ABW9SAfJL6vi+XW5vJiRR0V1PRMS+vLrmyZyzcShdI/S4RnpPCp6kXbknGNddhnPfrKP97Y3zp65asIQ7p6WwuTk/po9I55Q0Yu0g+q6Bl7fuJ9n1uSw88BR+sdE863LRnLbVM2eEe+p6EXOQFH5cZ5fm8vSjDwOV9UxdkgffvnVc5hzXoJmz0jQaLPozSwJWAQMAfzAAufcoy32MeBRYDZQBdzlnNvQ/nFFvNd47ZnDLFyTw9tbD+CcY+a4wdx90XCd3CRBKZARfT3wsHNug5n1Adab2XvOue3N9rkaGN30kwb8oelPkbBRU9/AW5uLeGZNDlv2l9OnRxRfvyiFOy5MIWlAjNfxRE6qzaJ3zhUBRU23j5rZDiABaF70c4BFzjkHrDOzfmY2tOm5IiGt+Gg1L6zLY0l6LiXHahk5qBc/v34CN+jaMxIiTulvqZmlAJOA9BYPJQD5ze4XNG37u6I3s/nAfACfz3dqSUU62ab8IzyzZh9vNV0aeMbYeO6+KIWLR8Xp8IyElICL3sx6A68ADzrnKlo+3MpT3AkbnFsALABITU094XERr9U1+PnL1gM8u2YfG/KO0Lt7FPPSkrlzWgrD43p5HU/ktARU9GYWTWPJL3bOvdrKLgVAUrP7iUDhmccT6Rylx2pYmpHH8+saV25KGRjDT64dz42TE+nTI9rreCJnJJBZNwY8Dexwzj1ykt2WA98xsxdp/BK2XMfnJRRsKyzn2TU5vL6pkNp6P5eMjuO/bjiH6WPiidDKTRImAhnRXwTcDmwxs41N234I+ACcc08AK2icWplF4/TKu9s/qkj78PsdK3cW89TH2aTvK6NndCRfS03kzgtTGD24j9fxRNpdILNuVtP6Mfjm+zjg/vYKJdIRqmobr/3+9Op95JRWkdCvJz+cPZabU33ExujwjIQvzQ2TsHegvJrn1uawJD2P8uN1TEzqx2NXnsVVZw8hKjLC63giHU5FL2Fr6/5ynl69jzc2FeJ3jivPHsI9lwznfJ8uLiZdi4peworf7/hgZzFPrc5mXXYZvbpFcvuFydw9bTi+gTp7VbomFb2Eharael7ZsJ+Fq/exr6SSYbE9Go+/X+AjtqeOv0vXpqKXkHawoprnPslh8efH3xNj+f3cSVw1YQjROv4uAqjoJURt3V/OwtX7eGNzIfV+x5XjG4+/a3EPkROp6CVk+P2OD3cV89TH+1ibXUpMt0jmpSVz90UpJA/U5QlETkZFL0HveG0Dr2woYOHqfWSXVDI0tgc/uHost0zR8XeRQKjoJWgdrKhm0drG4+9Hquo4NzGW382dxNU6/i5ySlT0EnS2F1bw1Ops3tjUePz9ivGDueeSEaTq+LvIaVHRS1BwzvHJ3lKe+GgvH+8p0fF3kXakohdP1Tf4WbH1AAtW7WXr/grienfnX648i9vSknX9GZF2oqIXT1TV1vOnzAKe/DibgsPHGRHXi/++4Ryun5RAj+hIr+OJhBUVvXSq0mM1PLc2l+fX5nC4qo7zff348TXjmTlusK7/LtJBVPTSKXJLK3nq4328nJlPTb2fmeMG863LRpCaMsDraCJhT0UvHWpzwRH++FE2f9laRFREBF+ZlMC9lw5nVLwW+BDpLCp6aXfOOT7afYg/fpTN2uxS+nSPYv6lI7n7ohQG9+3hdTyRLkdFL+2mrsHPG5sKWbAqm50HjjKkbw9+NHsct0xJ0gLbIh5S0csZO1ZTz4sZeSxcvY/C8mrGDO7Nr26ayHUTh9EtSmewinhNRS+nrfRYDc+syWHR2hwqqutJGz6AX3xlAtPHxGsGjUgQUdHLKSsqP86Tq/axNCOP6voGrhw/hG9eNoJJvv5eRxORVqjoJWA5JZU88dFeXtlQgN/BnPOG8e3pIzWDRiTIqeilTTsPVPC/H+7lzc2FREVGcMsFPuZfOoKkAVqDVSQUqOjlpD7LO8zjH+7l/R0H6dUtknsvGcE3LhlOfB9NkRQJJW0WvZktBK4Bip1zE1p5fDrwOrCvadOrzrmftWdI6TzOOdbuLeXxv2axJquU2J7RPDhzNHdNS6FfTDev44nIaQhkRP8s8Biw6B/s87Fz7pp2SSSecM6xckcxj32Yxcb8Iwzq050fzR7H3DQfvbvrH34ioazN32Dn3CozS+n4KOKFBr/jrS1F/O+HWew8cJTE/j35xfUTuHFyoq4iKRIm2muodqGZbQIKgX92zm1rbSczmw/MB/D5fO301nI66hv8/Pmz/Tz+YRY5pVWMiu/NI19rPMkpSsv0iYSV9ij6DUCyc+6Ymc0GXgNGt7ajc24BsAAgNTXVtcN7yyn6vOAf+zCL3NIqJiT05YnbzueK8UN0kpNImDrjonfOVTS7vcLM/tfM4pxzJWf62tJ+6hv8vLaxkN9/sOdvBf/UHalcPi5e67CKhLkzLnozGwIcdM45M5sCRAClZ5xM2kXLgj97WF+evCOVmSp4kS4jkOmVS4HpQJyZFQA/AaIBnHNPADcC95lZPXAcuMU5p8MyHlPBi8jnApl1M7eNxx+jcfqlBIH6Bj+vNxV8jgpeRNCZsWGjZcGPH9qXBbdPZtb4wSp4kS5ORR/i/H7Hm1uK+M17u9lXUqmCF5ETqOhDlHOOv+46xP+8s4vtRRWMHdKHP94+mStU8CLSgoo+BGXmlPH/3t5FRk4ZvgEx/Pbm87hu4jDNgxeRVqnoQ8iOogr+551dfLCzmEF9uvPzOWdz8wU+LdcnIv+Qij4E5JZW8sh7u1m+qZA+3aP416vO4q5pKcR0038+EWmbmiKIFVdU87sP9vBiRj5Rkca3LhvJty4dSWxMtNfRRCSEqOiDUGVNPX9clc2CVXupb3DMneLjgRmjiO+rBT9E5NSp6INIg9/xyvoCfvXuLoqP1nDNuUP5lyvPInlgL6+jiUgIU9EHiTVZJfzirR3sKKpgkq8ff7htMpOT+3sdS0TCgIreY1nFx/ivFTtYubOYxP49+f3cSVxz7lDNhReRdqOi90hZZS2Pvr+bF9LziImO5PtXj+WuaSla1UlE2p2KvpPVNfh57pMcHl25h6raBuZOSeLBmWOI693d62giEqZU9J1oTVYJP12+jT3Fx7hszCD+7cvjGD24j9exRCTMqeg7wf4jx/nPt7azYssBfANitLKTiHQqFX0Hqqlv4MlV2Tz2YRYAD88aw72XjtBxeBHpVCr6DvJJVgn/9tpWsksqmX3OEH705fEk9OvpdSwR6YJU9O2s5FgN//nWDv782X58A2J47utTuGzMIK9jiUgXpqJvJ845Xtu4n58u305VbT0PzBjF/V8apcM0IuI5FX07OHS0hh/9eQvvbj/I5OT+/PKr5zAqXrNpRCQ4qOjP0Fubi/i317ZQWdvAD2eP5RsXjyBSC4CISBBR0Z+mw5W1/PvrW3lzcxHnJsby65smak68iAQlFf1pWLX7EA+9vIny47U8PGsM900fSVSkVnkSkeDUZjuZ2UIzKzazrSd53Mzsd2aWZWabzez89o8ZHOob/PzPOzu585kMBvSK5vX7L+aBy0er5EUkqAUyon8WeAxYdJLHrwZGN/2kAX9o+jOsFJUf57tLN5KRU8bNqUn89Lqz6dlNM2pEJPi1WfTOuVVmlvIPdpkDLHLOOWCdmfUzs6HOuaJ2yui5D3cV89BLG6mp9/Pbm8/j+kkJXkcSEQlYexyjTwDym90vaNoW8kVf1+DnV+/u4o8fZTNuaF8ev3USIwb19jqWiMgpaY+ib20uoWt1R7P5wHwAn8/XDm/dcQ4dreH+xRvIyCljXpqPf79mvE5+EpGQ1B5FXwAkNbufCBS2tqNzbgGwACA1NbXV/xkEg80FR/jm8+s5XFXLo7ecx5zzdKhGREJXe0wXWQ7c0TT7ZipQHsrH51/dUMCNT6wlwoxl35qmkheRkNfmiN7MlgLTgTgzKwB+AkQDOOeeAFYAs4EsoAq4u6PCdiS/3/Hfb+9kwapspo4YwOO3ns9ArfokImEgkFk3c9t43AH3t1siD1TXNfDwnzbx1uYibp+azI+vHU+05saLSJjo8mfGHqmqZf6i9WTklPHD2WO595IRWvlJRMJKly76/LIq7nomg/yy4/xu7iSumzjM60giIu2uyxb9noNHmfdUOtV1DSz6xhSmjhjodSQRkQ7RJYt+54EK5j2ZTkSEsey+aYzRVSdFJIx1uaLfVljObU+l0z0qkiX3pulMVxEJe12q6LcUlHPb0+n06hbJ0vlTSR7Yy+tIIiIdrssU/Wd5h7ljYQaxPaNZeu9UkgbEeB1JRKRTdImiX59bxp0LP2Vg724suXcqCf16eh1JRKTThH3Rby44wp0LPyW+T3eW3DuVIbE9vI4kItKpwvr0z90Hj3Lnwgz6xUSz+N40lbyIdElhW/S5pZXc9lQ60ZERLL4njaGxOlwjIl1TWBa93+/49uIN1DX4eeGeNM2uEZEuLSyL/u1tB9hWWMGPrx2vk6FEpMsLu6Jv8Dt+895uRsX35rqJupa8iEjYFf0bmwrZU3yMB2eOJjJCV6EUEQmroq9v8PPoyj2MHdKH2ROGeh1HRCQohFXRv/rZfvaVVPLQrDFEaDQvIgKEUdHX1vt59P09nJsYy6zxg72OIyISNMKm6F/OzGf/keM8NGuMVogSEWkmLIq+uq6Bxz7IYnJyfy4bM8jrOCIiQSUsin5pRh4HKqp5WKN5EZEThHzRH69t4PEP93LhiIFMGxXndRwRkaAT8kW/aG0OJcdqePiKMV5HEREJSiFd9Mdq6nnio71cOmYQqSkDvI4jIhKUAip6M7vKzHaZWZaZfb+Vx+8ys0NmtrHp5572j3qiZ1bv43BVHQ/N0mheRORk2lx4xMwigceBWUAB8KmZLXfObW+x60vOue90QMZWlR+v48mPs5k5bjDnJfXrrLcVEQk5gYzopwBZzrls51wt8CIwp2Njte3pj7OpqK7XaF5EpA2BFH0CkN/sfkHTtpa+amabzWyZmSW19kJmNt/MMs0s89ChQ6cRt1FZZS0L1+Qw+5whjB/W97RfR0SkKwik6FubmO5a3H8DSHHOnQu8DzzX2gs55xY451Kdc6mDBp3+iU1/XLWXytp6vjdTo3kRkbYEUvQFQPMReiJQ2HwH51ypc66m6e6TwOT2iXeiQ0drWPRJLnMmDmO0FhUREWlTIEX/KTDazIabWTfgFmB58x3MrPk1ga8DdrRfxL/3h7/upbbBz3c1mhcRCUibs26cc/Vm9h3gHSASWOic22ZmPwMynXPLgX8ys+uAeqAMuKsjwhaVH+eF9Fy+en4Cw+O0DqyISCDaLHoA59wKYEWLbT9udvsHwA/aN9qJHv8wC+ccD8wY3dFvJSISNkLmzNiCw1W89Gk+X0tNImlAjNdxRERCRsgU/e9XZmFmfGfGKK+jiIiElJAo+pySSpZtKGBemo+hsT29jiMiElJCougfXbmH6EjjvukjvY4iIhJygr7o9xw8ymsb93PnhSnE9+nhdRwRkZAT9EX/2/f3EBMdyTcv02heROR0BHXRby+s4K0tRXz94uEM6NXN6zgiIiEpqIv+N+/vpk+PKO65eITXUUREQlbQFv3mgiO8t/0g8y8ZQWxMtNdxRERCVtAW/a/f3U3/mGjuvni411FEREJaUBb9+twyPtp9iG9eNpLe3QO6SoOIiJxEUBb9r9/dTVzvbtxxYbLXUUREQl7QFf0ne0v4ZG8p354+iphuGs2LiJypoCp65xyPvLubIX17cGuaz+s4IiJhIaiKftWeEjJzD3P/jFH0iI70Oo6ISFgImqJvHM3vIqFfT25ObXVtcREROQ1BU/Tv7yhmU0E53718NN2igiaWiEjIC4pG9fsdj7y3m5SBMdxwfoLXcUREwkpQFP3b2w6wo6iCB2eOISoyKCKJiIQNz1u1oWk0Pzq+N9dOHOZ1HBGRsON50b+xqZCs4mM8OHMMkRHmdRwRkbDjadHXN/h5dOUexg7pw9UThngZRUQkbHla9K9+tp99JZU8fMVZRGg0LyLSITwreufg0ff3MDExlpnj4r2KISIS9gIqejO7ysx2mVmWmX2/lce7m9lLTY+nm1lKW695uKqW/UeO871ZYzDTaF5EpKO0WfRmFgk8DlwNjAfmmtn4Frt9AzjsnBsF/Ab4ZVuvW1xRQ2pyfy4bM+jUU4uISMACGdFPAbKcc9nOuVrgRWBOi33mAM813V4GXG5tDNPr/H4eukKjeRGRjhZI0ScA+c3uFzRta3Uf51w9UA4MbPlCZjbfzDLNLLNnhJ9pI+NOL7WIiAQskKJvbcjtTmMfnHMLnHOpzrnUUUP7B5JPRETOUCBFXwA0v5xkIlB4sn3MLAqIBcraI6CIiJyZQIr+U2C0mQ03s27ALcDyFvssB+5sun0j8IFz7oQRvYiIdL421+pzztWb2XeAd4BIYKFzbpuZ/QzIdM4tB54GnjezLBpH8rd0ZGgREQlcQIuyOudWACtabPtxs9vVwE3tG01ERNqD5xc1ExGRjqWiFxEJcyp6EZEwp6IXEQlz5tUsSDM7Cuzy5M2DTxxQ4nWIIKHP4gv6LL6gz+ILZznn+pzKEwKaddNBdjnnUj18/6BhZpn6LBrps/iCPosv6LP4gpllnupzdOhGRCTMqehFRMKcl0W/wMP3Djb6LL6gz+IL+iy+oM/iC6f8WXj2ZayIiHQOHboREQlzKnoRkTDnSdG3tdh4V2FmSWb2oZntMLNtZvZdrzN5ycwizewzM3vT6yxeM7N+ZrbMzHY2/f240OtMXjGz7zX9fmw1s6Vm1sPrTJ3FzBaaWbGZbW22bYCZvWdme5r+bHMVp04v+gAXG+8q6oGHnXPjgKnA/V34swD4LrDD6xBB4lHgbefcWGAiXfRzMbME4J+AVOfcBBovld6VLoP+LHBVi23fB1Y650YDK5vu/0NejOgDWWy8S3DOFTnnNjTdPkrjL3PL9Xi7BDNLBL4MPOV1Fq+ZWV/gUhrXecA5V+ucO+JtKk9FAT2bVq+L4cQV7sKWc24VJ67WNwd4run2c8D1bb2OF0UfyGLjXY6ZpQCTgHRvk3jmt8C/An6vgwSBEcAh4JmmQ1lPmVkvr0N5wTm3H/gVkAcUAeXOuXe9TeW5wc65ImgcLALxbT3Bi6IPaCHxrsTMegOvAA865yq8ztPZzOwaoNg5t97rLEEiCjgf+INzbhJQSQD/PA9HTcef5wDDgWFALzO7zdtUoceLog9ksaInyLsAAAEjSURBVPEuw8yiaSz5xc65V73O45GLgOvMLIfGQ3kzzOwFbyN5qgAocM59/q+7ZTQWf1c0E9jnnDvknKsDXgWmeZzJawfNbChA05/FbT3Bi6IPZLHxLsHMjMbjsDucc494nccrzrkfOOcSnXMpNP59+MA512VHbc65A0C+mZ3VtOlyYLuHkbyUB0w1s5im35fL6aJfTDezHLiz6fadwOttPaHTr155ssXGOztHkLgIuB3YYmYbm7b9sGmNXunaHgAWNw2GsoG7Pc7jCedcupktAzbQOEvtM7rQ5RDMbCkwHYgzswLgJ8B/Ay+b2Tdo/B9hm+t16xIIIiJhTmfGioiEORW9iEiYU9GLiIQ5Fb2ISJhT0YuIhDkVvYhImFPRi4iEuf8PNFU+czHK+nAAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "from HARK.utilities import plotFuncs\n", + "plotFuncs([LifecycleExample.solution[0].cFunc],LifecycleExample.solution[0].mNrmMin,10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us then create a solver for the first period." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from HARK.ConsumptionSaving.ConsIndShockModel import ConsIndShockSolverBasic\n", + "solver = ConsIndShockSolverBasic(LifecycleExample.solution[1],\n", + " LifecycleExample.IncomeDstn[0],\n", + " LifecycleExample.LivPrb[0],\n", + " LifecycleExample.DiscFac,\n", + " LifecycleExample.CRRA,\n", + " LifecycleExample.Rfree,\n", + " LifecycleExample.PermGroFac[0],\n", + " LifecycleExample.BoroCnstArt,\n", + " LifecycleExample.aXtraGrid,\n", + " LifecycleExample.vFuncBool,\n", + " LifecycleExample.CubicBool)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "solver.prepareToSolve()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Many important values are now calculated and stored in solver, such as the effective discount factor, the smallest permanent income shock, and more." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.9503999999999999" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solver.DiscFacEff" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.850430160026919" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solver.PermShkMinNext" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These values were calculated in `setAndUpdateValues`. In `defBoroCnst` that was also called, several things were calculated, for example the consumption function defined by the borrowing constraint." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plotFuncs([solver.cFuncNowCnst],solver.mNrmMinNow,10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we set up all the grids, grabs the discrete shock distributions, and state grids in `prepareToCalcEndOfPrdvP`." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-2.49175086e-01, -2.30003713e-01, -2.09710489e-01, -1.88206151e-01,\n", + " -1.65392397e-01, -1.41160763e-01, -1.15391357e-01, -8.79513885e-02,\n", + " -5.86934916e-02, -2.74537788e-02, 5.95040319e-03, 4.17230788e-02,\n", + " 8.00926738e-02, 1.21315551e-01, 1.65680145e-01, 2.13511821e-01,\n", + " 2.65178592e-01, 3.21097879e-01, 3.81744527e-01, 4.47660342e-01,\n", + " 5.19465496e-01, 5.97872200e-01, 6.83701170e-01, 7.77901553e-01,\n", + " 8.81575133e-01, 9.96005867e-01, 1.12269613e+00, 1.26341136e+00,\n", + " 1.42023542e+00, 1.59563952e+00, 1.79256862e+00, 2.01455026e+00,\n", + " 2.26583269e+00, 2.55156109e+00, 2.87800413e+00, 3.25284719e+00,\n", + " 3.68557479e+00, 4.18797327e+00, 4.77479697e+00, 5.46465892e+00,\n", + " 6.28123238e+00, 7.25488755e+00, 8.42494379e+00, 9.84280193e+00,\n", + " 1.15763503e+01, 1.37162363e+01, 1.63849084e+01, 1.97498249e+01])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solver.prepareToCalcEndOfPrdvP()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we calculate the marginal utility of next period's resources given the stochastic environment and current grids." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "EndOfPrdvP = solver.calcEndOfPrdvP()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we essentially just have to construct the (resource, consumption) pairs by completing the EGM step, and constructing the interpolants by using the knowledge that the limiting solutions are those of the perfect foresight model. This is done with `makeBasicSolution` as discussed above." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "solution = solver.makeBasicSolution(EndOfPrdvP,solver.aNrmNow,solver.makeLinearcFunc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lastly, we add the MPC and human wealth quantities we calculated in the method that prepared the solution of this period." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solver.addMPCandHumanWealth(solution)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All that is left is to verify that the solution in `solution` is identical to `LifecycleExample.solution[0]`. We can plot the against each other:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plotFuncs([LifecycleExample.solution[0].cFunc, solution.cFunc],LifecycleExample.solution[0].mNrmMin,10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Although, it's probably even clearer if we just subtract the function values from each other at some grid." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "eval_grid = np.linspace(0, 20, 200)\n", + "LifecycleExample.solution[0].cFunc(eval_grid) - solution.cFunc(eval_grid)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "@webio": { + "lastCommId": null, + "lastKernelId": null + }, + "hide_input": false, + "jupytext": { + "formats": "ipynb,py:light" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/HowWeSolveIndShockConsumerType/HoweWeSolveIndShockConsumerType.py b/examples/HowWeSolveIndShockConsumerType/HoweWeSolveIndShockConsumerType.py new file mode 100644 index 000000000..e12ee3bb7 --- /dev/null +++ b/examples/HowWeSolveIndShockConsumerType/HoweWeSolveIndShockConsumerType.py @@ -0,0 +1,165 @@ +# --- +# jupyter: +# jupytext: +# formats: ipynb,py:light +# text_representation: +# extension: .py +# format_name: light +# format_version: '1.4' +# jupytext_version: 1.2.4 +# kernelspec: +# display_name: Python 3 +# language: python +# name: python3 +# --- + +# # How we solve a model defined by the `IndShockConsumerType` class +# The IndShockConsumerType reprents the work-horse consumption savings model with temporary and permanent shocks to income, finite or infinite horizons, CRRA utility and more. In this DemARK we take you through the steps involved in solving one period of such a model. The inheritance chains can be a little long, so figuring out where all the parameters and methods come from can be a bit confusing. Hence this map! The intention is to make it easier to know how to inheret from IndShockConsumerType in the sense that you know where to look for specific solver logic, but also so you know can figure out which methods to overwrite or supplement in your own `AgentType` and solver! +# ## The `solveConsIndShock` function +# In HARK, a period's problem is always solved by the callable (function or callable object instance) stored in the field `solveOnePeriod`. In the case of `IndShockConsumerType`, this function is called `solveConsIndShock`. The function accepts a number of arguments, that it uses to construct an instance of either a `ConsIndShockSolverBasic` or a `ConsIndShockSolver`. These solvers both have the methods `prepareToSolve` and `solve`, that we will have a closer look at in this notebook. This means, that the logic of `solveConsIndShock` is basically: +# +# 1. Check if cubic interpolation (`CubicBool`) or construction of the value function interpolant (`vFuncBool`) are requested. Construct an instance of `ConsIndShockSolverBasic` if neither are requested, else construct a `ConsIndShockSolver`. Call this `solver`. +# 1. Call `solver.prepareToSolve()` +# 1. Call `solver.solve()` and return the output as the current solution. + +# ### Two types of solvers +# As mentioned above, `solveOnePeriod` will construct an instance of the class `ConsIndShockSolverBasic`or `ConsIndShockSolver`. The main difference is whether it uses cubic interpolation or if it explicitly constructs a value function approximation. The choice and construction of a solver instance is bullet 1) from above. +# +# #### What happens in upon construction +# Neither of the two solvers have their own `__init__`. `ConsIndShockSolver` inherits from `ConsIndShockSolverBasic` that in turn inherits from `ConsIndShockSetup`. `ConsIndShockSetup` inherits from `ConsPerfForesightSolver`, which itself is just an `Object`, so we get the inheritance structure +# +# - `ConsPerfForesightSolver` $\leftarrow$ `ConsIndShockSetup` $\leftarrow$ `ConsIndShockSolverBasic` $\leftarrow$ `ConsIndShockSolver` +# +# When one of the two classes in the end of the inheritance chain is called, it will call `ConsIndShockSetup.__init__(args...)`. This takes a whole list of fixed inputs that then gets assigned to the object through a +# ``` +# ConsIndShockSetup.assignParameters(solution_next,IncomeDstn,LivPrb,DiscFac,CRRA,Rfree,PermGroFac,BoroCnstArt,aXtraGrid,vFuncBool,CubicBool) +# ``` +# call, that then calls +# ``` +# ConsPerfForesightSolver.assignParameters(self,solution_next,DiscFac,LivPrb,CRRA,Rfree,PermGroFac) +# ``` +# We're getting kind of detailed here, but it is simply to help us understand the inheritance structure. The methods are quite straight forward, and simply assign the list of variables to self. The ones that do not get assigned by the `ConsPerfForesightSolver` method gets assign by the `ConsIndShockSetup` method instead. +# +# +# After all the input parameters are set, we update the utility function definitions. Remember, that we restrict ourselves to CRRA utility functions, and these are parameterized with the scalar we call `CRRA` in HARK. We use the two-argument CRRA utility (and derivatives, inverses, etc) from `HARK.utilities`, so we need to create a `lambda` (an anonymous function) according to the fixed `CRRA` we have chosen. This gets done through a call to +# +# ``` +# ConsIndShockSetup.defUtilityFuncs() +# ``` +# that itself calls +# ``` +# ConsPerfForesightSolver.defUtilityFuncs() +# ``` +# Again, we wish to emphasize the inheritance structure. The method in `ConsPerfForesightSolver` defines the most basic utility functions (utility, its marginal and its marginal marginal), and `ConsIndShockSolver` adds additional functions (marginal of inverse, inverse of marginal, marginal of inverse of marginal, and optionally inverse if `vFuncBool` is true). +# +# To sum up, the `__init__` method lives in `ConsIndShockSetup`, calls `assignParameters` and `defUtilityFuncs` from `ConsPerfForesightSolver` and defines its own methods with the same names that adds some methods used to solve the `IndShockConsumerType` using EGM. The main things controlled by the end-user are whether cubic interpolation should be used, `CubicBool`, and if the value function should be explicitly formed, `vFuncBool`. +# ### Prepare to solve +# We are now in bullet 2) from the list above. The `prepareToSolve` method is all about grabbing relevant information from next period's solution, calculating some limiting solutions. It comes from `ConsIndShockSetup` and calls two methods: +# +# 1. `ConsIndShockSetup.setAndUpdateValues(self.solution_next,self.IncomeDstn,self.LivPrb,self.DiscFac)` +# 2. `ConsIndShockSetup.defBoroCnst(self.BoroCnstArt)` +# +# First, we have `setAndUpdateValues`. The main purpose is to grab the relevant vectors that represent the shock distributions, the effective discount factor, and value function (marginal, level, marginal marginal depending on the options). It also calculates some limiting marginal propensities to consume and human wealth levels. Second, we have `defBoroCnst`. As the name indicates, it calculates the natural borrowing constraint, handles artificial borrowing constraints, and defines the consumption function where the constraint binds (`cFuncNowCnst`). +# +# To sum, `prepareToSolve` sets up the stochastic environment an borrowing constraints the consumer might face. It also grabs interpolants from "next period"'s solution. +# +# ### Solve it! +# The last method `solveConsIndShock` will call from the `solver` is `solve`. This method essentially has four steps: +# 1. Pre-processing for EGM: solver.prepareToCalcEndOfPrdvP +# 1. First step of EGM: solver.calcEndOfPrdvP +# 1. Second step of EGM: solver.makeBasicSolution +# 1. Add MPC and human wealth: solver.addMPCandHumanWealth +# +# #### Pre-processing for EGM `prepareToCalcEndOfPrdvP` +# Find relevant values of end-of-period asset values (according to `aXtraGrid` and natural borrowing constraint) and next period values implied by current period end-of-period assets and stochastic elements. The method stores the following in `self`: +# +# 1. values of permanent shocks in `PermShkVals_temp` +# 1. shock probabilities in `ShkPrbs_temp` +# 1. next period resources in `mNrmNext` +# 1. current grid of end-of-period assets in `aNrmNow` +# +# The method also returns `aNrmNow`. The definition is in `ConsIndShockSolverBasic` and is not overwritten in `ConsIndShockSolver`. +# +# #### First step of EGM `calcEndOfPrdvP` +# Find the marginal value of having some level of end-of-period assets today. End-of-period assets as well as stochastics imply next-period resources at the beginning of the period, calculated above. Return the result as `EndOfPrdvP`. +# +# #### Second step of EGM `makeBasicSolution` +# Apply inverse marginal utility function to nodes from about to find (m, c) pairs for the new consumption function in `getPointsForInterpolation` and create the interpolants in `usePointsForInterpolation`. The latter constructs the `ConsumerSolution` that contains the current consumption function `cFunc`, the current marginal value function `vPfunc`, and the smallest possible resource level `mNrmMinNow`. +# +# #### Add MPC and human wealth `addMPCandHumanWealth` +# Add values calculated in `defBoroCnst` now that we have a solution object to put them in. +# +# #### Special to the non-Basic solver +# We are now done, but in the `ConsIndShockSolver` (non-`Basic`!) solver there are a few extra steps. We add steady state m, and depending on the values of `vFuncBool` and `CubicBool` we also add the value function and the marginal marginal value function. + +# # Let's try it in action! +# First, we define a standard lifecycle model, solve it and then + +import HARK.ConsumptionSaving.ConsumerParameters as Params +from HARK.ConsumptionSaving.ConsIndShockModel import IndShockConsumerType +import numpy as np +import matplotlib.pyplot as plt +LifecycleExample = IndShockConsumerType(**Params.init_lifecycle) +LifecycleExample.cycles = 1 # Make this consumer live a sequence of periods exactly once +LifecycleExample.solve() + +# Let's have a look at the solution in time period second period. We should then be able to + +from HARK.utilities import plotFuncs +plotFuncs([LifecycleExample.solution[0].cFunc],LifecycleExample.solution[0].mNrmMin,10) + +# Let us then create a solver for the first period. + +from HARK.ConsumptionSaving.ConsIndShockModel import ConsIndShockSolverBasic +solver = ConsIndShockSolverBasic(LifecycleExample.solution[1], + LifecycleExample.IncomeDstn[0], + LifecycleExample.LivPrb[0], + LifecycleExample.DiscFac, + LifecycleExample.CRRA, + LifecycleExample.Rfree, + LifecycleExample.PermGroFac[0], + LifecycleExample.BoroCnstArt, + LifecycleExample.aXtraGrid, + LifecycleExample.vFuncBool, + LifecycleExample.CubicBool) + +solver.prepareToSolve() + +# Many important values are now calculated and stored in solver, such as the effective discount factor, the smallest permanent income shock, and more. + +solver.DiscFacEff + +solver.PermShkMinNext + +# These values were calculated in `setAndUpdateValues`. In `defBoroCnst` that was also called, several things were calculated, for example the consumption function defined by the borrowing constraint. + +plotFuncs([solver.cFuncNowCnst],solver.mNrmMinNow,10) + +# Then, we set up all the grids, grabs the discrete shock distributions, and state grids in `prepareToCalcEndOfPrdvP`. + +solver.prepareToCalcEndOfPrdvP() + +# Then we calculate the marginal utility of next period's resources given the stochastic environment and current grids. + +EndOfPrdvP = solver.calcEndOfPrdvP() + +# Then, we essentially just have to construct the (resource, consumption) pairs by completing the EGM step, and constructing the interpolants by using the knowledge that the limiting solutions are those of the perfect foresight model. This is done with `makeBasicSolution` as discussed above. + +solution = solver.makeBasicSolution(EndOfPrdvP,solver.aNrmNow,solver.makeLinearcFunc) + +# Lastly, we add the MPC and human wealth quantities we calculated in the method that prepared the solution of this period. + +solver.addMPCandHumanWealth(solution) + +# All that is left is to verify that the solution in `solution` is identical to `LifecycleExample.solution[0]`. We can plot the against each other: + +plotFuncs([LifecycleExample.solution[0].cFunc, solution.cFunc],LifecycleExample.solution[0].mNrmMin,10) + +# Although, it's probably even clearer if we just subtract the function values from each other at some grid. + +eval_grid = np.linspace(0, 20, 200) +LifecycleExample.solution[0].cFunc(eval_grid) - solution.cFunc(eval_grid) + + + +