def codeprint(code): if isinstance(code, str): print deindent(code) else: for k, v in code.items(): print k+':' print indent(deindent(v))
def code_object(self, owner, name, abstract_code, variables, template_name, variable_indices, codeobj_class=None, template_kwds=None, override_conditional_write=None, compiler_kwds=None): if compiler_kwds is None: compiler_kwds = {} name = find_name(name) codeobj_class = self.code_object_class(codeobj_class) template = getattr(codeobj_class.templater, template_name) iterate_all = template.iterate_all generator = codeobj_class.generator_class(variables=variables, variable_indices=variable_indices, owner=owner, iterate_all=iterate_all, codeobj_class=codeobj_class, override_conditional_write=override_conditional_write, allows_scalar_write=template.allows_scalar_write, name=name, template_name=template_name) if template_kwds is None: template_kwds = dict() else: template_kwds = template_kwds.copy() logger.diagnostic('%s abstract code:\n%s' % (name, indent(code_representation(abstract_code)))) scalar_code, vector_code, kwds = generator.translate(abstract_code, dtype=prefs['core.default_float_dtype']) # Add the array names as keywords as well for varname, var in variables.items(): if isinstance(var, ArrayVariable): pointer_name = generator.get_array_name(var) if var.scalar: pointer_name += '[0]' template_kwds[varname] = pointer_name if hasattr(var, 'resize'): dyn_array_name = generator.get_array_name(var, access_data=False) template_kwds['_dynamic_'+varname] = dyn_array_name template_kwds.update(kwds) logger.diagnostic('%s snippet (scalar):\n%s' % (name, indent(code_representation(scalar_code)))) logger.diagnostic('%s snippet (vector):\n%s' % (name, indent(code_representation(vector_code)))) code = template(scalar_code, vector_code, owner=owner, variables=variables, codeobj_name=name, variable_indices=variable_indices, get_array_name=generator.get_array_name, **template_kwds) logger.diagnostic('%s code:\n%s' % (name, indent(code_representation(code)))) codeobj = codeobj_class(owner, code, variables, variable_indices, template_name=template_name, template_source=template.template_source, name=name, compiler_kwds=compiler_kwds) codeobj.compile() return codeobj
def code_object(self, owner, name, abstract_code, variables, template_name, variable_indices, codeobj_class=None, template_kwds=None, override_conditional_write=None, compiler_kwds=None): if compiler_kwds is None: compiler_kwds = {} name = find_name(name) codeobj_class = self.code_object_class(codeobj_class) template = getattr(codeobj_class.templater, template_name) iterate_all = template.iterate_all generator = codeobj_class.generator_class(variables=variables, variable_indices=variable_indices, owner=owner, iterate_all=iterate_all, codeobj_class=codeobj_class, override_conditional_write=override_conditional_write, allows_scalar_write=template.allows_scalar_write, name=name, template_name=template_name) if template_kwds is None: template_kwds = dict() else: template_kwds = template_kwds.copy() logger.diagnostic('%s abstract code:\n%s' % (name, indent(code_representation(abstract_code)))) scalar_code, vector_code, kwds = generator.translate(abstract_code, dtype=prefs['core.default_float_dtype']) # Add the array names as keywords as well for varname, var in variables.iteritems(): if isinstance(var, ArrayVariable): pointer_name = generator.get_array_name(var) if var.scalar: pointer_name += '[0]' template_kwds[varname] = pointer_name if hasattr(var, 'resize'): dyn_array_name = generator.get_array_name(var, access_data=False) template_kwds['_dynamic_'+varname] = dyn_array_name template_kwds.update(kwds) logger.diagnostic('%s snippet (scalar):\n%s' % (name, indent(code_representation(scalar_code)))) logger.diagnostic('%s snippet (vector):\n%s' % (name, indent(code_representation(vector_code)))) code = template(scalar_code, vector_code, owner=owner, variables=variables, codeobj_name=name, variable_indices=variable_indices, get_array_name=generator.get_array_name, **template_kwds) logger.diagnostic('%s code:\n%s' % (name, indent(code_representation(code)))) codeobj = codeobj_class(owner, code, variables, variable_indices, template_name=template_name, template_source=template.template_source, name=name, compiler_kwds=compiler_kwds) codeobj.compile() return codeobj
def vectorise_code(self, statements, variables, variable_indices, index='_idx'): # We treat every statement individually with its own read and write code # to be on the safe side lines = [] created_vars = {stmt.var for stmt in statements if stmt.op == ':='} for statement in statements: lines.append('# Abstract code: {var} {op} {expr}'.format(var=statement.var, op=statement.op, expr=statement.expr)) read, write, indices, conditional_write_vars = self.arrays_helper([statement]) try: # We make sure that we only add code to `lines` after it went # through completely ufunc_lines = [] # No need to load a variable if it is only in read because of # the in-place operation if (statement.inplace and variable_indices[statement.var] != '_idx' and statement.var not in get_identifiers(statement.expr)): read = read - {statement.var} ufunc_lines.extend(self.read_arrays(read, write, indices, variables, variable_indices)) ufunc_lines.append(self.ufunc_at_vectorisation(statement, variables, variable_indices, conditional_write_vars, created_vars, index=index)) # Do not write back such values, the ufuncs have modified the # underlying array already if statement.inplace and variable_indices[statement.var] != '_idx': write = write - {statement.var} ufunc_lines.extend(self.write_arrays([statement], read, write, variables, variable_indices)) lines.extend(ufunc_lines) except VectorisationError: logger.warn("Failed to vectorise synapses code, falling back on Python loop: note that " "this will be very slow! Switch to another code generation target for " "best performance (e.g. cython or weave).", once=True) lines.extend(['_full_idx = _idx', 'for _idx in _full_idx:']) lines.extend(indent(code) for code in self.read_arrays(read, write, indices, variables, variable_indices)) line = self.translate_statement(statement) line = self.conditional_write(line, statement, variables, conditional_write_vars, created_vars) lines.append(indent(line)) lines.extend(indent(code) for code in self.write_arrays(statements, read, write, variables, variable_indices)) lines.append('_idx = _full_idx') return lines
def translate_one_statement_sequence(self, statements, scalar=False): variables = self.variables variable_indices = self.variable_indices read, write, indices, conditional_write_vars = self.arrays_helper(statements) lines = [] # index and read arrays (index arrays first) for varname in itertools.chain(indices, read): var = variables[varname] index = variable_indices[varname] line = '{varname} = {arrayname}[{index}]'.format(varname=varname, arrayname=self.get_array_name(var), index=index) lines.append(line) # the actual code created_vars = set([]) for stmt in statements: if stmt.op==':=': created_vars.add(stmt.var) line = self.translate_statement(stmt) if stmt.var in conditional_write_vars: subs = {} condvar = conditional_write_vars[stmt.var] lines.append('if %s:' % condvar) lines.append(indent(line)) else: lines.append(line) # write arrays for varname in write: index_var = self.variable_indices[varname] var = self.variables[varname] line = self.get_array_name(var, self.variables) + '[' + index_var + '] = ' + varname lines.append(line) return lines
def translate_one_statement_sequence(self, statements, scalar=False): variables = self.variables variable_indices = self.variable_indices read, write, indices, conditional_write_vars = self.arrays_helper(statements) lines = [] # index and read arrays (index arrays first) for varname in itertools.chain(indices, read): var = variables[varname] index = variable_indices[varname] line = '{varname} = {arrayname}[{index}]'.format(varname=varname, arrayname=self.get_array_name(var), index=index) lines.append(line) # the actual code for stmt in statements: if stmt.op == ':=' and not stmt.var in variables: self.temporary_vars.add((stmt.var, stmt.dtype)) line = self.translate_statement(stmt) if stmt.var in conditional_write_vars: subs = {} condvar = conditional_write_vars[stmt.var] lines.append('if %s:' % condvar) lines.append(indent(line)) else: lines.append(line) # write arrays for varname in write: index_var = self.variable_indices[varname] var = self.variables[varname] line = self.get_array_name(var, self.variables) + '[' + index_var + '] = ' + varname lines.append(line) return lines
def numerically_check_permutation_code(code): # numerically checks that a code block used in the test below is permutation-independent by creating a # presynaptic and postsynaptic group of 3 neurons each, and a full connectivity matrix between them, then # repeatedly filling in random values for each of the variables, and checking for several random shuffles of # the synapse order that the result doesn't depend on it. This is a sort of test of the test itself, to make # sure we didn't accidentally assign a good/bad example to the wrong class. code = deindent(code) from collections import defaultdict vars = get_identifiers(code) indices = defaultdict(lambda: '_idx') vals = {} for var in vars: if var.endswith('_syn'): indices[var] = '_idx' vals[var] = zeros(9) elif var.endswith('_pre'): indices[var] ='_presynaptic_idx' vals[var] = zeros(3) elif var.endswith('_post'): indices[var] = '_postsynaptic_idx' vals[var] = zeros(3) subs = dict((var, var+'['+idx+']') for var, idx in indices.iteritems()) code = word_substitute(code, subs) code = ''' from numpy import * from numpy.random import rand, randn for _idx in shuffled_indices: _presynaptic_idx = presyn[_idx] _postsynaptic_idx = postsyn[_idx] {code} '''.format(code=indent(code)) ns = vals.copy() ns['shuffled_indices'] = arange(9) ns['presyn'] = arange(9)%3 ns['postsyn'] = arange(9)/3 for _ in xrange(10): origvals = {} for k, v in vals.iteritems(): v[:] = randn(len(v)) origvals[k] = v.copy() exec code in ns endvals = {} for k, v in vals.iteritems(): endvals[k] = v.copy() for _ in xrange(10): for k, v in vals.iteritems(): v[:] = origvals[k] shuffle(ns['shuffled_indices']) exec code in ns for k, v in vals.iteritems(): try: assert_allclose(v, endvals[k]) except AssertionError: raise OrderDependenceError()
def _get_documentation(self): s = '' for name in sorted(self._values.keys()): default = self._default_values[name] doc = str(self._docs[name]) # Make a link target s += '.. _brian-pref-{name}:\n\n'.format(name=name.replace('_', '-')) s += '``{name}`` = ``{default}``\n'.format(name=name, default=repr(default)) s += indent(deindent(doc)) s += '\n\n' return s
def translate_to_statements(self, statements, conditional_write_vars): lines = [] for stmt in statements: if stmt.op == ':=' and not stmt.var in self.variables: self.temporary_vars.add((stmt.var, stmt.dtype)) line = self.translate_statement(stmt) if stmt.var in conditional_write_vars: subs = {} condvar = conditional_write_vars[stmt.var] lines.append('if %s:' % condvar) lines.append(indent(line)) else: lines.append(line) return lines
def translate_to_statements(self, statements, conditional_write_vars): lines = [] for stmt in statements: if stmt.op == ':=' and not stmt.var in self.variables: self.temporary_vars.add((stmt.var, stmt.dtype)) line = self.translate_statement(stmt) if stmt.var in conditional_write_vars: subs = {} condvar = conditional_write_vars[stmt.var] lines.append(f'if {condvar}:') lines.append(indent(line)) else: lines.append(line) return lines
def _get_one_documentation(self, basename, link_targets): ''' Document a single category of preferences. ''' s = '' if not basename in self.pref_register: raise ValueError('No preferences under the name "%s" are registered' % basename) prefdefs, basedoc = self.pref_register[basename] s += deindent(basedoc, docstring=True).strip() + '\n\n' for name in sorted(prefdefs.keys()): pref = prefdefs[name] name = basename + '.' + name linkname = name.replace('_', '-').replace('.', '-') if link_targets: # Make a link target s += '.. _brian-pref-{name}:\n\n'.format(name=linkname) s += '``{name}`` = ``{default}``\n'.format(name=name, default=pref.representor(pref.default)) s += indent(deindent(pref.docs, docstring=True)) s += '\n\n' return s
def exceptions(self): exc_list = [] for configuration in self.configurations: curconfig = [] for ft in self.feature_tests: sym, txt, exc, tb = self.full_results[configuration.name, ft.fullname()] if tb is not None: curconfig.append((ft.fullname(), tb)) if len(curconfig): exc_list.append((configuration.name, curconfig)) if len(exc_list)==0: return '' r = '' s = 'Exceptions' r += s+'\n'+'-'*len(s)+'\n\n' for config_name, curconfig in exc_list: s = config_name r += s+'\n'+'^'*len(s)+'\n\n' for name, tb in curconfig: r += name+'::\n\n'+indent(tb)+'\n\n' return r
def exceptions(self): exc_list = [] for configuration in self.configurations: curconfig = [] for ft in self.feature_tests: sym, txt, exc, tb, runtime, prof_info = self.full_results[ configuration.name, ft.fullname()] if tb is not None: curconfig.append((ft.fullname(), tb)) if len(curconfig): exc_list.append((configuration.name, curconfig)) if len(exc_list) == 0: return '' r = '' s = 'Exceptions' r += s + '\n' + '-' * len(s) + '\n\n' for config_name, curconfig in exc_list: s = config_name r += s + '\n' + '^' * len(s) + '\n\n' for name, tb in curconfig: r += name + '::\n\n' + indent(tb) + '\n\n' return r
def _get_one_documentation(self, basename, link_targets): """ Document a single category of preferences. """ s = '' if not basename in self.pref_register: raise ValueError( f"No preferences under the name '{basename}' are registered") prefdefs, basedoc = self.pref_register[basename] s += deindent(basedoc, docstring=True).strip() + '\n\n' for name in sorted(prefdefs.keys()): pref = prefdefs[name] name = basename + '.' + name linkname = name.replace('_', '-').replace('.', '-') if link_targets: # Make a link target s += f".. _brian-pref-{linkname}:\n\n" s += f"``{name}`` = ``{pref.representor(pref.default)}``\n" s += indent(deindent(pref.docs, docstring=True)) s += "\n\n" return s
def apply_code_template(code, template, placeholder='%CODE%'): ''' Inserts the string ``code`` into ``template`` at ``placeholder``. The ``code`` is deindented, and inserted into ``template`` with the indentation level at the place where ``placeholder`` appears. The placeholder should appear on its own line. All tab characters are replaced by four spaces. ''' code = deindent(code) code = strip_empty_lines(code) template = template.replace('\t', ' '*4) lines = template.split('\n') newlines = [] for line in lines: if placeholder in line: indentlevel = len(line)-len(line.lstrip()) newlines.append(indent(code, indentlevel, tab=' ')) else: newlines.append(line) return '\n'.join(newlines)
def code_object(self, owner, name, abstract_code, variables, template_name, variable_indices, codeobj_class=None, template_kwds=None, override_conditional_write=None): codeobj_class = self.code_object_class(codeobj_class) template = getattr(codeobj_class.templater, template_name) iterate_all = template.iterate_all generator = codeobj_class.generator_class(variables=variables, variable_indices=variable_indices, owner=owner, iterate_all=iterate_all, codeobj_class=codeobj_class, override_conditional_write=override_conditional_write, allows_scalar_write=template.allows_scalar_write, name=name, template_name=template_name) if template_kwds is None: template_kwds = dict() else: template_kwds = template_kwds.copy() # Check that all functions are available for varname, value in variables.iteritems(): if isinstance(value, Function): try: value.implementations[codeobj_class] except KeyError as ex: # if we are dealing with numpy, add the default implementation if codeobj_class is NumpyCodeObject: value.implementations.add_numpy_implementation(value.pyfunc) else: raise NotImplementedError(('Cannot use function ' '%s: %s') % (varname, ex)) logger.diagnostic('%s abstract code:\n%s' % (name, indent(code_representation(abstract_code)))) scalar_code, vector_code, kwds = generator.translate(abstract_code, dtype=prefs['core.default_float_dtype']) # Add the array names as keywords as well for varname, var in variables.iteritems(): if isinstance(var, ArrayVariable): pointer_name = generator.get_array_name(var) if var.scalar: pointer_name += '[0]' template_kwds[varname] = pointer_name if hasattr(var, 'resize'): dyn_array_name = generator.get_array_name(var, access_data=False) template_kwds['_dynamic_'+varname] = dyn_array_name template_kwds.update(kwds) logger.diagnostic('%s snippet (scalar):\n%s' % (name, indent(code_representation(scalar_code)))) logger.diagnostic('%s snippet (vector):\n%s' % (name, indent(code_representation(vector_code)))) name = find_name(name) code = template(scalar_code, vector_code, owner=owner, variables=variables, codeobj_name=name, variable_indices=variable_indices, get_array_name=generator.get_array_name, **template_kwds) logger.diagnostic('%s code:\n%s' % (name, indent(code_representation(code)))) codeobj = codeobj_class(owner, code, variables, variable_indices, template_name=template_name, template_source=template.template_source, name=name) codeobj.compile() return codeobj
def vectorise_code(self, statements, variables, variable_indices, index='_idx'): created_vars = {stmt.var for stmt in statements if stmt.op == ':='} try: lines = [] used_variables = set() for statement in statements: lines.append('# Abstract code: {var} {op} {expr}'.format( var=statement.var, op=statement.op, expr=statement.expr)) # We treat every statement individually with its own read and write code # to be on the safe side read, write, indices, conditional_write_vars = self.arrays_helper( [statement]) # We make sure that we only add code to `lines` after it went # through completely ufunc_lines = [] # No need to load a variable if it is only in read because of # the in-place operation if (statement.inplace and variable_indices[statement.var] != '_idx' and statement.var not in get_identifiers(statement.expr)): read = read - {statement.var} ufunc_lines.extend( self.read_arrays(read, write, indices, variables, variable_indices)) ufunc_lines.append( self.ufunc_at_vectorisation( statement, variables, variable_indices, conditional_write_vars, created_vars, used_variables, )) # Do not write back such values, the ufuncs have modified the # underlying array already if statement.inplace and variable_indices[ statement.var] != '_idx': write = write - {statement.var} ufunc_lines.extend( self.write_arrays([statement], read, write, variables, variable_indices)) lines.extend(ufunc_lines) except VectorisationError: if self._use_ufunc_at_vectorisation: logger.info( "Failed to vectorise code, falling back on Python loop: note that " "this will be very slow! Switch to another code generation target for " "best performance (e.g. cython). First line is: " + str(statements[0]), once=True) lines = [] lines.extend([ '_full_idx = _idx', 'for _idx in _full_idx:', ' _vectorisation_idx = _idx' ]) read, write, indices, conditional_write_vars = self.arrays_helper( statements) lines.extend( indent(code) for code in self.read_arrays( read, write, indices, variables, variable_indices)) for statement in statements: line = self.translate_statement(statement) if statement.var in conditional_write_vars: lines.append( indent('if {}:'.format( conditional_write_vars[statement.var]))) lines.append(indent(line, 2)) else: lines.append(indent(line)) lines.extend( indent(code) for code in self.write_arrays( statements, read, write, variables, variable_indices)) return lines
code = ''' _tmp_V = x V += _tmp_V*x*dt ''' specifiers = { 'V':ArrayVariable('_array_V', '_neuron_idx', float64), 'I':ArrayVariable('_array_I', '_neuron_idx', float64), 'x':Subexpression('-(V+I)/tau'), 'tau':Value(float64), 'dt':Value(float64), '_cond':OutputVariable(bool), #'_neuron_idx':Index(), '_neuron_idx':Index(all=False), } for lang in [ CLanguage(), PythonLanguage(), NumexprPythonLanguage() ]: print lang.__class__.__name__ print '='*len(lang.__class__.__name__) output = translate(code, specifiers, float64, lang) print 'OUTPUT CODE:' if isinstance(output, str): print indent(output) else: for k, v in output.items(): print k+':' print indent(v) print
def create_runner_codeobj( group, code, template_name, variable_indices=None, name=None, check_units=True, needed_variables=None, additional_variables=None, level=0, run_namespace=None, template_kwds=None, override_conditional_write=None, ): ''' Create a `CodeObject` for the execution of code in the context of a `Group`. Parameters ---------- group : `Group` The group where the code is to be run code : str or dict of str The code to be executed. template_name : str The name of the template to use for the code. variable_indices : dict-like, optional A mapping from `Variable` objects to index names (strings). If none is given, uses the corresponding attribute of `group`. name : str, optional A name for this code object, will use ``group + '_codeobject*'`` if none is given. check_units : bool, optional Whether to check units in the statement. Defaults to ``True``. needed_variables: list of str, optional A list of variables that are neither present in the abstract code, nor in the ``USES_VARIABLES`` statement in the template. This is only rarely necessary, an example being a `StateMonitor` where the names of the variables are neither known to the template nor included in the abstract code statements. additional_variables : dict-like, optional A mapping of names to `Variable` objects, used in addition to the variables saved in `group`. level : int, optional How far to go up in the stack to find the call frame. run_namespace : dict-like, optional An additional namespace that is used for variable lookup (if not defined, the implicit namespace of local variables is used). template_kwds : dict, optional A dictionary of additional information that is passed to the template. override_conditional_write: list of str, optional A list of variable names which are used as conditions (e.g. for refractoriness) which should be ignored. ''' if isinstance(code, str): code = {None: code} msg = 'Creating code object (group=%s, template name=%s) for abstract code:\n' % ( group.name, template_name) msg += indent(code_representation(code)) logger.debug(msg) from brian2.devices import get_device device = get_device() if override_conditional_write is None: override_conditional_write = set([]) else: override_conditional_write = set(override_conditional_write) if check_units: for c in code.values(): check_code_units(c, group, additional_variables=additional_variables, level=level + 1, run_namespace=run_namespace) codeobj_class = device.code_object_class(group.codeobj_class) template = getattr(codeobj_class.templater, template_name) all_variables = dict(group.variables) if additional_variables is not None: all_variables.update(additional_variables) # Determine the identifiers that were used used_known = set() unknown = set() for v in code.values(): _, uk, u = analyse_identifiers(v, all_variables, recursive=True) used_known |= uk unknown |= u logger.debug('Unknown identifiers in the abstract code: ' + ', '.join(unknown)) # Only pass the variables that are actually used variables = group.resolve_all(used_known | unknown, additional_variables=additional_variables, run_namespace=run_namespace, level=level + 1) conditional_write_variables = {} # Add all the "conditional write" variables for var in variables.itervalues(): cond_write_var = getattr(var, 'conditional_write', None) if cond_write_var in override_conditional_write: continue if cond_write_var is not None and cond_write_var not in variables.values( ): if cond_write_var.name in variables: raise AssertionError( ('Variable "%s" is needed for the ' 'conditional write mechanism of variable ' '"%s". Its name is already used for %r.') % (cond_write_var.name, var.name, variables[cond_write_var.name])) conditional_write_variables[cond_write_var.name] = cond_write_var variables.update(conditional_write_variables) # Add variables that are not in the abstract code, nor specified in the # template but nevertheless necessary if needed_variables is None: needed_variables = [] # Also add the variables that the template needs variables.update( group.resolve_all( set(needed_variables) | set(template.variables), additional_variables=additional_variables, run_namespace=run_namespace, level=level + 1, do_warn=False)) # no warnings for internally used variables if name is None: if group is not None: name = '%s_%s_codeobject*' % (group.name, template_name) else: name = '%s_codeobject*' % template_name all_variable_indices = copy.copy(group.variables.indices) if additional_variables is not None: all_variable_indices.update(additional_variables.indices) if variable_indices is not None: all_variable_indices.update(variable_indices) # Make "conditional write" variables use the same index as the variable # that depends on them for varname, var in variables.iteritems(): cond_write_var = getattr(var, 'conditional_write', None) if cond_write_var is not None: all_variable_indices[ cond_write_var.name] = all_variable_indices[varname] # Add the indices needed by the variables varnames = variables.keys() for varname in varnames: var_index = all_variable_indices[varname] if not var_index in ('_idx', '0'): variables[var_index] = all_variables[var_index] return device.code_object( owner=group, name=name, abstract_code=code, variables=variables, template_name=template_name, variable_indices=all_variable_indices, template_kwds=template_kwds, codeobj_class=group.codeobj_class, override_conditional_write=override_conditional_write, )
def __str__(self): s = 'def %s(%s):\n%s\n return %s\n' % (self.name, ', '.join(self.args), indent(self.code), self.return_expr) return s
def create_runner_codeobj(group, code, template_name, user_code=None, variable_indices=None, name=None, check_units=True, needed_variables=None, additional_variables=None, level=0, run_namespace=None, template_kwds=None, override_conditional_write=None, codeobj_class=None ): ''' Create a `CodeObject` for the execution of code in the context of a `Group`. Parameters ---------- group : `Group` The group where the code is to be run code : str or dict of str The code to be executed. template_name : str The name of the template to use for the code. user_code : str, optional The code that had been specified by the user before other code was added automatically. If not specified, will be assumed to be identical to ``code``. variable_indices : dict-like, optional A mapping from `Variable` objects to index names (strings). If none is given, uses the corresponding attribute of `group`. name : str, optional A name for this code object, will use ``group + '_codeobject*'`` if none is given. check_units : bool, optional Whether to check units in the statement. Defaults to ``True``. needed_variables: list of str, optional A list of variables that are neither present in the abstract code, nor in the ``USES_VARIABLES`` statement in the template. This is only rarely necessary, an example being a `StateMonitor` where the names of the variables are neither known to the template nor included in the abstract code statements. additional_variables : dict-like, optional A mapping of names to `Variable` objects, used in addition to the variables saved in `group`. level : int, optional How far to go up in the stack to find the call frame. run_namespace : dict-like, optional An additional namespace that is used for variable lookup (if not defined, the implicit namespace of local variables is used). template_kwds : dict, optional A dictionary of additional information that is passed to the template. override_conditional_write: list of str, optional A list of variable names which are used as conditions (e.g. for refractoriness) which should be ignored. codeobj_class : class, optional The `CodeObject` class to run code with. If not specified, defaults to the `group`'s ``codeobj_class`` attribute. ''' if name is None: if group is not None: name = '%s_%s_codeobject*' % (group.name, template_name) else: name = '%s_codeobject*' % template_name if user_code is None: user_code = code if isinstance(code, str): code = {None: code} user_code = {None: user_code} msg = 'Creating code object (group=%s, template name=%s) for abstract code:\n' % (group.name, template_name) msg += indent(code_representation(code)) logger.debug(msg) from brian2.devices import get_device device = get_device() if override_conditional_write is None: override_conditional_write = set([]) else: override_conditional_write = set(override_conditional_write) if check_units: for c in code.values(): # This is the first time that the code is parsed, catch errors try: check_code_units(c, group, additional_variables=additional_variables, level=level+1, run_namespace=run_namespace) except (SyntaxError, KeyError, ValueError) as ex: error_msg = _error_msg(c, name) raise ValueError(error_msg + str(ex)) if codeobj_class is None: codeobj_class = device.code_object_class(group.codeobj_class) else: codeobj_class = device.code_object_class(codeobj_class) template = getattr(codeobj_class.templater, template_name, None) if template is None: codeobj_class_name = codeobj_class.class_name or codeobj_class.__name__ raise AttributeError(('"%s" does not provide a code generation ' 'template "%s"') % (codeobj_class_name, template_name)) all_variables = dict(group.variables) if additional_variables is not None: all_variables.update(additional_variables) # Determine the identifiers that were used identifiers = set() user_identifiers = set() for v, u_v in zip(code.values(), user_code.values()): _, uk, u = analyse_identifiers(v, all_variables, recursive=True) identifiers |= uk | u _, uk, u = analyse_identifiers(u_v, all_variables, recursive=True) user_identifiers |= uk | u # Only pass the variables that are actually used variables = group.resolve_all(identifiers, user_identifiers, additional_variables=additional_variables, run_namespace=run_namespace, level=level+1) conditional_write_variables = {} # Add all the "conditional write" variables for var in variables.itervalues(): cond_write_var = getattr(var, 'conditional_write', None) if cond_write_var in override_conditional_write: continue if cond_write_var is not None and cond_write_var not in variables.values(): if cond_write_var.name in variables: raise AssertionError(('Variable "%s" is needed for the ' 'conditional write mechanism of variable ' '"%s". Its name is already used for %r.') % (cond_write_var.name, var.name, variables[cond_write_var.name])) conditional_write_variables[cond_write_var.name] = cond_write_var variables.update(conditional_write_variables) # Add variables that are not in the abstract code, nor specified in the # template but nevertheless necessary if needed_variables is None: needed_variables = [] # Also add the variables that the template needs variables.update(group.resolve_all(set(needed_variables) | set(template.variables), # template variables are not known to the user: user_identifiers=set(), additional_variables=additional_variables, run_namespace=run_namespace, level=level+1)) all_variable_indices = copy.copy(group.variables.indices) if additional_variables is not None: all_variable_indices.update(additional_variables.indices) if variable_indices is not None: all_variable_indices.update(variable_indices) # Make "conditional write" variables use the same index as the variable # that depends on them for varname, var in variables.iteritems(): cond_write_var = getattr(var, 'conditional_write', None) if cond_write_var is not None: all_variable_indices[cond_write_var.name] = all_variable_indices[varname] # Add the indices needed by the variables varnames = variables.keys() for varname in varnames: var_index = all_variable_indices[varname] if not var_index in ('_idx', '0'): variables[var_index] = all_variables[var_index] return device.code_object(owner=group, name=name, abstract_code=code, variables=variables, template_name=template_name, variable_indices=all_variable_indices, template_kwds=template_kwds, codeobj_class=codeobj_class, override_conditional_write=override_conditional_write, )
def __str__(self): s = '' for k, v in self._templates.items(): s += k+':\n' s += strip_empty_lines(indent(v))+'\n' return s
:maxdepth: 1 :titlesonly: ''' for tutorial, _ in tutorials: text += ' ' + tutorial + '\n' text += ''' .. only:: html Interactive notebooks and files ------------------------------- ''' for tutorial, _ in tutorials: text += indent( deindent(''' .. |launchbinder{tutid}| image:: http://mybinder.org/badge.svg .. _launchbinder{tutid}: http://mybinder.org:/repo/brian-team/brian2-binder/notebooks/tutorials/{tutorial}.ipynb '''.format(tutorial=tutorial, tutid=tutorial.replace('-', '')))) text += '\n' for tutorial, title in tutorials: text += ' * |launchbinder{tutid}|_ :download:`{title} <{tutorial}.ipynb>`\n'.format( title=title, tutorial=tutorial, tutid=tutorial.replace('-', '')) text += ''' .. _`Jupyter Notebooks`: http://jupyter-notebook-beginner-guide.readthedocs.org/en/latest/what_is_jupyter.html .. _`Jupyter`: http://jupyter.org/ .. _`Jupyter Notebook documentation`: http://jupyter.readthedocs.org/ .. [#] Formerly known as "IPython Notebooks". '''
def create_runner_codeobj(group, code, template_name, run_namespace, user_code=None, variable_indices=None, name=None, check_units=True, needed_variables=None, additional_variables=None, template_kwds=None, override_conditional_write=None, codeobj_class=None): ''' Create a `CodeObject` for the execution of code in the context of a `Group`. Parameters ---------- group : `Group` The group where the code is to be run code : str or dict of str The code to be executed. template_name : str The name of the template to use for the code. run_namespace : dict-like An additional namespace that is used for variable lookup (either an explicitly defined namespace or one taken from the local context). user_code : str, optional The code that had been specified by the user before other code was added automatically. If not specified, will be assumed to be identical to ``code``. variable_indices : dict-like, optional A mapping from `Variable` objects to index names (strings). If none is given, uses the corresponding attribute of `group`. name : str, optional A name for this code object, will use ``group + '_codeobject*'`` if none is given. check_units : bool, optional Whether to check units in the statement. Defaults to ``True``. needed_variables: list of str, optional A list of variables that are neither present in the abstract code, nor in the ``USES_VARIABLES`` statement in the template. This is only rarely necessary, an example being a `StateMonitor` where the names of the variables are neither known to the template nor included in the abstract code statements. additional_variables : dict-like, optional A mapping of names to `Variable` objects, used in addition to the variables saved in `group`. template_kwds : dict, optional A dictionary of additional information that is passed to the template. override_conditional_write: list of str, optional A list of variable names which are used as conditions (e.g. for refractoriness) which should be ignored. codeobj_class : class, optional The `CodeObject` class to run code with. If not specified, defaults to the `group`'s ``codeobj_class`` attribute. ''' if name is None: if group is not None: name = '%s_%s_codeobject*' % (group.name, template_name) else: name = '%s_codeobject*' % template_name if user_code is None: user_code = code if isinstance(code, str): code = {None: code} user_code = {None: user_code} msg = 'Creating code object (group=%s, template name=%s) for abstract code:\n' % ( group.name, template_name) msg += indent(code_representation(code)) logger.diagnostic(msg) from brian2.devices import get_device device = get_device() if override_conditional_write is None: override_conditional_write = set([]) else: override_conditional_write = set(override_conditional_write) if codeobj_class is None: codeobj_class = device.code_object_class(group.codeobj_class) else: codeobj_class = device.code_object_class(codeobj_class) template = getattr(codeobj_class.templater, template_name) template_variables = getattr(template, 'variables', None) all_variables = dict(group.variables) if additional_variables is not None: all_variables.update(additional_variables) # Determine the identifiers that were used identifiers = set() user_identifiers = set() for v, u_v in zip(code.values(), user_code.values()): _, uk, u = analyse_identifiers(v, all_variables, recursive=True) identifiers |= uk | u _, uk, u = analyse_identifiers(u_v, all_variables, recursive=True) user_identifiers |= uk | u # Add variables that are not in the abstract code, nor specified in the # template but nevertheless necessary if needed_variables is None: needed_variables = [] # Resolve all variables (variables used in the code and variables needed by # the template) variables = group.resolve_all( identifiers | set(needed_variables) | set(template_variables), # template variables are not known to the user: user_identifiers=user_identifiers, additional_variables=additional_variables, run_namespace=run_namespace) # We raise this error only now, because there is some non-obvious code path # where Jinja tries to get a Synapse's "name" attribute via syn['name'], # which then triggers the use of the `group_get_indices` template which does # not exist for standalone. Putting the check for template == None here # means we will first raise an error about the unknown identifier which will # then make Jinja try syn.name if template is None: codeobj_class_name = codeobj_class.class_name or codeobj_class.__name__ raise AttributeError( ('"%s" does not provide a code generation ' 'template "%s"') % (codeobj_class_name, template_name)) conditional_write_variables = {} # Add all the "conditional write" variables for var in variables.itervalues(): cond_write_var = getattr(var, 'conditional_write', None) if cond_write_var in override_conditional_write: continue if cond_write_var is not None: if (cond_write_var.name in variables and not variables[cond_write_var.name] is cond_write_var): logger.diagnostic(('Variable "%s" is needed for the ' 'conditional write mechanism of variable ' '"%s". Its name is already used for %r.') % (cond_write_var.name, var.name, variables[cond_write_var.name])) else: conditional_write_variables[ cond_write_var.name] = cond_write_var variables.update(conditional_write_variables) if check_units: for c in code.values(): # This is the first time that the code is parsed, catch errors try: check_units_statements(c, variables) except (SyntaxError, ValueError) as ex: error_msg = _error_msg(c, name) raise ValueError(error_msg + str(ex)) all_variable_indices = copy.copy(group.variables.indices) if additional_variables is not None: all_variable_indices.update(additional_variables.indices) if variable_indices is not None: all_variable_indices.update(variable_indices) # Make "conditional write" variables use the same index as the variable # that depends on them for varname, var in variables.iteritems(): cond_write_var = getattr(var, 'conditional_write', None) if cond_write_var is not None: all_variable_indices[ cond_write_var.name] = all_variable_indices[varname] # Add the indices needed by the variables varnames = variables.keys() for varname in varnames: var_index = all_variable_indices[varname] if not var_index in ('_idx', '0'): variables[var_index] = all_variables[var_index] return device.code_object( owner=group, name=name, abstract_code=code, variables=variables, template_name=template_name, variable_indices=all_variable_indices, template_kwds=template_kwds, codeobj_class=codeobj_class, override_conditional_write=override_conditional_write, )
def __str__(self): s = '' for k, v in self._templates.items(): s += k + ':\n' s += strip_empty_lines(indent(v)) + '\n' return s
:maxdepth: 1 :titlesonly: ''' for tutorial, _ in tutorials: text += ' ' + tutorial + '\n' text += ''' .. only:: html Interactive notebooks and files ------------------------------- ''' for tutorial, _ in tutorials: text += indent( deindent(''' .. |launchbinder{tutid}| image:: http://mybinder.org/badge.svg .. _launchbinder{tutid}: https://mybinder.org/v2/gh/brian-team/brian2-binder/master?filepath=tutorials/{tutorial}.ipynb '''.format(tutorial=tutorial, tutid=tutorial.replace('-', '')))) text += '\n' for tutorial, title in tutorials: text += ' * |launchbinder{tutid}|_ :download:`{title} <{tutorial}.ipynb>`\n'.format( title=title, tutorial=tutorial, tutid=tutorial.replace('-', '')) text += ''' .. _`Jupyter Notebooks`: http://jupyter-notebook-beginner-guide.readthedocs.org/en/latest/what_is_jupyter.html .. _`Jupyter`: http://jupyter.org/ .. _`Jupyter Notebook documentation`: http://jupyter.readthedocs.org/ .. [#] Formerly known as "IPython Notebooks". '''
def create_runner_codeobj(group, code, template_name, run_namespace, user_code=None, variable_indices=None, name=None, check_units=True, needed_variables=None, additional_variables=None, template_kwds=None, override_conditional_write=None, codeobj_class=None ): ''' Create a `CodeObject` for the execution of code in the context of a `Group`. Parameters ---------- group : `Group` The group where the code is to be run code : str or dict of str The code to be executed. template_name : str The name of the template to use for the code. run_namespace : dict-like An additional namespace that is used for variable lookup (either an explicitly defined namespace or one taken from the local context). user_code : str, optional The code that had been specified by the user before other code was added automatically. If not specified, will be assumed to be identical to ``code``. variable_indices : dict-like, optional A mapping from `Variable` objects to index names (strings). If none is given, uses the corresponding attribute of `group`. name : str, optional A name for this code object, will use ``group + '_codeobject*'`` if none is given. check_units : bool, optional Whether to check units in the statement. Defaults to ``True``. needed_variables: list of str, optional A list of variables that are neither present in the abstract code, nor in the ``USES_VARIABLES`` statement in the template. This is only rarely necessary, an example being a `StateMonitor` where the names of the variables are neither known to the template nor included in the abstract code statements. additional_variables : dict-like, optional A mapping of names to `Variable` objects, used in addition to the variables saved in `group`. template_kwds : dict, optional A dictionary of additional information that is passed to the template. override_conditional_write: list of str, optional A list of variable names which are used as conditions (e.g. for refractoriness) which should be ignored. codeobj_class : class, optional The `CodeObject` class to run code with. If not specified, defaults to the `group`'s ``codeobj_class`` attribute. ''' if name is None: if group is not None: name = '%s_%s_codeobject*' % (group.name, template_name) else: name = '%s_codeobject*' % template_name if user_code is None: user_code = code if isinstance(code, str): code = {None: code} user_code = {None: user_code} msg = 'Creating code object (group=%s, template name=%s) for abstract code:\n' % (group.name, template_name) msg += indent(code_representation(code)) logger.diagnostic(msg) from brian2.devices import get_device device = get_device() if override_conditional_write is None: override_conditional_write = set([]) else: override_conditional_write = set(override_conditional_write) if codeobj_class is None: codeobj_class = device.code_object_class(group.codeobj_class) else: codeobj_class = device.code_object_class(codeobj_class) template = getattr(codeobj_class.templater, template_name) template_variables = getattr(template, 'variables', None) all_variables = dict(group.variables) if additional_variables is not None: all_variables.update(additional_variables) # Determine the identifiers that were used identifiers = set() user_identifiers = set() for v, u_v in zip(code.values(), user_code.values()): _, uk, u = analyse_identifiers(v, all_variables, recursive=True) identifiers |= uk | u _, uk, u = analyse_identifiers(u_v, all_variables, recursive=True) user_identifiers |= uk | u # Add variables that are not in the abstract code, nor specified in the # template but nevertheless necessary if needed_variables is None: needed_variables = [] # Resolve all variables (variables used in the code and variables needed by # the template) variables = group.resolve_all(identifiers | set(needed_variables) | set(template_variables), # template variables are not known to the user: user_identifiers=user_identifiers, additional_variables=additional_variables, run_namespace=run_namespace) # We raise this error only now, because there is some non-obvious code path # where Jinja tries to get a Synapse's "name" attribute via syn['name'], # which then triggers the use of the `group_get_indices` template which does # not exist for standalone. Putting the check for template == None here # means we will first raise an error about the unknown identifier which will # then make Jinja try syn.name if template is None: codeobj_class_name = codeobj_class.class_name or codeobj_class.__name__ raise AttributeError(('"%s" does not provide a code generation ' 'template "%s"') % (codeobj_class_name, template_name)) conditional_write_variables = {} # Add all the "conditional write" variables for var in variables.itervalues(): cond_write_var = getattr(var, 'conditional_write', None) if cond_write_var in override_conditional_write: continue if cond_write_var is not None: if (cond_write_var.name in variables and not variables[cond_write_var.name] is cond_write_var): logger.diagnostic(('Variable "%s" is needed for the ' 'conditional write mechanism of variable ' '"%s". Its name is already used for %r.') % (cond_write_var.name, var.name, variables[cond_write_var.name])) else: conditional_write_variables[cond_write_var.name] = cond_write_var variables.update(conditional_write_variables) if check_units: for c in code.values(): # This is the first time that the code is parsed, catch errors try: check_units_statements(c, variables) except (SyntaxError, ValueError) as ex: error_msg = _error_msg(c, name) raise ValueError(error_msg + str(ex)) all_variable_indices = copy.copy(group.variables.indices) if additional_variables is not None: all_variable_indices.update(additional_variables.indices) if variable_indices is not None: all_variable_indices.update(variable_indices) # Make "conditional write" variables use the same index as the variable # that depends on them for varname, var in variables.iteritems(): cond_write_var = getattr(var, 'conditional_write', None) if cond_write_var is not None: all_variable_indices[cond_write_var.name] = all_variable_indices[varname] # Check that all functions are available for varname, value in variables.iteritems(): if isinstance(value, Function): try: value.implementations[codeobj_class] except KeyError as ex: # if we are dealing with numpy, add the default implementation from brian2.codegen.runtime.numpy_rt import NumpyCodeObject if codeobj_class is NumpyCodeObject: value.implementations.add_numpy_implementation(value.pyfunc) else: raise NotImplementedError(('Cannot use function ' '%s: %s') % (varname, ex)) # Gather the additional compiler arguments declared by function # implementations all_keywords = [_gather_compiler_kwds(var, codeobj_class) for var in variables.itervalues() if isinstance(var, Function)] compiler_kwds = _merge_compiler_kwds(all_keywords) # Add the indices needed by the variables varnames = variables.keys() for varname in varnames: var_index = all_variable_indices[varname] if not var_index in ('_idx', '0'): variables[var_index] = all_variables[var_index] return device.code_object(owner=group, name=name, abstract_code=code, variables=variables, template_name=template_name, variable_indices=all_variable_indices, template_kwds=template_kwds, codeobj_class=codeobj_class, override_conditional_write=override_conditional_write, compiler_kwds=compiler_kwds )
.. toctree:: :maxdepth: 1 :titlesonly: ''' for tutorial, _ in tutorials: text += ' ' + tutorial + '\n' text += ''' .. only:: html Interactive notebooks and files ------------------------------- ''' for tutorial, _ in tutorials: text += indent(deindent(''' .. |launchbinder{tutid}| image:: http://mybinder.org/badge.svg .. _launchbinder{tutid}: http://mybinder.org:/repo/brian-team/brian2-binder/notebooks/tutorials/{tutorial}.ipynb '''.format(tutorial=tutorial, tutid=tutorial.replace('-', '')))) text += '\n' for tutorial, title in tutorials: text += ' * |launchbinder{tutid}|_ :download:`{title} <{tutorial}.ipynb>`\n'.format(title=title, tutorial=tutorial, tutid=tutorial.replace('-', '')) text += ''' .. _`Jupyter Notebooks`: http://jupyter-notebook-beginner-guide.readthedocs.org/en/latest/what_is_jupyter.html .. _`Jupyter`: http://jupyter.org/ .. _`Jupyter Notebook documentation`: http://jupyter.readthedocs.org/ .. [#] Formerly known as "IPython Notebooks". ''' with open(os.path.join(target_dir, 'index.rst'), 'w') as f: