Example #1
0
    def translate(self, code, dtype):
        '''
        Translates an abstract code block into the target language.
        '''
        scalar_statements = {}
        vector_statements = {}
        for ac_name, ac_code in code.iteritems():
            scalar_statements[ac_name], vector_statements[
                ac_name] = make_statements(ac_code, self.variables, dtype)
        for vs in vector_statements.itervalues():
            # Check that the statements are meaningful independent on the order of
            # execution (e.g. for synapses)
            try:
                check_for_order_independence(vs, self.variables,
                                             self.variable_indices)
            except OrderDependenceError:
                # If the abstract code is only one line, display it in full
                if len(vs) <= 1:
                    error_msg = 'Abstract code: "%s"\n' % vs[0]
                else:
                    error_msg = ('%d lines of abstract code, first line is: '
                                 '"%s"\n') % (len(vs), vs[0])
                logger.warn(('Came across an abstract code block that is not '
                             'well-defined: the outcome may depend on the '
                             'order of execution. ' + error_msg))

        return self.translate_statement_sequence(scalar_statements,
                                                 vector_statements)
Example #2
0
 def translate(self, code, dtype):
     '''
     Translates an abstract code block into the target language.
     '''
     scalar_statements = {}
     vector_statements = {}
     for ac_name, ac_code in code.iteritems():
         statements = make_statements(ac_code,
                                      self.variables,
                                      dtype,
                                      optimise=True,
                                      blockname=ac_name)
         scalar_statements[ac_name], vector_statements[ac_name] = statements
     for vs in vector_statements.itervalues():
         # Check that the statements are meaningful independent on the order of
         # execution (e.g. for synapses)
         try:
             if self.has_repeated_indices(vs):  # only do order dependence if there are repeated indices
                 check_for_order_independence(vs,
                                              self.variables,
                                              self.variable_indices)
         except OrderDependenceError:
             # If the abstract code is only one line, display it in full
             if len(vs) <= 1:
                 error_msg = 'Abstract code: "%s"\n' % vs[0]
             else:
                 error_msg = ('%d lines of abstract code, first line is: '
                              '"%s"\n') % (len(vs), vs[0])
             logger.warn(('Came across an abstract code block that may not be '
                          'well-defined: the outcome may depend on the '
                          'order of execution. You can ignore this warning if '
                          'you are sure that the order of operations does not '
                          'matter. ' + error_msg))
     return self.translate_statement_sequence(scalar_statements,
                                              vector_statements)
Example #3
0
    def translate(self, code, dtype):
        '''
        Translates an abstract code block into the target language.
        '''
        scalar_statements = {}
        vector_statements = {}
        for ac_name, ac_code in code.iteritems():
            scalar_statements[ac_name], vector_statements[ac_name] = make_statements(ac_code,
                                                                                     self.variables,
                                                                                     dtype)
        for vs in vector_statements.itervalues():
            # Check that the statements are meaningful independent on the order of
            # execution (e.g. for synapses)
            try:
                check_for_order_independence(vs,
                                             self.variables,
                                             self.variable_indices)
            except OrderDependenceError:
                # If the abstract code is only one line, display it in full
                if len(vs) <= 1:
                    error_msg = 'Abstract code: "%s"\n' % vs[0]
                else:
                    error_msg = ('%d lines of abstract code, first line is: '
                                 '"%s"\n') % (len(vs), vs[0])
                logger.warn(('Came across an abstract code block that is not '
                             'well-defined: the outcome may depend on the '
                             'order of execution. ' + error_msg))

        return self.translate_statement_sequence(scalar_statements,
                                                 vector_statements)
Example #4
0
def check_permutation_code(code):
    from collections import defaultdict
    vars = get_identifiers(code)
    indices = defaultdict(lambda: '_idx')
    for var in vars:
        if var.endswith('_syn'):
            indices[var] = '_idx'
        elif var.endswith('_pre'):
            indices[var] ='_presynaptic_idx'
        elif var.endswith('_post'):
            indices[var] = '_postsynaptic_idx'
    variables = dict()
    for var in indices:
        variables[var] = ArrayVariable(var, 1, None, 10, device)
    variables['_presynaptic_idx'] = ArrayVariable(var, 1, None, 10, device)
    variables['_postsynaptic_idx'] = ArrayVariable(var, 1, None, 10, device)
    scalar_statements, vector_statements = make_statements(code, variables, float64)
    check_for_order_independence(vector_statements, variables, indices)
Example #5
0
def check_permutation_code(code):
    from collections import defaultdict
    vars = get_identifiers(code)
    indices = defaultdict(lambda: '_idx')
    for var in vars:
        if var.endswith('_syn'):
            indices[var] = '_idx'
        elif var.endswith('_pre'):
            indices[var] = '_presynaptic_idx'
        elif var.endswith('_post'):
            indices[var] = '_postsynaptic_idx'
    variables = dict()
    for var in indices:
        variables[var] = ArrayVariable(var, 1, None, 10, device)
    variables['_presynaptic_idx'] = ArrayVariable(var, 1, None, 10, device)
    variables['_postsynaptic_idx'] = ArrayVariable(var, 1, None, 10, device)
    scalar_statements, vector_statements = make_statements(
        code, variables, float64)
    check_for_order_independence(vector_statements, variables, indices)
Example #6
0
    def translate(self, code, dtype):
        """
        Translates an abstract code block into the target language.
        """
        scalar_statements = {}
        vector_statements = {}
        for ac_name, ac_code in code.items():
            statements = make_statements(ac_code,
                                         self.variables,
                                         dtype,
                                         optimise=True,
                                         blockname=ac_name)
            scalar_statements[ac_name], vector_statements[ac_name] = statements
        for vs in vector_statements.values():
            # Check that the statements are meaningful independent on the order of
            # execution (e.g. for synapses)
            try:
                if self.has_repeated_indices(
                        vs
                ):  # only do order dependence if there are repeated indices
                    check_for_order_independence(vs, self.variables,
                                                 self.variable_indices)
            except OrderDependenceError:
                # If the abstract code is only one line, display it in full
                if len(vs) <= 1:
                    error_msg = f"Abstract code: '{vs[0]}'\n"
                else:
                    error_msg = (
                        f"{len(vs)} lines of abstract code, first line is: "
                        f"'{vs[0]}'\n")
                logger.warn(
                    ('Came across an abstract code block that may not be '
                     'well-defined: the outcome may depend on the '
                     'order of execution. You can ignore this warning if '
                     'you are sure that the order of operations does not '
                     'matter. ' + error_msg))

        translated = self.translate_statement_sequence(scalar_statements,
                                                       vector_statements)

        return translated
