def test_link_connectsTwoTrees(self):
     #arrange
     tree = LinkCutTree()
     a1 = tree.makeTree('a1')
     a2 = tree.makeTree('a2')
     
     #act
     tree.link(a1,a2)
     
     #assert
     self.assertEqual(a1, tree.getRoot(a2))
    def test_lca_query_order_doesnt_matter(self):
        #Arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        tree.link(a1, a2)
        tree.link(a2, a3)

        self.assertEqual(tree.lca(a2, a3), tree.lca(a3, a2))
    def test_lca_path_shouldReturnOlderNode(self):
        #Arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        tree.link(a1, a2)
        tree.link(a2, a3)

        self.assertEqual(tree.lca(a2, a3), a2)
    def test_lca_balancedTree_ShouldReturnRoot(self):
        #Arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        tree.link(a1, a2)
        tree.link(a1, a3)

        self.assertEqual(tree.lca(a2, a3), a1)
    def test_lca_query_order_doesnt_matter(self):
        #Arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        tree.link(a1,a2)
        tree.link(a2,a3)

        self.assertEqual(tree.lca(a2,a3),tree.lca(a3,a2))
 def test_getRoot__returnsProperRootWhenRootHasMultipleChildren(self):
     #arrange
     tree = LinkCutTree()
     a1 = tree.makeTree('a1')
     a2 = tree.makeTree('a2')
     b1 = tree.makeTree('b1')
     tree.link(a1, a2)
     tree.link(a1, b1)
     #act / assert
     self.assertEqual(a1, tree.getRoot(a2))
     self.assertEqual(a1, tree.getRoot(b1))
    def test_lca_balancedTree_ShouldReturnRoot(self):
        #Arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        tree.link(a1,a2)
        tree.link(a1,a3)

        self.assertEqual(tree.lca(a2,a3),a1)
    def test_lca_path_shouldReturnOlderNode(self):
        #Arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        tree.link(a1,a2)
        tree.link(a2,a3)

        self.assertEqual(tree.lca(a2,a3),a2)
 def test_getRoot__returnsProperRootWhenRootHasMultipleChildren(self):
     #arrange
     tree = LinkCutTree()
     a1 = tree.makeTree('a1')
     a2 = tree.makeTree('a2')
     b1 = tree.makeTree('b1')
     tree.link(a1,a2)
     tree.link(a1,b1)
     #act / assert
     self.assertEqual(a1, tree.getRoot(a2))
     self.assertEqual(a1, tree.getRoot(b1))
Exemple #10
0
    def test_link_connectsTwoTrees(self):
        #arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')

        #act
        tree.link(a1, a2)

        #assert
        self.assertEqual(a1, tree.getRoot(a2))
Exemple #11
0
 def test_getNode_nodeDoesntExist_returnsNone(self):
     tree = LinkCutTree()
     self.assertIsNone(tree.getNode('a1'))
Exemple #12
0
    def test_lca_multipleLinks_shouldFindLCA(self):
        tree = LinkCutTree()
        #Arrange
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1, a2)
        tree.link(a2, a3)
        tree.link(a3, a4)
        tree.link(a4, a5)
        tree.link(a5, a6)

        b1 = tree.makeTree('b1')
        b2 = tree.makeTree('b2')
        b3 = tree.makeTree('b3')

        tree.link(b1, b2)
        tree.link(b2, b3)

        tree.link(a3, b1)

        c1 = tree.makeTree('c1')
        c2 = tree.makeTree('c2')
        c3 = tree.makeTree('c3')
        tree.link(c1, c2)
        tree.link(c1, c3)

        tree.link(a5, c1)

        self.assertEqual(tree.lca(c3, b3), a3)
Exemple #13
0
    def test_makeRoot_path_shouldFlipPath(self):

        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1, a2, 1)
        tree.link(a2, a3, 2)
        tree.link(a3, a4, 3)
        tree.link(a4, a5, 4)
        tree.link(a5, a6, 5)

        #act
        tree.makeRoot(a6)

        #assert
        self.assertEqual(a6, tree.getRoot(a1))
        self.assertEqual(a6, a5.represented_parent)
        self.assertEqual(a5, a4.represented_parent)
        self.assertEqual(a4, a3.represented_parent)
        self.assertEqual(a3, a2.represented_parent)
        self.assertEqual(a2, a1.represented_parent)
