Beispiel #1
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 #2
0
def check_unit(expression, unit, namespace, variables):
    '''
    Evaluates the unit for an expression in a given namespace.
    
    Parameters
    ----------
    expression : str
        The expression to evaluate.
    namespace : dict-like
        The namespace of external variables.
    variables : dict of `Variable` objects
        The information about the internal variables
    
    Raises
    ------
    KeyError
        In case on of the identifiers cannot be resolved.
    DimensionMismatchError
        If an unit mismatch occurs during the evaluation.
    
    See Also
    --------
    unit_from_expression
    '''
    expr_unit = parse_expression_unit(expression, namespace, variables)
    fail_for_dimension_mismatch(expr_unit, unit,
                                ('Expression %s does not '
                                 'have the expected units' % expression))
Beispiel #3
0
def test_parse_expression_unit():
    Var = namedtuple('Var', ['unit', 'dtype'])
    variables = {'a': Var(unit=volt*amp, dtype=np.float64),
                 'b': Var(unit=volt, dtype=np.float64),
                 'c': Var(unit=amp, dtype=np.float64)}
    group = SimpleGroup(namespace={}, variables=variables)
    EE = [
        (volt*amp, 'a+b*c'),
        (DimensionMismatchError, 'a+b'),
        (DimensionMismatchError, 'a<b'),
        (1, 'a<b*c'),
        (1, 'a or b'),
        (1, 'not (a >= b*c)'),
        (DimensionMismatchError, 'a or b<c'),
        (1, 'a/(b*c)<1'),
        (1, 'a/(a-a)'),
        (1, 'a<mV*mA'),
        (volt**2, 'b**2'),
        (volt*amp, 'a%(b*c)'),
        (volt, '-b'),
        (1, '(a/a)**(a/a)'),
        # Expressions involving functions
        (volt, 'rand()*b'),
        (volt**0.5, 'sqrt(b)'),
        (volt, 'ceil(b)'),
        (volt, 'sqrt(randn()*b**2)'),
        (1, 'sin(b/b)'),
        (DimensionMismatchError, 'sin(b)'),
        (DimensionMismatchError, 'sqrt(b) + b'),
        (SyntaxError, 'sqrt(b, b)'),
        (SyntaxError, 'sqrt()'),
        (SyntaxError, 'int(1, 2)'),
        ]
    for expect, expr in EE:
        all_variables = {}
        for name in get_identifiers(expr):
            if name in variables:
                all_variables[name] = variables[name]
            else:
                all_variables[name] = group._resolve(name, {})

        if isinstance(expect, type) and issubclass(expect, Exception):
            assert_raises(expect, parse_expression_unit, expr,
                          all_variables)
        else:
            u = parse_expression_unit(expr, all_variables)
            assert have_same_dimensions(u, expect)

    wrong_expressions = ['a**b',
                         'a << b',
                         'int(True' # typo
                        ]
    for expr in wrong_expressions:
        all_variables = {}
        for name in get_identifiers(expr):
            if name in variables:
                all_variables[name] = variables[name]
            else:
                all_variables[name] = group._resolve(name, {})
        assert_raises(SyntaxError, parse_expression_unit, expr, all_variables)
Beispiel #4
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 #5
0
def check_unit(expression, unit, variables):
    '''
    Compares the unit for an expression to an expected unit in a given
    namespace.
    
    Parameters
    ----------
    expression : str
        The expression to evaluate.
    unit : `Unit`
        The expected unit for the `expression`.
    variables : dict
        Dictionary of all variables (including external constants) used in
        the `expression`.
    
    Raises
    ------
    KeyError
        In case on of the identifiers cannot be resolved.
    DimensionMismatchError
        If an unit mismatch occurs during the evaluation.
    '''
    expr_unit = parse_expression_unit(expression, variables)
    fail_for_dimension_mismatch(expr_unit, unit, ('Expression %s does not '
                                                  'have the expected units' %
                                                  expression))
Beispiel #6
0
def check_unit(expression, unit, variables):
    '''
    Compares the unit for an expression to an expected unit in a given
    namespace.
    
    Parameters
    ----------
    expression : str
        The expression to evaluate.
    unit : `Unit`
        The expected unit for the `expression`.
    variables : dict
        Dictionary of all variables (including external constants) used in
        the `expression`.
    
    Raises
    ------
    KeyError
        In case on of the identifiers cannot be resolved.
    DimensionMismatchError
        If an unit mismatch occurs during the evaluation.
    '''
    expr_unit = parse_expression_unit(expression, variables)
    fail_for_dimension_mismatch(expr_unit, unit, ('Expression %s does not '
                                                  'have the expected unit %r') %
                                                  (expression.strip(), unit))
Beispiel #7
0
def test_parse_expression_unit():
    Var = namedtuple('Var', ['unit', 'dtype'])
    variables = {
        'a': Var(unit=volt * amp, dtype=np.float64),
        'b': Var(unit=volt, dtype=np.float64),
        'c': Var(unit=amp, dtype=np.float64)
    }
    group = SimpleGroup(namespace={}, variables=variables)
    EE = [
        (volt * amp, 'a+b*c'),
        (DimensionMismatchError, 'a+b'),
        (DimensionMismatchError, 'a<b'),
        (1, 'a<b*c'),
        (1, 'a or b'),
        (1, 'not (a >= b*c)'),
        (DimensionMismatchError, 'a or b<c'),
        (1, 'a/(b*c)<1'),
        (1, 'a/(a-a)'),
        (1, 'a<mV*mA'),
        (volt**2, 'b**2'),
        (volt * amp, 'a%(b*c)'),
        (volt, '-b'),
        (1, '(a/a)**(a/a)'),
        # Expressions involving functions
        (volt, 'rand()*b'),
        (volt**0.5, 'sqrt(b)'),
        (volt, 'ceil(b)'),
        (volt, 'sqrt(randn()*b**2)'),
        (1, 'sin(b/b)'),
        (DimensionMismatchError, 'sin(b)'),
        (DimensionMismatchError, 'sqrt(b) + b')
    ]
    for expect, expr in EE:
        all_variables = {}
        for name in get_identifiers(expr):
            if name in variables:
                all_variables[name] = variables[name]
            else:
                all_variables[name] = group.resolve(name)

        if expect is DimensionMismatchError:
            assert_raises(DimensionMismatchError, parse_expression_unit, expr,
                          all_variables)
        else:
            u = parse_expression_unit(expr, all_variables)
            assert have_same_dimensions(u, expect)

    wrong_expressions = [
        'a**b',
        'a << b',
        'int(True'  # typo
    ]
    for expr in wrong_expressions:
        all_variables = {}
        for name in get_identifiers(expr):
            if name in variables:
                all_variables[name] = variables[name]
            else:
                all_variables[name] = group.resolve(name)
        assert_raises(SyntaxError, parse_expression_unit, expr, all_variables)
Beispiel #8
0
def check_unit(expression, unit, namespace, variables):
    '''
    Evaluates the unit for an expression in a given namespace.
    
    Parameters
    ----------
    expression : str
        The expression to evaluate.
    namespace : dict-like
        The namespace of external variables.
    variables : dict of `Variable` objects
        The information about the internal variables
    
    Raises
    ------
    KeyError
        In case on of the identifiers cannot be resolved.
    DimensionMismatchError
        If an unit mismatch occurs during the evaluation.
    
    See Also
    --------
    unit_from_expression
    '''
    expr_unit = parse_expression_unit(expression, namespace, variables)
    fail_for_dimension_mismatch(expr_unit, unit, ('Expression %s does not '
                                                  'have the expected units' %
                                                  expression))
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 _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 #11
0
 def before_run(self, run_namespace=None):
     rates_var = self.variables['rates']
     if isinstance(rates_var, Subexpression):
         # Check that the units of the expression make sense
         expr = rates_var.expr
         identifiers = get_identifiers(expr)
         variables = self.resolve_all(identifiers,
                                      run_namespace,
                                      user_identifiers=identifiers)
         unit = parse_expression_unit(rates_var.expr, variables)
         fail_for_dimension_mismatch(unit, Hz, "The expression provided for "
                                               "PoissonGroup's 'rates' "
                                               "argument, has to have units "
                                               "of Hz")
     super(PoissonGroup, self).before_run(run_namespace)
