Ticket #10432: trac_10432.patch

File trac_10432.patch, 17.6 KB (added by ncohen, 9 years ago)
  • sage/combinat/posets/posets.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1291575004 -3600
    # Node ID e8203abc9c19aa7850cf3187099ace78303c1d1f
    # Parent  063ffd2a1aa7c0aaf2f7548513dc8ee546a0a108
    trac 10432 - DiGraph.is_directed_acyclic in Cython (--> without NetworX) and its certificates
    
    diff -r 063ffd2a1aa7 -r e8203abc9c19 sage/combinat/posets/posets.py
    a b  
    998998            sage: P = Posets.SymmetricGroupBruhatOrderPoset(4)
    999999       
    10001000            sage: [(v,P.rank(v)) for v in P]
    1001             [(1234, 0),
    1002              (1243, 1),
     1001            [(1234, 0), 
     1002             (1324, 1),
    10031003            ...
    1004              (4312, 5),
     1004             (4231, 5),
    10051005             (4321, 6)]
    10061006        """
    10071007        if element is None:
     
    14301430       
    14311431            sage: B = Posets.BooleanLattice(4)
    14321432            sage: B.order_filter([3,8])
    1433             [8, 9, 10, 3, 11, 12, 13, 14, 7, 15]
     1433            [3, 7, 8, 9, 10, 11, 12, 13, 14, 15]
    14341434        """
    14351435        vertices = sorted(map(self._element_to_vertex,elements))
    14361436        of = self._hasse_diagram.order_filter(vertices)
     
    14441444       
    14451445            sage: B = Posets.BooleanLattice(4)
    14461446            sage: B.principal_order_filter(2)
    1447             [2, 10, 3, 11, 6, 14, 7, 15]
     1447            [2, 3, 6, 7, 10, 11, 14, 15]
    14481448        """
    14491449        return self.order_filter([x])
    14501450
     
    14591459       
    14601460            sage: B = Posets.BooleanLattice(4)
    14611461            sage: B.order_ideal([7,10])
    1462             [0, 8, 1, 2, 10, 3, 4, 5, 6, 7]
     1462            [0, 1, 2, 3, 4, 5, 6, 7, 8, 10]
    14631463        """
    14641464        vertices = map(self._element_to_vertex,elements)
    14651465        oi = self._hasse_diagram.order_ideal(vertices)
  • sage/geometry/fan.py

    diff -r 063ffd2a1aa7 -r e8203abc9c19 sage/geometry/fan.py
    a b  
    9898:meth:`~sage.geometry.fan.RationalPolyhedralFan.cones`::
    9999
    100100    sage: [cone.ambient_ray_indices() for cone in fan1.cones(2)]
    101     [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (0, 4),
    102      (2, 4), (3, 4), (3, 5), (4, 5), (0, 5), (1, 5)]
     101    [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (0, 4), 
     102     (2, 4), (3, 4), (1, 5), (3, 5), (4, 5), (0, 5)]
    103103
    104104In fact, you don't have to type ``.cones``::
    105105
    106106    sage: [cone.ambient_ray_indices() for cone in fan1(2)]
    107107    [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (0, 4),
    108      (2, 4), (3, 4), (3, 5), (4, 5), (0, 5), (1, 5)]
     108     (2, 4), (3, 4), (1, 5), (3, 5), (4, 5), (0, 5)]
    109109
    110110You may also need to know the inclusion relations between all of the cones of
    111111the fan. In this case check out
  • sage/graphs/base/c_graph.pyx

    diff -r 063ffd2a1aa7 -r e8203abc9c19 sage/graphs/base/c_graph.pyx
    a b  
    26632663        cdef set b = set(self.depth_first_search(v, reverse=True))
    26642664        return list(a & b)
    26652665
     2666    def is_directed_acyclic(self, certificate = False):
     2667        r"""
     2668        Returns whether the graph is both directed and acylic (possibly with a
     2669        certificate)
     2670
     2671
     2672        INPUT:
     2673
     2674        - ``certificate`` -- whether to return a certificate (``False`` by
     2675          default).
     2676
     2677        OUTPUT:
     2678
     2679        When ``certificate=False``, returns a boolean value. When
     2680        ``certificate=True`` :
     2681
     2682            * If the graph is acyclic, returns a pair ``(True, ordering)`` where
     2683              ``ordering`` is a list of the vertices such that ``u`` appears
     2684              before ``v`` in ``ordering`` if ``u, v`` is an edge.
     2685
     2686            * Else, returns a pair ``(False, cycle)`` where ``cycle`` is a list
     2687              of vertices representing a circuit in the graph.
     2688
     2689        .. NOTE::
     2690
     2691            The graph is assumed to be directed. An exception is raised if it is
     2692            not.
     2693
     2694        EXAMPLES:
     2695
     2696        At first, the following graph is acyclic::
     2697       
     2698            sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10] })
     2699            sage: D.plot(layout='circular').show()
     2700            sage: D.is_directed_acyclic()
     2701            True
     2702       
     2703        Adding an edge from `9` to `7` does not change it::
     2704       
     2705            sage: D.add_edge(9,7)
     2706            sage: D.is_directed_acyclic()
     2707            True
     2708
     2709        We can obtain as a proof an ordering of the vertices such that `u`
     2710        appears before `v` if `uv` is an edge of the graph::
     2711
     2712            sage: D.is_directed_acyclic(certificate = True)
     2713            (True, [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10])
     2714       
     2715        Adding an edge from 7 to 4, though, makes a difference::
     2716       
     2717            sage: D.add_edge(7,4)
     2718            sage: D.is_directed_acyclic()
     2719            False
     2720
     2721        Indeed, it creates a circuit `7, 4, 5`::
     2722
     2723            sage: D.is_directed_acyclic(certificate = True)
     2724            (False, [7, 4, 5])
     2725
     2726        Checking acyclic graphs are indeed acyclic ::
     2727
     2728            sage: def random_acyclic(n, p):
     2729            ...    g = graphs.RandomGNP(n, p)
     2730            ...    h = DiGraph()
     2731            ...    h.add_edges([ ((u,v) if u<v else (v,u)) for u,v,_ in g.edges() ])
     2732            ...    return h
     2733            ...
     2734            sage: all( random_acyclic(100, .2).is_directed_acyclic()    # long time
     2735            ...        for i in range(50))                              # long time
     2736            True
     2737        """
     2738
     2739        if not self._directed:
     2740            raise ValueError("The graph should be directed !")
     2741
     2742        # Vertices that have already been seen
     2743        cdef bitset_t seen
     2744        bitset_init(seen, (<CGraph>self._cg).active_vertices.size)
     2745        bitset_set_first_n(seen, 0)
     2746         
     2747        # Activated vertices
     2748        cdef bitset_t activated
     2749        bitset_init(activated, (<CGraph>self._cg).active_vertices.size)
     2750        bitset_set_first_n(activated, (<CGraph>self._cg).active_vertices.size)
     2751
     2752        # Vertices whose neighbors have already been added to the stack
     2753        cdef bitset_t tried
     2754        bitset_init(tried, (<CGraph>self._cg).active_vertices.size)
     2755        bitset_set_first_n(tried, 0)
     2756         
     2757        # Parent of a vertex in the discovery tree
     2758        cdef dict parent = {}
     2759         
     2760        # The vertices left to be visited
     2761        cdef list stack = []
     2762
     2763        # Final ordering, if the graph turns out to be acyclic
     2764        cdef list ordering = []
     2765
     2766        # Circuit, if the graph turns out to contain one
     2767        cdef list cycle
     2768         
     2769        # We try any vertex as the source of the exploration tree
     2770        for v in (<CGraph>self._cg).verts():
     2771                 
     2772            # We are not interested in trying de-activated vertices
     2773            if bitset_not_in(activated, v):
     2774                continue
     2775         
     2776            stack = [v]
     2777            bitset_add(seen, v)
     2778         
     2779            # For as long as some vertices are to be visited
     2780            while stack:
     2781         
     2782                # We take the last one (depth-first search)
     2783                u = stack.pop(-1)
     2784         
     2785                # If we never tried it, we put it at the end of the stack again,
     2786                # but remember we tried it once.
     2787                if bitset_not_in(tried, u):
     2788                    bitset_add(tried, u)
     2789                    bitset_add(seen, u)
     2790                    stack.append(u)
     2791         
     2792                # If we tried all the path starting from this vertex already, it
     2793                # means it leads to no circuit. We can remove it, and go to the
     2794                # next one
     2795                else:
     2796                    ordering.insert(0, vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg))
     2797                    bitset_discard(seen, u)
     2798                    bitset_discard(activated, u)
     2799                    continue
     2800         
     2801                # For each out-neighbor of the current vertex
     2802                for uu in self._cg.out_neighbors(u):
     2803         
     2804                    # If we have found a new vertex, we put it at the end of the
     2805                    # stack. We ignored de-activated vertices.
     2806                    if bitset_not_in(seen, uu):
     2807                        if bitset_in(activated, uu):
     2808                            parent[uu] = u
     2809                            stack.append(uu)
     2810         
     2811                    # If we have already met this vertex, it means we have
     2812                    # found a circuit !
     2813                    else:
     2814
     2815                        bitset_free(seen)
     2816                        bitset_free(activated)
     2817                        bitset_free(tried)
     2818                       
     2819                        if not certificate:
     2820                            return False
     2821         
     2822                        # We build it, then return it
     2823                        # // answer = [u]
     2824                        cycle = [vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg)]
     2825                       
     2826                        tmp = u
     2827                        while u != uu:
     2828                            u = parent.get(u,uu)
     2829                            cycle.append(vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg))
     2830         
     2831                        cycle.reverse()
     2832                        return (False, cycle)
     2833         
     2834            # Each time we have explored all the descendants of a vertex v and
     2835            # met no circuit, we de-activate all these vertices, as we know we
     2836            # do not need them anyway.
     2837            for v in (<CGraph>self._cg).verts():
     2838                if bitset_in(seen, v):
     2839                    bitset_discard(seen, v)
     2840                    bitset_discard(activated, v)
     2841                    bitset_add(tried, v)
     2842
     2843
     2844        # No Cycle... Good news ! Let's return it.
     2845        bitset_free(seen)
     2846        bitset_free(activated)
     2847        bitset_free(tried)
     2848       
     2849        if certificate:
     2850            return (True, ordering)
     2851        else:
     2852            return True
     2853
    26662854cdef class Search_iterator:
    26672855    r"""
    26682856    An iterator for traversing a (di)graph.
  • sage/graphs/digraph.py

    diff -r 063ffd2a1aa7 -r e8203abc9c19 sage/graphs/digraph.py
    a b  
    758758
    759759    ### Properties
    760760
    761     def is_directed_acyclic(self):
     761    def is_directed_acyclic(self, certificate = False):
    762762        """
    763763        Returns whether the digraph is acyclic or not.
    764764       
    765         A directed graph is acyclic if for any vertex v, there is no
    766         directed path that starts and ends at v. Every directed acyclic
    767         graph (dag) corresponds to a partial ordering of its vertices,
    768         however multiple dags may lead to the same partial ordering.
     765        A directed graph is acyclic if for any vertex `v`, there is no directed
     766        path that starts and ends at `v`. Every directed acyclic graph (DAG)
     767        corresponds to a partial ordering of its vertices, however multiple dags
     768        may lead to the same partial ordering.
     769
     770        INPUT:
     771
     772        - ``certificate`` -- whether to return a certificate (``False`` by
     773          default).
     774
     775        OUTPUT:
     776
     777            * When ``certificate=False``, returns a boolean value. 
     778
     779            * When ``certificate=True`` :
     780
     781                * If the graph is acyclic, returns a pair ``(True, ordering)``
     782                  where ``ordering`` is a list of the vertices such that ``u``
     783                  appears before ``v`` in ``ordering`` if ``u, v`` is an edge.
     784
     785                * Else, returns a pair ``(False, cycle)`` where ``cycle`` is a
     786                  list of vertices representing a circuit in the graph.
    769787       
    770         EXAMPLES::
     788        EXAMPLES:
     789
     790        At first, the following graph is acyclic::
    771791       
    772792            sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10] })
    773793            sage: D.plot(layout='circular').show()
    774794            sage: D.is_directed_acyclic()
    775795            True
    776796       
    777         ::
     797        Adding an edge from `9` to `7` does not change it::
    778798       
    779799            sage: D.add_edge(9,7)
    780800            sage: D.is_directed_acyclic()
    781801            True
     802
     803        We can obtain as a proof an ordering of the vertices such that `u`
     804        appears before `v` if `uv` is an edge of the graph::
     805
     806            sage: D.is_directed_acyclic(certificate = True)
     807            (True, [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10])
    782808       
    783         ::
     809        Adding an edge from 7 to 4, though, makes a difference::
    784810       
    785811            sage: D.add_edge(7,4)
    786812            sage: D.is_directed_acyclic()
    787813            False
     814
     815        Indeed, it creates a circuit `7, 4, 5`::
     816
     817            sage: D.is_directed_acyclic(certificate = True)
     818            (False, [7, 4, 5])
     819
     820        Checking acyclic graphs are indeed acyclic ::
     821
     822            sage: def random_acyclic(n, p):
     823            ...    g = graphs.RandomGNP(n, p)
     824            ...    h = DiGraph()
     825            ...    h.add_edges([ ((u,v) if u<v else (v,u)) for u,v,_ in g.edges() ])
     826            ...    return h
     827            ...
     828            sage: all( random_acyclic(100, .2).is_directed_acyclic()    # long time
     829            ...        for i in range(50))                              # long time
     830            True
    788831        """
    789         try:
    790             S = self.topological_sort()
    791             return True
    792         except:
    793             return False
     832        return self._backend.is_directed_acyclic(certificate = certificate)
    794833
    795834    def to_directed(self):
    796835        """
     
    20362075
    20372076    ### Directed Acyclic Graphs (DAGs)
    20382077
    2039     def topological_sort(self):
     2078    def topological_sort(self, implementation = "default"):
    20402079        """
    2041         Returns a topological sort of the digraph if it is acyclic, and
    2042         raises a TypeError if the digraph contains a directed cycle.
     2080        Returns a topological sort of the digraph if it is acyclic, and raises a
     2081        TypeError if the digraph contains a directed cycle.
    20432082       
    2044         A topological sort is an ordering of the vertices of the digraph
    2045         such that each vertex comes before all of its successors. That is,
    2046         if u comes before v in the sort, then there may be a directed path
    2047         from u to v, but there will be no directed path from v to u.
     2083        A topological sort is an ordering of the vertices of the digraph such
     2084        that each vertex comes before all of its successors. That is, if `u`
     2085        comes before `v` in the sort, then there may be a directed path from `u`
     2086        to `v`, but there will be no directed path from `v` to `u`.
     2087
     2088        INPUT:
     2089
     2090        - ``implementation`` -- Use the default Cython implementation
     2091          (``implementation = default``) or the NetworkX library
     2092          (``implementation = "NetworkX"``)
     2093
     2094        .. SEEALSO::
     2095
     2096            - :meth:`is_directed_acyclic` -- Tests whether a directed graph is
     2097              acyclic (can also join a certificate -- a topological sort or a
     2098              circuit in the graph1).
    20482099       
    20492100        EXAMPLES::
    2050        
     2101
    20512102            sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10] })
    20522103            sage: D.plot(layout='circular').show()
    20532104            sage: D.topological_sort()
     
    20582109            sage: D.add_edge(9,7)
    20592110            sage: D.topological_sort()
    20602111            [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10]
    2061        
     2112
     2113        Using the NetworkX implementation ::
     2114
     2115            sage: D.topological_sort(implementation = "NetworkX")
     2116            [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10]
     2117
    20622118        ::
    20632119       
    20642120            sage: D.add_edge(7,4)
     
    20792135              [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10]
    20802136              sage: networkx.topological_sort_recursive(N) is None
    20812137              True
     2138
     2139        TESTS:
     2140
     2141        A wrong value for the ``implementation`` keyword::
     2142
     2143            sage: D.topological_sort(implementation = "cloud-reading")
     2144            Traceback (most recent call last):
     2145            ...
     2146            ValueError: implementation must be set to one of "default" or "NetworkX"
    20822147        """
    2083         import networkx
    2084         S = networkx.topological_sort(self.networkx_graph(copy=False))
    2085         if S is None:
    2086             raise TypeError('Digraph is not acyclic-- there is no topological sort.')
     2148
     2149        if implementation == "default":
     2150            b, ordering = self._backend.is_directed_acyclic(certificate = True)
     2151            if b:
     2152                return ordering
     2153            else:
     2154                raise TypeError('Digraph is not acyclic-- there is no topological sort.')
     2155               
     2156        elif implementation == "NetworkX":
     2157            import networkx
     2158            S = networkx.topological_sort(self.networkx_graph(copy=False))
     2159            if S is None:
     2160                raise TypeError('Digraph is not acyclic-- there is no topological sort.')
     2161            else:
     2162                return S
     2163
    20872164        else:
    2088             return S
     2165            raise ValueError("implementation must be set to one of \"default\" or \"NetworkX\"")
    20892166   
    20902167    def topological_sort_generator(self):
    20912168        """
  • sage/homology/cell_complex.py

    diff -r 063ffd2a1aa7 -r e8203abc9c19 sage/homology/cell_complex.py
    a b  
    707707            sage: P = SimplicialComplex(3, [[0, 1], [1,2], [2,3]]).face_poset(); P
    708708            Finite poset containing 7 elements
    709709            sage: P.list()
    710             [(3,), (2,), (2, 3), (1,), (0,), (1, 2), (0, 1)]
     710            [(3,), (2,), (2, 3), (1,), (0,), (0, 1), (1, 2)]
    711711
    712712            sage: S2 = cubical_complexes.Sphere(2)
    713713            sage: S2.face_poset()