示例#1
0
def test_split_stochastic():
    tau = 5 * ms
    expr = Expression('(-v + I) / tau')
    # No stochastic part
    assert expr.split_stochastic() == (expr, None)

    # No non-stochastic part -- note that it should return 0 and not None
    expr = Expression('sigma*xi/tau**.5')
    non_stochastic, stochastic = expr.split_stochastic()
    assert sympy_equals(non_stochastic.code, 0)
    assert 'xi' in stochastic
    assert len(stochastic) == 1
    assert sympy_equals(stochastic['xi'].code, 'sigma/tau**.5')

    expr = Expression('(-v + I) / tau + sigma*xi/tau**.5')
    non_stochastic, stochastic = expr.split_stochastic()
    assert 'xi' in stochastic
    assert len(stochastic) == 1
    assert sympy_equals(non_stochastic.code, '(-v + I) / tau')
    assert sympy_equals(stochastic['xi'].code, 'sigma/tau**.5')

    expr = Expression(
        '(-v + I) / tau + sigma*xi_1/tau**.5 + xi_2*sigma2/sqrt(tau_2)')
    non_stochastic, stochastic = expr.split_stochastic()
    assert set(stochastic.keys()) == {'xi_1', 'xi_2'}
    assert sympy_equals(non_stochastic.code, '(-v + I) / tau')
    assert sympy_equals(stochastic['xi_1'].code, 'sigma/tau**.5')
    assert sympy_equals(stochastic['xi_2'].code, 'sigma2/tau_2**.5')

    expr = Expression('-v / tau + 1 / xi')
    with pytest.raises(ValueError):
        expr.split_stochastic()
示例#2
0
def test_construction_errors():
    '''
    Test that the Equations constructor raises errors correctly
    '''
    # parse error
    assert_raises(EquationError, lambda: Equations('dv/dt = -v / tau volt'))

    # Only a single string or a list of SingleEquation objects is allowed
    assert_raises(TypeError, lambda: Equations(None))
    assert_raises(TypeError, lambda: Equations(42))
    assert_raises(TypeError, lambda: Equations(['dv/dt = -v / tau : volt']))

    # duplicate variable names
    assert_raises(EquationError, lambda: Equations('''dv/dt = -v / tau : volt
                                                    v = 2 * t/second * volt : volt'''))

    eqs = [SingleEquation(DIFFERENTIAL_EQUATION, 'v', volt,
                          expr=Expression('-v / tau')),
           SingleEquation(SUBEXPRESSION, 'v', volt,
                          expr=Expression('2 * t/second * volt'))
           ]
    assert_raises(EquationError, lambda: Equations(eqs))

    # illegal variable names
    assert_raises(ValueError, lambda: Equations('ddt/dt = -dt / tau : volt'))
    assert_raises(ValueError, lambda: Equations('dt/dt = -t / tau : volt'))
    assert_raises(ValueError, lambda: Equations('dxi/dt = -xi / tau : volt'))
    assert_raises(ValueError, lambda: Equations('for : volt'))
    assert_raises((EquationError, ValueError),
                  lambda: Equations('d1a/dt = -1a / tau : volt'))
    assert_raises(ValueError, lambda: Equations('d_x/dt = -_x / tau : volt'))

    # xi in a subexpression
    assert_raises(EquationError,
                  lambda: Equations('''dv/dt = -(v + I) / (5 * ms) : volt
                                       I = second**-1*xi**-2*volt : volt'''))

    # more than one xi
    assert_raises(EquationError,
                  lambda: Equations('''dv/dt = -v / tau + xi/tau**.5 : volt
                                       dx/dt = -x / tau + 2*xi/tau : volt
                                       tau : second'''))
    # using not-allowed flags
    eqs = Equations('dv/dt = -v / (5 * ms) : volt (flag)')
    eqs.check_flags({DIFFERENTIAL_EQUATION: ['flag']})  # allow this flag
    assert_raises(ValueError, lambda: eqs.check_flags({DIFFERENTIAL_EQUATION: []}))
    assert_raises(ValueError, lambda: eqs.check_flags({}))
    assert_raises(ValueError, lambda: eqs.check_flags({SUBEXPRESSION: ['flag']}))
    assert_raises(ValueError, lambda: eqs.check_flags({DIFFERENTIAL_EQUATION: ['otherflag']}))

    # Circular subexpression
    assert_raises(ValueError, lambda: Equations('''dv/dt = -(v + w) / (10 * ms) : 1
                                                   w = 2 * x : 1
                                                   x = 3 * w : 1'''))

    # Boolean/integer differential equations
    assert_raises(TypeError, lambda: Equations('dv/dt = -v / (10*ms) : boolean'))
    assert_raises(TypeError, lambda: Equations('dv/dt = -v / (10*ms) : integer'))
