Ejemplo n.º 1
0
def solve(sol, par):

    grid_last = np.linspace(par.m_min, par.m_max, par.Nm + par.N_bottom)

    if np.size(sol.c[0, :]) >= (par.Nm + par.N_bottom - 1):
        grid = grid_last
    else:
        grid = par.grid_m

    for n in range(2):  # Loop over housing state
        for m_i, m in enumerate(grid):  # Loop over exogeneous asset grid

            if n == 0:

                # Cannot buy a house
                if m < par.ph:
                    sol.c[n, m_i] = m
                    sol.h[n, m_i] = 0

                # Can buy a house
                else:
                    u_dif = util.u_h(m, 0, par) - util.u_h(
                        m - par.ph, 1, par)  # dif in utility from choice

                    if u_dif >= 0:  # If not buying a house is optimal
                        sol.c[n, m_i] = m
                        sol.h[n, m_i] = 0

                    else:  # If buying a house is optimal
                        sol.c[n, m_i] = m - par.ph
                        sol.h[n, m_i] = 1

            if n == 1:

                u_dif = util.u_h(m, 1, par) - util.u_h(
                    m + par.ph, 0, par)  # dif in utility from choice

                if u_dif >= 0:
                    sol.c[n, m_i] = m
                    sol.h[n, m_i] = 1

                else:
                    sol.c[n, m_i] = m + par.ph
                    sol.h[n, m_i] = 0

            # Compute value of choice
            sol.v[n, m_i] = util.u_h(sol.c[n, m_i], sol.h[n, m_i], par)
Ejemplo n.º 2
0
def solve(sol, par):

    for n in range(2):  # Loop over housing state
        for m_i, m in enumerate(par.grid_m):  # Loop over exogeneous asset grid

            if n == 0:

                # Cannot buy a house
                if m < par.ph:
                    sol.c[n, m_i] = m
                    sol.h[n, m_i] = 0

                # Can buy a house
                else:
                    u_dif = util.u_h(m, 0, par) - util.u_h(
                        m - par.ph, 1, par)  # dif in utility from choice

                    if u_dif >= 0:  # If not buying a house is optimal
                        sol.c[n, m_i] = m
                        sol.h[n, m_i] = 0

                    else:  # If buying a house is optimal
                        sol.c[n, m_i] = m - par.ph
                        sol.h[n, m_i] = 1

            if n == 1:

                u_dif = util.u_h(m, 1, par) - util.u_h(
                    m + par.ph, 0, par)  # dif in utility from choice

                if u_dif >= 0:
                    sol.c[n, m_i] = m
                    sol.h[n, m_i] = 1

                else:
                    sol.c[n, m_i] = m + par.ph
                    sol.h[n, m_i] = 0

            # Compute value of choice
            sol.v[n, m_i] = util.u_h(sol.c[n, m_i], sol.h[n, m_i], par)
Ejemplo n.º 3
0
def obj_keep(
    arg, n, m, v_next, par, m_next
):  # I have added m_next to the interpolation since it changes throughout iterations

    # Unpack
    c = arg

    # End of period assets
    m_plus = (1 + par.r) * (m - c) + par.y1

    # Continuation value
    v_plus = tools.interp_linear_1d_scalar(m_next, v_next, m_plus)

    # Value of choice
    value = util.u_h(c, n, par) + par.beta * v_plus

    return value
Ejemplo n.º 4
0
def obj_keep(arg, n, m, v_next, par):

    # Unpack
    c = arg

    # End of period assets
    m_plus = (1 + par.r) * (m - c) + par.y1

    # Continuation value
    v_plus = tools.interp_linear_1d_scalar(par.grid_m, v_next, m_plus)

    # Value of choice
    value = util.u_h(c, n, par) + par.beta * v_plus

    return value

    #def solve_NEGM(par,sol):

    # a. next-period cash-on-hand
    m_plus = par['R'] * par['grid_a'] + par['y']

    # b. post-decision value function
    sol['w_vec'] = np.empty(m_plus.size)
    linear_interp.interp_1d_vec(par['grid_m'], sol['v_next'], m_plus,
                                sol['w_vec'])

    # c. post-decision marginal value of cash
    c_next_interp = np.empty(m_plus.size)
    linear_interp.interp_1d_vec(par['grid_m'], sol['c_next'], m_plus,
                                c_next_interp)
    q = par['beta'] * par['R'] * marg_u(c_next_interp, par)

    # d. EGM
    sol['c_vec'] = inv_marg_u(q, par)
    sol['m_vec'] = par['grid_a'] + sol['c_vec']

    myupperenvelope = upperenvelope.create(u)  # where is the utility function

    # b. apply upperenvelope
    c_ast_vec = np.empty(par['grid_m'].size)  # output
    v_ast_vec = np.empty(par['grid_m'].size)  # output
    myupperenvelope(par['grid_a'], sol['m_vec'], sol['c_vec'], sol['w_vec'],
                    par['grid_m'], c_ast_vec, v_ast_vec, par['rho'])

    return  #sol from upperenvelope
