def discretize_gdp(self, N=3): Σ = self.Σ ρ = self.ρ n_nodes = N n_std = 2.5 n_integration_nodes = 5 try: assert Σ.shape[0] == 1 except: raise Exception("Not implemented.") try: assert ρ.shape[0] == ρ.shape[1] == 1 except: raise Exception("Not implemented.") ρ = ρ[0, 0] σ = np.sqrt(Σ[0, 0]) from dolo.numeric.discretization import gauss_hermite_nodes epsilons, weights = gauss_hermite_nodes([n_integration_nodes], Σ) min = -n_std * (σ / (np.sqrt(1 - ρ**2))) max = n_std * (σ / (np.sqrt(1 - ρ**2))) from .grids import CartesianGrid grid = CartesianGrid([min], [max], [n_nodes]) nodes = np.linspace(min, max, n_nodes)[:, None] iweights = weights[None, :].repeat(n_nodes, axis=0) integration_nodes = np.zeros((n_nodes, n_integration_nodes))[:, :, None] for i in range(n_nodes): for j in range(n_integration_nodes): integration_nodes[i, j, :] = ρ * nodes[i, :] + epsilons[j] return GDP(nodes, integration_nodes, iweights, grid=grid)
def evaluate_policy(model, dr, tol=1e-8, grid={}, distribution={}, maxit=2000, verbose=False, hook=None, integration_orders=None): ''' Compute value function corresponding to policy ``dr`` Parameters: ----------- model: "dtcscc" model. Must contain a 'value' function. dr: decision rule to evaluate Returns: -------- decision rule: value function (a function of the space similar to a decision rule object) ''' assert (model.model_type == 'dtcscc') vfun = model.functions["value"] gfun = model.functions['transition'] parms = model.calibration['parameters'] n_vals = len(model.symbols['values']) t1 = time.time() err = 1.0 it = 0 approx = model.get_grid(**grid) interp_type = approx.interpolation distrib = model.get_distribution(**distribution) sigma = distrib.sigma drv = create_interpolator(approx, approx.interpolation) grid = drv.grid N = drv.grid.shape[0] controls = dr(grid) guess_0 = model.calibration['values'] guess_0 = guess_0[None, :].repeat(N, axis=0) if not integration_orders: integration_orders = [3] * sigma.shape[0] [nodes, weights] = gauss_hermite_nodes(integration_orders, sigma) if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |'.format('N', ' Error', 'Gain', 'Time') stars = '-' * len(headline) print(stars) print(headline) print(stars) err_0 = 1.0 while err > tol and it < maxit: if hook: hook() t_start = time.time() it += 1 # update spline coefficients with current values drv.set_values(guess_0) # update the geuss of value functions guess = update_value(gfun, vfun, grid, controls, dr, drv, nodes, weights, parms, n_vals) # compute error err = abs(guess - guess_0).max() err_SA = err / err_0 err_0 = err # update guess guess_0[:] = guess.copy() # print update to user, if verbose t_end = time.time() elapsed = t_end - t_start if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err, err_SA, elapsed)) if it == maxit: warnings.warn(UserWarning("Maximum number of iterations reached")) t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return drv
def solve_policy(model, tol=1e-6, grid={}, distribution={}, integration_orders=None, maxit=500, maxit_howard=500, verbose=False, hook=None, initial_dr=None, pert_order=1): ''' Solve for the value function and associated decision rule by iterating over the value function. Parameters ----------- model : ``dtcscc`` model. Must contain a ``felicity`` function. Returns -------- dr : Markov decision rule The solved decision rule/policy function drv : decision rule The solved value function ''' assert (model.model_type == 'dtcscc') def vprint(t): if verbose: print(t) # transition(s, x, e, p, out), felicity(s, x, p, out) transition = model.functions['transition'] felicity = model.functions['felicity'] controls_lb = model.functions['controls_lb'] controls_ub = model.functions['controls_ub'] parms = model.calibration['parameters'] discount = model.calibration['beta'] x0 = model.calibration['controls'] s0 = model.calibration['states'] r0 = felicity(s0, x0, parms) approx = model.get_grid(**grid) # a = approx.a # b = approx.b # orders = approx.orders distrib = model.get_distribution(**distribution) sigma = distrib.sigma # Possibly use the approximation orders? if integration_orders is None: integration_orders = [3] * sigma.shape[0] [nodes, weights] = gauss_hermite_nodes(integration_orders, sigma) interp_type = approx.interpolation drv = create_interpolator(approx, interp_type) if initial_dr is None: if pert_order == 1: dr = approximate_controls(model) if pert_order > 1: raise Exception("Perturbation order > 1 not supported (yet).") else: dr = initial_dr grid = drv.grid N = grid.shape[0] # Number of states n_x = grid.shape[1] # Number of controls controls = dr(grid) controls_0 = np.zeros((N, n_x)) controls_0[:, :] = model.calibration['controls'][None, :] values_0 = np.zeros((N, 1)) values_0[:, :] = r0/(1-discount) if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |'.format('N', ' Error','Gain', 'Time') stars = '-' * len(headline) print(stars) print(headline) print(stars) t1 = time.time() # FIRST: value function iterations, 10 iterations to start it = 0 err_v = 100 err_v_0 = 0.0 gain_v = 0.0 err_x = 100 err_x_0 = 100 if verbose: print(stars) print('Starting value function iteration') print(stars) while err_v > tol and it < 10: t_start = time.time() it += 1 # update interpolation object with current values drv.set_values(values_0) values = values_0.copy() controls = controls_0.copy() for n in range(N): s = grid[n, :] x = controls[n, :] lb = controls_lb(s, parms) ub = controls_ub(s, parms) bnds = [e for e in zip(lb, ub)] def valfun(xx): return -choice_value(transition, felicity, s, xx, drv, nodes, weights, parms, discount)[0] res = minimize(valfun, x, bounds=bnds, tol=1e-4) controls[n, :] = res.x values[n, 0] = -valfun(res.x) # compute error, update value and dr err_x = abs(controls - controls_0).max() err_v = abs(values - values_0).max() t_end = time.time() elapsed = t_end - t_start values_0 = values controls_0 = controls gain_x = err_x / err_x_0 gain_v = err_v / err_v_0 err_x_0 = err_x err_v_0 = err_v # print update to user, if verbose if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err_v, gain_v, elapsed)) # SECOND: Howard improvement step, 10-20 iterations it = 0 err_v = 100 err_v_0 = 0.0 gain_v = 0.0 if verbose: print(stars) print('Starting Howard improvement step') print(stars) while err_v > tol and it < maxit_howard: t_start = time.time() it += 1 # update interpolation object with current values drv.set_values(values_0) values = values_0.copy() controls = controls_0.copy() # controls = controls_0.copy() # No need to keep updating for n in range(N): s = grid[n, :] x = controls[n, :] values[n, 0] = choice_value(transition, felicity, s, x, drv, nodes, weights, parms, discount)[0] # compute error, update value function err_v = abs(values - values_0).max() values_0 = values t_end = time.time() elapsed = t_end - t_start gain_v = err_v / err_v_0 err_v_0 = err_v # print update to user, if verbose if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err_v, gain_v, elapsed)) # THIRD: Back to value function iteration until convergence. it = 0 err_v = 100 err_v_0 = 0.0 gain_v = 0.0 err_x = 100 err_x_0 = 100 if verbose: print(stars) print('Starting value function iteration') print(stars) while err_v > tol and it < maxit: t_start = time.time() it += 1 # update interpolation object with current values drv.set_values(values_0) values = values_0.copy() controls = controls_0.copy() for n in range(N): s = grid[n, :] x = controls[n, :] lb = controls_lb(s, parms) ub = controls_ub(s, parms) bnds = [e for e in zip(lb, ub)] def valfun(xx): return -choice_value(transition, felicity, s, xx, drv, nodes, weights, parms, discount)[0] res = minimize(valfun, x, bounds=bnds, tol=1e-4) controls[n, :] = res.x values[n, 0] = -valfun(res.x) # compute error, update value and dr err_x = abs(controls - controls_0).max() err_v = abs(values - values_0).max() t_end = time.time() elapsed = t_end - t_start values_0 = values controls_0 = controls gain_x = err_x / err_x_0 gain_v = err_v / err_v_0 err_x_0 = err_x err_v_0 = err_v # print update to user, if verbose if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err_v, gain_v, elapsed)) if it == maxit: warnings.warn(UserWarning("Maximum number of iterations reached")) t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) # final value function and decision rule drv.set_values(values_0) dr = create_interpolator(approx, interp_type) dr.set_values(controls_0) return dr, drv
def pea(model, maxit=100, tol=1e-8, initial_dr=None, verbose=False): t1 = time.time() g = model.functions['transition'] d = model.functions['direct_response'] h = model.functions['expectation'] p = model.calibration['parameters'] if initial_dr is None: drp = approximate_controls(model) else: drp = approximate_controls(model) nodes, weights = gauss_hermite_nodes([5], model.covariances) ap = model.options['approximation_space'] a = ap['a'] b = ap['b'] orders = ap['orders'] grid = mlinspace(a,b,orders) dr = MultivariateCubicSplines(a,b,orders) N = grid.shape[0] z = np.zeros((N,len(model.symbols['expectations']))) x_0 = drp(grid) it = 0 err = 10 err_0 = 10 if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |' headline = headline.format('N', ' Error', 'Gain', 'Time') stars = '-'*len(headline) print(stars) print(headline) print(stars) # format string for within loop fmt_str = '|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |' while err>tol and it<=maxit: t_start = time.time() dr.set_values(x_0) z[...] = 0 for i in range(weights.shape[0]): e = nodes[i,:] S = g(grid, x_0, e, p) # evaluate future controls X = dr(S) z += weights[i]*h(S,X,p) # TODO: check that control is admissible new_x = d(grid, z, p) # check whether they differ from the preceding guess err = (abs(new_x - x_0).max()) x_0 = new_x if verbose: # update error and print if `verbose` err_SA = err/err_0 err_0 = err t_finish = time.time() elapsed = t_finish - t_start if verbose: print(fmt_str.format(it, err, err_SA, elapsed)) if it == maxit: import warnings warnings.warn(UserWarning("Maximum number of iterations reached")) # compute final fime and do final printout if `verbose` t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return dr
def test_simulations(): from dolo import yaml_import, approximate_controls model = yaml_import('../../examples/models/rbc.yaml') dr = approximate_controls(model) parms = model.calibration['parameters'] sigma = model.covariances import numpy s0 = dr.S_bar horizon = 50 import time t1 = time.time() simul = simulate(model, dr, s0, sigma, n_exp=1000, parms=parms, seed=1, horizon=horizon) t2 = time.time() print("Took: {}".format(t2-t1)) from dolo.numeric.discretization import gauss_hermite_nodes N = 80 [x,w] = gauss_hermite_nodes(N, sigma) t3 = time.time() simul_2 = simulate(model, dr, s0, sigma, n_exp=1000, parms=parms, horizon=horizon, seed=1, solve_expectations=True, nodes=x, weights=w) t4 = time.time() print("Took: {}".format(t4-t3)) from matplotlib.pyplot import hist, show, figure, plot, title timevec = numpy.array(range(simul.shape[2])) figure() for k in range(10): plot(simul[:,k,0] - simul_2[:,k,0]) title("Productivity") show() figure() for k in range(10): plot(simul[:,k,1] - simul_2[:,k,1]) title("Investment") show() # # figure() # plot(simul[0,0,:]) # plot(simul_2[0,0,:]) # show() figure() for i in range( horizon ): hist( simul[i,:,0], bins=50 ) show()
def time_iteration(model, bounds=None, verbose=False, initial_dr=None, pert_order=1, with_complementarities=True, interp_type='smolyak', smolyak_order=3, interp_orders=None, maxit=500, tol=1e-8, inner_maxit=10, integration='gauss-hermite', integration_orders=None, T=200, n_s=3, hook=None): ''' Finds a global solution for ``model`` using backward time-iteration. This algorithm iterates on the residuals of the arbitrage equations Parameters ---------- model : NumericModel "fg" or "fga" model to be solved bounds : ndarray boundaries for approximations. First row contains minimum values. Second row contains maximum values. verbose : boolean if True, display iterations initial_dr : decision rule initial guess for the decision rule pert_order : {1} if no initial guess is supplied, the perturbation solution at order ``pert_order`` is used as initial guess with_complementarities : boolean (True) if False, complementarity conditions are ignored interp_type : {`smolyak`, `spline`} type of interpolation to use for future controls smolyak_orders : int parameter ``l`` for Smolyak interpolation interp_orders : 1d array-like list of integers specifying the number of nodes in each dimension if ``interp_type="spline" `` Returns ------- decision rule : approximated solution ''' def vprint(t): if verbose: print(t) parms = model.calibration['parameters'] sigma = model.covariances if initial_dr is None: if pert_order == 1: initial_dr = approximate_controls(model) if pert_order > 1: raise Exception("Perturbation order > 1 not supported (yet).") if interp_type == 'perturbations': return initial_dr if bounds is not None: pass elif model.options and 'approximation_space' in model.options: vprint('Using bounds specified by model') approx = model.options['approximation_space'] a = approx['a'] b = approx['b'] bounds = np.row_stack([a, b]) bounds = np.array(bounds, dtype=float) if interp_orders is None: interp_orders = approx.get('orders', [5] * bounds.shape[1]) else: vprint('Using asymptotic bounds given by first order solution.') from dolo.numeric.timeseries import asymptotic_variance # this will work only if initial_dr is a Taylor expansion Q = asymptotic_variance(initial_dr.A.real, initial_dr.B.real, initial_dr.sigma, T=T) devs = np.sqrt(np.diag(Q)) bounds = np.row_stack([ initial_dr.S_bar - devs * n_s, initial_dr.S_bar + devs * n_s, ]) if interp_orders is None: interp_orders = [5] * bounds.shape[1] if interp_type == 'smolyak': from dolo.numeric.interpolation.smolyak import SmolyakGrid dr = SmolyakGrid(bounds[0, :], bounds[1, :], smolyak_order) elif interp_type == 'spline': from dolo.numeric.interpolation.splines import MultivariateSplines dr = MultivariateSplines(bounds[0, :], bounds[1, :], interp_orders) if integration == 'optimal_quantization': from dolo.numeric.discretization import quantization_nodes # number of shocks [epsilons, weights] = quantization_nodes(N_e, sigma) elif integration == 'gauss-hermite': from dolo.numeric.discretization import gauss_hermite_nodes if not integration_orders: integration_orders = [3] * sigma.shape[0] [epsilons, weights] = gauss_hermite_nodes(integration_orders, sigma) vprint('Starting time iteration') # TODO: transpose grid = dr.grid xinit = initial_dr(grid) xinit = xinit.real # just in case... f = model.functions['arbitrage'] g = model.functions['transition'] # define objective function (residuals of arbitrage equations) def fun(x): return step_residual(grid, x, dr, f, g, parms, epsilons, weights) ## t1 = time.time() err = 1 x0 = xinit it = 0 verbit = True if verbose == 'full' else False if with_complementarities: lbfun = model.functions['controls_lb'] ubfun = model.functions['controls_ub'] lb = lbfun(grid, parms) ub = ubfun(grid, parms) else: lb = None ub = None if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} | {4:3} |' headline = headline.format('N', ' Error', 'Gain', 'Time', 'nit') stars = '-'*len(headline) print(stars) print(headline) print(stars) # format string for within loop fmt_str = '|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} | {4:3} |' err_0 = 1 while err > tol and it < maxit: # update counters t_start = time.time() it += 1 # update interpolation coefficients (NOTE: filters through `fun`) dr.set_values(x0) # Derivative of objective function sdfun = SerialDifferentiableFunction(fun) # Apply solver with current decision rule for controls if with_complementarities: [x, nit] = ncpsolve(sdfun, lb, ub, x0, verbose=verbit, maxit=inner_maxit) else: [x, nit] = serial_newton(sdfun, x0, verbose=verbit) # update error and print if `verbose` err = abs(x-x0).max() err_SA = err/err_0 err_0 = err t_finish = time.time() elapsed = t_finish - t_start if verbose: print(fmt_str.format(it, err, err_SA, elapsed, nit)) # Update control vector x0[:] = x # x0 = x0 + (x-x0) # call user supplied hook, if any if hook: hook(dr, it, err) # warn and bail if we get inf if False in np.isfinite(x0): print('iteration {} failed : non finite value') return [x0, x] if it == maxit: import warnings warnings.warn(UserWarning("Maximum number of iterations reached")) # compute final fime and do final printout if `verbose` t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return dr
def evaluate_policy(model, dr, tol=1e-8, maxit=2000, verbose=False, hook=None, integration_orders=None): """Compute value function corresponding to policy ``dr`` Parameters: ----------- model: "fg" or "fga" model. Must contain a 'value' function. dr: decision rule to evaluate Returns: -------- decision rule: value function (a function of the space similar to a decision rule object) """ assert(model.model_spec=='fga') vfun = model.functions["value"] gfun = model.functions['transition'] afun = model.functions['auxiliary'] parms = model.calibration['parameters'] n_vals = len(model.symbols['values']) import time t1 = time.time() err = 1 it = 0 approx = model.options['approximation_space'] a = approx['a'] b = approx['b'] orders = approx['orders'] from dolo.numeric.interpolation.splines import MultivariateSplines drv = MultivariateSplines(a,b,orders) grid = drv.grid N = drv.grid.shape[0] controls = dr(grid) auxiliaries = model.functions['auxiliary'](grid, controls, parms) guess_0 = model.calibration['values'] guess_0 = guess_0[None,:].repeat(N, axis=0) sigma = model.covariances from dolo.numeric.discretization import gauss_hermite_nodes if not integration_orders: integration_orders = [3] * sigma.shape[0] [epsilons, weights] = gauss_hermite_nodes(integration_orders, sigma) if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |'.format( 'N',' Error', 'Gain','Time') stars = '-'*len(headline) print(stars) print(headline) print(stars) err_0 = 1 while err > tol and it < maxit: if hook: hook() t_start = time.time() it +=1 drv.set_values(guess_0) guess = update_value(gfun, afun, vfun, grid, controls, auxiliaries, dr, drv, epsilons, weights, parms, n_vals) err = abs(guess-guess_0).max() err_SA = err/err_0 err_0 = err guess_0 = guess t_finish = time.time() elapsed = t_finish - t_start if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err, err_SA, elapsed)) if it == maxit: import warnings warnings.warn(UserWarning("Maximum number of iterations reached")) t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return drv
def evaluate_policy(model, dr, tol=1e-8, maxit=2000, verbose=False, hook=None, integration_orders=None): """Compute value function corresponding to policy ``dr`` Parameters: ----------- model: "fg" or "fga" model. Must contain a 'value' function. dr: decision rule to evaluate Returns: -------- decision rule: value function (a function of the space similar to a decision rule object) """ assert (model.model_type == 'dtcscc') vfun = model.functions["value"] gfun = model.functions['transition'] afun = model.functions['auxiliary'] parms = model.calibration['parameters'] n_vals = len(model.symbols['values']) t1 = time.time() err = 1.0 it = 0 approx = model.options['approximation_space'] a = approx['a'] b = approx['b'] orders = approx['orders'] drv = MultivariateSplines(a, b, orders) grid = drv.grid N = drv.grid.shape[0] controls = dr(grid) auxiliaries = afun(grid, controls, parms) guess_0 = model.calibration['values'] guess_0 = guess_0[None, :].repeat(N, axis=0) sigma = model.covariances if not integration_orders: integration_orders = [3] * sigma.shape[0] [epsilons, weights] = gauss_hermite_nodes(integration_orders, sigma) if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |'.format( 'N', ' Error', 'Gain', 'Time') stars = '-' * len(headline) print(stars) print(headline) print(stars) err_0 = 1.0 while err > tol and it < maxit: if hook: hook() t_start = time.time() it += 1 # update spline coefficients with current values drv.set_values(guess_0) # update the geuss of value functions guess = update_value(gfun, afun, vfun, grid, controls, dr, drv, epsilons, weights, parms, n_vals) # compute error err = abs(guess - guess_0).max() err_SA = err / err_0 err_0 = err # update guess guess_0[:] = guess.copy() # print update to user, if verbose t_finish = time.time() elapsed = t_finish - t_start if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err, err_SA, elapsed)) if it == maxit: warnings.warn(UserWarning("Maximum number of iterations reached")) t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return drv
def pea(model, maxit=100, tol=1e-8, initial_dr=None, verbose=False): t1 = time.time() g = model.functions['transition'] d = model.functions['direct_response'] h = model.functions['expectation'] p = model.calibration['parameters'] if initial_dr is None: drp = approximate_controls(model) else: drp = approximate_controls(model) nodes, weights = gauss_hermite_nodes([5], model.covariances) ap = model.options['approximation_space'] a = ap['a'] b = ap['b'] orders = ap['orders'] grid = mlinspace(a, b, orders) dr = MultivariateCubicSplines(a, b, orders) N = grid.shape[0] z = np.zeros((N, len(model.symbols['expectations']))) x_0 = drp(grid) it = 0 err = 10 err_0 = 10 if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |' headline = headline.format('N', ' Error', 'Gain', 'Time') stars = '-' * len(headline) print(stars) print(headline) print(stars) # format string for within loop fmt_str = '|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |' while err > tol and it <= maxit: t_start = time.time() dr.set_values(x_0) z[...] = 0 for i in range(weights.shape[0]): e = nodes[i, :] S = g(grid, x_0, e, p) # evaluate future controls X = dr(S) z += weights[i] * h(S, X, p) # TODO: check that control is admissible new_x = d(grid, z, p) # check whether they differ from the preceding guess err = (abs(new_x - x_0).max()) x_0 = new_x if verbose: # update error and print if `verbose` err_SA = err / err_0 err_0 = err t_finish = time.time() elapsed = t_finish - t_start if verbose: print(fmt_str.format(it, err, err_SA, elapsed)) if it == maxit: import warnings warnings.warn(UserWarning("Maximum number of iterations reached")) # compute final fime and do final printout if `verbose` t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return dr
def evaluate_policy(model, dr, tol=1e-8, grid={}, distribution={}, maxit=2000, verbose=False, hook=None, integration_orders=None): ''' Compute value function corresponding to policy ``dr`` Parameters: ----------- model: "dtcscc" model. Must contain a 'value' function. dr: decision rule to evaluate Returns: -------- decision rule: value function (a function of the space similar to a decision rule object) ''' assert (model.model_type == 'dtcscc') vfun = model.functions["value"] gfun = model.functions['transition'] parms = model.calibration['parameters'] n_vals = len(model.symbols['values']) t1 = time.time() err = 1.0 it = 0 approx = model.get_grid(**grid) interp_type = approx.interpolation distrib = model.get_distribution(**distribution) sigma = distrib.sigma drv = create_interpolator(approx, approx.interpolation) grid = drv.grid N = drv.grid.shape[0] controls = dr(grid) guess_0 = model.calibration['values'] guess_0 = guess_0[None, :].repeat(N, axis=0) if not integration_orders: integration_orders = [3] * sigma.shape[0] [nodes, weights] = gauss_hermite_nodes(integration_orders, sigma) if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |'.format( 'N', ' Error', 'Gain', 'Time') stars = '-' * len(headline) print(stars) print(headline) print(stars) err_0 = 1.0 while err > tol and it < maxit: if hook: hook() t_start = time.time() it += 1 # update spline coefficients with current values drv.set_values(guess_0) # update the geuss of value functions guess = update_value(gfun, vfun, grid, controls, dr, drv, nodes, weights, parms, n_vals) # compute error err = abs(guess - guess_0).max() err_SA = err / err_0 err_0 = err # update guess guess_0[:] = guess.copy() # print update to user, if verbose t_end = time.time() elapsed = t_end - t_start if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err, err_SA, elapsed)) if it == maxit: warnings.warn(UserWarning("Maximum number of iterations reached")) t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return drv
def solve_policy(model, tol=1e-6, grid={}, distribution={}, integration_orders=None, maxit=500, maxit_howard=500, verbose=False, hook=None, initial_dr=None, pert_order=1): ''' Solve for the value function and associated decision rule by iterating over the value function. Parameters ----------- model : ``dtcscc`` model. Must contain a ``felicity`` function. Returns -------- dr : Markov decision rule The solved decision rule/policy function drv : decision rule The solved value function ''' assert (model.model_type == 'dtcscc') def vprint(t): if verbose: print(t) # transition(s, x, e, p, out), felicity(s, x, p, out) transition = model.functions['transition'] felicity = model.functions['felicity'] controls_lb = model.functions['controls_lb'] controls_ub = model.functions['controls_ub'] parms = model.calibration['parameters'] discount = model.calibration['beta'] x0 = model.calibration['controls'] s0 = model.calibration['states'] r0 = felicity(s0, x0, parms) approx = model.get_grid(**grid) # a = approx.a # b = approx.b # orders = approx.orders distrib = model.get_distribution(**distribution) sigma = distrib.sigma # Possibly use the approximation orders? if integration_orders is None: integration_orders = [3] * sigma.shape[0] [nodes, weights] = gauss_hermite_nodes(integration_orders, sigma) interp_type = approx.interpolation drv = create_interpolator(approx, interp_type) if initial_dr is None: if pert_order == 1: dr = approximate_controls(model) if pert_order > 1: raise Exception("Perturbation order > 1 not supported (yet).") else: dr = initial_dr grid = drv.grid N = grid.shape[0] # Number of states n_x = grid.shape[1] # Number of controls controls = dr(grid) controls_0 = np.zeros((N, n_x)) controls_0[:, :] = model.calibration['controls'][None, :] values_0 = np.zeros((N, 1)) values_0[:, :] = r0 / (1 - discount) if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |'.format( 'N', ' Error', 'Gain', 'Time') stars = '-' * len(headline) print(stars) print(headline) print(stars) t1 = time.time() # FIRST: value function iterations, 10 iterations to start it = 0 err_v = 100 err_v_0 = 0.0 gain_v = 0.0 err_x = 100 err_x_0 = 100 if verbose: print(stars) print('Starting value function iteration') print(stars) while err_v > tol and it < 10: t_start = time.time() it += 1 # update interpolation object with current values drv.set_values(values_0) values = values_0.copy() controls = controls_0.copy() for n in range(N): s = grid[n, :] x = controls[n, :] lb = controls_lb(s, parms) ub = controls_ub(s, parms) bnds = [e for e in zip(lb, ub)] def valfun(xx): return -choice_value(transition, felicity, s, xx, drv, nodes, weights, parms, discount)[0] res = minimize(valfun, x, bounds=bnds, tol=1e-4) controls[n, :] = res.x values[n, 0] = -valfun(res.x) # compute error, update value and dr err_x = abs(controls - controls_0).max() err_v = abs(values - values_0).max() t_end = time.time() elapsed = t_end - t_start values_0 = values controls_0 = controls gain_x = err_x / err_x_0 gain_v = err_v / err_v_0 err_x_0 = err_x err_v_0 = err_v # print update to user, if verbose if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err_v, gain_v, elapsed)) # SECOND: Howard improvement step, 10-20 iterations it = 0 err_v = 100 err_v_0 = 0.0 gain_v = 0.0 if verbose: print(stars) print('Starting Howard improvement step') print(stars) while err_v > tol and it < maxit_howard: t_start = time.time() it += 1 # update interpolation object with current values drv.set_values(values_0) values = values_0.copy() controls = controls_0.copy() # controls = controls_0.copy() # No need to keep updating for n in range(N): s = grid[n, :] x = controls[n, :] values[n, 0] = choice_value(transition, felicity, s, x, drv, nodes, weights, parms, discount)[0] # compute error, update value function err_v = abs(values - values_0).max() values_0 = values t_end = time.time() elapsed = t_end - t_start gain_v = err_v / err_v_0 err_v_0 = err_v # print update to user, if verbose if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err_v, gain_v, elapsed)) # THIRD: Back to value function iteration until convergence. it = 0 err_v = 100 err_v_0 = 0.0 gain_v = 0.0 err_x = 100 err_x_0 = 100 if verbose: print(stars) print('Starting value function iteration') print(stars) while err_v > tol and it < maxit: t_start = time.time() it += 1 # update interpolation object with current values drv.set_values(values_0) values = values_0.copy() controls = controls_0.copy() for n in range(N): s = grid[n, :] x = controls[n, :] lb = controls_lb(s, parms) ub = controls_ub(s, parms) bnds = [e for e in zip(lb, ub)] def valfun(xx): return -choice_value(transition, felicity, s, xx, drv, nodes, weights, parms, discount)[0] res = minimize(valfun, x, bounds=bnds, tol=1e-4) controls[n, :] = res.x values[n, 0] = -valfun(res.x) # compute error, update value and dr err_x = abs(controls - controls_0).max() err_v = abs(values - values_0).max() t_end = time.time() elapsed = t_end - t_start values_0 = values controls_0 = controls gain_x = err_x / err_x_0 gain_v = err_v / err_v_0 err_x_0 = err_x err_v_0 = err_v # print update to user, if verbose if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |'.format( it, err_v, gain_v, elapsed)) if it == maxit: warnings.warn(UserWarning("Maximum number of iterations reached")) t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) # final value function and decision rule drv.set_values(values_0) dr = create_interpolator(approx, interp_type) dr.set_values(controls_0) return dr, drv
def test_simulations(): import time from matplotlib.pyplot import hist, show, figure, plot, title from dolo import yaml_import, approximate_controls from dolo.numeric.discretization import gauss_hermite_nodes model = yaml_import('../../examples/models/rbc.yaml') dr = approximate_controls(model) parms = model.calibration['parameters'] sigma = model.get_calibration().sigma s0 = dr.S_bar horizon = 50 t1 = time.time() simul = simulate(model, dr, s0, sigma, n_exp=1000, parms=parms, seed=1, horizon=horizon) t2 = time.time() print("Took: {}".format(t2 - t1)) N = 80 [x, w] = gauss_hermite_nodes(N, sigma) t3 = time.time() simul_2 = simulate(model, dr, s0, sigma, n_exp=1000, parms=parms, horizon=horizon, seed=1, solve_expectations=True, nodes=x, weights=w) t4 = time.time() print("Took: {}".format(t4 - t3)) timevec = numpy.array(range(simul.shape[2])) figure() for k in range(10): plot(simul[:, k, 0] - simul_2[:, k, 0]) title("Productivity") show() figure() for k in range(10): plot(simul[:, k, 1] - simul_2[:, k, 1]) title("Investment") show() # # figure() # plot(simul[0,0,:]) # plot(simul_2[0,0,:]) # show() figure() for i in range(horizon): hist(simul[i, :, 0], bins=50) show()
def time_iteration(model, bounds=None, verbose=False, initial_dr=None, pert_order=1, with_complementarities=True, interp_type='smolyak', smolyak_order=3, interp_orders=None, maxit=500, tol=1e-8, integration='gauss-hermite', integration_orders=None, T=200, n_s=3, hook=None): """Finds a global solution for ``model`` using backward time-iteration. Parameters: ----------- model: NumericModel "fg" or "fga" model to be solved bounds: ndarray boundaries for approximations. First row contains minimum values. Second row contains maximum values. verbose: boolean if True, display iterations initial_dr: decision rule initial guess for the decision rule pert_order: {1} if no initial guess is supplied, the perturbation solution at order ``pert_order`` is used as initial guess with_complementarities: boolean (True) if False, complementarity conditions are ignored interp_type: {`smolyak`, `spline`} type of interpolation to use for future controls smolyak_orders: int parameter ``l`` for Smolyak interpolation interp_orders: 1d array-like list of integers specifying the number of nods in each dimension if ``interp_type="spline" `` Returns: -------- decision rule object (SmolyakGrid or MultivariateSplines) """ def vprint(t): if verbose: print(t) parms = model.calibration['parameters'] sigma = model.covariances if initial_dr == None: if pert_order == 1: from dolo.algos.perturbations import approximate_controls initial_dr = approximate_controls(model) if pert_order > 1: raise Exception("Perturbation order > 1 not supported (yet).") if interp_type == 'perturbations': return initial_dr if bounds is not None: pass elif model.options and 'approximation_space' in model.options: vprint('Using bounds specified by model') approx = model.options['approximation_space'] a = approx['a'] b = approx['b'] bounds = numpy.row_stack([a, b]) bounds = numpy.array(bounds, dtype=float) else: vprint('Using asymptotic bounds given by first order solution.') from dolo.numeric.timeseries import asymptotic_variance # this will work only if initial_dr is a Taylor expansion Q = asymptotic_variance(initial_dr.A.real, initial_dr.B.real, initial_dr.sigma, T=T) devs = numpy.sqrt(numpy.diag(Q)) bounds = numpy.row_stack([ initial_dr.S_bar - devs * n_s, initial_dr.S_bar + devs * n_s, ]) if interp_orders == None: interp_orders = [5] * bounds.shape[1] if interp_type == 'smolyak': from dolo.numeric.interpolation.smolyak import SmolyakGrid dr = SmolyakGrid(bounds[0, :], bounds[1, :], smolyak_order) elif interp_type == 'spline': from dolo.numeric.interpolation.splines import MultivariateSplines dr = MultivariateSplines(bounds[0, :], bounds[1, :], interp_orders) elif interp_type == 'multilinear': from dolo.numeric.interpolation.multilinear import MultilinearInterpolator dr = MultilinearInterpolator(bounds[0, :], bounds[1, :], interp_orders) if integration == 'optimal_quantization': from dolo.numeric.discretization import quantization_nodes # number of shocks [epsilons, weights] = quantization_nodes(N_e, sigma) elif integration == 'gauss-hermite': from dolo.numeric.discretization import gauss_hermite_nodes if not integration_orders: integration_orders = [3] * sigma.shape[0] [epsilons, weights] = gauss_hermite_nodes(integration_orders, sigma) vprint('Starting time iteration') # TODO: transpose grid = dr.grid xinit = initial_dr(grid) xinit = xinit.real # just in case... from dolo.algos.convert import get_fg_functions f, g = get_fg_functions(model) import time fun = lambda x: step_residual(grid, x, dr, f, g, parms, epsilons, weights) ## t1 = time.time() err = 1 x0 = xinit it = 0 verbit = True if verbose == 'full' else False if with_complementarities: lbfun = model.functions['arbitrage_lb'] ubfun = model.functions['arbitrage_ub'] lb = lbfun(grid, parms) ub = ubfun(grid, parms) else: lb = None ub = None if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} | {4:3} |'.format( 'N', ' Error', 'Gain', 'Time', 'nit') stars = '-' * len(headline) print(stars) print(headline) print(stars) err_0 = 1 while err > tol and it < maxit: t_start = time.time() it += 1 dr.set_values(x0) from dolo.numeric.optimize.newton import serial_newton, SerialDifferentiableFunction from dolo.numeric.optimize.ncpsolve import ncpsolve sdfun = SerialDifferentiableFunction(fun) if with_complementarities: [x, nit] = ncpsolve(sdfun, lb, ub, x0, verbose=verbit) else: [x, nit] = serial_newton(sdfun, x0, verbose=verbit) err = abs(x - x0).max() err_SA = err / err_0 err_0 = err t_finish = time.time() elapsed = t_finish - t_start if verbose: print('|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} | {4:3} |'.format( it, err, err_SA, elapsed, nit)) x0 = x0 + (x - x0) if hook: hook(dr, it, err) if False in np.isfinite(x0): print('iteration {} failed : non finite value') return [x0, x] if it == maxit: import warnings warnings.warn(UserWarning("Maximum number of iterations reached")) t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return dr
def gssa(model, maxit=100, tol=1e-8, initial_dr=None, verbose=False, n_sim=10000, deg=3, damp=0.1, seed=42): """ Sketch of algorithm: 0. Choose levels for the initial states and the simulation length (n_sim) 1. Obtain an initial decision rule -- here using first order perturbation 2. Draw a sequence of innovations epsilon 3. Iterate on the following steps: - Use the epsilons, initial states, and proposed decision rule to simulate model forward. Will leave us with time series of states and controls - Evaluate expectations using quadrature - Use direct response to get alternative proposal for controls - Regress updated controls on the simulated states to get proposal coefficients. New coefficients are convex combination of previous coefficients and proposal coefficients. Weights controlled by damp, where damp is the weight on the old coefficients. This should be fairly low to increase chances of convergence. - Check difference between the simulated series of controls and the direct response version of controls """ # verify input arguments if deg < 0 or deg > 5: raise ValueError("deg must be in [1, 5]") if damp < 0 or damp > 1: raise ValueError("damp must be in [0, 1]") t1 = time.time() # extract model functions and parameters g = model.__original_functions__['transition'] g_gu = model.__original_gufunctions__['transition'] h_gu = model.__original_gufunctions__['expectation'] d_gu = model.__original_gufunctions__['direct_response'] p = model.calibration['parameters'] n_s = len(model.symbols["states"]) n_x = len(model.symbols["controls"]) n_z = len(model.symbols["expectations"]) n_eps = len(model.symbols["shocks"]) s0 = model.calibration["states"] x0 = model.calibration["controls"] # construct initial decision rule if not supplied if initial_dr is None: drp = approximate_controls(model) else: drp = initial_dr # set up quadrature weights and nodes sigma = model.covariances nodes, weights = gauss_hermite_nodes([5], model.covariances) # draw sequence of innovations np.random.seed(seed) epsilon = numpy.random.multivariate_normal(np.zeros(n_eps), sigma, n_sim) # simulate initial decision rule and do initial regression for coefs init_sim = simulate(model, drp, horizon=n_sim, return_array=True, forcing_shocks=epsilon) s_sim = init_sim[:, 0, 0:n_s] x_sim = init_sim[:, 0, n_s:n_s + n_x] Phi_sim = complete_polynomial(s_sim.T, deg).T coefs = np.ascontiguousarray(lstsq(Phi_sim, x_sim)[0]) # NOTE: the ascontiguousarray above was needed for numba to compile the # `np.dot` in the simulation function in no python mode. Appearantly # the array returned from lstsq is not C-contiguous # allocate for simulated series of expectations and next period states z_sim = np.empty((n_sim, n_z)) S = np.empty_like(s_sim) X = np.empty_like(x_sim) H = np.empty_like(z_sim) new_x = np.empty_like(x_sim) # set initial states and controls s_sim[0, :] = s0 x_sim[0, :] = x0 Phi_t = np.empty(n_complete(n_s, deg)) # buffer array for simulation # create jitted function that will simulate states and controls, using # the epsilon shocks from above (define here as closure over all data # above). @jit(nopython=True) def simulate_states_controls(s, x, Phi_t, coefs): for t in range(1, n_sim): g(s[t - 1, :], x[t - 1, :], epsilon[t, :], p, s[t, :]) # fill Phi_t with new complete poly version of s[t, :] _complete_poly_impl_vec(s[t, :], deg, Phi_t) # do inner product to get new controls x[t, :] = Phi_t @coefs it = 0 err = 10.0 err_0 = 10 if verbose: headline = '|{0:^4} | {1:10} | {2:8} | {3:8} |' headline = headline.format('N', ' Error', 'Gain', 'Time') stars = '-' * len(headline) print(stars) print(headline) print(stars) # format string for within loop fmt_str = '|{0:4} | {1:10.3e} | {2:8.3f} | {3:8.3f} |' while err > tol and it <= maxit: t_start = time.time() # simulate with new coefficients simulate_states_controls(s_sim, x_sim, Phi_t, coefs) # update expectations of z # update_expectations(s_sim, x_sim, z_sim, Phi_sim) z_sim[:, :] = 0.0 for i in range(weights.shape[0]): e = nodes[i, :] # extract nodes # evaluate future states at each node (stores in S) g_gu(s_sim, x_sim, e, p, S) # evaluate future controls at each future state _complete_poly_impl(S.T, deg, Phi_sim.T) np.dot(Phi_sim, coefs, out=X) # compute expectation (stores in H) h_gu(S, X, p, H) z_sim += weights[i] * H # get controls on the simulated points from direct_resposne # (stores in new_x) d_gu(s_sim, z_sim, p, new_x) # update basis matrix and do regression of new_x on s_sim to get # updated coefficients _complete_poly_impl(s_sim.T, deg, Phi_sim.T) new_coefs = np.ascontiguousarray(lstsq(Phi_sim, new_x)[0]) # check whether they differ from the preceding guess err = (abs(new_x - x_sim).max()) # update the series of controls and coefficients x_sim[:, :] = new_x coefs = (1 - damp) * new_coefs + damp * coefs if verbose: # update error and print if `verbose` err_SA = err / err_0 err_0 = err t_finish = time.time() elapsed = t_finish - t_start if verbose: print(fmt_str.format(it, err, err_SA, elapsed)) it += 1 if it == maxit: warnings.warn(UserWarning("Maximum number of iterations reached")) # compute final fime and do final printout if `verbose` t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return coefs