def solve_bellman(t, sol, par): """solve bellman equation using vfi""" # unpack (helps numba optimize) c = sol.c[t] v = sol.v[t] # loop over outer states for ip in prange(par.Np): # in parallel # a. permanent income p = par.grid_p[ip] # d. loop over cash-on-hand for im in range(par.Nm): # a. cash-on-hand m = par.grid_m[im] # b. optimal choice c_low = np.fmin(m / 2, 1e-8) c_high = m c[ip, im] = golden_section_search.optimizer(obj_bellman, c_low, c_high, args=(p, m, sol.v[t + 1], par), tol=par.tol) # note: the above finds the minimum of obj_bellman in range [c_low,c_high] with a tolerance of par.tol # and arguments (except for c) as specified # c. optimal value v[ip, im] = -obj_bellman(c[ip, im], p, m, sol.v[t + 1], par)
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 solve_keep(inv_w,grid_b,grid_m,grid_n,d_ubar,sigma,Np,Nn,Nm,P_n_p): # P_n_p """solve bellman equation for keepers using nvfi""" # unpack output keep_shape = (Np,Nn,Nm) inv_v_keep = np.zeros(keep_shape) c_keep = np.zeros(keep_shape) # loop over outer states for i_p in prange(Np): for i_n in range(Nn): # outer states n = grid_n[i_n] # loop over m state for i_m in range(Nm): # a. cash-on-hand m = grid_m[i_m] if i_m == 0: c_keep[i_p,i_n,i_m] = 0 inv_v_keep[i_p,i_n,i_m] = 0 # b. optimal choice b = m - c, b <=-0.5.m min c_low = np.fmin(m/2,1e-8) c_high = m/P_n_p # m = P_n_p*c (if using everything) c_keep[i_p,i_n,i_m] = golden_section_search.optimizer(obj_keep,c_low,c_high,args=(n,m,inv_w[i_p,i_n],grid_b,d_ubar,sigma,P_n_p),tol=1e-8) # c. optimal value v = -obj_keep(c_keep[i_p,i_n,i_m],n,m,inv_w[i_p,i_n],grid_b,d_ubar,sigma,P_n_p) inv_v_keep[i_p,i_n,i_m] = -1.0/v return inv_v_keep,c_keep
def last_period(sigma,d_ubar,Np,Nn,Nm,Nx,grid_n,grid_m,grid_x,n_max,P_n_p,P_d_p): # P_n_p, P_d_p """ solve the problem in the last period """ # unpack keep_shape = (Np,Nn,Nm) c_keep = np.zeros(keep_shape) inv_v_keep = np.zeros(keep_shape) adj_shape = (Np,Nx) d_adj = np.zeros(adj_shape) c_adj = np.zeros(adj_shape) inv_v_adj = np.zeros(adj_shape) # a. keep for i_p in prange(Np): for i_n in range(Nn): for i_m in range(Nm): # i. states n = grid_n[i_n] m = grid_m[i_m] if i_m == 0: # forced c = 0 c_keep[i_p,i_n,i_m] = 0 inv_v_keep[i_p,i_n,i_m] = 0 continue # ii. optimal choice c_keep[i_p,i_n,i_m] = m/P_n_p # iii. optimal value v_keep = utility(c_keep[i_p,i_n,i_m],n,d_ubar,sigma) inv_v_keep[i_p,i_n,i_m] = -1.0/v_keep # b. adj for i_p in prange(Np): for i_x in range(Nx): # i. states x = grid_x[i_x] if i_x == 0: # forced c = d = 0 d_adj[i_p,i_x] = 0 c_adj[i_p,i_x] = 0 inv_v_adj[i_p,i_x] = 0 continue # ii. optimal choices d_low = np.fmin(x/2,1e-8) d_high = np.fmin(x/P_d_p,n_max) d_adj[i_p,i_x] = golden_section_search.optimizer(obj_last_period,d_low,d_high,args=(x,sigma,d_ubar,P_n_p,P_d_p),tol=1e-8) c_adj[i_p,i_x] = (x-P_d_p*d_adj[i_p,i_x])/P_n_p # x - P_n_p*c - P_n_d*d = 0 => c=(x- P_n_d*d)/P_n_p # iii. optimal value v_adj = -obj_last_period(d_adj[i_p,i_x],x,sigma,d_ubar,P_n_p,P_d_p) inv_v_adj[i_p,i_x] = -1.0/v_adj return c_keep, c_adj, d_adj, inv_v_keep, inv_v_adj
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 solve_keep(t, sol, par): """solve bellman equation for keepers using nvfi""" # unpack output inv_v = sol.inv_v_keep[t] inv_marg_u = sol.inv_marg_u_keep[t] c = sol.c_keep[t] # unpack input inv_w = sol.inv_w[t] grid_a = par.grid_a d_ubar = par.d_ubar alpha = par.alpha rho = par.rho # loop over outer states for i_p in prange(par.Np): for i_n in range(par.Nn): # outer states n = par.grid_n[i_n] # loop over m state for i_m in range(par.Nm): # a. cash-on-hand m = par.grid_m[i_m] if i_m == 0: c[i_p, i_n, i_m] = 0 inv_v[i_p, i_n, i_m] = 0 if par.do_marg_u: inv_marg_u[i_p, i_n, i_m] = 0 continue # b. optimal choice c_low = np.fmin(m / 2, 1e-8) c_high = m c[i_p, i_n, i_m] = golden_section_search.optimizer( obj_keep, c_low, c_high, args=(n, m, inv_w[i_p, i_n], grid_a, d_ubar, alpha, rho), tol=par.tol) # c. optimal value v = -obj_keep(c[i_p, i_n, i_m], n, m, inv_w[i_p, i_n], grid_a, d_ubar, alpha, rho) inv_v[i_p, i_n, i_m] = -1 / v if par.do_marg_u: inv_marg_u[i_p, i_n, i_m] = 1 / utility.marg_func_nopar( c[i_p, i_n, i_m], n, d_ubar, alpha, rho)
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 solve_keep(t, sol, par): """solve bellman equation for keepers using vfi""" # unpack (helps numba optimize) inv_v = sol.inv_v_keep[t] c = sol.c_keep[t] # keep: loop over outer states for i_p in prange(par.Np): # loop in parallel for i_n in range(par.Nn): p = par.grid_p[i_p] n = par.grid_n[i_n] # loop over cash-on-hand for i_m in range(par.Nm): # a. cash-on-hand m = par.grid_m[i_m] if i_m == 0: c[i_p, i_n, i_m] = 0 inv_v[i_p, i_n, i_m] = 0 continue # b. optimal choice c_low = np.fmin(m / 2, 1e-8) c_high = m c_opt = golden_section_search.optimizer( obj_keep, c_low, c_high, args=(t, n, p, m, sol.inv_v_keep, sol.inv_v_adj, par), tol=par.tol) c[i_p, i_n, i_m] = c_opt # c. optimal value v = -obj_keep(c[i_p, i_n, i_m], t, n, p, m, sol.inv_v_keep, sol.inv_v_adj, par) inv_v[i_p, i_n, i_m] = -1 / v
def solve(t, sol, par): """ solve the problem in the last period """ # unpack inv_v_keep = sol.inv_v_keep[t] inv_marg_u_keep = sol.inv_marg_u_keep[t] c_keep = sol.c_keep[t] inv_v_adj = sol.inv_v_adj[t] inv_marg_u_adj = sol.inv_marg_u_adj[t] d_adj = sol.d_adj[t] c_adj = sol.c_adj[t] # a. keep for i_p in prange(par.Np): for i_n in range(par.Nn): for i_m in range(par.Nm): # i. states n = par.grid_n[i_n] m = par.grid_m[i_m] if m == 0: # forced c = 0 c_keep[i_p, i_n, i_m] = 0 inv_v_keep[i_p, i_n, i_m] = 0 inv_marg_u_keep[i_p, i_n, i_m] = 0 continue # ii. optimal choice c_keep[i_p, i_n, i_m] = m # iii. optimal value v_keep = utility.func(c_keep[i_p, i_n, i_m], n, par) inv_v_keep[i_p, i_n, i_m] = -1.0 / v_keep inv_marg_u_keep[i_p, i_n, i_m] = 1.0 / utility.marg_func( c_keep[i_p, i_n, i_m], n, par) # b. adj for i_p in prange(par.Np): for i_x in range(par.Nx): # i. states x = par.grid_x[i_x] if x == 0: # forced c = d = 0 d_adj[i_p, i_x] = 0 c_adj[i_p, i_x] = 0 inv_v_adj[i_p, i_x] = 0 inv_marg_u_adj[i_p, i_x] = 0 continue # ii. optimal choices d_low = np.fmin(x / 2, 1e-8) d_high = np.fmin(x, par.n_max) d_adj[i_p, i_x] = golden_section_search.optimizer( d_low, d_high, par.tol, obj_last_period, x, par) c_adj[i_p, i_x] = x - d_adj[i_p, i_x] # iii. optimal value v_adj = -obj_last_period(d_adj[i_p, i_x], x, par) inv_v_adj[i_p, i_x] = -1.0 / v_adj inv_marg_u_adj[i_p, i_x] = 1.0 / utility.marg_func( c_adj[i_p, i_x], d_adj[i_p, i_x], par)
def solve_2d(t, sol, par): """ solve the problem in the last period """ # unpack inv_v_keep = sol.inv_v_keep_2d[t] inv_marg_u_keep = sol.inv_marg_u_keep_2d[t] c_keep = sol.c_keep_2d[t] inv_v_adj_full = sol.inv_v_adj_full_2d[t] inv_marg_u_adj_full = sol.inv_marg_u_adj_full_2d[t] d1_adj_full = sol.d1_adj_full_2d[t] d2_adj_full = sol.d2_adj_full_2d[t] c_adj_full = sol.c_adj_full_2d[t] inv_v_adj_d1 = sol.inv_v_adj_d1_2d[t] inv_marg_u_adj_d1 = sol.inv_marg_u_adj_d1_2d[t] d1_adj_d1 = sol.d1_adj_d1_2d[t] c_adj_d1 = sol.c_adj_d1_2d[t] inv_v_adj_d2 = sol.inv_v_adj_d2_2d[t] inv_marg_u_adj_d2 = sol.inv_marg_u_adj_d2_2d[t] d2_adj_d2 = sol.d2_adj_d2_2d[t] c_adj_d2 = sol.c_adj_d2_2d[t] # a. keep for i_p in prange(par.Np): for i_n1 in range(par.Nn): for i_n2 in range(par.Nn): for i_m in range(par.Nm): # i. states n1 = par.grid_n[i_n1] n2 = par.grid_n[i_n2] m = par.grid_m[i_m] if m == 0: # forced c = 0 c_keep[i_p, i_n1, i_n2, i_m] = 0 inv_v_keep[i_p, i_n1, i_n2, i_m] = 0 inv_marg_u_keep[i_p, i_n1, i_n2, i_m] = 0 continue # ii. optimal choice c_keep[i_p, i_n1, i_n2, i_m] = m # iii. optimal value v_keep = utility.func_2d(c_keep[i_p, i_n1, i_n2, i_m], n1, n2, par) inv_v_keep[i_p, i_n1, i_n2, i_m] = -1.0 / v_keep inv_marg_u_keep[i_p, i_n1, i_n2, i_m] = 1.0 / utility.marg_func_2d( c_keep[i_p, i_n1, i_n2, i_m], n1, n2, par) # b. adj full (use gamma = 0.5) for i_p in prange(par.Np): for i_x in range(par.Nx): # i. states x = par.grid_x[i_x] if x == 0: # forced c = d1 = d2 = 0 d1_adj_full[i_p, i_x] = 0 d2_adj_full[i_p, i_x] = 0 c_adj_full[i_p, i_x] = 0 inv_v_adj_full[i_p, i_x] = 0 inv_marg_u_adj_full[i_p, i_x] = 0 continue # ii. optimal choices d_low = np.fmin(x / 2, 1e-8) d_high = np.fmin(x / 2, par.n_max) d1_adj_full[i_p, i_x] = golden_section_search.optimizer( obj_last_period_full_2d, d_low, d_high, args=(x, par), tol=par.tol) d2_adj_full[i_p, i_x] = d1_adj_full[i_p, i_x] c_adj_full[i_p, i_x] = x - 2 * d1_adj_full[i_p, i_x] # iii. optimal value v_adj = -obj_last_period_full_2d(d1_adj_full[i_p, i_x], x, par) inv_v_adj_full[i_p, i_x] = -1.0 / v_adj inv_marg_u_adj_full[i_p, i_x] = 1.0 / utility.marg_func_2d( c_adj_full[i_p, i_x], d1_adj_full[i_p, i_x], d2_adj_full[i_p, i_x], par) # c. adj d1 for i_p in prange(par.Np): for i_n2 in range(par.Nn): for i_x in range(par.Nx): # i. states n2 = par.grid_n[i_n2] x = par.grid_x[i_x] if x == 0: # forced c = d1 = 0 d1_adj_d1[i_p, i_n2, i_x] = 0 c_adj_d1[i_p, i_n2, i_x] = 0 inv_v_adj_d1[i_p, i_n2, i_x] = 0 inv_marg_u_adj_d1[i_p, i_n2, i_x] = 0 continue # ii. optimal choices d_low = np.fmin(x / 2, 1e-8) d_high = np.fmin(x, par.n_max) d1_adj_d1[i_p, i_n2, i_x] = golden_section_search.optimizer( obj_last_period_d1_2d, d_low, d_high, args=(n2, x, par), tol=par.tol) c_adj_d1[i_p, i_n2, i_x] = x - d1_adj_d1[i_p, i_n2, i_x] # iii. optimal value v_adj = -obj_last_period_d1_2d(d1_adj_d1[i_p, i_n2, i_x], n2, x, par) inv_v_adj_d1[i_p, i_n2, i_x] = -1.0 / v_adj inv_marg_u_adj_d1[i_p, i_n2, i_x] = 1.0 / utility.marg_func_2d( c_adj_d1[i_p, i_n2, i_x], d1_adj_d1[i_p, i_n2, i_x], n2, par) # d. adj d2 for i_p in prange(par.Np): for i_n1 in range(par.Nn): for i_x in range(par.Nx): # i. states n1 = par.grid_n[i_n1] x = par.grid_x[i_x] if x == 0: # forced c = d2 = 0 d2_adj_d2[i_p, i_n1, i_x] = 0 c_adj_d2[i_p, i_n1, i_x] = 0 inv_v_adj_d2[i_p, i_n1, i_x] = 0 inv_marg_u_adj_d2[i_p, i_n1, i_x] = 0 continue # ii. optimal choices d_low = np.fmin(x / 2, 1e-8) d_high = np.fmin(x, par.n_max) d2_adj_d2[i_p, i_n1, i_x] = golden_section_search.optimizer( obj_last_period_d2_2d, d_low, d_high, args=(n1, x, par), tol=par.tol) c_adj_d2[i_p, i_n1, i_x] = x - d2_adj_d2[i_p, i_n1, i_x] # iii. optimal value v_adj = -obj_last_period_d2_2d(d2_adj_d2[i_p, i_n1, i_x], n1, x, par) inv_v_adj_d2[i_p, i_n1, i_x] = -1.0 / v_adj inv_marg_u_adj_d2[i_p, i_n1, i_x] = 1.0 / utility.marg_func_2d( c_adj_d2[i_p, i_n1, i_x], n1, d2_adj_d2[i_p, i_n1, i_x], par)