Ejemplo n.º 1
0
def compute_q(sol, par, t, t_plus):
    """ compute the post-decision function q """

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

    # loop over delta
    for idelta in prange(par.Ndelta):

        # clean-up
        q[t, idelta, :] = 0

        # temp
        m_plus = np.empty(par.Na)
        c_plus = np.empty(par.Na)

        # loop over shock
        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]
            weight = psi_w * xi_w

            # ii. next-period extra income component
            delta_plus = par.grid_delta[idelta] / (psi * par.G)
            if t == 0:
                delta_plus *= par.zeta

            # ii. next-period cash-on-hand
            for ia in range(par.Na):
                m_plus[ia] = par.R * par.grid_a[ia] / (psi * par.G) + xi

            # iii. next-period consumption
            if par.Ndelta > 1:
                prep = linear_interp.interp_2d_prep(par.grid_delta, delta_plus,
                                                    par.Na)
            else:
                prep = linear_interp.interp_1d_prep(par.Na)

            if par.Ndelta > 1:
                linear_interp.interp_2d_only_last_vec_mon(
                    prep, par.grid_delta, par.grid_m, sol.c[t_plus],
                    delta_plus, m_plus, c_plus)
            else:
                linear_interp.interp_1d_vec_mon(prep, par.grid_m,
                                                sol.c[t_plus,
                                                      idelta], m_plus, c_plus)

            # iv. accumulate all
            for ia in range(par.Na):
                q[t, idelta,
                  ia] += weight * par.R * par.beta * utility.marg_func(
                      par.G * psi * c_plus[ia], par)
def compute_wq(t, sol, par, compute_w=False, compute_q=False):
    """ compute the post-decision functions w and/or q """

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

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

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

        # a. permanent income
        p = par.grid_p[ip]

        # b. allocate containers and initialize at zero
        m_plus = np.empty(par.Na)
        if compute_w:
            w[ip, :] = 0
            v_plus = np.empty(par.Na)
        if compute_q:
            q[ip, :] = 0
            c_plus = np.empty(par.Na)

        # c. loop over shocks and then end-of-period assets
        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 income
            p_plus = p * psi
            y_plus = p_plus * xi

            # iii. prepare interpolation in p direction
            prep = linear_interp.interp_2d_prep(par.grid_p, p_plus, par.Na)

            # iv. weight
            weight = psi_w * xi_w

            # v. next-period cash-on-hand and interpolate
            for ia in range(par.Na):
                m_plus[ia] = par.R * par.grid_a[ia] + y_plus

            # v_plus
            if compute_w:
                linear_interp.interp_2d_only_last_vec_mon(
                    prep, par.grid_p, par.grid_m, sol.v[t + 1], p_plus, m_plus,
                    v_plus)

            # c_plus
            if compute_q:
                linear_interp.interp_2d_only_last_vec_mon(
                    prep, par.grid_p, par.grid_m, sol.c[t + 1], p_plus, m_plus,
                    c_plus)

            # vi. accumulate all
            if compute_w:
                for ia in range(par.Na):
                    w[ip, ia] += weight * par.beta * v_plus[ia]
            if compute_q:
                for ia in range(par.Na):
                    q[ip, ia] += weight * par.R * par.beta * utility.marg_func(
                        c_plus[ia], par)
