Beispiel #1
0
 def remove_with_alias(self):
     """
     Tests cloning after an add / remove event.
     """
     m = Model('AddRemoveClone')
     c = m.add_component('c')
     p = c.add_variable('p')
     p.set_binding('time')
     p.set_rhs(0)
     q = c.add_variable('q')
     q.set_rhs(12)
     m.validate()  # Raises error if not ok
     m.clone()  # Raises error if not ok
     d = m.add_component('d')
     d.add_alias('bert', p)
     e = d.add_variable('e')
     e.set_rhs('10 * bert')
     m.validate()
     m.clone()
     d.add_alias('ernie', q)
     m.validate()
     m.clone()
     c.remove_variable(q)
     m.validate()
     m.clone()  # Will raise error if alias isn't deleted
Beispiel #2
0
 def unused_and_cycles(self):
     """
     Test unused variable and cycle detection.
     """
     m = Model('LotkaVolterra')
     c0 = m.add_component('c0')
     t = c0.add_variable('time')
     t.set_rhs(Number(0))
     t.set_binding('time')
     c1 = m.add_component('c1')
     m.add_component('c2')
     c1_a = c1.add_variable('a')
     c1_b = c1.add_variable('b')
     c1_a.promote(1.0)
     c1_a.set_rhs(Multiply(Name(c1_a), Number(0.5)))
     c1_b.set_rhs(Multiply(Name(c1_a), Number(1.0)))
     # b is unused, test if found
     m.validate()
     w = m.warnings()
     self.assertEqual(len(w), 1)
     self.assertEqual(type(w[0]), UnusedVariableError)
     # b is used by c, c is unused, test if found
     c1_c = c1.add_variable('c')
     c1_c.set_rhs(Name(c1_b))
     m.validate()
     w = m.warnings()
     self.assertEqual(len(w), 2)
     self.assertEqual(type(w[0]), UnusedVariableError)
     self.assertEqual(type(w[1]), UnusedVariableError)
     # Test 1:1 cycle
     c1_b.set_rhs(Name(c1_b))
     self.assertRaises(CyclicalDependencyError, m.validate)
     # Test longer cycles
     c1_b.set_rhs(Multiply(Number(10), Name(c1_c)))
     self.assertRaises(CyclicalDependencyError, m.validate)
     # Reset
     c1_b.set_rhs(Multiply(Name(c1_a), Number(1.0)))
     m.validate()
     # Test cycle involving state variable
     c1_a.set_rhs(Name(c1_b))
     m.validate()
     c1_b.set_rhs(Multiply(Name(c1_a), Name(c1_b)))
     self.assertRaises(CyclicalDependencyError, m.validate)
     c1_b.set_rhs(Multiply(Name(c1_a), Name(c1_c)))
     c1_c.set_rhs(Multiply(Name(c1_a), Number(3)))
     m.validate()
     w = m.warnings()
     self.assertEqual(len(w), 0)
     c1_c.set_rhs(Multiply(Name(c1_a), Name(c1_b)))
     self.assertRaises(CyclicalDependencyError, m.validate)
Beispiel #3
0
 def scope(self):
     """
     Tests if illegal references are detected.
     """
     m = Model('Scope')
     c = m.add_component('c')
     p = c.add_variable('p')
     q = p.add_variable('q')
     p.set_rhs('10 + q')
     q.set_rhs('18 / 2.4')
     d = m.add_component('d')
     r = d.add_variable('r')
     r.set_rhs(Name(q))
     self.assertRaises(IllegalReferenceError, r.validate)
