#!/usr/bin/env python3
#
# Tests the expression classes.
#
# This file is part of Myokit.
# See http://myokit.org for copyright, sharing, and licensing details.
#
import pickle
import unittest

import numpy as np

import myokit


# Unit --> See test_units.py
# Quantity --> See test_units.py


# Tiny model for partial derivative testing.
pd_model = myokit.parse_model("""
    [[model]]
    name: pd_model
    ina.m = 0.1
    membrane.V = -80
    bound.dot_pace_direct = 0
    bound.dot_pace_indirect = 0

    [engine]
    time = 0 [ms]
        in [ms]
        bind time

    [membrane]
    dot(V) = (ina.I1 + ina.I2) / C
        in [mV]
    C = 10 [pF]
        in [pF]

    [ina]
    use membrane.V
    a = 1 [1/ms] in [1/ms]
    b = 10 [1/mV] in [1/mV]
    c = 2 [1/ms] in [1/ms]
    d = 8 [1/mV] in [1/mV]
    k1 = a * exp(b * V)
        in [1/ms]
    k2 = c * exp(-d * V)
        in [1/ms]
    inf = k1 * tau
        in [1]
    tau = 1 / (k1 + k2)
        in [ms]
    dot(m) = (inf - m) / tau
        in [1]
    E = 2 * E2 in [mV]
    E2 = E3 / 3 in [mV]
    E3 = 100 [mV] in [mV]
    g = 16 [nS] in [nS]
    I1 = 0.6 * g * m^3 * (V - E)
        in [pA]
    I2 = 0.4 * g * m^3 * (V - E)
        in [pA]

    [bound]
    pace = 0 bind pace
    pace_direct = pace
    pace_indirect = pace_direct
    time_direct = engine.time
        in [ms]
    time_indirect = time_direct
        in [ms]
    dot(dot_pace_direct) = pace_direct
        in [ms]
    dot(dot_pace_indirect) = pace_indirect
        in [ms]

""")


