Ticket #13599: trac_13599.patch
File trac_13599.patch, 10.1 KB (added by , 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 4614 4614 4615 4615 return D[0] == "Prime" and len(D[1]) == self.order() 4616 4616 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) the4624 method only returns ``True`` or ``False`` answers. If ``certificate =4625 True``, the ``True`` answers are replaced by the list of the factors of4626 the graph.4627 4628 .. SEEALSO::4629 4630  :meth:`~sage.graphs.generic_graph.GenericGraph.cartesian_product`4631 4632  :mod:`~sage.graphs.graph_decompositions.graph_products`  a4633 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 False4642 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 True4649 sage: p2.is_isomorphic(graphs.PathGraph(5))4650 True4651 4652 And of course, we find the factors back when we build a graph from a4653 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 True4659 sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])4660 True4661 """4662 from sage.graphs.graph_decompositions.graph_products import is_cartesian_product4663 return is_cartesian_product(self, certificate = certificate)4664 4665 4666 4617 def _gomory_hu_tree(self, vertices=None, method="FF"): 4667 4618 r""" 4668 4619 Returns a GomoryHu tree associated to self. … … 4933 4884 4934 4885 return classes_b 4935 4886 4887 4936 4888 # Aliases to functions defined in Cython modules 4937 4889 import types 4938 4890 … … 4953 4905 import sage.graphs.cliquer 4954 4906 Graph.cliques_maximum = types.MethodType(sage.graphs.cliquer.all_max_clique, None, Graph) 4955 4907 4908 import sage.graphs.graph_decompositions.graph_products 4909 Graph.is_cartesian_product = types.MethodType(sage.graphs.graph_decompositions.graph_products.is_cartesian_product, None, Graph) 4910 4956 4911 def compare_edges(x, y): 4957 4912 """ 4958 4913 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 2 2 Products of graphs 3 3 4 4 This module gathers everything related to graph products. At the moment it 5 contains different implementations of recognition algorithms for graphs that can6 bewritten as a cartesian product of smaller ones.5 contains an implementation of a recognition algorithm for graphs that can be 6 written as a cartesian product of smaller ones. 7 7 8 8 References: 9 9 … … 28 28 if and only if : 29 29 30 30  `g=g'` and `hh'\in H`; or 31  `h=h'` and `gg'\in H`31  `h=h'` and `gg'\in G` 32 32 33 33 Two remarks follow : 34 34 … … 46 46 unique. What is explained below can be found in the book *Handbook of Product 47 47 Graphs* [HIK11]_. 48 48 49 Everything is actually based on a simple observation. Given a graph `G`, finding49 Everything is actually based on simple observations. Given a graph `G`, finding 50 50 out whether `G` can be written as the product of several graphs can be attempted 51 51 by trying to color its edges according to some rules. Indeed, if we are to color 52 52 the edges of `G` in such a way that each color class represents a factor of `G`, … … 111 111 \put(55,0){\makebox(0,0)[r]{$u_2=(g',h)$}} 112 112 \end{picture} 113 113 114 As a corollary, we alsoknow that:114 **1st criterion** : As a corollary, we know that: 115 115 116 116 #. 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. 118 118 119 119 #. If two vertices `u, v` have more that two common neighbors `x_1, ..., 120 120 x_k` then all edges between the `x_i` and the vertices of `u,v` have the 121 121 same color. This is also a consequence of the first remark. 122 122 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 123 133 The algorithm 124 134 ^^^^^^^^^^^^^ 125 135 … … 135 145 136 146 Then again, please refer to [HIK11]_ for any technical question. 137 147 148 To Do 149 ^^^^^ 150 151 This implementation is made at Python level, and some parts of the algorithm 152 could be rewritten in Cython to save time. Especially when enumerating all pairs 153 of edges and computing their distances. This can easily be done in C with the 154 functions from the :mod:`sage.graphs.distances_all_pairs` module. 155 138 156 Methods 139 157  140 158 """ … … 146 164 # http://www.gnu.org/licenses/ * 147 165 #****************************************************************************** 148 166 149 def is_cartesian_product(g, certificate = False ):167 def is_cartesian_product(g, certificate = False, relabeling = False): 150 168 r""" 151 Tests whether the graph can be factorized.169 Tests whether the graph is a cartesian product. 152 170 153 171 INPUT: 154 172 … … 157 175 True``, the ``True`` answers are replaced by the list of the factors of 158 176 the graph. 159 177 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 160 185 .. SEEALSO:: 161 186 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 ! 163 197 164 198 EXAMPLE: 165 199 … … 179 213 sage: p2.is_isomorphic(graphs.PathGraph(5)) 180 214 True 181 215 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 182 228 And of course, we find the factors back when we build a graph from a 183 229 product:: 184 230 … … 188 234 True 189 235 sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2]) 190 236 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 191 245 """ 246 if relabeling: 247 certificate = True 248 192 249 from sage.rings.integer import Integer 193 250 H = g 194 251 195 252 # Of course the number of vertices of g can not be prime ! 196 253 if Integer(g.order()).is_prime(): 197 return False254 return (False, None) if relabeling else False 198 255 if not g.is_connected(): 199 256 raise ValueError("The graph must be connected !") 200 257 … … 255 312 else: 256 313 h.add_path([r(u,x) for x in intersect] + [r(v,x) for x in intersect]) 257 314 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 258 328 # Gathering the connected components, relabeling the vertices onthefly 259 329 edges = map(lambda x:map(lambda y : (t[y[0]],t[y[1]]),x),h.connected_components()) 260 330 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 261 336 # Only one connected component ? 262 337 if len(edges) == 1: 263 return False338 return (False, None) if relabeling else False 264 339 265 340 # Building the list of factors 266 341 factors = [] … … 275 350 answer = answer.cartesian_product(factors[i]) 276 351 277 352 # 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: 279 355 raise ValueError("Something weird happened during the algorithm... "+ 280 356 "Please report the bug and give us the graph instance"+ 281 357 " that made it fail !!!") 282 358 if relabeling: 359 return isiso, dictt 283 360 if certificate: 284 361 return factors 285 362 else: