Exemplo n.º 1
0
    def setup_grids(self):
        """ construct grids for states and shocks """

        if self.solmethod in ['negm', 'negm_cpp']:
            self.par.do_marg_u = True

        # a. states
        self.par.grid_p = misc.nonlinspace(self.par.p_min, self.par.p_max,
                                           self.par.Np, 1.1)
        self.par.grid_n = misc.nonlinspace(0, self.par.n_max, self.par.Nn, 1.1)
        self.par.grid_m = misc.nonlinspace(0, self.par.m_max, self.par.Nm, 1.1)
        self.par.grid_x = misc.nonlinspace(0, self.par.x_max, self.par.Nx, 1.1)

        # b. post-decision states
        self.par.grid_a = misc.nonlinspace(0, self.par.a_max, self.par.Na, 1.1)

        # c. shocks
        shocks = misc.create_shocks(self.par.sigma_psi, self.par.Npsi,
                                    self.par.sigma_xi, self.par.Nxi,
                                    self.par.pi, self.par.mu)
        self.par.psi, self.par.psi_w, self.par.xi, self.par.xi_w, self.par.Nshocks = shocks

        # d. set seed
        np.random.seed(self.par.sim_seed)

        # e. timing
        self.par.time_w = np.zeros(self.par.T)
        self.par.time_keep = np.zeros(self.par.T)
        self.par.time_adj = np.zeros(self.par.T)
    def create_grids(self):
        """ construct grids for states and shocks """

        par = self.par

        if self.solmethod in ['negm', 'negm_cpp', 'negm_2d_cpp']:
            par.do_marg_u = True

        # a. states
        par.grid_p = nonlinspace(par.p_min, par.p_max, par.Np, 1.1)
        par.grid_n = nonlinspace(0, par.n_max, par.Nn, 1.1)
        par.grid_m = nonlinspace(0, par.m_max, par.Nm, 1.1)
        par.grid_x = nonlinspace(0, par.x_max, par.Nx, 1.1)

        # b. post-decision states
        par.grid_a = nonlinspace(0, par.a_max, par.Na, 1.1)

        # c. shocks
        shocks = create_shocks(par.sigma_psi, par.Npsi, par.sigma_xi, par.Nxi,
                               par.pi, par.mu)
        par.psi, par.psi_w, par.xi, par.xi_w, par.Nshocks = shocks

        # d. set seed
        np.random.seed(par.sim_seed)

        # e. timing
        par.time_w = np.zeros(par.T)
        par.time_keep = np.zeros(par.T)
        par.time_adj = np.zeros(par.T)
        par.time_adj_full = np.zeros(par.T)
        par.time_adj_d1 = np.zeros(par.T)
        par.time_adj_d2 = np.zeros(par.T)
    def setup_grids(self):
        """ construct grids for states and shocks """

        # a. states (unequally spaced vectors of length Nm)
        self.par.grid_m = misc.nonlinspace(1e-6, 20, self.par.Nm, 1.1)
        self.par.grid_p = misc.nonlinspace(1e-4, 10, self.par.Np, 1.1)

        # b. post-decision states (unequally spaced vector of length Na)
        self.par.grid_a = misc.nonlinspace(1e-6, 20, self.par.Na, 1.1)

        # c. shocks (qudrature nodes and weights using GaussHermite)
        shocks = misc.create_shocks(self.par.sigma_psi, self.par.Npsi,
                                    self.par.sigma_xi, self.par.Nxi,
                                    self.par.pi, self.par.mu)
        self.par.psi, self.par.psi_w, self.par.xi, self.par.xi_w, self.par.Nshocks = shocks

        # d. set seed
        np.random.seed(self.par.sim_seed)