class ExpressionTest(unittest.TestCase):
    """ Tests various methods of the :class:`myokit.Expression` class. """

    def test_contains_type(self):
        # Test :meth:`Expression.contains_type`.

        self.assertTrue(myokit.Name('x').contains_type(myokit.Name))
        self.assertFalse(myokit.Name('x').contains_type(myokit.Number))
        self.assertTrue(myokit.Number(4).contains_type(myokit.Number))
        self.assertFalse(myokit.Number(4).contains_type(myokit.Name))

        e = myokit.parse_expression('x + 3')
        self.assertTrue(e.contains_type(myokit.Name))
        self.assertTrue(e.contains_type(myokit.Number))
        self.assertTrue(e.contains_type(myokit.Plus))
        self.assertFalse(e.contains_type(myokit.Minus))

        e = myokit.parse_expression('x * (x * (x * (x * (x * (1 + 1)))))')
        self.assertTrue(e.contains_type(myokit.Multiply))
        self.assertTrue(e.contains_type(myokit.Plus))
        self.assertTrue(e.contains_type(myokit.Number))
        self.assertFalse(e.contains_type(myokit.Minus))

    def test_depends_on(self):
        # Tests Expression.depends_on()

        # Shallow checking
        m = pd_model.clone()
        c = m.get('membrane.C').lhs()
        v = m.get('membrane.V').lhs()
        self.assertTrue(c.depends_on(c))
        self.assertFalse(c.depends_on(v))
        self.assertTrue(v.depends_on(v))
        self.assertFalse(v.depends_on(c))

        # Deep checking
        self.assertFalse(c.depends_on(v, deep=True))
        self.assertTrue(v.depends_on(c, deep=True))

        # Deep checking can handle improper names
        # Note: The order of execution is not guaranteed, so that sometimes
        # the test will find 'c' before dealing with the improper ref. As a
        # result, the False scenario is required for consistent coverage.
        # https://github.com/myokit/myokit/issues/913
        p = myokit.Plus(c, myokit.Name('x'))
        self.assertTrue(p.depends_on(c, True))
        self.assertTrue(p.depends_on(myokit.Name('x'), True))
        self.assertFalse(p.depends_on(v, True))

        # Deep checking can handle partial derivs and inits
        q = myokit.PartialDerivative(myokit.Name(v.var()), c)
        self.assertFalse(q.depends_on(c, True))
        self.assertFalse(q.depends_on(c, False))
        self.assertFalse(q.depends_on(myokit.Name(v.var()), True))
        self.assertFalse(q.depends_on(myokit.Name(v.var()), False))
        q = myokit.InitialValue(myokit.Name(v.var()))
        self.assertFalse(q.depends_on(c, True))
        self.assertFalse(q.depends_on(c, False))
        self.assertFalse(q.depends_on(myokit.Name(v.var()), True))
        self.assertFalse(q.depends_on(myokit.Name(v.var()), False))

        # Deep checking can handle partial derivs and inits & improper names
        # See note above about issue 913
        q = myokit.Plus(p, myokit.PartialDerivative(v, myokit.Name('x')))
        self.assertTrue(q.depends_on(c, True))
        self.assertTrue(q.depends_on(myokit.Name('x'), True))
        q = myokit.Plus(p, myokit.InitialValue(myokit.Name('x')))
        self.assertTrue(q.depends_on(c, True))
        self.assertTrue(q.depends_on(myokit.Name('x'), True))
        self.assertFalse(q.depends_on(v, True))

        # Test with complex web of dependencies
        m.get('ina.E').set_rhs('a + b + c + k1 + k2 + inf')
        m.get('ina.E2').set_rhs('b + k1 + k2 + inf + tau + E3 + E')
        e = m.get('ina.E')
        a = m.get('ina.a').lhs()
        self.assertFalse(e.lhs().depends_on(a, False))
        self.assertTrue(e.lhs().depends_on(a, True))
        self.assertTrue(e.rhs().depends_on(a, False))
        self.assertTrue(e.rhs().depends_on(a, True))

        e = m.get('ina.E2')
        self.assertFalse(e.lhs().depends_on(a, False))
        self.assertTrue(e.lhs().depends_on(a, True))
        self.assertFalse(e.rhs().depends_on(a, False))
        self.assertTrue(e.rhs().depends_on(a, True))

    def test_depends_on_state(self):
        # Tests Expression.depends_on_state()

        # Shallow checking
        m = pd_model.clone()
        c = m.get('membrane.C').lhs()
        k = m.get('ina.k1').lhs()
        t = m.get('ina.tau').lhs()
        self.assertFalse(c.depends_on_state())
        self.assertFalse(k.depends_on_state())
        self.assertFalse(t.depends_on_state())
        self.assertTrue(k.depends_on_state(deep=True))
        self.assertTrue(t.depends_on_state(deep=True))

        v = m.get('membrane.V')
        self.assertTrue(myokit.Name(v).depends_on_state())
        self.assertTrue(myokit.Name(v).depends_on_state(deep=True))
        self.assertFalse(v.lhs().depends_on_state())
        self.assertTrue(v.rhs())
        self.assertTrue(v.lhs().depends_on_state(deep=True))

        # Can handle improper names
        p = myokit.Plus(c, myokit.Name('x'))
        self.assertFalse(p.depends_on_state(deep=False))
        self.assertFalse(p.depends_on_state(deep=True))

        # Can handle partial derivs and inits (always false)
        v = v.lhs()
        q = myokit.PartialDerivative(v, c)
        self.assertFalse(q.depends_on_state(False))
        self.assertFalse(q.depends_on_state(True))
        q = myokit.Plus(c, myokit.PartialDerivative(v, c))
        self.assertFalse(q.depends_on_state(False))
        self.assertFalse(q.depends_on_state(True))
        q = myokit.InitialValue(myokit.Name(v.var()))
        self.assertFalse(q.depends_on_state(False))
        self.assertFalse(q.depends_on_state(True))
        q = myokit.Plus(c, myokit.InitialValue(myokit.Name(v.var())))
        self.assertFalse(q.depends_on_state(False))
        self.assertFalse(q.depends_on_state(True))

    def test_diff(self):
        # Tests :meth:`Expression.diff()`

        # Test basic functionality
        m = pd_model.clone()
        m.check_units(myokit.UNIT_STRICT)

        # Direct dependence on a constant
        i = m.get('ina.I1')
        E = m.get('ina.E')
        d = i.rhs().diff(E.lhs())
        self.assertEqual(d.code(), '0.6 * ina.g * ina.m^3 * -1')

        # Dependence on a constant via another constant
        E3 = m.get('ina.E3')
        d = i.rhs().diff(E3.lhs())
        self.assertEqual(
            d.code(), '0.6 * ina.g * ina.m^3 * -diff(ina.E, ina.E3)')

        # Correct unit gets set for None
        p = E3.rhs().diff(E.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.units.dimensionless)
        E3.set_unit(None)
        E3.set_rhs('4')
        p = E3.rhs().diff(E.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.mV)
        E.set_unit(None)
        E.set_rhs('1 + E3')
        p = E3.rhs().diff(E.lhs())
        self.assertTrue(p.is_number(0))
        self.assertIsNone(p.unit())
        E3.set_unit('mV')
        E3.set_rhs('4 [mV]')
        p = E3.rhs().diff(E.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.units.mV)

        # Except if there are unit errors
        E3.set_unit('mV')
        E3.set_rhs('4 [mV] + 2 [pA]')
        E.set_unit('mV')
        E.set_rhs('1 [mV] + E3')
        p = E3.rhs().diff(E.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.mV)

        # Only Names or intial values are allowed
        self.assertRaisesRegex(
            ValueError, 'only be taken with respect to a myokit.Name or',
            i.rhs().diff, myokit.Number(3))
        V = m.get('membrane.V')
        self.assertRaisesRegex(
            ValueError, 'only be taken with respect to a myokit.Name or',
            i.rhs().diff, V.lhs())

        # Derivative w.r.t. initial condition is zero when states are
        # independent, otherwise equates to dependence on any state
        V0 = myokit.InitialValue(myokit.Name(V))
        dV = V.lhs()
        self.assertEqual(
            dV.diff(V0, independent_states=True),
            myokit.Number(0, 1 / myokit.units.ms))
        self.assertEqual(
            dV.diff(V0, independent_states=False),
            myokit.PartialDerivative(dV, V0))
        self.assertEqual(
            i.lhs().diff(V0, independent_states=True),
            myokit.Number(0, myokit.units.pA / myokit.units.mV))
        self.assertEqual(
            i.lhs().diff(V0, independent_states=False),
            myokit.PartialDerivative(i.lhs(), V0))

    def test_equal(self):
        # Test equality checking on general equations

        m1 = myokit.load_model('example')
        m2 = m1.clone()
        for v in m1.variables(deep=True):
            e1 = v.rhs()
            e2 = m2.get(v.qname()).rhs()
            if e1.is_literal():
                self.assertEqual(e1, e1)
            else:
                self.assertNotEqual(e1, e2)

    def test_eval(self):
        # Test :meth:`Expression.eval()`.

        # Test basic use
        e = myokit.parse_expression('1 + 1 + 1')
        self.assertEqual(e.eval(), 3)

        # Test errors
        e = myokit.parse_expression('1 / 0')
        self.assertRaises(myokit.NumericalError, e.eval)

        # Test errors-in-errors
        e = myokit.parse_expression('16^1000 / 0')
        self.assertRaisesRegex(myokit.NumericalError, 'another error', e.eval)

        # Test errors with variables
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(0)
        y.set_rhs('5 / 2')
        z.set_rhs('(x + y) / 0')
        self.assertRaisesRegex(
            myokit.NumericalError, 'c.x = 0', z.rhs().eval)
        self.assertRaisesRegex(
            myokit.NumericalError, 'c.y = 5 / 2', z.rhs().eval)

        # Test error in error with variables
        y.set_rhs('16^1000')
        self.assertRaisesRegex(
            myokit.NumericalError, 'another error', z.eval)

        # Test substitution
        y.set_rhs('5')
        z.set_rhs('x / y')
        z.rhs().eval(subst={x.lhs(): 0})
        z.rhs().eval(subst={x.lhs(): myokit.Number(1)})
        self.assertEqual(
            z.rhs().eval(
                subst={x.lhs(): myokit.parse_expression('5 * 5 * 5')}),
            25)

        # Test errors in substitution dict format
        self.assertRaisesRegex(ValueError, 'dict or None', z.rhs().eval, 2)
        self.assertRaisesRegex(ValueError, 'All keys', z.rhs().eval, {5: 1})
        self.assertRaisesRegex(
            ValueError, 'All values', z.rhs().eval, {x.lhs(): 'hello'})

        # Test if substituted Name is treated as number in error formatting
        y.set_rhs('x')
        z.set_rhs('(x + y) / 0')
        self.assertRaisesRegex(
            myokit.NumericalError, 'c.y = 3', z.rhs().eval, {y.lhs(): 3})

        # Error handling --> Correct bit should be highlighted
        z.set_rhs('(1 + 2 * (3 + sin(1 / (2 * x + (0 / 0)))))')
        with self.assertRaises(myokit.NumericalError) as e:
            z.eval()
        m = str(e.exception).splitlines()
        self.assertEqual(len(m), 7)
        self.assertEqual(m[2], '  1 + 2 * (3 + sin(1 / (2 * c.x + 0 / 0)))')
        self.assertEqual(m[3], '                                  ~~~~~')

        # Error handling --> Error when descending down a tree should be found
        y.set_rhs('3 * z')
        with self.assertRaises(myokit.NumericalError) as e:
            y.eval()
        m = str(e.exception).splitlines()
        self.assertEqual(len(m), 10)
        self.assertEqual(m[1], 'Encountered when evaluating')
        self.assertEqual(m[2], '  3 * c.z')
        self.assertEqual(m[3], 'Error located at:')
        self.assertEqual(m[4], '  c.z')
        self.assertEqual(
            m[5], 'c.z = 1 + 2 * (3 + sin(1 / (2 * c.x + 0 / 0)))')
        self.assertEqual(m[6], '                                      ~~~~~')
        self.assertEqual(m[7], 'With the following operands:')
        self.assertEqual(m[8], '  (1) 0.0')
        self.assertEqual(m[9], '  (2) 0.0')

        # Debugging name: unlinked!
        x = myokit.Name('x')
        self.assertEqual(
            x._eval_unit(myokit.UNIT_TOLERANT), None)
        self.assertEqual(
            x._eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_eval_unit_error(self):
        # Test error handling for eval_unit.

        # Incompatible units
        x = myokit.parse_expression('1 + 2 * (3 + 4 * (5 [mV] + 6 [A]))')
        with self.assertRaises(myokit.IncompatibleUnitError) as e:
            x.eval_unit()
        m = str(e.exception).splitlines()
        self.assertEqual(len(m), 4)
        self.assertEqual(m[2], '  1 + 2 * (3 + 4 * (5 [mV] + 6 [A]))')
        self.assertEqual(m[3], '                    ~~~~~~~~~~~~~~')

    def test_int_conversion(self):
        # Test conversion of expressions to int.

        x = myokit.parse_expression('1 + 2 + 3')
        self.assertEqual(int(x), 6)
        x = myokit.parse_expression('1 + 3.9')
        self.assertEqual(int(x), 4)

    def test_float_conversion(self):
        # Test conversion of expressions to float.

        x = myokit.parse_expression('1 + 2 + 3')
        self.assertEqual(int(x), 6)
        x = myokit.parse_expression('1 + 3.9')
        self.assertEqual(float(x), 4.9)

    def test_is_conditional(self):
        # Test :meth:`Expression.is_conditional().`.

        pe = myokit.parse_expression
        self.assertFalse(pe('1 + 2 + 3').is_conditional())
        self.assertTrue(pe('if(1 == 2, 0, 2)').is_conditional())
        self.assertTrue(pe('1 + if(1 == 1, 0, 2)').is_conditional())

    def test_pickling_error(self):
        # Tests pickling of expressions raises an exception

        # Test that the right exception is raised
        m = myokit.load_model('example')
        e = m.get('ina.INa').rhs()
        self.assertRaises(NotImplementedError, pickle.dumps, e)

        # Test that the trick in the exception actually works
        s = e.code()
        f = myokit.parse_expression(s, context=m)
        self.assertEqual(e, f)

    def test_pyfunc(self):
        # Test the pyfunc() method.

        # Note: Extensive testing happens in pywriter / numpywriter tests!
        x = myokit.parse_expression('3 * sqrt(v)')
        f = x.pyfunc(use_numpy=False)
        self.assertTrue(callable(f))
        self.assertEqual(f(4), 6)
        self.assertRaises(TypeError, f, np.array([1, 2, 3]))

        f = x.pyfunc(use_numpy=True)
        self.assertTrue(callable(f))
        self.assertEqual(f(4), 6)
        self.assertEqual(list(f(np.array([1, 4, 9]))), [3, 6, 9])

    def test_pystr(self):
        # Test the pystr() method.
        # Note: Extensive testing happens in pywriter / numpywriter tests!

        x = myokit.parse_expression('3 * sqrt(v)')
        self.assertEqual(x.pystr(use_numpy=False), '3.0 * math.sqrt(v)')
        self.assertEqual(x.pystr(use_numpy=True), '3.0 * numpy.sqrt(v)')

    def test_sequence_interface(self):
        # Tests the Expression class's sequence interface

        x = myokit.parse_expression('1 + 2')
        self.assertEqual(len(x), 2)                 # __len__
        self.assertIn(myokit.Number(1), x)          # __contains__
        self.assertIn(myokit.Number(2), x)
        self.assertEqual(x[0], myokit.Number(1))    # __getitem__
        self.assertEqual(x[1], myokit.Number(2))

        y = [op for op in x]                        # __iter__
        self.assertEqual(len(y), 2)
        self.assertIn(myokit.Number(1), y)
        self.assertIn(myokit.Number(2), y)
        self.assertEqual(y[0], myokit.Number(1))
        self.assertEqual(y[1], myokit.Number(2))

    def test_string_conversion(self):
        # Tests __str__ and __repr__

        x = myokit.Plus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(str(x), '1 + 2')
        self.assertEqual(repr(x), 'myokit.Expression[1 + 2]')

    def test_tree_str(self):
        # Test :meth:`Expression.tree_str()`.
        # More extensive testing of this method should happen in the individual
        # expression tests.

        x = myokit.parse_expression('1 + 2 * 3 / 4')
        self.assertEqual(x.tree_str(), '\n'.join([
            '+',
            '  1',
            '  /',
            '    *',
            '      2',
            '      3',
            '    4',
            '',
        ]))

    def test_validation(self):
        # Test :meth:`Expression.validate()`.

        e = myokit.parse_expression('5 + 2 * exp(3 / (1 + 2))')
        e.validate()
        self.assertIsNone(e.validate())

        # Test cycles in expression tree are found (not via variables!)
        p = myokit.Plus(myokit.Number(1), myokit.Number(1))
        # Have to hack this in, since, properly used, expressions are immutable
        p._operands = (myokit.Number(2), p)
        self.assertRaisesRegex(myokit.IntegrityError, 'yclical', p.validate)

    def test_walk(self):
        # Test :meth:`Expression.walk().

        e = myokit.parse_expression('1 / (2 + exp(3 + sqrt(4)))')
        w = list(e.walk())
        self.assertEqual(len(w), 9)
        self.assertEqual(type(w[0]), myokit.Divide)
        self.assertEqual(type(w[1]), myokit.Number)
        self.assertEqual(type(w[2]), myokit.Plus)
        self.assertEqual(type(w[3]), myokit.Number)
        self.assertEqual(type(w[4]), myokit.Exp)
        self.assertEqual(type(w[5]), myokit.Plus)
        self.assertEqual(type(w[6]), myokit.Number)
        self.assertEqual(type(w[7]), myokit.Sqrt)
        self.assertEqual(type(w[8]), myokit.Number)
        self.assertEqual(w[1].eval(), 1)
        self.assertEqual(w[3].eval(), 2)
        self.assertEqual(w[6].eval(), 3)
        self.assertEqual(w[8].eval(), 4)

        w = list(e.walk(allowed_types=[myokit.Sqrt, myokit.Exp]))
        self.assertEqual(len(w), 2)
        self.assertEqual(type(w[0]), myokit.Exp)
        self.assertEqual(type(w[1]), myokit.Sqrt)

        w = list(e.walk(allowed_types=myokit.Exp))
        self.assertEqual(len(w), 1)
        self.assertEqual(type(w[0]), myokit.Exp)


class NumberTest(unittest.TestCase):
    """ Tests myokit.Number. """

    def test_basic(self):
        # Test construction, other basics.

        # Test myokit.Number creation and representation
        x = myokit.Number(-4.0)
        self.assertEqual(str(x), '-4')
        self.assertEqual(x.value(), -4)
        self.assertIsNone(x.unit())
        x = myokit.Number(4.0)
        self.assertEqual(str(x), '4')
        y = myokit.Number(4)
        self.assertEqual(str(y), '4')
        self.assertEqual(x, y)
        self.assertFalse(x is y)
        x = myokit.Number(4.01)
        self.assertEqual(str(x), '4.01')
        x = myokit.Number(-4.01)
        self.assertEqual(str(x), '-4.01')
        x = myokit.Number('-4e9')
        self.assertEqual(str(x), '-4.00000000000000000e9')
        x = myokit.Number('4e+09')
        self.assertEqual(str(x), ' 4.00000000000000000e9')
        x = myokit.Number('-4e+00')
        self.assertEqual(str(x), '-4')
        x = myokit.Number('4e-05')
        self.assertEqual(str(x), '4e-5')
        x = myokit.Number('4e+15')
        self.assertEqual(float(x), 4e15)
        x = myokit.Number(4, myokit.Unit.parse_simple('pF'))
        self.assertEqual(str(x), '4 [pF]')
        x = myokit.Number(-3, myokit.Unit.parse_simple('pF'))
        self.assertEqual(str(x), '-3 [pF]')

        # Test unit conversion
        x = myokit.Number('2000', myokit.units.pF)
        y = x.convert('nF')
        self.assertEqual(y.eval(), 2)
        self.assertEqual(str(y), '2 [nF]')
        self.assertEqual(y.unit(), myokit.Unit.parse_simple('nF'))
        a = y.convert('uF')
        b = x.convert('uF')
        self.assertEqual(a, b)
        self.assertRaises(myokit.IncompatibleUnitError, x.convert, 'A')

        # Test properties
        x = myokit.Number(2)
        self.assertFalse(x.is_conditional())
        self.assertTrue(x.is_constant())
        self.assertTrue(x.is_literal())
        self.assertFalse(x.is_state_value())

        # Test construction
        # Second argument must be a unit, if given
        myokit.Number(3, 'kg')
        self.assertRaisesRegex(ValueError, 'Unit', myokit.Number, 3, 1)
        # Construction from quantity
        q = myokit.Quantity(3, 'kg')
        myokit.Number(q)
        self.assertEqual(q.unit(), myokit.parse_unit('kg'))
        self.assertRaisesRegex(ValueError, 'unit', myokit.Number, q, 'kg')

    def test_bracket(self):
        # Test Number.bracket().
        # Never needs a bracket
        x = myokit.Number(2)
        self.assertFalse(x.bracket())

        # Doesn't have an operand
        self.assertRaises(ValueError, x.bracket, myokit.Number(2))

    def test_clone(self):
        # Test Number.clone().

        x = myokit.Number(2)
        y = x.clone()
        self.assertIsNot(x, y)
        self.assertEqual(x, y)

        # With substitution
        z = myokit.Number(10)
        y = x.clone(subst={x: z})
        self.assertEqual(y, z)

        # Test that substitution changes references
        # Note: This should follow automatically from set_rhs() implementation
        # and fact that expressions are immutable.
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs(2)
        y = c.add_variable('y')
        y.set_rhs('3 * x')
        self.assertIn(x.lhs(), y.rhs().references())
        self.assertIn(x, y.refs_to())
        self.assertIn(y, x.refs_by())
        y.set_rhs(y.rhs().clone(subst={x.lhs(): myokit.Number(4)}))
        self.assertNotIn(x.lhs(), y.rhs().references())
        self.assertNotIn(x, y.refs_to())
        self.assertNotIn(y, x.refs_by())

    def test_diff(self):

        # Derivative of a number w.r.t. anything is zero (but with the right
        # unit)
        m = pd_model
        C = m.get('membrane.C')
        E = m.get('ina.E')
        self.assertEqual(C.unit(), myokit.units.pF)
        self.assertEqual(E.unit(), myokit.units.mV)
        self.assertIsInstance(C.rhs(), myokit.Number)
        d = C.rhs().diff(E.lhs())
        self.assertTrue(d.is_number(0))
        self.assertEqual(d.unit(), myokit.units.pF / myokit.units.mV)

    def test_equal(self):
        # Test equality checking on numbers
        a = myokit.Number(1)
        b = myokit.Number(1)
        c = myokit.Number(2)
        self.assertEqual(a, b)
        self.assertEqual(b, a)
        self.assertNotEqual(a, c)
        self.assertNotEqual(c, a)
        self.assertNotEqual(b, c)
        self.assertNotEqual(c, b)

    def test_eval(self):
        # Test evaluation (with single precision).

        x = myokit.Number(2)
        self.assertEqual(type(x.eval()), float)
        self.assertEqual(
            type(x.eval(precision=myokit.SINGLE_PRECISION)), np.float32)

    def test_eval_unit(self):
        # Test Number eval_unit.

        # Test in tolerant mode
        x = myokit.Number(3)
        self.assertEqual(x.eval_unit(), None)
        y = myokit.Number(3, myokit.units.ampere)
        self.assertEqual(y.eval_unit(), myokit.units.ampere)

        # Test in strict mode
        self.assertEqual(
            x.eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(y.eval_unit(myokit.UNIT_STRICT), myokit.units.ampere)

    def test_is_name_number_derivative(self):
        # Test is_name(), is_number(), and is_derivative()

        x = myokit.Number(3, myokit.units.volt)
        self.assertFalse(x.is_name())
        self.assertFalse(x.is_derivative())
        v = myokit.Model().add_component('c').add_variable('x')
        self.assertFalse(x.is_name(v))
        self.assertFalse(x.is_derivative(v))

        self.assertTrue(x.is_number())
        self.assertFalse(x.is_number(12))
        self.assertFalse(x.is_number(0))
        self.assertTrue(x.is_number(3))

        x = myokit.Number(0)
        self.assertTrue(x.is_number())
        self.assertTrue(x.is_number(0))

    def test_tree_str(self):
        # Test Number.tree_str()

        # Test simple
        x = myokit.Number(1)
        self.assertEqual(x.tree_str(), '1\n')

        # Test with spaces
        e = myokit.Plus(x, myokit.Number(-2))
        self.assertEqual(e.tree_str(), '+\n  1\n  -2\n')


class NameTest(unittest.TestCase):
    """ Tests myokit.Name. """

    def test_basics(self):
        # Test Name basics

        model = myokit.Model()
        component = model.add_component('c')
        xvar = component.add_variable('x')
        xvar.set_rhs('15')
        yvar = component.add_variable('y')
        yvar.set_rhs('3 * x ')
        zvar = component.add_variable('z')
        zvar.set_rhs('2 + y + x')

        x = myokit.Name(xvar)
        y = myokit.Name(yvar)
        z = myokit.Name(zvar)

        self.assertEqual(x.code(), 'c.x')

        # Test rhs
        # Name of non-state: rhs() should be the associated variable's rhs
        self.assertEqual(x.rhs(), myokit.Number(15))
        # Name of state: rhs() should be the initial value (since this is the
        # value of the variable).
        xvar.promote(12)
        self.assertEqual(x.rhs(), myokit.Number(12))
        # Invalid variable:
        a = myokit.Name('test')
        self.assertIsNone(a.rhs())

        # Test validation
        x.validate()
        y.validate()
        z.validate()
        a = myokit.Name('test')
        self.assertRaises(myokit.IntegrityError, a.validate)

        # Test var()
        self.assertEqual(x.var(), xvar)
        self.assertEqual(y.var(), yvar)
        self.assertEqual(z.var(), zvar)

        # Test properties
        # State x
        self.assertFalse(x.is_conditional())
        self.assertFalse(x.is_constant())
        self.assertFalse(x.is_literal())
        self.assertTrue(x.is_state_value())

        # State-dependent variable y
        self.assertFalse(y.is_conditional())
        self.assertFalse(y.is_constant())
        self.assertFalse(y.is_literal())
        self.assertFalse(y.is_state_value())

        # Non-state x
        xvar.demote()
        self.assertFalse(x.is_conditional())
        self.assertTrue(x.is_constant())
        self.assertFalse(x.is_literal())    # A name is never a literal!
        self.assertFalse(x.is_state_value())

        # (Non-state)-dependent variable y
        self.assertFalse(y.is_conditional())
        self.assertTrue(y.is_constant())
        self.assertFalse(y.is_literal())
        self.assertFalse(y.is_state_value())

    def test_bracket(self):
        # Test Name.bracket().
        # Never needs a bracket
        x = myokit.Name('hi')
        self.assertFalse(x.bracket())

        # Doesn't have an operand
        self.assertRaises(ValueError, x.bracket, myokit.Number(2))

    def test_clone(self):
        # Test Name.clone().
        m = myokit.Model()
        c = m.add_component('c')
        vx = c.add_variable('x')
        vy = c.add_variable('y')
        vz = c.add_variable('z')
        vx.set_rhs(1)
        vy.set_rhs('2 * x')
        vz.set_rhs('2 * x + y')
        x = myokit.Name(vx)
        y = myokit.Name(vy)
        z = myokit.Name(vz)

        # Test clone
        a = x.clone()
        self.assertEqual(x, a)
        a = z.clone()
        self.assertEqual(z, a)

        # With substitution (handled in Name)
        a = x.clone(subst={x: y})
        self.assertEqual(y, a)
        a = x.clone()
        self.assertEqual(x, a)

        # With expansion (handled in Name)
        a = z.clone()
        self.assertEqual(z, a)
        a = z.clone(expand=True)
        self.assertTrue(a.is_literal())
        self.assertFalse(z.is_literal())
        self.assertEqual(z.eval(), a.eval())

        # With expansion but retention of selected variables (handled in Name)
        a = z.clone(expand=True, retain=[x])
        self.assertNotEqual(a, z)
        self.assertFalse(a.is_literal())
        self.assertEqual(z.eval(), a.eval())

        # Few options for how to specify x:
        b = z.clone(expand=True, retain=['c.x'])
        self.assertEqual(a, b)
        b = z.clone(expand=True, retain=[vx])
        self.assertEqual(a, b)

    def test_diff(self):
        # Tests Name.diff

        # Derivative of a state variable is one, zero, or an object
        m = pd_model.clone()
        V = myokit.Name(m.get('membrane.V'))
        self.assertEqual(V.diff(V, independent_states=True), myokit.Number(1))
        self.assertEqual(V.diff(V, independent_states=False), myokit.Number(1))
        C = myokit.Name(m.get('membrane.C'))
        self.assertEqual(
            V.diff(C, independent_states=True),
            myokit.Number(0, myokit.units.mV / myokit.units.pF))
        self.assertEqual(
            V.diff(C, independent_states=False),
            myokit.PartialDerivative(V, C))

        # Derivative of an non-state variable is one, zero, or an object
        tau = myokit.Name(m.get('ina.tau'))
        self.assertEqual(
            tau.diff(tau, independent_states=True), myokit.Number(1))
        self.assertEqual(
            tau.diff(tau, independent_states=False), myokit.Number(1))
        self.assertEqual(
            tau.diff(C, independent_states=True),    # No dep
            myokit.Number(0, myokit.units.ms / myokit.units.pF))
        self.assertEqual(
            tau.diff(C, independent_states=False),    # No dep
            myokit.PartialDerivative(tau, C))
        a = myokit.Name(m.get('ina.a'))
        self.assertEqual(
            tau.diff(a, independent_states=True),     # Dep
            myokit.PartialDerivative(tau, a))
        self.assertEqual(
            tau.diff(a, independent_states=False),    # Dep
            myokit.PartialDerivative(tau, a))

        # Derivative of a bound variable is one or zero
        t = myokit.Name(m.get('engine.time'))
        self.assertEqual(t.diff(t, independent_states=True), myokit.Number(1))
        self.assertEqual(t.diff(t, independent_states=False), myokit.Number(1))
        self.assertEqual(
            t.diff(C, independent_states=True),
            myokit.Number(0, myokit.units.ms / myokit.units.pF))
        self.assertEqual(
            t.diff(C, independent_states=False),
            myokit.Number(0, myokit.units.ms / myokit.units.pF))
        # Even if it has an interesting RHS
        t.var().set_rhs('4 * membrane.C')
        self.assertEqual(t.diff(t, independent_states=True), myokit.Number(1))
        self.assertEqual(t.diff(t, independent_states=False), myokit.Number(1))
        self.assertEqual(
            t.diff(C, independent_states=True),
            myokit.Number(0, myokit.units.ms / myokit.units.pF))
        self.assertEqual(
            t.diff(C, independent_states=False),
            myokit.Number(0, myokit.units.ms / myokit.units.pF))

        # Derivative of something depending only on a bound variable is one or
        # zero
        p = myokit.Name(m.get('bound.pace'))
        self.assertEqual(p.diff(p, independent_states=True), myokit.Number(1))
        self.assertEqual(p.diff(p, independent_states=False), myokit.Number(1))
        self.assertEqual(
            p.diff(C, independent_states=True),
            myokit.Number(0, 1 / myokit.units.pF))
        self.assertEqual(
            p.diff(C, independent_states=False),
            myokit.Number(0, 1 / myokit.units.pF))

        pd = myokit.Name(m.get('bound.pace_direct'))
        self.assertEqual(
            pd.diff(C, independent_states=True),
            myokit.Number(0, 1 / myokit.units.pF))
        self.assertEqual(
            pd.diff(C, independent_states=False),
            myokit.Number(0, 1 / myokit.units.pF))

        pi = myokit.Name(m.get('bound.pace_indirect'))
        self.assertEqual(
            pi.diff(C, independent_states=True),
            myokit.Number(0, 1 / myokit.units.pF))
        self.assertEqual(
            pi.diff(C, independent_states=False),
            myokit.Number(0, 1 / myokit.units.pF))

        td = myokit.Name(m.get('bound.time_direct'))
        self.assertEqual(
            td.diff(C, independent_states=True),
            myokit.Number(0, myokit.units.ms / myokit.units.pF))
        self.assertEqual(
            td.diff(C, independent_states=False),
            myokit.Number(0, myokit.units.ms / myokit.units.pF))

        ti = myokit.Name(m.get('bound.time_indirect'))
        self.assertEqual(
            ti.diff(C, independent_states=True),
            myokit.Number(0, myokit.units.ms / myokit.units.pF))
        self.assertEqual(
            ti.diff(C, independent_states=False),
            myokit.Number(0, myokit.units.ms / myokit.units.pF))

        # Test diff of "improper" name
        x = myokit.Name('x')
        y = myokit.Name('y')
        z = x.diff(y)
        self.assertIsInstance(z, myokit.PartialDerivative)
        self.assertEqual(z.code(), 'diff(str:x, str:y)')

    def test_equal(self):
        # Test equality checking on names

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs(3)
        y = c.add_variable('y')
        y.set_rhs(2)
        y.set_unit(myokit.units.Newton)

        self.assertEqual(myokit.Name(x), myokit.Name(x))
        self.assertEqual(myokit.Name(y), myokit.Name(y))
        self.assertNotEqual(myokit.Name(x), myokit.Name(y))
        self.assertNotEqual(myokit.Name(y), myokit.Name(x))
        self.assertNotEqual(myokit.Name(x), myokit.Name(m.clone().get('c.x')))
        self.assertNotEqual(myokit.Name(x), myokit.Name('x'))
        self.assertNotEqual(myokit.Name(x), myokit.Name('c.x'))

        # Debug/unofficial options
        self.assertEqual(myokit.Name('a'), myokit.Name('a'))
        self.assertNotEqual(myokit.Name('a'), myokit.Name('A'))
        # The next ones _should_ be equal: since the components and models are
        # not what's supposed to go inside a name, it will convert to string
        # and compare the resulting representations. This is the same as what
        # would happen if __eq__ was called on an expression wrapping a Name.
        self.assertEqual(myokit.Name(c), myokit.Name(c))
        self.assertEqual(myokit.Name(m), myokit.Name(m.clone()))

    def test_eval_unit(self):
        # Test Name eval_unit.

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs(3)
        y = c.add_variable('y')
        y.set_rhs(2)
        y.set_unit(myokit.units.Newton)

        # At this point, x and y both have a unitless rhs (despite y having a
        # variable unit)

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), None)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

        # Now have x mention y in its rhs
        x.set_rhs('y')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), myokit.units.Newton)
        self.assertEqual(y.rhs().eval_unit(), None)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_is_name_number_derivative(self):
        # Tests is_name(), is_number(), and is_derivative()

        v = myokit.Model().add_component('c').add_variable('v')
        x = myokit.Name(v)
        self.assertTrue(x.is_name())
        self.assertTrue(x.is_name(v))
        self.assertFalse(x.is_derivative())
        w = v.parent().add_variable('w')
        self.assertFalse(x.is_name(w))
        self.assertFalse(x.is_derivative(v))
        self.assertFalse(x.is_derivative(w))

        self.assertFalse(x.is_number())
        self.assertFalse(x.is_number(0))

    def test_rhs(self):
        # Test Name.rhs().

        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('3 + 2')

        x = myokit.Name(x)
        self.assertEqual(x.rhs().eval(), 5)

    def test_tree_str(self):
        # Test Name.tree_str()

        # Test simple
        x = myokit.Name('y')
        self.assertEqual(x.tree_str(), 'y\n')

        # Test with spaces
        e = myokit.Plus(x, x)
        self.assertEqual(e.tree_str(), '+\n  y\n  y\n')

    def test_values(self):
        # Test with values other than Variables

        # Special case: string
        x = myokit.Name('this is ok')
        self.assertEqual(x.code(), 'str:this is ok')

        # All other values (this allows e.g. CellML expressions to be created)
        x = myokit.Name(12.3)
        self.assertEqual(x.code(), '12.3')


class DerivativeTest(unittest.TestCase):
    """ Tests myokit.Derivative. """

    def test_basic(self):
        # Test creation.

        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs(3)
        x.promote(0)
        y = c.add_variable('y')
        y.set_rhs(2)

        # Derivative of state
        d = myokit.Derivative(myokit.Name(x))
        d.validate()

        # Derivative of non-state: allowed during model building, but doesn't
        # validate
        d = myokit.Derivative(myokit.Name(y))
        self.assertRaisesRegex(
            myokit.IntegrityError, 'only be defined for state', d.validate)

        # Derivative of something other than a name: never allowed
        self.assertRaisesRegex(
            myokit.TypeError, 'requires a myokit.Name',
            myokit.Derivative, myokit.Number(1))
        self.assertRaisesRegex(  # Not even another LhsExpression
            myokit.TypeError, 'requires a myokit.Name',
            myokit.Derivative, myokit.Derivative(myokit.Name(x)))

    def test_bracket(self):
        # Test Derivative.bracket()
        x = myokit.Derivative(myokit.Name('x'))
        self.assertFalse(x.bracket(myokit.Name('x')))
        self.assertRaises(ValueError, x.bracket, myokit.Number(1))

    def test_clone(self):
        # Test Derivative.clone().
        x = myokit.Derivative(myokit.Name('x'))
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Derivative(myokit.Name('z'))
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        i = myokit.Name('i')
        j = myokit.Name('j')
        x = myokit.Derivative(i)
        y = x.clone(subst={i: j})
        self.assertIsNot(y, x)
        self.assertNotEqual(y, x)
        self.assertEqual(y, myokit.Derivative(j))

    def test_diff(self):
        # Tests Derivative.diff()

        # Derivative of a dot is zero or an object
        m = pd_model
        C = m.get('membrane.C').lhs()
        dm = m.get('ina.m').lhs()       # No dep on C
        dV = m.get('membrane.V').lhs()  # Dep on C
        self.assertEqual(
            dm.diff(C, independent_states=True),
            myokit.Number(0, 1 / myokit.units.pF / myokit.units.ms))
        self.assertEqual(
            dm.diff(C, independent_states=False),
            myokit.PartialDerivative(dm, C))
        self.assertEqual(
            dV.diff(C, independent_states=True),
            myokit.PartialDerivative(dV, C))
        self.assertEqual(
            dV.diff(C, independent_states=False),
            myokit.PartialDerivative(dV, C))

        # Diff of "improper" partial derivative
        x = myokit.Derivative(myokit.Name('x'))
        y = myokit.Name('y')
        z = x.diff(y)
        self.assertIsInstance(z, myokit.PartialDerivative)
        self.assertEqual(z.code(), 'diff(dot(str:x), str:y)')

        # Derivative of something depending only on a bound variable is one or
        # zero
        dpd = m.get('bound.dot_pace_direct').lhs()
        self.assertEqual(
            dpd.diff(C, independent_states=True),
            myokit.Number(0, 1 / myokit.units.pF))
        self.assertEqual(
            dpd.diff(C, independent_states=False),
            myokit.Number(0, 1 / myokit.units.pF))

        dpi = m.get('bound.dot_pace_indirect').lhs()
        self.assertEqual(
            dpi.diff(C, independent_states=True),
            myokit.Number(0, 1 / myokit.units.pF))
        self.assertEqual(
            dpi.diff(C, independent_states=False),
            myokit.Number(0, 1 / myokit.units.pF))

    def test_equal(self):
        # Test equality checking on derivatives

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs(3)
        y = c.add_variable('y')
        y.set_rhs(2)
        y.set_unit(myokit.units.Newton)

        D, N = myokit.Derivative, myokit.Name
        self.assertEqual(D(N(x)), D(N(x)))
        self.assertEqual(D(N(y)), D(N(y)))
        self.assertNotEqual(D(N(x)), D(N(y)))
        self.assertNotEqual(D(N(y)), D(N(x)))
        self.assertNotEqual(D(N(x)), D(N(m.clone().get('c.x'))))
        self.assertNotEqual(D(N(x)), D(N('x')))
        self.assertNotEqual(D(N(x)), D(N('c.x')))

    def test_eval_unit(self):
        # Test Derivative.eval_unit()
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        t = c.add_variable('t')
        t.set_rhs('0')
        t.set_binding('time')
        x = c.add_variable('x')
        x.set_rhs('(10 - x) / 100')
        x.promote(0)

        # Get derivative object
        d = x.lhs()

        s = myokit.UNIT_STRICT

        # No units set anywhere: dimensionless
        self.assertEqual(d.eval_unit(), None)
        self.assertEqual(d.eval_unit(s), myokit.units.dimensionless)

        # Time has a unit
        t.set_unit(myokit.units.second)
        self.assertEqual(d.eval_unit(), 1 / myokit.units.second)
        self.assertEqual(d.eval_unit(s), 1 / myokit.units.second)

        # Both have a unit
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            d.eval_unit(), myokit.units.volt / myokit.units.second)
        self.assertEqual(
            d.eval_unit(s), myokit.units.volt / myokit.units.second)

        # Time has no unit
        t.set_unit(None)
        self.assertEqual(d.eval_unit(), myokit.units.volt)
        self.assertEqual(d.eval_unit(s), myokit.units.volt)

    def test_is_name_number_derivative(self):
        # Tests is_name(), is_number(), and is_derivative()

        v = myokit.Model().add_component('c').add_variable('v')
        x = myokit.Derivative(myokit.Name(v))
        self.assertFalse(x.is_name())
        self.assertFalse(x.is_name(v))
        self.assertTrue(x.is_derivative())
        self.assertTrue(x.is_derivative(v))
        w = v.parent().add_variable('w')
        self.assertFalse(x.is_name(w))
        self.assertFalse(x.is_derivative(w))

        self.assertFalse(x.is_number())
        self.assertFalse(x.is_number(0))
        self.assertFalse(x.is_number(1))

    def test_rhs(self):
        # Test Derivative.rhs()
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('(10 - x) / 100')
        x.promote(0)

        # Get derivative object
        d = x.lhs()
        self.assertEqual(d.rhs(), x.rhs())

        # Test with "improper" derivative
        x = myokit.Derivative(myokit.Name('x'))
        self.assertIsNone(x.rhs())

    def test_tree_str(self):
        # Test Derivative.tree_str()

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('(10 - x) / 100')
        x.promote(0)

        # Get derivative object
        d = x.lhs()

        # Test simple
        self.assertEqual(d.tree_str(), 'dot(c.x)\n')

        # Test with spaces
        e = myokit.Plus(d, d)
        self.assertEqual(e.tree_str(), '+\n  dot(c.x)\n  dot(c.x)\n')