Beispiel #12
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 #13
0
def test_parse_expression_unit():
    default_namespace = create_namespace({})
    varunits = dict(default_namespace)
    varunits.update({'a': volt * amp, 'b': volt, 'c': amp})

    EE = [
        (volt * amp, 'a+b*c'),
        (DimensionMismatchError, 'a+b'),
        (DimensionMismatchError, 'a<b'),
        (1, 'a<b*c'),
        (1, 'a or b'),
        (1, 'not (a >= b*c)'),
        (DimensionMismatchError, 'a or b<c'),
        (1, 'a/(b*c)<1'),
        (1, 'a/(a-a)'),
        (1, 'a<mV*mA'),
        (volt**2, 'b**2'),
        (volt * amp, 'a%(b*c)'),
        (volt, '-b'),
        (1, '(a/a)**(a/a)'),
        # Expressions involving functions
        (volt, 'rand()*b'),
        (volt**0.5, 'sqrt(b)'),
        (volt, 'ceil(b)'),
        (volt, 'sqrt(randn()*b**2)'),
        (1, 'sin(b/b)'),
        (DimensionMismatchError, 'sin(b)'),
        (DimensionMismatchError, 'sqrt(b) + b')
    ]
    for expect, expr in EE:
        if expect is DimensionMismatchError:
            assert_raises(DimensionMismatchError, parse_expression_unit, expr,
                          varunits, {})
        else:
            u = parse_expression_unit(expr, varunits, {})
            assert have_same_dimensions(u, expect)

    wrong_expressions = [
        'a**b',
        'a << b',
        'ot True'  # typo
    ]
    for expr in wrong_expressions:
        assert_raises(SyntaxError, parse_expression_unit, expr, varunits, {})
Beispiel #14
0
def test_parse_expression_unit():
    default_namespace = create_namespace({})
    varunits = dict(default_namespace)
    varunits.update({'a': volt*amp, 'b': volt, 'c': amp})

    EE = [
        (volt*amp, 'a+b*c'),
        (DimensionMismatchError, 'a+b'),
        (DimensionMismatchError, 'a<b'),
        (1, 'a<b*c'),
        (1, 'a or b'),
        (1, 'not (a >= b*c)'),
        (DimensionMismatchError, 'a or b<c'),
        (1, 'a/(b*c)<1'),
        (1, 'a/(a-a)'),
        (1, 'a<mV*mA'),
        (volt**2, 'b**2'),
        (volt*amp, 'a%(b*c)'),
        (volt, '-b'),
        (1, '(a/a)**(a/a)'),
        # Expressions involving functions
        (volt, 'rand()*b'),
        (volt**0.5, 'sqrt(b)'),
        (volt, 'ceil(b)'),
        (volt, 'sqrt(randn()*b**2)'),
        (1, 'sin(b/b)'),
        (DimensionMismatchError, 'sin(b)'),
        (DimensionMismatchError, 'sqrt(b) + b')
        ]
    for expect, expr in EE:
        if expect is DimensionMismatchError:
            assert_raises(DimensionMismatchError, parse_expression_unit, expr, varunits, {})
        else:
            u = parse_expression_unit(expr, varunits, {})
            assert have_same_dimensions(u, expect)

    wrong_expressions = ['a**b',
                         'a << b',
                         'ot True' # typo
                        ]
    for expr in wrong_expressions:
        assert_raises(SyntaxError, parse_expression_unit, expr, varunits, {})
