def solve_acon(out_c,out_d,out_v,w,wb,par):

    num = 3

    # i. allocate
    c = np.zeros((par.Nc_acon,par.Nb_acon))
    d = np.zeros((par.Nc_acon,par.Nb_acon))
    a = np.zeros((par.Nc_acon,par.Nb_acon))
    b = np.zeros((par.Nc_acon,par.Nb_acon))
    w_acon = np.zeros((par.Nc_acon,par.Nb_acon))

    for i_b in range(par.Nb_acon):
        
        # ii. setup
        wb_acon = linear_interp.interp_2d(par.grid_b_pd,par.grid_a_pd,wb,par.b_acon[i_b],0)

        c_min = utility.inv_marg_func((par.chi+1)*wb_acon,par)
        c_max = utility.inv_marg_func(wb_acon,par)

        c[:,i_b] = misc.nonlinspace_jit(c_min,c_max,par.Nc_acon,par.phi_m)
        
        # iii. choices
        d[:,i_b] = par.chi/(utility.marg_func(c[:,i_b],par)/(wb_acon)-1)-1
                        
        # iv. post-decision states and value function
        b[:,i_b] = par.b_acon[i_b]
        w_acon[:,i_b] = linear_interp.interp_2d(par.grid_b_pd,par.grid_a_pd,w,par.b_acon[i_b],0)
                
    # v. states and value
    m,n,v = inv_mn_and_v(c,d,a,b,w_acon,par)
                    
    # vi. upperenvelope and interp to common
    upperenvelope.compute(out_c,out_d,out_v,m,n,c,d,v,num,w,par)
示例#2
0
def obj_bellman(c, p, m, v_plus, par):
    """ evaluate bellman equation """

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

    # b. continuation value
    w = 0
    for ishock in range(par.Nshocks):

        # i. shocks
        psi = par.psi[ishock]
        psi_w = par.psi_w[ishock]
        xi = par.xi[ishock]
        xi_w = par.xi_w[ishock]

        # ii. next-period states
        p_plus = p * psi
        y_plus = p_plus * xi
        m_plus = par.R * a + y_plus

        # iii. weight
        weight = psi_w * xi_w

        # iv. interpolate
        w += weight * par.beta * linear_interp.interp_2d(
            par.grid_p, par.grid_m, v_plus, p_plus, m_plus)

    # c. total value
    value_of_choice = utility.func(c, par) + w

    return -value_of_choice  # we are minimizing
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
示例#4
0
def solve_adj(inv_v_keep,c_keep,d_ubar,sigma,n_max,Np,Nx,grid_n,grid_m,grid_x,P_d_p): # P_d_p,
    """solve bellman equation for adjusters using nvfi"""

    # unpack output
    adj_shape = (Np,Nx)
    inv_v_adj = np.zeros(adj_shape)
    d_adj = np.zeros(adj_shape)
    c_adj = np.zeros(adj_shape)

    # loop over outer states
    for i_p in prange(Np):
            
        # loop over x state
        for i_x in range(Nx):
            
            # a. cash-on-hand
            x = grid_x[i_x]
            if i_x == 0:
                d_adj[i_p,i_x] = 0
                c_adj[i_p,i_x] = 0
                inv_v_adj[i_p,i_x] = 0
      
                continue

            # b. optimal choice
            d_low = np.fmin(x/2,1e-8)
            d_high = np.fmin(x/P_d_p,n_max) # cash on hand grid now x = m + (1-tau)*n + B.C. (eg 0.5, or collateral eg. coll_ratio*n)
            d_adj[i_p,i_x] = golden_section_search.optimizer(obj_adj,d_low,d_high,args=(x,inv_v_keep[i_p],grid_n,grid_m,P_d_p),tol=1e-8)

            # c. optimal value
            m = x - P_d_p*d_adj[i_p,i_x]
            c_adj[i_p,i_x] = linear_interp.interp_2d(grid_n,grid_m,c_keep[i_p],d_adj[i_p,i_x],m)
            inv_v_adj[i_p,i_x] = -obj_adj(d_adj[i_p,i_x],x,inv_v_keep[i_p],grid_n,grid_m,P_d_p)

    return inv_v_adj, d_adj, c_adj