class PartialDerivativeTest(unittest.TestCase):
    """ Tests myokit.PartialDerivative. """

    def test_creation(self):
        # Tests creating a partial derivative

        n = myokit.Name('v')
        d = myokit.Derivative(n)
        i = myokit.InitialValue(n)

        # First = name or derivative, Second = name or initial value
        p = myokit.PartialDerivative(n, n)
        self.assertIs(p.dependent_expression(), n)
        self.assertIs(p.independent_expression(), n)

        p = myokit.PartialDerivative(d, n)
        self.assertIs(p.dependent_expression(), d)
        self.assertIs(p.independent_expression(), n)

        p = myokit.PartialDerivative(n, i)
        self.assertIs(p.dependent_expression(), n)
        self.assertIs(p.independent_expression(), i)

        p = myokit.PartialDerivative(d, i)
        self.assertIs(p.dependent_expression(), d)
        self.assertIs(p.independent_expression(), i)

        # Others are not allowed
        self.assertRaisesRegex(
            myokit.TypeError, 'first argument to a partial',
            myokit.PartialDerivative, i, n)
        self.assertRaisesRegex(
            myokit.TypeError, 'first argument to a partial',
            myokit.PartialDerivative, myokit.Number(3), n)
        self.assertRaisesRegex(
            myokit.TypeError, 'first argument to a partial',
            myokit.PartialDerivative, myokit.PrefixPlus(n), n)
        self.assertRaisesRegex(
            myokit.TypeError, 'second argument to a partial',
            myokit.PartialDerivative, n, d)
        self.assertRaisesRegex(
            myokit.TypeError, 'second argument to a partial',
            myokit.PartialDerivative, n, myokit.Number(3))
        self.assertRaisesRegex(
            myokit.TypeError, 'second argument to a partial',
            myokit.PartialDerivative, n, myokit.PrefixPlus(n))

    def test_bracket(self):
        # Tests PartialDerivative.bracket()
        n = myokit.Name('v')
        p = myokit.PartialDerivative(n, n)
        self.assertFalse(p.bracket(n))
        m = myokit.Name('w')
        self.assertRaises(ValueError, p.bracket, m)

    def test_clone(self):
        # Tests PartialDerivative.clone()
        n = myokit.Name('v')
        m = myokit.Name('w')
        p = myokit.PartialDerivative(n, n)
        self.assertEqual(p, p.clone())
        self.assertFalse(p is p.clone())
        self.assertEqual(p.clone(subst={n: m}), myokit.PartialDerivative(m, m))
        self.assertEqual(p.clone(subst={p: m}), m)

    def test_code(self):
        # Tests PartialDerivative.code()
        n = myokit.Name('v')
        p = myokit.PartialDerivative(n, n)
        self.assertEqual(p.code(), 'diff(str:v, str:v)')

    def test_diff(self):
        # Tests PartialDerivative.diff()
        m = pd_model
        C = m.get('membrane.C').lhs()
        p = myokit.PartialDerivative(C, C)
        self.assertRaises(NotImplementedError, p.diff, C)

    def test_equal(self):
        # Tests PartialDerivative.__equal__()
        n = myokit.Name('v')
        m = myokit.Name('w')
        p = myokit.PartialDerivative(n, n)
        q = myokit.PartialDerivative(n, n)
        r = myokit.PartialDerivative(n, m)
        self.assertEqual(p, q)
        self.assertFalse(p is q)
        self.assertNotEqual(p, r)
        self.assertNotEqual(p, n)

    def test_eval_unit(self):
        # Tests PartialDerivative.eval_unit()
        m = pd_model.clone()
        V = myokit.Name(m.get('membrane.V'))
        C = myokit.Name(m.get('membrane.C'))
        p = myokit.PartialDerivative(V, C)
        self.assertEqual(p.eval_unit(), myokit.units.mV / myokit.units.pF)
        m.get('membrane.V').set_unit(None)
        self.assertEqual(p.eval_unit(), 1 / myokit.units.pF)
        m.get('membrane.V').set_unit('mV')
        m.get('membrane.C').set_unit(None)
        self.assertEqual(p.eval_unit(), myokit.units.mV)
        m.get('membrane.V').set_unit(None)
        self.assertEqual(p.eval_unit(), None)

    def test_repr(self):
        # Tests PartialDerivative.__repr__()
        n = myokit.Name('v')
        p = myokit.PartialDerivative(n, n)
        self.assertEqual(
            repr(p), '<PartialDerivative(' + repr(n) + ', ' + repr(n) + ')>')

    def test_rhs(self):
        # Tests PartialDerivative.rhs()
        n = myokit.Name('v')
        p = myokit.PartialDerivative(n, n)
        self.assertIsNone(p.rhs())

    def test_tree_str(self):
        # Tests PartialDerivative.tree_str()
        n = myokit.Name('v')
        p = myokit.PartialDerivative(n, n)
        self.assertEqual(p.tree_str(), 'partial\n  v\n  v\n')
        q = myokit.PrefixPlus(p)
        self.assertEqual(q.tree_str(), '+\n  partial\n    v\n    v\n')

    def test_var(self):
        # Tests PartialDerivative.var()
        m = pd_model
        V = myokit.Name(m.get('membrane.V'))
        C = myokit.Name(m.get('membrane.C'))
        p = myokit.PartialDerivative(V, C)
        self.assertEqual(p.var(), V.var())


class InitialValueTest(unittest.TestCase):
    """ Tests myokit.InitialValue. """

    def test_creation(self):
        # Tests creating an initial value

        n = myokit.Name('v')
        d = myokit.Derivative(n)
        i = myokit.InitialValue(n)

        # Value must be a name
        self.assertRaisesRegex(
            myokit.TypeError, 'argument to an initial value must be a variab',
            myokit.InitialValue, d)
        self.assertRaisesRegex(
            myokit.TypeError, 'argument to an initial value must be a variab',
            myokit.InitialValue, i)
        self.assertRaisesRegex(
            myokit.TypeError, 'argument to an initial value must be a variab',
            myokit.InitialValue, myokit.Number(3),)
        self.assertRaisesRegex(
            myokit.TypeError, 'argument to an initial value must be a variab',
            myokit.InitialValue, myokit.PrefixPlus(n))

    def test_bracket(self):
        # Tests InitialValue.bracket()
        n = myokit.Name('v')
        i = myokit.InitialValue(n)
        self.assertFalse(i.bracket(n))
        m = myokit.Name('w')
        self.assertRaises(ValueError, i.bracket, m)

    def test_clone(self):
        # Tests InitialValue.clone()
        n = myokit.Name('v')
        m = myokit.Name('w')
        i = myokit.InitialValue(n)
        self.assertEqual(i, i.clone())
        self.assertFalse(i is i.clone())
        self.assertEqual(i.clone(subst={n: m}), myokit.InitialValue(m))
        self.assertEqual(i.clone(subst={i: m}), m)

    def test_code(self):
        # Tests InitialValue.code()
        n = myokit.Name('v')
        i = myokit.InitialValue(n)
        self.assertEqual(i.code(), 'init(str:v)')

    def test_diff(self):
        # Tests InitialValue.diff()
        m = pd_model
        V = myokit.Name(m.get('membrane.V'))
        C = myokit.Name(m.get('membrane.C'))
        i = myokit.InitialValue(V)
        self.assertRaises(NotImplementedError, i.diff, C)

    def test_equal(self):
        # Tests InitialValue.__equal__()
        n = myokit.Name('v')
        m = myokit.Name('w')
        i = myokit.InitialValue(n)
        j = myokit.InitialValue(n)
        k = myokit.InitialValue(m)
        self.assertEqual(i, j)
        self.assertFalse(i is j)
        self.assertNotEqual(i, k)
        self.assertNotEqual(i, m)

    def test_eval_unit(self):
        # Tests InitialValue.eval_unit()

        m = pd_model.clone()
        V = myokit.Name(m.get('membrane.V'))
        i = myokit.InitialValue(V)
        self.assertEqual(i.eval_unit(), myokit.units.mV)

    def test_repr(self):
        # Tests InitialValue.__repr__()
        n = myokit.Name('v')
        i = myokit.InitialValue(n)
        self.assertEqual(repr(i), '<InitialValue(' + repr(n) + ')>')

    def test_rhs(self):
        # Tests InitialValue.rhs()
        n = myokit.Name('v')
        i = myokit.InitialValue(n)
        self.assertIsNone(i.rhs())

    def test_tree_str(self):
        # Tests InitialValue.tree_str()
        n = myokit.Name('v')
        i = myokit.InitialValue(n)
        self.assertEqual(i.tree_str(), 'init(v)\n')
        q = myokit.PrefixPlus(i)
        self.assertEqual(q.tree_str(), '+\n  init(v)\n')

    def test_var(self):
        # Tests InitialValue.var()
        m = pd_model
        V = myokit.Name(m.get('membrane.V'))
        i = myokit.InitialValue(V)
        self.assertEqual(i.var(), V.var())

    def test_validate(self):
        # Tests InitialValue validation

        # Must be a state
        m = pd_model
        V = myokit.Name(m.get('membrane.V'))
        C = myokit.Name(m.get('membrane.C'))
        i = myokit.InitialValue(V)
        i.validate()
        i = myokit.InitialValue(C)
        self.assertRaises(myokit.IntegrityError, i.validate)


