From c5af4021febdb1cfb3add773f4d58154d9165280 Mon Sep 17 00:00:00 2001 From: thesamovar Date: Tue, 24 Sep 2013 22:05:30 -0400 Subject: [PATCH] Created new Group._set_with_code_conditional will be needed for standalone mode, works in runtime but not used automatically, doesn't work in standalone because _array_i is not defined --- brian2/codegen/codeobject.py | 8 ++- brian2/codegen/languages/cpp_lang.py | 2 +- .../group_variable_set_conditional.py_ | 16 +++++ .../group_variable_set_conditional.cpp | 21 ++++++ .../group_variable_set_conditional.cpp | 64 +++++++++++++++++++ brian2/groups/group.py | 55 ++++++++++++++-- dev/ideas/devices/cpp_standalone.py | 18 +++++- 7 files changed, 172 insertions(+), 12 deletions(-) create mode 100644 brian2/codegen/runtime/numpy_rt/templates/group_variable_set_conditional.py_ create mode 100644 brian2/codegen/runtime/weave_rt/templates/group_variable_set_conditional.cpp create mode 100644 brian2/devices/cpp_standalone/templates/group_variable_set_conditional.cpp diff --git a/brian2/codegen/codeobject.py b/brian2/codegen/codeobject.py index 241b8ec80..ac74f5d88 100644 --- a/brian2/codegen/codeobject.py +++ b/brian2/codegen/codeobject.py @@ -64,7 +64,11 @@ def create_codeobject(owner, name, abstract_code, namespace, variables, template namespace = prepare_namespace(namespace, variables, codeobj_class=codeobj_class) - logger.debug(name + " abstract code:\n" + abstract_code) + if isinstance(abstract_code, dict): + for k, v in abstract_code.items(): + logger.debug('%s abstract code key %s:\n%s' % (name, k, v)) + else: + logger.debug(name + " abstract code:\n" + abstract_code) iterate_all = template.iterate_all if isinstance(abstract_code, dict): snippet = {} @@ -76,7 +80,7 @@ def create_codeobject(owner, name, abstract_code, namespace, variables, template variable_indices=variable_indices, iterate_all=iterate_all) snippet[ac_name] = snip - for k, v in snip_kwds: + for k, v in snip_kwds.items(): kwds[ac_name+'_'+k] = v else: diff --git a/brian2/codegen/languages/cpp_lang.py b/brian2/codegen/languages/cpp_lang.py index 0fdc12f0b..c7ae10ed9 100644 --- a/brian2/codegen/languages/cpp_lang.py +++ b/brian2/codegen/languages/cpp_lang.py @@ -215,7 +215,7 @@ def translate_statement_sequence(self, statements, variables, namespace, func_namespace = func.implementations[codeobj_class].namespace if func_namespace is not None: namespace.update(func_namespace) - + return (stripped_deindented_lines(code), {'pointers_lines': stripped_deindented_lines(pointers), 'support_code_lines': stripped_deindented_lines(support_code), diff --git a/brian2/codegen/runtime/numpy_rt/templates/group_variable_set_conditional.py_ b/brian2/codegen/runtime/numpy_rt/templates/group_variable_set_conditional.py_ new file mode 100644 index 000000000..9ca60bb8b --- /dev/null +++ b/brian2/codegen/runtime/numpy_rt/templates/group_variable_set_conditional.py_ @@ -0,0 +1,16 @@ +# Phase 1: we compute the indices where the conditional setting is to +# be applied, and to do this we want to vectorise over all the values, +# but we don't want to do the iterate all protocol, so we explicitly +# set the idx to be slice(None) +_vectorisation_idx = _idx = slice(None) +{% for line in code_lines['condition'] %} +{{line}} +{% endfor %} + +# Phase 2: having computed _cond, the boolean array of points where +# the setting is to be applied, we want to vectorise over idx being +# only these values. +_vectorisation_idx = _idx = _cond +{% for line in code_lines['statement'] %} +{{line}} +{% endfor %} diff --git a/brian2/codegen/runtime/weave_rt/templates/group_variable_set_conditional.cpp b/brian2/codegen/runtime/weave_rt/templates/group_variable_set_conditional.cpp new file mode 100644 index 000000000..b674a9924 --- /dev/null +++ b/brian2/codegen/runtime/weave_rt/templates/group_variable_set_conditional.cpp @@ -0,0 +1,21 @@ +{% import 'common_macros.cpp' as common with context %} + +{% macro main() %} + {{ common.insert_lines_commented('SUPPORT CODE', condition_support_code_lines) }} + {{ common.insert_lines('HANDLE DENORMALS', condition_denormals_code_lines) }} + {{ common.insert_lines('HASH DEFINES', condition_hashdefine_lines) }} + {{ common.insert_lines('POINTERS', condition_pointers_lines) }} + //// MAIN CODE //////////// + for(int _idx=0; _idx<_num_idx; _idx++) + { + const int _vectorisation_idx = _idx; + {{ common.insert_lines('CONDITION', code_lines['condition']) }} + if(_cond) { + {{ common.insert_lines('STATEMENT', code_lines['statement']) }} + } + } +{% endmacro %} + +{% macro support_code() %} + {{ common.insert_lines('SUPPORT CODE', condition_support_code_lines) }} +{% endmacro %} diff --git a/brian2/devices/cpp_standalone/templates/group_variable_set_conditional.cpp b/brian2/devices/cpp_standalone/templates/group_variable_set_conditional.cpp new file mode 100644 index 000000000..bd0eecb0f --- /dev/null +++ b/brian2/devices/cpp_standalone/templates/group_variable_set_conditional.cpp @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////// +//// MAIN CODE ///////////////////////////////////////////////////////////// + +{% macro cpp_file() %} + +#include "{{codeobj_name}}.h" +#include +#include "brianlib/common_math.h" +#include + +////// SUPPORT CODE /////// +namespace { + {% for line in condition_support_code_lines %} + {{line}} + {% endfor %} +} + +////// HASH DEFINES /////// +{% for line in condition_hashdefine_lines %} +{{line}} +{% endfor %} + +void _run_{{codeobj_name}}(double t) +{ + ///// CONSTANTS /////////// + %CONSTANTS% + ///// POINTERS //////////// + {% for line in condition_pointers_lines %} + {{line}} + {% endfor %} + + //// MAIN CODE //////////// + const int _num_group_idx = _num_idx; + for(int _idx_group_idx=0; _idx_group_idx<_num_group_idx; _idx_group_idx++) + { + //const int _idx = _group_idx[_idx_group_idx]; + const int _idx = _idx_group_idx; + const int _vectorisation_idx = _idx; + {% for line in code_lines['condition'] %} + {{line}} + {% endfor %} + if(_cond) + { + {% for line in code_lines['statement'] %} + {{line}} + {% endfor %} + } + } +} +{% endmacro %} + +//////////////////////////////////////////////////////////////////////////// +//// HEADER FILE /////////////////////////////////////////////////////////// + +{% macro h_file() %} +#ifndef _INCLUDED_{{codeobj_name}} +#define _INCLUDED_{{codeobj_name}} + +#include "arrays.h" + +void _run_{{codeobj_name}}(double t); + +#endif +{% endmacro %} diff --git a/brian2/groups/group.py b/brian2/groups/group.py index ee52674b7..81fb566a8 100644 --- a/brian2/groups/group.py +++ b/brian2/groups/group.py @@ -218,7 +218,27 @@ def _set_with_code(self, variable, group_indices, code, additional_namespace=additional_namespace, check_units=check_units) codeobj() - + + def _set_with_code_conditional(self, variable, cond, code, + template, check_units=True, level=0): + abstract_code_cond = '_cond = '+cond + abstract_code = variable.name + ' = ' + code + namespace = get_local_namespace(level + 1) + additional_namespace = ('implicit-namespace', namespace) + additional_variables = self.item_mapping.variables + check_code_units(abstract_code_cond, self, + additional_variables=additional_variables, + additional_namespace=additional_namespace) + # TODO: Have an additional argument to avoid going through the index + # array for situations where iterate_all could be used + codeobj = create_runner_codeobj(self, + {'condition': abstract_code_cond, 'statement': abstract_code}, + template, + additional_variables=additional_variables, + additional_namespace=additional_namespace, + check_units=check_units) + codeobj() + def check_code_units(code, group, additional_variables=None, additional_namespace=None, @@ -249,6 +269,11 @@ def check_code_units(code, group, additional_variables=None, DimensionMismatchError If `code` has unit mismatches ''' + if isinstance(code, dict): + for v in code.values(): + check_code_units(v, group, additional_variables=additional_variables, + additional_namespace=additional_namespace, + ignore_keyerrors=ignore_keyerrors) all_variables = dict(group.variables) if additional_variables is not None: all_variables.update(additional_variables) @@ -259,7 +284,13 @@ def check_code_units(code, group, additional_variables=None, # Note that here we do not need to recursively descend into # subexpressions. For unit checking, we only need to know the units of # the subexpressions not what variables they refer to - _, _, unknown = analyse_identifiers(code, all_variables) + if isinstance(code, dict): + unknown = set() + for v in code.values(): + _, _, u = analyse_identifiers(v, all_variables) + unknown |= u + else: + _, _, unknown = analyse_identifiers(code, all_variables) try: resolved_namespace = group.namespace.resolve_all(unknown, additional_namespace, @@ -272,7 +303,11 @@ def check_code_units(code, group, additional_variables=None, else: raise ex - check_units_statements(code, resolved_namespace, all_variables) + if isinstance(code, dict): + for v in code.values(): + check_units_statements(v, resolved_namespace, all_variables) + else: + check_units_statements(code, resolved_namespace, all_variables) def create_runner_codeobj(group, code, template_name, indices=None, @@ -332,10 +367,18 @@ def create_runner_codeobj(group, code, template_name, indices=None, all_variables = dict(group.variables) if additional_variables is not None: all_variables.update(additional_variables) - + # Determine the identifiers that were used - _, used_known, unknown = analyse_identifiers(code, all_variables, - recursive=True) + if isinstance(code, dict): + used_known = set() + unknown = set() + for v in code.values(): + _, uk, u = analyse_identifiers(v, all_variables, recursive=True) + used_known |= uk + unknown |= u + else: + _, used_known, unknown = analyse_identifiers(code, all_variables, + recursive=True) logger.debug('Unknown identifiers in the abstract code: ' + str(unknown)) diff --git a/dev/ideas/devices/cpp_standalone.py b/dev/ideas/devices/cpp_standalone.py index 9c950ea7e..11d5f4214 100644 --- a/dev/ideas/devices/cpp_standalone.py +++ b/dev/ideas/devices/cpp_standalone.py @@ -9,11 +9,16 @@ from brian2 import * import time +BrianLogger.log_level_debug() + start = time.time() if standalone_mode: from brian2.devices.cpp_standalone import * set_device('cpp_standalone') +else: + brian_prefs['codegen.target'] = 'weave' + #brian_prefs['codegen.target'] = 'numpy' ##### Define the model tau = 1*ms @@ -34,12 +39,19 @@ refractory=refractory, name='gp') M = SpikeMonitor(G) -#G2 = NeuronGroup(1, eqs, reset=reset, threshold=threshold, refractory=refractory, name='gp2') +G2 = NeuronGroup(1, eqs, reset=reset, threshold=threshold, refractory=refractory, name='gp2') +#S = Synapses(G, G2, 'w:volt', pre='V+=w') # Run the network for 0 seconds to generate the code -G.V = '1*volt' +#print G.V.__class__ +#exit() +#G.V['i>10'] = '1*volt' +#G._set_with_code_conditional(G.variables['V'], 'i>10', '1*volt', 'group_variable_set_conditional') +#print G.V[0], G.V[11] +#exit() net = Network(G, M, - #G2, + G2, + #S, ) if not standalone_mode: