def match_view_within_type(self, tx_type, view): """ Utilize children_of_type method from textX module to return all elements that match textX type defined in view starting from root tx_type. :param tx_type: root tx_type to start searching from :param view: defined view for contained textX type that should be found within element of tx_type :return: / """ children = children_of_type(view.name, tx_type) conditional_parent = view.__getattribute__('conditional_parent') if conditional_parent is None: for child in children: self.elements.update(self.build_graph_element(child, view)) # follow condition of defined parent properties else: elements_of_type = children_of_type(conditional_parent.name, self.model) for parent in elements_of_type: for child in children: if self.item_contains_property_by_structure( view.class_properties, parent, child): self.elements.update( self.build_graph_element(child, view))
def validate(model): """ Generator specific validation of ER models. Throws ValidationError if there is an error in the model. """ for ent in children_of_type(model, "Entity"): without_dbcols = set() dbcols = set() for attr in children_of_type(ent, "Attribute"): if attr.name in dbcols: raise ValidationError( "In '{}.{}'. '{}' already defined.".format( ent.name, attr.name, attr.name)) if is_entity_ref(attr) and get_constraint(attr, "dbcols") is None: target_entity_name = attr_type(attr).name if target_entity_name in without_dbcols and \ len(pk_attrs(attr_type(attr))) > 1: raise ValidationError( "While validating '{}.{}'. Multiple references to the " "same target Entity '{}' without 'dbcols' definition.". format(ent.name, attr.name, target_entity_name)) without_dbcols.add(target_entity_name) dbcols_constr = get_constraint(attr, "dbcols") if dbcols_constr: for p in dbcols_constr.parameters: if p in dbcols: raise ValidationError( 'In "{}.{}" dbcols. "{}" already defined.'.format( ent.name, attr.name, p)) dbcols.add(p)
def get_optimize_table(self, root, macro_table): code = "" ions = [[x.r[0].reads[0].name, x.w[0].writes[0].name] for x in children_of_type('UseIon', root)] params = [x.name for x in children_of_type('Range', root)[0].ranges] +\ children_of_type('Nonspecific', root)[0].nonspecifics +\ [x.name for x in children_of_type('State', root)[0].state_vars] +\ ['v', 'g'] +\ reduce(lambda x, y: x+y, ions) # if we have ordered table, then we use it first # then add the remainings at the end if macro_table: code = "" for i in range(len(macro_table)): code += "static double opt_table{0}"\ "[BUFFER_SIZE * MAX_NTHREADS][{1}];\n"\ .format(i, len(macro_table[i])) for j in range(len(macro_table[i])): code += "#define TABLE_{0}(x) "\ "opt_table{1}[(x)][{2}]\n"\ .format(macro_table[i][j].upper(), i, j) if macro_table[i][j] in params: params.remove(macro_table[i][j]) for param in params: code += "static double _{0}_table[BUFFER_SIZE * MAX_NTHREADS];\n"\ .format(param) return code
def obtain_link_table(self, root): ions = [[x.r[0].reads[0].name, x.w[0].writes[0].name] for x in children_of_type('UseIon', root)] return [x.name for x in children_of_type('Range', root)[0].ranges] +\ children_of_type('Nonspecific', root)[0].nonspecifics +\ [x.name for x in children_of_type('State', root)[0].state_vars] +\ reduce(lambda x, y: x+y, ions) +\ ['v', 'g']
def add_block_bodies(self, model, metamodel): # derivative blocks for dx in children_of_type('Derivative', model): self.process_block(dx) # append function body for every function/procedure call for fc in children_of_type('FuncCall', model): if fc.func.user: self.process_user_func(fc)
def get_initlists(self, root): code = "" cnt = 0 for state in children_of_type('State', root)[0].state_vars: code += "\t_slist1[{0}] = &({1}) - _p;\n"\ "\t_dlist1[{0}] = &(D{1}) - _p;\n"\ .format(cnt, state.name) cnt += 1 for param in children_of_type('Global', root)[0].globals: code += "\t_t_{0} = makevector(201 * sizeof(double));\n"\ .format(param.name) return code
def test_kaxon(mm): blocks = mm.model_from_file(get_sample('123815_Kaxon.mod')).blocks (units, neuron, indep, parameter, state, assigned, initial, breakpoint) = blocks[:8] suf = children_of_type('Suffix', neuron)[0] assert suf.suffix == 'Kaxon' sol = children_of_type('Solve', breakpoint)[0] assert sol.solve.name == 'states' assert len(state.state_vars) == 1 assert state.state_vars[0].name == 'n'
def test_children_of_type(): metamodel = metamodel_from_str(grammar) model = metamodel.model_from_str(model_str) thirds = children_of_type('Third', model) assert len(thirds) == 5 assert set(['first', 'second', 'third', 'one', 'two']) \ == set([a.x for a in thirds]) # Test search in the part of the model thirds = children_of_type("Third", model.a[1]) assert len(thirds) == 1 assert 'two' == list(thirds)[0].x
def ent_elements(ent): """ For the given entity returns all columns and relationships. Columns are deduced from ER attributes and * references to this entity following rules outlined in Notes.org. """ elements = [] fk_constraints = [] # Add columns and relationships introduced by external references. for e in children_of_type(model_root(ent), "Entity"): if e is ent: continue for attr in children_of_type(e, "Attribute"): if attr_type(attr) is ent: cols = columns(ent, attr) elements.extend(cols) if len(cols) > 1: fk_constraints.append( ForeignKeyConstraint(name="fk_{}_{}".format( dbname(ent), attr.name), fk_columns=cols)) if cols: elements.append(rel(ent, attr)) # Add columns and relationships from the direct attributes for attr in children_of_type(ent, "Attribute"): cols = columns(ent, attr) elements.extend(cols) if is_entity_ref(attr): if cols: elements.append(rel(ent, attr)) if len(cols) > 1: fk_constraints.append( ForeignKeyConstraint(name="fk_{}_{}".format( dbname(ent), attr.name), fk_columns=cols)) # Check that elements names are unique enames = set() for e in elements: if e.name in enames: raise ValidationError( 'In "{}" class. Attribute "{}" exists.'.format( ent.name, e.name)) enames.add(e.name) return elements, fk_constraints
def get_mechanism(self, root): code = "\t\"{0}\",\n"\ "\t\"{1}\",\n"\ .format(self.version, self.filename) for parm in children_of_type('Range', root)[0].ranges: code += "\t\"{0}_{1}\",\n"\ .format(parm.name, self.filename) for parm in children_of_type('Nonspecific', root)[0].nonspecifics: code += "\t\"{0}_{1}\",\n"\ .format(parm, self.filename) for parm in children_of_type('State', root)[0].state_vars: code += "\t\"{0}_{1}\",\n"\ .format(parm.name, self.filename) code += "\t0" return code
def get_initialize_table(self, root): code = "" params = \ [x.name for x in children_of_type('ParDef', root)] +\ [x.name for x in children_of_type('State', root)[0].state_vars] +\ ['v'] for param in params: code += "\t\t{0}_table[_iml] = {0};\n"\ .format(param) ions = [[x.r[0].reads[0].name, x.w[0].writes[0].name] for x in children_of_type('UseIon', root)] for ion in children_of_type('UseIon', root): code += "\t\t{0}_table[_iml] = _ion_{0};\n"\ .format(ion.r[0].reads[0].name) return code
def get_define_params(self, root): code = "" cnt = 0 ions = [[x.r[0].reads[0].name, x.w[0].writes[0].name] for x in children_of_type('UseIon', root)] params = [x.name for x in children_of_type('Range', root)[0].ranges] +\ children_of_type('Nonspecific', root)[0].nonspecifics +\ [x.name for x in children_of_type('State', root)[0].state_vars] +\ ["D{0}".format(x.name) for x in children_of_type('State', root)[0].state_vars] +\ reduce(lambda x, y: x+y, ions) +\ ['v', '_g'] for param in params: code += "#define {0} _p[{1}]\n".format(param, cnt) cnt += 1 return code
def test_multiple_locals(): p = """ PARAMETER { v (mV) } STATE { n } FUNCTION alpha(x)(/ms){ LOCAL a a = 0.1 if(fabs(x) > a){ alpha=a*x/(1-exp(-x)) }else{ alpha=a/(1-0.5*x) } } DERIVATIVE dn { LOCAL a a = 10 n' = alpha((v + 55)/a)} """ blocks = mm.model_from_str(p).blocks (parameter, state, alpha, dn) = blocks locals_in_alpha = children_of_type('Local', alpha) alpha_a = locals_in_alpha[0] alpha_x = alpha.pars[0] assert refs_in(alpha)[0].var == alpha_a # _a_ = 0.1 assert refs_in(alpha)[1].var == alpha_x # fabs(_x_) > a assert refs_in(alpha)[2].var == alpha_a # fabs(x) > _a_ assert refs_in(alpha)[3].var == alpha # _alpha_=a*x/(1-exp(-x)) assert refs_in(alpha)[4].var == alpha_a # alpha=_a_*x/(1-exp(-x)) assert refs_in(alpha)[5].var == alpha_x # alpha=a*_x_/(1-exp(-x))
def process_block(self, root, context={}): import functools def asgn_var(asgn): return functools.reduce(getattr, [asgn, 'variable', 'var']) def inner_asgns(x): return (a for a in children_of_type('Assignment', x) if a.variable) # handle if blocks separately (cond deriv vars) nonif_asgns = (a for a in inner_asgns(root) if not parent_of_type('IfStatement', a)) for asgn in nonif_asgns: self.L.dv(asgn.variable.lems.format(**context), asgn.expression.lems.format(**context)) # paired if/else assignements for ifst in children_of_type('IfStatement', root): ift_asgns = {asgn_var(a): a for a in inner_asgns(ifst.true_blk)} iff_asgns = {asgn_var(a): a for a in inner_asgns(ifst.false_blk)} for var in ift_asgns.keys() ^ iff_asgns.keys(): asgn = ift_asgns.get(var, iff_asgns.get(var)) self.L.dv(asgn.variable.lems.format(**context), asgn.expression.lems.format(**context)) for var in ift_asgns.keys() & iff_asgns.keys(): tasgn = ift_asgns[var] fasgn = iff_asgns[var] self.L.cdv(tasgn.variable.lems.format(**context), ifst.cond.lems.format(**context), tasgn.expression.lems.format(**context), fasgn.expression.lems.format(**context))
def test_initial(): nrn = ''' INITIAL { tadj = q10^((celsius - temp)/(10 (degC))) trates(v+vshift) m = minf h = hinf SOLVE ks STEADYSTATE sparse } ''' init = mm.model_from_str(nrn) tadk, proc, m0, h0, solve = init.b.stmts fcall = children_of_type('FuncCall', proc)[0] assert (fcall.func.user.name == 'trates') assert (children_of_type('VarRef', h0.expression)[0].var.name == 'hinf')
def get_restruct_table(self, root): code = "\tfor(_iml = 0; _iml < TABLE_SIZE; _iml++) {\n" for param in children_of_type('Global', root)[0].globals: code += "\t\tTABLE_{0}(_iml) = _t_{1}[_iml];\n"\ .format(param.name.upper(), param.name) code += "\t}\n" return code
def process_user_func(self, func_call, scope={}): # nested funcs need to access parent scope for arg passing # (if scope is present, it is being processed from the parent) # aux_vars are also inherited from parents if parent_of_type('FuncDef', func_call) and not scope: return args = [] # handle expressions in args that became aux variables for arg in func_call.args: try: args.append(func_call.aux_vars[arg.lems]) except KeyError: args.append(arg.lems) fun = func_call.func.user arg_val = dict(zip([p.name for p in fun.pars], args)) if scope: for val, arg in arg_val.items(): arg_val[val] = arg.format(**scope) for val, aux_var in func_call.aux_vars.items(): if aux_var not in self.generated_aux: self.L.dv(aux_var, val.format(**arg_val, **scope)) self.generated_aux.append(aux_var) # if the function being called calls other funcs, process them for cfc in children_of_type('FuncCall', fun): if cfc.func.user: # catch funcs and procedures, not builtins self.process_user_func(cfc, arg_val) if args not in fun.visited_with_args: self.process_block(fun, arg_val) fun.visited_with_args.append(args)
def get_param_size(self, root): """ " Param size equals to sum of followings, " Range parameter ex. gnabar, gkbar " Non specific current ex. il " ion (read / write) ex. ena, ina " state (original + differencial) ex. m, dm " common variable? (TODO: make sure what is this) v, _g """ param_size = \ len(children_of_type('Range', root)[0].ranges) + \ len(children_of_type('Nonspecific', root)[0].nonspecifics) + \ len(children_of_type('UseIon', root)) * 2 + \ len(children_of_type('State', root)[0].state_vars) * 2 + \ + 2 return "{0}".format(param_size)
def get_n_rates_global(self, root): code = "" for param in children_of_type('Global', root)[0].globals: code +=\ "\t{0} = _t_{0}[_i] + _theta * (_t_{0}[_i+1] - _t_{0}[_i]);\n"\ .format(param.name) return code
def entity_processor(ent): """ Validates entities. """ # Check constraints for c in ent.constraints: if not c.type.applies_to_entity: raise TextXSemanticError('In Entity "{}". Constraint "{}" can not ' 'be applied to Entity.'.format( ent.name, c.type.name)) # Collect all referenced entities without other side attr name spec. referenced_entities = set() attr_names = set() for attr in children_of_type(ent, "Attribute"): if is_entity_ref(attr): if not attr.ref or not attr.ref.other_side: if id(attr_type(attr)) in referenced_entities: raise TextXSemanticError( 'In entity "{}". Multiple references to Entity "{}" ' 'without other side ' 'attr name specification. Specify other side name ' 'using "<->" syntax.'.format( parent_entity(attr).name, attr_type(attr).name)) referenced_entities.add(id(attr_type(attr))) if attr.name in attr_names: raise TextXSemanticError( 'Attribute "{}" defined more than once for' ' entity {}.'.format(attr.name, ent.name)) attr_names.add(attr.name)
def get_hoc_global_param(self, root): code = "" for param in children_of_type('Global', root)[0].globals: code += "\t\"{0}_{1}\", &{0}_{1},\n"\ .format(param.name, self.filename) code += "\t\"usetable_{0}\", &usetable_{0},\n"\ "\t0, 0"\ .format(self.filename) return code
def get_hoc_parm_units(self, root): code = "" for assigned in children_of_type('Assigned', root)[0].assigneds: if assigned.unit: unit = assigned.unit unit = unit.replace('(', '') unit = unit.replace(')', '') code += "\t\"{0}_{1}\", \"{2}\",\n"\ .format(assigned.name, self.filename, unit) for param in children_of_type('Parameter', root)[0].parameters: if param.unit: unit = param.unit unit = unit.replace('(', '') unit = unit.replace(')', '') code += "\t\"{0}_{1}\", \"{2}\",\n"\ .format(param.name, self.filename, unit) code += "\t0,0" return code
def side_effects(funcdef): if funcdef.is_procedure: side_effs = [ asgn.variable.name for asgn in children_of_type('Assignment', funcdef) if is_assignment(asgn) and not isinstance(asgn.variable, 'Local') ] else: side_effs = [] return side_effs
def get_define_global_param(self, root): cnt = 0 code = "#define _gth 0\n" for param in children_of_type('Global', root)[0].globals: code += "#define {0}_{1} _thread1data[{2}]\n"\ "#define {0} _thread[_gth]._pval[{2}]\n"\ .format(param.name, self.filename, cnt) cnt += 1 code += "#define usetable usetable_{0}\n".format(self.filename) return code
def add_block_bodies(self, model, metamodel): # append function body for every function call for fc in children_of_type('FuncCall', model): if fc.func.user: args = [a.lems for a in fc.args] fun = fc.func.user arg_val = dict(zip([p.name for p in fun.pars], args)) if args not in fun.visited_with_args: self.process_block(fun, arg_val) fun.visited_with_args.append(args)
def test_scoping(): p = """ PARAMETER { v (mV) } STATE { x } INITIAL { LOCAL v v = 10 x = -v : v is local } FUNCTION f(v) { if(2 > 1){ LOCAL v v = 123 f = v : v is local } else{ f = -v : v is funcpar } } DERIVATIVE dx { x' = f(x) + v : v is par } """ blocks = mm.model_from_str(p).blocks (parameter, state, initial, function_f, derivative) = blocks locals_in_init = children_of_type('Local', initial) assert refs_in(initial)[0].var == locals_in_init[0] locals_in_function_f = children_of_type('Local', function_f) assert refs_in(function_f)[0].var == locals_in_function_f[0] assert refs_in(function_f)[2].var == locals_in_function_f[0] assert type(refs_in(function_f)[-1].var).__name__ == 'FuncPar' assert refs_in(derivative)[-1].var == parameter.parameters[0]
def get_nrn_update_ion_pointer(self, root): code = "" cnt = 0 for ion in children_of_type('UseIon', root): code += "\tnrn_update_ion_pointer(_{0}_sym, _ppvar, {1}, 0);\n"\ "\tnrn_update_ion_pointer(_{0}_sym, _ppvar, {2}, 3);\n"\ "\tnrn_update_ion_pointer(_{0}_sym, _ppvar, {3}, 4);\n"\ .format(ion.ion, cnt * 3, cnt * 3 + 1, cnt * 3 + 2) cnt += 1 return code
def test_solvableblock(): s = """ { SOLVE states ina = gnabar*m*h*(v - ena) ik = gkbar*n*(v - ek) il = gl*(v - el) } """ block = mm.model_from_str(s) solve, ina, ik, il = block.stmts assert solve.solve.name == 'states' assert children_of_type('VarRef', ina)[0].var.name == 'ina'
def test_derivative(): nrn = """ DERIVATIVE states { trates(v+vshift) m' = (minf-m)/mtau h' = (hinf-h)/htau } """ deriv = mm.model_from_str(nrn) assert (deriv.name == 'states') expr, mprime, hprime = deriv.b.stmts fcall = children_of_type('FuncCall', expr)[0] assert (fcall.func.user.name == 'trates') assert (mprime.variable == 'm')
def handle_varref(self, ref): def populate_global_scope(root): self.global_scope = children_of_type('StateVariable', root) +\ children_of_type('ParDef', root) +\ children_of_type('AssignedDef', root) +\ children_of_type('ConstDef', root) def enclosing_block(node): return parent_of_type('Block', node) or \ parent_of_type('SolvableBlock', node) def enclosing_func(node): return parent_of_type('FuncDef', ref) def block_locals(blk): locs = [] # children_of_type recurses into children, we don't want that for stmt in blk.stmts: if type(stmt).__name__ == 'Locals': locs.extend(stmt.vars) return locs if getattr(self, 'global_scope', None) is None: populate_global_scope(model_root(ref)) # this whole logic is inneficient, scopes should be built only once! # but we want to do it along with other obj processors (which come # before any model processing) found = 0 block_chain = [] # pun intended blk = enclosing_block(ref) while blk: block_chain += block_locals(blk) blk = enclosing_block(blk) scopes = [ block_chain, children_of_type('FuncPar', enclosing_func(ref)), self.global_scope ] for scope in scopes: for var in scope: if var.name == ref.var.name: ref.var = var found = True break if found: break