Ticket #11736: linear_lex_bfs_fixed.patch

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

    # HG changeset patch
    # User Diego de Estrada <destrada@dc.uba.ar>
    # Date 1332815729 10800
    # Node ID aa34a7311cec0b0d83667442e178fcb6bd81d185
    # Parent  c239be1054e01526a1b0b62da6691061b9dd5587
    Trac 11736: Implementation of lex_BFS() in linear time.
    
    diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
    a b  
    96779677        for each vertex `v` the subgraph induces by its non-deleted neighbors,
    96789678        then testing whether this graph is complete.
    96799679   
    9680         This problem can be solved in `O(m)` [Rose75]_ ( where `m` is the number
    9681         of edges in the graph ) but this implementation is not linear because of
    9682         the complexity of Lex BFS.
    9683 
    96849680        .. NOTE::
    96859681
    96869682            Because of a past bug (#11735, #11961), the first implementation
     
    1196411960        vertex of maximal code ( according to the lexicographic
    1196511961        order ) is then removed, and the codes are updated.
    1196611962   
    11967         This algorithm runs in time `O(n^2)` ( where `n` is the
    11968         number of vertices in the graph ), which is not optimal.
    11969         An optimal algorithm would run in time `O(m)` ( where `m`
    11970         is the number of edges in the graph ), and require the use
    11971         of a doubly-linked list which are not available in python
    11972         and can not really be written efficiently. This could be
    11973         done in Cython, though.
     11963        This algorithm runs in time `O(n+m)` ( where `n` is the
     11964        number of vertices and `m` is the number of edges in the
     11965        graph ). The implementation follows [HMPV00]_.
    1197411966   
    1197511967        EXAMPLE:
    1197611968   
     
    1199911991            sage: all([g.subgraph(g.neighbors(v)).is_clique() for v in leaves])
    1200011992            True
    1200111993
    12002         """
    12003         id_inv = dict([(i,v) for (v,i) in zip(self.vertices(),range(self.order()))])
    12004         code = [[] for i in range(self.order())]
    12005         m = self.am()
    12006        
    12007         l = lambda x : code[x]
    12008         vertices = set(range(self.order()))
    12009    
    12010         value = []
    12011         pred = [-1]*self.order()
    12012    
    12013         add_element = (lambda y:value.append(id_inv[y])) if not reverse else (lambda y: value.insert(0,id_inv[y]))
    12014 
    12015         # Should we take care of the first vertex we pick ?
    12016         first = True if initial_vertex is not None else False
    12017 
    12018    
    12019         while vertices:
    12020 
    12021             if not first:
    12022                 v = max(vertices,key=l)
    12023             else:
    12024                 v = self.vertices().index(initial_vertex)
    12025                 first = False
    12026 
    12027             vertices.remove(v)
    12028             vector = m.column(v)
    12029             for i in vertices:
    12030                 code[i].append(vector[i])
    12031                 if vector[i]:
    12032                     pred[i] = v
    12033             add_element(v)
    12034    
     11994        REFERENCES:
     11995       
     11996        .. [HMPV00] Habib, McConnell, Paul and Viennot. Lex-BFS and Partition
     11997          Refinement, with Applications to Transitive Orientation, Interval
     11998          Graph Recognition and Consecutive Ones Testing. TCS 234, 2000.
     11999        """
     12000        n = self.order()
     12001        perm_inv = self.vertices()
     12002        perm = dict(zip(perm_inv,range(n)))
     12003
     12004        if initial_vertex is not None:
     12005            i = perm[initial_vertex]
     12006            if i != 0:
     12007                v = perm_inv[0]
     12008                perm[initial_vertex], perm[v] = 0, i
     12009                perm_inv[i], perm_inv[0] = v, initial_vertex
     12010
     12011        slice_of = [0]*n
     12012        slice_head = [0]*n
     12013        subslice = [0]*n
     12014        pred = {}
     12015
     12016        k = 1
     12017        for i in range(n):
     12018            old_k = k
     12019            v = perm_inv[i]
     12020            for w in self.neighbors(v):
     12021                j = perm[w]
     12022                if j <= i:
     12023                    continue
     12024                a = slice_of[j]
     12025                if slice_head[a] <= i:
     12026                    slice_head[a] = i+1
     12027                l = slice_head[a]
     12028                if l==n-1 or slice_of[l+1] != a:
     12029                    continue
     12030                if l != j:
     12031                    u = perm_inv[l]
     12032                    perm[w], perm[u] = l, j
     12033                    perm_inv[j], perm_inv[l] = u, w
     12034                slice_head[a] += 1
     12035                if subslice[a] < old_k:
     12036                    subslice[a] = k
     12037                    slice_head[k] = j
     12038                    k += 1
     12039                slice_of[j] = subslice[a]
     12040                pred[w] = v
     12041
     12042        if reverse:
     12043            perm_inv.reverse()
    1203512044        if tree:
    1203612045            from sage.graphs.digraph import DiGraph
    1203712046            g = DiGraph(sparse=True)
    12038             edges = [(id_inv[i], id_inv[pred[i]]) for i in range(self.order()) if pred[i]!=-1]
    12039             g.add_edges(edges)
    12040             return value, g
    12041 
    12042         else:
    12043             return value
     12047            g.add_edges(pred.items())
     12048            return perm_inv, g
     12049        return perm_inv
    1204412050   
    1204512051    ### Constructors
    1204612052
  • sage/graphs/generic_graph.py

    # HG changeset patch
    # User Diego de Estrada <destrada@dc.uba.ar>
    # Date 1332827916 10800
    # Node ID 28d5b5a4ca41134c1fd254257c908664406b92d1
    # Parent  aa34a7311cec0b0d83667442e178fcb6bd81d185
    Trac #11736: Implementation of lex_BFS() in linear time.
    
    diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
    a b  
    1200912009                perm_inv[i], perm_inv[0] = v, initial_vertex
    1201012010
    1201112011        slice_of = [0]*n
    12012         slice_head = [0]*n
    12013         subslice = [0]*n
     12012        slice_head = {0:0}
     12013        subslice = {0:0}
    1201412014        pred = {}
    1201512015
    1201612016        k = 1
     
    1202112021                j = perm[w]
    1202212022                if j <= i:
    1202312023                    continue
     12024                pred[w] = v
    1202412025                a = slice_of[j]
    1202512026                if slice_head[a] <= i:
    1202612027                    slice_head[a] = i+1
    1202712028                l = slice_head[a]
    12028                 if l==n-1 or slice_of[l+1] != a:
    12029                     continue
    1203012029                if l != j:
    1203112030                    u = perm_inv[l]
    1203212031                    perm[w], perm[u] = l, j
     
    1203412033                slice_head[a] += 1
    1203512034                if subslice[a] < old_k:
    1203612035                    subslice[a] = k
    12037                     slice_head[k] = j
     12036                    slice_head[k] = l
     12037                    subslice[k] = 0
    1203812038                    k += 1
    12039                 slice_of[j] = subslice[a]
    12040                 pred[w] = v
     12039                slice_of[l] = subslice[a]
     12040                if l==n-1 or slice_of[l+1] != a:
     12041                    del slice_head[a]
     12042                    del subslice[a]
    1204112043
    1204212044        if reverse:
    1204312045            perm_inv.reverse()