Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade RNG #144

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 35 additions & 24 deletions brian2genn/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ def extract_source_variables(variables, varname, smvariables):
def find_executable(executable):
"""Tries to find 'executable' in the path

Modified version of distutils.spawn.find_executable as
this has stupid rules for extensions on Windows.
Modified version of distutils.spawn.find_executable as
this has stupid rules for extensions on Windows.
Returns the complete filename or None if not found.
"""
path = os.environ.get('PATH', os.defpath)
Expand Down Expand Up @@ -199,7 +199,7 @@ def after_run(self):

class neuronModel(object):
'''
Class that contains all relevant information of a neuron model.
Class that contains all relevant information of a neuron model.
'''

def __init__(self):
Expand Down Expand Up @@ -335,6 +335,7 @@ def __init__(self):
#: Set of all source and header files (to be included in runner)
self.source_files = set()
self.header_files = set()
self._seed = 0

self.connectivityDict = dict()
self.groupDict = dict()
Expand Down Expand Up @@ -478,7 +479,7 @@ def code_object(self, owner, name, abstract_code, variables, template_name,
else:
codeobj_class = GeNNUserCodeObject
if ('_synapses_create_generator_' in name) or ('_synapses_create_array_' in name):
# Here we process max_row_length for synapses
# Here we process max_row_length for synapses
# the strategy is to do a dry run of connection generationin in the model definition
# function that has the same random numbers and just counts synaptic connections
# rather than generating them for real
Expand Down Expand Up @@ -685,8 +686,15 @@ def make_main_lines(self):
runfuncs[name] = main_lines
name, main_lines = procedures[-1]
elif func == 'seed':
raise NotImplementedError('Setting a seed is currently '
'not supported')
logger.warn('Setting a seed with Brian2GeNN is experimental.')
self._seed = 0 if args is None else int(args)
if args == 0:
logger.warn('In Brian2GeNN, seed(0) is equivalent to '
'seed() and sets a randomly chosen seed.')
if self._seed == 0:
main_lines.append('rk_randomseed(brian::_mersenne_twister_states[0]);')
else:
main_lines.append(f'rk_seed({self._seed}, brian::_mersenne_twister_states[0]);')
else:
raise TypeError("Unknown main queue function type " + func)

Expand All @@ -708,6 +716,8 @@ def fix_random_generators(self, model, code):
# commonly used. We cannot check for explicit names `_rand`, etc.,
# since multiple uses of binomial or PoissonInput will need to names
# that we cannot easily predict (poissoninput_binomial_2, etc.)
code = code.replace('_rand(_vectorisation_idx)', '$(gennrand_uniform)')
code = code.replace('_randn(_vectorisation_idx)', '$(gennrand_normal)')
if '_vectorisation_idx)' in code:
code = code.replace('_vectorisation_idx)',
'_seed)')
Expand Down Expand Up @@ -741,7 +751,7 @@ def build(self, directory='GeNNworkspace', compile=True, run=True,
'''

print('building genn executable ...')

if directory is None: # used during testing
directory = tempfile.mkdtemp()

Expand Down Expand Up @@ -980,7 +990,7 @@ def generate_max_row_length_code_objects(self, writer):
code_object_defs[codeobj.name].add('const int _num%s = %s;' % (k, v.size))
except TypeError:
pass

for codeobj in itervalues(self.max_row_length_code_objects):
ns = codeobj.variables
# TODO: fix these freeze/CONSTANTS hacks somehow - they work but not elegant.
Expand All @@ -989,8 +999,8 @@ def generate_max_row_length_code_objects(self, writer):
code_object_defs[codeobj.name]))
writer.write('code_objects/' + codeobj.name + '.cpp', code)



def run(self, directory, use_GPU, with_output):
gpu_arg = "1" if use_GPU else "0"
if gpu_arg == "1":
Expand Down Expand Up @@ -1061,7 +1071,7 @@ def compile_source(self, debug, directory, use_GPU):
genn_bin = (find_executable("genn-buildmodel.bat")
if os.sys.platform == 'win32'
else find_executable("genn-buildmodel.sh"))

if genn_bin is None:
raise RuntimeError('Add GeNN\'s bin directory to the path '
'or set the devices.genn.path preference.')
Expand All @@ -1070,7 +1080,7 @@ def compile_source(self, debug, directory, use_GPU):
genn_path = os.path.normpath(os.path.join(os.path.dirname(genn_bin), ".."))
logger.debug('Using GeNN path determined from path: '
'"{}"'.format(genn_path))

# Check for GeNN compatibility
genn_version = None
version_file = os.path.join(genn_path, 'version.txt')
Expand Down Expand Up @@ -1106,13 +1116,13 @@ def compile_source(self, debug, directory, use_GPU):
if os.sys.platform == 'win32':
# Make sure that all environment variables are upper case
env = {k.upper() : v for k, v in iteritems(env)}

# If there is vcvars command to call, start cmd with that
cmd = ''
msvc_env, vcvars_cmd = get_msvc_env()
if vcvars_cmd:
cmd += vcvars_cmd + ' && '
# Otherwise, update environment, again ensuring
# Otherwise, update environment, again ensuring
# that all variables are upper case
else:
env.update({k.upper() : v for k, v in iteritems(msvc_env)})
Expand All @@ -1121,11 +1131,11 @@ def compile_source(self, debug, directory, use_GPU):
buildmodel_cmd = os.path.join(genn_path, 'bin',
'genn-buildmodel.bat')
cmd += buildmodel_cmd + ' -s'

# If we're not using CPU, add CPU option
if not use_GPU:
cmd += ' -c'

# Add include directories
# **NOTE** on windows semicolons are used to seperate multiple include paths
# **HACK** argument list syntax to check_call doesn't support quoting arguments to batch
Expand All @@ -1134,23 +1144,23 @@ def compile_source(self, debug, directory, use_GPU):
cmd += ' -i "%s;%s;%s"' % (wdir, os.path.join(wdir, directory),
os.path.join(wdir, directory, 'brianlib','randomkit'))
cmd += ' magicnetwork_model.cpp'

# Add call to build generated code
cmd += ' && msbuild /m /verbosity:minimal /p:Configuration=Release "' + os.path.join(wdir, directory, 'magicnetwork_model_CODE', 'runner.vcxproj') + '"'

# Add call to build executable
cmd += ' && msbuild /m /verbosity:minimal /p:Configuration=Release "' + os.path.join(wdir, directory, 'project.vcxproj') + '"'

# Run combined command
# **NOTE** because vcvars MODIFIED environment,
# **NOTE** because vcvars MODIFIED environment,
# making seperate check_calls doesn't work
check_call(cmd, cwd=directory, env=env)
else:
if prefs['codegen.cpp.extra_link_args']:
# declare the link flags as an environment variable so that GeNN's
# generateALL can pick it up
env['LDFLAGS'] = ' '.join(prefs['codegen.cpp.extra_link_args'])

buildmodel_cmd = os.path.join(genn_path, 'bin', 'genn-buildmodel.sh')
args = [buildmodel_cmd]
if not use_GPU:
Expand Down Expand Up @@ -1192,7 +1202,7 @@ def process_poisson_groups(self, objects, poisson_groups):
for obj in poisson_groups:
# throw error if events other than spikes are used
event_keys = list(iterkeys(obj.events))
if (len(event_keys) > 1
if (len(event_keys) > 1
or (len(event_keys) == 1 and event_keys[0] != 'spike')):
raise NotImplementedError(
'Brian2GeNN does not support events that are not spikes')
Expand Down Expand Up @@ -1463,7 +1473,7 @@ def process_synapses(self, synapse_groups, objects):
if k not in synapse_model.variables:
self.add_array_variable(synapse_model, k, v)
addVar= addVar.replace(k,'$('+k+')')
code= '\\n\\\n $(addToInSyn,'+addVar+');\\n'
code= '\\n\\\n $(addToInSyn,'+addVar+');\\n'
synapse_model.main_code_lines['dynamics'] += code
#quick and dirty test to avoid adding the same support code twice
support_code = stringify('\n'.join(kwds['support_code_lines']))
Expand Down Expand Up @@ -1670,7 +1680,8 @@ def generate_model_source(self, writer, main_lines, use_GPU):
dtDef=self.dtDef,
prefs=prefs,
precision=precision,
header_files=prefs['codegen.cpp.headers']
header_files=prefs['codegen.cpp.headers'],
seed=self._seed,
)
writer.write('magicnetwork_model.cpp', model_tmp)

Expand Down
1 change: 1 addition & 0 deletions brian2genn/templates/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ void modelDefinition(NNmodel &model)
{% if prefs['devices.genn.kernel_timing'] %}
model.setTiming(true);
{% endif %}
model.setSeed({{seed}});
{% for neuron_model in neuron_models %}
model.addNeuronPopulation<{{neuron_model.name}}NEURON>("{{neuron_model.name}}", {{neuron_model.N}}, {{neuron_model.name}}_p, {{neuron_model.name}}_ini);
{% endfor %}
Expand Down