Exemple #14
0
    def test_makeRoot_flip_tree(self):

        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1, a2, 1)
        tree.link(a2, a3, 2)
        tree.link(a3, a4, 3)
        tree.link(a4, a5, 4)
        tree.link(a5, a6, 5)

        b1 = tree.makeTree('b1')
        b2 = tree.makeTree('b2')
        b3 = tree.makeTree('b3')

        tree.link(b1, b2)
        tree.link(b2, b3)

        tree.link(a3, b1)
        #act
        tree.makeRoot(b3)

        #assert

        self.assertEqual(b3, tree.getRoot(a6))

        # nodes on the flipped path still share root
        self.assertEqual(tree.getRoot(b1), tree.getRoot(a2))

        # node in flipped path and node out of path share root
        self.assertEqual(tree.getRoot(a6), tree.getRoot(a2))

        self.assertEqual(b2, b1.represented_parent)
        self.assertEqual(b3, b2.represented_parent)
        self.assertEqual(b1, a3.represented_parent)
        self.assertEqual(a3, a2.represented_parent)
        self.assertEqual(a2, a1.represented_parent)
Exemple #15
0
    def test_link_threeTrees_getRootShouldBeSameForAll(self):
        tree = LinkCutTree()
        #Arrange
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1,a2)
        tree.link(a2,a3)
        tree.link(a3,a4)
        tree.link(a4,a5)
        tree.link(a5,a6)
        
        b1 = tree.makeTree('b1')
        b2 = tree.makeTree('b2')
        b3 = tree.makeTree('b3')
        
        tree.link(b1,b2)
        tree.link(b2,b3)

        
        tree.link(a3,b1)
        
        c1 = tree.makeTree('c1')
        c2 = tree.makeTree('c2')
        c3 = tree.makeTree('c3')
        tree.link(c1,c2)
        tree.link(c2,c3)
        
        tree.link(a5,c1)

        # act/assert
        self.assertEqual(a1, tree.getRoot(c1))
        self.assertEqual(a1, tree.getRoot(b3))
Exemple #16
0
    def test_link__preservesRepresentedParent(self):
        ''' after linking all these tree's the represented_parent nodes should represent the paths in the represented tree
        '''
        #Arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1,a2)
        tree.link(a2,a3)
        tree.link(a3,a4)
        tree.link(a4,a5)
        tree.link(a5,a6)
        tree.access(a3)

        c1 = tree.makeTree('c1')
        c2 = tree.makeTree('c2')
        c3 = tree.makeTree('c3')
        tree.link(c1,c2)
        tree.link(c2,c3)

        tree.link(a4,c1);
        
        # act/assert
        self.assertEqual(a1,a2.represented_parent)
        self.assertEqual(a2,a3.represented_parent)
        self.assertEqual(a3,a4.represented_parent)
        self.assertEqual(a4,a5.represented_parent)
        self.assertEqual(a5,a6.represented_parent)
        
        self.assertEqual(c1,c2.represented_parent)
        self.assertEqual(c2,c3.represented_parent)

        self.assertEqual(a4,c1.represented_parent)
Exemple #17
0
    def test_cut__leaves_bothTreesIntact(self):
        # arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1,a2)
        tree.link(a2,a3)
        tree.link(a3,a4)
        tree.link(a4,a5)
        tree.link(a5,a6)

        c1 = tree.makeTree('c1')
        c2 = tree.makeTree('c2')
        c3 = tree.makeTree('c3')
        tree.link(c1,c2)
        tree.link(c2,c3)

        tree.link(a6,c1);

        #act
        tree.cut(c2)

        #assert
        self.assertEqual(a1, tree.getRoot(c1))
        self.assertEqual(c2, tree.getRoot(c3))
Exemple #18
0
    def test_makeRoot_flip_tree(self):
        
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1,a2,1)
        tree.link(a2,a3,2)
        tree.link(a3,a4,3)
        tree.link(a4,a5,4)
        tree.link(a5,a6,5)
    
         
        b1 = tree.makeTree('b1')
        b2 = tree.makeTree('b2')
        b3 = tree.makeTree('b3')
        
        tree.link(b1,b2)
        tree.link(b2,b3)

        
        tree.link(a3,b1)
        #act
        tree.makeRoot(b3)

        #assert
        
        self.assertEqual(b3, tree.getRoot(a6))

        # nodes on the flipped path still share root
        self.assertEqual(tree.getRoot(b1), tree.getRoot(a2))

        # node in flipped path and node out of path share root
        self.assertEqual(tree.getRoot(a6), tree.getRoot(a2))
       
        self.assertEqual(b2,b1.represented_parent)
        self.assertEqual(b3,b2.represented_parent)
        self.assertEqual(b1,a3.represented_parent)
        self.assertEqual(a3,a2.represented_parent)
        self.assertEqual(a2,a1.represented_parent)
