<jupyter_start><jupyter_text>Durable Consumption Model This notebooks shows you how to use the tools of the **consav** package to solve a **durable consumption model** with either1. **vfi**: standard value function iteration (written in C++)* **nvfi**: nested value function iteration (writen in Python, or **nvfi_cpp** is written i C++)* **negm**: nested endogenous grid point method (writen in Python, or **negm_cpp** is written i C++)The implemented solution methods are explained in detail in [A Guide to Solve Non-Convex Consumption-Saving Model](http://web.econ.ku.dk/druedahl/papers/2019_NEGM.pdf).  Model equations The **states** are:1. the persistent component of income, $p_t$2. stock of the durable good, $n_t$3. cash-on-hand, $m_t$The **choices** are:1. durable consumption, $d_t$2. non-durable consumption, $c_t$**Utility** is CRRA over a Cobb-Douglas aggregate:$$ u(c_{t},d_{t})=\frac{(c_{t}^{\alpha}(d_{t}+\underline{d})^{1-\alpha})^{1-\rho}}{1-\rho} $$**Income** follows a persistent-transitory process:$$\begin{eqnarray*}p_{t+1}&=&\psi_{t+1}p_{t}^{\lambda},\,\,\,\log\psi_{t+1}\sim\mathcal{N}(-0.5\sigma_{\psi}^{2},\sigma_{\psi}^{2}) \\ y_{t+1}&=&\xi_{t+1}p_{t+1},\,\,\,\log\xi_{t+1}\sim\mathcal{N}(-0.5\sigma_{\xi}^{2},\sigma_{\xi}^{2})\end{eqnarray*} $$The household **cannot borrow** and the **interest rate** on savings is $r$. Adjusting the stock of durables is subject to a **proportional adjustment cost** $\tau$ and **durables depreciates** with a rate of $\delta$.$$ n_{t+1}=(1-\delta)d_{t} $$The **bellman equation** is$$\begin{eqnarray*}v_{t}(p_{t},n_{t},m_{t})&=&\max\{v_{t}^{keep}(p_{t},n_{t},m_{t}),v_{t}^{adj.}(p_{t},x_{t})\}\\&\text{s.t.}&\\x_{t}&=&m_{t}+(1-\tau)n_{t}\end{eqnarray*} $$ where $$\begin{eqnarray*}v_{t}^{keep}(p_{t},n_{t},m_{t})&=&\max_{c_{t}}u(c_{t},n_{t})+\beta\mathbb{E}_{t}[v_{t+1}(p_{t+1},n_{t+1},m_{t+1})]\\&\text{s.t.}&\\a_{t}&=&m_{t}-c_{t}\\m_{t+1}&=&(1+r)a_{t}+y_{t+1}\\n_{t+1}&=&(1-\delta)n_{t}\\a_{t}&\geq&0\end{eqnarray*} $$and $$\begin{eqnarray*}v_{t}^{adj.}(p_{t},x_{t})&=&\max_{c_{t},d_{t}}u(c_{t},d_{t})+\beta\mathbb{E}_{t}[v_{t+1}(p_{t+1},n_{t+1},m_{t+1})]\\&\text{s.t.}&\\a_{t}&=&x_{t}-c_{t}-d_{t}\\m_{t+1}&=&(1+r)a_{t}+y_{t+1}\\ n_{t+1}&=&(1-\delta)n_{t}\\a_{t}&\geq&0\end{eqnarray*} $$  Overview The model solved in this notebook is written in **DurableConsumptionModelModel.py**. It provides a class called **DurableConsumptionModelClass** inheriting its basic interface from the **ModelClass**. A short **overview** of the interface is:1. Each instance of the BufferStockModel class must have a **name** and a **solmethod** * The **save()** method saves the model naming it **data/name_solmethod*** Three lists must be defined in the initialization:  1. **parlist**; parameters, grids, etc. (model.par)  2. **sollist**; solution variables (model.sol)  3. **simlist**; simulation variables (model.sim)* The **setup()** method defines baseline parameters* The **setup_grids()** method constructs grids for states and shocks* The **solve()** method solves the model* The **simulate()** method simulates the modelIn addition to **DurableConsumptionModel.py**, this folder contains the following files:1. **last_period.py**: calculate consumption and value function in last period* **utility.py**: utility function and marginal utility function* **trans.py**: state transition functions* **post_decision.py**: calcualte $w$ and $q$* **nvfi.py**: solve with nested value function iteration* **negm.py**: solve with the nested endogenous grid method* **simulate.py**: simulate for all solution methods* **figs.py**: plot figures* **tabs.py**: prints tables in .tex filesThe functions in these modules are loaded in **DurableConsumptionModel.py**.The folder **cppfuncs** contains C++ functions used for solving with **vfi**, **nvfi_cpp** or **negm_cpp**.  Numba Before (important!) you load **Numba** you can disable it or choose the numbe of threads as follows:<jupyter_code>from consav import runtools
runtools.write_numba_config(disable=0,threads=8)<jupyter_output><empty_output><jupyter_text>Setup<jupyter_code>import time
import numpy as np

%matplotlib inline

# reload module each time cell is run
%load_ext autoreload
%autoreload 2

# load the BufferStockModel module
from DurableConsumptionModel import DurableConsumptionModelClass<jupyter_output><empty_output><jupyter_text>Choose number of periods to solve:<jupyter_code>T = 5<jupyter_output><empty_output><jupyter_text>NVFI - nested value function iteration Define the **post-decision value function** as$$ w_{t}(p_{t},n_{t},a_{t}) = \beta \mathbb{E}_{t}[v_{t+1}(m_{t+1},n_{t+1},p_{t+1})] $$The **keeper problem** can then be written:$$\begin{eqnarray*}v_{t}^{keep}(p_{t},n_{t},m_{t})&=&\max_{c_{t}}u(c_{t},n_{t})+ w_{t}(p_{t},n_{t},a_{t})]\\&\text{s.t.}&\\a_{t}&=&m_{t}-c_{t}\geq0\end{eqnarray*}$$The **adjuster problem** can further be written:$$\begin{eqnarray*}v_{t}^{adj.}(x_{t})&=&\max_{d_{t}}v_{t}^{keep}(p_{t},d_{t},n_{t})\\&\text{s.t.}&\\m_{t}&=&x_{t}-d_{t}\end{eqnarray*}$$**NVFI** solves this reformulated problem.<jupyter_code>model_nvfi = DurableConsumptionModelClass(name='example',solmethod='nvfi',T=T,do_print=True)
model_nvfi.precompile_numba() # solve with very coarse grids
model_nvfi.solve()
model_nvfi.simulate()
model_nvfi.save()<jupyter_output>numba precompiled in 10.0 secs
 t = 4 solved in 0.0 secs
  w computed in 0.1 secs
  solved keeper problem in 0.3 secs
  solved adjuster problem in 0.0 secs
 t = 3 solved in 0.4 secs
  w computed in 0.1 secs
  solved keeper problem in 0.3 secs
  solved adjuster problem in 0.0 secs
 t = 2 solved in 0.3 secs
  w computed in 0.1 secs
  solved keeper problem in 0.3 secs
  solved adjuster problem in 0.0 secs
 t = 1 solved in 0.3 secs
  w computed in 0.1 secs
  solved keeper problem in 0.3 secs
  solved adjuster problem in 0.1 secs
 t = 0 solved in 0.4 secs
