def ncpsolve(f, a, b, x, tol=1e-8, maxit=100, infos=False, verbose=False, jactype="serial"): def fcmp(z): [val, dval] = f(z) # revert convention val = -val dval = -dval [val, dval] = smooth(z, a, b, val, dval, jactype=jactype) return [val, dval] [sol, nit] = newton(fcmp, x, tol=tol, maxit=maxit, verbose=verbose, jactype=jactype) return [sol, nit]
def ncpsolve(f, a, b, x, tol=1e-8, maxit=100, infos=False, verbose=False, jactype='serial'): def fcmp(z): [val, dval] = f(z) [val, dval] = smooth(z, a, b, val, dval, jactype=jactype) return [val, dval] [sol, nit] = newton(fcmp, x, tol=tol, maxit=maxit, verbose=verbose, jactype=jactype) return [sol, nit]
def time_iteration(model, dr0=None, dprocess=None, with_complementarities=True, verbose=True, grid={}, maxit=1000, inner_maxit=10, tol=1e-6, hook=None, details=False, interp_method='cubic'): ''' 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 dr0 : 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_endo_grid(**grid) exo_grid = dprocess.grid mdr = DecisionRule(exo_grid, endo_grid, dprocess=dprocess, interp_method=interp_method) grid = mdr.endo_grid.nodes N = grid.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, grid) except Exception: for i_m in range(n_ms): m = dprocess.node(i_m) controls_0[i_m, :, :] = dr0(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: 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) mdr.set_values(controls_0) 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} )
def deterministic_solve( model, exogenous=None, s0=None, m0=None, T=100, ignore_constraints=False, maxit=100, initial_guess=None, verbose=True, solver="ncpsolve", keep_steady_state=False, s1=None, # deprecated shocks=None, # deprecated tol=1e-6, ): """ Computes a perfect foresight simulation using a stacked-time algorithm. Typical simulation exercises are: - start from an out-of-equilibrium exogenous and/or endogenous state: specify `s0` and or `m0`. Missing values are taken from the calibration (`model.calibration`). - specify an exogenous path for shocks `exogenous`. Initial exogenous state `m0` is then first value of exogenous values. Economy is supposed to have been at the equilibrium for $t<0$, which pins down initial endogenous state `s0`. `x0` is a jump variable. If $s0$ is not specified it is then set equal to the steady-state consistent with the first value 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 : Model Model to be solved exogenous : array-like, dict, or pandas.DataFrame A specification for the path of exogenous variables (aka shocks). Can be any of the following (note by "declaration order" below we mean the order of `model.symbols["exogenous"]`): - A 1d numpy array-like specifying a time series for a single exogenous variable, or all exogenous variables 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["exogenous"]` and values are a time series of values for that shock. For exogenous variables 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, `exogenous` is set equal to the calibrated values found in `model.calibration["exogenous"]` 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 simulation. s0 : None or ndarray or dict If vector with the value of initial states If an exogenous timeseries is given for exogenous shocks, `s0` will be computed as the steady-state value that is consistent with its first value. 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. keep_steady_state : bool if True, initial steady-states and steady-controls are appended to the simulation with date -1. Returns ------- pandas dataframe a dataframe with T+1 observations of the model variables along the simulation (states, controls, auxiliaries). The simulation should return to a steady-state consistent with the last specified value of the exogenous shocks. """ if shocks is not None: import warnings warnings.warn( "`shocks` argument is deprecated. Use `exogenous` instead.") exogenous = shocks if s1 is not None: import warnings warnings.warn("`s1` argument is deprecated. Use `s0` instead.") s0 = s1 # definitions n_s = len(model.calibration["states"]) n_x = len(model.calibration["controls"]) p = model.calibration["parameters"] if exogenous is not None: epsilons = _shocks_to_epsilons(model, exogenous, T) m0 = epsilons[0, :] # get initial steady-state from dolo.algos.steady_state import find_steady_state start_state = find_steady_state(model, m=m0) s0 = start_state["states"] x0 = start_state["controls"] m1 = epsilons[1, :] s1 = model.functions["transition"](m0, s0, x0, m1, p) else: if s0 is None: s0 = model.calibration["states"] if m0 is None: m0 = model.calibration["exogenous"] # if m0 is None: # m0 = np.zeros(len(model.symbols['exogenous'])) # we should probably do something here with the nature of the exogenous process if specified # i.e. compute nonlinear irf epsilons = _shocks_to_epsilons(model, exogenous, T) x0 = model.calibration["controls"] m1 = epsilons[1, :] s1 = model.functions["transition"](m0, s0, x0, m1, p) s1 = np.array(s1) x1_g = model.calibration["controls"] # we can do better here sT_g = model.calibration["states"] # we can do better here xT_g = model.calibration["controls"] # we can do better here if initial_guess is None: start = np.concatenate([s1, x1_g]) final = np.concatenate([sT_g, xT_g]) 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[model.symbols["states"] + model.symbols["controls"]]) initial_guess = initial_guess[1:, :] initial_guess = initial_guess[:, :n_s + n_x] sh = initial_guess.shape if model.x_bounds and not ignore_constraints: initial_states = initial_guess[:, :n_s] [lb, ub] = [u(epsilons[:, :], 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 print(initial_guess.shape) print(epsilons.shape) det_residual(model, initial_guess, s1, xT_g, epsilons) if not ignore_constraints: def ff(vec): return det_residual(model, vec.reshape(sh), s1, xT_g, epsilons, jactype="sparse") v0 = initial_guess.ravel() if solver == "ncpsolve": sol, nit = ncpsolve( ff, lower_bound.ravel(), upper_bound.ravel(), initial_guess.ravel(), verbose=verbose, maxit=maxit, tol=tol, jactype="sparse", ) else: from dolo.numeric.extern.lmmcp import lmmcp sol = lmmcp( lambda u: ff(u)[0], lambda u: ff(u)[1].todense(), lower_bound.ravel(), upper_bound.ravel(), initial_guess.ravel(), verbose=verbose, ) nit = -1 sol = sol.reshape(sh) else: def ff(vec): ll = det_residual(model, vec.reshape(sh), s1, xT_g, epsilons, diff=True) return ll v0 = initial_guess.ravel() # from scipy.optimize import root # sol = root(ff, v0, jac=True) # sol = sol.x.reshape(sh) from dolo.numeric.optimize.newton import newton sol, nit = newton(ff, v0, jactype="sparse") sol = sol.reshape(sh) # sol = sol[:-1, :] if (exogenous is not None) and keep_steady_state: sx = np.concatenate([s0, x0]) sol = np.concatenate([sx[None, :], sol], axis=0) epsilons = np.concatenate([epsilons[:1:], epsilons], axis=0) index = range(-1, T + 1) else: index = range(0, T + 1) # epsilons = np.concatenate([epsilons[:1,:], epsilons], axis=0) if "auxiliary" in model.functions: colnames = (model.symbols["states"] + model.symbols["controls"] + model.symbols["auxiliaries"]) # compute auxiliaries y = model.functions["auxiliary"](epsilons, 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["exogenous"] ts = pd.DataFrame(sol, columns=colnames, index=index) return ts
def deterministic_solve(model, shocks=None, s1=None, T=100, ignore_constraints=False, maxit=100, initial_guess=None, verbose=True, solver='ncpsolve', 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 : Model 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. s1 : ndarray or dict a vector with the value of initial states 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. """ # definitions n_s = len(model.calibration['states']) n_x = len(model.calibration['controls']) p = model.calibration['parameters'] epsilons = _shocks_to_epsilons(model, shocks, T) m0 = epsilons[0, :] # get initial steady-state from dolo.algos.steady_state import find_steady_state # TODO: use initial_guess for steady_state # TODO: if s1 is None: start_state = find_steady_state(model, m=m0) s0 = start_state['states'] x0 = start_state['controls'] m1 = epsilons[1, :] s1 = model.functions['transition'](m0, s0, x0, m1, p) else: s0 = model.calibration['states'] * np.nan x0 = model.calibration['controls'] * np.nan s1 = np.array(s1) x1_g = model.calibration['controls'] # we can do better here sT_g = model.calibration['states'] # we can do better here xT_g = model.calibration['controls'] # we can do better here if initial_guess is None: start = np.concatenate([s1, x1_g]) final = np.concatenate([sT_g, xT_g]) initial_guess = np.row_stack( [start * (1 - l) + final * l for l in linspace(0.0, 1.0, T)]) else: if isinstance(initial_guess, pd.DataFrame): initial_guess = np.array(initial_guess[model.symbols['states'] + model.symbols['controls']]) initial_guess = initial_guess[1:, :] initial_guess = initial_guess[:, :n_s + n_x] sh = initial_guess.shape if model.x_bounds and not ignore_constraints: initial_states = initial_guess[:, :n_s] [lb, ub] = [u(epsilons[1:, :], 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 if not ignore_constraints: def ff(vec): return det_residual(model, vec.reshape(sh), s1, xT_g, epsilons[1:, :], jactype='sparse') v0 = initial_guess.ravel() if solver == 'ncpsolve': sol, nit = ncpsolve(ff, lower_bound.ravel(), upper_bound.ravel(), initial_guess.ravel(), verbose=verbose, maxit=maxit, tol=tol, jactype='sparse') else: from dolo.numeric.extern.lmmcp import lmmcp sol = lmmcp(lambda u: ff(u)[0], lambda u: ff(u)[1].todense(), lower_bound.ravel(), upper_bound.ravel(), initial_guess.ravel(), verbose=verbose) nit = -1 sol = sol.reshape(sh) else: def ff(vec): ll = det_residual(model, vec.reshape(sh), s1, xT_g, epsilons[1:, :], diff=True) return (ll) v0 = initial_guess.ravel() # from scipy.optimize import root # sol = root(ff, v0, jac=True) # sol = sol.x.reshape(sh) from dolo.numeric.optimize.newton import newton sol, nit = newton(ff, v0, jactype='sparse') sol = sol.reshape(sh) sx = np.concatenate([s0, x0]) # sol = sol[:-1, :] sol = np.concatenate([sx[None, :], sol], axis=0) # epsilons = np.concatenate([epsilons[:1,:], epsilons], axis=0) if 'auxiliary' in model.functions: colnames = (model.symbols['states'] + model.symbols['controls'] + model.symbols['auxiliaries']) # compute auxiliaries y = model.functions['auxiliary'](epsilons, 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['exogenous'] ts = pd.DataFrame(sol, columns=colnames) return ts
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, initial_guess=None, with_complementarities=True, verbose=True, grid={}, maxit=1000, inner_maxit=10, tol=1e-6, 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 "dtmscc" model to be solved verbose : boolean if True, display iterations initial_dr : decision rule initial guess for the decision rule with_complementarities : boolean (True) if False, complementarity conditions are ignored grid: grid 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 ''' from dolo import dprint def vprint(t): if verbose: print(t) process = model.exogenous dprocess = process.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) interp_type = 'cubic' 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: for i_m in range(n_ms): controls_0[i_m, :, :] = initial_guess(i_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) return mdr
def time_iteration(model, initial_guess=None, with_complementarities=True, verbose=True, orders=None, output_type='dr', maxit=1000, inner_maxit=10, tol=1e-6, hook=None): assert (model.model_type == 'dtmscc') def vprint(t): if verbose: print(t) [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) 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 = 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 # 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 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(f, g, grid, x.reshape(sh_c), mdr, P, Q, parms ).reshape((-1, n_x)) dfn = SerialDifferentiableFunction(fn) 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 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, initial_guess=None, with_complementarities=True, verbose=True, grid={}, output_type='dr', maxit=1000, inner_maxit=10, tol=1e-6, 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 "dtmscc" model to be solved verbose : boolean if True, display iterations initial_dr : decision rule initial guess for the decision rule with_complementarities : boolean (True) if False, complementarity conditions are ignored grid: grid 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 ''' assert (model.model_type == 'dtmscc') def vprint(t): if verbose: print(t) [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.get_grid(**grid) a = approx.a b = approx.b orders = approx.orders interp_type = approx.interpolation # unused from dolo.numeric.decision_rules_markov import MarkovDecisionRule mdr = MarkovDecisionRule(n_ms, a, b, orders) grid = mdr.grid N = grid.shape[0] 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) 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 = 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 # 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 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(f, g, grid, x.reshape(sh_c), mdr, P, Q, parms ).reshape((-1, n_x)) dfn = SerialDifferentiableFunction(fn) 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 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: 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} )