Beispiel #1
0
 def max_threads_per_block(self, device=0):
     try:
         result = self.cy_cc.max_threads_per_block(device)
     except Exception as e:
         Global._print(e)
         Global._error('CUDA is not correctly installed on your system.')
     return result
Beispiel #2
0
def check_and_apply_pow_fix(eqs):
    """
    CUDA SDKs before 7.5 had an error if std=c++11 is enabled related
    to pow(double, int). Only pow(double, double) was detected as
    device function, the pow(double, int) will be detected as host
    function. (This was fixed within SDK 7.5)

    To support also earlier versions, we simply add a double type cast.
    """
    if eqs.strip() == "":
        # nothing to do
        return eqs

    try:
        from ANNarchy.generator.CudaCheck import CudaCheck
        if CudaCheck().runtime_version() > 7000:
            # nothing to do, is working in higher SDKs
            return eqs
    except:
        Global._error('CUDA is not correctly installed on your system')

    if Global.config['verbose']:
        Global._print(
            'occurance of pow() and SDK below 7.5 detected, apply fix.')

    # detect all pow statements
    pow_occur = re.findall(r"pow[\( [\S\s]*?\)*?, \d+\)]*?", eqs)
    for term in pow_occur:
        eqs = eqs.replace(term, term.replace(', ', ', (double)'))

    return eqs
Beispiel #3
0
 def warp_size(self, device=0):
     try:
         result = self.cy_cc.warp_size(device)
     except Exception as e:
         Global._print(e)
         Global._error('CUDA is not correctly installed on your system.')
     return result
Beispiel #4
0
    def eventdriven(self, expression):
        # Standardize the equation
        real_tau, _, steadystate = self.standardize_ODE(expression)

        if real_tau is None:  # the equation can not be standardized
            Global._print(self.expression)
            Global._error(
                'The equation is not a linear ODE and can not be evaluated exactly.'
            )

        # Check the steady state is not dependent on other variables
        for var in self.variables:
            if self.local_dict[var] in steadystate.atoms():
                Global._print(self.expression)
                Global._error(
                    'The equation can not depend on other variables (' + var +
                    ') to be evaluated exactly.')

        # Obtain C code
        variable_name = self.c_code(self.local_dict[self.name])
        steady = self.c_code(steadystate)
        if steady == '0':
            code = variable_name + ' *= exp(dt*(_last_event%(local_index)s - (t))/(' + self.c_code(
                real_tau) + '));'
        else:
            code = variable_name + ' = ' + steady + ' + (' + variable_name + ' - ' + steady + ')*exp(dt*(_last_event%(local_index)s - (t))/(' + self.c_code(
                real_tau) + '));'
        return code
Beispiel #5
0
def load_cython_lib(libname, libpath):
    """
    Load the shared library created by Cython using importlib. Follows the example
    "Multiple modules in one library" in PEP 489.

    TODO:

    As described in PEP 489 "Module Reloading" a reloading of dynamic extension modules is
    not supported. This leads to some problems for our reusage of the ANNarchyCore library ...

    Sources:

    PEP 489: (https://www.python.org/dev/peps/pep-0489/)
    """
    # create a loader to mimic find module
    loader = importlib.machinery.ExtensionFileLoader(libname, libpath)
    spec = importlib.util.spec_from_loader(libname, loader)
    module = importlib.util.module_from_spec(spec)

    if Global.config['verbose']:
        Global._print('Loading library...', libname, libpath)

    loader.exec_module(module)

    if Global.config['verbose']:
        Global._print('Library loaded.')

    return module
Beispiel #6
0
    def _init_attributes(self):
        """ Method used after compilation to initialize the attributes."""
        # Initialize the population
        self.initialized = True

        # Transfer the initial values of all attributes
        for name, value in self.init.items():
            if isinstance(value, Global.Constant):
                self.__setattr__(name, value.value)
            else:
                self.__setattr__(name, value)


        # Activate the population
        self.cyInstance.activate(self.enabled)

        # Reset to generate the right structures
        self.cyInstance.reset()

        # If the spike population has a refractory period:
        if self.neuron_type.type == 'spike' and self.neuron_type.description['refractory']:
            if isinstance(self.neuron_type.description['refractory'], str): # a global variable
                try:
                    self.refractory = eval('self.'+self.neuron_type.description['refractory'])
                except Exception as e:
                    Global._print(e, self.neuron_type.description['refractory'])
                    Global._error('The initialization for the refractory period is not valid.')

            else: # a value
                self.refractory = self.neuron_type.description['refractory']

        # Spiking neurons can compute a mean FR
        if self.neuron_type.type == 'spike':
            getattr(self.cyInstance, 'compute_firing_rate')(self._compute_mean_fr)
Beispiel #7
0
    def reset(self, attributes=-1):
        """
        Resets all parameters and variables of the population to the value they had before the call to compile().

        :param attributes: list of attributes (parameter or variable) which should be reinitialized. Default: all attributes.
        """
        if attributes == -1:
            try:
                self.set(self.init)
            except Exception as e:
                Global._print(e)
                Global._error(
                    "Population.reset(): something went wrong while resetting."
                )
        else:  # only some of them
            for var in attributes:
                # check it exists
                if not var in self.attributes:
                    Global._warning(
                        "Population.reset():", var,
                        "is not an attribute of the population, skipping.")
                    continue

                try:
                    self.__setattr__(var, self.init[var])
                except Exception as e:
                    Global._print(e)
                    Global._warning(
                        "Population.reset(): something went wrong while resetting",
                        var)

        self.cyInstance.activate(self.enabled)
        self.cyInstance.reset()
Beispiel #8
0
def _load_from_sparse(self, pre, post, weights, delays):
    from scipy.sparse import csc_matrix

    # Create an empty CSR object
    csr = Connector.CSR()

    # Find offsets
    if isinstance(self.pre, PopulationView):
        pre_ranks = self.pre.ranks
    else:
        pre_ranks = [i for i in range(self.pre.size)]

    if isinstance(self.post, PopulationView):
        post_ranks = self.post.ranks
    else:
        post_ranks = [i for i in range(self.post.size)]
    
    # Process the sparse matrix and fill the csr
    weights.sort_indices()
    (pre, post) = weights.shape

    if (pre, post) != (len(pre_ranks), len(post_ranks)):
        Global._error("connect_from_sparse(): the sparse matrix does not have the correct dimensions.")
        Global._print('Expected:', (len(pre_ranks), len(post_ranks)))
        Global._print('Received:', (pre, post))
        exit(0)

    for idx_post in range(post):
        idx_pre = weights.getcol(idx_post).indices
        w = weights.getcol(idx_post).data
        pr = [pre_ranks[i] for i in idx_pre]
        csr.add(post_ranks[idx_post], pr, w, [float(delays)])

    return csr        
Beispiel #9
0
    def reset(self, attributes=-1):
        """
        Resets all parameters and variables of the population to the value they had before the call to compile().

        *Parameters:*

        * **attributes**: list of attributes (parameter or variable) which should be reinitialized. Default: all attributes.
        """
        if attributes == -1:
            try:
                self.set(self.init)
            except Exception as e:
                Global._print(e)
                Global._error("Population.reset(): something went wrong while resetting", var)
        else: # only some of them
            for var in attributes:
                # check it exists
                if not var in self.attributes:
                    Global._warning("Population.reset():", var, "is not an attribute of the population, skipping.")
                    continue

                try:
                    self.__setattr__(var, self.init[var])
                except Exception as e:
                    Global._print(e)
                    Global._warning("Population.reset(): something went wrong while resetting", var)

        self.cyInstance.activate(self.enabled)
        self.cyInstance.reset()
Beispiel #10
0
 def gpu_count(self):
     try:
         result = self.cy_cc.gpu_count()
     except Exception as e:
         Global._print(e)
         Global._error('CUDA is not correctly installed on your system.')
     return result
Beispiel #11
0
def check_and_apply_pow_fix(eqs):
    """
    CUDA SDKs before 7.5 had an error if std=c++11 is enabled related
    to pow(double, int). Only pow(double, double) was detected as
    device function, the pow(double, int) will be detected as host
    function. (This was fixed within SDK 7.5)

    To support also earlier versions, we simply add a double type cast.
    """
    if eqs.strip() == "":
        # nothing to do
        return eqs

    if Global.config['cuda_version'] > 7.0:
        # nothing to do, is working in higher SDKs
        return eqs

    if Global.config['verbose']:
        Global._print(
            'occurance of pow() and SDK below 7.5 detected, apply fix.')

    # detect all pow statements
    pow_occur = re.findall(r"pow[\( [\S\s]*?\)*?, \d+\)]*?", eqs)
    for term in pow_occur:
        eqs = eqs.replace(term, term.replace(', ', ', (double)'))

    return eqs
Beispiel #12
0
    def reset(self, attributes=-1, synapses=False):
        """
        Resets all parameters and variables of the projection to the value they had before the call to compile.

        *Parameters:*

        * **attributes**: list of attributes (parameter or variable) which should be reinitialized. Default: all attributes.

        .. note::

            Only parameters and variables are reinitialized, not the connectivity structure (including the weights and delays).

            The parameter ``synapses`` will be used in a future release to also reinitialize the connectivity structure.

        """
        if attributes == -1:
            attributes = self.attributes

        for var in attributes:
            # Skip w
            if var=='w':
                continue
            # check it exists
            if not var in self.attributes:
                Global._warning("Projection.reset():", var, "is not an attribute of the population, won't reset.")
                continue
            # Set the value
            try:
                self.__setattr__(var, self.init[var])
            except Exception as e:
                Global._print(e)
                Global._warning("Projection.reset(): something went wrong while resetting", var)
Beispiel #13
0
    def parse(self, part=None):
        if not part:
            part = self.eq

        expression = transform_condition(part)

        # Check if there is a == in the condition
        if '==' in expression:
            # Is it the only term, or are there other operations?
            if '&' in expression or '|' in expression:
                expression = re.sub(r'([\w\s.]+)==([\w\s.]+)', r'Equality(\1, \2)', expression)
            else:
                terms = expression.split('==')
                expression = 'Equality(' + terms[0] + ', ' + terms[1] + ')'

        # Check if there is a != in the condition
        if '!=' in expression:
            # Is it the only term, or are there other operations?
            if '&' in expression or '|' in expression:
                expression = re.sub(r'([\w\s.]+)!=([\w\s.]+)', r'Not(Equality(\1, \2))', expression)
            else:
                terms = expression.split('!=')
                expression = 'Not(Equality(' + terms[0] + ', ' + terms[1] + '))'

        try:
            eq = parse_expr(expression,
                local_dict = self.local_dict,
                transformations = ((auto_number, convert_xor,))
            )
        except:
            Global._print(expression)
            Global._error('The function depends on unknown variables.')

        return ccode(eq, precision=8,
            user_functions=self.user_functions)
Beispiel #14
0
def check_and_apply_pow_fix(eqs):
    """
    CUDA SDKs before 7.5 had an error if std=c++11 is enabled related
    to pow(double, int). Only pow(double, double) was detected as
    device function, the pow(double, int) will be detected as host
    function. (This was fixed within SDK 7.5)

    To support also earlier versions, we simply add a double type cast.
    """
    if eqs.strip() == "":
        # nothing to do
        return eqs

    try:
        from ANNarchy.generator.CudaCheck import CudaCheck
        if CudaCheck().runtime_version() > 7000:
            # nothing to do, is working in higher SDKs
            return eqs
    except:
        Global._error('CUDA is not correctly installed on your system')

    if Global.config['verbose']:
        Global._print('occurance of pow() and SDK below 7.5 detected, apply fix.')

    # detect all pow statements
    pow_occur = re.findall(r"pow[\( [\S\s]*?\)*?, \d+\)]*?", eqs)
    for term in pow_occur:
        eqs = eqs.replace(term, term.replace(', ', ', (double)'))

    return eqs
Beispiel #15
0
    def create_synapse(self, rank, w=0.0, delay=0):
        """
        Creates a synapse for this dendrite with the given pre-synaptic neuron.

        *Parameters*:

        * **rank**: rank of the pre-synaptic neuron
        * **w**: synaptic weight (defalt: 0.0).
        * **delay**: synaptic delay (default = dt)
        """
        if not Global.config['structural_plasticity']:
            Global._error('"structural_plasticity" has not been set to True in setup(), can not add the synapse.')
            return

        if rank in self.pre_ranks:
            Global._error('the synapse of rank ' + str(rank) + ' already exists.')
            return

        # Set default values for the additional variables
        extra_attributes = {}
        for var in self.proj.synapse_type.description['parameters'] + self.proj.synapse_type.description['variables']:
            if not var['name'] in ['w', 'delay'] and  var['name'] in self.proj.synapse_type.description['local']:
                if not isinstance(self.proj.init[var['name']], (int, float, bool)):
                    init = var['init']
                else:
                    init = self.proj.init[var['name']]
                extra_attributes[var['name']] = init

        try:
            self.proj.cyInstance.add_synapse(self.post_rank, rank, w, int(delay/Global.config['dt']), **extra_attributes)
        except Exception as e:
            Global._print(e)
