示例#1
0
    def value_of_choice(self, c, t, m):
        """ value of choice of c used in vfi """

        par = self.par
        sol = self.sol

        # a. end-of-period assets
        a = m - c

        # b. next-period cash-on-hand
        still_working_next_period = t + 1 <= par.TR - 1
        if still_working_next_period:
            fac = par.G * par.L[t] * par.psi_vec
            w = par.w
            xi = par.xi_vec
        else:
            fac = par.G * par.L[t]
            w = 1
            xi = 1

        m_plus = (par.R / fac) * a + xi

        # c. continuation value
        inv_v_plus = np.zeros(m_plus.size)
        linear_interp.interp_1d_vec(sol.m[t + 1, :], sol.inv_v[t + 1, :],
                                    m_plus, inv_v_plus)
        v_plus = 1 / inv_v_plus

        # d. value-of-choice
        total = utility(
            c, par) + par.beta * np.sum(w * fac**(1 - par.rho) * v_plus)
        return -total
示例#2
0
def solve_backwards(par, r, w, Va_p, Va, a, c, m, V_p, V, Vbar):
    """ perform time iteration step with Va_p from previous iteration """

    # a. post-decision
    marg_u_plus = (par.beta * par.e_trans) @ Va_p
    Vbar[:, :] = (par.beta * par.e_trans) @ V_p

    # b. egm loop
    for i_e in prange(par.Ne):

        # i. egm
        c_endo = marg_u_plus[i_e]**(-1 / par.sigma)
        m_endo = c_endo + par.a_grid

        # ii. interpolation
        linear_interp.interp_1d_vec(m_endo, par.a_grid, m[i_e], a[i_e])
        a[i_e, 0] = np.fmax(a[i_e, 0], 0)
        c[i_e] = m[i_e] - a[i_e]

        # iii. envelope condition
        Va[i_e] = (1 + r) * c[i_e]**(-par.sigma)

        # iv. value function
        for i_a in range(par.Na):
            a[i_e, i_a] = np.fmax(a[i_e, i_a], 0)
            Vbar_now = linear_interp.interp_1d(par.a_grid, Vbar[i_e], a[i_e,
                                                                        i_a])
            V[i_e,
              i_a] = c[i_e, i_a]**(1 - par.sigma) / (1 - par.sigma) + Vbar_now
def solve(sol,par,G2EGM=True):

    # a. last_period
    t = par.T-1

    sol.m_ret[t,:] = par.grid_m_ret
    sol.c_ret[t,:] = sol.m_ret[t,:]
    
    v = utility.func_ret(sol.c_ret[t,:],par)
    sol.inv_v_ret[t,:] = -1.0/v
    
    vm = utility.marg_func(sol.c_ret[t,:],par)
    sol.inv_vm_ret[t,:] = 1.0/vm
    if G2EGM:
        sol.inv_vn_ret[t,:] = sol.inv_vm_ret[t,:]

    # b. backwards inducation
    for j in range(2,par.T+1):
        
        t = par.T-j

        # i. optimal c choice
        m_plus = par.Ra*par.grid_a_ret + par.yret
        c_plus = np.zeros(m_plus.shape)
        linear_interp.interp_1d_vec(sol.m_ret[t+1,:],sol.c_ret[t+1,:],m_plus,c_plus)
        
        vm_plus = utility.marg_func(c_plus,par) 
        q = par.beta*par.Ra*vm_plus
        sol.c_ret[t,par.Nmcon_ret:] = utility.inv_marg_func(q,par)

        # ii. constraint            
        sol.c_ret[t,:par.Nmcon_ret] = nonlinspace_jit(1e-6,sol.c_ret[t,par.Nmcon_ret]*0.999,par.Nmcon_ret,par.phi_m)
    
        # iii. end-of-period assets and value-of-choice
        sol.a_ret[t,par.Nmcon_ret:] = par.grid_a_ret
        
        inv_v_plus = np.zeros(m_plus.shape)
        linear_interp.interp_1d_vec(sol.m_ret[t+1,:],sol.inv_v_ret[t+1,:],m_plus,inv_v_plus)
        v_plus = -1.0/inv_v_plus

        v1 = utility.func_ret(sol.c_ret[t,:par.Nmcon_ret],par) + par.beta*v_plus[0] 
        v2 = utility.func_ret(sol.c_ret[t,par.Nmcon_ret:],par) + par.beta*v_plus

        sol.inv_v_ret[t,:par.Nmcon_ret] = -1.0/v1
        sol.inv_v_ret[t,par.Nmcon_ret:] = -1.0/v2
                
        # iv. endogenous grid
        sol.m_ret[t,:] = sol.a_ret[t,:] + sol.c_ret[t,:]

        # v. marginal v
        vm = utility.marg_func(sol.c_ret[t,:],par)
        sol.inv_vm_ret[t,:] = 1.0/vm
        if G2EGM:
            sol.inv_vn_ret[t,:] = sol.inv_vm_ret[t,:]
