Example #1
0
    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
Example #2
0
    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
Example #3
0
    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
Example #4
0
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
                              )
Example #5
0
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,
    )
Example #6
0
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,
                              )
Example #7
0
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,
    )