def parameterized_expectations(model, verbose=False, dr0=None, pert_order=1, with_complementarities=True, grid={}, distribution={}, maxit=100, tol=1e-8, inner_maxit=10, direct=False): ''' Find global solution for ``model`` via parameterized expectations. Controls must be expressed as a direct function of equilibrium objects. Algorithm iterates over the expectations function in the arbitrage equation. Parameters: ---------- model : NumericModel ``dtcscc`` model to be solved verbose : boolean if True, display iterations dr0 : 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 grid : grid options distribution : distribution options maxit : maximum number of iterations tol : tolerance criterium for successive approximations inner_maxit : maximum number of iteration for inner solver direct : if True, solve with direct method. If false, solve indirectly Returns ------- decision rule : approximated solution ''' t1 = time.time() g = model.functions['transition'] h = model.functions['expectation'] d = model.functions['direct_response'] f = model.functions['arbitrage_exp'] # f(s, x, z, p, out) parms = model.calibration['parameters'] if dr0 is None: if pert_order == 1: dr0 = approximate_controls(model) if pert_order > 1: raise Exception("Perturbation order > 1 not supported (yet).") approx = model.get_endo_grid(**grid) grid = approx.grid interp_type = approx.interpolation dr = create_interpolator(approx, interp_type) expect = create_interpolator(approx, interp_type) distrib = model.get_distribution(**distribution) nodes, weights = distrib.discretize() N = grid.shape[0] z = np.zeros((N, len(model.symbols['expectations']))) x_0 = dr0(grid) x_0 = x_0.real # just in case ... h_0 = h(grid, x_0, parms) it = 0 err = 10 err_0 = 10 verbit = True if verbose == 'full' else False if with_complementarities is True: 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} |' 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: it += 1 t_start = time.time() # dr.set_values(x_0) expect.set_values(h_0) # evaluate expectation over the future state z[...] = 0 for i in range(weights.shape[0]): e = nodes[i, :] S = g(grid, x_0, e, parms) z += weights[i] * expect(S) if direct is True: # Use control as direct function of arbitrage equation new_x = d(grid, z, parms) if with_complementarities is True: new_x = np.minimum(new_x, ub) new_x = np.maximum(new_x, lb) else: # Find control by solving arbitrage equation def fun(x): return f(grid, x, z, parms) sdfun = SerialDifferentiableFunction(fun) if with_complementarities is True: [new_x, nit] = ncpsolve(sdfun, lb, ub, x_0, verbose=verbit, maxit=inner_maxit) else: [new_x, nit] = serial_newton(sdfun, x_0, verbose=verbit) new_h = h(grid, new_x, parms) # update error err = (abs(new_h - h_0).max()) # Update guess for decision rule and expectations function x_0 = new_x h_0 = new_h # print error infomation 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) # Interpolation for the decision rule dr.set_values(x_0) return dr
def parameterized_expectations(model, verbose=False, initial_dr=None, pert_order=1, with_complementarities=True, grid={}, distribution={}, maxit=100, tol=1e-8, inner_maxit=10, direct=False): ''' Find global solution for ``model`` via parameterized expectations. Controls must be expressed as a direct function of equilibrium objects. Algorithm iterates over the expectations function in the arbitrage equation. Parameters: ---------- model : NumericModel ``dtcscc`` model to be solved 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 grid : grid options distribution : distribution options maxit : maximum number of iterations tol : tolerance criterium for successive approximations inner_maxit : maximum number of iteration for inner solver direct : if True, solve with direct method. If false, solve indirectly Returns ------- decision rule : approximated solution ''' t1 = time.time() g = model.functions['transition'] h = model.functions['expectation'] d = model.functions['direct_response'] f = model.functions['arbitrage_exp'] # f(s, x, z, p, out) parms = model.calibration['parameters'] 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).") approx = model.get_grid(**grid) grid = approx.grid interp_type = approx.interpolation dr = create_interpolator(approx, interp_type) expect = create_interpolator(approx, interp_type) distrib = model.get_distribution(**distribution) nodes, weights = distrib.discretize() N = grid.shape[0] z = np.zeros((N, len(model.symbols['expectations']))) x_0 = initial_dr(grid) x_0 = x_0.real # just in case ... h_0 = h(grid, x_0, parms) it = 0 err = 10 err_0 = 10 verbit = True if verbose == 'full' else False if with_complementarities is True: 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} |' 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: it += 1 t_start = time.time() # dr.set_values(x_0) expect.set_values(h_0) # evaluate expectation over the future state z[...] = 0 for i in range(weights.shape[0]): e = nodes[i, :] S = g(grid, x_0, e, parms) z += weights[i]*expect(S) if direct is True: # Use control as direct function of arbitrage equation new_x = d(grid, z, parms) if with_complementarities is True: new_x = np.minimum(new_x, ub) new_x = np.maximum(new_x, lb) else: # Find control by solving arbitrage equation def fun(x): return f(grid, x, z, parms) sdfun = SerialDifferentiableFunction(fun) if with_complementarities is True: [new_x, nit] = ncpsolve(sdfun, lb, ub, x_0, verbose=verbit, maxit=inner_maxit) else: [new_x, nit] = serial_newton(sdfun, x_0, verbose=verbit) new_h = h(grid, new_x, parms) # update error err = (abs(new_h - h_0).max()) # Update guess for decision rule and expectations function x_0 = new_x h_0 = new_h # print error infomation 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) # Interpolation for the decision rule dr.set_values(x_0) return dr
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 time_iteration(model, verbose=False, initial_dr=None, pert_order=1, with_complementarities=True, grid={}, distribution={}, maxit=500, tol=1e-8, inner_maxit=10, 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 "dtcscc" model to be solved 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 grid: grid options distribution: distribution options maxit: maximum number of iterations inner_maxit: maximum number of iteration for inner solver tol: tolerance criterium for successive approximations Returns ------- decision rule : approximated solution ''' def vprint(t): if verbose: print(t) f = model.functions['arbitrage'] g = model.functions['transition'] parms = model.calibration['parameters'] approx = model.get_grid(**grid) interp_type = approx.interpolation dr = create_interpolator(approx, interp_type) distrib = model.get_distribution(**distribution) nodes, weights = distrib.discretize() 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).") vprint('Starting time iteration') # TODO: transpose grid = dr.grid x_0 = initial_dr(grid) x_0 = x_0.real # just in case... # define objective function (residuals of arbitrage equations) def fun(x): return step_residual(grid, x, dr, f, g, parms, nodes, weights) ## t1 = time.time() err = 1 err_0 = 1 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} |' while err > tol and it < maxit: # update counters t_start = time.time() it += 1 # update interpolation coefficients (NOTE: filters through `fun`) dr.set_values(x_0) # Derivative of objective function sdfun = SerialDifferentiableFunction(fun) # Apply solver with current decision rule for controls if with_complementarities: [x, nit] = ncpsolve(sdfun, lb, ub, x_0, verbose=verbit, maxit=inner_maxit) else: [x, nit] = serial_newton(sdfun, x_0, verbose=verbit) # update error and print if `verbose` err = abs(x-x_0).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 x_0[:] = 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(x_0): print('iteration {} failed : non finite value') return [x_0, x] if it == maxit: import warnings warnings.warn(UserWarning("Maximum number of iterations reached")) # compute final time and do final printout if `verbose` t2 = time.time() if verbose: print(stars) print('Elapsed: {} seconds.'.format(t2 - t1)) print(stars) return dr
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