Ticket #7662: trac_7662.patch

File trac_7662.patch, 7.7 KB (added by ncohen, 12 years ago)
  • sage/graphs/generic_graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1280750465 -28800
    # Node ID f0aa9edf0089ad1f7267574dcd49d7bb3ef770ab
    # Parent  e369cc8bfa30fbab80056966a4d484c1eb2766f6
    trac 7662 -- Updating is_cordal to return a certificate (peo or hole)
    
    diff -r e369cc8bfa30 -r f0aa9edf0089 sage/graphs/generic_graph.py
    a b  
    87968796                vertices.append(v)
    87978797        return self.subgraph(vertices=vertices, inplace=inplace)
    87988798
    8799     def is_chordal(self):
     8799    def is_chordal(self, certificate = False):
    88008800        r"""
    88018801        Tests whether the given graph is chordal.
    88028802   
    8803         A Graph `G` is said to be chordal if it contains no induced
    8804         hole. Being chordal is equivalent to having an elimination
    8805         order on the vertices such that the neighborhood of each
    8806         vertex, before being removed from the graph, is a complete
    8807         graph [Fulkerson65]_.
    8808 
    8809         Such an ordering is called a Perfect Elimination Order.
     8803        A Graph `G` is said to be chordal if it contains no induced hole (a
     8804        cycle of length at least 4).
     8805
     8806        Alternatively, chordality can be defined using a Perfect Elimination
     8807        Order :
     8808
     8809        A Perfect Elimination Order of a graph `G` is an ordering `v_1,...,v_n`
     8810        of its vertex set such that for all `i`, the neighbors of `v_i` whose
     8811        index is greater that `i` induce a complete subgraph in `G`. Hence, the
     8812        graph `G` can be totally erased by successively removing vertices whose
     8813        neighborhood is a clique (also called *simplicial* vertices)
     8814        [Fulkerson65]_.
     8815
     8816        (It can be seen that if `G` contains an induced hole, then it can not
     8817        have a perfect elimination order. Indeed, if we write `h_1,...,h_k` the
     8818        `k` vertices of such a hole, then the first of those vertices to be
     8819        removed would have two non-adjacent neighbors in the graph.)
     8820
     8821        A Graph is then chordal if and only if it has a Perfect Elimination
     8822        Order.
     8823
     8824        INPUT:
     8825
     8826        - ``certificate`` (boolean) -- Whether to return a certificate.
     8827
     8828            * If ``certificate = False`` (default), returns ``True`` or
     8829              ``False`` accordingly.
     8830
     8831            * If ``certificate = True``, returns :
     8832
     8833                * ``(True, peo)`` when the graph is chordal, where ``peo`` is a
     8834                  perfect elimination order of its vertices.
     8835
     8836                * ``(False, Hole)`` when the graph is not chordal, where
     8837                  ``Hole`` (a ``Graph`` object) is an induced subgraph of
     8838                  ``self`` isomorphic to a hole.
    88108839   
    88118840        ALGORITHM:
    88128841   
    8813         This algorithm works through computing a Lex BFS on the
    8814         graph, then checking whether the order is a Perfect
    8815         Elimination Order by computing for each vertex `v` the
    8816         subgraph induces by its non-deleted neighbors, then
    8817         testing whether this graph is complete.
    8818    
    8819         This problem can be solved in `O(m)` [Rose75]_ ( where `m`
    8820         is the number of edges in the graph ) but this
    8821         implementation is not linear because of the complexity of
    8822         Lex BFS. Improving Lex BFS to linear complexity would make
    8823         this algorithm linear.
    8824    
    8825         The complexity of this algorithm is equal to the
    8826         complexity of the implementation of Lex BFS.
     8842        This algorithm works through computing a Lex BFS on the graph, then
     8843        checking whether the order is a Perfect Elimination Order by computing
     8844        for each vertex `v` the subgraph induces by its non-deleted neighbors,
     8845        then testing whether this graph is complete.
     8846   
     8847        This problem can be solved in `O(m)` [Rose75]_ ( where `m` is the number
     8848        of edges in the graph ) but this implementation is not linear because of
     8849        the complexity of Lex BFS. Improving Lex BFS to linear complexity would
     8850        make this algorithm linear.
     8851   
     8852        The complexity of this algorithm is equal to the complexity of the
     8853        implementation of Lex BFS.
    88278854   
    88288855        EXAMPLES:
    88298856   
     
    88468873            sage: (2*g).is_chordal()
    88478874            True
    88488875
     8876        Let us check the certificate given by Sage is indeed a perfect elimintion order::
     8877
     8878            sage: (_, peo) = g.is_chordal(certificate = True)
     8879            sage: for v in peo:
     8880            ...       if not g.subgraph(g.neighbors(v)).is_clique():
     8881            ...            print "This should never happen !"
     8882            ...       g.delete_vertex(v)
     8883            sage: print "Everything is fine !"
     8884            Everything is fine !
    88498885
    88508886        Of course, the Petersen Graph is not chordal as it has girth 5 ::
    88518887   
     
    88548890            5
    88558891            sage: g.is_chordal()
    88568892            False
     8893
     8894        We can even obtain such a cycle as a certificate ::
     8895
     8896            sage: (_, hole) = g.is_chordal(certificate = True)
     8897            sage: hole
     8898            Subgraph of (Petersen graph): Graph on 5 vertices
     8899            sage: hole.is_isomorphic(graphs.CycleGraph(5))
     8900            True
    88578901   
    88588902        REFERENCES:
    88598903   
     
    88688912          Vol. 15, number 3, pages 835--855
    88698913        """
    88708914
     8915        # If the graph is not connected, we are computing the result on each component
    88718916        if not self.is_connected():
    8872             for gg in self.connected_components_subgraphs():
    8873                 if not gg.is_chordal():
    8874                     return False
    8875 
    8876             return True
    8877 
    8878    
     8917
     8918            # If the user wants a certificate, we had no choice but to
     8919            # collect the perfect elimination orders... But we return
     8920            # a hole immediately if we find any !
     8921            if certificate:
     8922                peo = []
     8923                for gg in self.connected_components_subgraphs():
     8924
     8925                    b, certif = gg.is_chordal(certificate = True)
     8926                    if not b:
     8927                        return certif
     8928                    else:
     8929                        peo.extend(certif)
     8930                   
     8931                return True, peo
     8932
     8933            # One line if no certificate is requested
     8934            else:
     8935                return all( gg.is_chordal() for gg in self.connected_components_subgraphs() )
     8936
    88798937        peo,t_peo = self.lex_BFS(tree=True)
    8880    
     8938
    88818939        g = self.copy()
    8882    
     8940        peo.reverse()
     8941   
     8942        # Remembering the (closed) neighborhoods of each vertex
    88838943        from sage.combinat.subset import Subsets
    88848944        neighbors_subsets = dict([(v,Subsets(self.neighbors(v)+[v])) for v in self.vertex_iterator()])
    88858945   
    8886         while peo:
    8887             v = peo.pop()
     8946        # Iteratively removing vertices and checking everything is fine.
     8947        for v in peo:
     8948
    88888949            if t_peo.out_degree(v)>0 and g.neighbors(v) not in neighbors_subsets[t_peo.neighbor_out_iterator(v).next()]:
    8889                 return False
     8950
     8951                if certificate:
     8952
     8953                    # In this case, let us take two nonadjacent neighbors of v
     8954
     8955                    x = t_peo.neighbor_out_iterator(v).next()
     8956                    S = neighbors_subsets[x]
     8957
     8958                    for y in g.neighbors(v):
     8959                        if [y] not in S:
     8960                            break
     8961
     8962                    g.delete_vertex(v)
     8963
     8964                    # Our hole is v + (a shortest path between x and y
     8965                    # not containing v)
     8966
     8967                    return (False, self.subgraph([v] + g.shortest_path(x,y)))
     8968                else:
     8969                    return False
     8970
    88908971            g.delete_vertex(v)
    8891         return True
     8972
     8973        if certificate:
     8974            return True, peo
     8975
     8976        else:
     8977            return True
    88928978
    88938979    def is_interval(self, certificate = False):
    88948980        r"""