Example #7
0
    def translate(
        self, code, dtype
    ):  # TODO: it's not so nice we have to copy the contents of this function..
        '''
        Translates an abstract code block into the target language.
        '''
        # first check if user code is not using variables that are also used by GSL
        reserved_variables = [
            '_dataholder', '_fill_y_vector', '_empty_y_vector',
            '_GSL_dataholder', '_GSL_y', '_GSL_func'
        ]
        if any([var in self.variables for var in reserved_variables]):
            # import here to avoid circular import
            raise ValueError(("The variables %s are reserved for the GSL "
                              "internal code." % (str(reserved_variables))))

        # if the following statements are not added, Brian translates the
        # differential expressions in the abstract code for GSL to scalar statements
        # in the case no non-scalar variables are used in the expression
        diff_vars = self.find_differential_variables(code.values())
        self.add_gsl_variables_as_non_scalar(diff_vars)

        # add arrays we want to use in generated code before self.generator.translate() so
        # brian does namespace unpacking for us
        pointer_names = self.add_meta_variables(self.method_options)

        scalar_statements = {}
        vector_statements = {}
        for ac_name, ac_code in code.iteritems():
            statements = make_statements(ac_code,
                                         self.variables,
                                         dtype,
                                         optimise=True,
                                         blockname=ac_name)
            scalar_statements[ac_name], vector_statements[ac_name] = statements
        for vs in vector_statements.itervalues():
            # Check that the statements are meaningful independent on the order of
            # execution (e.g. for synapses)
            try:
                if self.has_repeated_indices(
                        vs
                ):  # only do order dependence if there are repeated indices
                    check_for_order_independence(
                        vs, self.generator.variables,
                        self.generator.variable_indices)
            except OrderDependenceError:
                # If the abstract code is only one line, display it in ful   l
                if len(vs) <= 1:
                    error_msg = 'Abstract code: "%s"\n' % vs[0]
                else:
                    error_msg = (
                        '%_GSL_driver lines of abstract code, first line is: '
                        '"%s"\n') % (len(vs), vs[0])

        # save function names because self.generator.translate_statement_sequence
        # deletes these from self.variables but we need to know which identifiers
        # we can safely ignore (i.e. we can ignore the functions because they are
        # handled by the original generator)
        self.function_names = self.find_function_names()

        scalar_code, vector_code, kwds = self.generator.translate_statement_sequence(
            scalar_statements, vector_statements)

        ############ translate code for GSL

        # first check if any indexing other than '_idx' is used (currently not supported)
        for code_list in scalar_code.values() + vector_code.values():
            for code in code_list:
                m = re.search('\[(\w+)\]', code)
                if m is not None:
                    if m.group(1) != '0' and m.group(1) != '_idx':
                        from brian2.stateupdaters.base import UnsupportedEquationsException
                        raise UnsupportedEquationsException(
                            ("Equations result in state "
                             "updater code with indexing "
                             "other than '_idx', which "
                             "is currently not supported "
                             "in combination with the "
                             "GSL stateupdater."))

        # differential variable specific operations
        to_replace = self.diff_var_to_replace(diff_vars)
        GSL_support_code = self.get_dimension_code(len(diff_vars))
        GSL_support_code += self.yvector_code(diff_vars)

        # analyze all needed variables; if not in self.variables: put in separate dic.
        # also keep track of variables needed for scalar statements and vector statements
        other_variables = self.find_undefined_variables(
            scalar_statements[None] + vector_statements[None])
        variables_in_scalar = self.find_used_variables(scalar_statements[None],
                                                       other_variables)
        variables_in_vector = self.find_used_variables(vector_statements[None],
                                                       other_variables)
        # so that _dataholder holds diff_vars as well, even if they don't occur
        # in the actual statements
        for var in diff_vars.keys():
            if not var in variables_in_vector:
                variables_in_vector[var] = self.variables[var]
        # lets keep track of the variables that eventually need to be added to
        # the _GSL_dataholder somehow
        self.variables_to_be_processed = variables_in_vector.keys()

        # add code for _dataholder struct
        GSL_support_code = self.write_dataholder(
            variables_in_vector) + GSL_support_code
        # add e.g. _lio_1 --> _GSL_dataholder._lio_1 to replacer
        to_replace.update(
            self.to_replace_vector_vars(variables_in_vector,
                                        ignore=diff_vars.keys()))
        # write statements that unpack (python) namespace to _dataholder struct
        # or local namespace
        GSL_main_code = self.unpack_namespace(variables_in_vector,
                                              variables_in_scalar, ['t'])

        # rewrite actual calculations described by vector_code and put them in _GSL_func
        func_code = self.translate_one_statement_sequence(
            vector_statements[None], scalar=False)
        GSL_support_code += self.make_function_code(
            self.translate_vector_code(func_code, to_replace))
        scalar_func_code = self.translate_one_statement_sequence(
            scalar_statements[None], scalar=True)
        # rewrite scalar code, keep variables that are needed in scalar code normal
        # and add variables to _dataholder for vector_code
        GSL_main_code += '\n' + self.translate_scalar_code(
            scalar_func_code, variables_in_scalar, variables_in_vector)
        if len(self.variables_to_be_processed) > 0:
            raise AssertionError(
                ("Not all variables that will be used in the vector "
                 "code have been added to the _GSL_dataholder. This "
                 "might mean that the _GSL_func is using unitialized "
                 "variables."
                 "\nThe unprocessed variables "
                 "are: %s" % (str(self.variables_to_be_processed))))

        scalar_code['GSL'] = GSL_main_code
        kwds['define_GSL_scale_array'] = self.scale_array_code(
            diff_vars, self.method_options)
        kwds['n_diff_vars'] = len(diff_vars)
        kwds['GSL_settings'] = dict(self.method_options)
        kwds['GSL_settings']['integrator'] = self.integrator
        kwds['support_code_lines'] += GSL_support_code.split('\n')
        kwds['t_array'] = self.get_array_name(self.variables['t']) + '[0]'
        kwds['dt_array'] = self.get_array_name(self.variables['dt']) + '[0]'
        kwds['define_dt'] = 'dt' not in variables_in_scalar
        kwds['cpp_standalone'] = self.is_cpp_standalone()
        for key, value in pointer_names.items():
            kwds[key] = value
        return scalar_code, vector_code, kwds
