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_type == 'fga': # model = GModel_fg_from_fga(model) # g = model.functions['transition'] # f = model.functions['arbitrage'] from dolo.algos.convert import get_fg_functions [f,g] = get_fg_functions(model) if steady_state is not None: calib = steady_state else: calib = model.calibration if solve_steady_state: from dolo.algos.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) # 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) 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) 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 perturbate(model, order=1, return_dr=True, steady_state=None, verbose=True): from dolo.numeric.processes import IIDProcess # here we should check that exogenous don't appear with time t-1 in transition # and with time t+1 in arbitrage. assert isinstance(model.exogenous, IIDProcess) import numpy if steady_state is None: calibration = model.calibration else: calibration = steady_state [f, g] = get_model_derivatives(model, order=order, calibration=calibration) sigma = model.exogenous.Sigma problem = PerturbationProblem(f, g, sigma) print(len(problem.f)) pert_sol = state_perturb(problem, verbose=verbose) controls_ss = calibration['controls'] states_ss = calibration['states'] n_s = len(model.symbols['states']) n_c = len(model.symbols['controls']) if order == 1: if return_dr: S_bar = numpy.array(states_ss) X_bar = numpy.array(controls_ss) # add transitions of states to the d.r. X_s = pert_sol[0] A = g[1][:, :n_s] + numpy.dot(g[1][:, n_s:n_s + n_c], X_s) B = g[1][:, n_s + n_c:] dr = CDR(S_bar, X_bar, X_s) dr.A = A dr.B = B dr.sigma = sigma return dr return [controls_ss] + pert_sol if order == 2: [[X_s, X_ss], [X_tt]] = pert_sol X_bar = controls_ss + X_tt / 2 if return_dr: S_bar = states_ss S_bar = numpy.array(S_bar) X_bar = numpy.array(X_bar) dr = CDR(S_bar, X_bar, X_s, X_ss) A = g[1][:, :n_s] + numpy.dot(g[1][:, n_s:n_s + n_c], X_s) B = g[1][:, n_s + n_c:] dr.sigma = sigma dr.A = A dr.B = B return dr return [X_bar, X_s, X_ss] if order == 3: [[X_s, X_ss, X_sss], [X_tt, X_stt]] = pert_sol X_bar = controls_ss + X_tt / 2 X_s = X_s + X_stt / 2 if return_dr: S_bar = states_ss dr = CDR(S_bar, X_bar, X_s, X_ss, X_sss) dr.sigma = sigma return dr return [X_bar, X_s, X_ss, X_sss]
def perturb(model, order=1, return_dr=True, steady_state=None, verbose=True): from dolo.numeric.processes import IIDProcess # here we should check that exogenous don't appear with time t-1 in transition # and with time t+1 in arbitrage. assert isinstance(model.exogenous, IIDProcess) import numpy if steady_state is None: calibration = model.calibration else: calibration = steady_state [f, g] = get_model_derivatives(model, order=order, calibration=calibration) sigma = model.exogenous.Sigma problem = PerturbationProblem(f,g,sigma) print(len(problem.f)) pert_sol = state_perturb(problem, verbose=verbose) controls_ss = calibration['controls'] states_ss = calibration['states'] n_s = len(model.symbols['states']) n_c = len(model.symbols['controls']) if order == 1: if return_dr: S_bar = numpy.array(states_ss) X_bar = numpy.array(controls_ss) # add transitions of states to the d.r. X_s = pert_sol[0] A = g[1][:, :n_s] + numpy.dot(g[1][:, n_s:n_s+n_c], X_s) B = g[1][:, n_s+n_c:] dr = CDR(S_bar, X_bar, X_s) dr.A = A dr.B = B dr.sigma = sigma return dr return [controls_ss] + pert_sol if order == 2: [[X_s, X_ss], [X_tt]] = pert_sol X_bar = controls_ss + X_tt/2 if return_dr: S_bar = states_ss S_bar = numpy.array(S_bar) X_bar = numpy.array(X_bar) dr = CDR(S_bar, X_bar, X_s, X_ss) A = g[1][:, :n_s] + numpy.dot(g[1][:, n_s:n_s+n_c], X_s) B = g[1][:, n_s+n_c:] dr.sigma = sigma dr.A = A dr.B = B return dr return [X_bar, X_s, X_ss] if order == 3: [[X_s, X_ss, X_sss], [X_tt, X_stt]] = pert_sol X_bar = controls_ss + X_tt/2 X_s = X_s + X_stt/2 if return_dr: S_bar = states_ss dr = CDR(S_bar, X_bar, X_s, X_ss, X_sss) dr.sigma = sigma return dr return [X_bar, X_s, X_ss, X_sss]