def iter_over_output(self, tol=.05): e = 1 out_prior = ss_output_flexible(self.params) while e > tol: res_dict = self() self.update(res_dict) out = res_dict['rigid_out'] e = np.abs(out_prior - out) print('The new error is {}'.format(e)) out_prior = out else: self.terminating_e = e
def run_one(params, res_dict=None): """ Once you have the parameters, this function completes one loop to get a dictionary of results. For the first loop leave res_dict as None. """ pi = params['pi'][0] # lambda_ = params['lambda_'][0] np.random.seed(42) w_grid = params['w_grid'][0] z_grid = params['z_grid'][0] if res_dict: print("Reusing res_dict.") v = res_dict['Tv'] out = res_dict['rigid_out'] else: v = Interp(w_grid, -w_grid + 27.3, kind='linear') out = ss_output_flexible(params) # ss output w/ flexible wages # Get close with linear first. Then do a few cubic to finish up Tv, ws, rest = iter_bellman(v, tol=0.005, strict=False, log=False, params=params, pi=pi, aggL=out, kind='linear') Tvc = Interp(Tv.X, Tv.Y, kind='cubic') Tv, ws, rest = iter_bellman(Tvc, tol=0.005, strict=False, log=False, params=params, pi=pi, aggL=out) res_dict = {'Tv': Tv, 'ws': ws, 'rest': rest} flex_ws = Interp(z_grid, ss_wage_flexible(params, shock=z_grid)) #------------------------------------------------------------------------- pths, shks = sample_path(ws, params, nseries=1000, nperiods=30) pth, shocks = pths[28], shks[28] # a period in steady state g = ecdf(np.sort(pth)) shocks = np.sort(shocks) #------------------------------------------------------------------------- rigid_out = get_rigid_output(ws, params, flex_ws, g) res_dict['gp'] = g res_dict['rigid_out'] = rigid_out return res_dict
def bellman(w, params, u_fn=u_, lambda_=None, z_grid=None, pi=None, kind=None, w_grid=None, aggL=None): """ Differs from bellman by optimizing for *each* shock, rather than for the mean. I think this is right since the agent observes Z_{it} *before* choosing w_{it}. Operate on the bellman equation. Returns the value function (interpolated linearly) at each point in grid. Parameters ---------- w : callable value function (probably instance of LinInterp from last iter) u_fn : The period utility function to be maximized. Omega in DH`2013 grid : Domain of w. This is the real wage today at start of today. lambda : float. Degree of wage rigidity. 0 = flexible, 1 = fully rigid shock : array. Draws from a lognormal distribution. pi : steady-state (for now) inflation level. Will be changed. kind : type of interpolation. Defualt taken from w. Overridden if not None. str or int. See scipy.interpolate.interp1d Returns ------- Tv : The next iteration of the value function v. Instance of LinInterp. wage_schedule : LinInterp. Wage as function of shock. vals : everything else. temporary. [(wage, shock, free_w*, res_w*)] This will be grid X shocks X 5 #------------------------------------------------------------------------- A note on `shock`: Why am I taking draws from a distribution? I optimize at each draw, and then take the mean over those. But wouldn't it be better to take a uniform sample over the *support* of the distribution, and then weight the resulting utilities by the *pdf at that point*? This branch (`rethink_distribution`) attempts to implement this alternative strategy. """ if lambda_ is None: lambda_ = params['lambda_'][0] if pi is None: pi = params['pi'][0] ln_dist = params['full_ln_dist'][0] if aggL is None: aggL = ss_output_flexible(params) # Need if since it's checking using or checks truth of array so any/all if w_grid is None: w_grid = params['w_grid'][0] if z_grid is None: z_grid = params['z_grid'][0] kind = kind or w.kind #-------------------------------------------------------------------------- vals = np.zeros((len(w_grid), len(z_grid), 5)) vals = opt_loop(vals, w_grid, z_grid, w, pi, lambda_, aggL) vals = pd.Panel(vals, items=w_grid, major_axis=z_grid, minor_axis=['wage', 'z_grid', 'value', 'm1', 'm2']) vals.items.name = 'w_grid' vals.major_axis.name = 'z_grid' weights = pd.Series(ln_dist.pdf(vals.major_axis.values.astype('float64')), index=vals.major_axis) weights /= weights.sum() weighted_values = vals.apply(lambda x: x * weights).sum(axis='major').ix['value'] Tv = Interp(w_grid, weighted_values.values, kind=kind) # Wage(z_grid). Doesn't matter which row for free case. wage_schedule = Interp(z_grid, vals.iloc[0]['m1'].values, kind=kind) return Tv, wage_schedule, vals