Package model :: Module model
[hide private]
[frames] | no frames]

Source Code for Module model.model

  1  #from xml.etree import ElementTree as ET 
  2  from symbolic import * 
  3  import copy 
  4  import inspect 
  5  import misc.calculus 
  6  import re  
  7   
8 -class Model:
9 10 fname = None # Model basename 11 variables = [] 12 exovariables = [] 13 shocks = [] 14 covariances = [] 15 parameters = [] 16 equations = [] 17 init_values = dict() 18 variables_order = dict() 19 commands = None # keep some instructions to treat the model, not sure how to do it 20
21 - def __init__(self, fname, lookup=False):
22 self.fname = fname 23 if lookup: 24 frame = inspect.currentframe().f_back 25 try: 26 self.variables = frame.f_globals["variables"] 27 self.exovariables = frame.f_globals["exovariables"] 28 self.shocks = frame.f_globals["shocks"] 29 self.parameters = frame.f_globals["parameters"] 30 self.equations = frame.f_globals["equations"] 31 except: 32 print("Variables, exovariables, shocks or parameters wer not defined correctly") 33 finally: 34 del frame 35 36 return(None)
37
38 - def copy(self):
39 c = Model(self.fname) 40 c.variables = copy.copy(self.variables) 41 c.exovariables = copy.copy(self.exovariables) 42 c.covariances = copy.copy(self.covariances) 43 c.shocks = copy.copy(self.shocks) 44 c.parameters = copy.copy(self.parameters) 45 c.equations = copy.copy(self.equations) 46 c.init_values = copy.copy(self.init_values) 47 c.commands = copy.copy(self.commands) 48 return(c)
49
50 - def check_all(self,print_info=False,print_eq_info=False):
51 for i in range(len(self.equations)): 52 self.equations[i].n = i 53 self.set_info(self.equations[i]) 54 if print_eq_info: 55 for eq in self.equations: 56 print("Eq (" + str(eq.n) +") : " + str(eq.info) ) 57 info = { 58 "n_variables" : len(self.variables), 59 "n_exovariables" : len(self.exovariables), 60 "n_variables" : len(self.variables), 61 "n_shocks" : len(self.shocks), 62 "n_equations" : len(self.equations) 63 } 64 if print_info: 65 print("Model check : " + self.fname) 66 for k in info: 67 print("\t"+k+"\t\t"+str(info[k]))
68
69 - def set_info(self,eq):
70 info = {} 71 all_vars = [] # will contain all variables 72 all_endo = [] 73 all_exo = [] 74 all_shocks = [] 75 for a in eq.atoms(): 76 if isinstance(a,Variable): 77 all_vars.append(a) 78 if a(-a.lag) in self.variables: 79 all_endo.append(a) 80 elif a(-a.lag) in self.exovariables: 81 all_exo.append(a) 82 elif a(-a.lag) in self.shocks: 83 all_shocks.append(a) 84 else: 85 raise("something impossible happened") 86 87 all_vars_c = map(lambda v: v(-v.lag),all_vars) 88 lags = map(lambda v: v.lag, all_vars) 89 # These information don't depend on the system of equations 90 info['max_lag'] = max(lags) 91 info['min_lag'] = min(lags) 92 info['expected'] = (max(lags) > 0) 93 # These information depend on the model 94 info['exogenous'] =set(all_vars_c).issubset(set(self.exovariables).union(self.shocks)) # & max(lags)<=0 95 info['all_endo'] = all_endo 96 info['all_exo'] = all_exo 97 info['all_shocks'] = all_shocks 98 eq.info = info
99
100 - def map_function_to_expression(self,f,expr):
101 if len(expr._args)==0 : 102 return( f(expr) ) 103 else: 104 l = list(expr._args) 105 args = [] 106 for a in l: 107 args.append(self.map_function_to_expression(f,a)) 108 return( expr.__class__(* args) )
109
110 - def current_equations(self):
111 c_eqs = [] 112 def f(x): 113 if x in self.shocks: 114 return(0) 115 elif x.__class__ == Variable: 116 return(x(-x.lag)) 117 else: 118 return(x)
119 for eq in self.equations: 120 n_eq = self.map_function_to_expression(f,eq) 121 #n_eq.is_endogenous = eq.is_endogenous 122 c_eqs.append(n_eq) 123 return(c_eqs)
124
125 - def future_variables(self):
126 # returns [f_vars, f_eq, f_eq_n] 127 # f_vars : list of variables with lag > 1 128 # f_eq : list of equations containing future variables 129 # f_eq_n : list of indices of equations containing future variables 130 131 f_eq_n = [] # indices of future equations 132 f_eq = [] # future equations (same order) 133 f_vars = set([]) # future variables 134 for i in range(len(self.equations)): 135 eq = self.equations[i] 136 all_atoms = eq.atoms() 137 f_var = [] 138 for a in all_atoms: 139 if (a.__class__ == Variable) and (a(-a.lag) in self.variables): 140 if a.lag > 0: 141 f_var.append(a) 142 if len(f_var)>0: 143 f_eq_n.append(i) 144 f_eq.append(eq) 145 f_vars = f_vars.union(f_var) 146 f_vars = list(f_vars) 147 return([f_vars,f_eq,f_eq_n])
148
149 - def get_jacobian(self):
150 ''' 151 returns the jacobian of the equations with respect to 152 all_variables_f,all_variables,all_variables_b 153 where all_variables == variables + exovariables 154 ''' 155 #print(self.variables) 156 all_variables = self.variables + self.exovariables 157 vec = map(lambda v: v(1), all_variables) + all_variables + map(lambda v: v(-1), all_variables) 158 vec = Matrix([vec]) 159 #print vec 160 f = Matrix( map(lambda eq: eq.gap(),self.equations) ) 161 return f.T.jacobian(vec)
162
163 - def is_matlab_compatible(self):
164 raise('Not implemented')
165
166 - def is_uhlig_compatible(self):
167 umodel = self.copy() 168 # look for epsilons in endogenous equations 169 for eq in self.equations: 170 if (not eq.info['exogenous']) and (eq.info['all_shocks']): 171 print("Error : " + str(eq)) 172 print(eq.info['all_shocks']) 173 raise("Uhlig says : endogenous equations cannot contain any shock.") 174 elif (eq.info['exogenous']): 175 s_lags = map(lambda v: v.lag,eq.info["all_shocks"]) 176 if max(s_lags)!= 0 or min(s_lags)!=0: 177 raise("Uhlig says : exogenous equations can only contain shocks at date t") 178 e_lags = map(lambda v: v.lag,eq.info["all_exo"]) 179 if max(e_lags) != 1: 180 raise("Uhlig says : exogenous equations must have variables appearing at date t+1") 181 if min(e_lags) < 0: 182 raise("Uhlig says : no backward variables allowed in exogenous equations") 183 return(True)
184
185 - def to_uhlig_model(self):
186 umodel = self.copy() 187 umodel.fname = umodel.fname + "_uhlig" 188 if umodel.exovariables: 189 raise("The model already has exogenous variables defined") 190 endo_shocks = {} # list of shocks appearing in endogenous equations with corresponding exogenous variable 191 for i in range(len(umodel.equations)): 192 eq = umodel.equations[i] 193 if (not eq.info['exogenous']): 194 all_shocks = eq.info['all_shocks'] 195 for s in all_shocks: 196 v = Variable('z_' + s.basename) # the exogenous variable such that : z(+1) = epsilon 197 if not s(-s.lag - 1) in endo_shocks: 198 endo_shocks[s(-s.lag - 1)] = v 199 if not s in endo_shocks: 200 endo_shocks[s] = v(s.lag + 1) 201 umodel.equations[i] = eq.subs_dict(endo_shocks) 202 all_shocks_c = set(map(lambda v: v(-v.lag), endo_shocks.keys())) 203 #all_z_c = map(lambda v: endo_shocks[v],all_shocks_c) 204 #umodel.exovariables = umodel.exovariables + all_z 205 for s in all_shocks_c: 206 umodel.exovariables.append(endo_shocks[s].p()) 207 umodel.equations.append(Equation(endo_shocks[s],s)) 208 return umodel
209
210 - def process_portfolio_model(self):
211 212 pf_model = self.copy() # I should work on a copy on the model not on itself ! 213 pf_model.fname = pf_model.fname + "_pf" 214 215 [f_vars,f_eq,f_eq_n] = pf_model.future_variables() 216 217 f_vars_c = map(lambda v: v(-v.lag), f_vars) # this returns current dates of future variables 218 219 nf_eq_n = list(set(range(len(self.equations))).difference(f_eq_n)) # indices of non forward equations 220 nf_eq = map(lambda (n): self.equations[n], nf_eq_n) # non forward equations (differences) 221 222 nf_eq = map(lambda eq: eq.gap(), nf_eq) # we remove equal signs before we can calculate jacobian 223 f_eq = map(lambda eq: eq.gap(), f_eq) 224 225 A = Matrix(len(nf_eq),len(self.exovariables), lambda i,j : Variable("A_"+str(i+1)+str(j+1))) 226 for a in A: 227 pf_model.variables.append(a) 228 229 # Thanks to non forward equations, forward variables variations are 230 # approximated by A * shocks (first order approximation) 231 f = Matrix(nf_eq) 232 f_X = f.jacobian(f_vars_c) 233 for v in pf_model.exovariables: 234 f_X = f_X.subs(v,0) 235 f_E = f.jacobian(Matrix(self.exovariables)) 236 for v in pf_model.exovariables: 237 f_E = f_E.subs(v,0) 238 f_ = f_X * A + f_E 239 240 # Then future variables are substituted in forward equations 241 # which are taylorized twice with respect to shocks 242 # Cross products of shocks are replaced by covariances 243 s_f_eq = [] # will contain future equations with substitutions 244 for i in range(len(f_eq)): 245 eq = f_eq[i] 246 for k in range(len(f_vars)): 247 v = f_vars[k] 248 dv = (A[k,:] * Matrix(self.exovariables))[0,0] 249 eq = eq.subs(v,v+dv) 250 seq = Calculus.second_order_taylorisation(eq, self.exovariables, self.covariances) 251 s_f_eq.append(Equality(0,seq)) 252 253 for eq in f_: 254 pf_model.equations.append(Equation(0,eq,"Another moment condition") ) 255 256 for i in range(len(f_eq)): 257 pf_model.equations[f_eq_n[i]] = s_f_eq[i] 258 259 return(pf_model)
260