示例#4
0
    def EGMvec(self, t, m, c, inv_v):
        """ EGM with fully vectorized code """

        par = self.par
        sol = self.sol

        # a. prep
        if t + 1 <= par.TR - 1:  # still working in next-period
            a = par.grid_a_tile[t, :]
            fac = par.G * par.L[t] * par.psi_vec_rep
            w = par.w_rep
            xi = par.xi_vec_rep
            Nshocks = par.Nshocks
        else:
            a = par.grid_a
            fac = par.G * par.L[t]
            w = 1
            xi = 1
            Nshocks = par.Nshocks

        inv_fac = 1.0 / fac

        # b. future m and c
        m_plus = inv_fac * par.R * a + xi

        c_plus = np.zeros(m_plus.size)
        linear_interp.interp_1d_vec(sol.m[t + 1, :], sol.c[t + 1, :], m_plus,
                                    c_plus)

        inv_v_plus = np.zeros(m_plus.size)
        linear_interp.interp_1d_vec(sol.m[t + 1, :], sol.inv_v[t + 1, :],
                                    m_plus, inv_v_plus)
        v_plus = 1.0 / inv_v_plus

        # c. average future marginal utility
        marg_u_plus = self.marg_utility(fac * c_plus)
        avg_marg_u_plus = np.sum((w * marg_u_plus).reshape((Nshocks, par.Na)),
                                 axis=0)
        avg_v_plus = np.sum((w * (fac**(1 - par.rho)) * v_plus).reshape(
            (Nshocks, par.Na)),
                            axis=0)

        # d. current c
        c[:] = self.inv_marg_utility(par.beta * par.R * avg_marg_u_plus)

        # e. current m
        m[:] = par.grid_a[t, :] + c

        # f. current v
        I = c > 0
        inv_v[I] = 1.0 / (self.utility(c[I]) + par.beta * avg_v_plus[I])
        inv_v[~I] = 0.0
示例#5
0
    def EGM(self, t, m, c, inv_v):
        """ EGM with partly vectorized code """

        par = self.par
        sol = self.sol

        # loop over end-of-period assets
        for i_a in range(par.Na):

            # a. prep
            a = par.grid_a[t, i_a]
            if t + 1 <= par.TR - 1:  # still working in next-period
                fac = par.G * par.L[t] * par.psi_vec
                w = par.w
                xi = par.xi_vec
            else:
                fac = par.G * par.L[t]
                w = 1
                xi = 1

            inv_fac = 1.0 / fac

            # b. future m and c (vectors)
            m_plus = inv_fac * par.R * a + xi

            c_plus = np.zeros(m_plus.size)
            linear_interp.interp_1d_vec(sol.m[t + 1, :], sol.c[t + 1, :],
                                        m_plus, c_plus)

            inv_v_plus = np.zeros(m_plus.size)
            linear_interp.interp_1d_vec(sol.m[t + 1, :], sol.inv_v[t + 1, :],
                                        m_plus, inv_v_plus)
            v_plus = 1.0 / inv_v_plus

            # c. average future marginal utility (number)
            marg_u_plus = self.marg_utility(fac * c_plus)
            avg_marg_u_plus = np.sum(w * marg_u_plus)
            avg_v_plus = np.sum(w * (fac**(1 - par.rho)) * v_plus)

            # d. current c
            c[i_a] = self.inv_marg_utility(par.beta * par.R * avg_marg_u_plus)

            # e. current m
            m[i_a] = a + c[i_a]

            # f. current v
            if c[i_a] > 0:
                inv_v[i_a] = 1.0 / (self.utility(c[i_a]) +
                                    par.beta * avg_v_plus)
            else:
                inv_v[i_a] = 0
示例#6
0
def _discrete(model, t, i_p):

    par = model.par

    # a. interpolation
    n, m = np.meshgrid(par.grid_n, par.grid_m, indexing='ij')
    x = m + (1 - par.tau) * n

    inv_v_adj = np.zeros(x.size)
    linear_interp.interp_1d_vec(par.grid_x, model.sol.inv_v_adj[t, i_p, :, ],
                                x.ravel(), inv_v_adj)
    inv_v_adj = inv_v_adj.reshape(x.shape)

    # f. best discrete choice
    fig = plt.figure(figsize=(6, 6))
    ax = fig.add_subplot(1, 1, 1)

    I = inv_v_adj > model.sol.inv_v_keep[t, i_p, :, :]

    x = m[I].ravel()
    y = n[I].ravel()
    ax.scatter(x, y, s=2, label='adjust')

    x = m[~I].ravel()
    y = n[~I].ravel()
    ax.scatter(x, y, s=2, label='keep')

    ax.set_title(
        f'optimal discrete choice ($t = {t}$, $p = {par.grid_p[i_p]:.2f}$)',
        pad=10)

    legend = ax.legend(loc='upper center', shadow=True)
    frame = legend.get_frame()
    frame.set_facecolor('0.90')

    # g. details
    ax.grid(True)
    ax.set_xlabel('$m_t$')
    ax.set_xlim([par.grid_m[0], par.grid_m[-1]])
    ax.set_ylabel('$n_t$')
    ax.set_ylim([par.grid_n[0], par.grid_n[-1]])

    plt.show()
def time_iteration(par, r, w, Va_p, Va, a, c, m):
    """ perform time iteration step with Va_p from previous iteration """

    # a. post-decision
    marg_u_plus = (par.beta * par.e_trans) @ Va_p

    # b. egm loop
    for i_e in prange(par.Ne):

        # i. egm
        c_endo = marg_u_plus[i_e]**(-1 / par.sigma)
        m_endo = c_endo + par.a_grid

        # ii. interpolation
        linear_interp.interp_1d_vec(m_endo, par.a_grid, m[i_e], a[i_e])
        a[i_e, 0] = np.fmax(a[i_e, 0], 0)
        c[i_e] = m[i_e] - a[i_e]

        # iii. envelope condition
        Va[i_e] = (1 + r) * c[i_e]**(-par.sigma)
def solve_backwards(par,r,w,Va_p,Va,a,c,m):
    """ solve backwards with Va_p from previous iteration """

    # a. post-decision 
    marg_u_plus = (par.beta*par.e_trans)@Va_p

    # b. egm loop
    for i_e in prange(par.Ne):
        
        # i. egm
        c_endo = marg_u_plus[i_e]**(-1/par.sigma)
        m_endo = c_endo + par.a_grid

        # ii. interpolation
        linear_interp.interp_1d_vec(m_endo,par.a_grid,m[i_e],a[i_e])
        a[i_e,0] = np.fmax(a[i_e,0],0) # enforce borrowing constraint
        c[i_e] = m[i_e]-a[i_e]

        # iii. envelope condition
        Va[i_e] = (1+r)*c[i_e]**(-par.sigma)
示例#9
0
    def simulate_timeloop(self):
        """ simulate model with loop over time """

        par = self.par
        sol = self.sol
        sim = self.sim

        # loop over time
        for t in range(par.simT):

            # a. solution
            if par.simlifecycle == 0:
                grid_m = sol.m[0, :]
                grid_c = sol.c[0, :]
            else:
                grid_m = sol.m[t, :]
                grid_c = sol.c[t, :]

            # b. consumption
            linear_interp.interp_1d_vec(grid_m, grid_c, sim.m[:, t], sim.c[:,
                                                                           t])
            sim.a[:, t] = sim.m[:, t] - sim.c[:, t]

            # c. next-period states
            if t < par.simT - 1:

                if t + 1 > par.TR - 1:
                    sim.m[:,
                          t + 1] = par.R * sim.a[:, t] / (par.G * par.L[t]) + 1
                    sim.p[:, t +
                          1] = np.log(par.G) + np.log(par.L[t]) + sim.p[:, t]
                    sim.y[:, t + 1] = sim.p[:, t + 1]
                else:
                    sim.m[:, t + 1] = par.R * sim.a[:, t] / (
                        par.G * par.L[t] * sim.psi[:, t + 1]) + sim.xi[:,
                                                                       t + 1]
                    sim.p[:, t + 1] = np.log(par.G) + np.log(
                        par.L[t]) + sim.p[:, t] + np.log(sim.psi[:, t + 1])
                    I = sim.xi[:, t + 1] > 0
                    sim.y[I,
                          t + 1] = sim.p[I, t + 1] + np.log(sim.xi[I, t + 1])