Beispiel #4
0
 def expressions_between(self):
     """
     Tests the ``expressions_between`` method.
     """
     m = Model('test')
     x = m.add_component('membrane')
     t = x.add_variable('time')
     t.set_rhs(0)
     t.set_binding('time')
     a = x.add_variable('a')
     a.set_rhs(12)
     b = x.add_variable('b')
     b.set_rhs('3 * a')
     c = x.add_variable('c')
     c.set_rhs('a + b')
     d = x.add_variable('d')
     d.set_rhs('a * c')
     e = x.add_variable('e')
     e.set_rhs('sqrt(d) * b + 3*c')
     f = x.add_variable('f')
     f.set_rhs('exp(e - 10)')
     g = x.add_variable('g')
     g.set_rhs('3 * e + 4 * f')
     h = x.add_variable('h')
     h.set_rhs('f + cos(g)')
     i = x.add_variable('i')
     i.promote(0.43)
     i.set_rhs('1 + h')
     m.validate()
     eqs = m.expressions_between(a, i)
     self.assertEqual(len(eqs), 9)
     for k, v in enumerate([a, b, c, d, e, f, g, h, i]):
         self.assertEqual(v.lhs(), eqs[k].lhs)
         self.assertEqual(v.rhs(), eqs[k].rhs)
Beispiel #5
0
 def no_time_variable(self):
     """
     Tests an exception is raised if nothing is bound to time.
     """
     m = Model('LotkaVolterra')
     c0 = m.add_component('c0')
     t = c0.add_variable('time')
     t.set_rhs(Number(0))
     self.assertRaises(MissingTimeVariableError, m.validate)
Beispiel #6
0
 def remove_component(self):
     """
     Tests the removal of a component.
     """
     # Create model
     m = Model('LotkaVolterra')
     # Simplest case
     X = m.add_component('X')
     self.assertEqual(m.count_components(), 1)
     m.remove_component(X)
     self.assertEqual(m.count_components(), 0)
     self.assertRaises(KeyError, m.remove_component, X)
     # Test if orphaned
     self.assertIsNone(X.parent())
     # Re-adding
     self.assertEqual(m.count_components(), 0)
     X = m.add_component('X')
     self.assertEqual(m.count_components(), 1)
     # With internal variables
     a = X.add_variable('a')
     a.set_rhs(Number(4))
     b = X.add_variable('b')
     b.set_rhs(Name(a))
     m.remove_component(X)
     self.assertEqual(m.count_components(), 0)
     # With dependencies from another component
     X = m.add_component('X')
     a = X.add_variable('a')
     a.set_rhs(Number(45))
     b = X.add_variable('b')
     b.set_rhs(Name(b))
     Y = m.add_component('Y')
     c = Y.add_variable('c')
     c.set_rhs(Name(a))
     d = Y.add_variable('d')
     d.set_rhs(Name(c))
     self.assertEqual(m.count_components(), 2)
     self.assertRaises(IntegrityError, m.remove_component, X)
     self.assertEqual(m.count_components(), 2)
     # In the right order...
     m.remove_component(Y)
     self.assertEqual(m.count_components(), 1)
     m.remove_component(X)
     self.assertEqual(m.count_components(), 0)
Beispiel #7
0
 def resolve(self):
     """
     Tests if an error is raised when a variable can't be resolved.
     """
     m = Model('Resolve')
     c = m.add_component('c')
     p = c.add_variable('p')
     q = c.add_variable('q')
     p.set_rhs('10 * q')
     self.assertRaises(ParseError, q.set_rhs, '10 * r')