Exemplo n.º 4
0
def grids(par):
    """ construct grids for states and shocks """

    # a. a-grid (unequally spaced vector of length Na)
    par.grid_a = misc.nonlinspace(par.tol, par.a_max, par.Na, par.a_phi)

    # b. shocks (quadrature nodes and weights for GaussHermite)
    par.xi = np.nan * np.zeros((len(par.MA), par.Nxi))
    par.xi_w = np.nan * np.zeros((len(par.MA), par.Nxi))
    for ma in range(len(par.MA)):
        par.xi[ma], par.xi_w[ma] = funs.GaussHermite_lognorm(
            par.var[ma], par.Nxi)

    # # c. correlated shocks for joint labor income (only for couples)
    if par.couple:
        par.xi_corr, par.w_corr = funs.GH_lognorm_corr(par.var, par.cov,
                                                       par.Nxi_men,
                                                       par.Nxi_women)
Exemplo n.º 5
0
def ss_calib(calib, settings): 
    # Load income tax functions 
    with open('Tax_Function_Fit/cs_avg.pickle', 'rb') as f:
        cs_avg = pickle.load(f)
    with open('Tax_Function_Fit/cs_marg.pickle', 'rb') as f:
        cs_marg = pickle.load(f)


    # Grids
    nA = 250
    nBeta = 5  
    ne = 11 
    nN = 2
    amax = 50  
   
    e_grid, pi_ern, Pi_ern = utils.markov_rouwenhorst(rho= 0.94, sigma= 0.7, N=ne) # Values from IMPC: rho = 0.91, variance = 0.92. Floden and linde (2001) for Sweden persistence values. 

    nPoints = [nBeta, ne, nA]
 
    beta_mid_guess  = 0.96513206
    beta_var_guess  =  0.02
    beta_disp_guess =  0.06
    vphi_guess       = 2.125509040803471
    nonlintax_guess  =  0.049834087883106254

    kappa_g = 0.04
    

    dist_type = "LeftSkewed"
    beta, pi_beta, Pi_beta = beta_dist(nBeta, beta_mid_guess, beta_var_guess, beta_disp_guess, dist_type )
    

    N = 0.95  
    b_ratio = 0.51

    mix = 0
    destr = 0.1
    eis = 0.5 
    frisch = 0.5 
    alpha = 0.35

    G = 0.24
    VAT = 0
    U = 0.05
          
    Y = 1 
    N = 1 - U   

    S, q, pMatch, V, Tight, ma, destrO, destrNO, nPos  = SAM_calib(U, destr, settings)
    Eq = q 
    
    pi_N = [N,1-N]    
    Pi_N = np.empty([2,2])
    Pi_N[0,0] = 1 - destr * (1-q)
    Pi_N[0,1] = destr * (1-q)
    Pi_N[1,1] = 1 - q * (1-destrO)
    Pi_N[1,0] = q * (1-destrO)
   
    Pi   =  np.kron(np.kron(Pi_beta, Pi_ern), Pi_N)
    pi_e =  np.kron(np.kron(pi_beta, pi_ern), pi_N)
    Pi_seed = pi_e
    
    r = 0.02 / 4 # 2% yearly    
    rstar = r   
    P = 1
    pi = 0
    i = r + pi 
   

    Benefit_type = 0 # proportional to e_grid  
    vacK_rate = 0.05
    w_g = 0.58 
    vacK_g = vacK_rate * w_g * N

    K = 8 
    mup = 1.1
    mc = 1 / mup 
    
    destr_L = destr
    destrO_L = destrO 
    
    
    A_tot = 2.3
    B  = A_tot * 0.5    
    p = A_tot - B
    T_firms_g = 0 
    F_cost_g = 0.05
    Agg_C_guess  = 0.4
    
    
    if settings['Fvac_share']:
        Fvac_factor = settings['Fvac_factor']
    else: 
        Fvac_factor = 5 

    def Asset_calib(x):
        T_firms_g, Agg_C_g, vacK_g, F_cost_g, w_g = x

        U_inc_g, U_inc_agg_g  = Unemp_benefit(Benefit_type, w_g * b_ratio, e_grid, pi_ern, ne, w_g)
        ssAvgInc =  N * w_g   + (1-N) * U_inc_agg_g
        tax_N  = N            * np.vdot(avgTaxf(w_g   * e_grid, ssAvgInc, cs_avg) * w_g * e_grid , pi_ern)
        tax_S  = (1-N)        * np.vdot(avgTaxf(U_inc_g, ssAvgInc, cs_avg) * U_inc_g, pi_ern)    
        
        
        mc = 1/mup
        rk = alpha * mc * Y / K
        delta = rk - r 
        I = K * delta  
        
        b = optimize.fsolve(b_calib, [w_g * 0.5], args = (Benefit_type, e_grid, pi_ern, ne, w_g, b_ratio, N, cs_avg, avgTaxf) )

        U_inc, U_inc_agg  = Unemp_benefit(Benefit_type, b, e_grid, pi_ern, ne, w_g)               
        MPL = (1-alpha) * mc * Y / N         

        if settings['SAM_model'] == 'Standard':
            JV = 0
            JM = (MPL - w_g) / (1 -  (1-destr) /(1+r))
            LS_res = JV - (- vacK_g + pMatch * JM)
            Vac_costs = vacK_g  
        elif settings['SAM_model'] == 'Costly_vac_creation':            
            if Fvac_factor == np.inf:
                Fvac  = vacK_g / nPos 
                vacK_g = 0 
            else:
                if settings['Fvac_share']:
                    Tot_cost = vacK_g #+ Fvac * nPos
                    Fvac  = Fvac_factor * Tot_cost / nPos
                    vacK_g =  Tot_cost - Fvac * nPos
                else:
                    Fvac  = Fvac_factor / (nPos / vacK_g)
                JV = Fvac * nPos
                
            if settings['SAM_model_variant']  == 'simple':
                JM = (MPL - w_g) / (1 -  (1-destr) /(1+r))
                LS_res = JV - (- vacK_g + pMatch * JM + (1-pMatch) * JV / (1+r))    
            else:              
                 JM  = (JV - (1-pMatch) *(1-destrO) * JV /(1+r) + vacK_g) / pMatch
                 LS_res = JM - ((MPL-w_g) + (1-destrO) * (1-destrNO)/(1+r) * JM  + destrNO * (1-destrO)  * JV /(1+r))                                            
                
            Vac_costs = vacK_g  + Fvac * nPos**2
            
        div = 1 - w_g * N  - I - Vac_costs - F_cost_g - T_firms_g
        p_res = div / r - p
       
        A_tot_ = p + B
        G_rev = tax_N + tax_S +  VAT * Agg_C_g   +  B + T_firms_g 
        G_exp = G +  U_inc_agg * (1-N) +  B * (1 + r)  
            
        lumpsum_T_res = G_rev - G_exp
        Agg_C  = (ssAvgInc - tax_N - tax_S   + A_tot_ * r ) / (1+VAT) 

        A2I =  (p  +   B) / (ssAvgInc - tax_N - tax_S + A_tot_ * r - A_tot_ * kappa_g * 0.15 )  

        w_res = ( MPL / w_g-1)   -  settings['vac2w_costs']

        return  np.array([lumpsum_T_res, Agg_C - Agg_C_g, LS_res, p_res, w_res]) 
    

    sol = optimize.root(Asset_calib, np.array([T_firms_g, Agg_C_guess, vacK_g, F_cost_g, w_g]),  method='hybr')
    (T_firms, Agg_C, vacK, F_cost, w) = sol.x 
    if not sol.success:
        raise Exception("Solver did not succeed") 
    lumpsum_T = 0 
    rk = alpha * mc / K
    delta = rk - r 
    I = K * delta  
    Fvac  = Fvac_factor / (nPos / vacK)
    
    assert w > 0 
    assert vacK >= 0 

    wss = w 
    sBorrow = 0.5
    a_lb = -w  * sBorrow
    a_grid = nonlinspace(a_lb , amax, nA, 1.5)         
    
    b = optimize.fsolve(b_calib, [w * 0.5], args = (Benefit_type, e_grid, pi_ern, ne, w, b_ratio, N, cs_avg, avgTaxf))
    U_inc, U_inc_agg  = Unemp_benefit(Benefit_type, b, e_grid, pi_ern, ne, w) 
    ssAvgInc =  N * w   + (1-N) * U_inc_agg # average taxable labor income in steady state     
    tax_N  = N            * np.vdot(avgTaxf(w   * e_grid, ssAvgInc, cs_avg) * w * e_grid , pi_ern)
    tax_S  = (1-N)        * np.vdot(avgTaxf(U_inc, ssAvgInc, cs_avg) * U_inc, pi_ern)
    
           
    Z = Y / (K ** alpha * N**(1-alpha))
    Zss = Z     

    MPL = (1-alpha) * mc * Y / N


    Tight = V / S 
    if settings['SAM_model'] == 'Standard':
        Vac_costs = vacK    
        JV = 0
        JM = (MPL - w) / (1 -  (1-destr) /(1+r))            
    elif settings['SAM_model'] == 'Costly_vac_creation':
        if settings['Fvac_share']:
                Tot_cost = vacK #+ Fvac * nPos
                Fvac  = Fvac_factor * Tot_cost / nPos
                vacK =  Tot_cost - Fvac * nPos            
        else:
            if Fvac_factor == np.inf:
                Fvac  = vacK / nPos 
                vacK = 0 
            else:
                Fvac  = Fvac_factor / (nPos / vacK)            
        JV = Fvac * nPos            
        Vac_costs = vacK  + Fvac * nPos**2
        if settings['SAM_model_variant']  == 'simple':
            JM = (MPL - w) / (1 -  (1-destr) /(1+r))  
        else:
            JM  = (JV - (1-pMatch) *(1-destrO) * JV /(1+r) + vacK) / pMatch
        
    div =  1 - w * N  - I - Vac_costs - F_cost - T_firms

    p = div / r
    
    MF_Div = 0
    mix = 0
    ra_test =  (div + p)  / A_tot  + (1+r ) * B / A_tot - (1  + r)   
    ra = r
    
    assert abs(ra_test) < 1e-07
    
    Agg_C  = (ssAvgInc  - tax_N  - tax_S   + lumpsum_T + A_tot * r ) / (1+VAT) 

    walras1 = 1 - Agg_C  - I - G - Vac_costs  - F_cost
    print('Walras 1', walras1)
    #assert abs(walras1) < 1e-8
    #print((100*Vac_costs/0.7)/(w))

    beta_max = 1/(1+ra)     
    assert  max(beta)  < beta_max
    
    Tss = lumpsum_T + nonlintax_guess
    T_dist = 0.1
    T = transfers(pi_ern, Tss, e_grid, T_dist)     
    bnds = [-8, 8]
    args = (U_inc, w, pi_ern, e_grid, N, div , Tss, ssAvgInc, cs_avg, transfers, avgTaxf)
    res = optimize.minimize_scalar(Income_gini, np.array([T_dist]), method='Bounded',  bounds = bnds, args=args)  
    T_dist = res.x 
    Income_gini_disp(x = T_dist, args = args)
    #Tss = lumpsum_T
    Ttd = 0
    ttd_inf = {'p75' : 0, 'ss_dist' : np.zeros((ne*nBeta, nA)) }


    # initialize guess for policy function iteration
    s_match = True     
    use_saved = settings['use_saved']
    save = settings['save']
    if use_saved == True:
        try:
            npzfile = np.load('init_values.npz')        
            EVa = npzfile['x']
            if (EVa.shape == (nBeta*ne*nN, nA)) is False: # check that loaded values match in shape 
                s_match = False            
        except OSError as e:
            s_match = False

    
    if s_match == False or use_saved == False:        
        coh_n  =  np.reshape( (1-avgTaxf(w   * e_grid , ssAvgInc, cs_avg)) * w * e_grid + T,   ((1, ne, 1))) 
        coh_s  =  np.reshape( (1-avgTaxf(b  * e_grid, ssAvgInc, cs_avg))   * b * e_grid + T ,   ((1, ne, 1)))  
        coh_n  = np.reshape(np.broadcast_to(coh_n, (nBeta,ne, nA)), (ne*nBeta, nA))
        coh_s  = np.reshape(np.broadcast_to(coh_s, (nBeta,ne, nA)), (ne*nBeta, nA))    
        EnVa =  (1 + r) * (0.8  * coh_n) ** (-1 / eis) 
        EuVa =  (1 + r) * (0.8  * (coh_s )) ** (-1 / eis) 
        EVa = np.reshape(np.stack((np.reshape(EnVa, (nBeta, ne, nA)), np.reshape(EuVa, (nBeta, ne, nA))), axis=-2), (nBeta* ne*nN, nA))
        
    ssc = np.ones([EVa.size])
    #beta_mid_guess, beta_var_guess, beta_disp_guess, obj  = init_search()
    lumpsum_T_init = lumpsum_T
    Tss = lumpsum_T 

    args = {}
    args = { 'EVa' : EVa,  'Pi' : Pi, 'dist_type' : dist_type, 'nBeta' : nBeta, 'Pi_ern' : Pi_ern, 'a_grid' : a_grid, 'pi_e' : pi_e, 'ssN' : N, 
             'e_grid' : e_grid, 'pi_ern' : pi_ern, 'w' : w, 'ra' : ra, 'eis' : eis, 'Eq' : q, 'N' : N, 'destr_L' : destr, 'U_inc' : U_inc, 'T_dist' : T_dist,
             'div' : div, 'lumpsum_T_init' : lumpsum_T_init, 'ssAvgInc' : ssAvgInc, 'VAT' : VAT, 'pi' : pi, 'rstar' : rstar, 'MF_Div' : MF_Div, 'mix' : mix, 'wss' : w, 
             'nPoints' : nPoints, 'cs_avg' : cs_avg, 'dist_type' : dist_type, 'B' : B, 'rss' : r, 'p' : p , 'sBorrow' : sBorrow, 'hss' : 1,  'T_firms' : T_firms,
             'beta_max' : beta_max, 'ttd_inf' : ttd_inf, 'K' : K, 'Tss' : Tss, 'frisch' : frisch, 'G' : G, 'P' : P, 'P_lag' : P, 'N_' : N, 
             'tax_N' : tax_N, 'a_lb' : a_lb, 'b' : b, 'Benefit_type' : Benefit_type, 'Pi_seed' : Pi_seed, 'Ttd' : Ttd, 'Tuni' :0, 'pi_N' : pi_N, 'Pi_N' : Pi_N,
             'Agg_C' : Agg_C, 'tax_S' : tax_S, 'destrO_L' : destrO, 'ssflag' : True}      
    
    
    if (calib == 'Full_calib') or (calib == 'Partial_calib'):           
            if calib == 'Full_calib':
                
                res1 = optimize.minimize(res_calib_2, np.array([beta_mid_guess, beta_var_guess, beta_disp_guess, vphi_guess, kappa_g]), method='Nelder-Mead',   args=args, tol = 1e-5)  
                
                beta_mid_guess, beta_var, beta_disp, vphi_guess, nonlintax_guess, kappa  = res1.x               
                beta_var_guess  = beta_var   
                beta_disp_guess = beta_disp
                kappa_g = kappa
            
            # partial calib    
            kappa = kappa_g
            beta_var  = beta_var_guess   
            beta_disp = beta_disp_guess    
            args.update({'beta_var' : beta_var, 'beta_disp' : beta_disp, 'kappa' : kappa})     
                        
                   
            print('Beta distribution:', beta_mid_guess, beta_var_guess, beta_disp_guess ) 
            print('Labor supply', vphi_guess, nonlintax_guess)
            

            res = optimize.root(res_calib_3_root, [beta_mid_guess], args=args, method='hybr')
            
            beta_mid = res.x          
            beta, pi_beta, Pi_beta = beta_dist(nBeta, beta_mid, beta_var, beta_disp, dist_type )
            Pi   =  np.kron(np.kron(Pi_beta, Pi_ern), Pi_N)
            pi_e =  np.kron(np.kron(pi_beta, pi_ern), pi_N)        
            Pi_seed = pi_e    
    elif calib == 'Solve' : 
            beta_mid  = beta_mid_guess
            beta_var  = beta_var_guess
            beta_disp = beta_disp_guess  
            vphi      = vphi_guess
            kappa = kappa_g                                
    else : 
            raise ValueError('No calibration chosen!')

    args.update({'beta' : beta, 'kappa' : kappa, 'Pi_seed' : Pi_seed, 'pi_e' : pi_e, 'Pi' : Pi, 'pi_beta' : pi_beta })   
    print(beta_mid, beta_var, beta_disp)
    ss =   EGMhousehold.ss(**args)    
    if save == True:
        np.savez('init_values', x = ss['EVa'])

    # Short run parameters not identified/needed in SS 
    phi = 1.3
    kappak = 6
    eps_p = mup / (mup-1)
    kappap =  (eps_p-1) / 0.03 

    Agg_C  = (ssAvgInc - tax_N - tax_S  + Tss + (p + B) * r) / (1+VAT) 


    sc_neg = np.nonzero(ss['a'] < 0)
    walras = 1 - ss['C']  - I - G - Vac_costs - F_cost + kappa * ss['A_DEBT']  
    G_rev = ss['TINC'] +  VAT * ss['C']   + B + T_firms 
    G_exp = G + ss['UINCAGG'] + Tss + B * (1 + r)   

    
    print('Walras 2', walras)   
    print('Asset market err', ss['A']-(B+p), 'G_budget', G_rev - G_exp)    
    
    ss.update({'goods_mkt' : walras})

    a_pop = ss['a']  
    sc = np.nonzero(ss['a'] < a_lb + 1e-7)
    print( 100 * sum(ss['D'][sc]))
    
    print( 100 * sum(ss['D'][sc_neg]))
    print(IneqStat(ss, nPoints, a_lb))
 
    ss.update({'V': V, 'vacK' : vacK, 'pMatch' : pMatch, 'q': q, 'N' : N, 'B': B, 'kappap': kappap, 'Y': Y, 'rstar': r, 'Z': Z, 'mup': mup, 'pi': pi, 'Pi' : Pi, 'eps_p' : eps_p,  'Pi_seed' : pi_e, 'MPL' : MPL, 'eps_r' : 0, 'mu' : 0, 'destr_L' : destr, 'destrO_L' : destrO,
               'K': K, 'alpha': alpha, 'delta': delta, 'I': I, 'S': S, 'G' : G,  'div' : div, 'phi' : phi, 'T_dist' : T_dist, 'Tuni' : 0, 'ttd_inf' : ttd_inf, 'L' :  N, 'U_inc' : U_inc, 'Agg_C' : Agg_C, 'p' : p, 'T_rate' : 1, 'ssN' : N, 'pshare' : p/ss['A'], 'destrO' : destrO, 'destrNO' : destrNO,
               'kappap': kappap, 'eis': eis, 'beta': beta,  'destr': destr, 'Q': 1,  'mc': mc,  'lumpsum_T' : lumpsum_T, 'Zss' : Zss, 'ra' : r, 'rk' : rk, 'r' : r, 'i' : i, 'Tightss' : Tight, 'ma' : ma, 'piw' : 0, 'a_lb' : a_lb, 'mix' : mix,'Pi_N' : Pi_N, 'pi_N' : pi_N,
               'Nss' : N, 'wss' : w,  'MF_Div' : MF_Div, 'G_rev' : G_rev, 'G_exp': G_exp, 'P' : 1, 'Tss' : lumpsum_T, 'Ttd' : Ttd, 'Z_I' : 1, 'Isip' :0, 'rss' : r, 'F_cost' : F_cost, 're' : r, 'b_ratio' : b_ratio, 'rg' : r, 'dist_type' : dist_type, 'Fvac' : Fvac,
               'VAT': VAT, 'pi_ern' : pi_ern, 'ssAvgInc' : ssAvgInc, 'b' : b,  'Tight' : Tight, 'psip' : 0, 'isip' : 0,  'K_cost' : 0, 'kappak' : kappak, 'cs_avg' : cs_avg, 'Bss' : B, 'epsI' :4, 'Benefit_type' : Benefit_type, 'div_' : div, 'UINCAGG_count' : ss['UINCAGG'], 'T_firms' : T_firms,
               'beta_mid' : beta_mid, 'beta_var' : beta_var, 'beta_disp' : beta_disp, 'uT' : 0,  'div_MF' : 0, 'nPos' : nPos, 'JV' : JV, 'JM' : JM, 'ssflag': False})    
     

    print('Average Beta' , np.vdot(beta, pi_beta))

    
    # Check bargaining set 
    upper_lvl =  (1-alpha) * mc / N
    lower_lvl = b

    assert w < upper_lvl
    assert w > lower_lvl  

    ss.update({'A_agg' : ss['A'], 'C_agg' : ss['C'], 'taxes' : ss['TINC']})
    
    # steady state values for endo. destr. rate 
    ss.update({'destrNOss' : destrNO, 'JMss' : JM, 'eps_m' : 0.5})
    ss.update({'destrOss' : destrO, 'JVss' : JV, 'eps_V' : 0.5, 'muV' : 0 })

    # Check that income is strictly positive 
    assert min(ss['Inc'].flatten()) > 0

    return ss 