def plot_buffer_stock_target(model):

    par = model.par
    sol = model.sol

    # a. find a and avg. m_plus and c_plus

    # allocate
    a = np.nan * np.ones(par.Na + 1)
    m_plus = np.nan * np.ones(par.Na + 1)
    C_plus = np.nan * np.ones(par.Na + 1)

    delta_log_C_plus = np.nan * np.ones(par.Na + 1)
    delta_log_C_plus_approx_2 = np.nan * np.ones(par.Na + 1)

    fac = 1.0 / (par.G * par.psi_vec)
    for i_a in range(par.Na + 1):

        # a. a and m
        a[i_a] = sol.m[0, i_a] - sol.c[0, i_a]
        m_plus[i_a] = np.sum(par.w * (fac * par.R * a[i_a] + par.xi_vec))

        # b. C_plus
        m_plus_vec = fac * par.R * a[i_a] + par.xi_vec
        c_plus_vec = np.zeros(m_plus_vec.size)
        linear_interp.interp_1d_vec(sol.m[0, :], sol.c[0, :], m_plus_vec,
                                    c_plus_vec)
        C_plus_vec = par.G * par.psi_vec * c_plus_vec
        C_plus[i_a] = np.sum(par.w * C_plus_vec)

        # c. approx
        if not (par.sigma_xi == 0 and par.sigma_psi == 0
                and par.pi == 0) and sol.c[0, i_a] > 0:

            delta_log_C_plus[i_a] = np.sum(
                par.w * (np.log(par.G * C_plus_vec))) - np.log(sol.c[0, i_a])
            var_C_plus = np.sum(
                par.w * (np.log(par.G * C_plus_vec) - np.log(sol.c[0, i_a]) -
                         delta_log_C_plus[i_a])**2)
            delta_log_C_plus_approx_2[i_a] = par.rho**(-1) * (np.log(
                par.R * par.beta)) + 2 / par.rho * var_C_plus + np.log(par.G)

    # b. find target
    i = np.argmin(np.abs(m_plus - sol.m[0, :]))
    m_target = sol.m[0, i]

    # c. figure 1 - buffer-stock target
    fig = plt.figure(figsize=(6, 4), dpi=100)
    ax = fig.add_subplot(1, 1, 1)

    # limits
    ax.set_xlim([np.min(par.a_min), 5])
    ax.set_ylim([0, 5])

    # layout
    bbox = {'boxstyle': 'square', 'ec': 'white', 'fc': 'white'}
    ax.text(2.1,
            0.25,
            f'$\\beta = {par.beta:.2f}$, $R = {par.R:.2f}$, $G = {par.G:.2f}$',
            bbox=bbox)
    ax.set_xlabel('$m_t$')
    ax.set_ylabel('')

    # i. consumption
    ax.plot(sol.m[0, :], sol.c[0, :], '-', lw=1.5, label='$c(m_t)$')
    ax.legend(loc='upper left', frameon=True)
    fig.savefig(f'figs/buffer_stock_target_{model.name}_c.pdf')

    # ii. perfect foresight solution
    if par.FHW < 1 and par.RI < 1:

        c_pf = (1 - par.RI) * (sol.m[0, :] + (1 - par.FHW)**(-1) - 1)
        ax.plot(sol.m[0, :],
                c_pf,
                ':',
                lw=1.5,
                color='black',
                label='$c^{PF}(m_t)$')

        ax.legend(loc='upper left', frameon=True)
        fig.savefig(f'figs/buffer_stock_target_{model.name}_pf.pdf')

    # iii. a
    ax.plot(sol.m[0, :], a, '-', lw=1.5, label=r'$a_t=m_t-c^{\star}(m_t)$')
    ax.legend(loc='upper left', frameon=True)
    fig.savefig(f'figs/buffer_stock_target_{model.name}_a.pdf')

    # iv. m_plus
    ax.plot(sol.m[0, :], m_plus, '-', lw=1.5, label='$E[m_{t+1} | a_t]$')
    ax.legend(loc='upper left', frameon=True)
    fig.savefig(f'figs/buffer_stock_target_{model.name}_m_plus.pdf')

    # v. 45
    ax.plot([0, 5], [0, 5], '-', lw=1.5, color='black', label='45 degree')
    ax.legend(loc='upper left', frameon=True)
    fig.savefig(f'figs/buffer_stock_target_{model.name}_45.pdf')

    # vi. target
    if not (par.sigma_xi == 0 and par.sigma_psi == 0
            and par.pi == 0) == 'bs' and par.GI < 1:
        ax.plot([m_target, m_target], [0, 5],
                '--',
                lw=1.5,
                color='black',
                label=f'target = {m_target:.2f}')

    ax.legend(loc='upper left', frameon=True)
    fig.savefig(f'figs/buffer_stock_target_{model.name}.pdf')

    # STOP
    if par.sigma_xi == 0 and par.sigma_psi == 0 and par.pi == 0:
        return

    # d. figure 2 - C ratio
    fig = plt.figure(figsize=(6, 4), dpi=100)
    ax = fig.add_subplot(1, 1, 1)

    I = sol.c[0, :] > 0
    ax.plot(sol.m[0, I], (C_plus[I] / sol.c[0, I]),
            '-',
            lw=1.5,
            label='$E[C_{t+1}/C_t]$')
    ax.plot([m_target, m_target], [0, 10],
            '--',
            lw=1.5,
            color='black',
            label='target')
    ax.plot([np.min(par.a_min), 500], [par.G, par.G],
            ':',
            lw=1.5,
            color='black',
            label='$G$')
    ax.plot([np.min(par.a_min), 500], [(par.R * par.beta)**(1 / par.rho),
                                       (par.R * par.beta)**(1 / par.rho)],
            '-',
            lw=1.5,
            color='black',
            label=r'$(\beta R)^{1/\rho}$')

    # limit
    ax.set_xlim([np.min(par.a_min), 10])
    ax.set_ylim([0.95, 1.1])

    # layout
    ax.set_xlabel('$m_t$')
    ax.set_ylabel('$C_{t+1}/C_t$')
    ax.legend(loc='upper right', frameon=True)

    fig.savefig(f'figs/cons_growth_{model.name}.pdf')

    # e. figure 3 - euler approx
    fig = plt.figure(figsize=(6, 4), dpi=100)
    ax = fig.add_subplot(1, 1, 1)

    ax.plot(sol.m[0, :],
            delta_log_C_plus,
            '-',
            lw=1.5,
            label=r'$E[\Delta \log C_{t+1}]$')

    ax.plot(sol.m[0, :],
            par.rho**(-1) * np.log(par.R * par.beta) * np.ones(par.Na + 1) +
            np.log(par.G),
            '-',
            lw=1.5,
            label='1st order approx.')
    ax.plot(sol.m[0, :],
            delta_log_C_plus_approx_2,
            '-',
            lw=1.5,
            label='2nd order approx.')
    ax.plot([m_target, m_target], [-10, 10],
            '--',
            lw=1.5,
            color='black',
            label='target')

    # limit
    ax.set_xlim([np.min(par.a_min), 10])
    ax.set_ylim([-0.03, 0.12])

    # layout
    ax.set_xlabel('$m_t$')
    ax.set_ylabel(r'$E[\Delta \log C_{t+1}]$')
    ax.legend(loc='upper right', frameon=True)

    fig.savefig(f'figs/euler_approx_{model.name}.pdf')
