Ticket #13599: trac_13599.patch

File trac_13599.patch, 10.1 KB (added by ncohen, 8 years ago)
  • sage/graphs/graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1350219732 -7200
    # Node ID 8054fcd6b8975b707a2424f2ea43c613758b7963
    # Parent  f58cebb10eeeb8e1fcaed9f36f953f475c338f95
    Bug in Graph.is_cartesian_product
    
    diff --git a/sage/graphs/graph.py b/sage/graphs/graph.py
    a b  
    46144614
    46154615        return D[0] == "Prime" and len(D[1]) == self.order()
    46164616
    4617     def is_cartesian_product(self, certificate = False):
    4618         r"""
    4619         Tests whether ``self`` is a cartesian product of graphs.
    4620 
    4621         INPUT:
    4622 
    4623         - ``certificate`` (boolean) -- if ``certificate = False`` (default) the
    4624           method only returns ``True`` or ``False`` answers. If ``certificate =
    4625           True``, the ``True`` answers are replaced by the list of the factors of
    4626           the graph.
    4627 
    4628         .. SEEALSO::
    4629 
    4630             - :meth:`~sage.graphs.generic_graph.GenericGraph.cartesian_product`
    4631 
    4632             - :mod:`~sage.graphs.graph_decompositions.graph_products` -- a
    4633               module on graph products.
    4634 
    4635         EXAMPLE:
    4636 
    4637         The Petersen graph is prime::
    4638 
    4639             sage: g = graphs.PetersenGraph()
    4640             sage: g.is_cartesian_product()
    4641             False
    4642 
    4643         A 2d grid is the product of paths::
    4644 
    4645             sage: g = graphs.Grid2dGraph(5,5)
    4646             sage: p1, p2 = g.is_cartesian_product(certificate = True)
    4647             sage: p1.is_isomorphic(graphs.PathGraph(5))
    4648             True
    4649             sage: p2.is_isomorphic(graphs.PathGraph(5))
    4650             True
    4651 
    4652         And of course, we find the factors back when we build a graph from a
    4653         product::
    4654 
    4655             sage: g = graphs.PetersenGraph().cartesian_product(graphs.CycleGraph(3))
    4656             sage: g1, g2 = g.is_cartesian_product(certificate = True)
    4657             sage: any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
    4658             True
    4659             sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])
    4660             True
    4661         """
    4662         from sage.graphs.graph_decompositions.graph_products import is_cartesian_product
    4663         return is_cartesian_product(self, certificate = certificate)
    4664 
    4665 
    46664617    def _gomory_hu_tree(self, vertices=None, method="FF"):
    46674618        r"""
    46684619        Returns a Gomory-Hu tree associated to self.
     
    49334884
    49344885        return classes_b
    49354886
     4887
    49364888# Aliases to functions defined in Cython modules
    49374889import types
    49384890
     
    49534905import sage.graphs.cliquer
    49544906Graph.cliques_maximum = types.MethodType(sage.graphs.cliquer.all_max_clique, None, Graph)
    49554907
     4908import sage.graphs.graph_decompositions.graph_products
     4909Graph.is_cartesian_product = types.MethodType(sage.graphs.graph_decompositions.graph_products.is_cartesian_product, None, Graph)
     4910
    49564911def compare_edges(x, y):
    49574912    """
    49584913    This function has been deprecated.
  • sage/graphs/graph_decompositions/graph_products.pyx

    diff --git a/sage/graphs/graph_decompositions/graph_products.pyx b/sage/graphs/graph_decompositions/graph_products.pyx
    a b  
    22Products of graphs
    33
    44This module gathers everything related to graph products. At the moment it
    5 contains different implementations of recognition algorithms for graphs that can
    6 be written as a cartesian product of smaller ones.
     5contains an implementation of a recognition algorithm for graphs that can be
     6written as a cartesian product of smaller ones.
    77
    88References:
    99
     
    2828  if and only if :
    2929
    3030  - `g=g'` and `hh'\in H`; or
    31   - `h=h'` and `gg'\in H`
     31  - `h=h'` and `gg'\in G`
    3232
    3333Two remarks follow :
    3434
     
    4646unique. What is explained below can be found in the book *Handbook of Product
    4747Graphs* [HIK11]_.
    4848
    49 Everything is actually based on a simple observation. Given a graph `G`, finding
     49Everything is actually based on simple observations. Given a graph `G`, finding
    5050out whether `G` can be written as the product of several graphs can be attempted
    5151by trying to color its edges according to some rules. Indeed, if we are to color
    5252the edges of `G` in such a way that each color class represents a factor of `G`,
     
    111111    \put(-55,0){\makebox(0,0)[r]{$u_2=(g',h)$}}
    112112    \end{picture}
    113113
    114   As a corollary, we also know that:
     114  **1st criterion** : As a corollary, we know that:
    115115
    116116  #. If two vertices `u,v` have a *unique* common neighbor `x`, then `ux` and
    117      `uv` have the same color.
     117     `xv` have the same color.
    118118
    119119  #. If two vertices `u, v` have more that two common neighbors `x_1, ...,
    120120     x_k` then all edges between the `x_i` and the vertices of `u,v` have the
    121121     same color. This is also a consequence of the first remark.
    122122
     123  **2nd criterion** : if two edges `uv` and `u'v'` of the product graph
     124  `G\square H` are such that `d(u,u')+d(v,v')\neq d(u,v') + d(v,u')` then the
     125  two edges `uv` and `u'v'` necessarily have the same color.
     126
     127    This is a consequence of the fact that for any two vertices `u,v` of
     128    `G\square H` (where `u=(u_G,u_H)` and `v=(v_G,v_H)`), we have `d(u,v) =
     129    d_G(u_G,v_G)+d_H(u_H,v_H)`. Indeed, a shortest path from `u` to `v` in
     130    `G\square H` contains the information of a shortest path from `u_G` to `v_G`
     131    in `G`, and a shortest path from `u_H` to `v_H` in `H`.
     132
    123133The algorithm
    124134^^^^^^^^^^^^^
    125135
     
    135145
    136146Then again, please refer to [HIK11]_ for any technical question.
    137147
     148To Do
     149^^^^^
     150
     151This implementation is made at Python level, and some parts of the algorithm
     152could be rewritten in Cython to save time. Especially when enumerating all pairs
     153of edges and computing their distances. This can easily be done in C with the
     154functions from the :mod:`sage.graphs.distances_all_pairs` module.
     155
    138156Methods
    139157-------
    140158"""
     
    146164#                         http://www.gnu.org/licenses/                        *
    147165#******************************************************************************
    148166
    149 def is_cartesian_product(g, certificate = False):
     167def is_cartesian_product(g, certificate = False, relabeling = False):
    150168    r"""
    151     Tests whether the graph can be factorized.
     169    Tests whether the graph is a cartesian product.
    152170
    153171    INPUT:
    154172
     
    157175      True``, the ``True`` answers are replaced by the list of the factors of
    158176      the graph.
    159177
     178    - ``relabeling`` (boolean) -- if ``relabeling = True`` (implies
     179      ``certificate = True``), the method also returns a dictionary associating
     180      to each vertex its natural coordinates as a vertex of a product graph. If
     181      `g` is not a cartesian product, ``None`` is returned instead.
     182
     183      This is set to ``False`` by default.
     184
    160185    .. SEEALSO::
    161186
    162         - :meth:`~sage.graphs.generic_graph.GenericGraph.cartesian_product`
     187        - :meth:`sage.graphs.generic_graph.GenericGraph.cartesian_product`
     188
     189        - :mod:`~sage.graphs.graph_decompositions.graph_products` -- a module on
     190          graph products.
     191
     192    .. NOTE::
     193
     194        This algorithm may run faster whenever the graph's vertices are integers
     195        (see :meth:`~sage.graphs.generic_graph.GenericGraph.relabel`). Give it a
     196        try if it is too slow !
    163197
    164198    EXAMPLE:
    165199
     
    179213        sage: p2.is_isomorphic(graphs.PathGraph(5))
    180214        True
    181215
     216    Forgetting the graph's labels, then finding them back::
     217
     218        sage: g.relabel()
     219        sage: g.is_cartesian_product(g, relabeling = True)
     220        (True, {0: (0, 0), 1: (0, 1), 2: (0, 2), 3: (0, 3),
     221                4: (0, 4), 5: (5, 0), 6: (5, 1), 7: (5, 2),
     222                8: (5, 3), 9: (5, 4), 10: (10, 0), 11: (10, 1),
     223                12: (10, 2), 13: (10, 3), 14: (10, 4), 15: (15, 0),
     224                16: (15, 1), 17: (15, 2), 18: (15, 3), 19: (15, 4),
     225                20: (20, 0), 21: (20, 1), 22: (20, 2), 23: (20, 3),
     226                24: (20, 4)})
     227
    182228    And of course, we find the factors back when we build a graph from a
    183229    product::
    184230
     
    188234        True
    189235        sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])
    190236        True
     237
     238    TESTS:
     239
     240    Wagner's Graph (:trac:`13599`)::
     241
     242        sage: g = graphs.WagnerGraph()
     243        sage: g.is_cartesian_product()
     244        False
    191245    """
     246    if relabeling:
     247        certificate = True
     248
    192249    from sage.rings.integer import Integer
    193250    H = g
    194251
    195252    # Of course the number of vertices of g can not be prime !
    196253    if Integer(g.order()).is_prime():
    197         return False
     254        return (False, None) if relabeling else False
    198255    if not g.is_connected():
    199256        raise ValueError("The graph must be connected !")
    200257
     
    255312            else:
    256313                h.add_path([r(u,x) for x in intersect] + [r(v,x) for x in intersect])
    257314
     315    # Edges uv and u'v' such that d(u,u')+d(v,v') != d(u,v')+d(v,u') are also
     316    # equivalent
     317
     318    edges = g.edges(labels = False)
     319    d = g.distance_all_pairs()
     320    for i,(u,v) in enumerate(edges):
     321        du = d[u]
     322        dv = d[v]
     323        for j in range(i+1,len(edges)):
     324            uu,vv = edges[j]
     325            if du[uu]+dv[vv] != du[vv] + dv[uu]:
     326                h.add_edge(r(u,v),r(uu,vv))
     327
    258328    # Gathering the connected components, relabeling the vertices on-the-fly
    259329    edges = map(lambda x:map(lambda y : (t[y[0]],t[y[1]]),x),h.connected_components())
    260330
     331    #Print the graph, distinguishing the edges according to their color classes
     332    #
     333    #from sage.plot.colors import rainbow
     334    #g.show(edge_colors = dict(zip(rainbow(len(edges)),edges)))
     335
    261336    # Only one connected component ?
    262337    if len(edges) == 1:
    263         return False
     338        return (False, None) if relabeling else False
    264339
    265340    # Building the list of factors
    266341    factors = []
     
    275350        answer = answer.cartesian_product(factors[i])
    276351
    277352    # Checking that the resulting graph is indeed isomorphic to what we have.
    278     if not answer.is_isomorphic(g):
     353    isiso, dictt = g.is_isomorphic(answer, certify = True)
     354    if not isiso:
    279355        raise ValueError("Something weird happened during the algorithm... "+
    280356                         "Please report the bug and give us the graph instance"+
    281357                         " that made it fail !!!")
    282 
     358    if relabeling:
     359        return isiso, dictt
    283360    if certificate:
    284361        return factors
    285362    else: