<jupyter_start><jupyter_text>[Aiyagari (1994)](https://doi.org/10.2307/2118417)In this TA session we take a look at the Aiyagari model.<jupyter_code>import numpy as np
from scipy import linalg as la
from scipy import interpolate as ip
from matplotlib import pyplot as plt<jupyter_output><empty_output><jupyter_text>The Aiyagari model is composed of two blocks: a demand side with a unit measure of ex-ante identical households and a supply side with a representative firm.We start with the easiest block, which is the supply one.Consider a firm that rents aggregate capital $K$ and hires aggregate labor $L$ to produce the consumption good $Y$.At every period, the firm decides how much to produce given _constant_ prices $r$ and $w$:\begin{align*}    \max_{Y, K, L} &\; Y - r K - w L \\    \text{s.t.} &\; Y = K^{\alpha} L^{1-\alpha}\end{align*}Note that all variables (including prices) are assumed to be constant over time.The representative firm is assumed to operate in perfect competition (price-taking behavior).As a consequence, the first-order conditions are\begin{align*}    r &= \alpha K^{\alpha-1} L^{1-\alpha} \\    w &= (1-\alpha) K^{\alpha} L^{-\alpha}.\end{align*}The households decide how much to consume $c_t$ and how much capital $k_{t+1}$ to accumulate.Every households's labor endowment $l_t$ is exogenous and follows a Gaussian AR(1) process.They choose how much to consume and how much capital to accumulate:\begin{align*}    \max_{c_t, k_{t+1}} &\; \mathbf{E}_0 \sum_{t=0}^{\infty} \beta^t \dfrac{c_t^{1-\gamma}}{1-\gamma} \\    \text{s.t.} &\;        \begin{cases}            c_t + k_{t+1} \leq w l_t + (1 + r_t) k_t \\            k_{t+1} \geq 0 \\            l_t = (1-\rho) \mu + \rho l_{t-1} + \varepsilon_t \\            \varepsilon_t \overset{iid}{\sim} \mathcal{N}(0, \sigma^2) \\            k_0 \text{ given}.        \end{cases}\end{align*} Intuition and main resultsThis paper connects to [Huggett (1993)](https://www.sciencedirect.com/science/article/pii/016518899390024M).Instead of trying to explain the Equity Premium Puzzle, Aiyagari tries to dig deeper on the excess consumption smoothness observed in the data.One explanation is about precautionary savings, which was shown to arise because of prudence.Aiyagari's paper contributes to the literature by showing that precautionary savings emerge in the aggregate because of financially constrained households.The main results are the following.It turns out that precautionary savings cannot explain the bulk of aggregate savings observed in the data.Prudence (related to the third derivative of utility function) is not always a necessary condition for precautionary savings: borrowing constraints might be enough.Borrowing constraints are a better explanation for precautionary savings because they abstract from preferences: this means that a policy-maker might do something to affect individuals' behavior.Finally, this paper is among the first ones to numerically solve for the general equilibrium of a model with idiosyncratic uncertainty. Replicating the paperThe way we replicate Aiyagari is not fundamentally different from Huggett's paper.The main steps are the same: we start with a guess for a sufficient statistics of the equilibrium (a price in Huggett, an aggregate allocation in Aiyagari), we solve for the households' problem and we verify that the policy functions together with the endogenous distribution of agents square with market clearing.If the net supply function is not zero, then we update the proposal for the equilibrium.More formally, the algorithm is the following:- Enter iteration $j$ with a guess for aggregate capital $K^{(j)}$:    1. From the firm's FOC, compute prices $r$ and $w$    1. Solve the households' problem for the policy functions $g^{(j)}(k, l)$    1. Compute the stationary endogenous distribution $\lambda^{(j)}(k, l)$    1. Compute the implied aggregate capital holdings       $$           K^{(*)} = \sum_k \sum_l g^{(k)}(k,l) \cdot \lambda^{(j)}(k,l)       $$    1. Obtain a new proposal for aggregate capital $K^{(j+1)} = \kappa K^{(j)} + (1-\kappa) K^{(*)}$ with some dampening parameter $\kappa \in (0, 1)$- If $|K^{(j+1)} - K^{(j)}|$ is close to zero, terminate the loop, otherwise enter iteration $j+1$.Numerically speaking, it is the case that if $\kappa$ is close to zero, then the algorithm will explore a large candidate interval for $K$, taking long jumps between a proposal and the next one.The goal of $\kappa$ is to slow down the updating, which in practice amounts to speeding up the convergence time.  Helper functions (wrappers)Before jumping to the actual replication, it makes sense to define certain functions that will simplify the code below.This is generally good practice when coding our own applications, because it allows us to clearly identify problems, should there be any.Moreover, working on small functions also increases the chances to re-use them later on.Here we define the following functions:- `rouwenhorst`: to discretize an AR(1) process- `cash_in_hand`: takes wage, labor endowment, capital holdings and the interest rate to compute how much liquidity a household has- `aggregate_kl`: takes the distribution of households $\lambda(k,l)$ and the grid $(k,l)$ to compute aggregate capital $K$ and labor $L$- `factor_prices`: takes aggregate capital $K$ and aggregate labor $L$ and returns the interest rate $r$ and the wage $w$ using the firm's FOC- `euler`: takes next period's consumption $c(k')$ and the RHS of the Euler equation and returns current period's consumption $c(k)$, considering whether the household is credit-constrained or not<jupyter_code>def rouwenhorst(N, mu, rho, sigma):

    def compute_P(p, N):
        if N == 2:
            P = np.array([[p, 1-p],
                          [1-p, p]])
        else:
            Q = compute_P(p, N-1)
            A = np.zeros((N, N))
            B = np.zeros((N, N))
            A[:N-1, :N-1] += Q
            A[1:N, 1:N] += Q
            B[:N-1, 1:N] += Q
            B[1:N, :N-1] += Q
            P = p * A + (1 - p) * B
            P[1:-1, :] /= 2
        return P

    p = (1 + rho) / 2
    P = compute_P(p, N)
    f = np.sqrt(N-1) * (sigma / np.sqrt(1-rho**2))
    s = np.linspace(-f, f, N) + mu
    return s, P
def factor_prices(K, L, param):
    a = param['alpha']
    r = a * (K/L) ** (a-1)
    w = (1 - a) * (K/L) ** (a)
    return r, w
def aggregate_kl(states, dist, param):
    K = dist @ states # wrong
    L = dist @ states # wrong
    return K, L
def cash_in_hand(k, l, r, w):
    cash = w * l + (1 + r) * k
    return cash<jupyter_output><empty_output><jupyter_text>Parametrization and gridsWe start by setting up the numerical framework.This consists of creating a grid for capital holdings and setting parameter values (including the grid for exogenous labor endowments).<jupyter_code>param = {
    'alpha': 0.5,
    'beta': 0.96,
    'gamma': 1.0,
    'phi': 1.0,
    'mu': 0.0,
    'rho': 0.53,
    'sigma': 0.296,
    'kMin': 0.0,
    'kMax': 40.0,
    'kNum': 100,
    'lNum': 9,
    'kappa': 0.2
}

kMin = 0  # also the borrowing constraint
kMax = 40
kNum = 100
k = np.linspace(kMin, kMax, kNum)
lLog = rouwenhorst(param['lNum'], param['mu'], param['rho'], param['sigma'])
l = np.exp(lLog)

kk, ll = np.meshgrid(k, l)<jupyter_output><empty_output><jupyter_text>Next, we proceed to define a function that implements policy function iteration.We define this as a function of prices $r$ and $w$.We do so because we need to solve the households' problem for various proposal values of prices.<jupyter_code>def solve_pfi(r, w, param, tol=1e-6):
    cash = cash_in_hand(r, w, state)
    diff = 1.0
    while diff > tol:
        c0 = euler(cash, param)
        diff = la.norm(c1 - c0)
        c1 = param['kappa'] * cs + (1 - param['kappa']) * c0<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11308458982877588, 'fraction_numerical': 0.0175057500638896, 'mean_word_length': 3.513840830449827, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 18, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, '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': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '635991', 'license': 'MIT', 'n_tokens_mistral': 2454, 'n_tokens_neox': 2310, 'n_words': 1003, 'path': 'ta_sessions/5_aiyagari.ipynb', 'repo_name': 'anhnguyendepocen/numerical_methods_macroeconomics', 'size': '7826'}