示例#11
0
def matrix(l, n, v_a):

    #parameter
    Na = 1000
    Ne = 11  # number of states
    sol_shape = (Ne, Na)
    a = np.zeros(sol_shape)
    r = 0.03
    w = 1.000
    a_grid = equilogspace(0, 200, Na)
    rho = 0.97  # AR(1) parameter
    sigma_e = 0.25  # std. of persistent shock
    sigma = 2
    beta = 0.96
    e_grid, e_trans, e_ergodic, e_trans_cumsum, e_ergodic_cumsum = markov_rouwenhorst(
        rho, sigma_e, Ne)

    #calculation
    #step 3
    A = np.kron(e_trans, np.identity(n))
    B = (beta * A) @ v_a
    C = np.power(B, (-sigma))
    a_extend = np.tile(a_grid, 11)
    m_endo = C + a_extend  #samme opbygning som vektoren v_a

    #step 4
    values = []
    m = (1 + r) * a_grid[np.newaxis, :] + w * e_grid[:, np.newaxis]
    new_m_endo = np.array_split(m_endo, Ne)

    for k in range(Ne):
        linear_interp.interp_1d_vec(new_m_endo[k], a_grid, m[k], a[k])
        for i_a in range(Na):
            a[k, i_a] = np.fmax(a[k, i_a], 0)
        values.append(m[k] - a[k])

    #print(f'new_m_endo[0]:{new_m_endo[0]}')
    #print(new_m_endo[0])
    c = np.concatenate(values)
    u = np.power(c, (1 - sigma)) / (1 - sigma)
    u[u == -np.inf] = -1000000000000000000000000000
    print(f'c:{c}')
    print(f'u:{u}')

    #Create Q^
    lis = []
    Q = np.zeros(Ne * Na)
    #calculate
    for e in range(Ne):
        q = np.zeros((Na, Na))  #create each Q_i
        for k in range(Na):
            opt = a[e, k]
            if opt >= np.max(a_grid):
                q[k, Na - 1] = 1  #If opt equals the end point

            elif opt <= np.min(a_grid):
                q[k, 0] = 1  #If opt equals the start point

            else:
                a_high = np.min(np.nonzero(opt <= a_grid))  #create points
                a_low = np.max(np.nonzero(opt >= a_grid))
                q[k, a_low] = (a_grid[a_low + 1] - opt) / (a_grid[a_low + 1] -
                                                           a_grid[a_low])
                q[k,
                  a_high] = (opt - a_grid[a_high - 1]) / (a_grid[a_high] -
                                                          a_grid[a_high - 1])
        lis.append(q)

    Q = block_diag(*lis)  #make block matrix from Q's

    omega = Q @ A

    new_v_a = np.linalg.inv(np.identity(11000) - beta * omega) @ u
    return new_v_a