def compute_wq_simple(t, sol, par, compute_w=False, compute_q=False):
    """ compute the post-decision functions w and/or q """

    # this is a variant of Algorithm 3 in Druedahl (2019): A Guide to Solve Non-Convex Consumption-Saving Problems

    # note: same result as compute_wq, simpler code, but much slower

    # unpack (helps numba optimize)
    w = sol.w
    q = sol.q

    # loop over outermost post-decision state
    for ip in prange(par.Np):  # in parallel

        for ia in range(par.Na):

            # initialize at zero
            if compute_w:
                w[ip, ia] = 0
            if compute_q:
                q[ip, ia] = 0

            for ishock in range(par.Nshocks):

                # i. shocks
                psi = par.psi[ishock]
                psi_w = par.psi_w[ishock]
                xi = par.xi[ishock]
                xi_w = par.xi_w[ishock]

                # ii. next-period states
                p_plus = par.grid_p[ip] * psi
                y_plus = p_plus * xi
                m_plus = par.R * par.grid_a[ia] + y_plus

                # iii. weights
                weight = psi_w * xi_w

                # iv. interpolate and accumulate
                if compute_w:
                    w[ip, ia] += weight * par.beta * linear_interp.interp_2d(
                        par.grid_p, par.grid_m, sol.v[t + 1], p_plus, m_plus)
                if compute_q:
                    c_plus_temp = linear_interp.interp_2d(
                        par.grid_p, par.grid_m, sol.c[t + 1], p_plus, m_plus)
                    q[ip, ia] += weight * par.R * par.beta * utility.marg_func(
                        c_plus_temp, par)
示例#6
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)
示例#7
0
def optimal_choice(t, p, n, m, discrete, d, c, a, sol, par):

    x = trans.x_plus_func(m, n, par)

    # a. discrete choice
    inv_v_keep = linear_interp.interp_3d(par.grid_p, par.grid_n, par.grid_m,
                                         sol.inv_v_keep[t], p, n, m)
    inv_v_adj = linear_interp.interp_2d(par.grid_p, par.grid_x,
                                        sol.inv_v_adj[t], p, x)
    adjust = inv_v_adj > inv_v_keep

    # b. continuous choices
    if adjust:

        discrete[0] = 1

        d[0] = linear_interp.interp_2d(par.grid_p, par.grid_x, sol.d_adj[t], p,
                                       x)

        c[0] = linear_interp.interp_2d(par.grid_p, par.grid_x, sol.c_adj[t], p,
                                       x)

        tot = d[0] + c[0]
        if tot > x:
            d[0] *= x / tot
            c[0] *= x / tot
            a[0] = 0.0
        else:
            a[0] = x - tot

    else:

        discrete[0] = 0

        d[0] = n

        c[0] = linear_interp.interp_3d(par.grid_p, par.grid_n, par.grid_m,
                                       sol.c_keep[t], p, n, m)

        if c[0] > m:
            c[0] = m
            a[0] = 0.0
        else:
            a[0] = m - c[0]
示例#8
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
示例#9
0
def obj_adj(d,x,inv_v_keep,grid_n,grid_m):
    """ evaluate bellman equation """

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

    # b. durables
    n = d
    
    # c. value-of-choice
    return -linear_interp.interp_2d(grid_n,grid_m,inv_v_keep,n,m)  # we are minimizing
