def parse_dynare_text(txt, add_model=True, full_output=False, debug=False): ''' Imports the content of a modfile into the current interpreter scope ''' # here we call "instruction group", a string finishing by a semicolon # an "instruction group" can have several lines # a line can be # - a comment //... # - an old-style tag //$... # - a new-style tag [key1='value1',..] # - macro-instruction @#... # A Modfile contains several blocks (in this order) : # - an initblock defining variables, exovariables, parameters, initialization # inside the initblock the order of declaration doesn't matter # - a model block with two special lines (model; end;) # - optional blocks (like endval, shocks) # seperated by free matlab instructions in any order; # - all other instructions are ignored otxt = txt otxt = otxt.replace("\r\n", "\n") otxt = otxt.replace("^", "**") # first, we remove end-of-line comments : they are definitely lost regex = re.compile("(.+)//[^#](.*)") def remove_end_comment(line): res = regex.search(line) if res: l = res.groups(1)[0] return (l) else: return line txt = str.join("\n", map(remove_end_comment, otxt.split("\n"))) name_regex = re.compile("//\s*fname\s*=\s*'(.*)'") m = name_regex.search(txt) if m: fname = m.group(1) else: fname = None instruction_groups = [Instruction_group(s) for s in txt.split(";")] instructions = [ig.instruction for ig in instruction_groups] if debug: print('Elementary instructions') for i in instruction_groups: print(i) try: imodel = [ re.compile('model(\(.*\)|)').match(e) is not None for e in instructions ] imodel = imodel.index(True) #imodel = instructions.index("model") #this doesn't work for "MODEL" iend = instructions.index("end") model_block = instruction_groups[imodel:(iend + 1)] init_block = instruction_groups[0:imodel] except: raise Exception('Model block could not be found.') next_instructions = instructions[(iend + 1):] next_instruction_groups = instruction_groups[(iend + 1):] if 'initval' in next_instructions: iinitval = next_instructions.index('initval') iend = next_instructions.index('end', iinitval) matlab_block_1 = next_instruction_groups[0:iinitval] initval_block = next_instruction_groups[iinitval:(iend + 1)] next_instruction_groups = next_instruction_groups[(iend + 1):] next_instructions = next_instructions[(iend + 1):] else: initval_block = None matlab_block_1 = None if 'endval' in next_instructions: iendval = next_instructions.index('endval') iend = next_instructions.index('end', iendval) matlab_block_2 = next_instruction_groups[0:iendval] endval_block = next_instruction_groups[iendval:(iend + 1)] next_instruction_groups = next_instruction_groups[(iend + 1):] next_instructions = next_instructions[(iend + 1):] else: endval_block = None matlab_block_2 = None # TODO : currently shocks block needs to follow initval, this restriction should be removed if 'shocks' in next_instructions: ishocks = next_instructions.index('shocks') iend = next_instructions.index('end', ishocks) matlab_block_3 = next_instruction_groups[0:ishocks] shocks_block = next_instruction_groups[ishocks:(iend + 1)] next_instruction_groups = next_instruction_groups[(iend + 1):] next_instructions = next_instructions[(iend + 1):] else: shocks_block = None matlab_block_3 = None try: init_regex = re.compile("(parameters |var |varexo |)(.*)") var_names = [] varexo_names = [] parameters_names = [] declarations = {} for ig in init_block: if ig.instruction != '': m = init_regex.match(ig.instruction) if not m: raise Exception("Unexpected instruction in init block : " + str(ig.instruction)) if m.group(1) == '': [lhs, rhs] = m.group(2).split("=") lhs = lhs.strip() rhs = rhs.strip() declarations[lhs] = rhs else: arg = m.group(2).replace(",", " ") names = [vn.strip() for vn in arg.split()] if m.group(1).strip() == 'var': dest = var_names elif m.group(1).strip() == 'varexo': dest = varexo_names elif m.group(1).strip() == 'parameters': dest = parameters_names for n in names: if not n in dest: dest.append(n) else: raise Exception( "symbol %s has already been defined".format(n)) except Exception as e: raise Exception('Init block could not be read : ' + str(e)) # the following instruction set the variables "variables","shocks","parameters" variables = [] for vn in var_names: v = Variable(vn) variables.append(v) shocks = [] for vn in varexo_names: s = Shock(vn) shocks.append(s) parameters = [] for vn in parameters_names: p = Parameter(vn) parameters.append(p) parse_dict = dict() for v in variables + shocks + parameters: parse_dict[v.name] = v special_symbols = [ sympy.exp, sympy.log, sympy.sin, sympy.cos, sympy.atan, sympy.tan ] for s in special_symbols: parse_dict[str(s)] = s parse_dict['sqrt'] = sympy.sqrt # Read parameters values parameters_values = {} for p in declarations: try: rhs = eval(declarations[p], parse_dict) except Exception as e: Exception("Impossible to evaluate parameter value : " + str(e)) try: lhs = eval(p, parse_dict) except Exception as e: # here we could declare p raise e parameters_values[lhs] = rhs # Now we read the model block model_tags = model_block[0].tags equations = [] for ig in model_block[1:-1]: if ig.instruction != '': teq = ig.instruction.replace('^', "**") if '=' in teq: teqlhs, teqrhs = teq.split("=") else: teqlhs = teq teqrhs = '0' eqlhs = eval(teqlhs, parse_dict) eqrhs = eval(teqrhs, parse_dict) eq = Equation(eqlhs, eqrhs) eq.tags.update(ig.tags) # if eq.tags.has_key('name'): # eq.tags[] = ig.tags['name'] equations.append(eq) # Now we read the initval block init_values = {} if initval_block != None: for ig in initval_block[1:-1]: if len(ig.instruction.strip()) > 0: try: [lhs, rhs] = ig.instruction.split("=") except Exception as e: print(ig.instruction) raise e init_values[eval(lhs, parse_dict)] = eval(rhs, parse_dict) # Now we read the endval block # I don't really care about the endval block ! end_values = {} if endval_block != None: for ig in endval_block[1:-1]: [lhs, rhs] = ig.instruction.split("=") end_values[eval(lhs)] = eval(rhs) # Now we read the shocks block covariances = None if shocks_block != None: covariances = sympy.zeros(len(shocks)) regex1 = re.compile("var (.*?),(.*?)=(.*)|var (.*?)=(.*)") for ig in shocks_block[1:-1]: m = regex1.match(ig.instruction) if not m: raise Exception("unrecognized instruction in block shocks : " + str(ig.instruction)) if m.group(1) != None: varname1 = m.group(1).strip() varname2 = m.group(2).strip() value = m.group(3).strip().replace("^", "**") elif m.group(4) != None: varname1 = m.group(4).strip() varname2 = varname1 value = m.group(5).strip().replace("^", "**") i = varexo_names.index(varname1) j = varexo_names.index(varname2) covariances[i, j] = eval(value, parse_dict) covariances[j, i] = eval(value, parse_dict) calibration = {} calibration.update(parameters_values) calibration.update(init_values) symbols = { 'variables': variables, 'shocks': shocks, 'parameters': parameters } from dolo.symbolic.model import SModel model = SModel({'dynare_block': equations}, symbols, calibration, covariances) return model
def read_model(self): import re import sympy from dolo.symbolic.symbolic import map_function_to_expression from dolo.symbolic.symbolic import Variable if self.__transformed_model__: return self.__transformed_model__ dmodel = SModel(**self.model) # copy the model dmodel.check_consistency(auto_remove_variables=False) def_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('def', 'auxiliary')] def timeshift(v,n): if isinstance(v,Variable): return v(n) else: return v # Build substitution dict def_dict = {} for eq in def_eqs: v = eq.lhs rhs = sympy.sympify(eq.rhs) def_dict[v] = rhs def_dict[v(1)] = map_function_to_expression(lambda x: timeshift(x,1), rhs) new_equations = [] tbr = [] for i,eq in enumerate(dmodel.equations) : if not ('def' == eq.tags['eq_type']): lhs = sympy.sympify( eq.lhs ).subs(def_dict) rhs = sympy.sympify( eq.rhs ).subs(def_dict) neq = Equation(lhs,rhs).tag(**eq.tags) new_equations.append(neq) dmodel['equations'] = new_equations dmodel.check_consistency() f_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('f','arbitrage','equilibrium')] g_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('g','transition')] h_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('h','expectation')] hm_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('h','expectation_mult')] # Need to understand the need for 'h' e_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('e','equation_error')] states_vars = [eq.lhs for eq in g_eqs] exp_vars = [eq.lhs for eq in h_eqs] controls = set(dmodel.variables) - set(states_vars + exp_vars) controls = list(controls) states_vars = [v for v in dmodel.variables if v in states_vars] exp_vars = [v for v in dmodel.variables if v in exp_vars] controls = [v for v in dmodel.variables if v in controls] # Remove the left-hand side of equations f_eqs = [eq.gap for eq in f_eqs] g_eqs = [eq.rhs for eq in g_eqs] h_eqs = [eq.rhs for eq in h_eqs] hm_eqs = [eq.rhs for eq in hm_eqs] e_eqs = [eq.lhs for eq in e_eqs] g_eqs = [map_function_to_expression(lambda x: timeshift(x,1),eq) for eq in g_eqs] #h_eqs = [map_function_to_expression(lambda x: timeshift(x,-1),eq) for eq in h_eqs] #no # sub_list[v] = v.name # Read complementarity conditions compcond = {} of_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('f','arbitrage','equilibrium')] locals = {} locals['inf'] = sympy.Symbol('inf') locals['log'] = sympy.log locals['exp'] = sympy.exp for v in dmodel.variables + dmodel.parameters: locals[v.name] = v compregex = re.compile('(.*)<=(.*)<=(.*)') for eq in of_eqs: tg = eq.tags['complementarity'] [lhs,mhs,rhs] = compregex.match(tg).groups() [lhs,mhs,rhs] = [dmodel.eval_string(x) for x in [lhs,mhs,rhs]] compcond[mhs] = (lhs,rhs) complementarities = [compcond[v] for v in controls] inf_bounds = [c[0] for c in complementarities] sup_bounds = [c[1] for c in complementarities] data = {'f_eqs': f_eqs, 'g_eqs': g_eqs, 'h_eqs': h_eqs, 'hm_eqs': hm_eqs, 'e_eqs':e_eqs, 'controls': controls, 'states_vars': states_vars, 'exp_vars': exp_vars, 'inf_bounds': inf_bounds, 'sup_bounds': sup_bounds} self.__transformed_model__ = data # cache computation return data
def parse_yaml_text(txt, verbose=False, compiler=None): ''' Imports the content of a modfile into the current interpreter scope ''' txt = txt.replace('..', '-') txt = txt.replace('--', '-') txt = txt.replace('^', '**') txt = txt.replace('equilibrium:', 'arbitrage:') txt = txt.replace('_|_', '|') raw_dict = yaml.load(txt) if verbose == True: print('YAML file successfully parsed') declarations = raw_dict['declarations'] # check variables_groups = OrderedDict() for vtype in declarations.keys(): if vtype not in ('shocks', 'parameters'): variables_groups[vtype] = [ Variable(vn) for vn in declarations[vtype] ] variables_ordering = sum(variables_groups.values(), []) # else: # vnames = declarations['variables'] # variables_ordering = [Variable(vn) for vn in vnames] # variables_groups = None parameters_ordering = [Parameter(vn) for vn in declarations['parameters']] shocks_ordering = [Shock(vn) for vn in declarations['shocks']] context = [ (s.name, s) for s in variables_ordering + parameters_ordering + shocks_ordering ] context = dict(context) from dolo.symbolic.symbolic import timeshift as TS # add some common functions for f in [ sympy.log, sympy.exp, sympy.sin, sympy.cos, sympy.tan, sympy.asin, sympy.acos, sympy.atan, sympy.sinh, sympy.cosh, sympy.tanh, sympy.pi, sympy.sign ]: context[str(f)] = f context['sqrt'] = sympy.sqrt context['TS'] = TS if 'horrible_hack' in raw_dict: tt = raw_dict['horrible_hack'] exec(tt, context) import re # we recognize two kinds of equations: # lhs = rhs # lhs | comp where comp is a complementarity condition equations = [] equations_groups = OrderedDict() raw_equations = raw_dict['equations'] if not isinstance(raw_equations, dict): raw_dict['model_type'] = 'dynare' raw_equations = {'dynare_block': raw_equations} if True: # tests whether there are groups of equations for groupname in raw_equations.keys(): equations_groups[groupname] = [] for raw_eq in raw_equations[ groupname]: # Modfile is supposed to represent a global model. TODO: change it teqg = raw_eq.split('|') teq = teqg[0] if '=' in teq: lhs, rhs = str.split(teq, '=') else: lhs = teq rhs = '0' try: lhs = eval(lhs, context) rhs = eval(rhs, context) except Exception as e: print('Error parsing equation : ' + teq) print(str(e)) raise e eq = Equation(lhs, rhs) eq.tag(eq_type=groupname) if len(teqg) > 1: comp = teqg[1] eq.tag(complementarity=comp) equations.append(eq) equations_groups[groupname].append(eq) else: for teq in raw_equations: if '=' in teq: lhs, rhs = str.split(teq, '=') else: lhs = teq rhs = '0' try: lhs = eval(lhs, context) rhs = eval(rhs, context) except Exception as e: print('Error parsing equations : ' + teq) print(str(e)) eq = Equation(lhs, rhs) equations.append(eq) equations_groups = None parameters_values = {} init_values = {} covariances = None if 'calibration' in raw_dict: calibration = raw_dict['calibration'] if 'parameters' in calibration: parameters_values = [ (Parameter(k), eval(str(v), context)) for k, v in iteritems(calibration['parameters']) ] parameters_values = dict(parameters_values) #steady_state = raw_dict['steady_state'] if 'steady_state' in calibration: init_values = [ (Variable(vn), eval(str(value), context)) for vn, value in iteritems(calibration['steady_state']) ] init_values = dict(init_values) if 'covariances' in calibration: context['sympy'] = sympy covariances = eval( 'sympy.Matrix({0})'.format(calibration['covariances']), context) else: covariances = None # to avoid importing numpy symbols = variables_groups symbols['shocks'] = shocks_ordering symbols['parameters'] = parameters_ordering calibration_s = {} calibration_s.update(parameters_values) calibration_s.update(init_values) from dolo.symbolic.model import SModel model = SModel(equations_groups, symbols, calibration_s, covariances) model.__data__ = raw_dict return model
def parse_yaml_text(txt,verbose=False, compiler=None): ''' Imports the content of a modfile into the current interpreter scope ''' txt = txt.replace('..','-') txt = txt.replace('--','-') txt = txt.replace('^','**') txt = txt.replace('equilibrium:','arbitrage:') txt = txt.replace('_|_','|') raw_dict = yaml.load(txt) if verbose == True: print('YAML file successfully parsed') declarations = raw_dict['declarations'] # check variables_groups = OrderedDict() for vtype in declarations.keys(): if vtype not in ('shocks','parameters'): variables_groups[vtype] = [Variable(vn) for vn in declarations[vtype]] variables_ordering = sum(variables_groups.values(),[]) # else: # vnames = declarations['variables'] # variables_ordering = [Variable(vn) for vn in vnames] # variables_groups = None parameters_ordering = [Parameter(vn) for vn in declarations['parameters']] shocks_ordering = [Shock(vn) for vn in declarations['shocks']] context = [(s.name,s) for s in variables_ordering + parameters_ordering + shocks_ordering] context = dict(context) from dolo.symbolic.symbolic import timeshift as TS # add some common functions for f in [sympy.log, sympy.exp, sympy.sin, sympy.cos, sympy.tan, sympy.asin, sympy.acos, sympy.atan, sympy.sinh, sympy.cosh, sympy.tanh, sympy.pi, sympy.sign]: context[str(f)] = f context['sqrt'] = sympy.sqrt context['TS'] = TS if 'horrible_hack' in raw_dict: tt = raw_dict['horrible_hack'] exec(tt, context) import re # we recognize two kinds of equations: # lhs = rhs # lhs | comp where comp is a complementarity condition equations = [] equations_groups = OrderedDict() raw_equations = raw_dict['equations'] if not isinstance(raw_equations,dict): raw_dict['model_type'] = 'dynare' raw_equations = {'dynare_block': raw_equations} if True: # tests whether there are groups of equations for groupname in raw_equations.keys(): equations_groups[groupname] = [] for raw_eq in raw_equations[groupname]: # Modfile is supposed to represent a global model. TODO: change it teqg = raw_eq.split('|') teq = teqg[0] if '=' in teq: lhs,rhs = str.split(teq,'=') else: lhs = teq rhs = '0' try: lhs = eval(lhs,context) rhs = eval(rhs,context) except Exception as e: print('Error parsing equation : ' + teq) print( str(e) ) raise e eq = Equation(lhs,rhs) eq.tag(eq_type=groupname) if len(teqg)>1: comp = teqg[1] eq.tag(complementarity=comp) equations.append(eq) equations_groups[groupname].append( eq ) else: for teq in raw_equations: if '=' in teq: lhs,rhs = str.split(teq,'=') else: lhs = teq rhs = '0' try: lhs = eval(lhs,context) rhs = eval(rhs,context) except Exception as e: print('Error parsing equations : ' + teq) print(str(e)) eq = Equation(lhs,rhs) equations.append(eq) equations_groups = None parameters_values = {} init_values = {} covariances = None if 'calibration' in raw_dict: calibration = raw_dict['calibration'] if 'parameters' in calibration: parameters_values = [ (Parameter(k), eval(str(v),context)) for k,v in iteritems(calibration['parameters']) ] parameters_values = dict(parameters_values) #steady_state = raw_dict['steady_state'] if 'steady_state' in calibration: init_values = [ (Variable(vn), eval(str(value),context)) for vn,value in iteritems(calibration['steady_state']) ] init_values = dict(init_values) if 'covariances' in calibration: context['sympy'] = sympy covariances = eval('sympy.Matrix({0})'.format( calibration['covariances'] ), context) else: covariances = None # to avoid importing numpy symbols = variables_groups symbols['shocks'] = shocks_ordering symbols['parameters'] = parameters_ordering calibration_s = {} calibration_s.update(parameters_values) calibration_s.update(init_values) from dolo.symbolic.model import SModel model = SModel( equations_groups, symbols, calibration_s, covariances ) model.__data__ = raw_dict return model
def read_model(self): if self.__transformed_model__: return self.__transformed_model__ dmodel = SModel(**self.model) # copy the model dmodel.check_consistency(auto_remove_variables=False) def_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('def', 'auxiliary')] from dolo.symbolic.symbolic import map_function_to_expression from dolo.symbolic.symbolic import Variable def timeshift(v,n): if isinstance(v,Variable): return v(n) else: return v import sympy #### build substitution dict def_dict = {} for eq in def_eqs: v = eq.lhs rhs = sympy.sympify( eq.rhs ) def_dict[v] = rhs def_dict[v(1)] = map_function_to_expression( lambda x: timeshift(x,1), rhs) new_equations = [] tbr = [] for i,eq in enumerate(dmodel.equations) : if not ('def' == eq.tags['eq_type']): lhs = sympy.sympify( eq.lhs ).subs(def_dict) rhs = sympy.sympify( eq.rhs ).subs(def_dict) neq = Equation(lhs,rhs).tag(**eq.tags) new_equations.append( neq ) dmodel['equations'] = new_equations dmodel.check_consistency() f_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('f','arbitrage')] g_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('g','transition')] h_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('h','expectation')] states_vars = [eq.lhs for eq in g_eqs] exp_vars = [eq.lhs for eq in h_eqs] controls = set(dmodel.variables) - set(states_vars + exp_vars) controls = list(controls) states_vars = [v for v in dmodel.variables if v in states_vars] exp_vars = [v for v in dmodel.variables if v in exp_vars] controls = [v for v in dmodel.variables if v in controls] # now we remove the left side of equations f_eqs = [eq.gap for eq in f_eqs] g_eqs = [eq.rhs for eq in g_eqs] h_eqs = [eq.rhs for eq in h_eqs] g_eqs = [map_function_to_expression(lambda x: timeshift(x,1),eq) for eq in g_eqs] #h_eqs = [map_function_to_expression(lambda x: timeshift(x,-1),eq) for eq in h_eqs] #no # sub_list[v] = v.name # read complementarity conditions compcond = {} of_eqs = [eq for eq in dmodel.equations if eq.tags['eq_type'] in ('f','arbitrage')] locals = {} import sympy locals['inf'] = sympy.Symbol('inf') locals['log'] = sympy.log # this should be more generic locals['exp'] = sympy.exp for v in dmodel.variables + dmodel.parameters: locals[v.name] = v import re compregex = re.compile('(.*)<=(.*)<=(.*)') for eq in of_eqs: tg = eq.tags['complementarity'] [lhs,mhs,rhs] = compregex.match(tg).groups() [lhs,mhs,rhs] = [dmodel.eval_string(x) for x in [lhs,mhs,rhs] ] compcond[mhs] = (lhs,rhs) complementarities = [compcond[v] for v in controls] inf_bounds = [c[0] for c in complementarities] sup_bounds = [c[1] for c in complementarities] data = { 'f_eqs': f_eqs, 'g_eqs': g_eqs, 'h_eqs': h_eqs, 'controls': controls, 'states_vars': states_vars, 'exp_vars': exp_vars, 'inf_bounds': inf_bounds, 'sup_bounds': sup_bounds } self.__transformed_model__ = data # cache computation return data