def dyn_tabify_expression(self, eq, for_matlab=False, for_c=True): #from dolo.misc.calculus import map_function_to_expression # works when all variables are expressed without lag subs_dict = self.dynamic_substitution_list res = DicPrinter(subs_dict).doprint(eq) # def f(expr): # if expr.__class__ in [Variable,Parameter]: # vname = subs_dict[expr] # return(Symbol(vname)) # else: # return(expr) # res = map_function_to_expression(f,eq) return res
def compute_dynamic_pfile(self, max_order=1, compact_order=True, with_parameters=False): if with_parameters: DerivativesTree.symbol_type = sympy.Symbol else: DerivativesTree.symbol_type = TSymbol model = self.model if compact_order: var_order = model.dyn_var_order + model.shocks else: var_order = [v(1) for v in model.variables] var_order += model.variables var_order += [v(-1) for v in model.variables] var_order += model.shocks if with_parameters: var_order += model.parameters # TODO create a log system sols = [] i = 0 for eq in model.equations: i += 1 ndt = DerivativesTree(eq.gap) ndt.compute_nth_order_children(max_order) sols.append(ndt) self.dynamic_derivatives = sols dyn_subs_dict = self.dynamic_substitution_list(brackets=True, compact=compact_order) dyn_printer = DicPrinter(dyn_subs_dict) txt = """def dynamic_gaps(y, x, params): # # Status : Computes dynamic model for Dynare # # Warning : this file is generated automatically by Dynare # from model file (.mod) # # Model equations # it_ = 0 import numpy as np from numpy import exp, log from numpy import arctan as atan g = [] residual = np.zeros({neq}); """ gs = str.join(", ", [("g" + str(i)) for i in range(1, (max_order + 1))]) txt = txt.format(gs=gs, fname=model.fname, neq=len(model.equations)) for i in range(len(sols)): ndt = sols[i] eq = ndt.expr rhs = dyn_printer.doprint_matlab(eq) txt += " residual[{0}] = {1};\n".format(i, rhs) txt += " g.append(residual)\n" for current_order in range(1, (max_order + 1)): if current_order == 1: matrix_name = "Jacobian" elif current_order == 2: matrix_name = "Hessian" else: matrix_name = "{0}_th order".format(current_order) txt += """ # # {matrix_name} matrix # """.format( orderr=current_order + 1, matrix_name=matrix_name ) if current_order == 2: txt.format(matrix_name="Hessian") elif current_order == 1: txt.format(matrix_name="Jacobian") # nnzd = self.NNZDerivatives(current_order) n_cols = (len(var_order),) * current_order n_cols = ",".join([str(s) for s in n_cols]) txt += " g{order} = np.zeros( ({n_eq}, {n_cols}) );\n".format( order=current_order, n_eq=len(model.equations), n_cols=n_cols ) for n in range(len(sols)): ndt = sols[n] l = ndt.list_nth_order_children(current_order) for nd in l: # here we compute indices where we write the derivatives indices = nd.compute_index_set(var_order) rhs = dyn_printer.doprint_numpy(nd.expr) i0 = indices[0] i_col_s = ",".join([str(nn) for nn in i0]) indices.remove(i0) i_col_s_ref = i_col_s txt += " g{order}[{i_eq},{i_col}] = {value}\n".format( order=current_order, i_eq=n, i_col=i_col_s, value=rhs ) for ind in indices: i += 1 i_col_s = ",".join([str(nn) for nn in ind]) txt += " g{order}[{i_eq},{i_col}] = g{order}[{i_eq},{i_col_ref}] \n".format( order=current_order, i_eq=n, i_col=i_col_s, i_col_ref=i_col_s_ref ) txt += " g.append(g{order})\n".format(order=current_order) txt += " return g\n" txt = txt.replace("^", "**") fun = code_to_function(txt, "dynamic_gaps") return fun
def compile_multiargument_function(equations, args_list, args_names, parms, diff=False, fname='anonymous_function', default=None): """ :param equations: list of sympy expressions :param args_list: list of lists of symbols (e.g. [[a_1,a_2], [b_1,b_2]]) :param args_names: list of strings (['a','b'] :param parms: list of symbols to be used as parameters :param fname: name of the function to be generated :param diff: include symbolic derivatives in generated function :param vectorize: arguments are vectorized (not parameters) :param return_function: the source of a Matlab function f(a,b,p) where p is a vector of parameters and a, b, arrays :return: """ template = '{0}(:,{1})' sub_list = {} for i,args in enumerate(args_list): vec_name = args_names[i] for j,v in enumerate(args): sub_list[v] = template.format(vec_name,j+1) for i,p in enumerate(parms): sub_list[p] = '{0}({1})'.format('p',i+1) import sympy sub_list[sympy.Symbol('inf')] = 'inf' text = ''' function [{return_names}] = {fname}({args_names}, {param_names}, output) if nargin <= {nargs} output = zeros({nargs},1); for i = 1:nargout output(i) = 1; end end n = size({var},1); {content} end ''' from dolo.compiler.common import DicPrinter dp = DicPrinter(sub_list) def write_eqs(eq_l, outname='val', default=None): '''Format equations''' if default: eq_block = ' {0} = ' + default + '( n , {1} );\n' eq_block = eq_block.format(outname, len(eq_l)) else: eq_block = ' {0} = zeros( n, {1} );\n'.format(outname, len(eq_l)) for i,eq in enumerate(eq_l): eq_txt = dp.doprint_matlab(eq, vectorize=True) if eq_txt != default: eq_block += ' {0}(:,{1}) = {2};\n'.format(outname, i+1, eq_txt) return eq_block def write_der_eqs(eq_l,v_l,lhs): '''Format Jacobians''' eq_block = ' {lhs} = zeros( n,{0},{1} );\n'.format(len(eq_l),len(v_l),lhs=lhs) eq_l_d = eqdiff(eq_l,v_l) for i,eqq in enumerate(eq_l_d): for j,eq in enumerate(eqq): s = dp.doprint_matlab( eq, vectorize=True ) if s != "0": eq_block += ' {lhs}(:,{0},{1}) = {2};\n'.format(i+1,j+1,s,lhs=lhs) return eq_block content = write_eqs(eq_l=equations, default=default) content += ''' if nargout <= 1 return end ''' if diff: for i,a_g in enumerate(args_list): content += "\n % Derivatives w.r.t: {0}\n\n".format(args_names[i]) lhs = 'val_' + args_names[i] content += ' if output({})\n'.format(i+2) content += write_der_eqs(equations, a_g, lhs) content += ' else\n' content += ' val_{} = [];\n'.format(args_names[i]) content += ' end;\n' return_names = str.join(', ', ['val'] + [ 'val_'+ str(a) for a in args_names] ) if diff else 'val' text = text.format( fname = fname, nargs = len(args_names)+1, var = args_names[0], content = content, return_names = return_names, args_names = str.join(', ', args_names), param_names = 'p' ) # text = text.replace('+','.+') # text = text.replace('-','.-') return text
def compile_function(equations, args, parms, max_order, return_text=False): """ :param equations: :param args: :param parms: :param max_order: :param return_function: :return: """ var_order = args sols = [] for eq in equations: ndt = DerivativesTree(eq, ref_var_list=var_order) ndt.compute_nth_order_children(max_order) sols.append(ndt) dyn_subs_dict = dict() for i,v in enumerate(args): dyn_subs_dict[v] = 'x_' + str(i) for i,p in enumerate(parms): dyn_subs_dict[p] = 'p_' + str(i) preamble_l = [' x_{i} = x[{i}] # {v}'.format(i=i,v=v) for i,v in enumerate(args)] preamble_l += [' p_{i} = p[{i}] # {p}'.format(i=i,p=p) for i,p in enumerate(parms)] preamble = str.join('\n',preamble_l) dyn_printer = DicPrinter(dyn_subs_dict) txt = """def dynamic_function(x, p): # # # import numpy as np from numpy import exp, log from numpy import sin, cos, tan from numpy import arcsin as asin from numpy import arccos as acos from numpy import arctan as atan from numpy import sinh, cosh, tanh from numpy import pi {preamble} f = [] residual = np.zeros({neq},dtype=np.float64); """ gs = str.join(', ',[('f'+str(i)) for i in range(1,(max_order+1))]) txt = txt.format(gs=gs,fname='noname',neq=len(equations), preamble=preamble) for i in range(len(sols)): ndt = sols[i] eq = ndt.expr rhs = dyn_printer.doprint_numpy(eq) txt += ' residual[{0}] = {1}\n'.format(i,rhs ) txt += ' f.append(residual)\n' for current_order in range(1,(max_order+1)): if current_order == 1: matrix_name = "Jacobian" elif current_order == 2: matrix_name = "Hessian" else: matrix_name = "{0}_th order".format(current_order) txt += """ # # {matrix_name} matrix # """.format(orderr=current_order+1,matrix_name=matrix_name) if current_order == 2: txt.format(matrix_name="Hessian") elif current_order == 1: txt.format(matrix_name="Jacobian") #nnzd = self.NNZDerivatives(current_order) n_cols = (len(var_order),)*current_order n_cols = ','.join( [str(s) for s in n_cols] ) txt += " f{order} = np.zeros( ({n_eq}, {n_cols}), dtype=np.float64 )\n".format(order=current_order,n_eq=len(equations), n_cols=n_cols ) for n in range(len(sols)): ndt = sols[n] l = ndt.list_nth_order_children(current_order) for nd in l: # here we compute indices where we write the derivatives indices = nd.compute_index_set(var_order) rhs = dyn_printer.doprint_numpy(nd.expr) i0 = indices[0] i_col_s = ','.join([str(nn) for nn in i0]) indices.remove(i0) i_col_s_ref = i_col_s txt += ' f{order}[{i_eq},{i_col}] = {value}\n'.format(order=current_order,i_eq=n,i_col=i_col_s,value=rhs) for ind in indices: i += 1 i_col_s = ','.join([str(nn) for nn in ind]) txt += ' f{order}[{i_eq},{i_col}] = f{order}[{i_eq},{i_col_ref}] \n'.format(order=current_order,i_eq = n,i_col=i_col_s,i_col_ref = i_col_s_ref) txt += " f.append(f{order})\n".format(order=current_order) txt += " return f\n" txt = txt.replace('^','**') if return_text: return txt else: return code_to_function(txt,'dynamic_function')
def compile_theano_source(values, args_list, args_names, parms, fname='anonymous_function'): """ :param vars: parameters :param values: list of values (already triangular) """ vars = ['_res_{}'.format(i) for i in range(len(values))] sub_dict = {} for e in vars: try: sn = e.safe_name() except Exception: sn = '_' + str(e) sub_dict[e] = sn from dolo.compiler.common import DicPrinter dec = '' for s in args_names: dec += "{} = T.matrix('{}')\n".format(s, s) dec += "p = T.vector('p')\n" for i, p in enumerate(parms): sn = '_' + str(p) sub_dict[p] = sn dec += '{} = p[{}]\n'.format(sn, i) for i, l in enumerate(args_list): name = args_names[i] for j, e in enumerate(l): try: sn = e.safe_name() except Exception: sn = '_' + str(e) sub_dict[e] = sn dec += '{} = {}[{},:]\n'.format(sn, name, j) dp = DicPrinter(sub_dict) strings = [] for i, eq in enumerate(values): rhs = (dp.doprint(eq)) lhs = vars[i] # strings.append( '{} = OO + {}'.format(lhs,rhs)) strings.append('{} = {}'.format(lhs, rhs)) source = """ from theano import tensor as T from theano import function from theano.tensor import exp {declarations} # OO = T.zeros((1,s.shape[1])) {computations} res = T.stack({vars}) f = function([{args}], res, mode='FAST_RUN',name="{fname}"{on_unused_input}) """ # print(args_names) source = source.format(computations=str.join('\n', strings), declarations=dec, vars=str.join(', ', [str(v) for v in vars]), args=str.join(', ', [str(v) for v in args_names] + ['p']), fname=fname, on_unused_input=",on_unused_input='ignore'" if not theano_less_than_6 else "") return source
def process_output_recs(self): '''Main function that formats the model in recs format''' import sympy from dolo.compiler.common import DicPrinter from dolo.misc.matlab import value_to_mat data = self.read_model() dmodel = self.model model = dmodel f_eqs = data['f_eqs'] g_eqs = data['g_eqs'] h_eqs = data['h_eqs'] hm_eqs = data['hm_eqs'] e_eqs = data['e_eqs'] states_vars = data['states_vars'] controls = data['controls'] exp_vars = data['exp_vars'] inf_bounds = data['inf_bounds'] sup_bounds = data['sup_bounds'] controls_f = [v(1) for v in controls] states_f = [v(1) for v in states_vars] sub_list = dict() for i, v in enumerate(exp_vars): sub_list[v] = 'z(:,{0})'.format(i + 1) for i, v in enumerate(controls): sub_list[v] = 'x(:,{0})'.format(i + 1) sub_list[v(1)] = 'xnext(:,{0})'.format(i + 1) for i, v in enumerate(states_vars): sub_list[v] = 's(:,{0})'.format(i + 1) sub_list[v(1)] = 'snext(:,{0})'.format(i + 1) for i, v in enumerate(dmodel.shocks): sub_list[v] = 'e(:,{0})'.format(i + 1) for i, v in enumerate(dmodel.parameters): sub_list[v] = 'p({0})'.format(i + 1) sub_list[sympy.Symbol('inf')] = 'inf' # Case h(s,x,e,sn,xn) text = '''function [out1,out2,out3,out4,out5] = {filename}(flag,s,x,z,e,snext,xnext,p,output) voidcell = cell(1,5); [out1,out2,out3,out4,out5] = voidcell{{:}}; switch flag case 'b' n = size(s,1); {eq_bounds_block} case 'f' n = size(s,1); {eq_fun_block} case 'g' n = size(s,1); {state_trans_block} case 'h' n = size(snext,1); {exp_fun_block} case 'e' n = size(s,1); {equation_error_block} case 'params' out1 = {model_params}; case 'ss' {model_ss} case 'J' {jac_struc} end''' # Case h(.,.,.,sn,xn)*hmult(e) textmult = '''function [out1,out2,out3,out4,out5,out6] = {filename}(flag,s,x,z,e,snext,xnext,p,output) voidcell = cell(1,6); [out1,out2,out3,out4,out5,out6] = voidcell{{:}}; switch flag case 'b' n = size(s,1); {eq_bounds_block} case 'f' n = size(s,1); {eq_fun_block} case 'g' n = size(s,1); {state_trans_block} case 'h' n = size(snext,1); {exp_fun_block} {exp_exp_mult_block} case 'e' n = size(s,1); {equation_error_block} case 'params' out1 = {model_params}; case 'ss' {model_ss} case 'J' {jac_struc} end''' dp = DicPrinter(sub_list) def write_eqs(eq_l, outname='out1', ntabs=0, default=None): '''Format equations and bounds''' if default: eq_block = ' ' * ntabs + '{0} = ' + default + '(n,{1});' eq_block = eq_block.format(outname, len(eq_l)) else: eq_block = ' ' * ntabs + '{0} = zeros(n,{1});'.format( outname, len(eq_l)) eq_template = '\n' + ' ' * ntabs + '{0}(:,{1}) = {2};' for i, eq in enumerate(eq_l): eq_txt = dp.doprint_matlab(eq, vectorize=True) if eq_txt != default: eq_block += eq_template.format(outname, i + 1, eq_txt) return eq_block def write_der_eqs(eq_l, v_l, lhs, ntabs=0): '''Format Jacobians''' eq_block = ' ' * ntabs + '{lhs} = zeros(n,{0},{1});' eq_block = eq_block.format(len(eq_l), len(v_l), lhs=lhs) eq_l_d = eqdiff(eq_l, v_l) eq_template = '\n' + ' ' * ntabs + '{lhs}(:,{0},{1}) = {2}; % d eq_{eq_n} w.r.t. {vname}' jac_struc = [[0 for i in range(len(v_l))] for j in range(len(eq_l))] for i, eqq in enumerate(eq_l_d): for j, eq in enumerate(eqq): s = dp.doprint_matlab(eq, vectorize=True) if s != '0': eq_block += eq_template.format(i + 1, j + 1, s, lhs=lhs, eq_n=i + 1, vname=str(v_l[j])) jac_struc[i][j] = 1 return [eq_block, jac_struc] eq_bounds_block = ''' % b {0} % db/ds if nargout==4 {1} {2} end''' eq_bounds_values = write_eqs(inf_bounds, ntabs=2, default='-inf') eq_bounds_values += '\n' eq_bounds_values += write_eqs(sup_bounds, 'out2', ntabs=2, default='inf') eq_bounds_jac_inf = write_der_eqs(inf_bounds, states_vars, 'out3', 3) eq_bounds_jac_sup = write_der_eqs(sup_bounds, states_vars, 'out4', 3) eq_bounds_block = eq_bounds_block.format(eq_bounds_values, eq_bounds_jac_inf[0], eq_bounds_jac_sup[0]) eq_f_block = ''' % f if output.F {0} end % df/ds if output.Js {1} end % df/dx if output.Jx {2} end % df/dz if output.Jz {3} end''' # eq_f_block = eq_f_block.format(write_eqs(f_eqs, 'out1', 3), # write_der_eqs(f_eqs, states_vars, 'out2', 3), # write_der_eqs(f_eqs, controls, 'out3', 3), # write_der_eqs(f_eqs, exp_vars, 'out4', 3)) df_ds = write_der_eqs(f_eqs, states_vars, 'out2', 3) df_dx = write_der_eqs(f_eqs, controls, 'out3', 3) df_dz = write_der_eqs(f_eqs, exp_vars, 'out4', 3) eq_f_block = eq_f_block.format(write_eqs(f_eqs, 'out1', 3), df_ds[0], df_dx[0], df_dz[0]) jac_struc = ' out1.fs = ' + list_to_mat(df_ds[1]) + ';\n' jac_struc += ' out1.fx = ' + list_to_mat(df_dx[1]) + ';\n' jac_struc += ' out1.fz = ' + list_to_mat(df_dz[1]) + ';\n' eq_g_block = ''' % g if output.F {0} end if output.Js {1} end if output.Jx {2} end''' # eq_g_block = eq_g_block.format(write_eqs(g_eqs, 'out1', 3), # write_der_eqs(g_eqs, states_vars, 'out2', 3), # write_der_eqs(g_eqs, controls, 'out3', 3)) dg_ds = write_der_eqs(g_eqs, states_vars, 'out2', 3) dg_dx = write_der_eqs(g_eqs, controls, 'out3', 3) eq_g_block = eq_g_block.format(write_eqs(g_eqs, 'out1', 3), dg_ds[0], dg_dx[0]) jac_struc += ' out1.gs = ' + list_to_mat(dg_ds[1]) + ';\n' jac_struc += ' out1.gx = ' + list_to_mat(dg_dx[1]) + ';\n' eq_h_block = ''' %h if output.F {0} end if output.Js {1} end if output.Jx {2} end if output.Jsn {3} end if output.Jxn {4} end''' # eq_h_block = eq_h_block.format(write_eqs(h_eqs, 'out1', 3), # write_der_eqs(h_eqs, states_vars, 'out2', 3), # write_der_eqs(h_eqs, controls, 'out3', 3), # write_der_eqs(h_eqs, states_f, 'out4', 3), # write_der_eqs(h_eqs, controls_f, 'out5', 3)) dh_ds = write_der_eqs(h_eqs, states_vars, 'out2', 3) dh_dx = write_der_eqs(h_eqs, controls, 'out3', 3) dh_ds_f = write_der_eqs(h_eqs, states_f, 'out4', 3) dh_dx_f = write_der_eqs(h_eqs, controls_f, 'out5', 3) eq_h_block = eq_h_block.format(write_eqs(h_eqs, 'out1', 3), dh_ds[0], dh_dx[0], dh_ds_f[0], dh_dx_f[0]) jac_struc += ' out1.hs = ' + list_to_mat(dh_ds[1]) + ';\n' jac_struc += ' out1.hx = ' + list_to_mat(dh_dx[1]) + ';\n' jac_struc += ' out1.hsnext = ' + list_to_mat(dh_ds_f[1]) + ';\n' jac_struc += ' out1.hxnext = ' + list_to_mat(dh_dx_f[1]) + ';\n' eq_hm_block = ''' % hmult if output.hmult {0} end''' eq_hm_block = eq_hm_block.format(write_eqs(hm_eqs, 'out6', 3)) if e_eqs: equation_error_block = write_eqs(e_eqs, 'out1', 3) else: equation_error_block = ''' out1 = [];''' # Model informations [y, x, params_values] = model.read_calibration() vvs = model.variables s_ss = [y[vvs.index(v)] for v in model['variables_groups']['states']] x_ss = [y[vvs.index(v)] for v in model['variables_groups']['controls']] model_ss = ''' out1 = {s_ss}; out2 = {x_ss};''' model_ss = model_ss.format(s_ss=value_to_mat(s_ss).replace(';', ''), x_ss=value_to_mat(x_ss).replace(';', '')) if hm_eqs: text = textmult.format(eq_bounds_block=eq_bounds_block, filename=model.fname, eq_fun_block=eq_f_block, state_trans_block=eq_g_block, exp_fun_block=eq_h_block, exp_exp_mult_block=eq_hm_block, equation_error_block=equation_error_block, model_params=value_to_mat(params_values), model_ss=model_ss, jac_struc=jac_struc) else: text = text.format(eq_bounds_block=eq_bounds_block, filename=model.fname, eq_fun_block=eq_f_block, state_trans_block=eq_g_block, exp_fun_block=eq_h_block, equation_error_block=equation_error_block, model_params=value_to_mat(params_values), model_ss=model_ss, jac_struc=jac_struc) return text
def compile_multiargument_function(equations, args_list, args_names, parms, fname='anonymous_function', diff=True, return_text=False, use_numexpr=False, order='rows'): """ :param equations: list of sympy expressions :param args_list: list of lists of symbols (e.g. [[a_1,a_2], [b_1,b_2]]) :param args_names: list of strings (['a','b'] :param parms: list of symbols to be used as parameters :param fname: name of the python function to be generated :param diff: include symbolic derivates in generated function :param vectorize: arguments are vectorized (not parameters) :param return_function: a python function f(a,b,p) where p is a vector of parameters and a, b, arrays :return: """ template = '{0}_{1}' declarations = "" sub_list = {} for i, args in enumerate(args_list): vec_name = args_names[i] for j, v in enumerate(args): sub_list[v] = template.format(vec_name, j) if order == 'rows': declarations += " {0}_{1} = {0}[{1},...]\n".format( vec_name, j) else: declarations += " {0}_{1} = {0}[:,{1}]\n".format( vec_name, j) for i, p in enumerate(parms): sub_list[p] = '{0}_{1}'.format('p', i) declarations += " {0}_{1} = {0}[{1}]\n".format('p', i) import sympy # TODO: construct a common list of symbol that should be understood everywhere sub_list[sympy.Symbol('inf')] = 'inf' text = ''' def {fname}({args_names}, {param_names}, derivs=False): import numpy as np from numpy import exp, log from numpy import sin, cos, tan from numpy import arcsin as asin from numpy import arccos as acos from numpy import arctan as atan from numpy import sinh, cosh, tanh from numpy import pi from numpy import inf {use_numexpr} {declarations} n = {var}.shape[{size}] {content} return {return_names} ''' from dolo.compiler.common import DicPrinter dp = DicPrinter(sub_list) def write_eqs(eq_l, outname='val'): if order == 'rows': eq_block = ' {0} = np.zeros( ({1},n) )\n'.format( outname, len(eq_l)) else: eq_block = ' {0} = np.zeros( (n,{1}) )\n'.format( outname, len(eq_l)) for i, eq in enumerate(eq_l): eq_string = dp.doprint_numpy(eq) if use_numexpr: if order == 'rows': eq_block += " {0}[{1},:] = numexpr.evaluate('{2}')\n".format( outname, i, eq_string) else: eq_block += " {0}[:,{1}] = numexpr.evaluate('{2}')\n".format( outname, i, eq_string) else: if order == 'rows': eq_block += ' {0}[{1},:] = {2}\n'.format( outname, i, eq_string) else: eq_block += ' {0}[:,{1}] = {2}\n'.format( outname, i, eq_string) return eq_block def write_der_eqs(eq_l, v_l, lhs): if order == 'rows': eq_block = ' {lhs} = np.zeros( ({0},{1},n) )\n'.format( len(eq_l), len(v_l), lhs=lhs) else: eq_block = ' {lhs} = np.zeros( (n,{0},{1}) )\n'.format( len(eq_l), len(v_l), lhs=lhs) eq_l_d = eqdiff(eq_l, v_l) for i, eqq in enumerate(eq_l_d): for j, eq in enumerate(eqq): if not eq == 0: if use_numexpr: eq_string = dp.doprint_numpy(eq) if order == 'rows': eq_block += " {lhs}[{0},{1},:] = numexpr.evaluate('{2}')\n".format( i, j, eq_string, lhs=lhs) else: eq_block += " {lhs}[:,{0},{1}] = numexpr.evaluate('{2}')\n".format( i, j, eq_string, lhs=lhs) else: eq_string = dp.doprint(eq) if order == 'rows': eq_block += " {lhs}[{0},{1},:] = {2}\n".format( i, j, eq_string, lhs=lhs) else: eq_block += " {lhs}[:,{0},{1}] = {2}\n".format( i, j, eq_string, lhs=lhs) return eq_block content = write_eqs(equations) content += ''' if not derivs: return val ''' if diff: for i, a_g in enumerate(args_list): lhs = 'val_' + args_names[i] content += "\n # Derivatives w.r.t: {0}\n\n".format( args_names[i]) content += write_der_eqs(equations, a_g, lhs) return_names = '[val, ' + str.join( ', ', ['val_' + str(a) for a in args_names]) + ']' if diff else 'val' text = text.format(size=-1 if order == 'rows' else 0, fname=fname, use_numexpr="import numexpr\n" if use_numexpr else "", declarations=declarations, var=args_names[0], content=content, return_names=return_names, args_names=str.join(', ', args_names), param_names='p') if return_text: return text return code_to_function(text, fname)
def compute_dynamic_mfile(self, max_order=2): print "Computing dynamic .m file at order {0}.".format(max_order) DerivativesTree.symbol_type = TSymbol model = self.model var_order = model.dyn_var_order + model.shocks # TODO create a log system t = [] t.append(time.time()) sols = [] i = 0 for eq in model.equations: i += 1 ndt = DerivativesTree(eq.gap) ndt.compute_nth_order_children(max_order) sols.append(ndt) t.append(time.time()) self.dynamic_derivatives = sols dyn_subs_dict = self.dynamic_substitution_list() dyn_printer = DicPrinter(dyn_subs_dict) txt = """function [residual, {gs}] = {fname}_dynamic(y, x, params, it_) % % Status : Computes dynamic model for Dynare % % Warning : this file is generated automatically by Dynare % from model file (.mod) % % Model equations % residual = zeros({neq}, 1); """ gs = str.join(", ", [("g" + str(i)) for i in range(1, (max_order + 1))]) txt = txt.format(gs=gs, fname=model.fname, neq=len(model.equations)) t.append(time.time()) for i in range(len(sols)): ndt = sols[i] eq = ndt.expr rhs = dyn_printer.doprint_matlab(eq) txt += " residual({0}) = {1};\n".format(i + 1, rhs) t.append(time.time()) for current_order in range(1, (max_order + 1)): if current_order == 1: matrix_name = "Jacobian" elif current_order == 2: matrix_name = "Hessian" else: matrix_name = "{0}_th order".format(current_order) txt += """ if nargout >= {orderr} % % {matrix_name} matrix % """.format( orderr=current_order + 1, matrix_name=matrix_name ) if current_order == 2: txt.format(matrix_name="Hessian") elif current_order == 1: txt.format(matrix_name="Jacobian") t.append(time.time()) nnzd = self.NNZDerivatives(current_order) if True: # we write full matrices ... txt += " v{order} = zeros({nnzd}, 3);\n".format(order=current_order, nnzd=nnzd) i = 0 for n in range(len(sols)): ndt = sols[n] l = ndt.list_nth_order_children(current_order) for nd in l: i += 1 # here we compute indices where we write the derivatives indices = nd.compute_index_set_matlab(var_order) rhs = dyn_printer.doprint_matlab(nd.expr) i0 = indices[0] indices.remove(i0) i_ref = i txt += " v{order}({i},:) = [{i_eq}, {i_col}, {value}] ;\n".format( order=current_order, i=i, i_eq=n + 1, i_col=i0, value=rhs ) for ind in indices: i += 1 txt += " v{order}({i},:) = [{i_eq}, {i_col}, v{order}({i_ref},3)];\n".format( order=current_order, i=i, i_eq=n + 1, i_col=ind, i_ref=i_ref ) txt += " g{order} = sparse(v{order}(:,1),v{order}(:,2),v{order}(:,3),{n_rows},{n_cols});\n".format( order=current_order, n_rows=len(model.equations), n_cols=len(var_order) ** current_order ) else: # ... or sparse matrices print "to be implemented" txt += """ end """ t.append(time.time()) f = file(model.fname + "_dynamic.m", "w") f.write(txt) f.close() return txt
def compile_multiargument_function(equations, args_list, args_names, parms, diff=False, fname='anonymous_function'): """ :param equations: list of sympy expressions :param args_list: list of lists of symbols (e.g. [[a_1,a_2], [b_1,b_2]]) :param args_names: list of strings (['a','b'] :param parms: list of symbols to be used as parameters :param fname: name of the python function to be generated :param diff: include symbolic derivates in generated function :param vectorize: arguments are vectorized (not parameters) :param return_function: the source of a Julia function f(a,b,p) where p is a vector of parameters and a, b, arrays :return: """ vectorize = True template = '{0}[:,{1}]' sub_list = {} for i, args in enumerate(args_list): vec_name = args_names[i] for j, v in enumerate(args): sub_list[v] = template.format(vec_name, j + 1) for i, p in enumerate(parms): sub_list[p] = '{0}[{1}]'.format('p', i + 1) import sympy sub_list[sympy.Symbol('inf')] = 'inf' text = ''' function {fname}({args_names}, {param_names}) n = size({var},1) {content} return {return_names} end ''' from dolo.compiler.common import DicPrinter dp = DicPrinter(sub_list) def write_eqs(eq_l, outname='val'): eq_block = ' {0} = zeros( n, {1} )\n'.format(outname, len(eq_l)) for i, eq in enumerate(eq_l): eq_block += ' {0}[:,{1}] = {2}\n'.format( outname, i + 1, dp.doprint_numpy(eq)) return eq_block def write_der_eqs(eq_l, v_l, lhs): eq_block = ' {lhs} = np.zeros( (n,{1},{0}) )\n'.format(len(eq_l), len(v_l), lhs=lhs) eq_l_d = eqdiff(eq_l, v_l) for i, eqq in enumerate(eq_l_d): for j, eq in enumerate(eqq): s = dp.doprint_numpy(eq) eq_block += ' {lhs}[:,{1},{0}] = {2}\n'.format(i + 1, j + 1, s, lhs=lhs) return eq_block content = write_eqs(equations) if diff: for i, a_g in enumerate(args_list): lhs = 'val_' + args_names[i] content += "\n # Derivatives w.r.t: {0}\n\n".format( args_names[i]) content += write_der_eqs(equations, a_g, lhs) return_names = '[val, ' + str.join( ', ', ['val_' + str(a) for a in args_names]) + ']' if diff else 'val' text = text.format(fname=fname, var=args_names[0], content=content, return_names=return_names, args_names=str.join(', ', args_names), param_names='p') text = text.replace('**', '.^') text = text.replace('*', '.*') text = text.replace('/', './') # text = text.replace('+','.+') # text = text.replace('-','.-') return text
def compute_static_mfile(self, max_order=1): print "Computing static .m file at order {0}.".format(max_order) DerivativesTree.symbol_type = Variable model = self.model var_order = model.variables # TODO create a log system sols = [] i = 0 for eq in model.equations: i += 1 l = [tv for tv in eq.atoms() if isinstance(tv, Variable)] expr = eq.gap for tv in l: if tv.lag != 0: expr = expr.subs(tv, tv.P) ndt = DerivativesTree(expr) ndt.compute_nth_order_children(max_order) sols.append(ndt) self.static_derivatives = sols stat_subs_dict = self.static_substitution_list() stat_printer = DicPrinter(stat_subs_dict) txt = """function [residual, {gs}] = {fname}_static(y, x, params, it_) % % Status : Computes static model for Dynare % % Warning : this file is generated automatically by Dynare % from model file (.mod) % % Model equations % residual = zeros({neq}, 1); """ gs = str.join(', ', [('g' + str(i)) for i in range(1, (max_order + 1))]) txt = txt.format(gs=gs, fname=model.fname, neq=len(model.equations)) for i in range(len(sols)): ndt = sols[i] eq = ndt.expr rhs = stat_printer.doprint_matlab(eq) txt += ' residual({0}) = {1};\n'.format(i + 1, rhs) for current_order in range(1, (max_order + 1)): if current_order == 1: matrix_name = "Jacobian" elif current_order == 2: matrix_name = "Hessian" else: matrix_name = "{0}_th order".format(current_order) txt += """ if nargout >= {orderr} g{order} = zeros({n_rows}, {n_cols}); % % {matrix_name} matrix % \n""".format(order=current_order, orderr=current_order + 1, n_rows=len(model.equations), n_cols=len(var_order)**current_order, matrix_name=matrix_name) if current_order == 2: txt.format(matrix_name="Hessian") # What is the equivalent of NNZ for static files ? nnzd = self.NNZStaticDerivatives(current_order) if True: for n in range(len(sols)): ndt = sols[n] l = ndt.list_nth_order_children(current_order) for nd in l: # here we compute indices where we write the derivatives indices = nd.compute_index_set_matlab(var_order) rhs = stat_printer.doprint_matlab(nd.expr) #rhs = comp.dyn_tabify_expression(nd.expr) i0 = indices[0] indices.remove(i0) txt += ' g{order}({0},{1}) = {2};\n'.format( n + 1, i0, rhs, order=current_order) for ind in indices: txt += ' g{order}({0},{1}) = g{order}({0},{2});\n'.format( n + 1, ind, i0, order=current_order) else: print 'to be implemented' txt += """ end """ f = file(model.fname + '_static.m', 'w') f.write(txt) f.close() return txt
def compute_dynamic_mfile(self, max_order=2): print "Computing dynamic .m file at order {0}.".format(max_order) DerivativesTree.symbol_type = TSymbol model = self.model var_order = model.dyn_var_order + model.shocks # TODO create a log system t = [] t.append(time.time()) sols = [] i = 0 for eq in model.equations: i += 1 ndt = DerivativesTree(eq.gap) ndt.compute_nth_order_children(max_order) sols.append(ndt) t.append(time.time()) self.dynamic_derivatives = sols dyn_subs_dict = self.dynamic_substitution_list() dyn_printer = DicPrinter(dyn_subs_dict) txt = """function [residual, {gs}] = {fname}_dynamic(y, x, params, it_) % % Status : Computes dynamic model for Dynare % % Warning : this file is generated automatically by Dynare % from model file (.mod) % % Model equations % residual = zeros({neq}, 1); """ gs = str.join(', ', [('g' + str(i)) for i in range(1, (max_order + 1))]) txt = txt.format(gs=gs, fname=model.fname, neq=len(model.equations)) t.append(time.time()) for i in range(len(sols)): ndt = sols[i] eq = ndt.expr rhs = dyn_printer.doprint_matlab(eq) txt += ' residual({0}) = {1};\n'.format(i + 1, rhs) t.append(time.time()) for current_order in range(1, (max_order + 1)): if current_order == 1: matrix_name = "Jacobian" elif current_order == 2: matrix_name = "Hessian" else: matrix_name = "{0}_th order".format(current_order) txt += """ if nargout >= {orderr} % % {matrix_name} matrix % """.format(orderr=current_order + 1, matrix_name=matrix_name) if current_order == 2: txt.format(matrix_name="Hessian") elif current_order == 1: txt.format(matrix_name="Jacobian") t.append(time.time()) nnzd = self.NNZDerivatives(current_order) if True: # we write full matrices ... txt += " v{order} = zeros({nnzd}, 3);\n".format( order=current_order, nnzd=nnzd) i = 0 for n in range(len(sols)): ndt = sols[n] l = ndt.list_nth_order_children(current_order) for nd in l: i += 1 # here we compute indices where we write the derivatives indices = nd.compute_index_set_matlab(var_order) rhs = dyn_printer.doprint_matlab(nd.expr) i0 = indices[0] indices.remove(i0) i_ref = i txt += ' v{order}({i},:) = [{i_eq}, {i_col}, {value}] ;\n'.format( order=current_order, i=i, i_eq=n + 1, i_col=i0, value=rhs) for ind in indices: i += 1 txt += ' v{order}({i},:) = [{i_eq}, {i_col}, v{order}({i_ref},3)];\n'.format( order=current_order, i=i, i_eq=n + 1, i_col=ind, i_ref=i_ref) txt += ' g{order} = sparse(v{order}(:,1),v{order}(:,2),v{order}(:,3),{n_rows},{n_cols});\n'.format( order=current_order, n_rows=len(model.equations), n_cols=len(var_order)**current_order) else: # ... or sparse matrices print 'to be implemented' txt += """ end """ t.append(time.time()) f = file(model.fname + '_dynamic.m', 'w') f.write(txt) f.close() return txt
def compute_main_file(self, omit_nnz=True): model = self.model # should be computed somewhere else all_symbols = set([]) for eq in model.equations: all_symbols.update(eq.atoms()) format_dict = dict() format_dict['fname'] = model.fname format_dict['maximum_lag'] = max( [-v.lag for v in all_symbols if isinstance(v, TSymbol)]) format_dict['maximum_lead'] = max( [v.lag for v in all_symbols if isinstance(v, TSymbol)]) format_dict['maximum_endo_lag'] = max( [-v.lag for v in all_symbols if isinstance(v, Variable)]) format_dict['maximum_endo_lead'] = max( [v.lag for v in all_symbols if isinstance(v, Variable)]) format_dict['maximum_exo_lag'] = max( [-v.lag for v in all_symbols if isinstance(v, Shock)]) format_dict['maximum_exo_lead'] = max( [v.lag for v in all_symbols if isinstance(v, Shock)]) format_dict['endo_nbr'] = len(model.variables) format_dict['exo_nbr'] = len(model.shocks) format_dict['param_nbr'] = len(model.parameters) output = """% % Status : main Dynare file % % Warning : this file is generated automatically by Dolo for Dynare % from model file (.mod) clear all tic; global M_ oo_ options_ global ys0_ ex0_ ct_ options_ = []; M_.fname = '{fname}'; % % Some global variables initialization % global_initialization; diary off; warning_old_state = warning; warning off; delete {fname}.log; warning warning_old_state; logname_ = '{fname}.log'; diary {fname}.log; options_.model_mode = 0; erase_compiled_function('{fname}_static'); erase_compiled_function('{fname}_dynamic'); M_.exo_det_nbr = 0; M_.exo_nbr = {exo_nbr}; M_.endo_nbr = {endo_nbr}; M_.param_nbr = {param_nbr}; M_.Sigma_e = zeros({exo_nbr}, {exo_nbr}); M_.exo_names_orig_ord = [1:{exo_nbr}]; """.format(**format_dict) string_of_names = lambda l: str.join(' , ', ["'%s'" % str(v) for v in l]) string_of_tex_names = lambda l: str.join( ' , ', ["'%s'" % v._latex_() for v in l]) output += "M_.exo_names = strvcat( {0} );\n".format( string_of_names(model.shocks)) output += "M_.exo_names_tex = strvcat( {0} );\n".format( string_of_tex_names(model.shocks)) output += "M_.endo_names = strvcat( {0} );\n".format( string_of_names(model.variables)) output += "M_.endo_names_tex = strvcat( {0} );\n".format( string_of_tex_names(model.variables)) output += "M_.param_names = strvcat( {0} );\n".format( string_of_names(model.parameters)) output += "M_.param_names_tex = strvcat( {0} );\n".format( string_of_tex_names(model.parameters)) from dolo.misc.matlab import value_to_mat lli = value_to_mat(self.lead_lag_incidence_matrix()) output += "M_.lead_lag_incidence = {0}';\n".format(lli) output += """M_.maximum_lag = {maximum_lag}; M_.maximum_lead = {maximum_lead}; M_.maximum_endo_lag = {maximum_endo_lag}; M_.maximum_endo_lead = {maximum_endo_lead}; M_.maximum_exo_lag = {maximum_exo_lag}; M_.maximum_exo_lead = {maximum_exo_lead}; oo_.steady_state = zeros({endo_nbr}, 1); oo_.exo_steady_state = zeros({exo_nbr}, 1); M_.params = repmat(NaN,{param_nbr}, 1); """.format(**format_dict) # Now we add tags for equations tags_array_string = [] for eq in model.equations: for k in eq.tags.keys(): tags_array_string.append("{n}, '{key}', '{value}'".format( n=eq.n, key=k, value=eq.tags[k])) output += "M_.equations_tags = {{\n{0}\n}};\n".format( ";\n".join(tags_array_string)) if not omit_nnz: # we don't set the number of non zero derivatives yet order = max([ndt.depth() for ndt in self.dynamic_derivatives]) output += "M_.NNZDerivatives = zeros({0}, 1); % parrot mode\n".format( order) output += "M_.NNZDerivatives(1) = {0}; % parrot mode\n".format( self.NNZDerivatives(1)) output += "M_.NNZDerivatives(2) = {0}; % parrot mode\n".format( self.NNZDerivatives(2)) output += "M_.NNZDerivatives(3) = {0}; % parrot mode\n".format( self.NNZDerivatives(3)) idp = DicPrinter( self.static_substitution_list(y='oo_.steady_state', params='M_.params')) # BUG: how do we treat parameters absent from the model, but present in parameters_values ? from dolo.misc.triangular_solver import solve_triangular_system [junk, porder] = solve_triangular_system(model.parameters_values) porder = [p for p in porder if p in model.parameters] d = dict() d.update(model.parameters_values) d.update(model.init_values) [junk, vorder] = solve_triangular_system(model.init_values) vorder = [v for v in vorder if p in model.variables] for p in porder: i = model.parameters.index(p) + 1 output += "M_.params({0}) = {1};\n".format( i, idp.doprint_matlab(model.parameters_values[p])) output += "{0} = M_.params({1});\n".format(p, i) output += '''% % INITVAL instructions % ''' #idp = DicPrinter(self.static_substitution_list(y='oo_.steady_state',params='M_.params')) output += "options_.initval_file = 0; % parrot mode\n" for v in vorder: if v in self.model.variables: # should be removed i = model.variables.index(v) + 1 output += "oo_.steady_state({0}) = {1};\n".format( i, idp.doprint_matlab(model.init_values[v])) # we don't allow initialization of shocks to nonzero values output += "oo_.exo_steady_state = zeros({0},1);\n".format( len(model.shocks)) output += '''oo_.endo_simul=[oo_.steady_state*ones(1,M_.maximum_lag)]; if M_.exo_nbr > 0; oo_.exo_simul = [ones(M_.maximum_lag,1)*oo_.exo_steady_state']; end; if M_.exo_det_nbr > 0; oo_.exo_det_simul = [ones(M_.maximum_lag,1)*oo_.exo_det_steady_state']; end; ''' #output += '''steady; output += """ % % SHOCKS instructions % make_ex_; M_.exo_det_length = 0; % parrot """ for i in range(model.covariances.shape[0]): for j in range(model.covariances.shape[1]): expr = model.covariances[i, j] if expr != 0: v = str(expr).replace("**", "^") #if (v != 0) and not isinstance(v,sympy.core.numbers.Zero): output += "M_.Sigma_e({0}, {1}) = {2};\n".format( i + 1, j + 1, v) # This results from the stoch_simul( # output += '''options_.drop = 200; #options_.order = 3; #var_list_=[]; #info = stoch_simul(var_list_); #''' # # output += '''save('example2_results.mat', 'oo_', 'M_', 'options_'); #diary off # #disp(['Total computing time : ' dynsec2hms(toc) ]);''' f = file(model.fname + '.m', 'w') f.write(output) f.close() return output
def static_tabify_expression(self, eq, for_matlab=False, for_c=True): #from dolo.misc.calculus import map_function_to_expression # works when all variables are expressed without lag subs_dict = self.static_substitution_list res = DicPrinter(subs_dict).doprint(eq)
def compute_static_pfile(self, max_order): DerivativesTree.symbol_type = Variable model = self.model var_order = model.variables # TODO create a log system sols = [] i = 0 for eq in model.equations: i += 1 l = [tv for tv in eq.atoms() if isinstance(tv, Variable)] expr = eq.gap for tv in l: if tv.lag != 0: expr = expr.subs(tv, tv.P) ndt = DerivativesTree(expr) ndt.compute_nth_order_children(max_order) sols.append(ndt) self.static_derivatives = sols stat_subs_dict = self.static_substitution_list(ind_0=0, brackets=True) stat_printer = DicPrinter(stat_subs_dict) txt = """def static_gaps(y, x, params): # # Status : Computes static model for Python # # Warning : this file is generated automatically by Dynare # from model file (.mod) # # # Model equations # import numpy as np from numpy import exp,log, sin, cos, tan, sinh, cosh, tanh from numpy import arcsin as asin from numpy import arccos as acos from numpy import arctan as atan it_ = 1 # should remove this ! g = [] residual = np.zeros({neq}) """ gs = str.join(", ", [("g" + str(i)) for i in range(1, (max_order + 1))]) txt = txt.format(gs=gs, fname=model.fname, neq=len(model.equations)) for i in range(len(sols)): ndt = sols[i] eq = ndt.expr rhs = stat_printer.doprint_matlab(eq) txt += " residual[{0}] = {1}\n".format(i, rhs) txt += " g.append(residual)\n" for current_order in range(1, (max_order + 1)): if current_order == 1: matrix_name = "Jacobian" elif current_order == 2: matrix_name = "Hessian" else: matrix_name = "{0}_th order".format(current_order) txt += """ g{order} = np.zeros(({n_rows}, {n_cols})) # {matrix_name} matrix\n""".format( order=current_order, orderr=current_order + 1, n_rows=len(model.equations), n_cols=len(var_order) ** current_order, matrix_name=matrix_name, ) for n in range(len(sols)): ndt = sols[n] l = ndt.list_nth_order_children(current_order) for nd in l: # here we compute indices where we write the derivatives indices = nd.compute_index_set_matlab(var_order) rhs = stat_printer.doprint_matlab(nd.expr) # rhs = comp.dyn_tabify_expression(nd.expr) i0 = indices[0] indices.remove(i0) txt += " g{order}[{0},{1}] = {2}\n".format(n, i0 - 1, rhs, order=current_order) for ind in indices: txt += " g{order}[{0},{1}] = g{order}[{0},{2}]\n".format( n, ind - 1, i0 - 1, order=current_order ) txt += " g.append(g{order})\n".format(order=current_order) txt += " return g\n" txt = txt.replace("^", "**") exec(txt) return static_gaps
def process_output_recs(self, solution_order=False, fname=None): data = self.read_model() dmodel = self.model model = dmodel f_eqs = data['f_eqs'] g_eqs = data['g_eqs'] h_eqs = data['h_eqs'] states_vars = data['states_vars'] controls = data['controls'] exp_vars = data['exp_vars'] inf_bounds = data['inf_bounds'] sup_bounds = data['sup_bounds'] controls_f = [v(1) for v in controls] states_f = [v(1) for v in states_vars] sub_list = dict() for i,v in enumerate(exp_vars): sub_list[v] = 'z(:,{0})'.format(i+1) for i,v in enumerate(controls): sub_list[v] = 'x(:,{0})'.format(i+1) sub_list[v(1)] = 'xnext(:,{0})'.format(i+1) for i,v in enumerate(states_vars): sub_list[v] = 's(:,{0})'.format(i+1) sub_list[v(1)] = 'snext(:,{0})'.format(i+1) for i,v in enumerate(dmodel.shocks): sub_list[v] = 'e(:,{0})'.format(i+1) for i,v in enumerate(dmodel.parameters): sub_list[v] = 'p({0})'.format(i+1) import sympy sub_list[sympy.Symbol('inf')] = 'Inf' text = '''function [out1,out2,out3,out4,out5] = {mfname}(flag,s,x,z,e,snext,xnext,p,out); output = struct('F',1,'Js',0,'Jx',0,'Jsn',0,'Jxn',0,'Jz',0,'hmult',0); if nargin == 9 output = catstruct(output,out); voidcell = cell(1,5); [out1,out2,out3,out4,out5] = voidcell{{:}}; else if nargout >= 2, output.Js = 1; end if nargout >= 3, output.Jx = 1; end if nargout >= 4 if strcmpi(flag, 'f') output.Jz = 1; else output.Jsn = 1; end end if nargout >= 5, output.Jxn = 1; end end switch flag case 'b'; n = size(s,1); {eq_bounds_block} case 'f'; n = size(s,1); {eq_fun_block} case 'g'; n = size(s,1); {state_trans_block} case 'h'; n = size(snext,1); {exp_fun_block} case 'e'; out1 = []; case 'model'; % informations about the model {model_info} end ''' from dolo.compiler.common import DicPrinter dp = DicPrinter(sub_list) def write_eqs(eq_l,outname='out1',ntabs=0): eq_block = ' ' * ntabs + '{0} = zeros(n,{1});'.format(outname,len(eq_l)) for i,eq in enumerate(eq_l): eq_block += '\n' + ' ' * ntabs + '{0}(:,{1}) = {2};'.format( outname, i+1, dp.doprint_matlab(eq,vectorize=True) ) return eq_block def write_der_eqs(eq_l,v_l,lhs,ntabs=0): eq_block = ' ' * ntabs + '{lhs} = zeros(n,{0},{1});'.format(len(eq_l),len(v_l),lhs=lhs) eq_l_d = eqdiff(eq_l,v_l) for i,eqq in enumerate(eq_l_d): for j,eq in enumerate(eqq): s = dp.doprint_matlab( eq, vectorize=True ) eq_block += '\n' + ' ' * ntabs + '{lhs}(:,{0},{1}) = {2}; % d eq_{eq_n} w.r.t. {vname}'.format(i+1,j+1,s,lhs=lhs,eq_n=i+1,vname=str(v_l[j]) ) return eq_block eq_bounds_block = write_eqs(inf_bounds,ntabs=2) eq_bounds_block += '\n' eq_bounds_block += write_eqs(sup_bounds,'out2',ntabs=2) eq_f_block = ''' % f if output.F {0} end % df/ds if output.Js {1} end % df/dx if output.Jx {2} end % df/dz if output.Jz {3} end '''.format( write_eqs(f_eqs,'out1',3), write_der_eqs(f_eqs,states_vars,'out2',3), write_der_eqs(f_eqs,controls,'out3',3), write_der_eqs(f_eqs,exp_vars,'out4',3) ) eq_g_block = ''' % g if output.F {0} end if output.Js {1} end if output.Jx {2} end '''.format( write_eqs(g_eqs,'out1',3), write_der_eqs(g_eqs,states_vars,'out2',3), write_der_eqs(g_eqs,controls,'out3',3) ) eq_h_block = ''' %h if output.F {0} end if output.Js {1} end if output.Jx {2} end if output.Jsn {3} end if output.Jxn {4} end '''.format( write_eqs(h_eqs,'out1',3), write_der_eqs(h_eqs,states_vars,'out2',3), write_der_eqs(h_eqs,controls,'out3',3), write_der_eqs(h_eqs,states_f,'out4',3), write_der_eqs(h_eqs,controls_f,'out5',3) ) # if not with_param_names: # eq_h_block = 's=snext;\nx=xnext;\n'+eq_h_block # param_def = 'p = [ ' + str.join(',',[p.name for p in dmodel.parameters]) + '];' from dolo.misc.matlab import value_to_mat # read model informations [y,x,params_values] = model.read_calibration() #params_values = '[' + str.join( ',', [ str( p ) for p in params] ) + '];' vvs = model.variables s_ss = [ y[vvs.index(v)] for v in model['variables_groups']['states'] ] x_ss = [ y[vvs.index(v)] for v in model['variables_groups']['controls'] ] model_info = ''' mod = struct; mod.s_ss = {s_ss}; mod.x_ss = {x_ss}; mod.params = {params_values}; '''.format( s_ss = value_to_mat(s_ss), x_ss = value_to_mat(x_ss), params_values = value_to_mat(params_values) ) if solution_order: from dolo.numeric.perturbations_to_states import approximate_controls ZZ = approximate_controls(self.model,order=solution_order) n_c = len(controls) ZZ = [np.array(e) for e in ZZ] ZZ = [e[:n_c,...] for e in ZZ] # keep only control vars. (x) not expectations (h) solution = " mod.X = cell({0},1);\n".format(len(ZZ)) for i,zz in enumerate(ZZ): solution += " mod.X{{{0}}} = {1};\n".format(i+1,value_to_mat(zz)) model_info += solution model_info += ' out1 = mod;\n' text = text.format( eq_bounds_block = eq_bounds_block, mfname = fname if fname else 'mf_' + model.fname, eq_fun_block=eq_f_block, state_trans_block=eq_g_block, exp_fun_block=eq_h_block, # solution = solution, model_info = model_info ) return text
def compute_main_file(self, omit_nnz=True): model = self.model # should be computed somewhere else all_symbols = set([]) for eq in model.equations: all_symbols.update(eq.atoms()) format_dict = dict() format_dict["fname"] = model.fname format_dict["maximum_lag"] = max([-v.lag for v in all_symbols if isinstance(v, TSymbol)]) format_dict["maximum_lead"] = max([v.lag for v in all_symbols if isinstance(v, TSymbol)]) format_dict["maximum_endo_lag"] = max([-v.lag for v in all_symbols if isinstance(v, Variable)]) format_dict["maximum_endo_lead"] = max([v.lag for v in all_symbols if isinstance(v, Variable)]) format_dict["maximum_exo_lag"] = max([-v.lag for v in all_symbols if isinstance(v, Shock)]) format_dict["maximum_exo_lead"] = max([v.lag for v in all_symbols if isinstance(v, Shock)]) format_dict["endo_nbr"] = len(model.variables) format_dict["exo_nbr"] = len(model.shocks) format_dict["param_nbr"] = len(model.parameters) output = """% % Status : main Dynare file % % Warning : this file is generated automatically by Dolo for Dynare % from model file (.mod) clear all tic; global M_ oo_ options_ global ys0_ ex0_ ct_ options_ = []; M_.fname = '{fname}'; % % Some global variables initialization % global_initialization; diary off; warning_old_state = warning; warning off; delete {fname}.log; warning warning_old_state; logname_ = '{fname}.log'; diary {fname}.log; options_.model_mode = 0; erase_compiled_function('{fname}_static'); erase_compiled_function('{fname}_dynamic'); M_.exo_det_nbr = 0; M_.exo_nbr = {exo_nbr}; M_.endo_nbr = {endo_nbr}; M_.param_nbr = {param_nbr}; M_.Sigma_e = zeros({exo_nbr}, {exo_nbr}); M_.exo_names_orig_ord = [1:{exo_nbr}]; """.format( **format_dict ) string_of_names = lambda l: str.join(" , ", ["'%s'" % str(v) for v in l]) string_of_tex_names = lambda l: str.join(" , ", ["'%s'" % v._latex_() for v in l]) output += "M_.exo_names = strvcat( {0} );\n".format(string_of_names(model.shocks)) output += "M_.exo_names_tex = strvcat( {0} );\n".format(string_of_tex_names(model.shocks)) output += "M_.endo_names = strvcat( {0} );\n".format(string_of_names(model.variables)) output += "M_.endo_names_tex = strvcat( {0} );\n".format(string_of_tex_names(model.variables)) output += "M_.param_names = strvcat( {0} );\n".format(string_of_names(model.parameters)) output += "M_.param_names_tex = strvcat( {0} );\n".format(string_of_tex_names(model.parameters)) from dolo.misc.matlab import value_to_mat lli = value_to_mat(self.lead_lag_incidence_matrix()) output += "M_.lead_lag_incidence = {0}';\n".format(lli) output += """M_.maximum_lag = {maximum_lag}; M_.maximum_lead = {maximum_lead}; M_.maximum_endo_lag = {maximum_endo_lag}; M_.maximum_endo_lead = {maximum_endo_lead}; M_.maximum_exo_lag = {maximum_exo_lag}; M_.maximum_exo_lead = {maximum_exo_lead}; oo_.steady_state = zeros({endo_nbr}, 1); oo_.exo_steady_state = zeros({exo_nbr}, 1); M_.params = repmat(NaN,{param_nbr}, 1); """.format( **format_dict ) # Now we add tags for equations tags_array_string = [] for eq in model.equations: for k in eq.tags.keys(): tags_array_string.append("{n}, '{key}', '{value}'".format(n=eq.n, key=k, value=eq.tags[k])) output += "M_.equations_tags = {{\n{0}\n}};\n".format(";\n".join(tags_array_string)) if not omit_nnz: # we don't set the number of non zero derivatives yet order = max([ndt.depth() for ndt in self.dynamic_derivatives]) output += "M_.NNZDerivatives = zeros({0}, 1); % parrot mode\n".format(order) output += "M_.NNZDerivatives(1) = {0}; % parrot mode\n".format(self.NNZDerivatives(1)) output += "M_.NNZDerivatives(2) = {0}; % parrot mode\n".format(self.NNZDerivatives(2)) output += "M_.NNZDerivatives(3) = {0}; % parrot mode\n".format(self.NNZDerivatives(3)) idp = DicPrinter(self.static_substitution_list(y="oo_.steady_state", params="M_.params")) # BUG: how do we treat parameters absent from the model, but present in parameters_values ? from dolo.misc.triangular_solver import solve_triangular_system [junk, porder] = solve_triangular_system(model.parameters_values) porder = [p for p in porder if p in model.parameters] d = dict() d.update(model.parameters_values) d.update(model.init_values) [junk, vorder] = solve_triangular_system(model.init_values) vorder = [v for v in vorder if p in model.variables] for p in porder: i = model.parameters.index(p) + 1 output += "M_.params({0}) = {1};\n".format(i, idp.doprint_matlab(model.parameters_values[p])) output += "{0} = M_.params({1});\n".format(p, i) output += """% % INITVAL instructions % """ # idp = DicPrinter(self.static_substitution_list(y='oo_.steady_state',params='M_.params')) output += "options_.initval_file = 0; % parrot mode\n" for v in vorder: if v in self.model.variables: # should be removed i = model.variables.index(v) + 1 output += "oo_.steady_state({0}) = {1};\n".format(i, idp.doprint_matlab(model.init_values[v])) # we don't allow initialization of shocks to nonzero values output += "oo_.exo_steady_state = zeros({0},1);\n".format(len(model.shocks)) output += """oo_.endo_simul=[oo_.steady_state*ones(1,M_.maximum_lag)]; if M_.exo_nbr > 0; oo_.exo_simul = [ones(M_.maximum_lag,1)*oo_.exo_steady_state']; end; if M_.exo_det_nbr > 0; oo_.exo_det_simul = [ones(M_.maximum_lag,1)*oo_.exo_det_steady_state']; end; """ # output += '''steady; output += """ % % SHOCKS instructions % make_ex_; M_.exo_det_length = 0; % parrot """ for i in range(model.covariances.shape[0]): for j in range(model.covariances.shape[1]): expr = model.covariances[i, j] if expr != 0: v = str(expr).replace("**", "^") # if (v != 0) and not isinstance(v,sympy.core.numbers.Zero): output += "M_.Sigma_e({0}, {1}) = {2};\n".format(i + 1, j + 1, v) # This results from the stoch_simul( # output += '''options_.drop = 200; # options_.order = 3; # var_list_=[]; # info = stoch_simul(var_list_); #''' # # output += '''save('example2_results.mat', 'oo_', 'M_', 'options_'); # diary off # # disp(['Total computing time : ' dynsec2hms(toc) ]);''' f = file(model.fname + ".m", "w") f.write(output) f.close() return output
def compile_theano_source(values, args_list, args_names, parms, fname='anonymous_function'): """ :param vars: parameters :param values: list of values (already triangular) """ vars = ['_res_{}'.format(i) for i in range(len(values))] sub_dict = {} for e in vars: try: sn = e.safe_name() except Exception: sn = '_'+str(e) sub_dict[e] = sn from dolo.compiler.common import DicPrinter dec = '' for s in args_names: dec += "{} = T.matrix('{}')\n".format(s,s) dec += "p = T.vector('p')\n" for i,p in enumerate(parms): sn = '_'+str(p) sub_dict[p] = sn dec += '{} = p[{}]\n'.format(sn,i) for i, l in enumerate( args_list): name = args_names[i] for j, e in enumerate(l): try: sn = e.safe_name() except Exception: sn = '_'+str(e) sub_dict[e] = sn dec += '{} = {}[{},:]\n'.format(sn,name,j) dp = DicPrinter(sub_dict) strings = [ ] for i,eq in enumerate( values ): rhs = ( dp.doprint( eq) ) lhs = vars[i] # strings.append( '{} = OO + {}'.format(lhs,rhs)) strings.append( '{} = {}'.format(lhs,rhs)) source = """ from theano import tensor as T from theano import function from theano.tensor import exp {declarations} # OO = T.zeros((1,s.shape[1])) {computations} res = T.stack({vars}) f = function([{args}], res, mode='FAST_RUN',name="{fname}"{on_unused_input}) """ # print(args_names) source = source.format( computations = str.join( '\n', strings), declarations = dec, vars = str.join(', ', [str(v) for v in vars]), args = str.join(', ', [str(v) for v in args_names] + ['p'] ), fname = fname, on_unused_input = ",on_unused_input='ignore'" if not theano_less_than_6 else "" ) return source
def compute_static_mfile(self, max_order=1): print "Computing static .m file at order {0}.".format(max_order) DerivativesTree.symbol_type = Variable model = self.model var_order = model.variables # TODO create a log system sols = [] i = 0 for eq in model.equations: i += 1 l = [tv for tv in eq.atoms() if isinstance(tv, Variable)] expr = eq.gap for tv in l: if tv.lag != 0: expr = expr.subs(tv, tv.P) ndt = DerivativesTree(expr) ndt.compute_nth_order_children(max_order) sols.append(ndt) self.static_derivatives = sols stat_subs_dict = self.static_substitution_list() stat_printer = DicPrinter(stat_subs_dict) txt = """function [residual, {gs}] = {fname}_static(y, x, params, it_) % % Status : Computes static model for Dynare % % Warning : this file is generated automatically by Dynare % from model file (.mod) % % Model equations % residual = zeros({neq}, 1); """ gs = str.join(", ", [("g" + str(i)) for i in range(1, (max_order + 1))]) txt = txt.format(gs=gs, fname=model.fname, neq=len(model.equations)) for i in range(len(sols)): ndt = sols[i] eq = ndt.expr rhs = stat_printer.doprint_matlab(eq) txt += " residual({0}) = {1};\n".format(i + 1, rhs) for current_order in range(1, (max_order + 1)): if current_order == 1: matrix_name = "Jacobian" elif current_order == 2: matrix_name = "Hessian" else: matrix_name = "{0}_th order".format(current_order) txt += """ if nargout >= {orderr} g{order} = zeros({n_rows}, {n_cols}); % % {matrix_name} matrix % \n""".format( order=current_order, orderr=current_order + 1, n_rows=len(model.equations), n_cols=len(var_order) ** current_order, matrix_name=matrix_name, ) if current_order == 2: txt.format(matrix_name="Hessian") # What is the equivalent of NNZ for static files ? nnzd = self.NNZStaticDerivatives(current_order) if True: for n in range(len(sols)): ndt = sols[n] l = ndt.list_nth_order_children(current_order) for nd in l: # here we compute indices where we write the derivatives indices = nd.compute_index_set_matlab(var_order) rhs = stat_printer.doprint_matlab(nd.expr) # rhs = comp.dyn_tabify_expression(nd.expr) i0 = indices[0] indices.remove(i0) txt += " g{order}({0},{1}) = {2};\n".format(n + 1, i0, rhs, order=current_order) for ind in indices: txt += " g{order}({0},{1}) = g{order}({0},{2});\n".format( n + 1, ind, i0, order=current_order ) else: print "to be implemented" txt += """ end """ f = file(model.fname + "_static.m", "w") f.write(txt) f.close() return txt
def compile_multiargument_function(equations, args_list, args_names, parms, fname='anonymous_function', diff=True, return_text=False, order='columns'): """ :param equations: list of sympy expressions :param args_list: list of lists of symbols (e.g. [[a_1,a_2], [b_1,b_2]]) :param args_names: list of strings (['a','b'] :param parms: list of symbols to be used as parameters :param fname: name of the python function to be generated :param diff: include symbolic derivates in generated function :param vectorize: arguments are vectorized (not parameters) :param return_function: a python function f(a,b,p) where p is a vector of parameters and a, b, arrays :return: """ if order == 'rows': raise (Exception('not implemented')) template = '{0}[i,{1}]' declarations = "" sub_list = {} for i, args in enumerate(args_list): vec_name = args_names[i] for j, v in enumerate(args): sub_list[v] = template.format(vec_name, j) # declarations += " {0}_{1} = {0}[{1}]\n".format(vec_name, j) for i, p in enumerate(parms): sub_list[p] = '{0}[{1}]'.format('p', i) # declarations += " {0}_{1} = {0}[{1}]\n".format('p', i) import sympy # TODO: construct a common list of symbol that should be understood everywhere sub_list[sympy.Symbol('inf')] = 'inf' args_size = [len(e) for e in args_list] + [len(parms)] return_size = len(equations) size_same_as_output = args_size.index(return_size) signature = str.join(',', ['(n{})'.format(i) for i in range(len(args_size))]) signature += '->(n{})'.format(return_size - 1) argtypes = [float64[:, :]] * (len(args_size) - 1) + [ float64[:], float64[:, :] ] text = ''' from numbapro import float64, void from numbapro import jit from numbapro import cuda @jit( argtypes={argtypes}, target='gpu' ) def {fname}({args_names}, {param_names}, val): i = cuda.grid(1) {content} # return val ''' from dolo.compiler.common import DicPrinter dp = DicPrinter(sub_list) def write_eqs(eq_l, outname='val'): eq_block = '' for i, eq in enumerate(eq_l): eq_string = dp.doprint_numpy(eq) eq_block += ' val[i,{0}] = {1}\n'.format(i, eq_string) return eq_block content = write_eqs(equations) return_names = 'val' text = text.format( fname=fname, n_equations=len(equations), declarations=declarations, var=args_names[0], content=content, return_names=return_names, args_names=str.join(', ', args_names), param_names='p', argtypes=str(argtypes), signature=signature, ) if return_text: return text print(args_list) return code_to_function(text, fname, args_size, return_size, size_same_as_output)
def compile_function(equations, args, parms, max_order, return_text=False): """ :param equations: :param args: :param parms: :param max_order: :param return_function: :return: """ var_order = args sols = [] for eq in equations: ndt = DerivativesTree(eq, ref_var_list=var_order) ndt.compute_nth_order_children(max_order) sols.append(ndt) dyn_subs_dict = dict() for i, v in enumerate(args): dyn_subs_dict[v] = 'x_' + str(i) for i, p in enumerate(parms): dyn_subs_dict[p] = 'p_' + str(i) preamble_l = [ ' x_{i} = x[{i}] # {v}'.format(i=i, v=v) for i, v in enumerate(args) ] preamble_l += [ ' p_{i} = p[{i}] # {p}'.format(i=i, p=p) for i, p in enumerate(parms) ] preamble = str.join('\n', preamble_l) dyn_printer = DicPrinter(dyn_subs_dict) txt = """def dynamic_function(x, p): # # # import numpy as np from numpy import exp, log from numpy import sin, cos, tan from numpy import arcsin as asin from numpy import arccos as acos from numpy import arctan as atan from numpy import sinh, cosh, tanh from numpy import pi {preamble} f = [] residual = np.zeros({neq},dtype=np.float64); """ gs = str.join(', ', [('f' + str(i)) for i in range(1, (max_order + 1))]) txt = txt.format(gs=gs, fname='noname', neq=len(equations), preamble=preamble) for i in range(len(sols)): ndt = sols[i] eq = ndt.expr rhs = dyn_printer.doprint_numpy(eq) txt += ' residual[{0}] = {1}\n'.format(i, rhs) txt += ' f.append(residual)\n' for current_order in range(1, (max_order + 1)): if current_order == 1: matrix_name = "Jacobian" elif current_order == 2: matrix_name = "Hessian" else: matrix_name = "{0}_th order".format(current_order) txt += """ # # {matrix_name} matrix # """.format(orderr=current_order + 1, matrix_name=matrix_name) if current_order == 2: txt.format(matrix_name="Hessian") elif current_order == 1: txt.format(matrix_name="Jacobian") #nnzd = self.NNZDerivatives(current_order) n_cols = (len(var_order), ) * current_order n_cols = ','.join([str(s) for s in n_cols]) txt += " f{order} = np.zeros( ({n_eq}, {n_cols}), dtype=np.float64 )\n".format( order=current_order, n_eq=len(equations), n_cols=n_cols) for n in range(len(sols)): ndt = sols[n] l = ndt.list_nth_order_children(current_order) for nd in l: # here we compute indices where we write the derivatives indices = nd.compute_index_set(var_order) rhs = dyn_printer.doprint_numpy(nd.expr) i0 = indices[0] i_col_s = ','.join([str(nn) for nn in i0]) indices.remove(i0) i_col_s_ref = i_col_s txt += ' f{order}[{i_eq},{i_col}] = {value}\n'.format( order=current_order, i_eq=n, i_col=i_col_s, value=rhs) for ind in indices: i += 1 i_col_s = ','.join([str(nn) for nn in ind]) txt += ' f{order}[{i_eq},{i_col}] = f{order}[{i_eq},{i_col_ref}] \n'.format( order=current_order, i_eq=n, i_col=i_col_s, i_col_ref=i_col_s_ref) txt += " f.append(f{order})\n".format(order=current_order) txt += " return f\n" txt = txt.replace('^', '**') if return_text: return txt else: return code_to_function(txt, 'dynamic_function')
def compile_multiargument_function(equations, args_list, args_names, parms, fname='anonymous_function', diff=True, return_text=False, use_numexpr=False, order='columns'): """ :param equations: list of sympy expressions :param args_list: list of lists of symbols (e.g. [[a_1,a_2], [b_1,b_2]]) :param args_names: list of strings (['a','b'] :param parms: list of symbols to be used as parameters :param fname: name of the python function to be generated :param diff: include symbolic derivates in generated function :param vectorize: arguments are vectorized (not parameters) :param return_function: a python function f(a,b,p) where p is a vector of parameters and a, b, arrays :return: """ if order == 'rows': raise (Exception('not implemented')) template = '{0}[{1}]' declarations = "" sub_list = {} for i, args in enumerate(args_list): vec_name = args_names[i] for j, v in enumerate(args): sub_list[v] = template.format(vec_name, j) # declarations += " {0}_{1} = {0}[{1}]\n".format(vec_name, j) for i, p in enumerate(parms): sub_list[p] = '{0}[{1}]'.format('p', i) # declarations += " {0}_{1} = {0}[{1}]\n".format('p', i) import sympy # TODO: construct a common list of symbol that should be understood everywhere sub_list[sympy.Symbol('inf')] = 'inf' text = ''' from numpy import zeros from numpy import exp, log from numpy import sin, cos, tan from numpy import arcsin as asin from numpy import arccos as acos from numpy import arctan as atan from numpy import sinh, cosh, tanh from numpy import pi from numpy import inf def {fname}({args_names}, {param_names}, val): val = zeros({n_equations}) {content} return val ''' from dolo.compiler.common import DicPrinter dp = DicPrinter(sub_list) def write_eqs(eq_l, outname='val'): eq_block = '' for i, eq in enumerate(eq_l): eq_string = dp.doprint_numpy(eq) eq_block += ' val[{0}] = {1}\n'.format(i, eq_string) return eq_block content = write_eqs(equations) return_names = 'val' text = text.format(fname=fname, n_equations=len(equations), declarations=declarations, var=args_names[0], content=content, return_names=return_names, args_names=str.join(', ', args_names), param_names='p') if return_text: return text args_size = [len(e) for e in args_list] + [len(parms)] return_size = len(equations) return code_to_function(text, fname, args_size, return_size)