def deviate_d_con(valt, n, c, a, w, par):

    for i_b in range(par.Nb_pd):
        for i_a in range(par.Na_pd):

            # a. choices
            d_x = par.delta_con * c[i_b, i_a]
            c_x = (1.0 - par.delta_con) * c[i_b, i_a]

            # b. post-decision states
            b_x = n[i_b, i_a] + d_x + pens.func(d_x, par)

            if not np.imag(b_x) == 0:
                valt[i_b, i_a] = np.nan
                continue

            # c. value
            w_x = linear_interp.interp_2d(par.grid_b_pd, par.grid_a_pd, w, b_x,
                                          a[i_b, i_a])
            v_x = utility.func(c_x, par) + w_x

            if not np.imag(v_x) == 0:
                valt[i_b, i_a] = np.nan
            else:
                valt[i_b, i_a] = v_x
def inv_mn_and_v(c, d, a, b, w, par):

    v = utility.func(c, par) + w
    m = a + c + d
    n = b - d - pens.func(d, par)

    return m, n, v
def solve(t,sol,par):

    w = sol.w[t]
    wa = sol.wa[t]
    wb = sol.wb[t]

    # a. solve each segment
    solve_ucon(sol.ucon_c[t,:,:],sol.ucon_d[t,:,:],sol.ucon_v[t,:,:],w,wa,wb,par)
    solve_dcon(sol.dcon_c[t,:,:],sol.dcon_d[t,:,:],sol.dcon_v[t,:,:],w,wa,par)
    solve_acon(sol.acon_c[t,:,:],sol.acon_d[t,:,:],sol.acon_v[t,:,:],w,wb,par)
    solve_con(sol.con_c[t,:,:],sol.con_d[t,:,:],sol.con_v[t,:,:],w,par)

    # b. upper envelope    
    seg_max = np.zeros(4)
    for i_n in range(par.Nn):
        for i_m in range(par.Nm):

            # i. find max
            seg_max[0] = sol.ucon_v[t,i_n,i_m]
            seg_max[1] = sol.dcon_v[t,i_n,i_m]
            seg_max[2] = sol.acon_v[t,i_n,i_m]
            seg_max[3] = sol.con_v[t,i_n,i_m]

            i = np.argmax(seg_max)

            # ii. over-arching optimal choices
            sol.inv_v[t,i_n,i_m] = -1.0/seg_max[i]

            if i == 0:
                sol.c[t,i_n,i_m] = sol.ucon_c[t,i_n,i_m]
                sol.d[t,i_n,i_m] = sol.ucon_d[t,i_n,i_m]
            elif i == 1:
                sol.c[t,i_n,i_m] = sol.dcon_c[t,i_n,i_m]
                sol.d[t,i_n,i_m] = sol.dcon_d[t,i_n,i_m]
            elif i == 2:
                sol.c[t,i_n,i_m] = sol.acon_c[t,i_n,i_m]
                sol.d[t,i_n,i_m] = sol.acon_d[t,i_n,i_m]
            elif i == 3:
                sol.c[t,i_n,i_m] = sol.con_c[t,i_n,i_m]
                sol.d[t,i_n,i_m] = sol.con_d[t,i_n,i_m]
        
    # c. derivatives 
    
    # i. m
    vm = utility.marg_func(sol.c[t],par)
    sol.inv_vm[t,:,:] = 1.0/vm

    # ii. n         
    a = par.grid_m_nd - sol.c[t] - sol.d[t]
    b = par.grid_n_nd + sol.d[t] + pens.func(sol.d[t],par)

    wb_now = np.zeros(a.shape)
    linear_interp.interp_2d_vec(par.grid_b_pd,par.grid_a_pd,wb,b.ravel(),a.ravel(),wb_now.ravel())
    
    vn = wb_now
    sol.inv_vn[t,:,:] = 1.0/vn
Beispiel #4
0
def obj_outer(d,n,m,t,sol,par):
    """ evaluate bellman equation """

    # a. cash-on-hand
    m_pure_c = m-d

    # b. durables
    n_pure_c = n + d + pens.func(d,par)
    
    # c. value-of-choice
    return -linear_interp.interp_2d(par.grid_b_pd,par.grid_l,sol.inv_v_pure_c[t],n_pure_c,m_pure_c)  # we are minimizing
