def test_serial_solve(self): fun = lambda x: [-josephy(x), -Djosephy(x)] x0=np.array( [1.25, 0.01, 0.01, 0.50] ) lb=np.array( [0.00, 0.00, 0.00, 0.00] ) # ub=np.array( [inf, inf, inf, inf] ) ub=np.array( [1e20, 1e20, 1e20, 1e20] ) # resp = ncpsolve(fun, lb, ub, x0, tol=1e-15) sol = np.array( [ 1.22474487e+00, 0.00000000e+00, 3.60543164e-17, 5.00000000e-01]) # assert_almost_equal(sol, resp) N = 10 d = len(x0) s_x0 = np.row_stack([x0]*N) s_lb = np.row_stack([lb]*N) s_ub = np.row_stack([ub]*N) def serial_fun(xvec): resp = np.zeros( (N,d) ) dresp = np.zeros( (N,d,d) ) for n in range(N): [v, dv] = fun(xvec[n,:]) resp[n,:] = v dresp[n,:,:] = dv return [resp, dresp] res = serial_fun(s_x0)[0] serial_sol = ncpsolve( serial_fun, s_lb, s_ub, s_x0, jactype='serial', verbose=True) print(serial_sol)
if __name__ == '__main__': from numpy import inf fun = lambda x: [-josephy(x), -Djosephy(x)] x0=np.array( [1.25, 0.01, 0.01, 0.50] ) lb=np.array( [0.00, 0.00, 0.00, 0.00] ) ub=np.array( [inf, inf, inf, inf] ) resp = ncpsolve(fun, lb, ub, x0, tol=1e-15) sol = np.array( [ 1.22474487e+00, 0.00000000e+00, 3.60543164e-17, 5.00000000e-01]) from numpy.testing import assert_almost_equal assert_almost_equal(sol, resp[0]) N = 2 d = len(x0) serial_sol_check = np.zeros((d,N)) for n in range(N): serial_sol_check[:,n] = resp[0]
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 simulate(model, dr, s0=None, n_exp=0, horizon=40, seed=1, discard=False, solve_expectations=False, nodes=None, weights=None, forcing_shocks=None): '''Simulate a model using the specified decision rule. Parameters --------- model: NumericModel an "fg" or "fga" model dr: decision rule s0: ndarray initial state where all simulations start n_exp: int number of simulations. Use 0 for impulse-response functions horizon: int horizon for the simulations seed: int used to initialize the random number generator. Use it to replicate exact same results among simulations discard: boolean (False) if True, then all simulations containing at least one non finite value are discarded solve_expectations: boolean (False) if True, Euler equations are solved at each step using the controls to form expectations nodes: ndarray if `solve_expectations` is True use ``nodes`` for integration weights: ndarray if `solve_expectations` is True use ``weights`` for integration forcing_shocks: ndarray specify an exogenous process of shocks (requires ``n_exp<=1``) Returns ------- ndarray or pandas.Dataframe: if `n_exp<=1` returns a DataFrame object if `n_exp>1` returns a ``horizon x n_exp x n_v`` array where ``n_v`` is the number of variables. ''' if n_exp ==0: irf = True n_exp = 1 else: irf = False calib = model.calibration parms = numpy.array( calib['parameters'] ) sigma = model.covariances if s0 is None: s0 = calib['states'] # s0 = numpy.atleast_2d(s0.flatten()).T x0 = dr(s0) s_simul = numpy.zeros( (horizon, n_exp, s0.shape[0]) ) x_simul = numpy.zeros( (horizon, n_exp, x0.shape[0]) ) s_simul[0,:,:] = s0[None,:] x_simul[0,:,:] = x0[None,:] fun = model.functions if model.model_spec == 'fga': from dolo.algos.fg.convert import get_fg_functions [f,g] = get_fg_functions(model) else: f = model.functions['arbitrage'] g = model.functions['transition'] numpy.random.seed(seed) for i in range(horizon): mean = numpy.zeros(sigma.shape[0]) if irf: if forcing_shocks is not None and i<forcing_shocks.shape[0]: epsilons = forcing_shocks[i,:] else: epsilons = numpy.zeros( (1,sigma.shape[0]) ) else: epsilons = numpy.random.multivariate_normal(mean, sigma, n_exp) s = s_simul[i,:,:] x = dr(s) if solve_expectations: lbfun = model.functions['arbitrage_lb'] ubfun = model.functions['arbitrage_ub'] lb = lbfun(s, parms) ub = ubfun(s, parms) from dolo.numeric.optimize.newton import newton as newton_solver, SerialDifferentiableFunction from dolo.numeric.optimize.ncpsolve import ncpsolve fobj = lambda t: step_residual(s, t, dr, f, g, parms, nodes, weights) dfobj = SerialDifferentiableFunction(fobj) # [x,nit] = newton_solver(dfobj, x) [x,nit] = ncpsolve(dfobj, lb, ub, x) x_simul[i,:,:] = x ss = g(s,x,epsilons,parms) if i<(horizon-1): s_simul[i+1,:,:] = ss from numpy import isnan,all if not 'auxiliary' in fun: # TODO: find a better test than this l = [s_simul, x_simul] varnames = model.symbols['states'] + model.symbols['controls'] else: aux = fun['auxiliary'] a_simul = aux( s_simul.reshape((n_exp*horizon,-1)), x_simul.reshape( (n_exp*horizon,-1) ), parms) a_simul = a_simul.reshape(horizon, n_exp, -1) l = [s_simul, x_simul, a_simul] varnames = model.symbols['states'] + model.symbols['controls'] + model.symbols['auxiliaries'] simul = numpy.concatenate(l, axis=2) if discard: iA = -isnan(x_simul) valid = all( all( iA, axis=0 ), axis=1 ) simul = simul[:,valid,:] n_kept = s_simul.shape[1] if n_exp > n_kept: print( 'Discarded {}/{}'.format(n_exp-n_kept,n_exp)) if irf or (n_exp==1): simul = simul[:,0,:] import pandas ts = pandas.DataFrame(simul, columns=varnames) return ts return simul
def deterministic_solve(model, shocks=None, start_states=None, T=100, ignore_constraints=False, maxit=100, initial_guess=None, verbose=False, tol=1e-6): '''Computes a perfect foresight simulation using a stacked-time algorithm. The initial state is specified either by providing a series of exogenous shocks and assuming the model is initially in equilibrium with the first value of the shock, or by specifying an initial value for the states. Parameters ---------- a : array_like The shape and data-type of `a` define these same attributes of the returned array. dtype : data-type, optional .. versionadded:: 1.6.0 Overrides the data type of the result. order : {'C', 'F', 'A', or 'K'}, optional .. versionadded:: 1.6.0 Overrides the memory layout of the result. 'C' means C-order, 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, 'C' otherwise. 'K' means match the layout of `a` as closely as possible. subok : bool, optional. If True, then the newly created array will use the sub-class type of 'a', otherwise it will be a base-class array. Defaults to True. Parameters ---------- model : NumericModel "fg" or "fga" model to be solved shocks : ndarray :math:`n_e\\times N` matrix containing :math:`N` realizations of the shocks. :math:`N` must be smaller than :math:`T`. The exogenous process is assumed to remain constant and equal to its last value after `N` periods. start_states : ndarray or dict a vector with the value of initial states, or a calibration dictionary with the initial values of states and controls T : int horizon for the perfect foresight simulation maxit : int maximum number of iteration for the nonlinear solver verbose : boolean if True, the solver displays iterations tol : float stopping criterium for the nonlinear solver ignore_constraints : bool if True, complementarity constraints are ignored. Returns ------- pandas dataframe a dataframe with T+1 observations of the model variables along the simulation (states, controls, auxiliaries). The first observation is the steady-state corresponding to the first value of the shocks. The simulation should return to a steady-state corresponding to the last value of the exogenous shocks. ''' # TODO: # if model.model_spec == 'fga': # from dolo.compiler.converter import GModel_fg_from_fga # model = GModel_fg_from_fga(model) # definitions n_s = len(model.calibration['states']) n_x = len(model.calibration['controls']) if shocks is None: shocks = numpy.zeros( (len(model.calibration['shocks']),1)) # until last period, exogenous shock takes its last value epsilons = numpy.zeros( (T+1, shocks.shape[1])) epsilons[:(shocks.shape[0]-1),:] = shocks[1:,:] epsilons[(shocks.shape[0]-1):,:] = shocks[-1:,:] # final initial and final steady-states consistent with exogenous shocks if isinstance(start_states,dict): # at least that part is clear start_equilibrium = start_states start_s = start_equilibrium['states'] start_x = start_equilibrium['controls'] final_s = start_equilibrium['states'] final_x = start_equilibrium['controls'] elif isinstance(start_states, numpy.ndarray): start_s = start_states start_x = model.calibration['controls'] final_s = model.calibration['states'] final_x = model.calibration['controls'] else: # raise Exception("You must compute initial calibration yourself") final_dict = {model.symbols['shocks'][i]: shocks[i,-1] for i in range(len(model.symbols['shocks']))} start_dict = {model.symbols['shocks'][i]: shocks[i,0] for i in range(len(model.symbols['shocks']))} start_calib = find_deterministic_equilibrium( model, constraints=start_dict) final_calib = find_deterministic_equilibrium( model, constraints=start_dict) start_s = start_calib['states'] start_x = start_calib['controls'] final_s = final_calib['states'] final_x = final_calib['controls'] # if start_constraints: # ### we ignore start_constraints # start_dict.update(start_constraints) # final_equilibrium = start_constraints.copy() # else: # final_equilibrium = find_deterministic_equilibrium( model, constraints=final_dict) # final_s = final_equilibrium['states'] # final_x = final_equilibrium['controls'] # start_s = start_states # start_x = final_x #TODO: for start_x, it should be possible to use first order guess final = numpy.concatenate( [final_s, final_x] ) start = numpy.concatenate( [start_s, start_x] ) if verbose==True: print("Initial states : {}".format(start_s)) print("Final controls : {}".format(final_x)) p = model.calibration['parameters'] if initial_guess is None: initial_guess = numpy.row_stack( [start*(1-l) + final*l for l in linspace(0.0,1.0,T+1)] ) else: from pandas import DataFrame if isinstance( initial_guess, DataFrame ): initial_guess = array( initial_guess ).T.copy() initial_guess = initial_guess[:,:n_s+n_x] initial_guess[0,:n_s] = start_s initial_guess[-1,n_s:] = final_x sh = initial_guess.shape if model.x_bounds and not ignore_constraints: initial_states = initial_guess[:,:n_s] [lb, ub] = [ u( initial_states, p ) for u in model.x_bounds] lower_bound = initial_guess*0 - numpy.inf lower_bound[:, n_s:] = lb upper_bound = initial_guess*0 + numpy.inf upper_bound[:, n_s:] = ub test1 = max( lb.max(axis=0) - lb.min(axis=0) ) test2 = max( ub.max(axis=0) - ub.min(axis=0) ) if test1 >0.00000001 or test2>0.00000001: raise Exception("Not implemented: perfect foresight solution requires that controls have constant bounds.") else: ignore_constraints=True lower_bound = None upper_bound = None nn = sh[0]*sh[1] fobj = lambda vec: det_residual(model, vec.reshape(sh), start_s, final_x, epsilons)[0].ravel() if not ignore_constraints: from dolo.numeric.optimize.ncpsolve import ncpsolve ff = lambda vec: det_residual(model, vec.reshape(sh), start_s, final_x, epsilons, jactype='sparse') from dolo.numeric.optimize.newton import newton x0 = initial_guess.ravel() sol, nit = ncpsolve(ff, lower_bound.ravel(), upper_bound.ravel(), initial_guess.ravel(), verbose=verbose, maxit=maxit, tol=tol, jactype='sparse') sol = sol.reshape(sh) else: from scipy.optimize import root from numpy import array # ff = lambda vec: det_residual(model, vec.reshape(sh), start_s, final_x, epsilons, jactype='full') ff = lambda vec: det_residual(model, vec.reshape(sh), start_s, final_x, epsilons, diff=False).ravel() x0 = initial_guess.ravel() sol = root(ff, x0, jac=False) res = ff(sol.x) sol = sol.x.reshape(sh) import pandas if 'auxiliary' in model.functions: colnames = model.symbols['states'] + model.symbols['controls'] + model.symbols['auxiliaries'] # compute auxiliaries y = model.functions['auxiliary'](sol[:,:n_s], sol[:,n_s:], p) sol = numpy.column_stack([sol,y]) else: colnames = model.symbols['states'] + model.symbols['controls'] sol = numpy.column_stack([sol,epsilons]) colnames = colnames + model.symbols['shocks'] ts = pandas.DataFrame(sol, columns=colnames) return ts
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 solve_mfg_model(model, maxit=1000, initial_guess=None, with_complementarities=True, verbose=True, orders=None, output_type='dr'): assert(model.model_type == 'mfga') [P, Q] = model.markov_chain n_ms = P.shape[0] # number of markov states n_mv = P.shape[1] # number of markov variables x0 = model.calibration['controls'] parms = model.calibration['parameters'] n_x = len(x0) n_s = len(model.symbols['states']) approx = model.options['approximation_space'] a = approx['a'] b = approx['b'] if orders is None: orders = approx['orders'] from dolo.numeric.decision_rules_markov import MarkovDecisionRule mdr = MarkovDecisionRule(n_ms, a, b, orders) grid = mdr.grid N = grid.shape[0] # if isinstance(initial_guess, numpy.ndarray): # print("Using initial guess (1)") # controls = initial_guess # elif isinstance(initial_guess, dict): # print("Using initial guess (2)") # controls_0 = initial_guess['controls'] # ap_space = initial_guess['approximation_space'] # if False in (approx['orders']==orders): # print("Interpolating initial guess") # old_dr = MarkovDecisionRule(controls_0.shape[0], ap_space['smin'], ap_space['smax'], ap_space['orders']) # old_dr.set_values(controls_0) # controls_0 = numpy.zeros( (n_ms, N, n_x) ) # for i in range(n_ms): # e = old_dr(i,grid) # controls_0[i,:,:] = e # else: # controls_0 = numpy.zeros((n_ms, N, n_x)) controls_0 = numpy.zeros((n_ms, N, n_x)) if initial_guess is None: controls_0[:,:,:] = x0[None,None,:] else: for i_m in range(n_ms): m = P[i_m,:][None,:] controls_0[i_m,:,:] = initial_guess(i_m, grid) ff = model.functions['arbitrage'] gg = model.functions['transition'] aa = model.functions['auxiliary'] if 'arbitrage_lb' in model.functions and with_complementarities==True: lb_fun = model.functions['arbitrage_lb'] ub_fun = model.functions['arbitrage_ub'] lb = numpy.zeros_like(controls_0)*numpy.nan ub = numpy.zeros_like(controls_0)*numpy.nan for i_m in range(n_ms): m = P[i_m,:][None,:] p = parms[None,:] m = numpy.repeat(m, N, axis=0) p = numpy.repeat(p, N, axis=0) lb[i_m,:,:] = lb_fun(m, grid, p) ub[i_m,:,:] = ub_fun(m, grid, p) else: with_complementarities = False f = lambda m,s,x,M,S,X,p: ff(m,s,x,aa(m,s,x,p),M,S,X,aa(M,S,X,p),p) g = lambda m,s,x,M,p: gg(m,s,x,aa(m,s,x,p),M,p) # mdr.set_values(controls) sh_c = controls_0.shape controls_0 = controls_0.reshape( (-1,n_x) ) from dolo.numeric.optimize.newton import newton, SerialDifferentiableFunction from dolo.numeric.optimize.ncpsolve import ncpsolve err = 10 tol = 1e-8 inner_maxit = 50 it = 0 if with_complementarities: print("Solving WITH complementarities.") lb = lb.reshape((-1,n_x)) ub = ub.reshape((-1,n_x)) 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) import time t1 = time.time() err_0 = numpy.nan verbit = (verbose == 'full') while err>tol and it<maxit: it += 1 t_start = time.time() mdr.set_values(controls_0.reshape(sh_c)) fn = lambda x: residuals(f, g, grid, x.reshape(sh_c), mdr, P, Q, parms).reshape((-1,n_x)) dfn = SerialDifferentiableFunction(fn) if with_complementarities: [controls,nit] = ncpsolve(dfn, lb, ub, controls_0, verbose=verbit, maxit=inner_maxit) else: [controls, nit] = newton(dfn, controls_0, verbose=verbit, maxit=inner_maxit) err = abs(controls-controls_0).max() err_SA = err/err_0 err_0 = err controls_0 = controls 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 )) controls_0 = controls.reshape(sh_c) t2 = time.time() if verbose: print(stars) print("Elapsed: {} seconds.".format(t2-t1)) print(stars) if output_type == 'dr': return mdr elif output_type == 'controls': return controls_0 else: raise Exception("Unsupported ouput type {}.".format(output_type))
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 deterministic_solve(model, shocks=None, start_states=None, T=100, ignore_constraints=False, maxit=100, initial_guess=None, verbose=False, tol=1e-6): """ Computes a perfect foresight simulation using a stacked-time algorithm. The initial state is specified either by providing a series of exogenous shocks and assuming the model is initially in equilibrium with the first value of the shock, or by specifying an initial value for the states. Parameters ---------- model : NumericModel "dtcscc" model to be solved shocks : array-like, dict, or pandas.DataFrame A specification of the shocks to the model. Can be any of the following (note by "declaration order" below we mean the order of `model.symbols["shocks"]`): - A 1d numpy array-like specifying a time series for a single shock, or all shocks stacked into a single array. - A 2d numpy array where each column specifies the time series for one of the shocks in declaration order. This must be an `N` by number of shocks 2d array. - A dict where keys are strings found in `model.symbols["shocks"]` and values are a time series of values for that shock. For model shocks that do not appear in this dict, the shock is set to the calibrated value. Note that this interface is the most flexible as it allows the user to pass values for only a subset of the model shocks and it allows the passed time series to be of different lengths. - A DataFrame where columns map shock names into time series. The same assumptions and behavior that are used in the dict case apply here If nothing is given here, `shocks` is set equal to the calibrated values found in `model.calibration["shocks"]` for all periods. If the length of any time-series in shocks is less than `T` (see below) it is assumed that that particular shock will remain at the final given value for the duration of the simulaiton. start_states : ndarray or dict a vector with the value of initial states, or a calibration dictionary with the initial values of states and controls T : int horizon for the perfect foresight simulation maxit : int maximum number of iteration for the nonlinear solver verbose : boolean if True, the solver displays iterations tol : float stopping criterium for the nonlinear solver ignore_constraints : bool if True, complementarity constraints are ignored. Returns ------- pandas dataframe a dataframe with T+1 observations of the model variables along the simulation (states, controls, auxiliaries). The first observation is the steady-state corresponding to the first value of the shocks. The simulation should return to a steady-state corresponding to the last value of the exogenous shocks. """ # TODO: # if model.model_spec == 'fga': # from dolo.compiler.converter import GModel_fg_from_fga # model = GModel_fg_from_fga(model) # definitions n_s = len(model.calibration['states']) n_x = len(model.calibration['controls']) epsilons = _shocks_to_epsilons(model, shocks, T) # final initial and final steady-states consistent with exogenous shocks if start_states is None: start_states = model.calibration if isinstance(start_states, dict): # at least that part is clear start_equilibrium = start_states start_s = start_equilibrium['states'] start_x = start_equilibrium['controls'] final_s = start_equilibrium['states'] final_x = start_equilibrium['controls'] elif isinstance(start_states, np.ndarray): start_s = start_states start_x = model.calibration['controls'] final_s = model.calibration['states'] final_x = model.calibration['controls'] # if start_constraints: # # we ignore start_constraints # start_dict.update(start_constraints) # final_equilibrium = start_constraints.copy() # else: # final_eqm = find_deterministic_equilibrium(model, # constraints=final_dict) # final_s = final_eqm['states'] # final_x = final_eqm['controls'] # # start_s = start_states # start_x = final_x # TODO: for start_x, it should be possible to use first order guess final = np.concatenate([final_s, final_x]) start = np.concatenate([start_s, start_x]) if verbose is True: print("Initial states : {}".format(start_s)) print("Final controls : {}".format(final_x)) p = model.calibration['parameters'] if initial_guess is None: initial_guess = np.row_stack([start*(1-l) + final*l for l in linspace(0.0, 1.0, T+1)]) else: if isinstance(initial_guess, pd.DataFrame): initial_guess = np.array(initial_guess).T.copy() initial_guess = initial_guess[:, :n_s+n_x] initial_guess[0, :n_s] = start_s initial_guess[-1, n_s:] = final_x sh = initial_guess.shape if model.x_bounds and not ignore_constraints: initial_states = initial_guess[:, :n_s] [lb, ub] = [u(initial_states, p) for u in model.x_bounds] lower_bound = initial_guess*0 - np.inf lower_bound[:, n_s:] = lb upper_bound = initial_guess*0 + np.inf upper_bound[:, n_s:] = ub test1 = max(lb.max(axis=0) - lb.min(axis=0)) test2 = max(ub.max(axis=0) - ub.min(axis=0)) if test1 > 0.00000001 or test2 > 0.00000001: msg = "Not implemented: perfect foresight solution requires that " msg += "controls have constant bounds." raise Exception(msg) else: ignore_constraints = True lower_bound = None upper_bound = None nn = sh[0]*sh[1] def fobj(vec): o = det_residual(model, vec.reshape(sh), start_s, final_x, epsilons)[0] return o.ravel() if not ignore_constraints: def ff(vec): return det_residual(model, vec.reshape(sh), start_s, final_x, epsilons, jactype='sparse') x0 = initial_guess.ravel() sol, nit = ncpsolve(ff, lower_bound.ravel(), upper_bound.ravel(), initial_guess.ravel(), verbose=verbose, maxit=maxit, tol=tol, jactype='sparse') sol = sol.reshape(sh) else: def ff(vec): return det_residual(model, vec.reshape(sh), start_s, final_x, epsilons, diff=False).ravel() x0 = initial_guess.ravel() sol = root(ff, x0, jac=False) res = ff(sol.x) sol = sol.x.reshape(sh) if 'auxiliary' in model.functions: colnames = (model.symbols['states'] + model.symbols['controls'] + model.symbols['auxiliaries']) # compute auxiliaries y = model.functions['auxiliary'](sol[:, :n_s], sol[:, n_s:], p) sol = np.column_stack([sol, y]) else: colnames = model.symbols['states'] + model.symbols['controls'] sol = np.column_stack([sol, epsilons]) colnames = colnames + model.symbols['shocks'] ts = pd.DataFrame(sol, columns=colnames) return ts
def time_iteration( model: Model, *, # dr0: DecisionRule = None, # verbose: bool = True, # details: bool = True, # ignore_constraints: bool = False, # trace: bool = False, # dprocess=None, maxit=1000, inner_maxit=10, tol=1e-6, hook=None, interp_method="cubic", # obsolete with_complementarities=None, ) -> TimeIterationResult: """Finds a global solution for ``model`` using backward time-iteration. This algorithm iterates on the residuals of the arbitrage equations Parameters ---------- model : Model model to be solved verbose : bool if True, display iterations dr0 : decision rule initial guess for the decision rule with_complementarities : bool (True) if False, complementarity conditions are ignored maxit: maximum number of iterations inner_maxit: maximum number of iteration for inner solver tol: tolerance criterium for successive approximations hook: Callable function to be called within each iteration, useful for debugging purposes Returns ------- decision rule : approximated solution """ # deal with obsolete options if with_complementarities is not None: # TODO warn pass else: with_complementarities = not ignore_constraints if trace: trace_details = [] else: trace_details = None from dolo import dprint def vprint(t): if verbose: print(t) grid, dprocess_ = model.discretize() if dprocess is None: dprocess = dprocess_ n_ms = dprocess.n_nodes # number of exogenous states n_mv = dprocess.n_inodes( 0) # this assume number of integration nodes is constant x0 = model.calibration["controls"] parms = model.calibration["parameters"] n_x = len(x0) n_s = len(model.symbols["states"]) endo_grid = grid["endo"] exo_grid = grid["exo"] mdr = DecisionRule(exo_grid, endo_grid, dprocess=dprocess, interp_method=interp_method) s = mdr.endo_grid.nodes N = s.shape[0] controls_0 = numpy.zeros((n_ms, N, n_x)) if dr0 is None: controls_0[:, :, :] = x0[None, None, :] else: if isinstance(dr0, AlgoResult): dr0 = dr0.dr try: for i_m in range(n_ms): controls_0[i_m, :, :] = dr0(i_m, s) except Exception: for i_m in range(n_ms): m = dprocess.node(i_m) controls_0[i_m, :, :] = dr0(m, s) f = model.functions["arbitrage"] g = model.functions["transition"] if "arbitrage_lb" in model.functions and with_complementarities == True: lb_fun = model.functions["arbitrage_lb"] ub_fun = model.functions["arbitrage_ub"] lb = numpy.zeros_like(controls_0) * numpy.nan ub = numpy.zeros_like(controls_0) * numpy.nan for i_m in range(n_ms): m = dprocess.node(i_m)[None, :] p = parms[None, :] m = numpy.repeat(m, N, axis=0) p = numpy.repeat(p, N, axis=0) lb[i_m, :, :] = lb_fun(m, s, p) ub[i_m, :, :] = ub_fun(m, s, p) else: with_complementarities = False sh_c = controls_0.shape controls_0 = controls_0.reshape((-1, n_x)) from dolo.numeric.optimize.newton import newton, SerialDifferentiableFunction from dolo.numeric.optimize.ncpsolve import ncpsolve err = 10 it = 0 if with_complementarities: lb = lb.reshape((-1, n_x)) ub = ub.reshape((-1, n_x)) itprint = IterationsPrinter( ("N", int), ("Error", float), ("Gain", float), ("Time", float), ("nit", int), verbose=verbose, ) itprint.print_header("Start Time Iterations.") import time t1 = time.time() err_0 = numpy.nan verbit = verbose == "full" while err > tol and it < maxit: it += 1 t_start = time.time() mdr.set_values(controls_0.reshape(sh_c)) if trace: trace_details.append({"dr": copy.deepcopy(mdr)}) fn = lambda x: residuals_simple(f, g, s, x.reshape(sh_c), mdr, dprocess, parms).reshape((-1, n_x)) dfn = SerialDifferentiableFunction(fn) res = fn(controls_0) if hook: hook() if with_complementarities: [controls, nit] = ncpsolve(dfn, lb, ub, controls_0, verbose=verbit, maxit=inner_maxit) else: [controls, nit] = newton(dfn, controls_0, verbose=verbit, maxit=inner_maxit) err = abs(controls - controls_0).max() err_SA = err / err_0 err_0 = err controls_0 = controls t_finish = time.time() elapsed = t_finish - t_start itprint.print_iteration(N=it, Error=err_0, Gain=err_SA, Time=elapsed, nit=nit), controls_0 = controls.reshape(sh_c) mdr.set_values(controls_0) if trace: trace_details.append({"dr": copy.deepcopy(mdr)}) itprint.print_finished() if not details: return mdr return TimeIterationResult( mdr, it, with_complementarities, dprocess, err < tol, # x_converged: bool tol, # x_tol err, #: float None, # log: object # TimeIterationLog trace_details, # trace: object #{Nothing,IterationTrace} )
def time_iteration(model, initial_guess=None, dprocess=None, with_complementarities=True, verbose=True, grid={}, maxit=1000, inner_maxit=10, tol=1e-6, hook=None, details=False): ''' Finds a global solution for ``model`` using backward time-iteration. This algorithm iterates on the residuals of the arbitrage equations Parameters ---------- model : Model model to be solved verbose : boolean if True, display iterations initial_guess : decision rule initial guess for the decision rule dprocess : DiscretizedProcess (model.exogenous.discretize()) discretized process to be used with_complementarities : boolean (True) if False, complementarity conditions are ignored grid: grid options overload the values set in `options:grid` section maxit: maximum number of iterations inner_maxit: maximum number of iteration for inner solver tol: tolerance criterium for successive approximations hook: Callable function to be called within each iteration, useful for debugging purposes Returns ------- decision rule : approximated solution ''' from dolo import dprint def vprint(t): if verbose: print(t) if dprocess is None: dprocess = model.exogenous.discretize() n_ms = dprocess.n_nodes() # number of exogenous states n_mv = dprocess.n_inodes(0) # this assume number of integration nodes is constant x0 = model.calibration['controls'] parms = model.calibration['parameters'] n_x = len(x0) n_s = len(model.symbols['states']) endo_grid = model.get_grid(**grid) exo_grid = dprocess.grid mdr = DecisionRule(exo_grid, endo_grid) grid = mdr.endo_grid.nodes() N = grid.shape[0] controls_0 = numpy.zeros((n_ms, N, n_x)) if initial_guess is None: controls_0[:, :, :] = x0[None,None,:] else: if isinstance(initial_guess, AlgoResult): initial_guess = initial_guess.dr try: for i_m in range(n_ms): controls_0[i_m, :, :] = initial_guess(i_m, grid) except Exception: for i_m in range(n_ms): m = dprocess.node(i_m) controls_0[i_m, :, :] = initial_guess(m, grid) f = model.functions['arbitrage'] g = model.functions['transition'] if 'controls_lb' in model.functions and with_complementarities==True: lb_fun = model.functions['controls_lb'] ub_fun = model.functions['controls_ub'] lb = numpy.zeros_like(controls_0)*numpy.nan ub = numpy.zeros_like(controls_0)*numpy.nan for i_m in range(n_ms): m = dprocess.node(i_m)[None,:] p = parms[None,:] m = numpy.repeat(m, N, axis=0) p = numpy.repeat(p, N, axis=0) lb[i_m,:,:] = lb_fun(m, grid, p) ub[i_m,:,:] = ub_fun(m, grid, p) else: with_complementarities = False sh_c = controls_0.shape controls_0 = controls_0.reshape( (-1,n_x) ) from dolo.numeric.optimize.newton import newton, SerialDifferentiableFunction from dolo.numeric.optimize.ncpsolve import ncpsolve err = 10 it = 0 if with_complementarities: vprint("Solving WITH complementarities.") lb = lb.reshape((-1,n_x)) ub = ub.reshape((-1,n_x)) 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) import time t1 = time.time() err_0 = numpy.nan verbit = (verbose == 'full') while err>tol and it<maxit: it += 1 t_start = time.time() mdr.set_values(controls_0.reshape(sh_c)) fn = lambda x: residuals_simple(f, g, grid, x.reshape(sh_c), mdr, dprocess, parms).reshape((-1,n_x)) dfn = SerialDifferentiableFunction(fn) res = fn(controls_0) if hook: hook() if with_complementarities: [controls,nit] = ncpsolve(dfn, lb, ub, controls_0, verbose=verbit, maxit=inner_maxit) else: [controls, nit] = newton(dfn, controls_0, verbose=verbit, maxit=inner_maxit) err = abs(controls-controls_0).max() err_SA = err/err_0 err_0 = err controls_0 = controls 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 )) controls_0 = controls.reshape(sh_c) t2 = time.time() if verbose: print(stars) print("Elapsed: {} seconds.".format(t2-t1)) print(stars) if not details: return mdr return TimeIterationResult( mdr, it, with_complementarities, dprocess, err<tol, # x_converged: bool tol, # x_tol err, #: float None, # log: object # TimeIterationLog None # trace: object #{Nothing,IterationTrace} )