Beispiel #16
0
def extract_axon_spike_condition(description):
    """
    Extract the condition for emitting an axonal spike event. Further
    the reset after the event is returned.
    """
    if description['raw_axon_spike'] == None:
        return None

    cond = prepare_string(description['raw_axon_spike'])
    if len(cond) > 1:
        Global._print(description['raw_axon_spike'])
        Global._error('The spike condition must be a single expression')

    translator = Equation('raw_axon_spike_cond', cond[0].strip(), description)
    raw_spike_code = translator.parse()
    # Also store the variables used in the condition, as it may be needed for CUDA generation
    spike_code_dependencies = translator.dependencies()

    reset_desc = []
    if 'raw_reset' in description.keys() and description['raw_axon_reset']:
        reset_desc = process_equations(description['raw_axon_reset'])
        for var in reset_desc:
            translator = Equation(var['name'], var['eq'], description)
            var['cpp'] = translator.parse()
            var['dependencies'] = translator.dependencies()

    return {
        'spike_cond': raw_spike_code,
        'spike_cond_dependencies': spike_code_dependencies,
        'spike_reset': reset_desc
    }
Beispiel #17
0
    def _guess_proj_kernel_config(self, proj):
        """
        Instead of a fixed amount of threads for each kernel, we try
        to guess a good configuration based on the pre-synaptic population size.
        """
        from math import log

        max_tpb = 512
        warp_size = 32

        num_neur = proj.pre.size / 4  # at least 1/4 of the neurons are connected
        guess = warp_size  # smallest block is 1 warp

        # Simplest case: we have more neurons than
        # available threads per block
        if num_neur > max_tpb:
            guess = max_tpb

        # check which is the closest possible thread amount
        pow_of_2 = [
            2**x for x in range(int(log(warp_size, 2)),
                                int(log(max_tpb, 2)) + 1)
        ]
        for i in range(len(pow_of_2)):
            if pow_of_2[i] < num_neur:
                continue
            else:
                guess = pow_of_2[i]
                break

        if Global.config['verbose']:
            Global._print('projection', proj.id, ' - kernel size:', guess)

        return guess
Beispiel #18
0
 def runtime_version(self):
     try:
         result = self.cy_cc.runtime_version()
     except Exception as e:
         Global._print(e)
         Global._error('CUDA is not correctly installed on your system.')
     return result
Beispiel #19
0
def report_latex(filename="./report.tex",
                 standalone=True,
                 gather_subprojections=False,
                 net_id=0):
    """ Generates a .tex file describing the network according to:

    Nordlie E, Gewaltig M-O, Plesser HE (2009). Towards Reproducible Descriptions of Neuronal Network Models. PLoS Comput Biol 5(8): e1000456.

    **Parameters:**

    * *filename*: name of the .tex file where the report will be written (default: "./report.tex")
    * *standalone*: tells if the generated file should be directly compilable or only includable (default: True)
    * *gather_subprojections*: if a projection between two populations has been implemented as a multiple of projections between sub-populations, this flag allows to group them in the summary (default: False).
    * *net_id*: id of the network to be used for reporting (default: 0, everything that was declared)
    """

    # stdout
    Global._print('Generating report in', filename)

    # Generate the summary
    summary = _generate_summary(net_id)
    # Generate the populations
    populations = _generate_populations(net_id)
    # Generate the projections
    projections = _generate_projections(net_id, gather_subprojections)
    # Generate the neuron models
    neuron_models = _generate_neuron_models(net_id)
    # Generate the synapse models
    synapse_models = _generate_synapse_models(net_id)
    # Generate the constants
    constants = _generate_constants(net_id)
    # Generate the functions
    functions = _generate_functions(net_id)
    # Generate the population parameters
    pop_parameters = _generate_population_parameters(net_id)
    # Generate the population parameters
    proj_parameters = _generate_projection_parameters(net_id,
                                                      gather_subprojections)

    if not os.path.exists(os.path.dirname(filename)):
        os.makedirs(os.path.dirname(filename))

    with open(filename, 'w') as wfile:
        if standalone:
            wfile.write(header)
            wfile.write(preamble)
        wfile.write(summary)
        wfile.write(populations)
        wfile.write(projections)
        wfile.write(neuron_models)
        wfile.write(synapse_models)
        wfile.write(parameters_template)
        wfile.write(constants)
        wfile.write(functions)
        wfile.write(pop_parameters)
        wfile.write(proj_parameters)
        if standalone:
            wfile.write(footer)
Beispiel #20
0
 def version_str(self):
     """
     Returns cuda compatibility as string, usable for -gencode as argument.
     """
     try:
         cu_version = self.cy_cc.get_cuda_version()
     except Exception as e:
         Global._print(e)
         Global._error('CUDA is not correctly installed on your system.')
     return str(cu_version[0]) + str(cu_version[1])
Beispiel #21
0
            def idx_target(val):
                target = val.group(1).strip()
                if target == '':
                    Global._print(eq)
                    Global._error('post.sum() requires one argument.')

                dependencies['post'].append('sum('+target+')')
                rep = '_post_sum_' + target.strip()
                untouched[rep] = '%(post_prefix)s_sum_' + target + '%(post_index)s'
                return rep
Beispiel #22
0
 def version(self):
     """
     Returns cuda compatibility as tuple(major,minor)
     """
     try:
         result = self.cy_cc.get_cuda_version()
     except Exception as e:
         Global._print(e)
         Global._error('CUDA is not correctly installed on your system.')
     return result
