예제 #1
0
def main():
    """Parse arguments, generate a random tree, and describe it with DOT."""
    parser = argparse.ArgumentParser(
        prog='python -m interval_tree',
        description='''\
        Generate a semi-random interval tree. Generate a DOT script describing
        the entire tree, and print that description to stdout.
        ''',
    )
    parser.parse_args()

    # The interval tree is type-agnostic. To demonstrate, change this.
    gen_interval = _gen_integer_interval
    # gen_interval = _gen_date_interval

    tree = IntervalTree()
    for _ in range(10):
        tree.insert(Node(gen_interval()))
    query = gen_interval()
    results = tree.overlapping_intervals(query)
    label = (
        'label="The root node is marked in yellow.\n'
        'The interval {} overlaps the following intervals:\n'
        '{}"'
    ).format(query, ', '.join((str(interval) for interval in results)))
    print('\n'.join(('digraph interval_tree {', tree.as_dot(), label, '}')))
예제 #2
0
    def test_full(self):
        """Rotate a fully-populated tree.

        The transformation is as such::

              r       r
              │       │
              y       x
             ┌┴┐  →  ┌┴┐
             x c     a y
            ┌┴┐       ┌┴┐
            a b       b c
        """
        tree = IntervalTree()
        node_r = Node(Interval(1, 1))
        node_a = Node(Interval(2, 2))
        node_x = Node(Interval(3, 3))
        node_b = Node(Interval(4, 4))
        node_y = Node(Interval(5, 5))
        node_c = Node(Interval(6, 6))
        tree.insert(node_r)
        tree.insert(node_y)

        # force tree to take desired shape
        node_y.left = node_x
        node_y.right = node_c
        node_x.parent = node_y
        node_x.left = node_a
        node_x.right = node_b
        node_c.parent = node_y
        node_a.parent = node_x
        node_b.parent = node_x

        tree._rotate_right(node_y)  # pylint:disable=protected-access
        with self.subTest(comment='verify node_r'):
            self.assertIsNone(node_r.parent)
            self.assertIsNone(node_r.left)
            self.assertEqual(node_r.right, node_x)
        with self.subTest(comment='verify node_y'):
            self.assertEqual(node_y.parent, node_x)
            self.assertEqual(node_y.left, node_b)
            self.assertEqual(node_y.right, node_c)
        with self.subTest(comment='verify node_x'):
            self.assertEqual(node_x.parent, node_r)
            self.assertEqual(node_x.left, node_a)
            self.assertEqual(node_x.right, node_y)
        with self.subTest(comment='verify node_a'):
            self.assertEqual(node_a.parent, node_x)
            self.assertIsNone(node_a.left)
            self.assertIsNone(node_a.right)
        with self.subTest(comment='verify node_b'):
            self.assertEqual(node_b.parent, node_y)
            self.assertIsNone(node_b.left)
            self.assertIsNone(node_b.right)
        with self.subTest(comment='verify node_c'):
            self.assertEqual(node_c.parent, node_y)
            self.assertIsNone(node_c.left)
            self.assertIsNone(node_c.right)
예제 #3
0
 def test_one_node(self):
     """Search through a tree with one node."""
     node = Node(Interval(1, 1))
     tree = IntervalTree()
     tree.insert(node)
     with self.subTest(comment='pass nothing'):
         self.assertEqual(tree.min(), node)
     with self.subTest(comment='pass node'):
         self.assertEqual(tree.min(node), node)
예제 #4
0
    def test_five_nodes(self):
        """Walk through a tree with five nodes.

        The nodes are organized as such::

              c
            ┌─┴─┐
            a   e
            └┐ ┌┘
             b d
        """
        tree = IntervalTree()
        node_a = Node(Interval(1, 1))
        node_b = Node(Interval(2, 2))
        node_c = Node(Interval(3, 3))
        node_d = Node(Interval(4, 4))
        node_e = Node(Interval(5, 5))
        for node in (node_c, node_a, node_e, node_b, node_d):
            tree.insert(node)
        self.assertEqual(tree.next(node_a), node_b)
        self.assertEqual(tree.next(node_b), node_c)
        self.assertEqual(tree.next(node_c), node_d)
        self.assertEqual(tree.next(node_d), node_e)
        with self.assertRaises(NoSuchIntervalError):
            tree.next(node_e)
예제 #5
0
    def test_three_nodes(self):
        """Search through a tree with three nodes.

        The nodes are organized as such::

              a
            ┌─┘
            b
            └┐
             c
        """
        tree = IntervalTree()
        node_a = Node(Interval(3, 3))
        node_b = Node(Interval(1, 1))
        node_c = Node(Interval(2, 2))
        tree.insert(node_a)
        tree.insert(node_b)
        node_b.right = node_c  # force tree to take desired shape
        node_c.parent = node_b
        with self.subTest(comment='pass nothing'):
            self.assertEqual(tree.min(), node_b)
        with self.subTest(comment='pass node_a'):
            self.assertEqual(tree.min(node_a), node_b)
        with self.subTest(comment='pass node_b'):
            self.assertEqual(tree.min(node_b), node_b)
        with self.subTest(comment='pass node_c'):
            self.assertEqual(tree.min(node_c), node_c)
예제 #6
0
    def test_five_nodes(self):
        """Walk through a tree with five nodes.

        The nodes are organized as such::

              c
            ┌─┴─┐
            a   e
            └┐ ┌┘
             b d
        """
        tree = IntervalTree()
        node_a = Node(Interval(1, 1))
        node_b = Node(Interval(2, 2))
        node_c = Node(Interval(3, 3))
        node_d = Node(Interval(4, 4))
        node_e = Node(Interval(5, 5))
        for node in (node_c, node_a, node_e, node_b, node_d):
            tree.insert(node)
        self.assertEqual(tree.next(node_a), node_b)
        self.assertEqual(tree.next(node_b), node_c)
        self.assertEqual(tree.next(node_c), node_d)
        self.assertEqual(tree.next(node_d), node_e)
        with self.assertRaises(NoSuchIntervalError):
            tree.next(node_e)
예제 #7
0
    def test_three_nodes(self):
        """Search through a tree with three nodes.

        The nodes are organized as such::

              a
            ┌─┘
            b
            └┐
             c
        """
        tree = IntervalTree()
        node_a = Node(Interval(3, 3))
        node_b = Node(Interval(1, 1))
        node_c = Node(Interval(2, 2))
        tree.insert(node_a)
        tree.insert(node_b)
        node_b.right = node_c  # force tree to take desired shape
        node_c.parent = node_b
        with self.subTest(comment='pass nothing'):
            self.assertEqual(tree.min(), node_b)
        with self.subTest(comment='pass node_a'):
            self.assertEqual(tree.min(node_a), node_b)
        with self.subTest(comment='pass node_b'):
            self.assertEqual(tree.min(node_b), node_b)
        with self.subTest(comment='pass node_c'):
            self.assertEqual(tree.min(node_c), node_c)
예제 #8
0
def main():
    """Parse arguments, generate a random tree, and describe it with DOT."""
    parser = argparse.ArgumentParser(
        prog='python -m interval_tree',
        description='''\
        Generate a semi-random interval tree. Generate a DOT script describing
        the entire tree, and print that description to stdout.
        ''',
    )
    parser.parse_args()

    # The interval tree is type-agnostic. To demonstrate, change this.
    gen_interval = _gen_integer_interval
    # gen_interval = _gen_date_interval

    tree = IntervalTree()
    for _ in range(10):
        tree.insert(Node(gen_interval()))
    query = gen_interval()
    results = tree.overlapping_intervals(query)
    label = ('label="The root node is marked in yellow.\n'
             'The interval {} overlaps the following intervals:\n'
             '{}"').format(query, ', '.join(
                 (str(interval) for interval in results)))
    print('\n'.join(('digraph interval_tree {', tree.as_dot(), label, '}')))