Exemple #19
0
    def test_lca_multipleLinks_shouldFindLCA(self):
        tree = LinkCutTree()
        #Arrange
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1,a2)
        tree.link(a2,a3)
        tree.link(a3,a4)
        tree.link(a4,a5)
        tree.link(a5,a6)
        
        b1 = tree.makeTree('b1')
        b2 = tree.makeTree('b2')
        b3 = tree.makeTree('b3')
        
        tree.link(b1,b2)
        tree.link(b2,b3)

        
        tree.link(a3,b1)
        
        c1 = tree.makeTree('c1')
        c2 = tree.makeTree('c2')
        c3 = tree.makeTree('c3')
        tree.link(c1,c2)
        tree.link(c1,c3)
        
        tree.link(a5,c1)

        
        self.assertEqual(tree.lca(c3,b3),a3)
Exemple #20
0
    def test_cut__leaves_bothTreesIntact(self):
        # arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1, a2)
        tree.link(a2, a3)
        tree.link(a3, a4)
        tree.link(a4, a5)
        tree.link(a5, a6)

        c1 = tree.makeTree('c1')
        c2 = tree.makeTree('c2')
        c3 = tree.makeTree('c3')
        tree.link(c1, c2)
        tree.link(c2, c3)

        tree.link(a6, c1)

        #act
        tree.cut(c2)

        #assert
        self.assertEqual(a1, tree.getRoot(c1))
        self.assertEqual(c2, tree.getRoot(c3))
Exemple #21
0
    def test_makeRoot_path_shouldFlipPath(self):
        
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1,a2,1)
        tree.link(a2,a3,2)
        tree.link(a3,a4,3)
        tree.link(a4,a5,4)
        tree.link(a5,a6,5)
    
        #act
        tree.makeRoot(a6)

        #assert
        self.assertEqual(a6, tree.getRoot(a1))
        self.assertEqual(a6, a5.represented_parent)
        self.assertEqual(a5, a4.represented_parent)
        self.assertEqual(a4, a3.represented_parent)
        self.assertEqual(a3, a2.represented_parent)
        self.assertEqual(a2, a1.represented_parent)
Exemple #22
0
    def test_link__preservesRepresentedParent(self):
        ''' after linking all these tree's the represented_parent nodes should represent the paths in the represented tree
        '''
        #Arrange
        tree = LinkCutTree()
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1, a2)
        tree.link(a2, a3)
        tree.link(a3, a4)
        tree.link(a4, a5)
        tree.link(a5, a6)
        tree.access(a3)

        c1 = tree.makeTree('c1')
        c2 = tree.makeTree('c2')
        c3 = tree.makeTree('c3')
        tree.link(c1, c2)
        tree.link(c2, c3)

        tree.link(a4, c1)

        # act/assert
        self.assertEqual(a1, a2.represented_parent)
        self.assertEqual(a2, a3.represented_parent)
        self.assertEqual(a3, a4.represented_parent)
        self.assertEqual(a4, a5.represented_parent)
        self.assertEqual(a5, a6.represented_parent)

        self.assertEqual(c1, c2.represented_parent)
        self.assertEqual(c2, c3.represented_parent)

        self.assertEqual(a4, c1.represented_parent)
Exemple #23
0
 def test_getNode_nodeExists_returnsNode(self):
     tree = LinkCutTree()
     a1 = tree.makeTree('a1')
     self.assertEqual(a1, tree.getNode('a1'))