Beispiel #15
0
def check_units_statements(code, namespace, variables):
    '''
    Check the units for a series of statements. Setting a model variable has to
    use the correct unit. For newly introduced temporary variables, the unit
    is determined and used to check the following statements to ensure
    consistency.
    
    Parameters
    ----------
    expression : str
        The expression to evaluate.
    namespace : dict-like
        The namespace of external variables.
    variables : dict of `Variable` objects
        The information about the internal variables
    
    Raises
    ------
    KeyError
        In case on of the identifiers cannot be resolved.
    DimensionMismatchError
        If an unit mismatch occurs during the evaluation.
    '''
    known = set(variables.keys()) | set(namespace.keys())
    newly_defined, _, unknown = analyse_identifiers(code, known)

    if len(unknown):
        raise AssertionError(
            ('Encountered unknown identifiers, this should '
             'not happen at this stage. Unkown identifiers: %s' % unknown))

    # We want to add newly defined variables to the variables dictionary so we
    # make a copy now
    variables = dict(variables)

    code = re.split(r'[;\n]', code)
    for line in code:
        line = line.strip()
        if not len(line):
            continue  # skip empty lines

        varname, op, expr = parse_statement(line)
        if op in ('+=', '-=', '*=', '/=', '%='):
            # Replace statements such as "w *=2" by "w = w * 2"
            expr = '{var} {op_first} {expr}'.format(var=varname,
                                                    op_first=op[0],
                                                    expr=expr)
            op = '='
        elif op == '=':
            pass
        else:
            raise AssertionError('Unknown operator "%s"' % op)

        expr_unit = parse_expression_unit(expr, namespace, variables)

        if varname in variables:
            fail_for_dimension_mismatch(variables[varname].unit, expr_unit,
                                        ('Code statement "%s" does not use '
                                         'correct units' % line))
        elif varname in newly_defined:
            # note the unit for later
            variables[varname] = Variable(expr_unit,
                                          is_bool=False,
                                          scalar=False)
        else:
            raise AssertionError(('Variable "%s" is neither in the variables '
                                  'dictionary nor in the list of undefined '
                                  'variables.' % varname))
Beispiel #16
0
def check_units_statements(code, variables):
    '''
    Check the units for a series of statements. Setting a model variable has to
    use the correct unit. For newly introduced temporary variables, the unit
    is determined and used to check the following statements to ensure
    consistency.
    
    Parameters
    ----------
    code : str
        The statements as a (multi-line) string
    variables : dict of `Variable` objects
        The information about all variables used in `code` (including
        `Constant` objects for external variables)
    
    Raises
    ------
    KeyError
        In case on of the identifiers cannot be resolved.
    DimensionMismatchError
        If an unit mismatch occurs during the evaluation.
    '''
    # Avoid a circular import
    from brian2.codegen.translation import analyse_identifiers
    known = set(variables.keys())
    newly_defined, _, unknown = analyse_identifiers(code, known)
    
    if len(unknown):
        raise AssertionError(('Encountered unknown identifiers, this should '
                             'not happen at this stage. Unkown identifiers: %s'
                             % unknown))

    
    code = re.split(r'[;\n]', code)
    for line in code:
        line = line.strip()
        if not len(line):
            continue  # skip empty lines
        
        varname, op, expr, comment = parse_statement(line)
        if op in ('+=', '-=', '*=', '/=', '%='):
            # Replace statements such as "w *=2" by "w = w * 2"
            expr = '{var} {op_first} {expr}'.format(var=varname,
                                                    op_first=op[0],
                                                    expr=expr)
            op = '='
        elif op == '=':
            pass
        else:
            raise AssertionError('Unknown operator "%s"' % op) 

        expr_unit = parse_expression_unit(expr, variables)

        if varname in variables:
            fail_for_dimension_mismatch(variables[varname].unit,
                                        expr_unit,
                                        ('Code statement "%s" does not use '
                                         'correct units' % line))
        elif varname in newly_defined:
            # note the unit for later
            variables[varname] = Variable(name=varname, unit=expr_unit,
                                          scalar=False)
        else:
            raise AssertionError(('Variable "%s" is neither in the variables '
                                  'dictionary nor in the list of undefined '
                                  'variables.' % varname))
Beispiel #17
0
def check_units_statements(code, variables):
    '''
    Check the units for a series of statements. Setting a model variable has to
    use the correct unit. For newly introduced temporary variables, the unit
    is determined and used to check the following statements to ensure
    consistency.
    
    Parameters
    ----------
    code : str
        The statements as a (multi-line) string
    variables : dict of `Variable` objects
        The information about all variables used in `code` (including
        `Constant` objects for external variables)
    
    Raises
    ------
    KeyError
        In case on of the identifiers cannot be resolved.
    DimensionMismatchError
        If an unit mismatch occurs during the evaluation.
    '''
    # Avoid a circular import
    from brian2.codegen.translation import analyse_identifiers
    known = set(variables.keys())
    newly_defined, _, unknown = analyse_identifiers(code, known)
    
    if len(unknown):
        raise AssertionError(('Encountered unknown identifiers, this should '
                             'not happen at this stage. Unkown identifiers: %s'
                             % unknown))

    
    code = re.split(r'[;\n]', code)
    for line in code:
        line = line.strip()
        if not len(line):
            continue  # skip empty lines
        
        varname, op, expr, comment = parse_statement(line)
        if op in ('+=', '-=', '*=', '/=', '%='):
            # Replace statements such as "w *=2" by "w = w * 2"
            expr = '{var} {op_first} {expr}'.format(var=varname,
                                                    op_first=op[0],
                                                    expr=expr)
            op = '='
        elif op == '=':
            pass
        else:
            raise AssertionError('Unknown operator "%s"' % op) 

        expr_unit = parse_expression_unit(expr, variables)

        if varname in variables:
            expected_unit = variables[varname].unit
            fail_for_dimension_mismatch(expr_unit, expected_unit,
                                        ('The right-hand-side of code '
                                         'statement ""%s" does not have the '
                                         'expected unit %r') % (line,
                                                               expected_unit))
        elif varname in newly_defined:
            # note the unit for later
            variables[varname] = Variable(name=varname, unit=expr_unit,
                                          scalar=False)
        else:
            raise AssertionError(('Variable "%s" is neither in the variables '
                                  'dictionary nor in the list of undefined '
                                  'variables.' % varname))
Beispiel #18
0
def check_units_statements(code, namespace, variables):
    '''
    Check the units for a series of statements. Setting a model variable has to
    use the correct unit. For newly introduced temporary variables, the unit
    is determined and used to check the following statements to ensure
    consistency.
    
    Parameters
    ----------
    expression : str
        The expression to evaluate.
    namespace : dict-like
        The namespace of external variables.
    variables : dict of `Variable` objects
        The information about the internal variables
    
    Raises
    ------
    KeyError
        In case on of the identifiers cannot be resolved.
    DimensionMismatchError
        If an unit mismatch occurs during the evaluation.
    '''
    known = set(variables.keys()) | set(namespace.keys())
    newly_defined, _, unknown = analyse_identifiers(code, known)
    
    if len(unknown):
        raise AssertionError(('Encountered unknown identifiers, this should '
                             'not happen at this stage. Unkown identifiers: %s'
                             % unknown))
    
    # We want to add newly defined variables to the variables dictionary so we
    # make a copy now
    variables = dict(variables)
    
    code = re.split(r'[;\n]', code)
    for line in code:
        line = line.strip()
        if not len(line):
            continue  # skip empty lines
        
        varname, op, expr = parse_statement(line)
        if op in ('+=', '-=', '*=', '/=', '%='):
            # Replace statements such as "w *=2" by "w = w * 2"
            expr = '{var} {op_first} {expr}'.format(var=varname,
                                                    op_first=op[0],
                                                    expr=expr)
            op = '='
        elif op == '=':
            pass
        else:
            raise AssertionError('Unknown operator "%s"' % op) 

        expr_unit = parse_expression_unit(expr, namespace, variables)

        if varname in variables:
            fail_for_dimension_mismatch(variables[varname].unit,
                                        expr_unit,
                                        ('Code statement "%s" does not use '
                                         'correct units' % line))
        elif varname in newly_defined:
            # note the unit for later
            variables[varname] = Variable(expr_unit, is_bool=False,
                                          scalar=False)
        else:
            raise AssertionError(('Variable "%s" is neither in the variables '
                                  'dictionary nor in the list of undefined '
                                  'variables.' % varname))