示例#10
0
def solve_adj(t, sol, par):
    """solve bellman equation for adjusters using nvfi"""

    # unpack output
    inv_v = sol.inv_v_adj[t]
    inv_marg_u = sol.inv_marg_u_adj[t]
    d = sol.d_adj[t]
    c = sol.c_adj[t]

    # unpack input
    inv_v_keep = sol.inv_v_keep[t]
    c_keep = sol.c_keep[t]
    grid_n = par.grid_n
    grid_m = par.grid_m
    d_ubar = par.d_ubar
    alpha = par.alpha
    rho = par.rho

    # loop over outer states
    for i_p in prange(par.Np):

        # loop over x state
        for i_x in range(par.Nx):

            # a. cash-on-hand
            x = par.grid_x[i_x]
            if i_x == 0:
                d[i_p, i_x] = 0
                c[i_p, i_x] = 0
                inv_v[i_p, i_x] = 0
                if par.do_marg_u:
                    inv_marg_u[i_p, i_x] = 0
                continue

            # b. optimal choice
            d_low = np.fmin(x / 2, 1e-8)
            d_high = np.fmin(x, par.n_max)
            d[i_p,
              i_x] = golden_section_search.optimizer(obj_adj,
                                                     d_low,
                                                     d_high,
                                                     args=(x, inv_v_keep[i_p],
                                                           grid_n, grid_m),
                                                     tol=par.tol)

            # c. optimal value
            m = x - d[i_p, i_x]
            c[i_p, i_x] = linear_interp.interp_2d(par.grid_n, par.grid_m,
                                                  c_keep[i_p], d[i_p, i_x], m)
            inv_v[i_p, i_x] = -obj_adj(d[i_p, i_x], x, inv_v_keep[i_p], grid_n,
                                       grid_m)
            if par.do_marg_u:
                inv_marg_u[i_p, i_x] = 1 / utility.marg_func_nopar(
                    c[i_p, i_x], d[i_p, i_x], d_ubar, alpha, rho)
def run(simT, simN, b_policy, d_policy, c_policy, e_grid, b_grid, d_grid,
        ergodic, e_cum, Ne, sim_p, sim_b, sim_d, sim_c, unif):

    # i. initial guess on productivity distribution

    for i in range(Ne):
        if i == 0:
            sim_p[0, 0:int(ergodic[i])] = i
        else:
            sim_p[
                0,
                int(np.sum(ergodic[:i])):int(np.sum(ergodic[:i]) +
                                             ergodic[i])] = i

    # ii. simulate
    for t in range(1, simT):
        for n in prange(
                simN):  # parallelize inner loop as time needs to be consistent

            # i. Markov Chain shock
            sim_p[t, n] = choice(e_cum[int(sim_p[t - 1, n])], unif[t, n])

            # ii. last period d,b
            b_minus = sim_b[t - 1, n]
            d_minus = sim_d[t - 1, n]

            # iii. find current d,b by interpolation of policy functions
            sim_d[t, n] = linear_interp.interp_2d(
                b_grid, d_grid, d_policy[int(sim_p[t, n]), :, :], b_minus,
                d_minus)
            sim_b[t, n] = linear_interp.interp_2d(
                b_grid, d_grid, b_policy[int(sim_p[t, n]), :, :], b_minus,
                d_minus)
            sim_c[t, n] = linear_interp.interp_2d(
                b_grid, d_grid, c_policy[int(sim_p[t, n]), :, :], b_minus,
                d_minus)

    return sim_b, sim_d, sim_c
def value_of_choice(t, c, d, p, x, inv_v_keep, inv_v_adj, par):

    # a. end-of-period-assets
    a = x - c - d

    # b. continuation value
    w = 0
    for ishock in range(par.Nshocks):

        # i. shocks
        psi = par.psi[ishock]
        psi_w = par.psi_w[ishock]
        xi = par.xi[ishock]
        xi_w = par.xi_w[ishock]

        # ii. next-period states
        p_plus = trans.p_plus_func(p, psi, par)
        n_plus = trans.n_plus_func(d, par)
        m_plus = trans.m_plus_func(a, p_plus, xi, par)
        x_plus = trans.x_plus_func(m_plus, n_plus, par)

        # iii. weight
        weight = psi_w * xi_w

        # iv. update
        inv_v_plus_keep_now = linear_interp.interp_3d(par.grid_p, par.grid_n,
                                                      par.grid_m,
                                                      inv_v_keep[t + 1],
                                                      p_plus, n_plus, m_plus)

        inv_v_plus_adj_now = linear_interp.interp_2d(par.grid_p, par.grid_x,
                                                     inv_v_adj[t + 1], p_plus,
                                                     x_plus)

        v_plus_now = -np.inf  # huge negative value

        if inv_v_plus_keep_now > inv_v_plus_adj_now and inv_v_plus_keep_now > 0:
            v_plus_now = -1 / inv_v_plus_keep_now
        elif inv_v_plus_adj_now > 0:
            v_plus_now = -1 / inv_v_plus_adj_now

        w += weight * par.beta * v_plus_now

    # v. total value
    v = utility.func(c, d, par) + w

    return v  # we are minimizing