Exemple #24
0
class RetroactiveUnionFind(object):
    """Fully retroactive union find implemented using link-cut trees to represented disjoint forests"""
    def __init__(self):
        self.forest = LinkCutTree()
        self.time = 0

    # unionAgo(a,b) links nodes a and b in the LinkCutTree if they weren't already linked.
    # If they were it cuts the latest edge on the path between a and b (if it is later than the new link time).
    # The new subtree will contain exactly one of a and b. We make that node the root of the subtree and link it to
    # the other node still in the main tree.
    # This preserves old unions because any edge below the cut edge will now follow a path through the a-b edge up to
    # the lca, which is guaranteed not to have an edge value greater than the cut edge. Any edge above the cut \
    # edge will not be affected.
    def unionAgo(self, a_data, b_data, tdelta=0):
        # if the sets are already connected at the specified time return
        if self.sameSetAgo(a_data, b_data, tdelta):
            return

        #get node objects to work with
        a = self.forest.getNode(a_data)
        b = self.forest.getNode(b_data)
        union_time = self.time + tdelta
        if a is None:
            a = self.forest.makeTree(a_data)

        if b is None:
            b = self.forest.makeTree(b_data)

        # if the nodes are not connected at all, connect them. If they are connected at a later time,
        # cut the oldest edge on the path between the two nodes, make the union'ed node the root of that tree
        # and attach it to the other union'ed node.
        if self.forest.getRoot(a) != self.forest.getRoot(b):
            self.forest.makeRoot(b)
            self.forest.link(a, b, union_time)
        else:
            lca = self.forest.lca(a, b)
            max_time = float("-inf")
            max_time_node = None
            for next in [a, b]:
                while next is not lca:
                    if next.parent_edge_weight > max_time:
                        max_time = next.parent_edge_weight
                        max_time_node = next
                    next = next.represented_parent

            self.forest.cut(max_time_node)
            if self.forest.getRoot(a) == next:
                self.forest.makeRoot(a)
                self.forest.link(b, a, union_time)
            else:
                self.forest.makeRoot(b)
                self.forest.link(a, b, union_time)
        self.time += 1

    # sameSetAgo(a,b,t) will find the lca of a and b and traverse the path from both to the lca,
    # finding the largest edge on the path between a and b. If any edge is larger than time + tdelta then a, and b
    # were not connected at (time + tdelta)
    def sameSetAgo(self, a_data, b_data, tdelta=0):
        # sameset is reflexive
        if a_data == b_data:
            return True

        a = self.forest.getNode(a_data)
        b = self.forest.getNode(b_data)
        query_time = self.time + tdelta

        if a is None or b is None:
            return False

        lca = self.forest.lca(a, b)
        if lca is None:
            return False

        for next in [a, b]:
            while next is not lca:
                if next.parent_edge_weight > query_time:
                    return False
                next = next.represented_parent

        return True

    # sameSetWhen(a,b) traverses the path between a and b and return the largest edge,
    # which is the time at which a and b were connected.
    def sameSetWhen(self, a, b):
        lca = self.forest.lca(a, b)
        if lca is None:
            return float("-inf")

        max_time = float("-inf")
        for next in [a, b]:
            while next is not lca:
                if next.parent_edge_weight > max_time:
                    max_time = next.parent_edge_weight
                next = next.represented_parent

        return max_time
Exemple #25
0
 def test_getNode_nodeDoesntExist_returnsNone(self):
      tree = LinkCutTree()
      self.assertIsNone(tree.getNode('a1'))
Exemple #26
0
 def __init__(self):
     self.forest = LinkCutTree()
     self.time = 0
Exemple #27
0
 def test_getNode_nodeExists_returnsNode(self):
      tree = LinkCutTree()
      a1 = tree.makeTree('a1')
      self.assertEqual(a1,tree.getNode('a1'))
Exemple #28
0
    def test_link_threeTrees_getRootShouldBeSameForAll(self):
        tree = LinkCutTree()
        #Arrange
        a1 = tree.makeTree('a1')
        a2 = tree.makeTree('a2')
        a3 = tree.makeTree('a3')
        a4 = tree.makeTree('a4')
        a5 = tree.makeTree('a5')
        a6 = tree.makeTree('a6')
        tree.link(a1, a2)
        tree.link(a2, a3)
        tree.link(a3, a4)
        tree.link(a4, a5)
        tree.link(a5, a6)

        b1 = tree.makeTree('b1')
        b2 = tree.makeTree('b2')
        b3 = tree.makeTree('b3')

        tree.link(b1, b2)
        tree.link(b2, b3)

        tree.link(a3, b1)

        c1 = tree.makeTree('c1')
        c2 = tree.makeTree('c2')
        c3 = tree.makeTree('c3')
        tree.link(c1, c2)
        tree.link(c2, c3)

        tree.link(a5, c1)

        # act/assert
        self.assertEqual(a1, tree.getRoot(c1))
        self.assertEqual(a1, tree.getRoot(b3))