示例#3
0
def test_repeated_construction():
    eqs1 = Equations('dx/dt = x : 1')
    eqs2 = Equations('dx/dt = x : 1', x='y')
    assert len(eqs1) == 1
    assert 'x' in eqs1
    assert eqs1['x'].expr == Expression('x')
    assert len(eqs2) == 1
    assert 'y' in eqs2
    assert eqs2['y'].expr == Expression('y')
示例#4
0
def test_expr_creation():
    '''
    Test creating expressions.
    '''
    expr = Expression('v > 5 * mV')
    assert expr.code == 'v > 5 * mV'
    assert ('v' in expr.identifiers and 'mV' in expr.identifiers and
            not 'V' in expr.identifiers)
    assert_raises(SyntaxError, lambda: Expression('v 5 * mV'))
示例#5
0
def test_expr_creation():
    """
    Test creating expressions.
    """
    expr = Expression('v > 5 * mV')
    assert expr.code == 'v > 5 * mV'
    assert ('v' in expr.identifiers and 'mV' in expr.identifiers
            and not 'V' in expr.identifiers)
    with pytest.raises(SyntaxError):
        Expression('v 5 * mV')
示例#6
0
def test_substitute():
    # Check that Equations.substitute returns an independent copy
    eqs = Equations('dx/dt = x : 1')
    eqs2 = eqs.substitute(x='y')

    # First equation should be unaffected
    assert len(eqs) == 1 and 'x' in eqs
    assert eqs['x'].expr == Expression('x')

    # Second equation should have x substituted by y
    assert len(eqs2) == 1 and 'y' in eqs2
    assert eqs2['y'].expr == Expression('y')
示例#7
0
def test_split_stochastic():
    tau = 5 * ms
    expr = Expression('(-v + I) / tau')
    # No stochastic part
    assert expr.split_stochastic() == (expr, None)
    
    expr = Expression('(-v + I) / tau + sigma*xi/tau**.5')
    non_stochastic, stochastic = expr.split_stochastic()
    assert 'xi' in stochastic
    assert len(stochastic) == 1
    assert sympy_equals(non_stochastic.code, '(-v + I) / tau')
    assert sympy_equals(stochastic['xi'].code, 'sigma/tau**.5')

    expr = Expression('(-v + I) / tau + sigma*xi_1/tau**.5 + xi_2*sigma2/sqrt(tau_2)')
    non_stochastic, stochastic = expr.split_stochastic()
    assert set(stochastic.keys()) == {'xi_1', 'xi_2'}
    assert sympy_equals(non_stochastic.code, '(-v + I) / tau')
    assert sympy_equals(stochastic['xi_1'].code, 'sigma/tau**.5')
    assert sympy_equals(stochastic['xi_2'].code, 'sigma2/tau_2**.5')
    
    expr = Expression('-v / tau + 1 / xi')
    assert_raises(ValueError, expr.split_stochastic)
示例#8
0
def test_str_repr():
    """
    Test the string representation of expressions and statements. Assumes that
    __str__ returns the complete expression/statement string and __repr__ a
    string of the form "Expression(...)" or "Statements(...)" that can be
    evaluated.
    """
    expr_string = '(v - I)/ tau'
    expr = Expression(expr_string)

    # use sympy to check for equivalence of expressions (terms may have be
    # re-arranged by sympy)
    assert sympy_equals(expr_string, str(expr))
    assert sympy_equals(expr_string, eval(repr(expr)).code)

    # Use exact string equivalence for statements
    statement_string = 'v += w'
    statement = Statements(statement_string)

    assert str(statement) == 'v += w'
    assert repr(statement) == "Statements('v += w')"
