def get_diffmodel(self): ''' Returns a model which calculates the partial derivatives of a model''' def makelag(var): vterm = udtryk_parse(var)[0] if vterm.lag: if vterm.lag[0] == '-': return f'{vterm.var}___lag___{vterm.lag[1:]}' elif vterm.lag[0] == '+': return f'{vterm.var}___lead___{vterm.lag[1:]}' else: return f'{vterm.var}___per___{vterm.lag}' else: return f'{vterm.var}___lag___0' with ttimer( 'Generates a model which calculatews the derivatives for a model', self.timeit): out = '\n'.join([ f'{lhsvar}__p__{makelag(rhsvar)} = {self.diffendocur[lhsvar][rhsvar]} ' for lhsvar in sorted(self.diffendocur) for rhsvar in sorted(self.diffendocur[lhsvar]) ]) dmodel = self.newmodel(out, funks=self.mmodel.funks, straight=True, modelname=self.mmodel.name + ' Derivatives ' + ' no lags and leads' if self.onlyendocur else ' all lags and leads') return dmodel
def get_diff_values_all(self, periode=None, df=None, asdf=False): ''' stuff the values of derivatives into nested dic ''' dmelt = self.get_diff_melted_var(periode=periode, df=df) with ttimer('Prepare numpy input to sparse matrix', self.timeit): self.diffvalues = defaultdict(lambda: defaultdict(dict)) grouped = dmelt.groupby(by=['var', 'pvar', 'lag']) for (var, pvar, lag), df in grouped: res = df.pivot(index='pvar', columns='dates', values='value') pvar_name = tovarlag(pvar, int(lag)) #reakpoint() # #csc_matrix((data, (row_ind, col_ind)), [shape=(M, N)]) # print(f'endo:{endo} ,date:{date}, lag:{lag}, \n df') self.diffvalues[var][pvar_name] = res return self.diffvalues
def get_diff_mat_all_1per(self, periode=None, df=None, asdf=False): dmelt = self.get_diff_melted_var(periode=periode, df=df) with ttimer('Prepare numpy input to sparse matrix', self.timeit): outdic = defaultdict(lambda: defaultdict(dict)) grouped = dmelt.groupby(by=['pvar_endo', 'dates', 'lag']) for (endo, date, lag), df in grouped: values = df.value.values # breakpoint() # #csc_matrix((data, (row_ind, col_ind)), [shape=(M, N)]) # print(f'endo:{endo} ,date:{date}, lag:{lag}, \n df') if endo: indicies = (df.var_plac.values, df.pvar_plac.values) this = sp.sparse.csc_matrix( (values, indicies), shape=(len(self.declared_endo_list), len(self.declared_endo_list))) if asdf: outdic[date]['endo'][f'lag={lag}'] = pd.DataFrame( this.toarray(), columns=self.declared_endo_list, index=self.declared_endo_list) else: outdic[date]['endo'][f'lag={lag}'] = this else: indicies = (df.var_plac.values, df.pvar_exo_plac.values) this = sp.sparse.csc_matrix( (values, indicies), shape=(len(self.endovar), len(self.exovar))) if asdf: outdic[date]['exo'][f'lag={lag}'] = pd.DataFrame( this.toarray(), columns=self.exovar, index=self.declared_endo_list) else: outdic[date]['exo'][f'lag={lag}'] = this return outdic
def get_diff_melted(self, periode=None, df=None): '''returns a tall matrix with all values to construct jacobimatrix(es) ''' def get_lagnr(l): ''' extract lag/lead from variable name and returns a signed lag (leads are positive''' #breakpoint() return int('-' * (l.split('___')[0] == 'LAG') + l.split('___')[1]) def get_elm(vartuples, i): ''' returns a list of lags list of tupels ''' return [v[i] for v in vartuples] _per_first = periode if type(periode) != type( None) else self.mmodel.current_per if hasattr(_per_first, '__iter__'): _per = _per_first else: _per = [_per_first] _df = self.df if type(df) != pd.DataFrame else df _df = _df.pipe( lambda df0: df0.rename(columns={c: c.upper() for c in df0.columns})) self.diff_model.current_per = _per # breakpoint() with ttimer('calculate derivatives', self.timeit): self.difres = self.diff_model.res( _df, silent=self.silent, stats=0, ljit=self.ljit, chunk=self.nchunk).loc[_per, self.diff_model.endogene] with ttimer('Prepare wide input to sparse matrix', self.timeit): cname = namedtuple('cname', 'var,pvar,lag') self.coltup = [ cname( i.rsplit('__P__', 1)[0], i.rsplit('__P__', 1)[1].split('___', 1)[0], get_lagnr(i.rsplit('__P__', 1)[1].split('___', 1)[1])) for i in self.difres.columns ] # breakpoint() self.coltupnum = [ (self.placdic[var], self.placdic[pvar + '___RES' if (pvar + '___RES' in self.mmodel.endogene) else pvar], lag) for var, pvar, lag in self.coltup ] self.difres.columns = self.coltupnum self.numbers = [i for i, n in enumerate(self.difres.index)] self.maxnumber = max(self.numbers) self.numbers_to_date = { i: n for i, n in enumerate(self.difres.index) } self.nvar = len(self.endovar) self.difres.loc[:, 'number'] = self.numbers with ttimer('melt the wide input to sparse matrix', self.timeit): dmelt = self.difres.melt(id_vars='number') dmelt.loc[:, 'value'] = dmelt['value'].astype('float') with ttimer('assign tall input to sparse matrix', self.timeit): # breakpoint() dmelt = dmelt.assign(var=lambda x: get_elm(x.variable, 0), pvar=lambda x: get_elm(x.variable, 1), lag=lambda x: get_elm(x.variable, 2)) return dmelt
def modeldiff(self): ''' Differentiate relations for self.enovar with respect to endogeneous variable The result is placed in a dictory in the model instanse: model.diffendocur ''' def numdif(model, v, rhv, delta=0.005, silent=True): # print('**',model.allvar[v]['terms']['frml']) def tout(t): if t.lag: return f'{t.var}({t.lag})' return t.op + t.number + t.var # breakpoint() nt = model.allvar[v]['terms'] assignpos = nt.index(model.aequalterm) # find the position of = rhsterms = nt[assignpos + 1:-1] vterm = udtryk_parse(rhv)[0] plusterm = udtryk_parse(f'({rhv}+{delta/2})', funks=model.funks) minusterm = udtryk_parse(f'({rhv}-{delta/2})', funks=model.funks) plus = itertools.chain.from_iterable( [plusterm if t == vterm else [t] for t in rhsterms]) minus = itertools.chain.from_iterable( [minusterm if t == vterm else [t] for t in rhsterms]) eplus = f'({"".join(tout(t) for t in plus)})' eminus = f'({"".join(tout(t) for t in minus)})' expression = f'({eplus}-{eminus})/{delta}' if (not silent) and False: print(expression) return expression def findallvar(model, v): '''Finds all endogenous variables which is on the right side of = in the expresion for variable v lagged variables are included if self.onlyendocur == False ''' # print(v) terms = self.mmodel.allvar[v]['terms'][model. allvar[v]['assigpos']:-1] if self.endoandexo: rhsvar = { (nt.var + ('(' + nt.lag + ')' if nt.lag != '' else '')) for nt in terms if nt.var } rhsvar = {tovarlag(nt.var, nt.lag) for nt in terms if nt.var} else: if self.onlyendocur: rhsvar = { tovarlag(nt.var, nt.lag) for nt in terms if nt.var and nt.lag == '' and nt.var in self.declared_endo_set } else: rhsvar = { tovarlag(nt.var, nt.lag) for nt in terms if nt.var and nt.var in self.declared_endo_set } var2 = sorted(list(rhsvar)) return var2 with ttimer('Find espressions for partial derivatives', self.timeit): clash = {var: Symbol(var) for var in self.mmodel.allvar.keys()} diffendocur = { } #defaultdict(defaultdict) #here we wanmt to store the derivativs i = 0 for nvar, v in enumerate(self.endovar): if nvar >= self.maxdif: break if not self.silent and 0: print(f'Now differentiating {v} {nvar}') endocur = findallvar(self.mmodel, v) diffendocur[v] = {} t = self.mmodel.allvar[v]['frml'].upper() a, fr, n, udtryk = split_frml(t) udtryk = udtryk udtryk = re.sub( r'LOG\(', 'log(', udtryk) # sympy uses lover case for log and exp udtryk = re.sub(r'EXP\(', 'exp(', udtryk) lhs, rhs = udtryk.split('=', 1) try: if not self.forcenum: # kat=sympify(rhs[0:-1], md._clash) # we take the the $ out _clash1 makes I is not taken as imiganary kat = sympify( rhs[0:-1], clash ) # we take the the $ out _clash1 makes I is not taken as imiganary except: # breakpoint() print('* Problem sympify ', lhs, '=', rhs[0:-1]) for rhv in endocur: try: # breakpoint() if not self.forcenum: # ud=str(kat.diff(sympify(rhv,md._clash))) try: ud = str(kat.diff(sympify(rhv, clash))) ud = re.sub( pt.namepat + r'(?:(\()([0-9])(\)))', r'\g<1>\g<2>+\g<3>\g<4>', ud) except: ud = numdif(self.mmodel, v, rhv, silent=self.silent) if self.forcenum or 'Derivative(' in ud: ud = numdif(self.mmodel, v, rhv, silent=self.silent) if not self.silent and 0: print('numdif of {rhv}') diffendocur[v.upper()][rhv.upper()] = ud except: print('we have a serious problem deriving:', lhs, '|', rhv, '\n', lhs, '=', rhs) # breakpoint() i += 1 if not self.silent: print('Model :', self.mmodel.name) print('Number of endogeneus variables :', len(diffendocur)) print('Number of derivatives :', i) return diffendocur