Beispiel #23
0
def report_markdown(filename="./report.tex", standalone=True, gather_subprojections=False, title=None, author=None, date=None, net_id=0):
    """ Generates a .md file describing the network.

    *Parameters:*

    * **filename**: name of the .tex file where the report will be written (default: "./report.tex")
    * **standalone**: tells if the generated file should be directly compilable or only includable (ignored)
    * **gather_subprojections**: if a projection between two populations has been implemented as a multiple of projections between sub-populations, this flag allows to group them in the summary (default: False).
    * **net_id**: id of the network to be used for reporting (default: 0, everything that was declared)
    * **title**: title of the document (default: "Network description")
    * **author**: author of the document (default: "ANNarchy (Artificial Neural Networks architect)")
    * **date**: date of the document (default: empty)
    """

    # stdout
    Global._print('Generating report in', filename)

    # Header
    if title == None:
        title = "Network description"
    if author == None:
        author = "ANNarchy (Artificial Neural Networks architect)"
    if date == None:
        date = ""
    header = """---
title: %(title)s
author: %(author)s
date: %(date)s
---
""" % {'title': title, 'author': author, 'date': date}

    # Structure
    structure = _generate_summary(net_id)

    # Neurons
    neuron_models = _generate_neuron_models(net_id)

    # Synapses
    synapse_models = _generate_synapse_models(net_id)

    # Parameters
    parameters = _generate_parameters(net_id, gather_subprojections)

    # Possibly create the directory if it does not exist
    path_name = os.path.dirname(filename)
    if not path_name in ["", "."]:
        if not os.path.exists(path_name):
            os.makedirs(path_name)
        
    with open(filename, 'w') as wfile:
        wfile.write(header)
        wfile.write(structure)
        wfile.write(neuron_models)
        wfile.write(synapse_models)
        wfile.write(parameters)
Beispiel #24
0
            def idx_target(val):
                target = val.group(1).strip()
                if target == '':
                    Global._print(eq)
                    Global._error('post.sum() requires one argument.')

                dependencies['post'].append('sum(' + target + ')')
                rep = '_post_sum_' + target.strip()
                untouched[
                    rep] = '%(post_prefix)s_sum_' + target + '%(post_index)s'
                return rep
Beispiel #25
0
def report_latex(filename="./report.tex", standalone=True, gather_subprojections=False, net_id=0):
    """ Generates a .tex file describing the network according to:

    Nordlie E, Gewaltig M-O, Plesser HE (2009). Towards Reproducible Descriptions of Neuronal Network Models. PLoS Comput Biol 5(8): e1000456.

    **Parameters:**

    * *filename*: name of the .tex file where the report will be written (default: "./report.tex")
    * *standalone*: tells if the generated file should be directly compilable or only includable (default: True)
    * *gather_subprojections*: if a projection between two populations has been implemented as a multiple of projections between sub-populations, this flag allows to group them in the summary (default: False).
    * *net_id*: id of the network to be used for reporting (default: 0, everything that was declared)
    """

    # stdout
    Global._print('Generating report in', filename)

    # Generate the summary
    summary = _generate_summary(net_id)
    # Generate the populations
    populations = _generate_populations(net_id)
    # Generate the projections
    projections = _generate_projections(net_id, gather_subprojections)
    # Generate the neuron models
    neuron_models = _generate_neuron_models(net_id)
    # Generate the synapse models
    synapse_models = _generate_synapse_models(net_id)
    # Generate the constants
    constants = _generate_constants(net_id)
    # Generate the functions
    functions = _generate_functions(net_id)
    # Generate the population parameters
    pop_parameters = _generate_population_parameters(net_id)
    # Generate the population parameters
    proj_parameters = _generate_projection_parameters(net_id, gather_subprojections)

    if not os.path.exists(os.path.dirname(filename)):
        os.makedirs(os.path.dirname(filename))

    with open(filename, 'w') as wfile:
        if standalone:
            wfile.write(header)
            wfile.write(preamble)
        wfile.write(summary)
        wfile.write(populations)
        wfile.write(projections)
        wfile.write(neuron_models)
        wfile.write(synapse_models)
        wfile.write(parameters_template)
        wfile.write(constants)
        wfile.write(functions)
        wfile.write(pop_parameters)
        wfile.write(proj_parameters)
        if standalone:
            wfile.write(footer)
Beispiel #26
0
def connect_from_file(self, filename):
    """
    Builds a connection pattern using data saved using the Projection.save_connectivity() method (not save()!).

    *Parameters*:

    * **filename**: file where the data was saved.

    .. note::

        Only the ranks, weights and delays are loaded, not the other variables.
    """
    # Create an empty CSR object
    csr = Connector.CSR()

    # Load the data
    from ANNarchy.core.IO import _load_data
    try:
        data = _load_data(filename)
    except Exception as e:
        Global._print(e)
        Global._error('connect_from_file(): Unable to load the data', filename,
                      'into the projection.')
        exit(0)

    # Load the CSR object
    try:
        csr.post_rank = data['post_ranks']
        csr.pre_rank = data['pre_ranks']
        if isinstance(data['w'], (int, float)):
            self._single_constant_weight = True
            csr.w = [[data['w']]]
        else:
            csr.w = data['w']
        csr.size = data['size']
        csr.nb_synapses = data['nb_synapses']
        if data['delay']:
            csr.delay = data['delay']
        csr.max_delay = data['max_delay']
        csr.uniform_delay = data['uniform_delay']
    except Exception as e:
        Global._print(e)
        Global._error('Unable to load the data', filename,
                      'into the projection.')
        exit(0)

    # Store the synapses
    self.connector_name = "From File"
    self.connector_description = "From File"
    self._store_connectivity(
        self._load_from_csr, (csr, ),
        csr.max_delay if csr.uniform_delay > -1 else csr.delay)
    return self
Beispiel #27
0
def report_markdown(filename="./report.tex", standalone=True, gather_subprojections=False, title=None, author=None, date=None, net_id=0):
    """ Generates a .md file describing the network.

    *Parameters:*

    * **filename**: name of the .tex file where the report will be written (default: "./report.tex")
    * **standalone**: tells if the generated file should be directly compilable or only includable (ignored)
    * **gather_subprojections**: if a projection between two populations has been implemented as a multiple of projections between sub-populations, this flag allows to group them in the summary (default: False).
    * **net_id**: id of the network to be used for reporting (default: 0, everything that was declared)
    * **title**: title of the document (default: "Network description")
    * **author**: author of the document (default: "ANNarchy (Artificial Neural Networks architect)")
    * **date**: date of the document (default: empty)
    """

    # stdout
    Global._print('Generating report in', filename)

    # Header
    if title == None:
        title = "Network description"
    if author == None:
        author = "ANNarchy (Artificial Neural Networks architect)"
    if date == None:
        date = ""
    header = """---
title: %(title)s
author: %(author)s
date: %(date)s
---
""" % {'title': title, 'author': author, 'date': date}

    # Structure
    structure = _generate_summary(net_id)

    # Neurons
    neuron_models = _generate_neuron_models(net_id)

    # Synapses
    synapse_models = _generate_synapse_models(net_id)

    # Parameters
    parameters = _generate_parameters(net_id, gather_subprojections)

    if not os.path.exists(os.path.dirname(filename)):
        os.makedirs(os.path.dirname(filename))
        
    with open(filename, 'w') as wfile:
        wfile.write(header)
        wfile.write(structure)
        wfile.write(neuron_models)
        wfile.write(synapse_models)
        wfile.write(parameters)