Beispiel #8
0
 def move_variable(self):
     """
     Tests the method to move component variables to another component.
     """
     # Create a model
     m = Model('LotkaVolterra')
     X = m.add_component('X')
     a = X.add_variable('a')
     a.set_rhs(3)
     b = X.add_variable('b')
     b1 = b.add_variable('b1')
     b2 = b.add_variable('b2')
     b1.set_rhs(1)
     b2.set_rhs(Minus(Minus(Name(a), Name(b1)), Number(1)))
     b.set_rhs(Plus(Name(b1), Name(b2)))
     x = X.add_variable('x')
     x.promote()
     Y = m.add_component('Y')
     c = Y.add_variable('c')
     c.set_rhs(Minus(Name(a), Number(1)))
     d = Y.add_variable('d')
     d.set_rhs(2)
     y = Y.add_variable('y')
     y.promote()
     x.set_rhs(
         Minus(Multiply(Name(a), Name(x)),
               Multiply(Multiply(Name(b), Name(x)), Name(y))))
     x.set_state_value(10)
     y.set_rhs(
         Plus(Multiply(PrefixMinus(Name(c)), Name(y)),
              Multiply(Multiply(Name(d), Name(x)), Name(y))))
     y.set_state_value(5)
     Z = m.add_component('Z')
     t = Z.add_variable('total')
     t.set_rhs(Plus(Name(x), Name(y)))
     E = m.add_component('engine')
     time = E.add_variable('time')
     time.set_rhs(0)
     time.set_binding('time')
     # Move time variable into X
     m.validate()  # If not valid, this will raise an exception
     E.move_variable(time, Z)
     m.validate()
Beispiel #9
0
 def invalid_names(self):
     """
     Tests if invalid or duplicate names are detected.
     """
     m = Model('Duplicates')
     c0 = m.add_component('c0')
     t = c0.add_variable('time')
     t.set_rhs(Number(0))
     t.set_binding('time')
     self.assertRaises(DuplicateName, m.add_component, 'c0')
     self.assertRaises(InvalidNameError, m.add_component, '0')
     self.assertRaises(InvalidNameError, m.add_component, '_0')
     self.assertRaises(InvalidNameError, m.add_component, '123abvc')
     self.assertRaises(InvalidNameError, m.add_component, 'ab cd')
     self.assertRaises(InvalidNameError, m.add_component, 'ab.cd')
     self.assertRaises(InvalidNameError, m.add_component, 'ab!cd')
     self.assertRaises(InvalidNameError, m.add_component, '5*x')
     c1 = m.add_component('c1')
     self.assertRaises(InvalidNameError, c0.add_variable, '0')
     self.assertRaises(InvalidNameError, c0.add_variable, '_aap')
     self.assertRaises(InvalidNameError, c0.add_variable, '123abvc')
     self.assertRaises(InvalidNameError, c0.add_variable, 'ab cd')
     self.assertRaises(InvalidNameError, c0.add_variable, 'ab.cd')
     self.assertRaises(InvalidNameError, c0.add_variable, 'ab!cd')
     self.assertRaises(InvalidNameError, c0.add_variable, '5*x')
     v1 = c0.add_variable('c0')
     self.assertRaises(InvalidNameError, v1.add_variable, '0')
     self.assertRaises(InvalidNameError, v1.add_variable, '_aap')
     self.assertRaises(InvalidNameError, v1.add_variable, '123abvc')
     self.assertRaises(InvalidNameError, v1.add_variable, 'ab cd')
     self.assertRaises(InvalidNameError, v1.add_variable, 'ab.cd')
     self.assertRaises(InvalidNameError, v1.add_variable, 'ab!cd')
     self.assertRaises(InvalidNameError, v1.add_variable, '5*x')
     v2 = c1.add_variable('c0')
     self.assertRaises(DuplicateName, c1.add_variable, 'c0')
     self.assertRaises(DuplicateName, v1.add_variable, 'c0')
     self.assertRaises(DuplicateName, v2.add_variable, 'c0')
Beispiel #10
0
 def no_rhs(self):
     """
     Tests an exception is raised when a variable is missing an rhs.
     """
     m = Model('LotkaVolterra')
     c0 = m.add_component('c0')
     t = c0.add_variable('time')
     t.set_binding('time')
     self.assertRaises(MissingRhsError, m.validate)
     t.set_rhs(Number(0))
     m.validate()
     a = c0.add_variable('test')
     self.assertRaises(MissingRhsError, m.validate)
     a.set_rhs(Number(1))
     m.validate()
     b = c0.add_variable('derv')
     b.promote(10)
     self.assertRaises(MissingRhsError, m.validate)
     b.set_rhs(2)
     m.validate()