예제 #9
0
    def test_full(self):
        """Rotate a fully-populated tree.

        The transformation is as such::

              r       r
              │       │
              y       x
             ┌┴┐  →  ┌┴┐
             x c     a y
            ┌┴┐       ┌┴┐
            a b       b c
        """
        tree = IntervalTree()
        node_r = Node(Interval(1, 1))
        node_a = Node(Interval(2, 2))
        node_x = Node(Interval(3, 3))
        node_b = Node(Interval(4, 4))
        node_y = Node(Interval(5, 5))
        node_c = Node(Interval(6, 6))
        tree.insert(node_r)
        tree.insert(node_y)

        # force tree to take desired shape
        node_y.left = node_x
        node_y.right = node_c
        node_x.parent = node_y
        node_x.left = node_a
        node_x.right = node_b
        node_c.parent = node_y
        node_a.parent = node_x
        node_b.parent = node_x

        tree._rotate_right(node_y)  # pylint:disable=protected-access
        with self.subTest(comment='verify node_r'):
            self.assertIsNone(node_r.parent)
            self.assertIsNone(node_r.left)
            self.assertEqual(node_r.right, node_x)
        with self.subTest(comment='verify node_y'):
            self.assertEqual(node_y.parent, node_x)
            self.assertEqual(node_y.left, node_b)
            self.assertEqual(node_y.right, node_c)
        with self.subTest(comment='verify node_x'):
            self.assertEqual(node_x.parent, node_r)
            self.assertEqual(node_x.left, node_a)
            self.assertEqual(node_x.right, node_y)
        with self.subTest(comment='verify node_a'):
            self.assertEqual(node_a.parent, node_x)
            self.assertIsNone(node_a.left)
            self.assertIsNone(node_a.right)
        with self.subTest(comment='verify node_b'):
            self.assertEqual(node_b.parent, node_y)
            self.assertIsNone(node_b.left)
            self.assertIsNone(node_b.right)
        with self.subTest(comment='verify node_c'):
            self.assertEqual(node_c.parent, node_y)
            self.assertIsNone(node_c.left)
            self.assertIsNone(node_c.right)
예제 #10
0
    def test_empty(self):
        """Rotate a tree consisting of just two nodes.

        The transformation is as such::

             x         y
             └┐   →   ┌┘
              y       x
        """
        tree = IntervalTree()
        node_x = Node(Interval(1, 1))  # current tree root
        node_y = Node(Interval(2, 2))  # future tree root
        tree.insert(node_x)
        tree.insert(node_y)
        tree._rotate_left(node_x)  # pylint:disable=protected-access
        with self.subTest(comment='verify node_x'):
            self.assertEqual(node_x.parent, node_y)
            self.assertIsNone(node_x.left)
            self.assertIsNone(node_x.right)
        with self.subTest(comment='verify node_y'):
            self.assertIsNone(node_y.parent)
            self.assertEqual(node_y.left, node_x)
            self.assertIsNone(node_y.right)
예제 #11
0
 def test_one_node(self):
     """Search through a tree with one node."""
     node = Node(Interval(1, 1))
     tree = IntervalTree()
     tree.insert(node)
     with self.subTest(comment='pass nothing'):
         self.assertEqual(tree.min(), node)
     with self.subTest(comment='pass node'):
         self.assertEqual(tree.min(node), node)
예제 #12
0
    def test_empty(self):
        """Rotate a tree consisting of just two nodes.

        The transformation is as such::

             x         y
             └┐   →   ┌┘
              y       x
        """
        tree = IntervalTree()
        node_x = Node(Interval(1, 1))  # current tree root
        node_y = Node(Interval(2, 2))  # future tree root
        tree.insert(node_x)
        tree.insert(node_y)
        tree._rotate_left(node_x)  # pylint:disable=protected-access
        with self.subTest(comment='verify node_x'):
            self.assertEqual(node_x.parent, node_y)
            self.assertIsNone(node_x.left)
            self.assertIsNone(node_x.right)
        with self.subTest(comment='verify node_y'):
            self.assertIsNone(node_y.parent)
            self.assertEqual(node_y.left, node_x)
            self.assertIsNone(node_y.right)
예제 #13
0
 def test_no_nodes(self):
     """Search through an empty tree."""
     tree = IntervalTree()
     with self.assertRaises(NoSuchIntervalError):
         tree.min()
예제 #14
0
 def test_no_nodes(self):
     """Search through an empty tree."""
     tree = IntervalTree()
     with self.assertRaises(NoSuchIntervalError):
         tree.min()