示例#9
0
def test_construction_errors():
    """
    Test that the Equations constructor raises errors correctly
    """
    # parse error
    with pytest.raises(EquationError):
        Equations('dv/dt = -v / tau volt')
    with pytest.raises(EquationError):
        Equations('dv/dt = -v / tau : volt second')

    # incorrect unit definition
    with pytest.raises(EquationError):
        Equations('dv/dt = -v / tau : mvolt')
    with pytest.raises(EquationError):
        Equations('dv/dt = -v / tau : voltage')
    with pytest.raises(EquationError):
        Equations('dv/dt = -v / tau : 1.0*volt')

    # Only a single string or a list of SingleEquation objects is allowed
    with pytest.raises(TypeError):
        Equations(None)
    with pytest.raises(TypeError):
        Equations(42)
    with pytest.raises(TypeError):
        Equations(['dv/dt = -v / tau : volt'])

    # duplicate variable names
    with pytest.raises(EquationError):
        Equations("""dv/dt = -v / tau : volt
                       v = 2 * t/second * volt : volt""")

    eqs = [
        SingleEquation(DIFFERENTIAL_EQUATION,
                       'v',
                       volt.dim,
                       expr=Expression('-v / tau')),
        SingleEquation(SUBEXPRESSION,
                       'v',
                       volt.dim,
                       expr=Expression('2 * t/second * volt'))
    ]
    with pytest.raises(EquationError):
        Equations(eqs)

    # illegal variable names
    with pytest.raises(SyntaxError):
        Equations('ddt/dt = -dt / tau : volt')
    with pytest.raises(SyntaxError):
        Equations('dt/dt = -t / tau : volt')
    with pytest.raises(SyntaxError):
        Equations('dxi/dt = -xi / tau : volt')
    with pytest.raises(SyntaxError):
        Equations('for : volt')
    with pytest.raises((EquationError, SyntaxError)):
        Equations('d1a/dt = -1a / tau : volt')
    with pytest.raises(SyntaxError):
        Equations('d_x/dt = -_x / tau : volt')

    # xi in a subexpression
    with pytest.raises(EquationError):
        Equations("""dv/dt = -(v + I) / (5 * ms) : volt
                     I = second**-1*xi**-2*volt : volt""")

    # more than one xi
    with pytest.raises(EquationError):
        Equations("""dv/dt = -v / tau + xi/tau**.5 : volt
                     dx/dt = -x / tau + 2*xi/tau : volt
                     tau : second""")
    # using not-allowed flags
    eqs = Equations('dv/dt = -v / (5 * ms) : volt (flag)')
    eqs.check_flags({DIFFERENTIAL_EQUATION: ['flag']})  # allow this flag
    with pytest.raises(ValueError):
        eqs.check_flags({DIFFERENTIAL_EQUATION: []})
    with pytest.raises(ValueError):
        eqs.check_flags({})
    with pytest.raises(ValueError):
        eqs.check_flags({SUBEXPRESSION: ['flag']})
    with pytest.raises(ValueError):
        eqs.check_flags({DIFFERENTIAL_EQUATION: ['otherflag']})
    eqs = Equations('dv/dt = -v / (5 * ms) : volt (flag1, flag2)')
    eqs.check_flags({DIFFERENTIAL_EQUATION: ['flag1',
                                             'flag2']})  # allow both flags
    # Don't allow the two flags in combination
    with pytest.raises(ValueError):
        eqs.check_flags({DIFFERENTIAL_EQUATION: ['flag1', 'flag2']},
                        incompatible_flags=[('flag1', 'flag2')])
    eqs = Equations("""dv/dt = -v / (5 * ms) : volt (flag1)
                       dw/dt = -w / (5 * ms) : volt (flag2)""")
    # They should be allowed when used independently
    eqs.check_flags({DIFFERENTIAL_EQUATION: ['flag1', 'flag2']},
                    incompatible_flags=[('flag1', 'flag2')])

    # Circular subexpression
    with pytest.raises(ValueError):
        Equations("""dv/dt = -(v + w) / (10 * ms) : 1
                      w = 2 * x : 1
                      x = 3 * w : 1""")

    # Boolean/integer differential equations
    with pytest.raises(TypeError):
        Equations('dv/dt = -v / (10*ms) : boolean')
    with pytest.raises(TypeError):
        Equations('dv/dt = -v / (10*ms) : integer')