Exemplo n.º 6
0
    def create_grids(self):
        """ create grids and other preperations for solving the model"""

        par = self.par

        # a. perfect foresight or buffer-stock model
        if par.sigma_xi == 0 and par.sigma_psi == 0 and par.low_p == 0:  # no risk
            self.model = 'pf'  # perfect foresight
        else:
            self.model = 'bs'  # buffer-stock

        # b. shocks

        # i. basic GuassHermite
        psi, psi_w = normal_gauss_hermite(sigma=par.sigma_psi, n=par.Npsi)
        xi, xi_w = normal_gauss_hermite(sigma=par.sigma_xi, n=par.Nxi)

        # ii. add low income shock to xi
        if par.low_p > 0:

            # a. weights
            xi_w *= (1.0 - par.low_p)
            xi_w = np.insert(xi_w, 0, par.low_p)

            # b. values
            xi = (xi - par.low_val * par.low_p) / (1.0 - par.low_p)
            xi = np.insert(xi, 0, par.low_val)

        # iii. vectorize tensor product of shocks and total weight
        psi_vec, xi_vec = np.meshgrid(psi, xi, indexing='ij')
        psi_w_vec, xi_w_vec = np.meshgrid(psi_w, xi_w, indexing='ij')

        par.psi_vec = psi_vec.ravel()
        par.xi_vec = xi_vec.ravel()
        par.w = xi_w_vec.ravel() * psi_w_vec.ravel()

        assert 1 - np.sum(par.w) < 1e-8  # == summing to 1

        # iv. count number of shock nodes
        par.Nshocks = par.w.size

        # c. minimum a
        if par.borrowingfac == 0:

            par.a_min = np.zeros(par.T)  # never any borriwng

        else:

            # using formula from slides
            psi_min = np.min(par.psi_vec)
            xi_min = np.min(par.xi_vec)

            par.a_min = np.nan * np.ones(par.T)
            for t in reversed(range(par.T - 1)):

                if t >= par.TR - 1:  # in retirement
                    Omega = 0
                elif t == par.TR - 2:  # next period is retirement
                    Omega = par.R**(-1) * par.G * par.L[t +
                                                        1] * psi_min * xi_min
                else:  # before retirement
                    Omega = par.R**(-1) * (np.fmin(Omega, par.borrowingfac) +
                                           xi_min) * par.G * par.L[t +
                                                                   1] * psi_min

                par.a_min[t] = -np.fmin(
                    Omega, par.borrowingfac) * par.G * par.L[t + 1] * psi_min

        # d. end-of-period assets and cash-on-hand
        par.grid_a = np.nan * np.ones((par.T, par.Na))
        par.grid_m = np.nan * np.ones((par.T, par.Nm))
        for t in range(par.T):
            par.grid_a[t, :] = nonlinspace(par.a_min[t] + 1e-6, par.a_max,
                                           par.Na, par.a_phi)
            par.grid_m[t, :] = nonlinspace(par.a_min[t] + 1e-6, par.m_max,
                                           par.Nm, par.m_phi)

        # e. conditions
        par.FHW = par.G / par.R
        par.AI = (par.R * par.beta)**(1 / par.rho)
        par.GI = par.AI * np.sum(par.w * par.psi_vec**(-1)) / par.G
        par.RI = par.AI / par.R
        par.WRI = par.low_p**(1 / par.rho) * par.AI / par.R
        par.FVA = par.beta * np.sum(par.w *
                                    (par.G * par.psi_vec)**(1 - par.rho))

        # f. fast solution with EGM

        # grid_a tiled with the number of shocks
        par.grid_a_tile = np.ones((par.TR, par.Na * par.Nshocks))
        for t in range(par.TR):
            par.grid_a_tile[t, :] = np.tile(par.grid_a[t, :], par.Nshocks)

        # xi, psi and w repeated with the number of grid points for a
        par.xi_vec_rep = np.repeat(par.xi_vec, par.Na)
        par.psi_vec_rep = np.repeat(par.psi_vec, par.Na)
        par.w_rep = np.repeat(par.w, par.Na)

        # g. check for existance of solution
        self.print_and_check_parameters(do_print=False)
    def create_grids(self):
        """ construct grids for states and shocks """

        par = self.par

        # b. shocks

        # i. basic GuassHermite
        psi, psi_w = normal_gauss_hermite(sigma=par.sigma_psi, n=par.Npsi)
        xi, xi_w = normal_gauss_hermite(sigma=par.sigma_xi, n=par.Nxi)

        # ii. add low income shock to xi
        if par.pi > 0:

            # a. weights
            xi_w *= (1.0 - par.pi)
            xi_w = np.insert(xi_w, 0, par.pi)

            # b. values
            xi = (xi - par.mu * par.pi) / (1.0 - par.pi)
            xi = np.insert(xi, 0, par.mu)

        # iii. vectorize tensor product of shocks and total weight
        psi_vec, xi_vec = np.meshgrid(psi, xi, indexing='ij')
        psi_w_vec, xi_w_vec = np.meshgrid(psi_w, xi_w, indexing='ij')

        par.psi_vec = psi_vec.ravel()
        par.xi_vec = xi_vec.ravel()
        par.w = xi_w_vec.ravel() * psi_w_vec.ravel()

        assert 1 - np.sum(par.w) < 1e-8  # == summing to 1

        # iv. count number of shock nodes
        par.Nshocks = par.w.size

        # c. minimum a
        if par.borrowingfac == 0:

            par.a_min = np.zeros(par.T)  # never any borriwng

        else:

            # using formula from slides
            psi_min = np.min(par.psi_vec)
            xi_min = np.min(par.xi_vec)

            par.a_min = np.ones(par.T)
            for t in reversed(range(par.T - 1)):

                if t >= par.TR - 1:  # in retirement
                    Omega = 0
                elif t == par.TR - 2:  # next period is retirement
                    Omega = par.R**(-1) * par.G * par.L[t +
                                                        1] * psi_min * xi_min
                else:  # before retirement
                    Omega = par.R**(-1) * (np.fmin(Omega, par.borrowingfac) +
                                           xi_min) * par.G * par.L[t +
                                                                   1] * psi_min

                par.a_min[t] = -np.fmin(
                    Omega, par.borrowingfac) * par.G * par.L[t + 1] * psi_min

        # d. end-of-period assets and cash-on-hand
        par.grid_a = np.ones((par.T, par.Na))
        par.grid_m = np.ones((par.T, par.Nm))
        for t in range(par.T):
            par.grid_a[t, :] = nonlinspace(par.a_min[t] + 1e-6, par.a_max,
                                           par.Na, par.a_phi)
            par.grid_m[t, :] = nonlinspace(par.a_min[t] + 1e-6, par.m_max,
                                           par.Nm, par.m_phi)

        # e. conditions
        par.FHW = np.float(par.G / par.R)
        par.AI = np.float((par.R * par.beta)**(1 / par.rho))
        par.GI = np.float(par.AI * np.sum(par.w * par.psi_vec**(-1)) / par.G)
        par.RI = np.float(par.AI / par.R)
        par.WRI = np.float(par.pi**(1 / par.rho) * par.AI / par.R)
        par.FVA = np.float(
            par.beta * np.sum(par.w * (par.G * par.psi_vec)**(1 - par.rho)))

        # g. check for existance of solution
        self.check(do_print=False)