Beispiel #28
0
    def get_projection(self, name):
        """
        Returns the projection with the given *name*.

        :param name: name of the projection
        :return: The requested ``Projection`` object if existing, ``None`` otherwise.
        """
        for proj in self.projections:
            if proj.name == name:
                return proj
        Global._print('get_projection(): the projection', name,
                      'does not exist in this network.')
        return None
Beispiel #29
0
    def connect(self):
        # create fake LIL object to have the forward view in C++
        try:
            from ANNarchy.core.cython_ext.Connector import LILConnectivity
        except Exception as e:
            Global._print(e)
            Global._error('ANNarchy was not successfully installed.')

        lil = LILConnectivity()
        lil.max_delay = self.max_delay
        lil.uniform_delay = self.uniform_delay
        self.connector_name = "Transpose"
        self.connector_description = "Transpose"
Beispiel #30
0
def _load_pop_data(pop, desc):
    """
    Update a population with the stored data set. 
    """
    if not 'attributes' in desc.keys():
        _error('Saved with a too old version of ANNarchy (< 4.2).', exit=True)
        
    for var in desc['attributes']:
        try:
            getattr(pop.cyInstance, 'set_'+var)(desc[var]) 
        except:
            Global._warning('Can not load the variable ' + var + ' in the population ' + pop.name)
            Global._print('Skipping this variable.')
            continue
Beispiel #31
0
def _load_data(filename):
    " Internally loads data contained in a file"   

    (path, fname) = os.path.split(filename)
    extension = os.path.splitext(fname)[1]
    desc = None
    if extension == '.mat':
        Global._error('Unable to load Matlab format.')
        return desc
    elif extension == '.gz':
        try:
            import gzip
        except:
            Global._error('gzip is not installed.')
            return desc
        try:
            with gzip.open(filename, mode = 'rb') as r_file:
                desc = pickle.load(r_file)
        except Exception as e:
            Global._print('Unable to read the file ' + filename)
            Global._print(e)
            return desc

    else:
        try:
            with open(filename, mode = 'rb') as r_file:
                desc = pickle.load(r_file)
        except Exception as e:
            Global._print('Unable to read the file ' + filename)
            Global._print(e)
            return desc
    return desc
Beispiel #32
0
def _check_locality(populations, projections):
    """
    Checks that a global variable does not depend on local ones.
    """
    for proj in projections:

        for var in proj.synapse_type.description['variables']:

            if var['locality'] == 'global': # cannot depend on local or semiglobal variables
                # Inside the equation
                for v in var['dependencies']:
                    if _get_locality(v, proj.synapse_type.description) in ['local', 'semiglobal']:
                        Global._print(var['eq'])
                        Global._error('The global variable', var['name'], 'cannot depend on a synapse-specific/post-synaptic one:', v)

                # As pre/post dependencies
                deps = var['prepost_dependencies']
                if len(deps['pre']) > 0 or len(deps['post']) > 0 : 
                    Global._print(proj.synapse_type.equations)
                    Global._error('The global variable', var['name'], 'cannot depend on pre- or post-synaptic variables.')

            if var['locality'] == 'semiglobal': # cannot depend on pre-synaptic variables
                # Inside the equation
                for v in var['dependencies']:
                    if _get_locality(v, proj.synapse_type.description) == 'local':
                        Global._print(var['eq'])
                        Global._error('The postsynaptic variable', var['name'], 'cannot depend on a synapse-specific one:', v)

                # As pre/post dependencies
                deps = var['prepost_dependencies']
                if len(deps['pre']) > 0  : 
                    Global._print(proj.synapse_type.equations)
                    Global._error('The postsynaptic variable', var['name'], 'cannot depend on pre-synaptic ones (e.g. pre.r).')
Beispiel #33
0
def _check_prepost(populations, projections):
    """
    Checks that when a synapse uses pre.x r post.x, the variable x exists in the corresponding neuron
    """
    for proj in projections:

        for dep in  proj.synapse_type.description['dependencies']['pre']:
            if dep.startswith('sum('):
                target = re.findall(r'\(([\s\w]+)\)', dep)[0].strip()
                if not target in proj.pre.targets:
                    Global._print(proj.synapse_type.equations)
                    Global._error('The pre-synaptic population ' + proj.pre.name + ' receives no projection with the type ' + target)
                continue

            if not dep in proj.pre.attributes:
                Global._print(proj.synapse_type.equations)
                Global._error('The pre-synaptic population ' + proj.pre.name + ' has no variable called ' + dep)

        for dep in proj.synapse_type.description['dependencies']['post']:
            if dep.startswith('sum('):
                target = re.findall(r'\(([\s\w]+)\)', dep)[0].strip()
                if not target in proj.post.targets:
                    Global._print(proj.synapse_type.equations)
                    Global._error('The post-synaptic population ' + proj.post.name + ' receives no projection with the type ' + target)
                continue

            if not dep in proj.post.attributes:
                Global._print(proj.synapse_type.equations)
                Global._error('The post-synaptic population ' + proj.post.name + ' has no variable called ' + dep)
Beispiel #34
0
    def _create(self):
        # create fake CSR object, just for compilation.
        try:
            from ANNarchy.core.cython_ext.Connector import CSR
        except Exception as e:
            Global._print(e)
            Global._error('ANNarchy was not successfully installed.')

        csr = CSR()
        csr.max_delay = self.delays
        csr.uniform_delay = self.delays
        self.connector_name = "Shared weights"
        self.connector_description = "Shared weights"
        self._store_connectivity(self._load_from_csr, (csr, ), self.delays)
Beispiel #35
0
    def parse_expression(self, expression, local_dict):
        " Parses a string with respect to the vocabulary defined in local_dict."
        from sympy.parsing.sympy_parser import parse_expr, standard_transformations, convert_xor, auto_number, rationalize
        try:
            res = parse_expr(expression,
                             local_dict=local_dict,
                             transformations=(standard_transformations +
                                              (convert_xor, )),
                             evaluate=False)
        except Exception as e:
            Global._print(e)
            Global._error('Can not analyse the expression :' + str(expression))

        return res