def lifecycle(sim, sol, par):
    """ simulate full life-cycle """

    # unpack (to help numba optimize)
    p = sim.p
    m = sim.m
    c = sim.c
    a = sim.a

    for t in range(par.simT):
        for i in prange(par.simN):  # in parallel

            # a. beginning of period states
            if t == 0:
                p[t, i] = 1
                m[t, i] = 1
            else:
                p[t, i] = sim.psi[t, i] * p[t - 1, i]
                m[t, i] = par.R * a[t - 1, i] + sim.xi[t, i] * p[t, i]

            # b. choices
            c[t, i] = linear_interp.interp_2d(par.grid_p, par.grid_m, sol.c[t],
                                              p[t, i], m[t, i])
            a[t, i] = m[t, i] - c[t, i]
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
def fill_holes(out_c, out_d, out_v, holes, w, num, par):

    # a. locate global bounding box with content
    i_n_min = 0
    i_n_max = par.Nn - 1
    min_n = np.inf
    max_n = -np.inf

    i_m_min = 0
    i_m_max = par.Nm - 1
    min_m = np.inf
    max_m = -np.inf

    for i_n in range(par.Nn):
        for i_m in range(par.Nn):

            m_now = par.grid_m[i_m]
            n_now = par.grid_n[i_n]

            if holes[i_n, i_m] == 1: continue

            if m_now < min_m:
                min_m = m_now
                i_m_min = i_m

            if m_now > max_m:
                max_m = m_now
                i_m_max = i_m

            if n_now < min_n:
                min_n = n_now
                i_n_min = i_n

            if n_now > max_n:
                max_n = n_now
                i_n_max = i_n

    # b. loop through m, n, k nodes to detect holes
    i_n_max = np.fmin(i_n_max + 1, par.Nn)
    i_m_max = np.fmin(i_m_max + 1, par.Nm)
    for i_n in range(i_n_min, i_n_max):
        for i_m in range(i_m_min, i_m_max):

            if holes[i_n, i_m] == 0:  # if not hole
                continue

            m_now = par.grid_m[i_m]
            n_now = par.grid_n[i_n]
            m_add = 2
            n_add = 2

            # loop over points close by
            i_n_close_min = np.fmax(0, i_n - n_add)
            i_n_close_max = np.fmin(i_n + n_add + 1, par.Nn)

            i_m_close_min = np.fmax(0, i_m - m_add)
            i_m_close_max = np.fmin(i_m + m_add + 1, par.Nm)

            for i_n_close in range(i_n_close_min, i_n_close_max):
                for i_m_close in range(i_m_close_min, i_m_close_max):

                    if holes[i_n_close, i_m_close] == 1:  # if itself a hole
                        continue

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

                        c_interp = out_c[i_n_close, i_m_close]
                        d_interp = out_d[i_n_close, i_m_close]
                        a_interp = m_now - c_interp - d_interp
                        b_interp = n_now + d_interp + par.chi * np.log(
                            1.0 + d_interp)

                    elif num == 2:  # dcon, interpolate c

                        c_interp = out_c[i_n_close, i_m_close]
                        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 = out_d[i_n_close, i_m_close]
                        c_interp = m_now - a_interp - d_interp
                        b_interp = n_now + d_interp + par.chi * np.log(
                            1.0 + d_interp)

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

                    # 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

                    # update if better
                    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