Ejemplo n.º 3
0
def compute(t, sol, par, G2EGM=True):

    # unpack
    w = sol.w[t]
    wa = sol.wa[t]
    if G2EGM:
        wb = sol.wb[t]

    # loop over outermost post-decision state
    for i_b in range(par.Nb_pd):

        # a. initialize
        w[i_b, :] = 0
        wa[i_b, :] = 0
        if G2EGM:
            wb[i_b, :] = 0

        # b. working memoery
        inv_v_plus = np.zeros(par.Na_pd)
        inv_vm_plus = np.zeros(par.Na_pd)
        if G2EGM:
            inv_vn_plus = np.zeros(par.Na_pd)

        inv_v_ret_plus = np.zeros(par.Na_pd)
        inv_vm_ret_plus = np.zeros(par.Na_pd)
        if G2EGM:
            inv_vn_ret_plus = np.zeros(par.Na_pd)

        # c. loop over shocks
        for i_eta in range(par.Neta):

            # i. next period states
            m_plus = par.Ra * par.grid_a_pd + par.eta[i_eta]
            n_plus = par.Rb * par.grid_b_pd[i_b]
            m_plus_ret = m_plus + n_plus

            # ii. prepare interpolation in p direction
            prep = linear_interp.interp_2d_prep(par.grid_n, n_plus, par.Na_pd)
            prep_ret = linear_interp.interp_1d_prep(par.Na_pd)

            # iii. interpolations

            # work
            linear_interp.interp_2d_only_last_vec_mon(prep, par.grid_n,
                                                      par.grid_m,
                                                      sol.inv_v[t + 1], n_plus,
                                                      m_plus, inv_v_plus)
            linear_interp.interp_2d_only_last_vec_mon_rep(
                prep, par.grid_n, par.grid_m, sol.inv_vm[t + 1], n_plus,
                m_plus, inv_vm_plus)
            if G2EGM:
                linear_interp.interp_2d_only_last_vec_mon_rep(
                    prep, par.grid_n, par.grid_m, sol.inv_vn[t + 1], n_plus,
                    m_plus, inv_vn_plus)

            # retire
            linear_interp.interp_1d_vec_mon(prep_ret, sol.m_ret[t + 1],
                                            sol.inv_v_ret[t + 1], m_plus_ret,
                                            inv_v_ret_plus)
            linear_interp.interp_1d_vec_mon_rep(prep_ret, sol.m_ret[t + 1],
                                                sol.inv_vm_ret[t + 1],
                                                m_plus_ret, inv_vm_ret_plus)
            if G2EGM:
                linear_interp.interp_1d_vec_mon_rep(prep_ret, sol.m_ret[t + 1],
                                                    sol.inv_vn_ret[t + 1],
                                                    m_plus_ret,
                                                    inv_vn_ret_plus)

            # iv. accumulate
            for i_a in range(par.Na_pd):

                if inv_v_ret_plus[i_a] > inv_v_plus[i_a]:
                    w_now = -1.0 / inv_v_ret_plus[i_a]
                    wa_now = 1.0 / inv_vm_ret_plus[i_a]
                    if G2EGM:
                        wb_now = 1.0 / inv_vn_ret_plus[i_a]
                else:
                    w_now = -1.0 / inv_v_plus[i_a]
                    wa_now = 1.0 / inv_vm_plus[i_a]
                    if G2EGM:
                        wb_now = 1.0 / inv_vn_plus[i_a]

                w[i_b, i_a] += par.w_eta[i_eta] * par.beta * w_now
                wa[i_b, i_a] += par.w_eta[i_eta] * par.Ra * par.beta * wa_now
                if G2EGM:
                    wb[i_b,
                       i_a] += par.w_eta[i_eta] * par.Rb * par.beta * wb_now
Ejemplo n.º 4
0
def compute_wq(t,sol,par,compute_q=False):
    """ compute the post-decision functions w and/or q """

    # unpack
    inv_w = sol.inv_w[t]
    q = sol.q[t]

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

        # allocate temporary containers
        m_plus = np.zeros(par.Na) # container, same lenght as grid_a
        x_plus = np.zeros(par.Na)
        w = np.zeros(par.Na) 
        inv_v_keep_plus = np.zeros(par.Na)
        inv_marg_u_keep_plus = np.zeros(par.Na)
        inv_v_adj_plus = np.zeros(par.Na)
        inv_marg_u_adj_plus = np.zeros(par.Na)
        
        # loop over other outer post-decision states
        for i_n in range(par.Nn):

            # a. permanent income and durable stock
            p = par.grid_p[i_p]
            n = par.grid_n[i_n]

            # b. initialize at zero
            for i_a in range(par.Na):
                w[i_a] = 0.0
                q[i_p,i_n,i_a] = 0.0

            # c. loop over shocks and then end-of-period assets
            for ishock in range(par.Nshocks):
                
                # i. shocks
                psi_plus = par.psi[ishock]
                psi_plus_w = par.psi_w[ishock]
                xi_plus = par.xi[ishock]
                xi_plus_w = par.xi_w[ishock]

                # ii. next-period income and durables
                p_plus = trans.p_plus_func(p,psi_plus,par)
                n_plus = trans.n_plus_func(n,par)

                # iii. prepare interpolators
                prep_keep = linear_interp.interp_3d_prep(par.grid_p,par.grid_n,p_plus,n_plus,par.Na)
                prep_adj = linear_interp.interp_2d_prep(par.grid_p,p_plus,par.Na)

                # iv. weight
                weight = psi_plus_w*xi_plus_w

                # v. next-period cash-on-hand and total resources
                for i_a in range(par.Na):
        
                    m_plus[i_a] = trans.m_plus_func(par.grid_a[i_a],p_plus,xi_plus,par)
                    x_plus[i_a] = trans.x_plus_func(m_plus[i_a],n_plus,par)
                
                # vi. interpolate
                linear_interp.interp_3d_only_last_vec_mon(prep_keep,par.grid_p,par.grid_n,par.grid_m,sol.inv_v_keep[t+1],p_plus,n_plus,m_plus,inv_v_keep_plus)
                linear_interp.interp_2d_only_last_vec_mon(prep_adj,par.grid_p,par.grid_x,sol.inv_v_adj[t+1],p_plus,x_plus,inv_v_adj_plus)
                if compute_q:
                    linear_interp.interp_3d_only_last_vec_mon_rep(prep_keep,par.grid_p,par.grid_n,par.grid_m,sol.inv_marg_u_keep[t+1],p_plus,n_plus,m_plus,inv_marg_u_keep_plus)
                    linear_interp.interp_2d_only_last_vec_mon_rep(prep_adj,par.grid_p,par.grid_x,sol.inv_marg_u_adj[t+1],p_plus,x_plus,inv_marg_u_adj_plus)
                     
                # vii. max and accumulate
                if compute_q:

                    for i_a in range(par.Na):                                

                        keep = inv_v_keep_plus[i_a] > inv_v_adj_plus[i_a]
                        if keep:
                            v_plus = -1/inv_v_keep_plus[i_a]
                            marg_u_plus = 1/inv_marg_u_keep_plus[i_a]
                        else:
                            v_plus = -1/inv_v_adj_plus[i_a]
                            marg_u_plus = 1/inv_marg_u_adj_plus[i_a]

                        w[i_a] += weight*par.beta*v_plus
                        q[i_p,i_n,i_a] += weight*par.beta*par.R*marg_u_plus

                else:

                    for i_a in range(par.Na):
                        w[i_a] += weight*par.beta*(-1.0/np.fmax(inv_v_keep_plus[i_a],inv_v_adj_plus[i_a]))
        
            # d. transform post decision value function
            for i_a in range(par.Na):
                inv_w[i_p,i_n,i_a] = -1/w[i_a]