model simulated in 0.3 secs
euler errors calculated in 0.0 secs
utility calculated in 0.0 secs<jupyter_text>**Plot** interactive decision functions:<jupyter_code>model_nvfi.decision_functions()<jupyter_output><empty_output><jupyter_text>**Plot** life-cycle profiles:<jupyter_code>model_nvfi.lifecycle()<jupyter_output><empty_output><jupyter_text>NEGM - nested endogenous grid method Define the **post-decision marginal value of cash:**$$\begin{eqnarray*}q_{t}(p_{t},d_{t},a_{t})&=&\beta R\mathbb{E}_{t}[u_{c}(c_{t+1},d_{t+1})]\\&=&\beta R\mathbb{E}_{t}[\alpha c_{t+1}^{\alpha(1-\rho)-1}d_{t+1}^{(1-\alpha)(1-\rho)}]\end{eqnarray*}$$Note that all optimal interior consumption choices must satisfy the **Euler-equation**$$\begin{eqnarray*}u_{c}(c_{t},d_{t})=\alpha c_{t}^{\alpha(1-\rho)-1}d_{t}^{(1-\alpha)(1-\rho)}&=q(p_{t},d_{t},a_{t})\end{eqnarray*}$$This implies that we have an analytical mapping from the post-decision space $(p_t,d_t,a_t)$ to consumption and cash-on-hand $(c_t,m_t)$:$$\begin{eqnarray*}c_{t} &=&=\frac{1}{\alpha}\left(\frac{q(a_{t},d_{t},p_{t})}{d_{t}^{(1-\alpha)(1-\rho)}}\right)^{\alpha(1-\rho)-1}\\m_{t} &=&a_{t}+c_{t}\end{eqnarray*}$$**NEGM** uses this mapping (and an upperenvelope algorithm) to solve the keeper problem much faster.<jupyter_code>model_negm = DurableConsumptionModelClass(name='example',solmethod='negm',T=T,do_print=True)
model_negm.precompile_numba() # solve with very coarse grids
model_negm.solve()
model_negm.simulate()
model_negm.save()<jupyter_output>numba precompiled in 9.6 secs
 t = 4 solved in 0.0 secs
  w computed in 0.2 secs
  solved keeper problem in 0.0 secs
  solved adjuster problem in 0.0 secs
 t = 3 solved in 0.2 secs
  w computed in 0.1 secs
  solved keeper problem in 0.0 secs
  solved adjuster problem in 0.0 secs
 t = 2 solved in 0.1 secs
  w computed in 0.1 secs
  solved keeper problem in 0.0 secs
  solved adjuster problem in 0.0 secs
 t = 1 solved in 0.1 secs
  w computed in 0.1 secs
  solved keeper problem in 0.0 secs
  solved adjuster problem in 0.0 secs
 t = 0 solved in 0.1 secs
