Skip to content

Commit

Permalink
Merge cc5962b into 9429991
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcel Stimberg committed Oct 8, 2013
2 parents 9429991 + cc5962b commit 9a2bdba
Show file tree
Hide file tree
Showing 56 changed files with 1,195 additions and 819 deletions.
34 changes: 11 additions & 23 deletions brian2/codegen/codeobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def prepare_namespace(namespace, variables, codeobj_class):
return namespace


def create_codeobject(owner, name, abstract_code, namespace, variables, template_name,
indices, variable_indices, codeobj_class,
def create_codeobject(owner, name, abstract_code, namespace, variables,
template_name, variable_indices, codeobj_class,
template_kwds=None):
'''
The following arguments keywords are passed to the template:
Expand All @@ -64,33 +64,21 @@ 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)
iterate_all = template.iterate_all
if isinstance(abstract_code, dict):
snippet = {}
kwds = {}
for ac_name, ac in abstract_code.iteritems():
snip, snip_kwds = translate(ac, variables, namespace,
dtype=brian_prefs['core.default_scalar_dtype'],
codeobj_class=codeobj_class,
variable_indices=variable_indices,
iterate_all=iterate_all)
snippet[ac_name] = snip
for k, v in snip_kwds:
kwds[ac_name+'_'+k] = v

for k, v in abstract_code.items():
logger.debug('%s abstract code key %s:\n%s' % (name, k, v))
else:
snippet, kwds = translate(abstract_code, variables, namespace,
dtype=brian_prefs['core.default_scalar_dtype'],
codeobj_class=codeobj_class,
variable_indices=variable_indices,
iterate_all=iterate_all)
logger.debug(name + " abstract code:\n" + abstract_code)
iterate_all = template.iterate_all
snippet, kwds = translate(abstract_code, variables, namespace,
dtype=brian_prefs['core.default_scalar_dtype'],
codeobj_class=codeobj_class,
variable_indices=variable_indices,
iterate_all=iterate_all)
template_kwds.update(kwds)
logger.debug(name + " snippet:\n" + str(snippet))

name = find_name(name)

variables.update(indices)

code = template(snippet,
owner=owner, variables=variables, codeobj_name=name, namespace=namespace,
Expand Down
16 changes: 14 additions & 2 deletions brian2/codegen/languages/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def translate_statement_sequence(self, statements, variables, namespace,
'''
raise NotImplementedError

def array_read_write(self, statements, variables):
def array_read_write(self, statements, variables, variable_indices):
'''
Helper function, gives the set of ArrayVariables that are read from and
written to in the series of statements. Returns the pair read, write
Expand All @@ -66,4 +66,16 @@ def array_read_write(self, statements, variables):
if isinstance(var, ArrayVariable) and varname in read)
write = set(varname for varname, var in variables.items()
if isinstance(var, ArrayVariable) and varname in write)
return read, write
# Gather the indices stored as arrays (ignore _idx which is special)
indices = set()
indices |= set(variable_indices[varname] for varname in read
if variable_indices[varname] != '_idx'
and isinstance(variables[variable_indices[varname]],
ArrayVariable))
indices |= set(variable_indices[varname] for varname in write
if variable_indices[varname] != '_idx'
and isinstance(variables[variable_indices[varname]],
ArrayVariable))
# don't list arrays that are read explicitly and used as indices twice
read -= indices
return read, write, indices
77 changes: 54 additions & 23 deletions brian2/codegen/languages/cpp_lang.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'''
TODO: use preferences to get arguments to Language
'''
import itertools

import numpy

from brian2.utils.stringtools import (deindent, stripped_deindented_lines,
Expand Down Expand Up @@ -37,6 +39,10 @@ def c_data_type(dtype):
dtype = 'float'
elif dtype == numpy.float64:
dtype = 'double'
elif dtype == numpy.int8:
dtype = 'int8_t'
elif dtype == numpy.int16:
dtype = 'int16_t'
elif dtype == numpy.int32:
dtype = 'int32_t'
elif dtype == numpy.int64:
Expand Down Expand Up @@ -133,17 +139,18 @@ def translate_statement(self, statement, namespace, codeobj_class):
namespace,
codeobj_class) + ';'

def translate_statement_sequence(self, statements, variables, namespace,
variable_indices, iterate_all,
codeobj_class):
def translate_one_statement_sequence(self, statements, variables, namespace,
variable_indices, iterate_all,
codeobj_class):

# Note that C++ code does not care about the iterate_all argument -- it
# always has to loop over the elements

read, write = self.array_read_write(statements, variables)
read, write, indices = self.array_read_write(statements, variables,
variable_indices)
lines = []
# read arrays
for varname in read:
# index and read arrays (index arrays first)
for varname in itertools.chain(indices, read):
index_var = variable_indices[varname]
var = variables[varname]
if varname not in write:
Expand All @@ -169,6 +176,21 @@ def translate_statement_sequence(self, statements, variables, namespace,
line = '_ptr' + var.arrayname + '[' + index_var + '] = ' + varname + ';'
lines.append(line)
code = '\n'.join(lines)

return stripped_deindented_lines(code)

def denormals_to_zero_code(self):
if self.flush_denormals:
return '''
#define CSR_FLUSH_TO_ZERO (1 << 15)
unsigned csr = __builtin_ia32_stmxcsr();
csr |= CSR_FLUSH_TO_ZERO;
__builtin_ia32_ldmxcsr(csr);
'''
else:
return ''

def determine_keywords(self, variables, namespace, codeobj_class):
# set up the restricted pointers, these are used so that the compiler
# knows there is no aliasing in the pointers, for optimisation
lines = []
Expand All @@ -184,7 +206,7 @@ def translate_statement_sequence(self, statements, variables, namespace,
lines.append(line)
arraynames.add(arrayname)
pointers = '\n'.join(lines)

# set up the functions
user_functions = []
support_code = ''
Expand All @@ -207,7 +229,6 @@ def translate_statement_sequence(self, statements, variables, namespace,
else:
namespace[pyfunc_name] = variable.pyfunc


# delete the user-defined functions from the namespace and add the
# function namespaces (if any)
for funcname, func in user_functions:
Expand All @@ -216,23 +237,33 @@ def translate_statement_sequence(self, statements, variables, 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),
'hashdefine_lines': stripped_deindented_lines(hash_defines),
'denormals_code_lines': stripped_deindented_lines(self.denormals_to_zero_code()),
})
return {'pointers_lines': stripped_deindented_lines(pointers),
'support_code_lines': stripped_deindented_lines(support_code),
'hashdefine_lines': stripped_deindented_lines(hash_defines),
'denormals_code_lines': stripped_deindented_lines(self.denormals_to_zero_code()),
}

def denormals_to_zero_code(self):
if self.flush_denormals:
return '''
#define CSR_FLUSH_TO_ZERO (1 << 15)
unsigned csr = __builtin_ia32_stmxcsr();
csr |= CSR_FLUSH_TO_ZERO;
__builtin_ia32_ldmxcsr(csr);
'''
def translate_statement_sequence(self, statements, variables, namespace,
variable_indices, iterate_all,
codeobj_class):
if isinstance(statements, dict):
blocks = {}
for name, block in statements.iteritems():
blocks[name] = self.translate_one_statement_sequence(block,
variables,
namespace,
variable_indices,
iterate_all,
codeobj_class)
else:
return ''
blocks = self.translate_one_statement_sequence(statements, variables,
namespace, variable_indices,
iterate_all, codeobj_class)

kwds = self.determine_keywords(variables, namespace, codeobj_class)

return blocks, kwds


################################################################################
# Implement functions
Expand Down
54 changes: 45 additions & 9 deletions brian2/codegen/languages/numpy_lang.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import itertools

import numpy as np

from brian2.utils.stringtools import word_substitute
Expand Down Expand Up @@ -37,13 +39,14 @@ def translate_statement(self, statement, namespace, codeobj_class):
namespace,
codeobj_class)

def translate_statement_sequence(self, statements, variables, namespace,
variable_indices, iterate_all,
codeobj_class):
read, write = self.array_read_write(statements, variables)
def translate_one_statement_sequence(self, statements, variables, namespace,
variable_indices, iterate_all,
codeobj_class):
read, write, indices = self.array_read_write(statements, variables,
variable_indices)
lines = []
# read arrays
for var in read:
# index and read arrays (index arrays first)
for var in itertools.chain(indices, read):
spec = variables[var]
index = variable_indices[var]
line = var + ' = ' + spec.arrayname
Expand Down Expand Up @@ -82,7 +85,27 @@ def translate_statement_sequence(self, statements, variables, namespace,
if isinstance(var, Function):
namespace[varname] = var.implementations[codeobj_class].code

return lines, {}
return lines

def translate_statement_sequence(self, statements, variables, namespace,
variable_indices, iterate_all,
codeobj_class):
if isinstance(statements, dict):
blocks = {}
all_kwds = {}
for name, block in statements.iteritems():
blocks[name] = self.translate_one_statement_sequence(block,
variables,
namespace,
variable_indices,
iterate_all,
codeobj_class)
return blocks, {}
else:
block = self.translate_one_statement_sequence(statements, variables,
namespace, variable_indices,
iterate_all, codeobj_class)
return block, {}

################################################################################
# Implement functions
Expand All @@ -98,9 +121,22 @@ def translate_statement_sequence(self, statements, variables, namespace,
DEFAULT_FUNCTIONS[func_name].implementations[NumpyLanguage] = FunctionImplementation(code=func)

# Functions that are implemented in a somewhat special way
randn_func = lambda vectorisation_idx: np.random.randn(len(vectorisation_idx))
def randn_func(vectorisation_idx):
try:
N = int(vectorisation_idx)
except TypeError, ValueError:
N = len(vectorisation_idx)

return np.random.randn(N)

def rand_func(vectorisation_idx):
try:
N = int(vectorisation_idx)
except TypeError, ValueError:
N = len(vectorisation_idx)

return np.random.rand(N)
DEFAULT_FUNCTIONS['randn'].implementations[NumpyLanguage] = FunctionImplementation(code=randn_func)
rand_func = lambda vectorisation_idx: np.random.rand(len(vectorisation_idx))
DEFAULT_FUNCTIONS['rand'].implementations[NumpyLanguage] = FunctionImplementation(code=rand_func)
clip_func = lambda array, a_min, a_max: np.clip(array, a_min, a_max)
DEFAULT_FUNCTIONS['clip'].implementations[NumpyLanguage] = FunctionImplementation(code=clip_func)
Expand Down
2 changes: 1 addition & 1 deletion brian2/codegen/runtime/numpy_rt/numpy_rt.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def variables_to_namespace(self):
self.namespace[name] = value

if isinstance(var, ArrayVariable):
self.namespace[var.arrayname] = var.get_value()
self.namespace[var.arrayname] = value

if isinstance(var, DynamicArrayVariable):
self.namespace[var.name+'_object'] = var.get_object()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# 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 %}

if _cond is True:
_cond = slice(None)
if _cond is False:
_cond = []

# 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 %}
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# USES_VARIABLES { _post_synaptic, _synaptic_pre, _synaptic_post }
# USES_VARIABLES { _post_synaptic }
# ITERATE_ALL { _idx }

import numpy as np

_presynaptic_idx = _synaptic_pre[:]
_postsynaptic_idx = _synaptic_post[:]

{% for line in code_lines %}
{{line}}
{% endfor %}
Expand Down
6 changes: 3 additions & 3 deletions brian2/codegen/runtime/numpy_rt/templates/spikemonitor.py_
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# { USES_VARIABLES _i, _t, _spikespace, _count, t, _source_start, _source_end}
# { USES_VARIABLES _i, _t, _spikespace, _count, t, _source_start, _source_stop}
import numpy as np
_spikes = _spikespace[:_spikespace[-1]]
# Take subgroups into account
_spikes = _spikes[(_spikes >= _source_start) & (_spikes < _source_end)]
_spikes = _spikes[(_spikes >= _source_start) & (_spikes < _source_stop)]
_spikes -= _source_start
_n_spikes = len(_spikes)
if _n_spikes > 0:
Expand All @@ -15,4 +15,4 @@ if _n_spikes > 0:
_i_object[_curlen:_newlen] = _spikes

# This is slow but correctly handles multiple spikes per neuron
_count += np.bincount(_spikes, minlength=_source_end-_source_start);
_count += np.bincount(_spikes, minlength=_source_stop-_source_start);
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
# ITERATE_ALL { _idx }

_vectorisation_idx = _idx
_vectorisation_idx = N

{% for line in code_lines %}
{{line}}
{% endfor %}
_return_values, = _cond.nonzero()

if _cond is True:
_cond = slice(None)
if _cond is False:
_cond = []

# _variable is set in the abstract code, see Group._get_with_code
_return_values = _variable[_cond]
2 changes: 1 addition & 1 deletion brian2/codegen/runtime/numpy_rt/templates/stateupdate.py_
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ITERATE_ALL { _idx }

_vectorisation_idx = _idx
_vectorisation_idx = N
{% for line in code_lines %}
{{line}}
{% endfor %}
4 changes: 2 additions & 2 deletions brian2/codegen/runtime/numpy_rt/templates/synapses.py_
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# USES_VARIABLES { _synaptic_post, _spiking_synapses, _target_offset }
# USES_VARIABLES { _synaptic_post, _spiking_synapses }

import numpy as np

_post_neurons = _synaptic_post.take(_spiking_synapses) + _target_offset
_post_neurons = _synaptic_post.take(_spiking_synapses)
_perm = _post_neurons.argsort()
_aux = _post_neurons.take(_perm)
_flag = np.empty(len(_aux)+1, dtype=bool)
Expand Down
Loading

0 comments on commit 9a2bdba

Please sign in to comment.