model.model

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