Ejemplo n.º 5
0
def compute_w(beta,R,delta,inv_v_keep_p,inv_v_adj_p,Np,Nn,Nm,Nb,grid_p,grid_n,grid_m,grid_x,grid_b,p_trans,n_max,tau,sigma_eps,P_d_p):# P_d_p
    """ compute the post-decision function w """

    # unpack
    post_shape = (Np,Nn,Nb)
    inv_w = np.nan*np.zeros(post_shape)

    # loop over outermost post-decision state
    for i_p in prange(Np):

        # allocate temporary containers
        m_plus = np.zeros(Nb) # container, same lenght as grid_b
        x_plus = np.zeros(Nb)
        w = np.zeros(Nb) 
        inv_v_keep_plus = np.zeros(Nb)
        inv_v_adj_plus = np.zeros(Nb)
        
        # loop over other outer post-decision states
        for i_n in range(Nn):

            # a. permanent income and durable stock
            n = grid_n[i_n]

            # b. initialize at zero
            for i_b in range(Nb):
                w[i_b] = 0.0

            # c. loop over shocks and then end-of-period assets
            for ishock in range(Np):
                
                # i. shocks
                weight = p_trans[i_p,ishock]

                # ii. next-period income and durables
                n_plus = (1-delta)*n
                n_plus = np.fmin(n_plus,n_max) # upper bound
                p_plus = grid_p[ishock]

                # iii. prepare interpolators
                prep_keep = linear_interp.interp_3d_prep(grid_p,grid_n,p_plus,n_plus,Nb)
                prep_adj = linear_interp.interp_2d_prep(grid_p,p_plus,Nb)

                # v. next-period cash-on-hand and total resources
                for i_b in range(Nb):
        
                    m_plus[i_b] = R*grid_b[i_b]+ p_plus - grid_b[0] # borrowing allowed
                    x_plus[i_b] = m_plus[i_b] + P_d_p*(1-tau)*n_plus # *pris
                
                # vi. interpolate
                linear_interp.interp_3d_only_last_vec_mon(prep_keep,grid_p,grid_n,grid_m,inv_v_keep_p,p_plus,n_plus,m_plus,inv_v_keep_plus) # t+1 v
                linear_interp.interp_2d_only_last_vec_mon(prep_adj,grid_p,grid_x,inv_v_adj_p,p_plus,x_plus,inv_v_adj_plus) # t+1 v

                # vii. max and accumulate
                for i_b in range(Nb):
                    if inv_v_keep_plus[i_b] == 0:
                        v_keep =-9999.0
                    else:
                        v_keep=-1.0/inv_v_keep_plus[i_b]
                    if inv_v_adj_plus[i_b] == 0:
                        v_adj=-9999.0
                    else:
                        v_adj=-1.0/inv_v_adj_plus[i_b]   

                    v_max = np.fmax(v_keep,v_adj) 
                    val = v_max + sigma_eps*np.log(np.exp((v_keep-v_max)/sigma_eps) + np.exp((v_adj-v_max)/sigma_eps)) 
                    w[i_b] += weight*beta*(val)               


            # d. transform post decision value function
            for i_b in range(Nb):
                inv_w[i_p,i_n,i_b] = -1/w[i_b]
    return inv_w