Beispiel #11
0
    def model_creation(self):
        # Create a model
        m = Model('LotkaVolterra')

        # Add the first component
        X = m.add_component('X')
        self.assertEqual(X.qname(), 'X')
        self.assertEqual(X.parent(), m)
        self.assertIsInstance(X, Component)
        self.assertIn(X.qname(), m)
        self.assertEqual(len(m), 1)

        # Add variable a
        a = X.add_variable('a')
        self.assertEqual(a, a)
        self.assertIsInstance(a, Variable)
        self.assertEqual(len(X), 1)
        self.assertIn(a.name(), X)
        a.set_rhs(3)
        self.assertFalse(a.is_state())
        self.assertFalse(a.is_intermediary())
        self.assertTrue(a.is_constant())
        self.assertEqual(a.lhs(), Name(a))
        self.assertEqual(a.rhs(), Number(3))
        self.assertEqual(a.rhs().eval(), 3)
        self.assertEqual(a.code(), 'a = 3\n')
        self.assertEqual(a.eq().code(), 'X.a = 3')
        self.assertEqual(a.lhs().code(), 'X.a')
        self.assertEqual(a.rhs().code(), '3')
        self.assertEqual(a.eq(), Equation(Name(a), Number(3)))

        # Check lhs
        a_name1 = myokit.Name(a)
        a_name2 = myokit.Name(a)
        self.assertEqual(a_name1, a_name1)
        self.assertEqual(a_name2, a_name2)
        self.assertEqual(a_name1, a_name2)
        self.assertEqual(a_name2, a_name1)

        # Add variable b with two temporary variables
        b = X.add_variable('b')
        self.assertIsInstance(b, Variable)
        self.assertEqual(len(X), 2)
        self.assertIn(b.name(), X)
        b1 = b.add_variable('b1')
        self.assertEqual(len(b), 1)
        self.assertIn(b1.name(), b)
        self.assertIsInstance(b1, Variable)
        b2 = b.add_variable('b2')
        self.assertEqual(len(b), 2)
        self.assertIn(b2.name(), b)
        self.assertIsInstance(b2, Variable)
        b1.set_rhs(1)
        b2.set_rhs(Minus(Minus(Name(a), Name(b1)), Number(1)))
        b.set_rhs(Plus(Name(b1), Name(b2)))
        self.assertEqual(b.rhs().eval(), 2)
        self.assertFalse(b.is_state())
        self.assertFalse(b.is_intermediary())
        self.assertTrue(b.is_constant())
        self.assertEqual(b.lhs(), Name(b))

        # Add state variable x
        x = X.add_variable('x')
        x.set_rhs(10)
        x.promote()
        self.assertNotEqual(x, X)
        self.assertIsInstance(x, Variable)
        self.assertEqual(len(X), 3)
        self.assertIn(x.name(), X)
        self.assertTrue(x.is_state())
        self.assertFalse(x.is_intermediary())
        self.assertFalse(x.is_constant())
        self.assertEqual(x.lhs(), Derivative(Name(x)))

        # Test demoting, promoting
        x.demote()
        self.assertFalse(x.is_state())
        self.assertFalse(x.is_intermediary())
        self.assertTrue(x.is_constant())
        self.assertEqual(x.lhs(), Name(x))
        x.promote()
        self.assertTrue(x.is_state())
        self.assertFalse(x.is_intermediary())
        self.assertFalse(x.is_constant())
        self.assertEqual(x.lhs(), Derivative(Name(x)))
        x.demote()
        x.promote()
        x.demote()
        x.promote()
        self.assertTrue(x.is_state())
        self.assertFalse(x.is_intermediary())
        self.assertFalse(x.is_constant())
        self.assertEqual(x.lhs(), Derivative(Name(x)))

        # Add second component, variables
        Y = m.add_component('Y')
        self.assertNotEqual(X, Y)
        self.assertEqual(len(m), 2)
        c = Y.add_variable('c')
        c.set_rhs(Minus(Name(a), Number(1)))
        d = Y.add_variable('d')
        d.set_rhs(2)
        y = Y.add_variable('y')
        y.promote()

        # Set rhs for x and y
        x.set_rhs(
            Minus(Multiply(Name(a), Name(x)),
                  Multiply(Multiply(Name(b), Name(x)), Name(y))))
        x.set_state_value(10)
        self.assertEqual(x.rhs().code(), 'X.a * X.x - X.b * X.x * Y.y')
        y.set_rhs(
            Plus(Multiply(PrefixMinus(Name(c)), Name(y)),
                 Multiply(Multiply(Name(d), Name(x)), Name(y))))
        y.set_state_value(5)
        self.assertEqual(y.rhs().code(), '-Y.c * Y.y + Y.d * X.x * Y.y')

        # Add another component, variables
        Z = m.add_component('Z')
        self.assertNotEqual(X, Z)
        self.assertNotEqual(Y, Z)
        self.assertEqual(len(m), 3)
        t = Z.add_variable('total')
        self.assertEqual(t.name(), 'total')
        self.assertEqual(t.qname(), 'Z.total')
        self.assertEqual(t.qname(X), 'Z.total')
        self.assertEqual(t.qname(Z), 'total')
        t.set_rhs(Plus(Name(x), Name(y)))
        self.assertFalse(t.is_state())
        self.assertFalse(t.is_constant())
        self.assertTrue(t.is_intermediary())
        self.assertEqual(t.rhs().code(), 'X.x + Y.y')
        self.assertEqual(t.rhs().code(X), 'x + Y.y')
        self.assertEqual(t.rhs().code(Y), 'X.x + y')
        self.assertEqual(t.rhs().code(Z), 'X.x + Y.y')

        # Add engine component
        E = m.add_component('engine')
        self.assertNotEqual(X, E)
        self.assertNotEqual(Y, E)
        self.assertNotEqual(Z, E)
        self.assertEqual(len(m), 4)
        time = E.add_variable('time')
        time.set_rhs(0)
        self.assertIsNone(time.binding())
        time.set_binding('time')
        self.assertIsNotNone(time.binding())

        # Check state
        state = [i for i in m.states()]
        self.assertEqual(len(state), 2)
        self.assertIn(x, state)
        self.assertIn(y, state)

        # Test variable iterators
        def has(*v):
            for var in v:
                self.assertIn(var, vrs)
            self.assertEqual(len(vrs), len(v))

        vrs = [i for i in m.variables()]
        has(a, b, c, d, x, y, t, time)
        vrs = [i for i in m.variables(deep=True)]
        has(a, b, c, d, x, y, t, b1, b2, time)
        vrs = [i for i in m.variables(const=True)]
        has(a, b, c, d)
        vrs = [i for i in m.variables(const=True, deep=True)]
        has(a, b, c, d, b1, b2)
        vrs = [i for i in m.variables(const=False)]
        has(x, y, t, time)
        vrs = [i for i in m.variables(const=False, deep=True)]
        has(x, y, t, time)
        vrs = [i for i in m.variables(state=True)]
        has(x, y)
        vrs = [i for i in m.variables(state=True, deep=True)]
        has(x, y)
        vrs = [i for i in m.variables(state=False)]
        has(a, b, c, d, t, time)
        vrs = [i for i in m.variables(state=False, deep=True)]
        has(a, b, c, d, t, b1, b2, time)
        vrs = [i for i in m.variables(inter=True)]
        has(t)
        vrs = [i for i in m.variables(inter=True, deep=True)]
        has(t)
        vrs = [i for i in m.variables(inter=False)]
        has(a, b, c, d, x, y, time)
        vrs = [i for i in m.variables(inter=False, deep=True)]
        has(a, b, c, d, x, y, b1, b2, time)
        vrs = [i for i in m.variables(const=True, state=True)]
        has()
        vrs = [i for i in m.variables(const=True, state=False)]
        has(a, b, c, d)

        # Test equation iteration
        eq = [eq for eq in X.equations(deep=False)]
        self.assertEqual(len(eq), 3)
        eq = [eq for eq in X.equations(deep=True)]
        self.assertEqual(len(eq), 5)
        eq = [eq for eq in Y.equations(deep=False)]
        self.assertEqual(len(eq), 3)
        eq = [eq for eq in Y.equations(deep=True)]
        self.assertEqual(len(eq), 3)
        eq = [eq for eq in Z.equations(deep=False)]
        self.assertEqual(len(eq), 1)
        eq = [eq for eq in Z.equations(deep=True)]
        self.assertEqual(len(eq), 1)
        eq = [eq for eq in E.equations(deep=False)]
        self.assertEqual(len(eq), 1)
        eq = [eq for eq in E.equations(deep=True)]
        self.assertEqual(len(eq), 1)
        eq = [eq for eq in m.equations(deep=False)]
        self.assertEqual(len(eq), 8)
        eq = [eq for eq in m.equations(deep=True)]
        self.assertEqual(len(eq), 10)

        # Test dependency mapping
        def has(var, *dps):
            lst = vrs[m.get(var).lhs() if type(var) == str else var]
            self.assertEqual(len(lst), len(dps))
            for d in dps:
                d = m.get(d).lhs() if type(d) == str else d
                self.assertIn(d, lst)

        vrs = m.map_shallow_dependencies(omit_states=False)
        self.assertEqual(len(vrs), 12)
        has('X.a')
        has('X.b', 'X.b.b1', 'X.b.b2')
        has('X.b.b1')
        has('X.b.b2', 'X.a', 'X.b.b1')
        has('X.x', 'X.a', 'X.b', Name(x), Name(y))
        has(Name(x))
        has('Y.c', 'X.a')
        has('Y.d')
        has('Y.y', 'Y.c', 'Y.d', Name(x), Name(y))
        has(Name(y))
        has('Z.total', Name(x), Name(y))
        vrs = m.map_shallow_dependencies()
        self.assertEqual(len(vrs), 10)
        has('X.a')
        has('X.b', 'X.b.b1', 'X.b.b2')
        has('X.b.b1')
        has('X.b.b2', 'X.a', 'X.b.b1')
        has('X.x', 'X.a', 'X.b')
        has('Y.c', 'X.a')
        has('Y.d')
        has('Y.y', 'Y.c', 'Y.d')
        has('Z.total')
        vrs = m.map_shallow_dependencies(collapse=True)
        self.assertEqual(len(vrs), 8)
        has('X.a')
        has('X.b', 'X.a')
        has('X.x', 'X.a', 'X.b')
        has('Y.c', 'X.a')
        has('Y.d')
        has('Y.y', 'Y.c', 'Y.d')
        has('Z.total')
        # Validate
        m.validate()
        # Get solvable order
        order = m.solvable_order()
        self.assertEqual(len(order), 5)
        self.assertIn('*remaining*', order)
        self.assertIn('X', order)
        self.assertIn('Y', order)
        self.assertIn('Z', order)
        # Check that X comes before Y
        pos = dict([(name, k) for k, name in enumerate(order)])
        self.assertLess(pos['X'], pos['Y'])
        self.assertEqual(pos['*remaining*'], 4)
        # Check component equation lists
        eqs = order['*remaining*']
        self.assertEqual(len(eqs), 0)
        eqs = order['Z']
        self.assertEqual(len(eqs), 1)
        self.assertEqual(eqs[0].code(), 'Z.total = X.x + Y.y')
        eqs = order['Y']
        self.assertEqual(len(eqs), 3)
        self.assertEqual(eqs[2].code(),
                         'dot(Y.y) = -Y.c * Y.y + Y.d * X.x * Y.y')
        eqs = order['X']
        self.assertEqual(len(eqs), 5)
        self.assertEqual(eqs[0].code(), 'X.a = 3')
        self.assertEqual(eqs[1].code(), 'b1 = 1')
        self.assertEqual(eqs[2].code(), 'b2 = X.a - b1 - 1')
        self.assertEqual(eqs[3].code(), 'X.b = b1 + b2')
        # Test model export and cloning
        code1 = m.code()
        code2 = m.clone().code()
        self.assertEqual(code1, code2)
