def test_is_boolean_expression(): # dummy "Variable" class Var = namedtuple("Var", ['is_boolean']) # dummy function object class Func(object): def __init__(self, returns_bool=False): self._returns_bool = returns_bool # variables / functions a = Constant('a', value=True) b = Constant('b', value=False) c = Constant('c', value=5) f = Func(returns_bool=True) g = Func(returns_bool=False) s1 = Var(is_boolean=True) s2 = Var(is_boolean=False) variables = {'a': a, 'b': b, 'c': c, 'f': f, 'g': g, 's1': s1, 's2': s2} EVF = [ (True, 'a or b'), (False, 'c'), (False, 's2'), (False, 'g(s1)'), (True, 's2 > c'), (True, 'c > 5'), (True, 'True'), (True, 'a<b'), (True, 'not (a>=b)'), (False, 'a+b'), (True, 'f(c)'), (False, 'g(c)'), ( True, 'f(c) or a<b and s1', ), ] for expect, expr in EVF: ret_val = is_boolean_expression(expr, variables) if expect != ret_val: raise AssertionError( ('is_boolean_expression(%r) returned %s, ' 'but was supposed to return %s') % (expr, ret_val, expect)) with pytest.raises(SyntaxError): is_boolean_expression('a<b and c', variables) with pytest.raises(SyntaxError): is_boolean_expression('a or foo', variables) with pytest.raises(SyntaxError): is_boolean_expression( 'ot a', # typo variables) with pytest.raises(SyntaxError): is_boolean_expression('g(c) and f(a)', variables)
def update_abstract_code(self, run_namespace): code = self.group.events[self.event] # Raise a useful error message when the user used a Brian1 syntax if not isinstance(code, str): if isinstance(code, Quantity): t = 'a quantity' else: t = f'{type(code)}' error_msg = f'Threshold condition has to be a string, not {t}.' if self.event == 'spike': try: vm_var = _guess_membrane_potential(self.group.equations) except AttributeError: # not a group with equations... vm_var = None if vm_var is not None: error_msg += f" Probably you intended to use '{vm_var} > ...'?" raise TypeError(error_msg) self.user_code = f"_cond = {code}" identifiers = get_identifiers(code) variables = self.group.resolve_all(identifiers, run_namespace, user_identifiers=identifiers) if not is_boolean_expression(code, variables): raise TypeError(f"Threshold condition '{code}' is not a boolean " f"expression") if self.group._refractory is False or self.event != 'spike': self.abstract_code = f'_cond = {code}' else: self.abstract_code = f'_cond = ({code}) and not_refractory'
def update_abstract_code(self, run_namespace=None, level=0): code = self.group.threshold # Raise a useful error message when the user used a Brian1 syntax if not isinstance(code, basestring): if isinstance(code, Quantity): t = 'a quantity' else: t = '%s' % type(code) error_msg = 'Threshold condition has to be a string, not %s.' % t vm_var = _guess_membrane_potential(self.group.equations) if vm_var is not None: error_msg += " Probably you intended to use '%s > ...'?" % vm_var raise TypeError(error_msg) self.user_code = '_cond = ' + code identifiers = get_identifiers(code) variables = self.group.resolve_all(identifiers, identifiers, run_namespace=run_namespace, level=level+1) if not is_boolean_expression(self.group.threshold, variables): raise TypeError(('Threshold condition "%s" is not a boolean ' 'expression') % self.group.threshold) if self.group._refractory is False: self.abstract_code = '_cond = %s' % self.group.threshold else: self.abstract_code = '_cond = (%s) and not_refractory' % self.group.threshold
def update_abstract_code(self, run_namespace): code = self.group.events[self.event] # Raise a useful error message when the user used a Brian1 syntax if not isinstance(code, basestring): if isinstance(code, Quantity): t = 'a quantity' else: t = '%s' % type(code) error_msg = 'Threshold condition has to be a string, not %s.' % t if self.event == 'spike': try: vm_var = _guess_membrane_potential(self.group.equations) except AttributeError: # not a group with equations... vm_var = None if vm_var is not None: error_msg += " Probably you intended to use '%s > ...'?" % vm_var raise TypeError(error_msg) self.user_code = '_cond = ' + code identifiers = get_identifiers(code) variables = self.group.resolve_all(identifiers, run_namespace, user_identifiers=identifiers) if not is_boolean_expression(code, variables): raise TypeError(('Threshold condition "%s" is not a boolean ' 'expression') % code) if self.group._refractory is False or self.event != 'spike': self.abstract_code = '_cond = %s' % code else: self.abstract_code = '_cond = (%s) and not_refractory' % code
def get_refractory_code(group): ref = group._refractory if ref is False: # No refractoriness abstract_code = '' elif isinstance(ref, Quantity): abstract_code = 'not_refractory = 1*((t - lastspike) > %f)\n' % ref else: namespace = group.namespace unit = parse_expression_unit(str(ref), namespace, group.variables) if have_same_dimensions(unit, second): abstract_code = 'not_refractory = 1*((t - lastspike) > %s)\n' % ref elif have_same_dimensions(unit, Unit(1)): if not is_boolean_expression(str(ref), namespace, group.variables): raise TypeError(('Refractory expression is dimensionless ' 'but not a boolean value. It needs to ' 'either evaluate to a timespan or to a ' 'boolean value.')) # boolean condition # we have to be a bit careful here, we can't just use the given # condition as it is, because we only want to *leave* # refractoriness, based on the condition abstract_code = 'not_refractory = 1*(not_refractory or not (%s))\n' % ref else: raise TypeError(('Refractory expression has to evaluate to a ' 'timespan or a boolean value, expression' '"%s" has units %s instead') % (ref, unit)) return abstract_code
def update_abstract_code(self, run_namespace): code = self.group.events[self.event] # Raise a useful error message when the user used a Brian1 syntax if not isinstance(code, basestring): if isinstance(code, Quantity): t = 'a quantity' else: t = '%s' % type(code) error_msg = 'Threshold condition has to be a string, not %s.' % t if self.event == 'spike': try: vm_var = _guess_membrane_potential(self.group.equations) except AttributeError: # not a group with equations... vm_var = None if vm_var is not None: error_msg += " Probably you intended to use '%s > ...'?" % vm_var raise TypeError(error_msg) self.user_code = '_cond = ' + code identifiers = get_identifiers(code) variables = self.group.resolve_all(identifiers, identifiers, run_namespace=run_namespace) if not is_boolean_expression(code, variables): raise TypeError(('Threshold condition "%s" is not a boolean ' 'expression') % code) if self.group._refractory is False or self.event != 'spike': self.abstract_code = '_cond = %s' % code else: self.abstract_code = '_cond = (%s) and not_refractory' % code
def _get_refractory_code(self, run_namespace, level=0): ref = self.group._refractory if ref is False: # No refractoriness abstract_code = '' elif isinstance(ref, Quantity): abstract_code = 'not_refractory = (t - lastspike) > %f\n' % ref else: identifiers = get_identifiers(ref) variables = self.group.resolve_all(identifiers, identifiers, run_namespace=run_namespace, level=level + 1) unit = parse_expression_unit(str(ref), variables) if have_same_dimensions(unit, second): abstract_code = 'not_refractory = (t - lastspike) > %s\n' % ref elif have_same_dimensions(unit, Unit(1)): if not is_boolean_expression(str(ref), variables): raise TypeError(('Refractory expression is dimensionless ' 'but not a boolean value. It needs to ' 'either evaluate to a timespan or to a ' 'boolean value.')) # boolean condition # we have to be a bit careful here, we can't just use the given # condition as it is, because we only want to *leave* # refractoriness, based on the condition abstract_code = 'not_refractory = not_refractory or not (%s)\n' % ref else: raise TypeError(('Refractory expression has to evaluate to a ' 'timespan or a boolean value, expression' '"%s" has units %s instead') % (ref, unit)) return abstract_code
def update_abstract_code(self): # Update the not_refractory variable for the refractory period mechanism ref = self.group._refractory if ref is None: # No refractoriness self.abstract_code = '' elif isinstance(ref, Quantity): self.abstract_code = 'not_refractory = 1*((t - lastspike) > %f)\n' % ref else: namespace = self.group.namespace unit = parse_expression_unit(str(ref), namespace, self.group.variables) if have_same_dimensions(unit, second): self.abstract_code = 'not_refractory = 1*((t - lastspike) > %s)\n' % ref elif have_same_dimensions(unit, Unit(1)): if not is_boolean_expression(str(ref), namespace, self.group.variables): raise TypeError(('Refractory expression is dimensionless ' 'but not a boolean value. It needs to ' 'either evaluate to a timespan or to a ' 'boolean value.')) # boolean condition # we have to be a bit careful here, we can't just use the given # condition as it is, because we only want to *leave* # refractoriness, based on the condition self.abstract_code = 'not_refractory = 1*(not_refractory or not (%s))\n' % ref else: raise TypeError(('Refractory expression has to evaluate to a ' 'timespan or a boolean value, expression' '"%s" has units %s instead') % (ref, unit)) self.abstract_code += self.method(self.group.equations, self.group.variables)
def _get_refractory_code(self, run_namespace, level=0): ref = self.group._refractory if ref is False: # No refractoriness abstract_code = '' elif isinstance(ref, Quantity): abstract_code = 'not_refractory = (t - lastspike) > %f\n' % ref else: identifiers = get_identifiers(ref) variables = self.group.resolve_all(identifiers, identifiers, run_namespace=run_namespace, level=level+1) unit = parse_expression_unit(str(ref), variables) if have_same_dimensions(unit, second): abstract_code = 'not_refractory = (t - lastspike) > %s\n' % ref elif have_same_dimensions(unit, Unit(1)): if not is_boolean_expression(str(ref), variables): raise TypeError(('Refractory expression is dimensionless ' 'but not a boolean value. It needs to ' 'either evaluate to a timespan or to a ' 'boolean value.')) # boolean condition # we have to be a bit careful here, we can't just use the given # condition as it is, because we only want to *leave* # refractoriness, based on the condition abstract_code = 'not_refractory = not_refractory or not (%s)\n' % ref else: raise TypeError(('Refractory expression has to evaluate to a ' 'timespan or a boolean value, expression' '"%s" has units %s instead') % (ref, unit)) return abstract_code
def update_abstract_code(self, run_namespace=None, level=0): code = self.group.threshold # Raise a useful error message when the user used a Brian1 syntax if not isinstance(code, basestring): if isinstance(code, Quantity): t = 'a quantity' else: t = '%s' % type(code) error_msg = 'Threshold condition has to be a string, not %s.' % t vm_var = _guess_membrane_potential(self.group.equations) if vm_var is not None: error_msg += " Probably you intended to use '%s > ...'?" % vm_var raise TypeError(error_msg) self.user_code = '_cond = ' + code identifiers = get_identifiers(code) variables = self.group.resolve_all(identifiers, identifiers, run_namespace=run_namespace, level=level + 1) if not is_boolean_expression(self.group.threshold, variables): raise TypeError(('Threshold condition "%s" is not a boolean ' 'expression') % self.group.threshold) if self.group._refractory is False: self.abstract_code = '_cond = %s' % self.group.threshold else: self.abstract_code = '_cond = (%s) and not_refractory' % self.group.threshold
def test_is_boolean_expression(): # dummy "Variable" class Var = namedtuple("Var", ['is_bool']) # dummy function object class Func(object): def __init__(self, returns_bool=False): self._returns_bool = returns_bool # namespace values / functions a = True b = False c = 5 f = Func(returns_bool=True) g = Func(returns_bool=False) # variables s1 = Var(is_bool=True) s2 = Var(is_bool=False) namespace = {'a': a, 'b': b, 'c': c, 'f': f, 'g': g} variables = {'s1': s1, 's2': s2} EVF = [ (True, 'a or b'), (False, 'c'), (False, 's2'), (False, 'g(s1)'), (True, 's2 > c'), (True, 'c > 5'), (True, 'True'), (True, 'a<b'), (True, 'not (a>=b)'), (False, 'a+b'), (True, 'f(c)'), (False, 'g(c)'), ( True, 'f(c) or a<b and s1', ), ] for expect, expr in EVF: ret_val = is_boolean_expression(expr, namespace, variables) if expect != ret_val: raise AssertionError( ('is_boolean_expression(%r) returned %s, ' 'but was supposed to return %s') % (expr, ret_val, expect)) assert_raises(SyntaxError, is_boolean_expression, 'a<b and c', namespace, variables) assert_raises(SyntaxError, is_boolean_expression, 'a or foo', namespace, variables) assert_raises( SyntaxError, is_boolean_expression, 'ot a', # typo namespace, variables) assert_raises(SyntaxError, is_boolean_expression, 'g(c) and f(a)', namespace, variables)
def update_abstract_code(self): if not is_boolean_expression(self.group.threshold, self.group.namespace, self.group.variables): raise TypeError(('Threshold condition "%s" is not a boolean ' 'expression') % self.group.threshold) if self.group._refractory is False: self.abstract_code = '_cond = %s' % self.group.threshold else: self.abstract_code = '_cond = (%s) and not_refractory' % self.group.threshold
def test_is_boolean_expression(): # dummy "Variable" class Var = namedtuple("Var", ['is_bool']) # dummy function object class Func(object): def __init__(self, returns_bool=False): self._returns_bool = returns_bool # namespace values / functions a = True b = False c = 5 f = Func(returns_bool=True) g = Func(returns_bool=False) # variables s1 = Var(is_bool=True) s2 = Var(is_bool=False) namespace = {'a': a, 'b': b, 'c': c, 'f': f, 'g': g} variables = {'s1': s1, 's2': s2} EVF = [ (True, 'a or b'), (False, 'c'), (False, 's2'), (False, 'g(s1)'), (True, 's2 > c'), (True, 'c > 5'), (True, 'True'), (True, 'a<b'), (True, 'not (a>=b)'), (False, 'a+b'), (True, 'f(c)'), (False, 'g(c)'), (True, 'f(c) or a<b and s1', ), ] for expect, expr in EVF: ret_val = is_boolean_expression(expr, namespace, variables) if expect != ret_val: raise AssertionError(('is_boolean_expression(%r) returned %s, ' 'but was supposed to return %s') % (expr, ret_val, expect)) assert_raises(SyntaxError, is_boolean_expression, 'a<b and c', namespace, variables) assert_raises(SyntaxError, is_boolean_expression, 'a or foo', namespace, variables) assert_raises(SyntaxError, is_boolean_expression, 'ot a', # typo namespace, variables) assert_raises(SyntaxError, is_boolean_expression, 'g(c) and f(a)', namespace, variables)
def update_abstract_code(self, run_namespace=None, level=0): code = self.group.threshold identifiers = get_identifiers(code) variables = self.group.resolve_all(identifiers, run_namespace=run_namespace, level=level+1) if not is_boolean_expression(self.group.threshold, variables): raise TypeError(('Threshold condition "%s" is not a boolean ' 'expression') % self.group.threshold) if self.group._refractory is False: self.abstract_code = '_cond = %s' % self.group.threshold else: self.abstract_code = '_cond = (%s) and not_refractory' % self.group.threshold
def update_abstract_code(self, run_namespace=None, level=0): code = self.group.threshold identifiers = get_identifiers(code) variables = self.group.resolve_all(identifiers, run_namespace=run_namespace, level=level + 1) if not is_boolean_expression(self.group.threshold, variables): raise TypeError(('Threshold condition "%s" is not a boolean ' 'expression') % self.group.threshold) if self.group._refractory is False: self.abstract_code = '_cond = %s' % self.group.threshold else: self.abstract_code = '_cond = (%s) and not_refractory' % self.group.threshold
def _get_refractory_code(self, run_namespace): ref = self.group._refractory if ref is False: # No refractoriness abstract_code = "" elif isinstance(ref, Quantity): fail_for_dimension_mismatch( ref, second, ("Refractory period has to " "be specified in units " "of seconds but got " "{value}"), value=ref, ) abstract_code = "not_refractory = (t - lastspike) > %f\n" % ref else: identifiers = get_identifiers(ref) variables = self.group.resolve_all(identifiers, identifiers, run_namespace=run_namespace) unit = parse_expression_unit(str(ref), variables) if have_same_dimensions(unit, second): abstract_code = "not_refractory = (t - lastspike) > %s\n" % ref elif have_same_dimensions(unit, Unit(1)): if not is_boolean_expression(str(ref), variables): raise TypeError( ( "Refractory expression is dimensionless " "but not a boolean value. It needs to " "either evaluate to a timespan or to a " "boolean value." ) ) # boolean condition # we have to be a bit careful here, we can't just use the given # condition as it is, because we only want to *leave* # refractoriness, based on the condition abstract_code = "not_refractory = not_refractory or not (%s)\n" % ref else: raise TypeError( ( "Refractory expression has to evaluate to a " "timespan or a boolean value, expression" '"%s" has units %s instead' ) % (ref, unit) ) return abstract_code
def _get_refractory_code(self, run_namespace): ref = self.group._refractory if ref is False: # No refractoriness abstract_code = '' elif isinstance(ref, Quantity): fail_for_dimension_mismatch(ref, second, ('Refractory period has to ' 'be specified in units ' 'of seconds but got ' '{value}'), value=ref) if prefs.legacy.refractory_timing: abstract_code = 'not_refractory = (t - lastspike) > %f\n' % ref else: abstract_code = 'not_refractory = timestep(t - lastspike, dt) >= timestep(%f, dt)\n' % ref else: identifiers = get_identifiers(ref) variables = self.group.resolve_all(identifiers, run_namespace, user_identifiers=identifiers) dims = parse_expression_dimensions(str(ref), variables) if dims is second.dim: if prefs.legacy.refractory_timing: abstract_code = '(t - lastspike) > %s\n' % ref else: abstract_code = 'not_refractory = timestep(t - lastspike, dt) >= timestep(%s, dt)\n' % ref elif dims is DIMENSIONLESS: if not is_boolean_expression(str(ref), variables): raise TypeError(('Refractory expression is dimensionless ' 'but not a boolean value. It needs to ' 'either evaluate to a timespan or to a ' 'boolean value.')) # boolean condition # we have to be a bit careful here, we can't just use the given # condition as it is, because we only want to *leave* # refractoriness, based on the condition abstract_code = 'not_refractory = not_refractory or not (%s)\n' % ref else: raise TypeError(('Refractory expression has to evaluate to a ' 'timespan or a boolean value, expression' '"%s" has units %s instead') % (ref, dims)) return abstract_code