class PrefixPlusTest(unittest.TestCase):
    """Tests myokit.PrefixPlus."""

    def test_bracket(self):
        # Test PrefixPlus.bracket().
        i = myokit.Number(1)
        x = myokit.PrefixPlus(i)
        self.assertFalse(x.bracket(i))
        i = myokit.Plus(myokit.Number(1), myokit.Number(2))
        x = myokit.PrefixPlus(i)
        self.assertTrue(x.bracket(i))
        self.assertRaises(ValueError, x.bracket, myokit.Number(1))

    def test_clone(self):
        # Test PrefixPlus.clone().
        x = myokit.PrefixPlus(myokit.Number(3))
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.PrefixPlus(myokit.Number(4))
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        i = myokit.Number(1)
        j = myokit.Number(2)
        x = myokit.PrefixPlus(i)
        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.PrefixPlus(j))

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.PrefixPlus, 3)
        self.assertRaisesRegex(
            myokit.TypeError, 'expected a numerical', myokit.PrefixPlus,
            myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests PrefixPlus.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('+ina.I1')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g)')
        V.set_rhs('+4')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test PrefixPlus evaluation.
        x = myokit.PrefixPlus(myokit.Number(2))
        self.assertEqual(x.eval(), 2)

    def test_eval_unit(self):
        # Test PrefixPlus.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('+(3)')
        y = c.add_variable('y')
        y.set_rhs('+(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_is_name_number_derivative(self):
        # Tests is_name(), is_number(), and is_derivative()

        x = myokit.PrefixPlus(myokit.Number(1))
        self.assertFalse(x.is_name())
        v = myokit.Model().add_component('c').add_variable('v')
        self.assertFalse(x.is_name(v))
        self.assertFalse(x.is_derivative())
        self.assertFalse(x.is_derivative(v))

        self.assertFalse(x.is_number())
        self.assertFalse(x.is_number(0))
        self.assertFalse(x.is_number(1))

    def test_tree_str(self):
        # Test PrefixPlus.tree_str()

        # Test simple
        x = myokit.PrefixPlus(myokit.Number(1))
        self.assertEqual(x.tree_str(), '+\n  1\n')

        # Test with spaces
        y = myokit.Plus(
            myokit.PrefixPlus(myokit.Number(-1)),
            myokit.PrefixPlus(myokit.Number(2)))
        self.assertEqual(y.tree_str(), '+\n  +\n    -1\n  +\n    2\n')


class PrefixMinusTest(unittest.TestCase):
    """Tests myokit.PrefixMinus."""

    def test_bracket(self):
        # Test PrefixMinus.bracket().

        i = myokit.Number(1)
        x = myokit.PrefixMinus(i)
        self.assertFalse(x.bracket(i))
        i = myokit.Plus(myokit.Number(1), myokit.Number(2))
        x = myokit.PrefixMinus(i)
        self.assertTrue(x.bracket(i))
        self.assertRaises(ValueError, x.bracket, myokit.Number(1))

    def test_clone(self):
        # Test PrefixMinus.clone().
        x = myokit.PrefixMinus(myokit.Number(3))
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.PrefixMinus(myokit.Number(4))
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        i = myokit.Number(1)
        j = myokit.Number(2)
        x = myokit.PrefixMinus(i)
        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.PrefixMinus(j))

    def test_creation(self):
        # Operand must be an expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.PrefixMinus, 'test')
        self.assertRaisesRegex(
            myokit.TypeError, 'expected a numerical', myokit.PrefixMinus,
            myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests PrefixMinus.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('-ina.I1')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), '-diff(ina.I1, ina.g)')
        V.set_rhs('-4')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test PrefixMinus evaluation.

        x = myokit.PrefixMinus(myokit.Number(2))
        self.assertEqual(x.eval(), -2)

    def test_eval_unit(self):
        # Test PrefixMinus.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('-(3)')
        y = c.add_variable('y')
        y.set_rhs('-(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_is_name_number_derivative(self):
        # Tests is_name(), is_number(), and is_derivative()

        x = myokit.PrefixMinus(myokit.Number(1))
        self.assertFalse(x.is_name())
        v = myokit.Model().add_component('c').add_variable('v')
        self.assertFalse(x.is_name(v))
        self.assertFalse(x.is_derivative())
        self.assertFalse(x.is_derivative(v))

        self.assertFalse(x.is_number())
        self.assertFalse(x.is_number(0))
        self.assertFalse(x.is_number(1))

    def test_tree_str(self):
        # Test PrefixMinus.tree_str()
        # Test simple
        x = myokit.PrefixMinus(myokit.Number(1))
        self.assertEqual(x.tree_str(), '-\n  1\n')

        # Test with spaces
        y = myokit.Plus(
            myokit.PrefixMinus(myokit.Number(1)),
            myokit.PrefixMinus(myokit.Number(-2)))
        self.assertEqual(y.tree_str(), '+\n  -\n    1\n  -\n    -2\n')


class PlusTest(unittest.TestCase):
    """Tests myokit.Plus."""

    def test_bracket(self):
        # Test Plus.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')
        x = myokit.Plus(i, j)
        self.assertFalse(x.bracket(i))
        self.assertTrue(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_clone(self):
        # Test Plus.clone().
        i = myokit.Number(3)
        j = myokit.Number(4)
        x = myokit.Plus(i, j)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Plus(j, i)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Plus(j, j))
        y = x.clone(subst={j: i})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Plus(i, i))

    def test_creation(self):
        # Operands must be numerical expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Plus, 'toast', 4)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.Plus, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.Plus, myokit.Number(1), a)

    def test_diff(self):
        # Tests Plus.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('2 + ina.I1')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g)')
        V.set_rhs('ina.I1 + 2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g)')
        V.set_rhs('ina.I1 + ina.I2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'diff(ina.I1, ina.g) + diff(ina.I2, ina.g)')
        V.set_rhs('1 [mV/ms] + 4 [mV/ms]')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.parse_unit('mV/ms/nS'))

    def test_eval(self):
        # Test Plus evaluation.

        x = myokit.Plus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.eval(), 3)
        x = myokit.Plus(myokit.Number(1), myokit.PrefixMinus(myokit.Number(2)))
        self.assertEqual(x.eval(), -1)

    def test_eval_unit(self):
        # Test Plus.eval_unit().
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Plus(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        x.set_unit(None)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

        # Tokens are used in IncompatibleUnitError messages
        m = myokit.parse_model('\n'.join([
            '[[model]]',
            '[a]',
            't = 1 [ms] + 1 [mV]',
            '    in [ms]',
            '    bind time',
        ]))
        try:
            m.check_units(myokit.UNIT_STRICT)
        except myokit.IncompatibleUnitError as e:
            self.assertIn('on line 3', str(e))
            token = e.token()
            self.assertIsNotNone(token)
            self.assertEqual(token[2], 3)
            self.assertEqual(token[3], 11)

    def test_is_name_number_derivative(self):
        # Tests is_name(), is_number(), and is_derivative()

        x = myokit.Plus(myokit.Number(1), myokit.Number(0))
        self.assertFalse(x.is_name())
        v = myokit.Model().add_component('c').add_variable('v')
        self.assertFalse(x.is_name(v))
        self.assertFalse(x.is_derivative())
        self.assertFalse(x.is_derivative(v))

        self.assertFalse(x.is_number())
        self.assertFalse(x.is_number(0))
        self.assertFalse(x.is_number(1))

    def test_tree_str(self):
        # Test Plus.tree_str().
        # Test simple
        x = myokit.Plus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '+\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  +\n    1\n    2\n')
        x = myokit.parse_expression('1 + (2 + 3)')
        self.assertEqual(x.tree_str(), '+\n  1\n  +\n    2\n    3\n')


class MinusTest(unittest.TestCase):
    """Tests myokit.Minus."""

    def test_creation(self):
        # Operands must be numerical expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Minus, 7, None)
        a = myokit.NotEqual(myokit.Number(3), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.Minus, a, myokit.Number(3))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.Minus, myokit.Number(3), a)

    def test_diff(self):
        # Tests Minus.diff()
        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('2 - ina.I1')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), '-diff(ina.I1, ina.g)')
        V.set_rhs('ina.I1 - 2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g)')
        V.set_rhs('ina.I1 - ina.I2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'diff(ina.I1, ina.g) - diff(ina.I2, ina.g)')
        V.set_rhs('1 [mV/ms] - 4 [mV/ms]')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.parse_unit('mV/ms/nS'))

    def test_eval(self):
        # Test Minus evaluation.

        x = myokit.Minus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.eval(), -1)

    def test_eval_unit(self):
        # Test Minus.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Minus(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        x.set_unit(None)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_is_name_number_derivative(self):
        # Tests is_name(), is_number(), and is_derivative()

        x = myokit.Minus(myokit.Number(2), myokit.Number(3))
        self.assertFalse(x.is_name())
        v = myokit.Model().add_component('c').add_variable('v')
        self.assertFalse(x.is_name(v))
        self.assertFalse(x.is_derivative())
        self.assertFalse(x.is_derivative(v))

        self.assertFalse(x.is_number())
        self.assertFalse(x.is_number(0))
        self.assertFalse(x.is_number(1))

    def test_tree_str(self):
        # Test Minus.tree_str().
        # Test simple
        x = myokit.Minus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '-\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  -\n    1\n    2\n')
        x = myokit.parse_expression('1 - (2 - 3)')
        self.assertEqual(x.tree_str(), '-\n  1\n  -\n    2\n    3\n')


class MultiplyTest(unittest.TestCase):
    """Tests myokit.Multiply."""

    def test_creation(self):
        # Operands must be expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Multiply, 15, 3)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.Multiply, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.Multiply, myokit.Number(1), a)

    def test_diff(self):
        # Tests Multiply.diff()
        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('2 * ina.I1')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), '2 * diff(ina.I1, ina.g)')
        V.set_rhs('ina.I1 * 2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g) * 2')
        V.set_rhs('ina.I1 * ina.I2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'diff(ina.I1, ina.g) * ina.I2 + '
            'ina.I1 * diff(ina.I2, ina.g)')
        V.set_rhs('1 [mV] * 4 [1/ms]')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.parse_unit('mV/ms/nS'))

    def test_eval(self):
        # Test Multiply evaluation.

        x = myokit.Multiply(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.eval(), 2)

    def test_eval_unit(self):
        # Test Multiply.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Multiply(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(), myokit.units.volt * myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (where None becomes dimensionless)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.volt * myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Multiply.tree_str().

        # Test simple
        x = myokit.Multiply(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '*\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  *\n    1\n    2\n')
        x = myokit.parse_expression('1 * (2 * 3)')
        self.assertEqual(x.tree_str(), '*\n  1\n  *\n    2\n    3\n')


class DivideTest(unittest.TestCase):
    """Tests myokit.Divide."""

    def test_creation(self):
        # Operands must be expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Divide, 15, 3)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.Divide, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.Divide, myokit.Number(1), a)

    def test_diff(self):
        # Tests Divide.diff()
        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('2 / ina.I1')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), '-2 * diff(ina.I1, ina.g) / ina.I1^2')
        V.set_rhs('ina.I1 / 2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g) / 2')
        V.set_rhs('ina.I1 / ina.I2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            '(diff(ina.I1, ina.g) * ina.I2'
            ' - ina.I1 * diff(ina.I2, ina.g))'
            ' / ina.I2^2')
        V.set_rhs('1 [mV] / 4 [ms]')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.parse_unit('mV/ms/nS'))

    def test_eval(self):
        # Test Divide evaluation.

        x = myokit.Divide(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.eval(), 0.5)

    def test_eval_unit(self):
        # Test Divide.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Divide(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(), myokit.units.volt / myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), 1 / myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (where None becomes dimensionless)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.volt / myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            1 / myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Divide.tree_str().
        # Test simple
        x = myokit.Divide(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '/\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  /\n    1\n    2\n')
        x = myokit.parse_expression('1 / (2 / 3)')
        self.assertEqual(x.tree_str(), '/\n  1\n  /\n    2\n    3\n')


class QuotientTest(unittest.TestCase):
    """Tests myokit.Quotient."""

    def test_creation(self):
        # Operands must be expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Quotient, 15, 3)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.Quotient, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.Quotient, myokit.Number(1), a)

    def test_diff(self):
        # Tests Quotient.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('ina.I1 // ina.I2')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.parse_unit('1/nS'))

    def test_eval(self):
        # Test Quotient evaluation.

        x = myokit.Quotient(myokit.Number(7), myokit.Number(2))
        self.assertEqual(x.eval(), 3.0)

    def test_eval_unit(self):
        # Test Quotient.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Quotient(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(), myokit.units.volt / myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), 1 / myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (where None becomes dimensionless)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.volt / myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            1 / myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Quotient.tree_str().
        # Test simple
        x = myokit.Quotient(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '//\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  //\n    1\n    2\n')
        x = myokit.parse_expression('1 // (2 // 3)')
        self.assertEqual(x.tree_str(), '//\n  1\n  //\n    2\n    3\n')


class RemainderTest(unittest.TestCase):
    """Tests myokit.Remainder."""

    def test_creation(self):
        # Operands must be expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Remainder, myokit.Number(3), 3)
        a = myokit.MoreEqual(myokit.Number(1.1), myokit.Number(2.1))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.Remainder, a, myokit.Number(1.3))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.Remainder, myokit.Number(-1.2), a)

    def test_diff(self):
        # Tests Remainder.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('2 % ina.I1')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), '-diff(ina.I1, ina.g) * floor(2 / ina.I1)')
        V.set_rhs('ina.I1 % 2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g)')
        V.set_rhs('ina.I1 % ina.I2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'diff(ina.I1, ina.g) - '
            'diff(ina.I2, ina.g) * floor(ina.I1 / ina.I2)')
        V.set_rhs('1 [mV/ms] % 4 [1]')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.parse_unit('mV/ms/nS'))

    def test_eval(self):
        # Test Divide evaluation.

        x = myokit.Remainder(myokit.Number(7), myokit.Number(4))
        self.assertEqual(x.eval(), 3.0)

    def test_eval_unit(self):
        # Test Remainder.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Remainder(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (where None becomes dimensionless)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.dimensionless)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Remainder.tree_str().

        # Test simple
        x = myokit.Remainder(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '%\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  %\n    1\n    2\n')
        x = myokit.parse_expression('1 % (2 % 3)')
        self.assertEqual(x.tree_str(), '%\n  1\n  %\n    2\n    3\n')


class PowerTest(unittest.TestCase):
    """Tests myokit.Power."""

    def test_bracket(self):
        # Test Power.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')
        x = myokit.Power(i, j)
        self.assertFalse(x.bracket(i))
        self.assertTrue(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_clone(self):
        # Test Power.clone().
        i = myokit.Number(3)
        j = myokit.Number(4)
        x = myokit.Power(i, j)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Power(j, i)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Power(j, j))
        y = x.clone(subst={j: i})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Power(i, i))

    def test_creation(self):
        # Operands must be expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Power, myokit.Number(3), 3)
        a = myokit.Less(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.Power, a, myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.Power, myokit.Number(3.2), a)

    def test_diff(self):
        # Tests Power.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('ina.I1^(2 * 3)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), '2 * 3 * ina.I1^(2 * 3 - 1) * diff(ina.I1, ina.g)')
        V.set_rhs('ina.I1^3')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), '3 * ina.I1^2 * diff(ina.I1, ina.g)')
        V.set_rhs('ina.I1^2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), '2 * ina.I1 * diff(ina.I1, ina.g)')
        V.set_rhs('ina.I1^1')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g)')
        V.set_rhs('2^ina.I1')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), '2^ina.I1 * diff(ina.I1, ina.g) / log(2)')
        V.set_rhs('ina.I1^ina.I2')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'ina.I1^ina.I2 * ('
            'log(ina.I1) * diff(ina.I2, ina.g) + '
            'ina.I2 / ina.I1 * diff(ina.I1, ina.g))')
        V.set_rhs('1 [mV]^1')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.units.mV / myokit.units.nS)

    def test_eval(self):
        # Test Power evaluation.

        x = myokit.Power(myokit.Number(2), myokit.Number(3))
        self.assertEqual(x.eval(), 8)
        x = myokit.Power(
            myokit.Number(2), myokit.PrefixMinus(myokit.Number(1)))
        self.assertEqual(x.eval(), 0.5)

    def test_eval_unit(self):
        # Test Power.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(2)
        z.set_rhs(myokit.Power(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt ** 2)
        y.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt ** 2)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.volt ** 2)
        y.set_unit(myokit.units.volt)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        x.set_unit(None)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_is_name_number_derivative(self):
        # Tests is_name(), is_number(), and is_derivative()

        x = myokit.Power(myokit.Number(2), myokit.Number(3))
        self.assertFalse(x.is_name())
        v = myokit.Model().add_component('c').add_variable('v')
        self.assertFalse(x.is_name(v))
        self.assertFalse(x.is_derivative())
        self.assertFalse(x.is_derivative(v))

        self.assertFalse(x.is_number())
        self.assertFalse(x.is_number(0))
        self.assertFalse(x.is_number(1))

    def test_tree_str(self):
        # Test Power.tree_str().

        # Test simple
        x = myokit.Power(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '^\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  ^\n    1\n    2\n')
        x = myokit.parse_expression('1^(2^3)')
        self.assertEqual(x.tree_str(), '^\n  1\n  ^\n    2\n    3\n')