Beispiel #12
0
 def remove_variable(self):
     """
     Tests the removal of a variable.
     """
     # Create a model
     m = Model('LotkaVolterra')
     # Add a variable 'a'
     X = m.add_component('X')
     # Simplest case
     a = X.add_variable('a')
     self.assertEqual(X.count_variables(), 1)
     X.remove_variable(a)
     self.assertEqual(X.count_variables(), 0)
     self.assertRaises(Exception, X.remove_variable, a)
     # Test re-adding
     a = X.add_variable('a')
     a.set_rhs(Number(5))
     self.assertEqual(X.count_variables(), 1)
     # Test deleting dependent variables
     b = X.add_variable('b')
     self.assertEqual(X.count_variables(), 2)
     b.set_rhs(Plus(Number(3), Name(a)))
     # Test blocking of removal
     self.assertRaises(IntegrityError, X.remove_variable, a)
     self.assertEqual(X.count_variables(), 2)
     # Test removal in the right order
     X.remove_variable(b)
     self.assertEqual(X.count_variables(), 1)
     X.remove_variable(a)
     self.assertEqual(X.count_variables(), 0)
     # Test reference to current state variable values
     a = X.add_variable('a')
     a.set_rhs(Number(5))
     a.promote()
     b = X.add_variable('b')
     b.set_rhs(Plus(Number(3), Name(a)))
     self.assertRaises(IntegrityError, X.remove_variable, a)
     X.remove_variable(b)
     X.remove_variable(a)
     self.assertEqual(X.count_variables(), 0)
     # Test reference to current state variable values with "self"-ref
     a = X.add_variable('a')
     a.promote()
     a.set_rhs(Name(a))
     X.remove_variable(a)
     # Test it doesn't interfere with normal workings
     a = X.add_variable('a')
     a.promote()
     a.set_rhs(Name(a))
     b = X.add_variable('b')
     b.set_rhs(Name(a))
     self.assertRaises(IntegrityError, X.remove_variable, a)
     X.remove_variable(b)
     X.remove_variable(a)
     # Test reference to dot
     a = X.add_variable('a')
     a.set_rhs(Number(5))
     a.promote()
     b = X.add_variable('b')
     b.set_rhs(Derivative(Name(a)))
     self.assertRaises(IntegrityError, X.remove_variable, a)
     X.remove_variable(b)
     X.remove_variable(a)
     # Test if orphaned
     self.assertIsNone(b.parent())
     # Test deleting variable with nested variables
     a = X.add_variable('a')
     b = a.add_variable('b')
     b.set_rhs(Plus(Number(2), Number(2)))
     a.set_rhs(Multiply(Number(3), Name(b)))
     self.assertRaises(IntegrityError, X.remove_variable, a)
     self.assertEqual(a.count_variables(), 1)
     self.assertEqual(X.count_variables(), 1)
     # Test recursive deleting
     X.remove_variable(a, recursive=True)
     self.assertEqual(a.count_variables(), 0)
     self.assertEqual(X.count_variables(), 0)
     # Same with dot(a) = a, b = 3 * a
     a = X.add_variable('a')
     a.promote(0.123)
     b = a.add_variable('b')
     b.set_rhs(Multiply(Number(3), Name(a)))
     a.set_rhs(Name(b))
     self.assertRaises(IntegrityError, X.remove_variable, a)
     self.assertRaises(IntegrityError, a.remove_variable, b)
     self.assertRaises(IntegrityError, a.remove_variable, b, True)
     X.remove_variable(a, recursive=True)