Ticket #11736: linear_lex_bfs.patch

File linear_lex_bfs.patch, 4.7 KB (added by ddestrada, 8 years ago)
  • sage/graphs/generic_graph.py

    # HG changeset patch
    # User Diego de Estrada <destrada@dc.uba.ar>
    # Date 1315290554 10800
    # Node ID 4a4d5218c2814646f948e002476e1c4173faed28
    # Parent  2a2abbcad325ccca9399981ceddf5897eb467e64
    Implementation of lex_BFS() in linear time.
    
    diff -r 2a2abbcad325 -r 4a4d5218c281 sage/graphs/generic_graph.py
    a b  
    93879387        for each vertex `v` the subgraph induces by its non-deleted neighbors,
    93889388        then testing whether this graph is complete.
    93899389   
    9390         This problem can be solved in `O(m)` [Rose75]_ ( where `m` is the number
    9391         of edges in the graph ) but this implementation is not linear because of
    9392         the complexity of Lex BFS. Improving Lex BFS to linear complexity would
    9393         make this algorithm linear.
    9394    
    93959390        The complexity of this algorithm is equal to the complexity of the
    9396         implementation of Lex BFS.
     9391        implementation of Lex BFS [Rose75]_, which is linear in the size of the
     9392        graph.
    93979393   
    93989394        EXAMPLES:
    93999395   
     
    1153511531        vertex of maximal code ( according to the lexicographic
    1153611532        order ) is then removed, and the codes are updated.
    1153711533   
    11538         This algorithm runs in time `O(n^2)` ( where `n` is the
    11539         number of vertices in the graph ), which is not optimal.
    11540         An optimal algorithm would run in time `O(m)` ( where `m`
    11541         is the number of edges in the graph ), and require the use
    11542         of a doubly-linked list which are not available in python
    11543         and can not really be written efficiently. This could be
    11544         done in Cython, though.
     11534        This algorithm runs in time `O(n+m)` ( where `n` is the
     11535        number of vertices in the graph and `m` is the number of
     11536        edges in the graph ).
    1154511537   
    1154611538        EXAMPLE:
    1154711539   
     
    1157111563            True
    1157211564
    1157311565        """
    11574         id_inv = dict([(i,v) for (v,i) in zip(self.vertices(),range(self.order()))])
    11575         code = [[] for i in range(self.order())]
    11576         m = self.am()
    11577        
    11578         l = lambda x : code[x]
    11579         vertices = set(range(self.order()))
    11580    
    11581         value = []
    11582         pred = [-1]*self.order()
    11583    
    11584         add_element = (lambda y:value.append(id_inv[y])) if not reverse else (lambda y: value.insert(0,id_inv[y]))
    11585 
    11586         # Should we take care of the first vertex we pick ?
    11587         first = True if initial_vertex is not None else False
    11588 
    11589    
    11590         while vertices:
    11591 
    11592             if not first:
    11593                 v = max(vertices,key=l)
    11594             else:
    11595                 v = self.vertices().index(initial_vertex)
    11596                 first = False
    11597 
    11598             vertices.remove(v)
    11599             vector = m.column(v)
    11600             for i in vertices:
    11601                 code[i].append(vector[i])
    11602                 if vector[i]:
    11603                     pred[i] = v
    11604             add_element(v)
    11605    
     11566        n = self.order()
     11567        perm_inv = self.vertices()
     11568        perm = dict(zip(perm_inv,range(n)))
     11569
     11570        if initial_vertex is not None:
     11571            i = perm[initial_vertex]
     11572            if i != 0:
     11573                v = perm_inv[0]
     11574                perm[initial_vertex], perm[v] = 0, i
     11575                perm_inv[i], perm_inv[0] = v, initial_vertex
     11576
     11577        slice_of = [0]*n
     11578        slice_head = [0]*n
     11579        subslice = [-1]*n
     11580        pred = {}
     11581
     11582        k = 1
     11583        for i in range(n):
     11584            old_k = k
     11585            v = perm_inv[i]
     11586            for w in self.neighbors(v):
     11587                j = perm[w]
     11588                if j <= i:
     11589                    continue
     11590                a = slice_of[j]
     11591                if slice_head[a] <= i:
     11592                    slice_head[a] = i+1
     11593                l = slice_head[a]
     11594                if l < n-1 and slice_of[l+1] != a:
     11595                    continue
     11596                u = perm_inv[l]
     11597                if l != j:
     11598                    perm[w], perm[u] = l, j
     11599                    perm_inv[j], perm_inv[l] = u, w
     11600                slice_head[a] += 1
     11601                if subslice[a] < old_k:
     11602                    subslice[a] = k
     11603                    slice_head[k] = l
     11604                    k += 1
     11605                slice_of[l] = subslice[a]
     11606                pred[u] = v
     11607
     11608        if reverse:
     11609            perm_inv.reverse()
    1160611610        if tree:
    1160711611            from sage.graphs.digraph import DiGraph
    1160811612            g = DiGraph(sparse=True)
    11609             edges = [(id_inv[i], id_inv[pred[i]]) for i in range(self.order()) if pred[i]!=-1]
    11610             g.add_edges(edges)
    11611             return value, g
    11612 
    11613         else:
    11614             return value
    11615    
     11613            g.add_edges(pred.items())
     11614            return perm_inv, g
     11615        return perm_inv
     11616
    1161611617    ### Constructors
    1161711618
    1161811619    def add_cycle(self, vertices):