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
e_z = atleast_2d( linspace(0.0, 0.0, 10) ).T start_s = model.calibration['states'].copy() start_s[0] = 1.5 import time #sol1 = deterministic_solve(model, shocks=e_z, T=50, use_pandas=True, ignore_constraints=True, start_s=start_s) #sol1 = deterministic_solve(model, T=50, use_pandas=True, ignore_constraints=True, start_s=start_s) from dolo.algos.steady_state import find_deterministic_equilibrium calib = find_deterministic_equilibrium(model) t2 = time.time() sol1 = deterministic_solve(model, start_states=start_s, T=50, use_pandas=True, ignore_constraints=False, verbose=True) t3 = time.time() t1 = time.time() sol2 = deterministic_solve(model, start_states=start_s, T=50, use_pandas=True, ignore_constraints=True, verbose=True) t2 = time.time()
def approximate_controls(model, verbose=False, steady_state=None, eigmax=1.0, solve_steady_state=False, order=1): """Compute first order approximation of optimal controls Parameters: ----------- model: NumericModel Model to be solved verbose: boolean If True: displays number of contracting eigenvalues steady_state: ndarray Use supplied steady-state value to compute the approximation. The routine doesn't check whether it is really a solution or not. solve_steady_state: boolean Use nonlinear solver to find the steady-state orders: {1} Approximation order. (Currently, only first order is supported). Returns: -------- TaylorExpansion: Decision Rule for the optimal controls around the steady-state. """ if order > 1: raise Exception("Not implemented.") # get steady_state import numpy # if model.model_spec == 'fga': # model = GModel_fg_from_fga(model) # g = model.functions['transition'] # f = model.functions['arbitrage'] from dolo.algos.dtcscc.convert import get_fg_functions f = model.functions["arbitrage"] g = model.functions["transition"] if steady_state is not None: calib = steady_state else: calib = model.calibration if solve_steady_state: from dolo.algos.dtcscc.steady_state import find_deterministic_equilibrium calib = find_deterministic_equilibrium(model) p = calib["parameters"] s = calib["states"] x = calib["controls"] e = calib["shocks"] if model.covariances is not None: sigma = model.covariances else: sigma = numpy.zeros((len(e), len(e))) from numpy.linalg import solve l = g(s, x, e, p, diff=True) [junk, g_s, g_x, g_e] = l[:4] # [el[0,...] for el in l[:4]] l = f(s, x, e, s, x, p, diff=True) [res, f_s, f_x, f_e, f_S, f_X] = l # [el[0,...] for el in l[:6]] n_s = g_s.shape[0] # number of controls n_x = g_x.shape[1] # number of states n_e = g_e.shape[1] n_v = n_s + n_x A = row_stack([column_stack([eye(n_s), zeros((n_s, n_x))]), column_stack([-f_S, -f_X])]) B = row_stack([column_stack([g_s, g_x]), column_stack([f_s, f_x])]) from dolo.numeric.extern.qz import qzordered [S, T, Q, Z, eigval] = qzordered(A, B, n_s) Q = Q.real # is it really necessary ? Z = Z.real diag_S = numpy.diag(S) diag_T = numpy.diag(T) tol_geneigvals = 1e-10 try: assert sum((abs(diag_S) < tol_geneigvals) * (abs(diag_T) < tol_geneigvals)) == 0 except Exception as e: print(e) # print(numpy.column_stack([diag_S, diag_T])) raise GeneralizedEigenvaluesError(diag_S, diag_T) # Check Blanchard=Kahn conditions n_big_one = sum(eigval > eigmax) n_expected = n_x if verbose: print("There are {} eigenvalues greater than {}. Expected: {}.".format(n_big_one, eigmax, n_x)) if n_expected != n_big_one: raise BlanchardKahnError(n_big_one, n_expected) Z11 = Z[:n_s, :n_s] Z12 = Z[:n_s, n_s:] Z21 = Z[n_s:, :n_s] Z22 = Z[n_s:, n_s:] S11 = S[:n_s, :n_s] T11 = T[:n_s, :n_s] # first order solution C = solve(Z11.T, Z21.T).T P = np.dot(solve(S11.T, Z11.T).T, solve(Z11.T, T11.T).T) Q = g_e s = s.ravel() x = x.ravel() A = g_s + dot(g_x, C) B = g_e dr = CDR([s, x, C]) dr.A = A dr.B = B dr.sigma = sigma return dr
def approximate_controls(model, verbose=False, steady_state=None, eigmax=1.0-1e-6, solve_steady_state=False, order=1): """Compute first order approximation of optimal controls Parameters: ----------- model: NumericModel Model to be solved verbose: boolean If True: displays number of contracting eigenvalues steady_state: ndarray Use supplied steady-state value to compute the approximation. The routine doesn't check whether it is really a solution or not. solve_steady_state: boolean Use nonlinear solver to find the steady-state orders: {1} Approximation order. (Currently, only first order is supported). Returns: -------- TaylorExpansion: Decision Rule for the optimal controls around the steady-state. """ if order > 1: raise Exception("Not implemented.") f = model.functions['arbitrage'] g = model.functions['transition'] if steady_state is not None: calib = steady_state else: calib = model.calibration if solve_steady_state: calib = find_deterministic_equilibrium(model) p = calib['parameters'] s = calib['states'] x = calib['controls'] e = calib['shocks'] distrib = model.get_distribution() sigma = distrib.sigma l = g(s, x, e, p, diff=True) [junk, g_s, g_x, g_e] = l[:4] # [el[0,...] for el in l[:4]] l = f(s, x, e, s, x, p, diff=True) [res, f_s, f_x, f_e, f_S, f_X] = l # [el[0,...] for el in l[:6]] n_s = g_s.shape[0] # number of controls n_x = g_x.shape[1] # number of states n_e = g_e.shape[1] n_v = n_s + n_x A = row_stack([ column_stack([eye(n_s), zeros((n_s, n_x))]), column_stack([-f_S , -f_X ]) ]) B = row_stack([ column_stack([g_s, g_x]), column_stack([f_s, f_x]) ]) [S, T, Q, Z, eigval] = qzordered(A, B, 1.0-1e-8) Q = Q.real # is it really necessary ? Z = Z.real diag_S = np.diag(S) diag_T = np.diag(T) tol_geneigvals = 1e-10 try: ok = sum((abs(diag_S) < tol_geneigvals) * (abs(diag_T) < tol_geneigvals)) == 0 assert(ok) except Exception as e: raise GeneralizedEigenvaluesError(diag_S=diag_S, diag_T=diag_T) if max(eigval[:n_s]) >= 1 and min(eigval[n_s:]) < 1: # BK conditions are met pass else: eigval_s = sorted(eigval, reverse=True) ev_a = eigval_s[n_s-1] ev_b = eigval_s[n_s] cutoff = (ev_a - ev_b)/2 if not ev_a > ev_b: raise GeneralizedEigenvaluesSelectionError( A=A, B=B, eigval=eigval, cutoff=cutoff, diag_S=diag_S, diag_T=diag_T, n_states=n_s ) import warnings if cutoff > 1: warnings.warn("Solution is not convergent.") else: warnings.warn("There are multiple convergent solutions. The one with the smaller eigenvalues was selected.") [S, T, Q, Z, eigval] = qzordered(A, B, cutoff) Z11 = Z[:n_s, :n_s] # Z12 = Z[:n_s, n_s:] Z21 = Z[n_s:, :n_s] # Z22 = Z[n_s:, n_s:] # S11 = S[:n_s, :n_s] # T11 = T[:n_s, :n_s] # first order solution # P = (solve(S11.T, Z11.T).T @ solve(Z11.T, T11.T).T) C = solve(Z11.T, Z21.T).T Q = g_e s = s.ravel() x = x.ravel() A = g_s + g_x @ C B = g_e dr = CDR([s, x, C]) dr.A = A dr.B = B dr.sigma = sigma return dr
def approximate_controls(model, verbose=False, steady_state=None, eigmax=1.0 - 1e-6, solve_steady_state=False, order=1): """Compute first order approximation of optimal controls Parameters: ----------- model: NumericModel Model to be solved verbose: boolean If True: displays number of contracting eigenvalues steady_state: ndarray Use supplied steady-state value to compute the approximation. The routine doesn't check whether it is really a solution or not. solve_steady_state: boolean Use nonlinear solver to find the steady-state orders: {1} Approximation order. (Currently, only first order is supported). Returns: -------- TaylorExpansion: Decision Rule for the optimal controls around the steady-state. """ if order > 1: raise Exception("Not implemented.") f = model.functions['arbitrage'] g = model.functions['transition'] if steady_state is not None: calib = steady_state else: calib = model.calibration if solve_steady_state: calib = find_deterministic_equilibrium(model) p = calib['parameters'] s = calib['states'] x = calib['controls'] e = calib['shocks'] distrib = model.get_distribution() sigma = distrib.sigma l = g(s, x, e, p, diff=True) [junk, g_s, g_x, g_e] = l[:4] # [el[0,...] for el in l[:4]] l = f(s, x, e, s, x, p, diff=True) [res, f_s, f_x, f_e, f_S, f_X] = l # [el[0,...] for el in l[:6]] n_s = g_s.shape[0] # number of controls n_x = g_x.shape[1] # number of states n_e = g_e.shape[1] n_v = n_s + n_x A = row_stack([ column_stack([eye(n_s), zeros((n_s, n_x))]), column_stack([-f_S, -f_X]) ]) B = row_stack([column_stack([g_s, g_x]), column_stack([f_s, f_x])]) [S, T, Q, Z, eigval] = qzordered(A, B, 1.0 - 1e-8) Q = Q.real # is it really necessary ? Z = Z.real diag_S = np.diag(S) diag_T = np.diag(T) tol_geneigvals = 1e-10 try: ok = sum((abs(diag_S) < tol_geneigvals) * (abs(diag_T) < tol_geneigvals)) == 0 assert (ok) except Exception as e: raise GeneralizedEigenvaluesError(diag_S=diag_S, diag_T=diag_T) if max(eigval[:n_s]) >= 1 and min(eigval[n_s:]) < 1: # BK conditions are met pass else: eigval_s = sorted(eigval, reverse=True) ev_a = eigval_s[n_s - 1] ev_b = eigval_s[n_s] cutoff = (ev_a - ev_b) / 2 if not ev_a > ev_b: raise GeneralizedEigenvaluesSelectionError(A=A, B=B, eigval=eigval, cutoff=cutoff, diag_S=diag_S, diag_T=diag_T, n_states=n_s) import warnings if cutoff > 1: warnings.warn("Solution is not convergent.") else: warnings.warn( "There are multiple convergent solutions. The one with the smaller eigenvalues was selected." ) [S, T, Q, Z, eigval] = qzordered(A, B, cutoff) Z11 = Z[:n_s, :n_s] # Z12 = Z[:n_s, n_s:] Z21 = Z[n_s:, :n_s] # Z22 = Z[n_s:, n_s:] # S11 = S[:n_s, :n_s] # T11 = T[:n_s, :n_s] # first order solution # P = (solve(S11.T, Z11.T).T @ solve(Z11.T, T11.T).T) C = solve(Z11.T, Z21.T).T Q = g_e s = s.ravel() x = x.ravel() A = g_s + g_x @ C B = g_e dr = CDR([s, x, C]) dr.A = A dr.B = B dr.sigma = sigma return dr
def approximate_controls(model, verbose=False, steady_state=None, eigmax=1.0, solve_steady_state=False, order=1): """Compute first order approximation of optimal controls Parameters: ----------- model: NumericModel Model to be solved verbose: boolean If True: displays number of contracting eigenvalues steady_state: ndarray Use supplied steady-state value to compute the approximation. The routine doesn't check whether it is really a solution or not. solve_steady_state: boolean Use nonlinear solver to find the steady-state orders: {1} Approximation order. (Currently, only first order is supported). Returns: -------- TaylorExpansion: Decision Rule for the optimal controls around the steady-state. """ if order > 1: raise Exception("Not implemented.") # get steady_state # if model.model_spec == 'fga': # model = GModel_fg_from_fga(model) f = model.functions['arbitrage'] g = model.functions['transition'] if steady_state is not None: calib = steady_state else: calib = model.calibration if solve_steady_state: calib = find_deterministic_equilibrium(model) p = calib['parameters'] s = calib['states'] x = calib['controls'] e = calib['shocks'] if model.covariances is not None: sigma = model.covariances else: sigma = zeros((len(e), len(e))) l = g(s, x, e, p, diff=True) [junk, g_s, g_x, g_e] = l[:4] # [el[0,...] for el in l[:4]] l = f(s, x, e, s, x, p, diff=True) [res, f_s, f_x, f_e, f_S, f_X] = l # [el[0,...] for el in l[:6]] n_s = g_s.shape[0] # number of controls n_x = g_x.shape[1] # number of states n_e = g_e.shape[1] n_v = n_s + n_x A = row_stack([ column_stack([eye(n_s), zeros((n_s, n_x))]), column_stack([-f_S, -f_X]) ]) B = row_stack([column_stack([g_s, g_x]), column_stack([f_s, f_x])]) [S, T, Q, Z, eigval] = qzordered(A, B, n_s) Q = Q.real # is it really necessary ? Z = Z.real diag_S = np.diag(S) diag_T = np.diag(T) tol_geneigvals = 1e-10 try: ok = sum((abs(diag_S) < tol_geneigvals) * (abs(diag_T) < tol_geneigvals)) == 0 assert (ok) except Exception as e: print(e) # print(np.column_stack([diag_S, diag_T])) raise GeneralizedEigenvaluesError(diag_S, diag_T) # Check Blanchard=Kahn conditions n_big_one = sum(eigval > eigmax) n_expected = n_x if verbose: msg = "There are {} eigenvalues greater than {}. Expected: {}." print(msg.format(n_big_one, eigmax, n_x)) if n_expected != n_big_one: raise BlanchardKahnError(n_big_one, n_expected, eigval=eigval, eigmax=eigmax) Z11 = Z[:n_s, :n_s] Z12 = Z[:n_s, n_s:] Z21 = Z[n_s:, :n_s] Z22 = Z[n_s:, n_s:] S11 = S[:n_s, :n_s] T11 = T[:n_s, :n_s] # first order solution C = solve(Z11.T, Z21.T).T P = dot(solve(S11.T, Z11.T).T, solve(Z11.T, T11.T).T) Q = g_e s = s.ravel() x = x.ravel() A = g_s + dot(g_x, C) B = g_e dr = CDR([s, x, C]) dr.A = A dr.B = B dr.sigma = sigma return dr