Description of problem
I am trying to reproduce the model from Klaus Wimmer’s 2015 paper (Sensory integration dynamics in a hierarchical network explains choice probabilities in cortical area MT) in Brian2, and all of the Brian1 code is publicly available on ModelDB here: ModelDB: Hierarchical network model of perceptual decision making (Wimmer et al 2015)
When trying to convert the synapse weights from Brian1 to Brian2, I end up with the following error: ‘The identifier “max” could not be resolved.’
Minimal code to reproduce problem
Wimmer’s Brian1 code is:
C_SE_SE = Connection(sensoryE, sensoryE, 'xe', delay=True, max_delay=1.5 * ms)
C_SE_SE.connect_random(sensoryE1, sensoryE1, sparseness=p, weight=lambda:w_p * gEE/gLeakE * max(0.0, 1.0 + 0.5 * randn()), delay=dE)
My Brian2 translation is
C_SE1_SE1 = Synapses(sensoryE1, sensoryE1, 'w: siemens', on_pre='ye+=w')
C_SE1_SE1.connect(p=0.2)
#C_SE1_SE1.w=max(0.0, w_p*gEE/gLeakE*(1.0 + 0.5 * randn()))*nS
C_SE1_SE1.w='w_p*gEE/gLeakE*max(0.0, 1.0 + 0.5 * randn())*nS' # This is the string that throws an error
C_SE1_SE1.delay='randn()*1.5*ms'
What you have already tried
If C_SE1_SE1.w='w_p*gEE/gLeakE*max(0.0, 1.0 + 0.5 * randn())*nS'
isn’t a string, then the code runs fine but all of the synaptic weights have the same value. However, I’m pretty sure the line above is a function.
Full traceback of error (if relevant)
Traceback (most recent call last)
Cell In[7], line 5
3 C_SE1_SE1.connect(p=0.2) #I think you need to separate these guys into different groups as the weights are different.
4 #C_SE1_SE1.w=max(0.0, w_p*gEE/gLeakE*(1.0 + 0.5 * randn()))*nS
----> 5 C_SE1_SE1.w='w_p*gEE/gLeakE*max(0.0, 1.0 + 0.5 * randn())*nS'
6 C_SE1_SE1.delay='randn()*1.5*ms'
7 #This works without putting anything into randn, but it doesn't when you turn it into a string?
File ~/Library/Python/3.11/lib/python/site-packages/brian2/groups/group.py:420, in VariableOwner.__setattr__(self, name, val, level)
418 raise TypeError(f'Variable {name} is read-only.')
419 # Make the call X.var = ... equivalent to X.var[:] = ...
--> 420 var.get_addressable_value_with_unit(name, self).set_item(slice(None),
421 val,
422 level=level+1)
423 elif len(name) and name[-1]=='_' and name[:-1] in self.variables:
424 # no unit checking
425 var = self.variables[name[:-1]]
File ~/Library/Python/3.11/lib/python/site-packages/brian2/core/variables.py:873, in VariableView.set_item(self, item, value, level, namespace)
870 # Both index and values are strings, use a single code object do deal
871 # with this situation
872 if isinstance(value, str) and isinstance(item, str):
--> 873 self.set_with_expression_conditional(item, value,
874 check_units=check_units,
875 run_namespace=namespace)
876 elif isinstance(item, str):
877 try:
File ~/Library/Python/3.11/lib/python/site-packages/brian2/core/base.py:293, in device_override.<locals>.device_override_decorator.<locals>.device_override_decorated_function(*args, **kwds)
291 return getattr(curdev, name)(*args, **kwds)
292 else:
--> 293 return func(*args, **kwds)
File ~/Library/Python/3.11/lib/python/site-packages/brian2/core/variables.py:1027, in VariableView.set_with_expression_conditional(self, cond, code, run_namespace, check_units)
1025 from brian2.devices.device import get_device
1026 device = get_device()
-> 1027 codeobj = create_runner_codeobj(self.group,
1028 {'condition': abstract_code_cond,
1029 'statement': abstract_code},
1030 'group_variable_set_conditional',
1031 additional_variables=variables,
1032 check_units=check_units,
1033 run_namespace=run_namespace,
1034 codeobj_class=device.code_object_class(fallback_pref='codegen.string_expression_target'))
1035 codeobj()
File ~/Library/Python/3.11/lib/python/site-packages/brian2/codegen/codeobject.py:352, in create_runner_codeobj(group, code, template_name, run_namespace, user_code, variable_indices, name, check_units, needed_variables, additional_variables, template_kwds, override_conditional_write, codeobj_class)
349 needed_variables = []
350 # Resolve all variables (variables used in the code and variables needed by
351 # the template)
--> 352 variables = group.resolve_all(sorted(identifiers | set(needed_variables) | set(template_variables)),
353 # template variables are not known to the user:
354 user_identifiers=user_identifiers,
355 additional_variables=additional_variables,
356 run_namespace=run_namespace)
357 # We raise this error only now, because there is some non-obvious code path
358 # where Jinja tries to get a Synapse's "name" attribute via syn['name'],
359 # which then triggers the use of the `group_get_indices` template which does
360 # not exist for standalone. Putting the check for template == None here
361 # means we will first raise an error about the unknown identifier which will
362 # then make Jinja try syn.name
363 if template is None:
File ~/Library/Python/3.11/lib/python/site-packages/brian2/groups/group.py:731, in Group.resolve_all(self, identifiers, run_namespace, user_identifiers, additional_variables)
729 resolved = {}
730 for identifier in identifiers:
--> 731 resolved[identifier] = self._resolve(identifier,
732 user_identifier=identifier in user_identifiers,
733 additional_variables=additional_variables,
734 run_namespace=run_namespace)
735 return resolved
File ~/Library/Python/3.11/lib/python/site-packages/brian2/groups/group.py:691, in Group._resolve(self, identifier, run_namespace, user_identifier, additional_variables)
687 return resolved_internal
689 # We did not find the name internally, try to resolve it in the external
690 # namespace
--> 691 return self._resolve_external(identifier, run_namespace=run_namespace)
File ~/Library/Python/3.11/lib/python/site-packages/brian2/groups/group.py:814, in Group._resolve_external(self, identifier, run_namespace, user_identifier, internal_variable)
812 else:
813 error_msg = f'The identifier "{identifier}" could not be resolved.'
--> 814 raise KeyError(error_msg)
816 elif len(matches) > 1:
817 # Possibly, all matches refer to the same object
818 first_obj = matches[0][1]
KeyError: 'The identifier "max" could not be resolved.'