Beispiel #1
0
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)
Beispiel #2
0
    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'
Beispiel #3
0
    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
Beispiel #4
0
    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
Beispiel #5
0
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
Beispiel #6
0
    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
Beispiel #7
0
 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
Beispiel #8
0
    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)
Beispiel #9
0
 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
Beispiel #10
0
    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
Beispiel #11
0
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)
Beispiel #12
0
 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
Beispiel #13
0
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)
Beispiel #14
0
 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
Beispiel #15
0
 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
Beispiel #16
0
    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
Beispiel #17
0
 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
Beispiel #18
0
 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