Beispiel #36
0
    def _create(self):
        # create fake LIL object, just for compilation.
        try:
            from ANNarchy.core.cython_ext.Connector import LILConnectivity
        except Exception as e:
            Global._print(e)
            Global._error('ANNarchy was not successfully installed.')

        lil = LILConnectivity()
        lil.max_delay = self.delays
        lil.uniform_delay = self.delays
        self.connector_name = "Copy"
        self.connector_description = "Copy projection"
        self._store_connectivity(self._load_from_lil, (lil, ), self.delays)
Beispiel #37
0
def connect_from_file(self, filename):
    """
    Builds a connection pattern using data saved using the Projection.save_connectivity() method (not save()!).

    *Parameters*:

    * **filename**: file where the data was saved.

    .. note::

        Only the ranks, weights and delays are loaded, not the other variables.
    """
    # Create an empty CSR object
    csr = Connector.CSR()

    # Load the data        
    from ANNarchy.core.IO import _load_data
    try:
        data = _load_data(filename)
    except Exception as e:
        Global._print(e)
        Global._error('connect_from_file(): Unable to load the data', filename, 'into the projection.')
        exit(0)

    # Load the CSR object
    try:
        csr.post_rank = data['post_ranks']
        csr.pre_rank = data['pre_ranks']
        if isinstance(data['w'], (int, float)):
            self._single_constant_weight = True
            csr.w = [[data['w']]]
        else:
            csr.w = data['w']
        csr.size = data['size']
        csr.nb_synapses = data['nb_synapses']
        if data['delay']:
            csr.delay = data['delay']
        csr.max_delay = data['max_delay']
        csr.uniform_delay = data['uniform_delay']
    except Exception as e:
        Global._print(e)
        Global._error('Unable to load the data', filename, 'into the projection.')
        exit(0)

    # Store the synapses
    self.connector_name = "From File"
    self.connector_description = "From File"
    self._store_connectivity(self._load_from_csr, (csr,), csr.max_delay if csr.uniform_delay > -1 else csr.delay)
    return self
Beispiel #38
0
    def parse_expression(self, expression, local_dict):
        " Parses a string with respect to the vocabulary defined in local_dict."
        from sympy.parsing.sympy_parser import parse_expr, standard_transformations, convert_xor
        try:
            res =  parse_expr(transform_condition(expression),
                local_dict = local_dict,
                transformations = (standard_transformations + (convert_xor,)),
                #evaluate=False
            )
        except Exception as e:
            Global._print(e)
            Global._error('Can not analyse the expression :' +  str(expression))

        else:
            return res
Beispiel #39
0
def _load_from_matrix(self, pre, post, weights, delays, pre_post):
    csr = Connector.CSR()

    uniform_delay = not isinstance(delays, (list, np.ndarray))
    if isinstance(delays, list):
        try:
            delays = np.array(delays)
        except:
            Global._error(
                'connect_from_matrix(): You must provide a dense 2D matrix.')
            exit(0)

    if pre_post:  # if the user prefers pre as the first index...
        weights = weights.T
        if isinstance(delays, np.ndarray):
            delays = delays.T

    shape = weights.shape
    if shape != (self.post.size, self.pre.size):
        if not pre_post:
            Global._error(
                "connect_from_matrix(): the matrix does not have the correct dimensions."
            )
            Global._print('Expected:', (self.post.size, self.pre.size))
            Global._print('Received:', shape)
        else:
            Global._error(
                "connect_from_matrix(): the matrix does not have the correct dimensions."
            )
            Global._print('Expected:', (self.pre.size, self.post.size))
            Global._print('Received:', shape)
        exit(0)

    for i in range(self.post.size):
        if isinstance(self.post, PopulationView):
            rk_post = self.post.ranks[i]
        else:
            rk_post = i
        r = []
        w = []
        d = []
        for j in range(self.pre.size):
            val = weights[i, j]
            if val != None:
                if isinstance(self.pre, PopulationView):
                    rk_pre = self.pre.ranks[j]
                else:
                    rk_pre = j
                r.append(rk_pre)
                w.append(val)
                if not uniform_delay:
                    d.append(delays[i, j])
        if uniform_delay:
            d.append(delays)
        if len(r) > 0:
            csr.add(rk_post, r, w, d)

    return csr
Beispiel #40
0
    def get_projection(self, name):
        """
        Returns the projection with the given *name*.

        *Parameter*:

        * **name**: name of the projection

        *Returns:*

        * The requested ``Projection`` object if existing, ``None`` otherwise.
        """
        for proj in self.projections:
            if proj.name == name:
                return proj
        Global._print('get_projection(): the projection', name, 'does not exist in this network.')
        return None
Beispiel #41
0
 def parse(self):
     "Main method called after creating the object."
     try:
         if self.type == 'ODE':
             code = self.analyse_ODE(self.expression)
         elif self.type == 'cond':
             code = self.analyse_condition(self.expression)
         elif self.type == 'inc':
             code = self.analyse_increment(self.expression)
         elif self.type == 'return':
             code = self.analyse_return(self.expression)
         elif self.type == 'simple':
             code = self.analyse_assignment(self.expression)
     except Exception as e:
         Global._print(e)
         Global._error('Can not analyse', self.expression)
     return code
Beispiel #42
0
    def implicit(self, expression):
        "Full implicit method, linearising for example (V - E)^2, but this is not desired."

        # print('Expression', expression)
        # Transform the gradient into a difference TODO: more robust...
        new_expression = expression.replace('d' + self.name, '_t_gradient_')
        new_expression = re.sub(r'([^\w]+)' + self.name + r'([^\w]+)',
                                r'\1_' + self.name + r'\2', new_expression)
        new_expression = new_expression.replace(
            '_t_gradient_', '(_' + self.name + ' - ' + self.name + ')')

        # print('New Expression', new_expression)

        # Add a sympbol for the next value of the variable
        new_var = sp.Symbol('_' + self.name)
        self.local_dict['_' + self.name] = new_var

        # Parse the string
        analysed = self.parse_expression(new_expression,
                                         local_dict=self.local_dict)
        self.analysed = analysed
        # print('Analysed', analysed)

        # Solve the equation for delta_mp
        solved = sp.solve(analysed, new_var, check=False, rational=False)
        # print('Solved', solved)
        if len(solved) > 1:
            Global._print(self.expression)
            Global._error(
                'Parser: the ODE is not linear, can not use the implicit method.'
            )

        else:
            solved = solved[0]

        equation = sp.simplify(sp.collect(solved, self.local_dict['dt']))

        # Obtain C code
        variable_name = self.c_code(self.local_dict[self.name])

        explicit_code = Global.config['precision'] + ' _' + self.name + ' = '\
                        +  self.c_code(equation) + ';'
        switch = variable_name + ' = _' + self.name + ' ;'

        # Return result
        return [{}, explicit_code, switch]
