Esempio n. 1
0
def test_bfs_properties_undirected(graph):
    """
    In any breadth-first search tree, all edges either (1) are in the
    tree, (2) connect two vertices in the same level of the tree, or
    (3) connect two vertices from adjacent levels of the tree
    """
    g = UndirectedGraph(graph())
    visitor = AggregateVisitor(visitors={ParentEdge:None, Depth:None})
    traverse(g.vertices(), visitor, breadth_first_generator(g))
    tree_edges = set([e for e in visitor.ParentEdge.itervalues() \
                      if e is not None])
    for e in g.edges():
        if e not in tree_edges:
            u_depth = visitor.Depth[e[0]]
            v_depth = visitor.Depth[e[1]]
            assert u_depth == v_depth or abs(u_depth - v_depth) == 1
Esempio n. 2
0
def test_graph_splits_undirected(graph):
    """
    In any depth-first search tree of an undirected graph, any 
    edge (root, X) in the depth-first search tree partitions 
    the graph: there are no edges between any vertex visited 
    before X and any vertices visited after X in the original graph.
    """
    g = UndirectedGraph(graph())
    visitor = AggregateVisitor(visitors={Parent : None, 
                                         ParentEdge : None, 
                                         DiscoverTime : None})
    traverse(g.vertices(), visitor, depth_first_generator(g))
    root = [v for v,time in visitor.DiscoverTime.iteritems() if time == 0][0]
    root_edges = [visitor.ParentEdge[v] for v in g.vertices() \
                  if v != root and visitor.Parent[v] == root] 
    for x,y in root_edges:
        before = [v for v in g.vertices() \
                  if visitor.DiscoverTime[v] < visitor.DiscoverTime[y] \
                  and v != root]
        after = [v for v in g.vertices() \
                 if visitor.DiscoverTime[v] > visitor.DiscoverTime[y]]
        for b in before:
            for a in after:
                assert [e for e in g.edges(source=b, target=a)] == []
                assert [e for e in g.edges(source=a, target=b)] == []
Esempio n. 3
0
    def __init__(self, g):
        self.g = UndirectedGraph(g)

        v = {LowPoint:None, LeastAncestor:None, Parent:None, ParentEdge:None}
        self.vis = AggregateVisitor(backend=self.g, visitors=v)
        traverse(self.g.vertices(), self.vis, depth_first_generator(self.g))

        self.vertices_by_lowpoint = \
            sorted(self.g.vertices(), 
                   key=partial(getitem, self.vis.LowPoint))

        self.vertices_by_dfs_num = \
            sorted(self.g.vertices(), 
                   key=partial(getitem, self.vis.DiscoverTime))

        self.face_handle = {}
        self.df_face_handle = {}
        self.canonical_df_child = dict((v,v) for v in self.g.vertices())
        self.pertinent_roots = dict((v,[]) for v in self.g.vertices())
        self.separated_df_child_list = dict((v,[]) for v in self.g.vertices())
        self.self_loops = []
        self.backedges = dict((v,[]) for v in self.g.vertices())
        self.backedge_flag = dict((v,-1) for v in self.g.vertices())
        self.visited = dict((v,-1) for v in self.g.vertices())

        for v in self.g.vertices():
            parent = self.vis.Parent.get(v)
            parent_edge = self.vis.ParentEdge.get(v)
            handle_list = [] if parent is None else [parent_edge]
            self.face_handle[v] = face_handle(v, handle_list[:])
            self.df_face_handle[v] = face_handle(parent, handle_list[:])

        PRINT('Parent: %s' % self.vis.Parent, 1)

        for v in self.g.vertices():
            PRINT('ParentEdge %s: %s' % (v, self.vis.ParentEdge.get(v)), 1)

        for v in self.g.vertices():
            PRINT('DiscoverTime %s: %s' % (v, self.vis.DiscoverTime.get(v)), 1)

        for v in self.g.vertices():
            PRINT('LowPoint %s: %s' % (v, self.vis.LowPoint.get(v)), 1)

        PRINT('Vertices by dfs num: %s' % self.vertices_by_dfs_num)
Esempio n. 4
0
class boyer_myrvold(object):

    def __init__(self, g):
        self.g = UndirectedGraph(g)

        v = {LowPoint:None, LeastAncestor:None, Parent:None, ParentEdge:None}
        self.vis = AggregateVisitor(backend=self.g, visitors=v)
        traverse(self.g.vertices(), self.vis, depth_first_generator(self.g))

        self.vertices_by_lowpoint = \
            sorted(self.g.vertices(), 
                   key=partial(getitem, self.vis.LowPoint))

        self.vertices_by_dfs_num = \
            sorted(self.g.vertices(), 
                   key=partial(getitem, self.vis.DiscoverTime))

        self.face_handle = {}
        self.df_face_handle = {}
        self.canonical_df_child = dict((v,v) for v in self.g.vertices())
        self.pertinent_roots = dict((v,[]) for v in self.g.vertices())
        self.separated_df_child_list = dict((v,[]) for v in self.g.vertices())
        self.self_loops = []
        self.backedges = dict((v,[]) for v in self.g.vertices())
        self.backedge_flag = dict((v,-1) for v in self.g.vertices())
        self.visited = dict((v,-1) for v in self.g.vertices())

        for v in self.g.vertices():
            parent = self.vis.Parent.get(v)
            parent_edge = self.vis.ParentEdge.get(v)
            handle_list = [] if parent is None else [parent_edge]
            self.face_handle[v] = face_handle(v, handle_list[:])
            self.df_face_handle[v] = face_handle(parent, handle_list[:])

        PRINT('Parent: %s' % self.vis.Parent, 1)

        for v in self.g.vertices():
            PRINT('ParentEdge %s: %s' % (v, self.vis.ParentEdge.get(v)), 1)

        for v in self.g.vertices():
            PRINT('DiscoverTime %s: %s' % (v, self.vis.DiscoverTime.get(v)), 1)

        for v in self.g.vertices():
            PRINT('LowPoint %s: %s' % (v, self.vis.LowPoint.get(v)), 1)

        PRINT('Vertices by dfs num: %s' % self.vertices_by_dfs_num)
            

    def planar_embedding(self):

        for v in reversed(self.vertices_by_dfs_num):
            self.store_old_face_handles()
            self.walkup(v)
            if not self.walkdown(v):
                 return False

        self.clean_up_embedding()
        return True

    def walkup(self, v):
        
        PRINT('--- Starting walkup from %s ---' % v, 1)
        PRINT('--- edges to consider: %s ---' % \
                  [e for e in self.g.edges(source=v)])
        for e in self.g.edges(source = v):
            w = other_vertex(e, v)
            PRINT('Looking at (v,w) = (%s,%s)' % (v,w), 4)
            if v == w:
                self.self_loops.append(e)
                continue
            
            if self.vis.DiscoverTime[w] < self.vis.DiscoverTime[v] or \
               e == self.vis.ParentEdge[w]:
                continue

            self.backedges[w].append(e)
            timestamp = self.vis.DiscoverTime[v]
            self.backedge_flag[w] = timestamp

            for face_itr in chain((w,),self.first_face_iter(w)):
                PRINT('Traveler: %s' % face_itr)
                if face_itr == v or self.visited[face_itr] == timestamp:
                    break
                elif self.is_bicomp_root(face_itr):
                    PRINT('Setting visited/pertinent roots for %s' % face_itr)
                    dfs_child = self.canonical_df_child[face_itr]
                    parent = self.vis.Parent.get(dfs_child, dfs_child)
                    handle = self.df_face_handle[dfs_child]
                    PRINT('Handle: %s' % handle)
                    if handle.vertex is not None:
                        self.visited[handle.first_endpoint()] = timestamp
                        self.visited[handle.second_endpoint()] = timestamp

                    v_df_number = self.vis.DiscoverTime[v]
                    if self.vis.LowPoint[dfs_child] < v_df_number or \
                       self.vis.LeastAncestor[dfs_child] < v_df_number:
                        PRINT('Appending %s to %s''s prs' % (handle, parent))
                        self.pertinent_roots[parent].append(handle)
                    else:
                        PRINT("Prepending %s to %s's prs" % (handle, parent))
                        self.pertinent_roots[parent].insert(0,handle)
                self.visited[face_itr] = timestamp

        PRINT('--- Done with walkup from %s ---' % v, 1)    
        PRINT('Visited: %s' % self.visited, 1)
            


    def walkdown(self, v):
        
        PRINT('--- Starting walkdown from %s ---' % v, 1)
        PRINT('pertinent roots: %s' % self.pertinent_roots[v], 1)
        merge_stack = []
        while self.pertinent_roots[v]:
            root_handle = self.pertinent_roots[v].pop(0)
            curr_handle = root_handle
            PRINT('Traversing from handle %s' % curr_handle)

            endpoints = []
            PRINT('Traversal endpoints are %s and %s' % \
                (curr_handle.first_endpoint(), curr_handle.second_endpoint()))
            first_endpoint = curr_handle.first_endpoint()
            second_endpoint = curr_handle.second_endpoint()
            if first_endpoint == second_endpoint:
                endpoints.append((curr_handle.vertex, first_endpoint))
            else:
                for endpoint in (first_endpoint, second_endpoint):
                    tail = curr_handle.vertex
                    for face_v in face_iterator(curr_handle.vertex, 
                                                endpoint,
                                                self.face_handle):
                        if self.pertinent(face_v, v) or \
                           self.externally_active(face_v, v):
                            endpoints.append((tail, face_v))
                            break
                    tail = face_v
            PRINT('Endpoints: %s' % endpoints)

            first_tail, first_side_vertex = endpoints[0]
            second_tail, second_side_vertex = endpoints[-1]
            if self.internally_active(first_side_vertex, v):
                chosen, chose_first_upper_path = first_side_vertex, True
            elif self.internally_active(second_side_vertex, v):
                chosen, chose_first_upper_path = second_side_vertex, False
            elif self.pertinent(first_side_vertex, v):
                chosen, chose_first_upper_path = first_side_vertex, True
            elif self.pertinent(second_side_vertex, v):
                chosen, chose_first_upper_path = second_side_vertex, False
            else:
                PRINT('NOT PLANAR!')
                return False

            PRINT('Chosen: %s, Chose first: %s' % \
                  (chosen, chose_first_upper_path))


        PRINT('--- Done with walkdown from %s ---' % v, 1)
        return True


    def store_old_face_handles(self):
        pass

    def clean_up_embedding(self):
        pass

    def first_face_iter(self, v):
        return face_iterator(v, self.face_handle[v].first_endpoint(), 
                             self.face_handle)

    def second_face_iter(self, v):
        return face_iterator(v, self.face_handle[v].second_endpoint(), 
                             self.face_handle)

    def pertinent(self, w, v):
        return self.backedge_flag[w] == self.vis.DiscoverTime[v] or \
               self.pertinent_roots[w]

    def externally_active(self, w, v):
        v_num = self.vis.DiscoverTime[v]
        return self.vis.LeastAncestor[w] < v_num or \
               (self.separated_df_child_list[w] and \
                self.vis.LowPoint[self.separated_df_child_list[w][0]] < v_num)

    def internally_active(self, w, v):
        return self.pertinent(w,v) and not self.externally_active(w,v)

    def is_bicomp_root(self, v):
        handle = self.face_handle[v]
        if not handle.handle_list:
            return True
        first_endpoint = handle.first_endpoint()
        second_endpoint = handle.second_endpoint()
        if first_endpoint == second_endpoint:
            return True # one-edge bicomp
        if face_handle[first_endpoint].first_endpoint() != v and \
           face_handle[first_endpoint].second_endpoint() != v:
            return True
        return False