Beispiel #5
0
def solve_outer(t,sol,par):

    # unpack output
    inv_v = sol.inv_v[t]
    inv_vm = sol.inv_vm[t]
    c = sol.c[t]
    d = sol.d[t]

    # loop over outer states
    for i_n in range(par.Nn):
            
        n = par.grid_n[i_n]

        # loop over m state
        for i_m in range(par.Nm):
            
            m = par.grid_m[i_m]
            
            # a. optimal choice
            d_low = 1e-8
            d_high = m-1e-8
            d[i_n,i_m] = golden_section_search.optimizer(obj_outer,d_low,d_high,args=(n,m,t,sol,par),tol=1e-8)

            # b. optimal value
            n_pure_c = n + d[i_n,i_m] + pens.func(d[i_n,i_m],par)
            m_pure_c = m - d[i_n,i_m]
            c[i_n,i_m] = np.fmin(linear_interp.interp_2d(par.grid_b_pd,par.grid_l,sol.c_pure_c[t],n_pure_c,m_pure_c),m_pure_c)
            inv_v[i_n,i_m] = -obj_outer(d[i_n,i_m],n,m,t,sol,par)

            # c. dcon
            obj_dcon = -obj_outer(0,n,m,t,sol,par)
            if obj_dcon > inv_v[i_n,i_m]:
                c[i_n,i_m] = linear_interp.interp_2d(par.grid_b_pd,par.grid_l,sol.c_pure_c[t],n,m)
                d[i_n,i_m] = 0
                inv_v[i_n,i_m] = obj_dcon

            # d. con
            w = linear_interp.interp_2d(par.grid_b_pd,par.grid_a_pd,sol.w[t],n,0)
            obj_con = -1.0/(utility.func(m,par) + w)
            if obj_con > inv_v[i_n,i_m]:
                c[i_n,i_m] = m
                d[i_n,i_m] = 0
                inv_v[i_n,i_m] = obj_con

            # e. derivative
            inv_vm[i_n,i_m] = 1.0/utility.marg_func(c[i_n,i_m],par)
def euler(sim, sol, par):

    euler = sim.euler

    # a. grids
    min_m = 0.50
    min_n = 0.01

    m_max = 5.00
    n_max = 5.00

    n_grid = np.linspace(min_n, n_max, par.eulerK)
    m_grid = np.linspace(min_m, m_max, par.eulerK)

    # b. loop over time
    for t in range(par.T - 1):
        for i_n in range(par.eulerK):
            for i_m in range(par.eulerK):

                # i. states
                n = n_grid[i_n]
                m = m_grid[i_m]
                m_retire = m_grid[i_m] + n_grid[i_n]

                # ii. discrete choice
                inv_v_retire = linear_interp.interp_1d(sol.m_ret[t],
                                                       sol.inv_v_ret[t],
                                                       m_retire)
                inv_v = linear_interp.interp_2d(par.grid_n, par.grid_m,
                                                sol.inv_v[t], n, m)

                if inv_v_retire > inv_v: continue

                # iii. continuous choice
                c = np.fmin(
                    linear_interp.interp_2d(par.grid_n, par.grid_m, sol.c[t],
                                            n, m), m)
                d = np.fmax(
                    linear_interp.interp_2d(par.grid_n, par.grid_m, sol.d[t],
                                            n, m), 0)
                a = m - c - d
                b = n + d + pens.func(d, par)

                if a < 0.001: continue

                # iv. shocks
                RHS = 0
                for i_eta in range(par.Neta):

                    # o. state variables
                    n_plus = par.Rb * b
                    m_plus = par.Ra * a + par.eta[i_eta]
                    m_retire_plus = m_plus + n_plus

                    # oo. discrete choice
                    inv_v_retire = linear_interp.interp_1d(
                        sol.m_ret[t + 1], sol.inv_v_ret[t + 1], m_retire_plus)
                    inv_v = linear_interp.interp_2d(par.grid_n, par.grid_m,
                                                    sol.inv_v[t + 1], n_plus,
                                                    m_plus)

                    # ooo. continous choice
                    if inv_v_retire > inv_v:
                        c_plus = np.fmin(
                            linear_interp.interp_1d(sol.m_ret[t + 1],
                                                    sol.c_ret[t + 1],
                                                    m_retire_plus),
                            m_retire_plus)
                    else:
                        c_plus = np.fmin(
                            linear_interp.interp_2d(par.grid_n, par.grid_m,
                                                    sol.c[t + 1], n_plus,
                                                    m_plus), m_plus)

                    # oooo. accumulate
                    RHS += par.w_eta[
                        i_eta] * par.beta * par.Ra * utility.marg_func(
                            c_plus, par)

                # v. euler error
                euler_raw = c - utility.inv_marg_func(RHS, par)
                euler[t, i_m, i_n] = np.log10(np.abs(euler_raw / c) + 1e-16)
