Time is discrete and indexed by \(t\). Individuals live for a finite number of periods, \(T\). They derive utility from consumption according to a CRRA utility function:
\[ u(c) = \frac{c^{1-\sigma}}{1-\sigma} \]
and from “bequests”, which are modeled here as cash on hand net of consumption in the final period:
Consumption can be transferred between periods via a portfolio of one-period bonds (“savings’, \(a\)) that can be purchased at the price \(1 / (1+r)\), and there is no borrowing. Inviduals receive income \(y\) every period that is governed by a deterministic (\(\mu_{t}\)) and stochastic component:
\[ \log(y_{t}) = \mu_{t} + \varepsilon_{it} \]
where \(\varepsilon_{it}\) is a stationary AR 1 process:
where \(\eta_{it} \sim \mathcal{N}(0,\sigma^2_{\eta})\). The unconditional variance of \(\varepsilon_{it}\) is therefore \(\sigma^2_{\eta} / (1-\rho^2)\).
We’re going to write code to solve the model naively using this recursive formulation. You may already be aware that there are more efficient solution methods that exploit the first order conditions of the problem. Not the focus of our class! Please don’t use the example below as a demonstration of best practice when it comes to solving savings models.
We’ll start picking some default parameters.
pars = (; T =45, β =0.95, σ =2,ρ =0.9,ση =0.1, μ =fill(2.,45), ψ =5., r =0.05)
Now, let’s think about how to solve this model. We have two state variables to track. We have discretized \(\varepsilon\), now let’s discretize assets and define a max operator.
Ka =100Kϵ =5agrid =LinRange(0,pars.μ[1] * pars.T,Ka) #<- is this a reasonable upper bound? We'll find out!Π,ϵgrid =tauchen(pars.ρ,pars.ση,Kϵ)pars = (;pars...,Ka,agrid,Π,ϵgrid,Kϵ)u(c,σ) = c^(1-σ) / (1-σ)functionsolve_max(V,t,iϵ,ia,pars) (;agrid,ϵgrid,Π,σ,Ka,r,β) = pars cash =exp(pars.μ[t] + ϵgrid[iϵ]) + agrid[ia] amax =0 vmax =-Inf loop =true a =1while loop && a<Ka c = cash - agrid[a] / (1+r)if c>0#@views v = u(c,σ) + β * dot(Π[:,iϵ],V[:,a,t+1]) v =u(c,σ)for iϵ′ inaxes(V,1) v += β * Π[iϵ′,iϵ] * V[iϵ′,a,t+1]endif v>vmax vmax = v amax = aendelse loop =falseend a +=1#<- move one up the grid spaceendreturn amax,vmaxend
solve_max (generic function with 1 method)
Next, a function that uses this max operator to get the value function for all states in a period, \(t\), and records the optimal savings policy.
functioniterate!(V,A,t,pars)for ia inaxes(V,2), iϵ inaxes(V,1) A[iϵ,ia,t],V[iϵ,ia,t] =solve_max(V,t,iϵ,ia,pars)endendfunctionterminal_values!(V,pars) (;σ,ψ,agrid) = parsfor ia inaxes(V,2), iϵ inaxes(V,1) V[iϵ,ia] = ψ *u(agrid[ia],σ)endend
terminal_values! (generic function with 2 methods)
functionbackward_induction!(V,A,pars) (;ψ,σ,T,agrid) = pars# set the values at T+1 (bequest motives)@viewsterminal_values!(V[:,:,T+1],pars)for t inreverse(1:T)iterate!(V,A,t,pars)endend
backward_induction! (generic function with 1 method)
Let’s check the model solution and time it also.
V =zeros(pars.Kϵ,pars.Ka,pars.T+1)A =zeros(Int64,pars.Kϵ,pars.Ka,pars.T)backward_induction!(V,A,pars)@timebackward_induction!(V,A,pars)
0.010476 seconds
Seems ok. We can plot the policy functions as a sanity check. The plot below shows savings policy at the median wage shock over time at different levels of assets.
You can see that the discreteness creates some jumpiness in the policy functions. As I said, other solution methods that use interpolation can be more efficient and will create smoother pictures, but since that is not the focus of this class we will use this simple solution method.