Beispiel #43
0
 def parse(self):
     "Main method called after creating the object."
     try:
         if self.type == 'ODE':
             code = self.analyse_ODE(self.expression)
         elif self.type == 'cond':
             code = self.analyse_condition(self.expression)
         elif self.type == 'inc':
             code = self.analyse_increment(self.expression)
         elif self.type == 'return':
             code = self.analyse_return(self.expression)
         elif self.type == 'simple':
             code = self.analyse_assignment(self.expression)
     except Exception as e:
         Global._print(e)
         Global._error('Parser: cannot analyse', self.expression)
     return code
Beispiel #44
0
    def parse(self):
        "Main method called after creating the object."
        # Check if the numerical method is the same for all ODEs
        methods = []
        for var in self.variables:
            methods.append(var['method'])
        if len(list(set(methods))) > 1: # mixture of methods
            Global._print(methods)
            Global._error('Can not mix different numerical methods when solving a coupled system of equations.')
            
        else:
            method = methods[0]

        if method == 'implicit' or method == 'semiimplicit':
            return self.solve_implicit(self.expression_list)
        elif method == 'midpoint': 
            return self.solve_midpoint(self.expression_list)
Beispiel #45
0
    def _get_cython_attribute(self, attribute):
        """
        Returns the value of the given attribute for all neurons in the population,
        as a NumPy array having the same geometry as the population if it is local.

        Parameter:

        * *attribute*: should be a string representing the variables's name.

        """
        try:
            if attribute in self.neuron_type.description["local"]:
                return getattr(self.cyInstance, "get_" + attribute)().reshape(self.geometry)
            else:
                return getattr(self.cyInstance, "get_" + attribute)()
        except Exception as e:
            Global._print(e)
            Global._error(" the variable " + attribute + " does not exist in this population (" + self.name + ")")
Beispiel #46
0
    def _create(self):
        """
        create fake LIL object, just for compilation process

        :return: no return value
        """
        try:
            from ANNarchy.core.cython_ext.Connector import LILConnectivity
        except Exception as e:
            Global._print(e)
            Global._error('ANNarchy was not successfully installed.')

        lil = LILConnectivity()
        lil.max_delay = self.delays
        lil.uniform_delay = self.delays
        self.connector_name = "Shared weights"
        self.connector_description = "Shared weights"
        self._store_connectivity(self._load_from_lil, (lil, ), self.delays)
Beispiel #47
0
    def _init_attributes(self):
        """ Method used after compilation to initialize the attributes."""
        self.initialized = True
        self.set(self.init)
        self.cyInstance.activate(self.enabled)
        self.cyInstance.reset()

        # If the spike population has a refractory period:
        if self.neuron_type.type == "spike" and self.neuron_type.description["refractory"]:
            if isinstance(self.neuron_type.description["refractory"], str):  # a global variable
                try:
                    self.refractory = eval("self." + self.neuron_type.description["refractory"])
                except Exception as e:
                    Global._print(e, self.neuron_type.description["refractory"])
                    Global._error("The initialization for the refractory period is not valid.")

            else:  # a value
                self.refractory = self.neuron_type.description["refractory"]
Beispiel #48
0
    def implicit(self, expression):
        "Full implicit method, linearising for example (V - E)^2, but this is not desired."

        # print('Expression', expression)
        # Transform the gradient into a difference TODO: more robust...
        new_expression = expression.replace('d'+self.name, '_t_gradient_')
        new_expression = re.sub(r'([^\w]+)'+self.name+r'([^\w]+)', r'\1_'+self.name+r'\2', new_expression)
        new_expression = new_expression.replace('_t_gradient_', '(_'+self.name+' - '+self.name+')')

        # print('New Expression', new_expression)

        # Add a sympbol for the next value of the variable
        new_var = Symbol('_'+self.name)
        self.local_dict['_'+self.name] = new_var

        # Parse the string
        analysed = self.parse_expression(new_expression,
            local_dict = self.local_dict
        )
        self.analysed = analysed
        # print('Analysed', analysed)

        # Solve the equation for delta_mp
        solved = solve(analysed, new_var)
        # print('Solved', solved)
        if len(solved) > 1:
            Global._print(self.expression)
            Global._error('the ODE is not linear, can not use the implicit method.')

        else:
            solved = solved[0]

        equation = simplify(collect( solved, self.local_dict['dt']))

        # Obtain C code
        variable_name = self.c_code(self.local_dict[self.name])

        explicit_code = Global.config['precision'] + ' _' + self.name + ' = '\
                        +  self.c_code(equation) + ';'
        switch = variable_name + ' = _' + self.name + ' ;'

        # Return result
        return [{}, explicit_code, switch]
Beispiel #49
0
def _load_from_matrix(self, pre, post, weights, delays, pre_post):
    csr = Connector.CSR()

    uniform_delay = not isinstance(delays, (list, np.ndarray))
    if isinstance(delays, list):
        try:
            delays= np.array(delays)
        except:
            Global._error('connect_from_matrix(): You must provide a dense 2D matrix.')
            exit(0)

    if pre_post: # if the user prefers pre as the first index...
        weights = weights.T
        if isinstance(delays, np.ndarray):
            delays = delays.T

    shape = weights.shape
    if shape != (self.post.size, self.pre.size):
        if not pre_post:
            Global._error("connect_from_matrix(): the matrix does not have the correct dimensions.")
            Global._print('Expected:', (self.post.size, self.pre.size))
            Global._print('Received:', shape)
        else:
            Global._error("connect_from_matrix(): the matrix does not have the correct dimensions.")
            Global._print('Expected:', (self.pre.size, self.post.size))
            Global._print('Received:', shape)
        exit(0)

    for i in range(self.post.size):
        if isinstance(self.post, PopulationView):
            rk_post = self.post.ranks[i]
        else:
            rk_post = i
        r = []
        w = []
        d = []
        for j in range(self.pre.size):
            val = weights[i, j]
            if val != None:
                if isinstance(self.pre, PopulationView):
                    rk_pre = self.pre.ranks[j]
                else:
                    rk_pre = j
                r.append(rk_pre)
                w.append(val) 
                if not uniform_delay:
                    d.append(delays[i,j])   
        if uniform_delay:        
            d.append(delays)
        if len(r) > 0:
            csr.add(rk_post, r, w, d)

    return csr