def upperenvelope(out_c, out_d, out_v, holes, i_a, i_b, tri, m, n, c, d, v, Na,
                  Nb, valid, num, w, par):

    # a. simplex in (a,b)-space (or similar with constrained choices)
    i_b_1 = i_b
    i_a_1 = i_a

    if i_b == Nb - 1: return
    i_b_2 = i_b + 1
    i_a_2 = i_a

    i_b_3 = -1  # to be overwritten
    i_a_3 = -1  # to be overwritten

    if tri == 0:
        if i_a == 0 or i_b == Nb - 1: return
        i_b_3 = i_b + 1
        i_a_3 = i_a - 1
    else:
        if i_a == Na - 1: return
        i_b_3 = i_b
        i_a_3 = i_a + 1

    if ~valid[i_b_1, i_a_1] or ~valid[i_b_2, i_a_2] or ~valid[i_b_3, i_a_3]:
        return

    # b. simplex in (m,n)-space
    m1 = m[i_b_1, i_a_1]
    m2 = m[i_b_2, i_a_2]
    m3 = m[i_b_3, i_a_3]

    n1 = n[i_b_1, i_a_1]
    n2 = n[i_b_2, i_a_2]
    n3 = n[i_b_3, i_a_3]

    # c. boundary box values and indices in common grid
    m_max = np.fmax(m1, np.fmax(m2, m3))
    m_min = np.fmin(m1, np.fmin(m2, m3))
    n_max = np.fmax(n1, np.fmax(n2, n3))
    n_min = np.fmin(n1, np.fmin(n2, n3))

    im_low = 0
    if m_min >= 0:
        im_low = linear_interp.binary_search(0, par.Nm, par.grid_m, m_min)
    im_high = linear_interp.binary_search(0, par.Nm, par.grid_m, m_max) + 1

    in_low = 0
    if n_min >= 0:
        in_low = linear_interp.binary_search(0, par.Nn, par.grid_n, n_min)
    in_high = linear_interp.binary_search(0, par.Nn, par.grid_n, n_max) + 1

    # correction to allow for more extrapolation
    im_low = np.fmax(im_low - par.egm_extrap_add, 0)
    im_high = np.fmin(im_high + par.egm_extrap_add, par.Nm)
    in_low = np.fmax(in_low - par.egm_extrap_add, 0)
    in_high = np.fmin(in_high + par.egm_extrap_add, par.Nn)

    # d. prepare barycentric interpolation
    denom = (n2 - n3) * (m1 - m3) + (m3 - m2) * (n1 - n3)

    # e. loop through common grid nodes in interior of bounding box
    for i_n in range(in_low, in_high):
        for i_m in range(im_low, im_high):

            # i. common grid values
            m_now = par.grid_m[i_m]
            n_now = par.grid_n[i_n]

            # ii. barycentric coordinates
            w1 = ((n2 - n3) * (m_now - m3) + (m3 - m2) * (n_now - n3)) / denom
            w2 = ((n3 - n1) * (m_now - m3) + (m1 - m3) * (n_now - n3)) / denom
            w3 = 1 - w1 - w2

            # iii. exit if too much outside simplex
            if w1 < par.egm_extrap_w or w2 < par.egm_extrap_w or w3 < par.egm_extrap_w:
                continue

            # iv. interpolate choices
            if num == 1:  # ucon, interpolate c and d

                c_interp = w1 * c[i_b_1, i_a_1] + w2 * c[
                    i_b_2, i_a_2] + w3 * c[i_b_3, i_a_3]
                d_interp = w1 * d[i_b_1, i_a_1] + w2 * d[
                    i_b_2, i_a_2] + w3 * d[i_b_3, i_a_3]
                a_interp = m_now - c_interp - d_interp
                b_interp = n_now + d_interp + pens.func(d_interp, par)

            elif num == 2:  # dcon, interpolate c

                c_interp = w1 * c[i_b_1, i_a_1] + w2 * c[
                    i_b_2, i_a_2] + w3 * c[i_b_3, i_a_3]
                d_interp = 0.0
                a_interp = m_now - c_interp - d_interp
                b_interp = n_now  # d_interp = 0

            elif num == 3:  # acon, interpolate d

                a_interp = 0.0
                d_interp = w1 * d[i_b_1, i_a_1] + w2 * d[
                    i_b_2, i_a_2] + w3 * d[i_b_3, i_a_3]
                c_interp = m_now - a_interp - d_interp
                b_interp = n_now + d_interp + pens.func(d_interp, par)

            if c_interp <= 0.0 or d_interp < 0.0 or a_interp < 0 or b_interp < 0:
                continue

            # v. value-of-choice
            w_interp = linear_interp.interp_2d(par.grid_b_pd, par.grid_a_pd, w,
                                               b_interp, a_interp)
            v_interp = utility.func(c_interp, par) + w_interp

            # vi. update if max
            if v_interp > out_v[i_n, i_m]:

                out_v[i_n, i_m] = v_interp
                out_c[i_n, i_m] = c_interp
                out_d[i_n, i_m] = d_interp
                holes[i_n, i_m] = 0