示例#17
0
def optimal_choice_2d(t, p, n1, n2, m, discrete, d1, d2, c, a, sol, par):

    # a. discrete choice
    inv_v = 0
    inv_v_keep = linear_interp.interp_4d(par.grid_p, par.grid_n, par.grid_n,
                                         par.grid_m, sol.inv_v_keep_2d[t], p,
                                         n1, n2, m)

    x_full = m + (1 - par.tau1) * n1 + (1 - par.tau2) * n2
    inv_v_adj_full = linear_interp.interp_2d(par.grid_p, par.grid_x,
                                             sol.inv_v_adj_full_2d[t], p,
                                             x_full)

    x_d1 = m + (1 - par.tau1) * n1
    inv_v_adj_d1 = linear_interp.interp_3d(par.grid_p, par.grid_n, par.grid_x,
                                           sol.inv_v_adj_d1_2d[t], p, n2, x_d1)

    x_d2 = m + (1 - par.tau2) * n2
    inv_v_adj_d2 = linear_interp.interp_3d(par.grid_p, par.grid_n, par.grid_x,
                                           sol.inv_v_adj_d2_2d[t], p, n1, x_d2)

    keep = False
    adj_full = False
    adj_d1 = False
    adj_d2 = False

    if inv_v_keep > inv_v:
        inv_v = inv_v_keep
        keep = True

    if inv_v_adj_full > inv_v:
        inv_v = inv_v_adj_full
        keep = False
        adj_full = True

    if inv_v_adj_d1 > inv_v:
        inv_v = inv_v_adj_d1
        keep = False
        adj_full = False
        adj_d1 = True

    if inv_v_adj_d2 > inv_v:
        inv_v = inv_v_adj_d2
        keep = False
        adj_full = False
        adj_d1 = False
        adj_d2 = True

    # b. continuous choices
    if keep:

        discrete[0] = 0

        d1[0] = n1
        d2[0] = n2

        c[0] = linear_interp.interp_4d(par.grid_p, par.grid_n, par.grid_n,
                                       par.grid_m, sol.c_keep_2d[t], p, n1, n2,
                                       m)

        if c[0] > m:
            c[0] = m
            a[0] = 0.0
        else:
            a[0] = m - c[0]

    elif adj_full:

        discrete[0] = 1

        d1[0] = linear_interp.interp_2d(par.grid_p, par.grid_x,
                                        sol.d1_adj_full_2d[t], p, x_full)

        d2[0] = linear_interp.interp_2d(par.grid_p, par.grid_x,
                                        sol.d2_adj_full_2d[t], p, x_full)

        c[0] = linear_interp.interp_2d(par.grid_p, par.grid_x,
                                       sol.c_adj_full_2d[t], p, x_full)

        tot = d1[0] + d2[0] + c[0]
        if tot > x_full:
            d1[0] *= x_full / tot
            d2[0] *= x_full / tot
            c[0] *= x_full / tot
            a[0] = 0.0
        else:
            a[0] = x_full - tot

    elif adj_d1:

        discrete[0] = 2

        d1[0] = linear_interp.interp_3d(par.grid_p, par.grid_n, par.grid_x,
                                        sol.d1_adj_d1_2d[t], p, n2, x_d1)

        d2[0] = n2

        c[0] = linear_interp.interp_3d(par.grid_p, par.grid_n, par.grid_x,
                                       sol.c_adj_d1_2d[t], p, n2, x_d1)

        tot = d1[0] + c[0]
        if tot > x_d1:
            d1[0] *= x_d1 / tot
            c[0] *= x_d1 / tot
            a[0] = 0.0
        else:
            a[0] = x_d1 - tot

    elif adj_d2:

        discrete[0] = 3

        d1[0] = n1

        d2[0] = linear_interp.interp_3d(par.grid_p, par.grid_n, par.grid_x,
                                        sol.d2_adj_d2_2d[t], p, n1, x_d2)

        c[0] = linear_interp.interp_3d(par.grid_p, par.grid_n, par.grid_x,
                                       sol.c_adj_d2_2d[t], p, n1, x_d2)

        tot = d2[0] + c[0]
        if tot > x_d2:
            d2[0] *= x_d2 / tot
            c[0] *= x_d2 / tot
            a[0] = 0.0
        else:
            a[0] = x_d2 - tot