Beispiel #50
0
    def _get_cython_attribute(self, attribute):
        """
        Returns the value of the given attribute for all neurons in the population,
        as a NumPy array having the same geometry as the population if it is local.

        *Parameter:*

        * **attribute**: should be a string representing the variables's name.

        """
        try:
            if attribute in self.neuron_type.description['local']:
                data = getattr(self.cyInstance, 'get_'+attribute)()
                return data.reshape(self.geometry)
            else:
                return getattr(self.cyInstance, 'get_'+attribute)()
        except Exception as e:
            Global._print(e)
            Global._error(' the variable ' +  attribute +  ' does not exist in this population (' + self.name + ')')
Beispiel #51
0
def _load_from_sparse(self, pre, post, weights, delays):
    # Create an empty LIL object
    lil = LILConnectivity()

    # Find offsets
    if isinstance(self.pre, PopulationView):
        pre_ranks = self.pre.ranks
    else:
        pre_ranks = [i for i in range(self.pre.size)]

    if isinstance(self.post, PopulationView):
        post_ranks = self.post.ranks
    else:
        post_ranks = [i for i in range(self.post.size)]

    # Process the sparse matrix and fill the lil
    weights.sort_indices()
    (pre, post) = weights.shape

    if (pre, post) != (len(pre_ranks), len(post_ranks)):
        Global._print("ERROR: connect_from_sparse(): the sparse matrix does not have the correct dimensions.")
        Global._print('Expected:', (len(pre_ranks), len(post_ranks)))
        Global._print('Received:', (pre, post))
        Global._error('Quitting...')


    for idx_post in range(post):
        idx_pre = weights.getcol(idx_post).indices
        w = weights.getcol(idx_post).data
        pr = [pre_ranks[i] for i in idx_pre]
        lil.add(post_ranks[idx_post], pr, w, [float(delays)])

    return lil
Beispiel #52
0
def _analyse_equation(orig, eq, local_dict, tex_dict):

    # Analyse the left part
    left = eq.split('=')[0]
    split_idx = len(left)
    if left[-1] in ['+', '-', '*', '/']:
        op = left[-1]
        try:
            left = _analyse_part(left[:-1], local_dict, tex_dict)
        except Exception as e:
            Global._print(e)
            Global._warning('can not transform the left side of ' + orig +' to LaTeX, you have to do it by hand...')
            left = left[:-1]
        operator = " = " + left +  " " + op + (" (" if op != '+' else '')
        operator = " \mathrel{" + op + "}= " 
    else:
        try:
            left = _analyse_part(left, local_dict, tex_dict)
        except Exception as e:
            Global._print(e)
            Global._warning('can not transform the left side of ' + orig +' to LaTeX, you have to do it by hand...')
        operator = " = "

    # Analyse the right part
    try:
        right = _analyse_part(eq[split_idx+1:], local_dict, tex_dict)
    except Exception as e:
        Global._print(e)
        Global._warning('can not transform the right side of ' + orig +' to LaTeX, you have to do it by hand...')
        right = "\\textbf{TODO} %%" + eq[split_idx+1:]

    return left + operator + right + (" )" if operator.strip().endswith('(') else "")
Beispiel #53
0
def connect_one_to_one(self, weights=1.0, delays=0.0, force_multiple_weights=False):
    """
    Builds a one-to-one connection pattern between the two populations.

    *Parameters*:

    * **weights**: initial synaptic values, either a single value (float) or a random distribution object.
    * **delays**: synaptic delays, either a single value or a random distribution object (default=dt).
    * **force_multiple_weights**: if a single value is provided for ``weights`` and there is no learning, a single weight value will be used for the whole projection instead of one per synapse. Setting ``force_multiple_weights`` to True ensures that a value per synapse will be used.
    """
    if self.pre.size != self.post.size:
        Global._warning("connect_one_to_one() between", self.pre.name, 'and', self.post.name, 'with target', self.target)
        Global._print("\t the two populations have different sizes, please check the connection pattern is what you expect.")

    self.connector_name = "One-to-One"
    self.connector_description = "One-to-One, weights %(weight)s, delays %(delay)s" % {'weight': _process_random(weights), 'delay': _process_random(delays)}

    if isinstance(weights, (int, float)) and not force_multiple_weights:
        self._single_constant_weight = True

    self._store_connectivity( one_to_one, (weights, delays, "lil", "post_to_pre"), delays )
    return self
Beispiel #54
0
    def check_structure(self):
        """
        Checks the structure to display more useful error messages.
        """
        # Check populations
        for pop in self.populations:
            # Reserved variable names
            for term in ['t', 'dt', 't_pre', 't_post', 't_spike']:
                if term in pop.attributes:
                    Global._print(pop.neuron_type.parameters)
                    Global._print(pop.neuron_type.equations)
                    Global._error(term + ' is a reserved variable name')
                    exit(0)

        # Check projections
        for proj in self.projections:
            # Reserved variable names
            for term in ['t', 'dt', 't_pre', 't_post', 't_spike']:
                if term in proj.attributes:
                    Global._print(proj.synapse_type.parameters)
                    Global._print(proj.synapse_type.equations)
                    Global._error(term + ' is a reserved variable name')
                    exit(0)
            # Check the connector method has been called
            if not proj._connection_method:
                Global._error('The projection between populations', proj.pre.id, 'and', proj.post.id, 'has not been connected. Call a connector method before compiling the network.')
                exit(0)

            # Check existing pre variables
            for dep in  proj.synapse_type.description['dependencies']['pre']:
                if dep.startswith('sum('):
                    target = re.findall(r'\(([\s\w]+)\)', dep)[0].strip()
                    if not target in proj.pre.targets:
                        Global._error('The pre-synaptic population ' + proj.pre.name + ' receives no projection with the type ' + target)
                        exit(0)
                    continue 
                if not dep in proj.pre.attributes:
                    Global._error('The pre-synaptic population ' + proj.pre.name + ' has no variable called ' + dep)
                    exit(0)
            for dep in  proj.synapse_type.description['dependencies']['post']:
                if dep.startswith('sum('):
                    target = re.findall(r'\(([\s\w]+)\)', dep)[0].strip()
                    if not target in proj.post.targets:
                        Global._error('The post-synaptic population ' + proj.post.name + ' receives no projection with the type ' + target)
                        exit(0)
                    continue 
                if not dep in proj.post.attributes:
                    Global._error('The post-synaptic population ' + proj.post.name + ' has no variable called ' + dep)
                    exit(0)