model simulated in 0.2 secs
euler errors calculated in 0.0 secs
utility calculated in 0.0 secs<jupyter_text>**Plot** interactive decision functions:<jupyter_code>model_negm.decision_functions()<jupyter_output><empty_output><jupyter_text>**Plot** life-cycle profiles:<jupyter_code>model_negm.lifecycle()<jupyter_output><empty_output><jupyter_text>Compare life-cycles from NVFI and NEGM<jupyter_code>from figs import lifecycle_compare
lifecycle_compare(model_negm,'negm',model_nvfi,'nvfi')<jupyter_output><empty_output><jupyter_text>Compare life-cycle profiles with VFI<jupyter_code>model_vfi = DurableConsumptionModelClass(name='example',solmethod='vfi',T=T,do_print=True) 
model_vfi.precompile_numba() # solve with very coarse grids
model_vfi.solve()
model_vfi.simulate()
model_vfi.save()
lifecycle_compare(model_negm,'negm',model_vfi,'vfi')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1836618434544833, 'fraction_numerical': 0.02016634385325282, 'mean_word_length': 6.451612903225806, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '426890', 'license': 'MIT', 'n_tokens_mistral': 3264, 'n_tokens_neox': 3132, 'n_words': 782, 'path': 'DurableConsumptionModel/DurableConsumptionModel.ipynb', 'repo_name': 'bbardoczy/ConsumptionSavingNotebooks', 'size': '8777'}