Example #8
0
    def translate(self, code, dtype): # TODO: it's not so nice we have to copy the contents of this function..
        '''
        Translates an abstract code block into the target language.
        '''
        # first check if user code is not using variables that are also used by GSL
        reserved_variables = ['_dataholder', '_fill_y_vector', '_empty_y_vector',
                              '_GSL_dataholder', '_GSL_y', '_GSL_func']
        if any([var in self.variables for var in reserved_variables]):
            # import here to avoid circular import
            raise ValueError(("The variables %s are reserved for the GSL "
                              "internal code."%(str(reserved_variables))))

        # if the following statements are not added, Brian translates the
        # differential expressions in the abstract code for GSL to scalar statements
        # in the case no non-scalar variables are used in the expression
        diff_vars = self.find_differential_variables(code.values())
        self.add_gsl_variables_as_non_scalar(diff_vars)

        # add arrays we want to use in generated code before self.generator.translate() so
        # brian does namespace unpacking for us
        pointer_names = self.add_meta_variables(self.method_options)

        scalar_statements = {}
        vector_statements = {}
        for ac_name, ac_code in code.iteritems():
            statements = make_statements(ac_code,
                                         self.variables,
                                         dtype,
                                         optimise=True,
                                         blockname=ac_name)
            scalar_statements[ac_name], vector_statements[ac_name] = statements
        for vs in vector_statements.itervalues():
            # Check that the statements are meaningful independent on the order of
            # execution (e.g. for synapses)
            try:
                if self.has_repeated_indices(vs):     # only do order dependence if there are repeated indices
                    check_for_order_independence(vs,
                                                 self.generator.variables,
                                                 self.generator.variable_indices)
            except OrderDependenceError:
                # If the abstract code is only one line, display it in ful   l
                if len(vs) <= 1:
                    error_msg = 'Abstract code: "%s"\n' % vs[0]
                else:
                    error_msg = ('%_GSL_driver lines of abstract code, first line is: '
                                 '"%s"\n') % (len(vs), vs[0])

        # save function names because self.generator.translate_statement_sequence
        # deletes these from self.variables but we need to know which identifiers
        # we can safely ignore (i.e. we can ignore the functions because they are
        # handled by the original generator)
        self.function_names = self.find_function_names()

        scalar_code, vector_code, kwds = self.generator.translate_statement_sequence(scalar_statements,
                                                                                     vector_statements)

        ############ translate code for GSL

        # first check if any indexing other than '_idx' is used (currently not supported)
        for code_list in scalar_code.values()+vector_code.values():
            for code in code_list:
                m = re.search('\[(\w+)\]', code)
                if m is not None:
                    if m.group(1) != '0' and m.group(1) != '_idx':
                        from brian2.stateupdaters.base import UnsupportedEquationsException
                        raise UnsupportedEquationsException(("Equations result in state "
                                                             "updater code with indexing "
                                                             "other than '_idx', which "
                                                             "is currently not supported "
                                                             "in combination with the "
                                                             "GSL stateupdater."))

        # differential variable specific operations
        to_replace = self.diff_var_to_replace(diff_vars)
        GSL_support_code = self.get_dimension_code(len(diff_vars))
        GSL_support_code += self.yvector_code(diff_vars)

        # analyze all needed variables; if not in self.variables: put in separate dic.
        # also keep track of variables needed for scalar statements and vector statements
        other_variables = self.find_undefined_variables(scalar_statements[None] +
                                                        vector_statements[None])
        variables_in_scalar = self.find_used_variables(scalar_statements[None],
                                                       other_variables)
        variables_in_vector = self.find_used_variables(vector_statements[None],
                                                       other_variables)
        # so that _dataholder holds diff_vars as well, even if they don't occur
        # in the actual statements
        for var in diff_vars.keys():
            if not var in variables_in_vector:
                variables_in_vector[var] = self.variables[var]
        # lets keep track of the variables that eventually need to be added to
        # the _GSL_dataholder somehow
        self.variables_to_be_processed = variables_in_vector.keys()

        # add code for _dataholder struct
        GSL_support_code = self.write_dataholder(variables_in_vector) + GSL_support_code
        # add e.g. _lio_1 --> _GSL_dataholder._lio_1 to replacer
        to_replace.update(self.to_replace_vector_vars(variables_in_vector,
                                                      ignore=diff_vars.keys()))
        # write statements that unpack (python) namespace to _dataholder struct
        # or local namespace
        GSL_main_code = self.unpack_namespace(variables_in_vector, variables_in_scalar, ['t'])

        # rewrite actual calculations described by vector_code and put them in _GSL_func
        func_code = self.translate_one_statement_sequence(vector_statements[None],
                                                          scalar=False)
        GSL_support_code += self.make_function_code(self.translate_vector_code(func_code,
                                                                               to_replace))
        scalar_func_code = self.translate_one_statement_sequence(scalar_statements[None],
                                                                 scalar=True)
        # rewrite scalar code, keep variables that are needed in scalar code normal
        # and add variables to _dataholder for vector_code
        GSL_main_code += '\n' + self.translate_scalar_code(scalar_func_code,
                                                    variables_in_scalar,
                                                    variables_in_vector)
        if len(self.variables_to_be_processed) > 0:
            raise AssertionError(("Not all variables that will be used in the vector "
                                  "code have been added to the _GSL_dataholder. This "
                                  "might mean that the _GSL_func is using unitialized "
                                  "variables."
                                  "\nThe unprocessed variables "
                                  "are: %s" % (str(self.variables_to_be_processed))))

        scalar_code['GSL'] = GSL_main_code
        kwds['define_GSL_scale_array'] = self.scale_array_code(diff_vars,
                                                               self.method_options)
        kwds['n_diff_vars'] = len(diff_vars)
        kwds['GSL_settings'] = dict(self.method_options)
        kwds['GSL_settings']['integrator'] = self.integrator
        kwds['support_code_lines'] += GSL_support_code.split('\n')
        kwds['t_array'] = self.get_array_name(self.variables['t']) + '[0]'
        kwds['dt_array'] = self.get_array_name(self.variables['dt']) + '[0]'
        kwds['define_dt'] = 'dt' not in variables_in_scalar
        kwds['cpp_standalone'] = self.is_cpp_standalone()
        for key, value in pointer_names.items():
            kwds[key] = value
        return scalar_code, vector_code, kwds