Source code for snowdrop.src.model.interface

import numpy as np
from snowdrop.src.misc.termcolor import colored

[docs] class Interface: def __init__(self,model_name,symbols,equations,ss_equations,calibration,exog_data=None,ss=None,order=1, constraints=None,objective_function=None,eq_vars=[],steady_state=None, measurement_equations=None,bellman=None,terminal_values=None,domain=None, exogenous=None,options=None,data_sources=None,measurement_file_path=None, definitions=None,priors=None,bSparse=False): """ Constructor that initializes Iterface object. Parameters: :param self: Parameter. :type self: Model. :param model_name: Name of model. :type model_name: str. :param symbols: List of symbols. :type symbols: list. :param equations: List of equations. :type equations: list. :param ss_equations: List of steady state equations. Those are obtained by dropping time index from original equations. :type ss_equations: list. :param calibration: Calibration dict. :type calibration: dict. :param exog_data: Exogenous time series. :type exog_data: dict. :param ss: Map with variables names as a key and steady states as values. :type ss: dict. :param order: Approximation order of solution of the non-linear system of equations. :type order: int. :param constraints: Constraints of variables. :type constraints: list. :param objective_function: Objective function. :type objective_function: str. :param eq_vars: List of variables in each equation. :type eq_vars: list. :param measurement_equations:List of measurement equations. :type measurement_equations: list. :param bellman: Bellman equation. :type bellman: list. :param terminal_values: List of terminal values. :type terminal_values: list. :param domain: The domain of endogenous variables. :type domain: dict. :param exogenous: List of exogenous variables. :type exogenous: list. :param options: Model options. :type options: dict. :param measurement_file_path: Path to a file with measurement data. :type measurement_file_path: str. :param definitions: Model definitions. :type definitions: dict. :param priors: Prior distribution and parameters values. :type priors: dict. :param bSparse: Use sparse matrix algebra. :type bSparse: bool. :returns: Instance of SymbolicModel class. """ self.name = model_name self.steady_state = steady_state self.ss = ss # reorder symbols from collections import OrderedDict canonical_order = ['variables', 'original_variables', 'new_variables', 'measurement_variables', 'exogenous', 'states', 'controls', 'values', 'steady-state', 'shocks', 'measurement_shocks', 'parameters'] osyms = OrderedDict() for vg in canonical_order: if vg in symbols: osyms[vg] = symbols[vg] for vg in symbols: if vg not in canonical_order: osyms[vg] = symbols[vg] self.order = order self.symbols = osyms self.eq_vars = eq_vars self.equations = equations self.ss_equations = ss_equations self.measurement_equations = measurement_equations self.bellman = bellman self.calibration_dict = calibration self.bSparse = bSparse self.domain = domain self.exogenous = exogenous self.options = options self.data_sources = data_sources self.definitions = definitions self.terminal_values = terminal_values self.priors = priors self.measurement_file_path = measurement_file_path self.exog_data = exog_data self.constraints = constraints self.objective_function = objective_function self.SOLVER = None self.labels = None self.eqLabels = None self.state_vars = None self.eqs_number = None self.numberOfNewEqs = 0 self.COMPLEMENTARITY_CONDITIONS = None # Use auto-differentiation autograd/jax package instead of symbolic differentiation with sympy package self.autodiff = False self.jaxdiff = False # Correct state equations if variable was assigned to fixed value: if not ss is None: for i,eq in enumerate(equations): if eq in ss: k,v = ss[eq] self.ss_equations[i] = f"{k}={v}" # def eval_formula(self, expr, dataframe=None, calib=None): # """Evaluate formula.""" # from snowdrop.src.snowdrop.src.preprocessor.eval_formula import eval_formula as evaluate # if calib is None: # calib = self.calibration_dict # return evaluate(expr,dataframe=dataframe,context=calib) # def get_exogenous(self, **opts): # """ # Return exogenous process object. # Parameters: # :param self: Model object. # :type self: 'SymbolicModel' # :param opts: Keyword arguments . # :type opts: Dictionary. # :returns: Exogenous process object. # """ # from snowdrop.src.preprocessor.processes import IIDProcess # import copy # gg = self.exogenous # if gg is None: # raise Exception("Model has no exogenous process.") # d = copy.deepcopy(gg) # d.update(opts) # if 'type' in d: d.pop('type') # obj = d.eval(self.calibration_dict.flat) # if not isinstance(obj, IIDProcess): # raise Exception("Exogenous shocks don't follow an IID process.") # else: # return obj
[docs] def get_exogenous(self): """Exogenous process assumption.""" from snowdrop.src.preprocessor.language import Normal,MvNormal,LogNormal,Beta,Binomial,Gamma,Logistic,Uniform exo = self.data.get("exogenous", {}) calibration = self.get_calibration() type = get_type(exo) if type == "Normal": exog = Normal(**exo) elif type == "MvNormal": exog = MvNormal(**exo) elif type == "LogNormal": exog = LogNormal(**exo) elif type == "Beta": exog = Beta(**exo) elif type == "Binomial": exog = Binomial(**exo) elif type == "Gamma": exog = Gamma(**exo) elif type == "Logistic": exog = Logistic(**exo) elif type == "Uniform": exog = Uniform(**exo) else: raise Exception("Unknown exogenous type {}.".format(type)) d = exog.eval(d=calibration) return d
[docs] def get_distribution(self, **opts): """ Return random process distribution. Parameters: :param self: Model object. :type self: 'SymbolicModel' :param opts: Keyword arguments. :type opts: Dictionary. :returns: Exogenous process object. """ import copy gg = self.options.get('distribution') if gg is None: raise Exception("Model has no distribution.") d = copy.deepcopy(gg) d.update(opts) if 'type' in d: d.pop('type') return d.eval(self.calibration_dict.flat)
[docs] def get_cov(self, **opts): """ Return covariance of distribution. Parameters: :param self: Model object. :type self: 'SymbolicModel' :param opts: Keyword arguments . :type opts: dict. :returns: Covariance matrix. """ gg = self.options.get('distribution') if gg is None: raise Exception("Model has no distribution.") return gg.get("cov")
[docs] def get_domain(self): """ Return domain of endogenous variables. Parameters: :param self: Model object. :type self: 'SymbolicModel' :returns: Domain of endogenous variables. """ sdomain = self.domain states = self.symbols['states'] from snowdrop.src.preprocessor.language import Domain d = Domain(**sdomain) domain = d.eval(d=self.calibration_dict.flat) # a bit of a hack... for k in domain.keys(): if k not in states: domain.pop(k) return domain
# def get_grid(self): # """Grid definitions.""" # # determine bounds: # domain = self.get_domain() # min = domain.min # max = domain.max # options = self.data.get("options", {}) # # determine grid_type # grid_type = get_type(options.get("grid")) # if grid_type is None: # grid_type = get_address(self.data, # ["options:grid:type", "options:grid_type"]) # if grid_type is None: # raise Exception('Missing grid geometry ("options:grid:type")') # if grid_type.lower() in ('cartesian', 'cartesiangrid'): # from snowdrop.src.utils.grids import CartesianGrid # orders = get_address(self.data, # ["options:grid:n", "options:grid:orders"]) # if orders is None: # orders = [20] * len(min) # grid = CartesianGrid(min=min, max=max, n=orders) # elif grid_type.lower() in ('smolyak', 'smolyakgrid'): # from snowdrop.src.utils.grids import SmolyakGrid # mu = get_address(self.data, ["options:grid:mu"]) # if mu is None: # mu = 2 # grid = SmolyakGrid(min=min, max=max, mu=mu) # else: # raise Exception("Unknown grid type.") # return grid
[docs] def get_grid(self, **dis_opts): """ Return model grid object. Parameters: :param self: Model object. :type self: 'SymbolicModel' :param dis_opts: Distribution options. :type dis_opts: dict :returns: Domain of endogenous variables. """ import copy domain = self.get_domain() a = np.array([e[0] for e in domain.values()]) b = np.array([e[1] for e in domain.values()]) gg = self.options.get('grid',{}) d = copy.deepcopy(gg) gtype = dis_opts.get('type') if gtype: from snowdrop.src.preprocessor.language import minilang try: cls = [e for e in minilang if e.__name__.lower()==gtype.lower()][0] except: raise Exception("Unknown grid type {}.".format(gtype)) d = cls(**d) d.update(**dis_opts) if 'a' not in d.keys(): d['min'] = a if 'b' not in d.keys(): d['max'] = b if 'type' in d: d.pop('type') grid = d.eval(d=self.calibration_dict.flat) from snowdrop.src.numeric.grids import CartesianGrid, SmolyakGrid if 'Cartesian' in str(grid.__class__): return CartesianGrid(grid.a, grid.b, grid.orders) if 'Smolyak' in str(grid.__class__): return SmolyakGrid(grid.a, grid.b, grid.mu)
def __str__(self): """ Represent Model class object as a string. Parameters: :param self: Model object. :type self: Model. """ equations = self.equations.copy() variables = self.symbols["variables"].copy() parameters = self.symbols["parameters"].copy() eqLabels = self.eqLabels s = '\nTransition Equations:\n---------------------\n\n' for i, eq in enumerate(equations): if not eqLabels is None and i < len(eqLabels): label = eqLabels[i] else: label = str(i+1) if not bool(label): label = str(i+1) s += u" {label:4} : {eqn}\n".format(label=label, eqn=eq) s += "\n" if bool(self.measurement_equations): s += '\nMeasurement Equations:\n---------------------\n\n' for i,eq in enumerate(self.measurement_equations): s += u" {eqn:2} : {eqs}\n".format(eqn=i+1, eqs=eq) s += "\n" if bool(variables): s += '\nVariables:\n----------\n' for v in variables: if v in self.calibration_dict: s += f" {v} : {self.calibration_dict[v]}\n" else: s += f" {v}\n" s += "\n" if bool(self.exogenous): s += '\nExogenous variables:\n-----------\n' for v in self.exogenous: s += f" {v}\n" s += "\n" if bool(parameters): s += '\nParameters:\n-----------\n' for p in parameters: if p in self.calibration_dict: s += f" {p} : {self.calibration_dict[p]}\n" else: s += f" {p}\n" s += "\n" if bool(self.calibration_dict): s += '\nCalibration:\n-----------\n' for k in self.calibration_dict: s += f" {k} : {self.calibration_dict[k]}\n" s += "\n" if bool(self.objective_function): s += colored("\nObjective Function: \n","blue") s += f"func = {self.objective_function}\n" if not self.constraints is None: s += colored("\nConstraints:\n","blue") #ss += "-"*12 + "\n" for c in self.constraints: c = c.replace(".lt.", " < ") c = c.replace(".le.", " <= ") c = c.replace(".gt.", " > ") c = c.replace(".ge.", " >= ") s += f" {c}\n" return s def __repr__(self): """ Official representation of Model class object. Parameters: :param self: Model object. :type self: Model. """ return self.__str__()
[docs] def get_type(d): """Type of a tag.""" try: s = d.tag.value return s.strip("!") except: v = d.get("type") return v
[docs] def get_address(data, address, default=None): """Type of a grid.""" if isinstance(address, list): found = [get_address(data, e, None) for e in address] found = [f for f in found if f is not None] if len(found) > 0: return found[0] else: return default fields = str.split(address, ':') while len(fields) > 0: data = data.get(fields[0]) fields = fields[1:] if data is None: return default return data