Ejemplo n.º 5
0
def solve_dc(sol, par, v_next, c_next, h_next, m_next):

    # a. Solve the keeper problem

    shape = (
        2, np.size(par.grid_a)
    )  # Row for each state of housing and colums for exogenous end-of-period assets grid

    # Intialize
    v_keep = np.zeros(shape) + np.nan
    c_keep = np.zeros(shape) + np.nan
    h_keep = np.zeros(shape) + np.nan

    # Loop over housing states
    for n in range(2):

        # Loop over exogenous states (post decision states)
        for a_i, a in enumerate(par.grid_a):

            #Next periods assets and consumption
            m_plus = (1 + par.r) * a + par.y1

            # Interpolate next periods consumption
            c_plus = tools.interp_linear_1d_scalar(m_next[n, :], c_next[n, :],
                                                   m_plus)

            # Marginal utility
            marg_u_plus = util.marg_u(c_plus, par)
            #av_marg_u_plus = np.sum(par.P*marg_u_plus, axis = 1) # Dot product by row (axis = 1) #### no average

            # Add optimal consumption and endogenous state using Euler equation
            c_keep[n, a_i] = util.inv_marg_u(
                (1 + par.r) * par.beta * marg_u_plus, par)  #### no average
            # v_keep[n,a_i] = obj_keep(c_keep[n,a_i], n, c_keep[n,a_i] + a, v_next[n,:], par, m_next[n, :])
            # The line below is faster and more precise as it avoids numerical errors
            v_keep[n, a_i] = util.u_h(
                c_keep[n, a_i], n,
                par) + par.beta * tools.interp_linear_1d_scalar(
                    m_next[n, :], v_next[n, :], m_plus)
            h_keep[n, a_i] = n

    ### UPPER ENVELOPE ###

    c_keep, v_keep, m_grid = upper_envelope(c_keep, v_keep, v_next, m_next,
                                            shape, par)

    ### Add points at the constraints ###

    m_con = np.array([
        np.linspace(0 + 1e-8, m_grid[0, 0] - 1e-4, par.N_bottom),
        np.linspace(0 + 1e-8, m_grid[1, 0] - 1e-4, par.N_bottom)
    ])
    c_con = m_con.copy()
    v_con_0 = [
        obj_keep(c_con[0, i], 0, m_con[0, i], v_next[0, :], par, m_next[0, :])
        for i in range(par.N_bottom)
    ]  # From N_bottom or whole
    v_con_1 = [
        obj_keep(c_con[1, i], 1, m_con[1, i], v_next[1, :], par, m_next[1, :])
        for i in range(par.N_bottom)
    ]  # From N_bottom or whole
    v_con = np.array([v_con_0, v_con_1])

    # initialize new larger keeper containers

    new_shape = (2, np.size(par.grid_a) + par.N_bottom)
    c_keep_append = np.zeros(new_shape) + np.nan
    v_keep_append = np.zeros(new_shape) + np.nan
    m_grid_append = np.zeros(new_shape) + np.nan

    # append

    for i in range(2):
        c_keep_append[i, :] = np.append(c_con[i, :], c_keep[i, :])
        v_keep_append[i, :] = np.append(v_con[i, :], v_keep[i, :])
        m_grid_append[i, :] = np.append(m_con[i, :], m_grid[i, :])

    # b. Solve the adjuster problem

    # Initialize
    v_adj = np.zeros(new_shape) + np.nan
    c_adj = np.zeros(new_shape) + np.nan
    h_adj = np.zeros(new_shape) + np.nan

    # Loop over housing state
    for n in range(2):

        # Housing choice is reverse of state n if adjusting
        h = 1 - n

        # Loop over asset grid
        for a_i, m in enumerate(m_grid_append[n]):  # endogenous grid

            # If adjustment is not possible
            if n == 0 and m < par.ph:
                v_adj[n, a_i] = -np.inf
                c_adj[n, a_i] = 0
                h_adj[n, a_i] = np.nan

            else:

                # Assets available after adjusting
                if n == 1:
                    p = par.p1
                else:
                    p = par.ph

                x = m - p * (h - n)

                # Value of choice
                v_adj[n, a_i] = tools.interp_linear_1d_scalar(
                    m_grid_append[h], v_keep_append[h, :], x)
                c_adj[n, a_i] = tools.interp_linear_1d_scalar(
                    m_grid_append[h], c_keep_append[h, :], x)
                h_adj[n, a_i] = h

    # c. Combine solutions

    # Loop over asset grid again
    for n in range(2):
        for a_i, m in enumerate(m_grid_append[n]):  # endogenous grid

            # If keeping is optimal
            if v_keep_append[n, a_i] > v_adj[n, a_i]:
                sol.v[n, a_i] = v_keep_append[n, a_i]
                sol.c[n, a_i] = c_keep_append[n, a_i]
                sol.h[n, a_i] = n
                sol.m[n, a_i] = m_grid_append[n, a_i]  # added

            # If adjusting is optimal
            else:
                sol.v[n, a_i] = v_adj[n, a_i]
                sol.c[n, a_i] = c_adj[n, a_i]
                sol.h[n, a_i] = 1 - n
                sol.m[n, a_i] = m_grid_append[n, a_i]  # added

    for i in range(2):
        sol.delta_save[i, sol.it] = max(abs(sol.v[i] - v_next[i]))

    return sol