class SqrtTest(unittest.TestCase):
    """Tests myokit.Sqrt."""

    def test_bracket(self):
        # Test Sqrt.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')
        x = myokit.Sqrt(i)
        self.assertFalse(x.bracket(i))
        x = myokit.Sqrt(j)
        self.assertFalse(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_clone(self):
        # Test Sqrt.clone().
        i = myokit.Number(3)
        j = myokit.Number(10)
        x = myokit.Sqrt(i)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Sqrt(j)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, z)

    def test_creation(self):
        myokit.Sqrt(myokit.Number(1))

        # Wrong number of operands
        self.assertRaisesRegex(
            myokit.IntegrityError, 'wrong number', myokit.Sqrt,
            myokit.Number(1), myokit.Number(2))

        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Sqrt, False)
        self.assertRaisesRegex(
            myokit.TypeError, r'sqrt\(\) expects a numerical operand',
            myokit.Sqrt, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests Sqrt.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('sqrt(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'diff(ina.I1, ina.g) / (2 * sqrt(ina.I1))')
        V.set_rhs('sqrt(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test Sqrt evaluation.

        x = myokit.Sqrt(myokit.Number(9))
        self.assertEqual(x.eval(), 3)

    def test_eval_unit(self):
        # Test Sqrt.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        z = c.add_variable('z')
        x.set_rhs(1)
        z.set_rhs(myokit.Sqrt(x.lhs()))

        # Test in tolerant mode
        #self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt**0.5)
        x.set_unit(myokit.units.volt ** 2)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt**0.5)
        x.set_unit(myokit.units.volt ** 2)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Sqrt.tree_str().
        # Test simple
        x = myokit.Sqrt(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'sqrt\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  sqrt\n    2\n')
        x = myokit.parse_expression('sqrt(1 + sqrt(2))')
        self.assertEqual(x.tree_str(), 'sqrt\n  +\n    1\n    sqrt\n      2\n')


class ExpTest(unittest.TestCase):
    """Tests myokit.Exp. """

    def test_bracket(self):
        # Test Exp.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')
        x = myokit.Exp(i)
        self.assertFalse(x.bracket(i))
        x = myokit.Exp(j)
        self.assertFalse(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_clone(self):
        # Test Exp.clone().
        i = myokit.Number(3)
        j = myokit.Number(10)
        x = myokit.Exp(i)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Exp(j)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, z)

    def test_creation(self):
        # Test Exp creation.
        myokit.Exp(myokit.Number(1))

        # Wrong number of operands
        self.assertRaisesRegex(
            myokit.IntegrityError, 'wrong number', myokit.Exp,
            myokit.Number(1), myokit.Number(2))

        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Exp, 1.2)
        self.assertRaisesRegex(
            myokit.TypeError, r'Function exp\(\) expects a numerical operand',
            myokit.Exp, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests Exp.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('exp(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'exp(ina.I1) * diff(ina.I1, ina.g)')
        V.set_rhs('exp(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test Exp.eval().
        x = myokit.Exp(myokit.Number(9))
        self.assertEqual(x.eval(), np.exp(9))

    def test_eval_unit(self):
        # Test Exp.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        z = c.add_variable('z')
        x.set_rhs(1)
        z.set_rhs(myokit.Exp(x.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_is_name_number_derivative(self):
        # Tests is_name(), is_number(), and is_derivative()

        x = myokit.Exp(myokit.Number(7))
        self.assertFalse(x.is_name())
        v = myokit.Model().add_component('c').add_variable('v')
        self.assertFalse(x.is_name(v))
        self.assertFalse(x.is_derivative())
        self.assertFalse(x.is_derivative(v))

        self.assertFalse(x.is_number())
        self.assertFalse(x.is_number(0))
        self.assertFalse(x.is_number(1))

    def test_tree_str(self):
        # Test Exp.tree_str().

        # Test simple
        x = myokit.Exp(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'exp\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  exp\n    2\n')
        x = myokit.parse_expression('exp(1 + exp(2))')
        self.assertEqual(x.tree_str(), 'exp\n  +\n    1\n    exp\n      2\n')


class LogTest(unittest.TestCase):
    """Tests myokit.Log."""

    def test_bracket(self):
        # Test Log.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')

        # Test with one operand
        x = myokit.Log(i)
        self.assertFalse(x.bracket(i))
        x = myokit.Log(j)
        self.assertFalse(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

        # Test with two operands
        x = myokit.Log(i, j)
        self.assertFalse(x.bracket(i))
        self.assertFalse(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_clone(self):
        # Test Log.clone().

        # Test with one operand
        i = myokit.Number(3)
        j = myokit.Number(10)
        x = myokit.Log(i)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Log(j)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, z)

        # Test with two operands
        x = myokit.Log(i, j)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Log(j, i)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Log(j, j))
        y = x.clone(subst={j: i})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Log(i, i))

    def test_creation(self):
        # Test Log creation.
        myokit.Log(myokit.Number(1))
        myokit.Log(myokit.Number(1), myokit.Number(2))

        # Wrong number of operatnds
        self.assertRaisesRegex(
            myokit.IntegrityError, 'wrong number', myokit.Log,
            myokit.Number(1), myokit.Number(2), myokit.Number(3))

        # Operands must be numerical expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Log, 1.2)
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Log, myokit.Number(3), 1.2)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, r'first operand: function log\(\) expects numer',
            myokit.Log, a)
        self.assertRaisesRegex(
            myokit.TypeError, r'first operand: function log\(\) expects numer',
            myokit.Log, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, r'second operand: function log\(\) expects nume',
            myokit.Log, myokit.Number(1), a)

    def test_diff(self):
        # Tests Log.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')

        # One operand
        V.set_rhs('log(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g) / ina.I1')
        V.set_rhs('log(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

        # Two operands
        V.set_rhs('log(ina.I1, 3)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'diff(ina.I1, ina.g) / (ina.I1 * log(3))')
        V.set_rhs('log(2, ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            '-diff(ina.I1, ina.g) * log(2) / (ina.I1 * log(ina.I1)^2)')
        V.set_rhs('log(ina.I2, ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'diff(ina.I2, ina.g) / (ina.I2 * log(ina.I1)) - '
            'diff(ina.I1, ina.g) * log(ina.I2) / ('
            'ina.I1 * log(ina.I1)^2)')
        V.set_rhs('log(3, 2)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test Exp.eval().
        # One argument
        x = myokit.Log(myokit.Number(9))
        self.assertEqual(x.eval(), np.log(9))

        # Two arguments
        x = myokit.Log(myokit.Number(9), myokit.Number(5))
        self.assertEqual(x.eval(), np.log(9) / np.log(5))

    def test_eval_unit(self):
        # Test Log.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(2)

        # Single operand
        z.set_rhs(myokit.Log(x.lhs()))

        # Test in tolerant mode (single operand)
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (single operand)
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

        # Double operand
        z.set_rhs(myokit.Log(x.lhs(), y.lhs()))

        # Test in tolerant mode (double operand)
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        y.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (double operand)
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        y.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        x.set_unit(None)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Log.tree_str().

        # Test simple
        x = myokit.Log(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'log\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  log\n    2\n')
        x = myokit.parse_expression('log(log(1, 2))')
        self.assertEqual(x.tree_str(), 'log\n  log\n    1\n    2\n')


class Log10Test(unittest.TestCase):
    """Tests myokit.Log10."""

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Log10, 1.2)
        self.assertRaisesRegex(
            myokit.TypeError, r'log10\(\) expects a numerical operand',
            myokit.Log10, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests Log10.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')

        V.set_rhs('log10(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'diff(ina.I1, ina.g) / (ina.I1 * log(10))')
        V.set_rhs('log10(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test Log10.eval().
        x = myokit.Log10(myokit.Number(9))
        self.assertEqual(x.eval(), np.log10(9))

    def test_tree_str(self):
        # Test Log10.tree_str().
        x = myokit.Log10(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'log10\n  2\n')


class SinTest(unittest.TestCase):
    """Tests myokit.Sin."""

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Sin, 2.1)
        self.assertRaisesRegex(
            myokit.TypeError, r'sin\(\) expects a numerical operand',
            myokit.Sin, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests Sin.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')

        V.set_rhs('sin(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'cos(ina.I1) * diff(ina.I1, ina.g)')
        V.set_rhs('sin(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test Sin.eval().
        x = myokit.Sin(myokit.Number(9))
        self.assertEqual(x.eval(), np.sin(9))

    def test_tree_str(self):
        # Test Sin.tree_str().
        x = myokit.Sin(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'sin\n  2\n')


class CosTest(unittest.TestCase):
    """Tests myokit.Cos."""

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Cos, myokit.Cos)
        self.assertRaisesRegex(
            myokit.TypeError, r'cos\(\) expects a numerical operand',
            myokit.Cos, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests Cos.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('cos(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), '-sin(ina.I1) * diff(ina.I1, ina.g)')
        V.set_rhs('cos(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test Cos.eval().
        x = myokit.Cos(myokit.Number(9))
        self.assertEqual(x.eval(), np.cos(9))

    def test_tree_str(self):
        # Test Cos.tree_str().
        x = myokit.Cos(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'cos\n  2\n')


class TanTest(unittest.TestCase):
    """ Tests myokit.Tan. """

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Tan, myokit.Model())
        self.assertRaisesRegex(
            myokit.TypeError, r'tan\(\) expects a numerical operand',
            myokit.Tan, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests Tan.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('tan(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(p.code(), 'diff(ina.I1, ina.g) / cos(ina.I1)^2')
        V.set_rhs('tan(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test Tan.eval().
        x = myokit.Tan(myokit.Number(9))
        self.assertEqual(x.eval(), np.tan(9))

    def test_tree_str(self):
        # Test Tan.tree_str().
        x = myokit.Tan(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'tan\n  2\n')


class ASinTest(unittest.TestCase):
    """ Tests myokit.ASin. """

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.ASin, 4)
        self.assertRaisesRegex(
            myokit.TypeError, r'asin\(\) expects a numerical operand',
            myokit.ASin, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests ASin.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')
        V.set_rhs('asin(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'diff(ina.I1, ina.g) / sqrt(1 - ina.I1^2)')
        V.set_rhs('asin(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test ASin.eval().
        x = myokit.ASin(myokit.Number(0.9))
        self.assertEqual(x.eval(), np.arcsin(0.9))

    def test_tree_str(self):
        # Test ASin.tree_str().
        x = myokit.ASin(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'asin\n  0.5\n')


class ACosTest(unittest.TestCase):
    """ Tests myokit.ACos. """

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.ACos, 4)
        self.assertRaisesRegex(
            myokit.TypeError, r'acos\(\) expects a numerical operand',
            myokit.ACos, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests ACos.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')

        V.set_rhs('acos(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), '-diff(ina.I1, ina.g) / sqrt(1 - ina.I1^2)')
        V.set_rhs('acos(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test ACos.eval().
        x = myokit.ACos(myokit.Number(0.9))
        self.assertEqual(x.eval(), np.arccos(0.9))

    def test_tree_str(self):
        # Test ACos.tree_str().
        x = myokit.ACos(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'acos\n  0.5\n')


class ATanTest(unittest.TestCase):
    """ Tests myokit.ATan. """

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.ATan, 4)
        self.assertRaisesRegex(
            myokit.TypeError, r'atan\(\) expects a numerical operand',
            myokit.ATan, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests ATan.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')

        V.set_rhs('atan(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'diff(ina.I1, ina.g) / (1 + ina.I1^2)')
        V.set_rhs('atan(3)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test ATan.eval().
        x = myokit.ATan(myokit.Number(0.9))
        self.assertEqual(x.eval(), np.arctan(0.9))

    def test_tree_str(self):
        # Test ATan.tree_str().
        x = myokit.ATan(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'atan\n  0.5\n')


class FloorTest(unittest.TestCase):
    """ Tests myokit.Floor. """

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Floor, 1.2)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, r'floor\(\) expects a numerical operand',
            myokit.Floor, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests Floor.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        C = m.get('membrane.C')

        V.set_rhs('floor(membrane.V)')
        p = V.rhs().diff(C.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.units.mV / myokit.units.pF)
        V.set_rhs('floor(3.2)')
        p = V.rhs().diff(C.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.pF)

    def test_eval(self):
        # Test Floor.eval().
        x = myokit.Floor(myokit.Number(0.9))
        self.assertEqual(x.eval(), 0)

    def test_eval_unit(self):
        # Test Floor.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('floor(3)')
        y = c.add_variable('y')
        y.set_rhs('floor(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_tree_str(self):
        # Test Floor.tree_str().
        x = myokit.Floor(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'floor\n  0.5\n')


class CeilTest(unittest.TestCase):
    """ Tests myokit.Ceil. """

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Ceil, 3.4)
        self.assertRaisesRegex(
            myokit.TypeError, r'ceil\(\) expects a numerical operand',
            myokit.Ceil, myokit.LessEqual(myokit.Number(3), myokit.Number(2)))

    def test_diff(self):
        # Tests Ceil.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        C = m.get('membrane.C')

        V.set_rhs('ceil(membrane.V)')
        p = V.rhs().diff(C.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.units.mV / myokit.units.pF)
        V.set_rhs('ceil(3.2)')
        p = V.rhs().diff(C.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.pF)

    def test_eval(self):
        # Test Ceil.eval().
        x = myokit.Ceil(myokit.Number(0.9))
        self.assertEqual(x.eval(), 1)

    def test_eval_unit(self):
        # Test Ceil.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('ceil(3)')
        y = c.add_variable('y')
        y.set_rhs('ceil(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_tree_str(self):
        # Test Ceil.tree_str().
        x = myokit.Ceil(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'ceil\n  0.5\n')


class AbsTest(unittest.TestCase):
    """ Tests myokit.Abs. """

    def test_creation(self):
        # Operand must be a numerical expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Abs, 3.4)
        self.assertRaisesRegex(
            myokit.TypeError, r'abs\(\) expects a numerical operand',
            myokit.Abs, myokit.Equal(myokit.Number(1), myokit.Number(2)))

    def test_diff(self):
        # Tests Abs.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')

        # Operand with derivative, and units
        V.set_rhs('abs(ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'if(ina.I1 >= 0 [pA], diff(ina.I1, ina.g),'
            ' -diff(ina.I1, ina.g))')
        # Operand with derivative, no units
        i = m.get('ina.I1')
        i.set_unit(None)
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'if(ina.I1 >= 0, diff(ina.I1, ina.g), -diff(ina.I1, ina.g))')
        # Operand with derivative, and invalid units
        V.set_rhs('abs(ina.I1 + 2 [pF])')
        i.set_unit('pA')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'if(ina.I1 + 2 [pF] >= 0, diff(ina.I1, ina.g), '
            '-diff(ina.I1, ina.g))')
        # Operand without derivative or units
        V.set_rhs('abs(-13.2)')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), 1 / myokit.units.nS)

    def test_eval(self):
        # Test Abs.eval().
        x = myokit.Abs(myokit.Number(0.9))
        self.assertEqual(x.eval(), 0.9)
        x = myokit.Abs(myokit.Number(-0.9))
        self.assertEqual(x.eval(), 0.9)

    def test_eval_unit(self):
        # Test Abs.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('abs(3)')
        y = c.add_variable('y')
        y.set_rhs('abs(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_tree_str(self):
        # Test Abs.tree_str().
        x = myokit.Abs(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'abs\n  0.5\n')


class EqualTest(unittest.TestCase):
    """ Tests myokit.Equal. """

    def test_creation(self):
        # Operands must be numerical expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Equal, 1, 1)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.Equal, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.Equal, myokit.Number(1), a)

    def test_diff(self):
        # Tests Equal.diff()
        x = myokit.Equal(myokit.Number(1), myokit.Number(1))
        y = myokit.Model().add_component('c').add_variable('y')
        y.set_rhs('3')
        y = myokit.Name(y)
        self.assertRaises(NotImplementedError, x.diff, y)

    def test_eval(self):
        # Test Equal.eval().
        x = myokit.Equal(myokit.Number(1), myokit.Number(1))
        self.assertTrue(x.eval())
        x = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertFalse(x.eval())

    def test_eval_unit(self):
        # Test Equal.eval_unit().

        # None and None is always fine
        s = myokit.UNIT_STRICT
        e = myokit.Equal(myokit.Number(1), myokit.Number(2))
        d = myokit.units.dimensionless
        self.assertEqual(e.eval_unit(), d)
        self.assertEqual(e.eval_unit(s), d)
        # None and dimensionless is always fine
        e = myokit.Equal(myokit.Number(1), myokit.Number(2, d))
        self.assertEqual(e.eval_unit(), d)
        self.assertEqual(e.eval_unit(s), d)
        # Equal is always fine
        e = myokit.Equal(myokit.Number(1, d), myokit.Number(2, d))
        self.assertEqual(e.eval_unit(), d)
        self.assertEqual(e.eval_unit(s), d)
        a = myokit.units.ampere
        e = myokit.Equal(myokit.Number(1, a), myokit.Number(2, a))
        self.assertEqual(e.eval_unit(), d)
        self.assertEqual(e.eval_unit(s), d)
        # Unequal is never fine
        e = myokit.Equal(myokit.Number(1, d), myokit.Number(2, a))
        self.assertRaises(myokit.IncompatibleUnitError, e.eval_unit)
        self.assertRaises(myokit.IncompatibleUnitError, e.eval_unit, s)
        # One None one not-dimensionless is only fine in tolerant mode
        e = myokit.Equal(myokit.Number(1, a), myokit.Number(2))
        self.assertEqual(e.eval_unit(), d)
        self.assertRaises(myokit.IncompatibleUnitError, e.eval_unit, s)

    def test_tree_str(self):
        # Test Equal.tree_str().
        x = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '==\n  1\n  2\n')
        self.assertEqual(myokit.Not(x).tree_str(), 'not\n  ==\n    1\n    2\n')


class NotEqualTest(unittest.TestCase):
    """ Tests myokit.NotEqual. """

    def test_creation(self):
        # Operands must be numerical expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.NotEqual, 1, 1)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.NotEqual, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.NotEqual, myokit.Number(1), a)

    def test_eval(self):
        # Test NotEqual.eval().
        x = myokit.NotEqual(myokit.Number(1), myokit.Number(1))
        self.assertFalse(x.eval())
        x = myokit.NotEqual(myokit.Number(1), myokit.Number(2))
        self.assertTrue(x.eval())

    def test_tree_str(self):
        # Test NotEqual.tree_str().
        x = myokit.NotEqual(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '!=\n  1\n  2\n')
        self.assertEqual(myokit.Not(x).tree_str(),
                         'not\n  !=\n    1\n    2\n')


class MoreTest(unittest.TestCase):
    """ Tests myokit.More. """

    def test_creation(self):
        # Operands must be numerical expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.More, 1, 1)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.More, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.More, myokit.Number(1), a)

    def test_eval(self):
        # Test More.eval().
        x = myokit.More(myokit.Number(1), myokit.Number(1))
        self.assertFalse(x.eval())
        x = myokit.More(myokit.Number(3), myokit.Number(2))
        self.assertTrue(x.eval())

    def test_tree_str(self):
        # Test More.tree_str().
        x = myokit.More(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '>\n  1\n  2\n')
        self.assertEqual(myokit.Not(x).tree_str(), 'not\n  >\n    1\n    2\n')


class LessTest(unittest.TestCase):
    """ Tests myokit.Less. """

    def test_creation(self):
        # Operands must be expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Less, 1, 1)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.Less, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.Less, myokit.Number(1), a)

    def test_eval(self):
        # Test Less.eval().
        x = myokit.Less(myokit.Number(1), myokit.Number(1))
        self.assertFalse(x.eval())
        x = myokit.Less(myokit.Number(1), myokit.Number(2))
        self.assertTrue(x.eval())

    def test_tree_str(self):
        # Test Less.tree_str().
        x = myokit.Less(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '<\n  1\n  2\n')
        self.assertEqual(myokit.Not(x).tree_str(), 'not\n  <\n    1\n    2\n')


class MoreEqualTest(unittest.TestCase):
    """ Tests myokit.MoreEqual. """

    def test_creation(self):
        # Operands must be numerical expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.MoreEqual, 1, 1)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.MoreEqual, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.MoreEqual, myokit.Number(1), a)

    def test_eval(self):
        # Test MoreEqual.eval().
        x = myokit.MoreEqual(myokit.Number(1), myokit.Number(1))
        self.assertTrue(x.eval())
        x = myokit.MoreEqual(myokit.Number(3), myokit.Number(2))
        self.assertTrue(x.eval())
        x = myokit.MoreEqual(myokit.Number(1), myokit.Number(2))
        self.assertFalse(x.eval())

    def test_tree_str(self):
        # Test MoreEqual.tree_str().
        x = myokit.MoreEqual(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '>=\n  1\n  2\n')
        self.assertEqual(myokit.Not(x).tree_str(), 'not\n  >=\n    1\n    2\n')


class LessEqualTest(unittest.TestCase):
    """ Tests myokit.LessEqual. """

    def test_creation(self):
        # Operands must be numerical expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.LessEqual, 1, 1)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a numerical',
            myokit.LessEqual, a, myokit.Number(1))
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a numerical',
            myokit.LessEqual, myokit.Number(1), a)

    def test_eval(self):
        # Test LessEqual.eval().
        x = myokit.LessEqual(myokit.Number(1), myokit.Number(1))
        self.assertTrue(x.eval())
        x = myokit.LessEqual(myokit.Number(1), myokit.Number(2))
        self.assertTrue(x.eval())
        x = myokit.LessEqual(myokit.Number(2), myokit.Number(1))
        self.assertFalse(x.eval())

    def test_tree_str(self):
        # Test LessEqual.tree_str().
        x = myokit.LessEqual(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '<=\n  1\n  2\n')
        self.assertEqual(myokit.Not(x).tree_str(), 'not\n  <=\n    1\n    2\n')


class AndTest(unittest.TestCase):
    """ Tests myokit.And. """

    def test_creation(self):
        # Operands must be conditional expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.And, 1, 1)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a condition',
            myokit.And, myokit.Number(1), a)
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a condition',
            myokit.And, a, myokit.Number(1))

    def test_diff(self):
        # Tests And.diff()
        x1 = myokit.Equal(myokit.Number(1), myokit.Number(1))
        x2 = myokit.Equal(myokit.Number(2), myokit.Number(3))
        x = myokit.And(x1, x2)

        y = myokit.Model().add_component('c').add_variable('y')
        y.set_rhs('3')
        y = myokit.Name(y)
        self.assertRaises(NotImplementedError, x.diff, y)

    def test_eval(self):
        # Test And.eval().
        a = myokit.Equal(myokit.Number(2), myokit.Number(2))
        b = myokit.Equal(myokit.Number(3), myokit.Number(1))
        self.assertTrue(myokit.And(a, a).eval())
        self.assertFalse(myokit.And(a, b).eval())
        self.assertFalse(myokit.And(b, b).eval())

    def test_eval_unit(self):
        # Test And.eval_unit().

        # Test in tolerant mode: no own testing, but should test operands!
        e = myokit.parse_expression('1 == 1 and 2 == 2')
        self.assertEqual(e.eval_unit(), myokit.units.dimensionless)
        e = myokit.parse_expression('1 == 1 [1] and 2 [1] == 2')
        self.assertEqual(e.eval_unit(), myokit.units.dimensionless)
        e = myokit.parse_expression('1 [1] == 1 [1] and 2 [1] == 2 [1]')
        self.assertEqual(e.eval_unit(), myokit.units.dimensionless)
        e = myokit.parse_expression('1 [1] == 1 [1] and 2 [1] == 2 [mg]')
        self.assertRaises(myokit.IncompatibleUnitError, e.eval_unit)

        # Test in strict mode: no own testing, but should test operands!
        s = myokit.UNIT_STRICT
        e = myokit.parse_expression('1 == 1 and 2 == 2')
        self.assertEqual(e.eval_unit(s), myokit.units.dimensionless)
        e = myokit.parse_expression('1 == 1 [1] and 2 [1] == 2')
        self.assertEqual(e.eval_unit(s), myokit.units.dimensionless)
        e = myokit.parse_expression('1 [1] == 1 [1] and 2 [1] == 2 [1]')
        self.assertEqual(e.eval_unit(s), myokit.units.dimensionless)
        e = myokit.parse_expression('1 == 1 [V] and 1 == 1 [1]')
        self.assertRaises(myokit.IncompatibleUnitError, e.eval_unit, s)

    def test_tree_str(self):
        # Test And.tree_str().
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        b = myokit.Less(myokit.Number(4), myokit.Number(3))
        self.assertEqual(myokit.And(a, b).tree_str(),
                         'and\n  ==\n    1\n    2\n  <\n    4\n    3\n')
        self.assertEqual(
            myokit.Not(myokit.And(b, a)).tree_str(),
            'not\n  and\n    <\n      4\n      3\n    ==\n      1\n      2\n')


class OrTest(unittest.TestCase):
    """ Tests myokit.Or. """

    def test_creation(self):
        # Operands must be expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Or, 1, 1)
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand: expected a condition',
            myokit.Or, myokit.Number(1), a)
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand: expected a condition',
            myokit.Or, a, myokit.Number(1))

    def test_eval(self):
        # Test Or.eval().
        a = myokit.Equal(myokit.Number(2), myokit.Number(2))
        b = myokit.Equal(myokit.Number(3), myokit.Number(1))
        self.assertTrue(myokit.Or(a, a).eval())
        self.assertTrue(myokit.Or(a, b).eval())
        self.assertFalse(myokit.Or(b, b).eval())

    def test_eval_unit(self):
        # Test Or.eval_unit().

        # Test in tolerant mode: no own testing, but should test operands!
        e = myokit.parse_expression('1 == 1 or 2 == 2')
        self.assertEqual(e.eval_unit(), myokit.units.dimensionless)
        e = myokit.parse_expression('1 == 1 [1] or 2 [1] == 2')
        self.assertEqual(e.eval_unit(), myokit.units.dimensionless)
        e = myokit.parse_expression('1 [1] == 1 [1] or 2 [1] == 2 [1]')
        self.assertEqual(e.eval_unit(), myokit.units.dimensionless)
        e = myokit.parse_expression('1 [1] == 1 [1] or 2 [1] == 2 [mg]')
        self.assertRaises(myokit.IncompatibleUnitError, e.eval_unit)

        # Test in strict mode: no own testing, but should test operands!
        s = myokit.UNIT_STRICT
        e = myokit.parse_expression('1 == 1 or 2 == 2')
        self.assertEqual(e.eval_unit(s), myokit.units.dimensionless)
        e = myokit.parse_expression('1 == 1 [1] or 2 [1] == 2')
        self.assertEqual(e.eval_unit(s), myokit.units.dimensionless)
        e = myokit.parse_expression('1 [1] == 1 [1] or 2 [1] == 2 [1]')
        self.assertEqual(e.eval_unit(s), myokit.units.dimensionless)
        e = myokit.parse_expression('1 == 1 [A] or 2 [1] == 2 [1]')
        self.assertRaises(myokit.IncompatibleUnitError, e.eval_unit, s)

    def test_tree_str(self):
        # Test Or.tree_str().
        a = myokit.Equal(myokit.Number(1), myokit.Number(2))
        b = myokit.NotEqual(myokit.Number(3), myokit.Number(4))
        x = myokit.Or(a, b)
        self.assertEqual(
            x.tree_str(),
            'or\n  ==\n    1\n    2\n  !=\n    3\n    4\n')
        x = myokit.Not(x)
        self.assertEqual(
            x.tree_str(),
            'not\n  or\n    ==\n      1\n      2\n    !=\n      3\n      4\n')


class NotTest(unittest.TestCase):
    """ Tests myokit.Not. """

    def test_creation(self):
        # Operand must be an expression
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Not, 1)
        self.assertRaisesRegex(
            myokit.TypeError, 'expected a condition',
            myokit.Not, myokit.Number(1))

    def test_code(self):
        # Test Not.code().
        x = myokit.Not(myokit.Equal(myokit.Number(1), myokit.Number(1)))
        self.assertEqual(x.code(), 'not (1 == 1)')

    def test_diff(self):
        # Tests Not.diff()
        x = myokit.Not(myokit.Equal(myokit.Number(1), myokit.Number(1)))
        y = myokit.Model().add_component('c').add_variable('y')
        y.set_rhs('3')
        y = myokit.Name(y)
        self.assertRaises(NotImplementedError, x.diff, y)

    def test_eval(self):
        # Test Not.eval().
        x = myokit.Not(myokit.Equal(myokit.Number(1), myokit.Number(1)))
        self.assertFalse(x.eval())
        x = myokit.Not(myokit.Equal(myokit.Number(1), myokit.Number(0)))
        self.assertTrue(x.eval())

    def test_eval_unit(self):
        # Test Not.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x', rhs=1)
        y = c.add_variable('y', rhs=2)
        e = myokit.parse_expression('not (x != y)', context=c)

        # Test in tolerant mode
        self.assertEqual(e.eval_unit(), myokit.units.dimensionless)
        x.set_unit(myokit.units.ampere)
        y.set_unit(myokit.units.dimensionless)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'equal units on both', e.eval_unit)
        x.set_unit(myokit.units.dimensionless)
        self.assertEqual(e.eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(e.eval_unit(), myokit.units.dimensionless)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(e.eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'equal units on bot', e.eval_unit, s)
        x.set_unit(myokit.units.dimensionless)
        self.assertEqual(e.eval_unit(s), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(e.eval_unit(s), myokit.units.dimensionless)

    def test_polish(self):
        # Test Not._polish().
        x = myokit.Not(myokit.Equal(myokit.Number(1), myokit.Number(1)))
        self.assertEqual(x._polish(), 'not == 1 1')


class IfTest(unittest.TestCase):
    """ Tests myokit.If. """

    def test_creation(self):
        # Test creation plus some accessor methods.

        cond = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then = myokit.Number(10)
        else_ = myokit.Number(20)
        if_ = myokit.If(cond, then, else_)

        # Test condition()
        self.assertEqual(if_.condition(), cond)

        # Test is_conditional()
        self.assertTrue(if_.is_conditional())

        # Operands must be expressions and have right types
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.If, 1, 1, 1)
        self.assertRaisesRegex(
            myokit.TypeError, 'first operand', myokit.If, then, then, then)
        self.assertRaisesRegex(
            myokit.TypeError, 'second operand', myokit.If, cond, cond, then)
        self.assertRaisesRegex(
            myokit.TypeError, 'third operand', myokit.If, cond, then, cond)

    def test_diff(self):
        # Tests If.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')

        V.set_rhs('if(1 == 1, ina.I1, 7 [pA])')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'if(1 == 1, diff(ina.I1, ina.g), 0 [mV])')
        V.set_rhs('if(1 == 1, 7 [pA], ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(), 'if(1 == 1, 0 [mV], diff(ina.I1, ina.g))')
        V.set_rhs('if(1 == 1, 2 * ina.I1, ina.I2)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'if(1 == 1, 2 * diff(ina.I1, ina.g), '
            'diff(ina.I2, ina.g))')
        V.set_rhs('if(1 == 1, 4 [mV/ms], 7 [mV/ms])')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.parse_unit('mV/ms/nS'))

    def test_eval(self):
        # Test If.eval().

        cond = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then = myokit.Number(10)
        else_ = myokit.Number(20)
        if_ = myokit.If(cond, then, else_)
        self.assertEqual(if_.eval(), 10)

        cond = myokit.Equal(myokit.Number(1), myokit.Number(2))
        if_ = myokit.If(cond, then, else_)
        self.assertEqual(if_.eval(), 20)

    def test_eval_unit(self):
        # Test If.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        v2 = c.add_variable('v2')
        v3 = c.add_variable('v3')
        v4 = c.add_variable('v4')
        v2.set_rhs(2)
        v3.set_rhs(3)
        v4.set_rhs('if(1 == 1, v2, v3)')
        z = v4.rhs()

        # Test in tolerant mode
        self.assertEqual(z.eval_unit(), None)
        v2.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        v3.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        v2.set_unit(None)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        v3.set_unit(None)
        self.assertEqual(z.eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.eval_unit(s), myokit.units.dimensionless)
        v2.set_unit(myokit.units.ampere)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        v3.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(s), myokit.units.ampere)
        v2.set_unit(None)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        v3.set_unit(None)
        self.assertEqual(z.eval_unit(s), myokit.units.dimensionless)

    def test_piecewise_conversion(self):
        # Test If.piecewise().
        cond = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then = myokit.Number(10)
        else_ = myokit.Number(20)
        if_ = myokit.If(cond, then, else_)
        pw = if_.piecewise()
        self.assertEqual(if_.eval(), pw.eval())

        cond = myokit.Equal(myokit.Number(1), myokit.Number(2))
        if_ = myokit.If(cond, then, else_)
        pw = if_.piecewise()
        self.assertEqual(if_.eval(), pw.eval())

    def test_value(self):
        # Test If.value().
        cond = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then = myokit.Number(10)
        else_ = myokit.Number(20)
        if_ = myokit.If(cond, then, else_)
        self.assertEqual(if_.value(True), then)
        self.assertEqual(if_.value(False), else_)


class PiecewiseTest(unittest.TestCase):
    """Tests myokit.Piecewise."""

    def test_creation(self):
        # Test Piecewise creation plus some accessor methods.

        # Like an if
        cond1 = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then1 = myokit.Number(10)
        final = myokit.Number(99)
        pw = myokit.Piecewise(cond1, then1, final)

        # Test is_conditional()
        self.assertTrue(pw.is_conditional())

        # Test conditions()
        c = list(pw.conditions())
        self.assertEqual(len(c), 1)
        self.assertEqual(c[0], cond1)

        # Test pieces()
        p = list(pw.pieces())
        self.assertEqual(len(p), 2)
        self.assertEqual(p[0], then1)
        self.assertEqual(p[1], final)

        # Like a big if
        cond1 = myokit.Equal(myokit.Number(2), myokit.Number(1))
        then1 = myokit.Number(1)
        cond2 = myokit.Equal(myokit.Number(3), myokit.Number(1))
        then2 = myokit.Number(2)
        cond3 = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then3 = myokit.Number(3)
        final = myokit.Number(99)
        pw = myokit.Piecewise(cond1, then1, cond2, then2, cond3, then3, final)

        # Test conditions()
        c = list(pw.conditions())
        self.assertEqual(len(c), 3)
        self.assertEqual(c[0], cond1)
        self.assertEqual(c[1], cond2)
        self.assertEqual(c[2], cond3)

        # Test pieces()
        p = list(pw.pieces())
        self.assertEqual(len(p), 4)
        self.assertEqual(p[0], then1)
        self.assertEqual(p[1], then2)
        self.assertEqual(p[2], then3)
        self.assertEqual(p[3], final)

        # Wrong number of operands
        self.assertRaisesRegex(
            myokit.IntegrityError, 'odd number', myokit.Piecewise,
            cond1, then1)
        self.assertRaisesRegex(
            myokit.IntegrityError, 'odd number', myokit.Piecewise,
            cond1, then1, cond2, then2)

        # Wrong number of operands
        self.assertRaisesRegex(
            myokit.IntegrityError, '3 or more', myokit.Piecewise, cond1)

        # Operands must be expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be other Express',
                               myokit.Piecewise, 1, 1, 1)

        # Operands must have right types
        self.assertRaisesRegex(
            myokit.TypeError, 'operand at index 0 must be a condition',
            myokit.Piecewise, then1, then2, then3)
        self.assertRaisesRegex(
            myokit.TypeError, 'operand at index 1 must be numerical',
            myokit.Piecewise, cond1, cond1, then1)
        self.assertRaisesRegex(
            myokit.TypeError, 'operand at index 2 must be numerical',
            myokit.Piecewise, cond1, then1, cond2)
        self.assertRaisesRegex(
            myokit.TypeError, 'operand at index 2 must be a condition',
            myokit.Piecewise, cond1, then1, then2, then3, then1)
        self.assertRaisesRegex(
            myokit.TypeError, 'operand at index 3 must be numerical',
            myokit.Piecewise, cond1, then1, cond2, cond3, then2)
        self.assertRaisesRegex(
            myokit.TypeError, 'operand at index 4 must be numerical',
            myokit.Piecewise, cond1, then1, cond2, then2, cond3)

    def test_diff(self):
        # Tests Piecewise.diff()

        m = pd_model.clone()
        V = m.get('membrane.V')
        g = m.get('ina.g')

        V.set_rhs('piecewise(1 == 1, ina.I1, 2 == 2, 3 [pA], 7 [pA])')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'piecewise('
            '1 == 1, diff(ina.I1, ina.g), '
            '2 == 2, 0 [mV], '
            '0 [mV])')
        V.set_rhs('piecewise(1 == 1, 7 [pA], 2 == 2, 3 [pA], ina.I1)')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'piecewise('
            '1 == 1, 0 [mV], '
            '2 == 2, 0 [mV], '
            'diff(ina.I1, ina.g))')
        V.set_rhs('piecewise(1 == 1, 2 * ina.I1, 2 == 2, ina.I1, 3 [pA])')
        p = V.rhs().diff(g.lhs())
        self.assertEqual(
            p.code(),
            'piecewise('
            '1 == 1, 2 * diff(ina.I1, ina.g), '
            '2 == 2, diff(ina.I1, ina.g), '
            '0 [mV])')
        V.set_rhs('piecewise(1 == 1, 4 [mV/ms], 7 [mV/ms])')
        p = V.rhs().diff(g.lhs())
        self.assertTrue(p.is_number(0))
        self.assertEqual(p.unit(), myokit.parse_unit('mV/ms/nS'))

    def test_eval(self):
        # Test Piecewise.eval().
        ct = myokit.Equal(myokit.Number(1), myokit.Number(1))
        cf = myokit.Equal(myokit.Number(1), myokit.Number(2))
        then1 = myokit.Number(1)
        then2 = myokit.Number(2)
        then3 = myokit.Number(3)
        final = myokit.Number(99)

        pw = myokit.Piecewise(cf, then1, cf, then2, cf, then3, final)
        self.assertEqual(pw.eval(), 99)
        pw = myokit.Piecewise(cf, then1, cf, then2, ct, then3, final)
        self.assertEqual(pw.eval(), 3)
        pw = myokit.Piecewise(cf, then1, ct, then2, ct, then3, final)
        self.assertEqual(pw.eval(), 2)
        pw = myokit.Piecewise(ct, then1, ct, then2, ct, then3, final)
        self.assertEqual(pw.eval(), 1)
        pw = myokit.Piecewise(ct, then1, cf, then2, ct, then3, final)
        self.assertEqual(pw.eval(), 1)
        pw = myokit.Piecewise(ct, then1, ct, then2, cf, then3, final)
        self.assertEqual(pw.eval(), 1)
        pw = myokit.Piecewise(ct, then1, cf, then2, cf, then3, final)
        self.assertEqual(pw.eval(), 1)
        pw = myokit.Piecewise(cf, then1, cf, then2, cf, then3, final)
        self.assertEqual(pw.eval(), 99)

    def test_eval_unit(self):
        # Test Piecewise.eval_unit().
        # Mini model
        m = myokit.Model()
        comp = m.add_component('comp')
        t1 = comp.add_variable('t1', rhs=1)
        t2 = comp.add_variable('t2', rhs=2)
        t3 = comp.add_variable('t3', rhs=3)

        # Create piecewise
        pw = comp.add_variable('pw')
        pw.set_rhs('piecewise(1 == 2, t1, 1 == 2, t2, t3)')
        z = pw.rhs()

        # Test in tolerant mode
        self.assertEqual(z.eval_unit(), None)
        t1.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t2.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t3.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t1.set_unit(None)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t2.set_unit(None)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t3.set_unit(None)
        self.assertEqual(z.eval_unit(), None)
        t2.set_unit(myokit.units.Newton)
        t3.set_unit(myokit.units.volt)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit)
        t1.set_unit(None)
        t2.set_unit(None)
        t3.set_unit(None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.eval_unit(s), myokit.units.dimensionless)
        t1.set_unit(myokit.units.ampere)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        t2.set_unit(myokit.units.ampere)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        t3.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(s), myokit.units.ampere)
        t1.set_unit(None)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        t2.set_unit(None)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        t3.set_unit(None)
        self.assertEqual(z.eval_unit(s), myokit.units.dimensionless)
        t2.set_unit(myokit.units.Newton)
        t3.set_unit(myokit.units.volt)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)


class EquationTest(unittest.TestCase):
    """
    Tests :class:`myokit.Equation` (which is not strictly speaking a part of
    the equation system).
    """

    def test_clone(self):
        # Test equation cloning
        eq1 = myokit.Equation(myokit.Name('x'), myokit.Name('y'))
        eq2 = myokit.Equation(myokit.Name('y'), myokit.Name('x'))
        self.assertEqual(eq1.clone(), eq1)
        self.assertEqual(eq1, eq2.clone(subst={
            myokit.Name('x'): myokit.Name('y'),
            myokit.Name('y'): myokit.Name('x'),
        }))

    def test_code(self):
        # Test :meth:`Equation.code()`.
        eq = myokit.Equation(myokit.Name('x'), myokit.Number('3'))
        self.assertEqual(eq.code(), 'str:x = 3')
        self.assertEqual(eq.code(), str(eq))

    def test_creation(self):
        # Test creation of equations.
        lhs = myokit.Name('x')
        rhs = myokit.Number('3')
        myokit.Equation(lhs, rhs)

        # Operands must be expressions
        # Operands must be expressions
        self.assertRaisesRegex(myokit.IntegrityError, 'must be myokit.Expres',
                               myokit.Equation, 1.2, 3.4)
        self.assertRaisesRegex(myokit.IntegrityError, 'must be myokit.Express',
                               myokit.Equation, myokit.Number(3), 1.2)

    def test_eq(self):
        # Test equality checking.
        eq1 = myokit.Equation(myokit.Name('x'), myokit.Number('3'))
        eq2 = myokit.Equation(myokit.Name('x'), myokit.Number('3'))
        self.assertEqual(eq1, eq2)
        self.assertEqual(eq2, eq1)
        self.assertFalse(eq1 != eq2)

        eq2 = myokit.Equation(myokit.Name('x'), myokit.Number('4'))
        self.assertNotEqual(eq1, eq2)
        self.assertNotEqual(eq2, eq1)
        self.assertTrue(eq1 != eq2)

        eq2 = myokit.Equation(myokit.Name('y'), myokit.Number('3'))
        self.assertNotEqual(eq1, eq2)
        self.assertNotEqual(eq2, eq1)

        eq2 = myokit.Equal(myokit.Name('x'), myokit.Number('3'))
        self.assertNotEqual(eq1, eq2)
        self.assertNotEqual(eq2, eq1)

        eq2 = 'hi'
        self.assertNotEqual(eq1, eq2)
        self.assertNotEqual(eq2, eq1)

    def test_hash(self):
        # Test that equations can be hashed.
        # No exception = pass
        hash(myokit.Equation(myokit.Name('x'), myokit.Number('3')))

        # Hash must be consistent during lifetime.
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('3 * sqrt(2)')
        a = hash(x.eq())
        x.rename('y')
        b = hash(x.eq())
        self.assertEqual(a, b)

    def test_iter(self):
        # Test iteration over an equation.
        lhs = myokit.Name('x')
        rhs = myokit.Number('3')
        eq = myokit.Equation(lhs, rhs)
        i = iter(eq)
        self.assertEqual(next(i), lhs)
        self.assertEqual(next(i), rhs)
        self.assertEqual(len(list(eq)), 2)

    def test_str_and_repr(self):
        # Test string conversion
        x = myokit.Model('m').add_component('c').add_variable('x')
        eq1 = myokit.Equation(myokit.Name(x), myokit.Number('3'))
        self.assertEqual(str(eq1), 'c.x = 3')
        self.assertEqual(repr(eq1), '<Equation c.x = 3>')


if __name__ == '__main__':
    unittest.main()
