Ticket #6679: trac_6679reviewer.patch
File trac_6679reviewer.patch, 35.4 KB (added by , 11 years ago) 


sage/graphs/graph.py
# HG changeset patch # User Minh Van Nguyen <nguyenminh2@gmail.com> # Date 1259691203 28800 # Node ID 6bb946d9b299a5b6ecbca3503f1f8691dc2ddde7 # Parent ba3480f452b56ec298bfd288ba022d3c5cd96c18 trac 6679: reviewer patch diff r ba3480f452b5 r 6bb946d9b299 sage/graphs/graph.py
a b 10022 10022 return chromatic_polynomial(self) 10023 10023 10024 10024 def chromatic_number(self, algorithm="DLX"): 10025 """10025 r""" 10026 10026 Returns the minimal number of colors needed to color the vertices 10027 10027 of the graph `G`. 10028 10028 10029 10029 INPUT: 10030 10030 10031  ``algorithm``  Select s an algorithm10032 10033  If ``algorithm = "DLX"`` ( default ), the chromatic number is computed 10034 through the dancing link algorithm.10035 10036 Computing the chromatic number through the Dancing Link Algorithm is a10037 very slow method, as it computes ALL the possible colorings to check10038 10039 10040  If ``algorithm ="CP"``, the chromatic number is computed10041 through the coefficients of the Chromatic Polynomial.10042 10043 Computing the chromatic number through the chromatic polynomial is a10044 very slow method, which will only be useful for small graphs. 10045 10046  If ``algorithm = "MILP"``, the chromatic number10047 is computed through a Mixed Integer Linear Program.10048 10049 Computing the chromatic number through a Mixed Integer Linear10050 Program may require to install an optional Sage package like GLPK 10051 or CoinOR's CBC.10052 10053 For more functions related to graph coloring, see10054 the ``sage.graphs.graph_coloring`` module.10055 10056 EXAMPLES:: 10057 10058 sage: G = Graph({0: [1,2,3],1:[2]})10031  ``algorithm``  Select an algorithm from the following supported 10032 algorithms: 10033 10034  If ``algorithm="DLX"`` (default), the chromatic number is 10035 computed using the dancing link algorithm. It is 10036 inefficient speedwise to compute the chromatic number through 10037 the dancing link algorithm because this algorithm computes 10038 *all* the possible colorings to check that one exists. 10039 10040  If ``algorithm="CP"``, the chromatic number is computed 10041 using the coefficients of the chromatic polynomial. Again, this 10042 method is inefficient in terms of speed and it only useful for 10043 small graphs. 10044 10045  If ``algorithm="MILP"``, the chromatic number is computed 10046 using a mixed integer linear program. This method requires 10047 you to install an optional Sage package like GLPK or 10048 COINOR's CBC. Of the methods "DLX", "CP", and "MILP", the last 10049 method is the fastest method of the three. 10050 10051 .. SEEALSO:: 10052 10053 For more functions related to graph coloring, see the 10054 module :mod:`sage.graphs.graph_coloring`. 10055 10056 EXAMPLES:: 10057 10058 sage: G = Graph({0: [1, 2, 3], 1: [2]}) 10059 10059 sage: G.chromatic_number(algorithm="DLX") 10060 10060 3 10061 10061 sage: G.chromatic_number(algorithm="MILP") # optional  requires GLPK or CBC … … 10065 10065 10066 10066 TESTS:: 10067 10067 10068 sage: G = Graph({0: [1,2,3],1:[2]})10068 sage: G = Graph({0: [1, 2, 3], 1: [2]}) 10069 10069 sage: G.chromatic_number(algorithm="foo") 10070 10070 Traceback (most recent call last): 10071 10071 ... 10072 ValueError: The `algorithm` variable must be set to either `DLX`, `MILP` or `CP`. 10073 """ 10072 ValueError: The 'algorithm' keyword must be set to either 'DLX', 'MILP' or 'CP'. 10073 """ 10074 # default builtin algorithm; bad performance 10074 10075 if algorithm == "DLX": 10075 10076 from sage.graphs.graph_coloring import chromatic_number 10076 10077 return chromatic_number(self) 10077 10078 # Algorithm with good performance, but requires an optional 10079 # package: choose any of GLPK or CBC. 10078 10080 elif algorithm == "MILP": 10079 10081 from sage.graphs.graph_coloring import vertex_coloring 10080 10082 return vertex_coloring(self, value_only=True) 10081 10083 # another algorithm with bad performance; only good for small graphs 10082 10084 elif algorithm == "CP": 10083 10085 f = self.chromatic_polynomial() 10084 10086 i = 0 … … 10086 10088 i += 1 10087 10089 return i 10088 10090 else: 10089 raise ValueError("The `algorithm` variable must be set to either `DLX`, `MILP` or `CP`.")10091 raise ValueError("The 'algorithm' keyword must be set to either 'DLX', 'MILP' or 'CP'.") 10090 10092 10091 10093 def coloring(self, algorithm="DLX", hex_colors=False): 10092 """10094 r""" 10093 10095 Returns the first (optimal) proper vertexcoloring found. 10094 10096 10095 10097 INPUT: 10096 10098 10097  If ``algorithm = "DLX"`` (default), the chromatic number is computed 10098 through the dancing link algorithm. 10099 10100  If ``algorithm = "MILP"``, the chromatic number 10101 is computed through a Mixed Integer Linear Program. 10102 10103 Computing the chromatic number through a Mixed Integer Linear 10104 Program may require to install an optional Sage package like GLPK 10105 or CoinOR's CBC. 10106 10107  ``hex_colors``  if ``True``, return a dict which can 10108 easily be used for plotting 10109 10110 For more functions related to graph coloring, see 10111 the ``sage.graphs.graph_coloring`` module. 10099  ``algorithm``  Select an algorithm from the following supported 10100 algorithms: 10101 10102  If ``algorithm="DLX"`` (default), the chromatic number is computed 10103 using the dancing link algorithm. 10104 10105  If ``algorithm="MILP"``, the chromatic number is computed using 10106 a mixed integer linear program. This algorithm requires you to 10107 install an optional Sage package like GLPK or COINOR's CBC. 10108 10109  ``hex_colors``  (default: ``False``) if ``True``, return a 10110 dictionary which can easily be used for plotting. 10111 10112 .. SEEALSO:: 10113 10114 For more functions related to graph coloring, see the 10115 module :mod:`sage.graphs.graph_coloring`. 10112 10116 10113 10117 EXAMPLES:: 10114 10118 10115 10119 sage: G = Graph("Fooba") 10116 10117 10120 sage: P = G.coloring(algorithm="MILP"); P # optional  requires GLPK or CBC 10118 10121 [[2, 1, 3], [0, 6, 5], [4]] 10119 10122 sage: P = G.coloring(algorithm="DLX"); P 10120 10123 [[1, 2, 3], [0, 5, 6], [4]] 10121 10124 sage: G.plot(partition=P) 10122 10123 sage: H = G.coloring(hex_colors=True,algorithm="MILP") # optional  requires GLPK or CBC 10124 sage: for c in sorted(H.keys()): # optional  requires GLPK or CBC 10125 ... print c, H[c] # optional  requires GLPK or CBC 10125 sage: H = G.coloring(hex_colors=True, algorithm="MILP") # optional  requires GLPK or CBC 10126 sage: for c in sorted(H.keys()): # optional  requires GLPK or CBC 10127 ... print c, H[c] # optional  requires GLPK or CBC 10126 10128 #0000ff [4] 10127 10129 #00ff00 [0, 6, 5] 10128 10130 #ff0000 [2, 1, 3] 10129 10131 sage: H = G.coloring(hex_colors=True, algorithm="DLX") 10130 10132 sage: for c in sorted(H.keys()): 10131 ... print c, H[c]10133 ... print c, H[c] 10132 10134 #0000ff [4] 10133 10135 #00ff00 [1, 2, 3] 10134 10136 #ff0000 [0, 5, 6] … … 10139 10141 sage: G.coloring(algorithm="foo") 10140 10142 Traceback (most recent call last): 10141 10143 ... 10142 ValueError: The `algorithm` variable must be set to either `DLX` or `MILP`.10144 ValueError: The 'algorithm' keyword must be set to either 'DLX' or 'MILP'. 10143 10145 """ 10144 10146 if algorithm == "MILP": 10145 10147 from sage.graphs.graph_coloring import vertex_coloring 10146 return vertex_coloring(self, hex_colors=hex_colors)10148 return vertex_coloring(self, hex_colors=hex_colors) 10147 10149 elif algorithm == "DLX": 10148 10150 from sage.graphs.graph_coloring import first_coloring 10149 10151 return first_coloring(self, hex_colors=hex_colors) 10150 10152 else: 10151 raise ValueError("The `algorithm` variable must be set to either `DLX` or `MILP`.")10153 raise ValueError("The 'algorithm' keyword must be set to either 'DLX' or 'MILP'.") 10152 10154 10153 10155 ### Centrality 10154 10156 … … 10838 10840 10839 10841 """ 10840 10842 if self.is_directed() or self.has_loops() or self.has_multiple_edges(): 10841 raise ValueError("Self must be an undirected simple graph to have a clique _complex.")10843 raise ValueError("Self must be an undirected simple graph to have a clique complex.") 10842 10844 import sage.homology.simplicial_complex 10843 10845 C = sage.homology.simplicial_complex.SimplicialComplex(self.vertices(),self.cliques_maximal(),maximality_check=True) 10844 10846 C._graph = self 
sage/graphs/graph_coloring.py
diff r ba3480f452b5 r 6bb946d9b299 sage/graphs/graph_coloring.py
a b 2 2 Graph Coloring Functions 3 3 4 4 AUTHORS: 5  Tom Boothby (20080221): Initial version 6  Carlo Hamalainen (20090328): minor change: switch to C++ DLX solver 7  Nathann Cohen (20091024): Coloring methods using Linear Programming 5 6  Tom Boothby (20080221): Initial version 7  Carlo Hamalainen (20090328): minor change: switch to C++ DLX solver 8  Nathann Cohen (20091024): Coloring methods using linear programming 8 9 """ 9 10 10 11 #***************************************************************************** … … 142 143 except RuntimeError: 143 144 raise RuntimeError, "Too much recursion! Graph coloring failed." 144 145 145 def first_coloring(G, n=0, hex_colors=True):146 """146 def first_coloring(G, n=0, hex_colors=False): 147 r""" 147 148 Given a graph, and optionally a natural number `n`, returns 148 149 the first coloring we find with at least `n` colors. 149 150 150 151 INPUT: 151 152 152  ``hex_colors``  When set to ``True`` ( it is ``False`` by default ), 153 the partition returned is a dictionary whose keys are colors and whose 154 values are the color classes ( ideal to be plotted ) 155  ``n``  The minimal number of colors to be tried. 153  ``hex_colors``  (default: ``False``) when set to ``True``, the 154 partition returned is a dictionary whose keys are colors and whose 155 values are the color classes (ideal for plotting). 156 156 157  ``n``  The minimal number of colors to try. 157 158 158 EXAMPLES: 159 EXAMPLES:: 160 159 161 sage: from sage.graphs.graph_coloring import first_coloring 160 sage: G = Graph({0: [1,2,3],1:[2]})161 sage: first_coloring(G, 3)162 {'#00ff00': [1, 3], '#ff0000': [0], '#0000ff': [2]}162 sage: G = Graph({0: [1, 2, 3], 1: [2]}) 163 sage: first_coloring(G, 3) 164 [[1, 3], [0], [2]] 163 165 """ 164 166 o = G.order() 165 for m in range(n,o+1):166 for C in all_graph_colorings(G, m):167 for m in xrange(n, o + 1): 168 for C in all_graph_colorings(G, m): 167 169 if hex_colors: 168 170 return C 169 171 else: … … 240 242 for C in all_graph_colorings(G,n): 241 243 return n 242 244 243 244 def vertex_coloring(self,k=None,value_only=False,hex_colors=False,log=0): 245 """246 Computes the chromatic number of a graph, or tests its `k`colorability247 ( cf. http://en.wikipedia.org/wiki/Graph_coloring )245 def vertex_coloring(g, k=None, value_only=False, hex_colors=False, log=0): 246 r""" 247 Computes the chromatic number of the given graph or tests its 248 `k`colorability. See http://en.wikipedia.org/wiki/Graph_coloring for 249 further details on graph coloring. 248 250 249 251 INPUT: 250 252 251  ``value_only`` ( boolean ) 252  When set to ``True``, only the chromatic number is returned 253  When set to ``False`` (default), a partition of the vertex set into 254 independant sets is returned is possible 253  ``g``  a graph. 255 254 256  ``k`` ( an integer )  Tests whether the graph is `k`colorable.257 The function returns a partition of the vertex set in `k` 258 independentsets if possible and ``False`` otherwise.255  ``k``  (default: ``None``) tests whether the graph is `k`colorable. 256 The function returns a partition of the vertex set in `k` independent 257 sets if possible and ``False`` otherwise. 259 258 260  ``hex_colors``  When set to ``True`` ( it is ``False`` by default ), 261 the partition returned is a dictionary whose keys are colors and whose 262 values are the color classes ( ideal to be plotted ) 259  ``value_only``  (default: ``False``): 263 260 264  ``log`` ( integer )  As vertexcoloring is a `NP`complete problem, 265 its solving may take some time depending on the graph. Use ``log`` to 266 define the level of verbosity you want from the linear program solver. 267 268 By default ``log=0``, meaning that there will be no message printed by the solver. 261  When set to ``True``, only the chromatic number is returned. 269 262 270 OUTPUT : 263  When set to ``False`` (default), a partition of the vertex set into 264 independent sets is returned if possible. 265 266  ``hex_colors``  (default: ``False``) when set to ``True``, the 267 partition returned is a dictionary whose keys are colors and whose 268 values are the color classes (ideal for plotting). 269 270  ``log``  (default: ``0``) as vertexcoloring is an `NP`complete 271 problem, this function may take some time depending on the graph. 272 Use ``log`` to define the level of verbosity you want from the 273 linear program solver. By default ``log=0``, meaning that there will 274 be no message printed by the solver. 275 276 OUTPUT: 271 277 272  If ``k=None`` and ``value_only= None``:273 Returns a partition of the vertex set into the minimum possible of independent sets278  If ``k=None`` and ``value_only=False``, then return a partition of the 279 vertex set into the minimum possible of independent sets. 274 280 275  If ``k=None`` and ``value_only=True``: 276 Returns the chromatic number 281  If ``k=None`` and ``value_only=True``, return the chromatic number. 277 282 278  If ``k`` is set and ``value_only=None`` :279 Returns False if the graph is not `k`colorable, and a partition of the280 vertex set into `k` independent sets otherwise283  If ``k`` is set and ``value_only=None``, return ``False`` if the 284 graph is not `k`colorable, and a partition of the vertex set into 285 `k` independent sets otherwise. 281 286 282  If ``k`` is set and ``value_only=True``: 283 Test whether the graph is `k`colorable and returns ``True`` or ``False`` accordingly 284 287  If ``k`` is set and ``value_only=True``, test whether the graph is 288 `k`colorable, and return ``True`` or ``False`` accordingly. 285 289 286 290 EXAMPLE:: 287 291 288 292 sage: from sage.graphs.graph_coloring import vertex_coloring 289 sage: g =graphs.PetersenGraph()293 sage: g = graphs.PetersenGraph() 290 294 sage: vertex_coloring(g, value_only=True) # optional  requires GLPK or CBC 291 295 3 292 293 296 """ 294 297 from sage.numerical.mip import MixedIntegerLinearProgram 295 298 from sage.plot.colors import rainbow 296 g=self297 299 298 300 # If k==None, tries to find an optimal coloring 299 if k==None: 300 301 # No need to start a linear program if the graph is an independent set or bipartite 302 # 301 if k is None: 302 # No need to start a linear program if the graph is an 303 # independent set or bipartite. 303 304 #  Independent set 304 if g.size() ==0:305 if g.size() == 0: 305 306 if value_only: 306 307 return 1 307 308 elif hex_colors: 308 return dict(zip(rainbow(1), g.vertices()))309 return dict(zip(rainbow(1), g.vertices())) 309 310 else: 310 311 return g.vertices() 311 312 312 #  Bipartite set 313 313 if g.is_bipartite(): 314 if value_only ==True:314 if value_only: 315 315 return 2 316 if hex_colors:317 return dict(zip(rainbow(2), g.bipartite_sets()))316 elif hex_colors: 317 return dict(zip(rainbow(2), g.bipartite_sets())) 318 318 else: 319 319 return g.bipartite_sets() 320 321 320 #  No need to try any k smaller than the maximum clique in the graph 322 #  max, because the graph could be trianglefree 323 324 k=max(3, g.clique_number() ) 325 321 #  max, because the graph could be trianglefree. 322 k = max(3, g.clique_number()) 326 323 while True: 327 324 # tries to color the graph, increasing k each time it fails. 328 tmp=vertex_coloring(g, k=k, value_only=value_only,hex_colors=hex_colors,log=log) 329 if tmp!=False: 325 tmp = vertex_coloring(g, k=k, value_only=value_only, 326 hex_colors=hex_colors, log=log) 327 if tmp is not False: 330 328 if value_only: 331 329 return k 332 330 else: 333 331 return tmp 334 k =k+1332 k += 1 335 333 else: 336 # Is the graph empty ? 337 338 # If the graph is empty, something should be returned.. 334 # Is the graph empty? 335 # If the graph is empty, something should be returned. 339 336 # This is not so stupid, as the graph could be emptied 340 # by the test of degeneracy 341 if g.order() ==0:342 if value_only ==True:337 # by the test of degeneracy. 338 if g.order() == 0: 339 if value_only: 343 340 return True 344 elif hex_colors ==True:345 return dict([(color, []) for color in rainbow(k)])341 elif hex_colors: 342 return dict([(color, []) for color in rainbow(k)]) 346 343 else: 347 return [[] for i in range(k)] 348 349 # Is the graph connected ? 350 344 return [[] for i in xrange(k)] 345 # Is the graph connected? 351 346 # This is not so stupid, as the graph could be disconnected 352 # by the test of degeneracy ( as previously ) 353 354 if g.is_connected()==False: 355 if value_only==True: 347 # by the test of degeneracy (as previously). 348 if not g.is_connected(): 349 if value_only: 356 350 for component in g.connected_components(): 357 if vertex_coloring(g.subgraph(component),k=k,value_only=value_only,hex_colors=hex_colors,log=log)==False: 351 tmp = vertex_coloring(g.subgraph(component), k=k, 352 value_only=value_only, 353 hex_colors=hex_colors, 354 log=log) 355 if tmp is False: 358 356 return False 359 357 return True 360 361 colorings=[] 358 colorings = [] 362 359 for component in g.connected_components(): 363 tmp=vertex_coloring(g.subgraph(component),k=k,value_only=value_only,hex_colors=False,log=log) 364 if tmp==False: 360 tmp = vertex_coloring(g.subgraph(component), k=k, 361 value_only=value_only, 362 hex_colors=False, log=log) 363 if tmp is False: 365 364 return False 366 365 colorings.append(tmp) 367 value =[[] for color inrange(k)]368 for color in range(k):366 value = [[] for color in xrange(k)] 367 for color in xrange(k): 369 368 for component in colorings: 370 369 value[color].extend(component[color]) 371 372 370 if hex_colors: 373 return dict(zip(rainbow(k), value))371 return dict(zip(rainbow(k), value)) 374 372 else: 375 373 return value 376 374 377 375 # Degeneracy 378 379 # Vertices whose degree is less than k are of no importance in the coloring 380 381 if min(g.degree())<k: 382 vertices=set(g.vertices()) 383 deg=[] 384 tmp=[v for v in vertices if g.degree(v)<k] 385 while len(tmp)>0: 386 v=tmp.pop(0) 387 neighbors=list(set(g.neighbors(v)) & vertices) 388 if v in vertices and len(neighbors)<k: 376 # Vertices whose degree is less than k are of no importance in 377 # the coloring. 378 if min(g.degree()) < k: 379 vertices = set(g.vertices()) 380 deg = [] 381 tmp = [v for v in vertices if g.degree(v) < k] 382 while len(tmp) > 0: 383 v = tmp.pop(0) 384 neighbors = list(set(g.neighbors(v)) & vertices) 385 if v in vertices and len(neighbors) < k: 389 386 vertices.remove(v) 390 387 tmp.extend(neighbors) 391 388 deg.append(v) 392 393 if value_only==True: 394 return vertex_coloring(g.subgraph(list(vertices)),k=k,value_only=value_only,hex_colors=hex_colors,log=log) 395 396 value=vertex_coloring(g.subgraph(list(vertices)),k=k,value_only=value_only,hex_colors=False,log=log) 397 if value==False: 389 if value_only: 390 return vertex_coloring(g.subgraph(list(vertices)), k=k, 391 value_only=value_only, 392 hex_colors=hex_colors, 393 log=log) 394 value = vertex_coloring(g.subgraph(list(vertices)), k=k, 395 value_only=value_only, 396 hex_colors=False, 397 log=log) 398 if value is False: 398 399 return False 399 while len(deg) >0:400 while len(deg) > 0: 400 401 for classe in value: 401 if len(list(set(classe) & set(g.neighbors(deg[1])))) ==0:402 if len(list(set(classe) & set(g.neighbors(deg[1])))) == 0: 402 403 classe.append(deg[1]) 403 404 deg.pop(1) 404 405 break 405 406 if hex_colors: 406 return dict(zip(rainbow(k), value))407 return dict(zip(rainbow(k), value)) 407 408 else: 408 409 return value 409 410 410 411 p=MixedIntegerLinearProgram(maximization=True) 412 color=p.new_variable(dim=2) 413 411 p = MixedIntegerLinearProgram(maximization=True) 412 color = p.new_variable(dim=2) 414 413 # a vertex has exactly one color 415 [p.add_constraint(sum([color[v][i] for i in range(k)]),min=1,max=1) for v in g.vertices()] 416 417 # Adjacent vertices have different colors 418 [p.add_constraint(color[u][i]+color[v][i],max=1) for (u,v) in g.edge_iterator(labels=None) for i in range(k)] 419 420 # Anything is good as an objective value as long as it is satisfiable 421 p.add_constraint(color[g.vertex_iterator().next()][0], max=1, min=1) 414 [p.add_constraint(sum([color[v][i] for i in xrange(k)]), min=1, max=1) 415 for v in g.vertices()] 416 # adjacent vertices have different colors 417 [p.add_constraint(color[u][i] + color[v][i], max=1) 418 for (u, v) in g.edge_iterator(labels=None) 419 for i in xrange(k)] 420 # anything is good as an objective value as long as it is satisfiable 421 p.add_constraint(color[g.vertex_iterator().next()][0], max=1, min=1) 422 422 p.set_objective(color[g.vertex_iterator().next()][0]) 423 424 423 p.set_binary(color) 425 424 from sage.numerical.mip import MIPSolverException 426 427 425 try: 428 if value_only ==True:429 p.solve(objective_only=True, log=log)426 if value_only: 427 p.solve(objective_only=True, log=log) 430 428 return True 431 429 else: 432 chi =p.solve(log=log)430 chi = p.solve(log=log) 433 431 except MIPSolverException: 434 432 return False 435 433 436 color=p.get_values(color) 437 434 color = p.get_values(color) 438 435 # builds the color classes 439 classes=[[] for i in range(k)] 440 [classes[i].append(v) for i in range(k) for v in g.vertices() if color[v][i]==1] 441 436 classes = [[] for i in xrange(k)] 437 [classes[i].append(v) 438 for i in xrange(k) 439 for v in g.vertices() 440 if color[v][i] == 1] 442 441 if hex_colors: 443 return dict(zip(rainbow(len(classes)), classes))442 return dict(zip(rainbow(len(classes)), classes)) 444 443 else: 445 444 return classes 446 445 447 def edge_coloring(self,value_only=False,vizing=False,hex_colors=False, log=0): 448 """ 449 Properly colors the edges of a graph. 450 ( cf. http://en.wikipedia.org/wiki/Edge_coloring ) 446 def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, log=0): 447 r""" 448 Properly colors the edges of a graph. See the URL 449 http://en.wikipedia.org/wiki/Edge_coloring for further details on 450 edge coloring. 451 451 452 452 INPUT: 453 453 454  `` value_only`` (boolean) 454  ``g``  a graph. 455 455 456  When set to ``True``, only the chromatic index is returned 457  When set to ``False`` (default), a partition of the edge set into 458 matchings is returned is possible 456  ``value_only``  (default: ``False``): 459 457 460  ``vizing`` (boolean)  461  When set to ``True``, tries to find a `\Delta+1`edgecoloring ( where 462 `\Delta` is equal to the maximum degree in the graph ) 458  When set to ``True``, only the chromatic index is returned. 463 459 464  When set to ``False``, tries to find a `\Delta`edgecoloring ( where 465 `\Delta` is equal to the maximum degree in the graph ). If impossible, 466 tries to find and returns a `\Delta+1`edgecoloring 467 468  Implies ``value_only = False``  460  When set to ``False``, a partition of the edge set into 461 matchings is returned if possible. 469 462 470  `` hex_colors`` (boolean) 463  ``vizing``  (default: ``False``): 471 464 472 When set to ``True`` ( it is ``False`` by default ), the partition returned 473 is a dictionary whose keys are colors and whose values are the color classes 474 ( ideal to be plotted ) 465  When set to ``True``, tries to find a `\Delta + 1`edgecoloring, 466 where `\Delta` is equal to the maximum degree in the graph. 475 467 476  ``log`` ( integer ) 477 As edgecoloring is a `NP`complete problem, its solving may take some time478 depending on the graph. Use ``log`` to define the level of verbosity you want479 from the linear program solver.468  When set to ``False``, tries to find a `\Delta`edgecoloring, 469 where `\Delta` is equal to the maximum degree in the graph. If 470 impossible, tries to find and returns a `\Delta + 1`edgecoloring. 471 This implies that ``value_only=False``. 480 472 481 By default ``log=0``, meaning that there will be no message printed by the solver. 473  ``hex_colors``  (default: ``False``) when set to ``True``, the 474 partition returned is a dictionary whose keys are colors and whose 475 values are the color classes (ideal for plotting). 482 476 483 OUTPUT : 477  ``log``  (default: ``0``) as edgecoloring is an `NP`complete 478 problem, this function may take some time depending on the graph. Use 479 ``log`` to define the level of verbosity you wantfrom the linear 480 program solver. By default ``log=0``, meaning that there will be no 481 message printed by the solver. 482 483 OUTPUT: 484 484 485 485 In the following, `\Delta` is equal to the maximum degree in the graph 486 ``g``. 486 487 487  If ``vizing=True`` and ``value_only=False`` :488 Returns a partition of the edge set into Delta+1 matchings488  If ``vizing=True`` and ``value_only=False``, return a partition of 489 the edge set into `\Delta + 1` matchings. 489 490 490  If ``vizing=False`` and ``value_only=True``: 491 Returns the chromatic index 491  If ``vizing=False`` and ``value_only=True``, return the chromatic index. 492 492 493  If ``vizing=False`` and ``value_only=False`` :494 Returns a partition of the edge set into the minimum number of matchings493  If ``vizing=False`` and ``value_only=False``, return a partition of 494 the edge set into the minimum number of matchings. 495 495 496  If ``vizing=True`` is set and ``value_only=True``: 497 Should return something, but mainly you are just trying to compute the maximum 498 degree of the graph, and this is not the easiest way ;) 499 By Vizing's theorem, a graph has a chromatic index equal to `\Delta` 500 or to `\Delta+1` 496  If ``vizing=True`` and ``value_only=True``, should return something, 497 but mainly you are just trying to compute the maximum degree of the 498 graph, and this is not the easiest way. By Vizing's theorem, a graph 499 has a chromatic index equal to `\Delta` or to `\Delta + 1`. 501 500 502 501 EXAMPLE:: 503 502 504 503 sage: from sage.graphs.graph_coloring import edge_coloring 505 sage: g =graphs.PetersenGraph()504 sage: g = graphs.PetersenGraph() 506 505 sage: edge_coloring(g, value_only=True) # optional  requires GLPK or CBC 507 506 4 508 507 509 Complete s graphs are colored using the lineartime Roundrobin coloring::508 Complete graphs are colored using the lineartime roundrobin coloring:: 510 509 511 510 sage: from sage.graphs.graph_coloring import edge_coloring 512 511 sage: len(edge_coloring(graphs.CompleteGraph(20))) 513 512 19 514 515 513 """ 516 514 from sage.numerical.mip import MixedIntegerLinearProgram 517 515 from sage.plot.colors import rainbow 518 g=self519 520 516 521 517 if g.is_clique(): 522 518 if value_only: 523 return g.order() if g.order() % 2 == 0 else g.order()+1524 vertices =g.vertices()519 return g.order() if g.order() % 2 == 0 else g.order() + 1 520 vertices = g.vertices() 525 521 r = round_robin(g.order()) 526 classes =[[] for v in g]527 if g.order() % 2 == 0 and vizing == False:522 classes = [[] for v in g] 523 if g.order() % 2 == 0 and not vizing: 528 524 classes.pop() 529 530 for (u,v,c) in r.edge_iterator(): 525 for (u, v, c) in r.edge_iterator(): 531 526 classes[c].append((vertices[u], vertices[v])) 532 533 527 if hex_colors: 534 from sage.plot.colors import rainbow 535 return zip(rainbow(len(classes)),classes) 528 return zip(rainbow(len(classes)), classes) 536 529 else: 537 530 return classes 538 539 531 540 p=MixedIntegerLinearProgram(maximization=True) 541 color=p.new_variable(dim=2) 542 obj={} 543 k=max(g.degree()) 544 532 p = MixedIntegerLinearProgram(maximization=True) 533 color = p.new_variable(dim=2) 534 obj = {} 535 k = max(g.degree()) 545 536 # reorders the edge if necessary... 546 R = lambda x : x if (x[0]<=x[1]) else (x[1],x[0],x[2]) 547 548 # Vizing's coloring uses Delta+1 colors 537 R = lambda x: x if (x[0] <= x[1]) else (x[1], x[0], x[2]) 538 # Vizing's coloring uses Delta + 1 colors 549 539 if vizing: 550 value_only =False551 k =k+1552 553 # A vertex can not have two incident edges with554 # the same color555 [p.add_constraint(sum([color[R(e)][i] for e in g.edges_incident(v)]),max=1) for v in g.vertex_iterator() for i in range(k)]556 557 # An edge must have a color558 [p.add_constraint(sum([color[R(e)][i] for i in range(k)]),max=1,min=1) for e in g.edge_iterator()]559 560 # Anything is good as an objective value as long as it is satisfiable561 e =g.edge_iterator().next()540 value_only = False 541 k += 1 542 # A vertex can not have two incident edges with the same color. 543 [p.add_constraint( 544 sum([color[R(e)][i] for e in g.edges_incident(v)]), max=1) 545 for v in g.vertex_iterator() 546 for i in xrange(k)] 547 # an edge must have a color 548 [p.add_constraint(sum([color[R(e)][i] for i in xrange(k)]), max=1, min=1) 549 for e in g.edge_iterator()] 550 # anything is good as an objective value as long as it is satisfiable 551 e = g.edge_iterator().next() 562 552 p.set_objective(color[R(e)][0]) 563 564 553 p.set_binary(color) 565 554 try: 566 if value_only ==True:567 p.solve(objective_only=True, log=log)555 if value_only: 556 p.solve(objective_only=True, log=log) 568 557 else: 569 chi =p.solve(log=log)558 chi = p.solve(log=log) 570 559 except: 571 560 if value_only: 572 return k +1561 return k + 1 573 562 else: 574 # if the coloring with Delta colors fails, tries Delta +1575 return edge_coloring(g, vizing=True,hex_colors=hex_colors,log=log)563 # if the coloring with Delta colors fails, tries Delta + 1 564 return edge_coloring(g, vizing=True, hex_colors=hex_colors, log=log) 576 565 if value_only: 577 566 return k 578 579 567 # Builds the color classes 580 color=p.get_values(color) 581 classes=[[] for i in range(k)] 582 [classes[i].append(e) for e in g.edge_iterator() for i in range(k) if color[R(e)][i]==1] 568 color = p.get_values(color) 569 classes = [[] for i in xrange(k)] 570 [classes[i].append(e) 571 for e in g.edge_iterator() 572 for i in xrange(k) 573 if color[R(e)][i] == 1] 583 574 # if needed, builds a dictionary from the color classes adding colors 584 575 if hex_colors: 585 return dict(zip(rainbow(len(classes)), classes))576 return dict(zip(rainbow(len(classes)), classes)) 586 577 else: 587 578 return classes 588 579 589 580 def round_robin(n): 590 581 r""" 591 Computes a Roundrobin coloring of the complete graph on `n` vertices.582 Computes a roundrobin coloring of the complete graph on `n` vertices. 592 583 593 A Roundrobin coloring of the complete graph `G` on594 `2n` vertices (`V=[0,\dots,2n1]`) is a proper coloring of its edges595 such that the edges with color `i` are all the `(i+j,ij)`,plus the596 edge `(2n 1,i)`.584 A roundrobin coloring of the complete graph `G` on `2n` vertices 585 (`V = [0, \dots, 2n  1]`) is a proper coloring of its edges such that 586 the edges with color `i` are all the `(i + j, i  j)` plus the 587 edge `(2n  1, i)`. 597 588 598 If `n` is odd, one obtain a Roundrobin coloring of the complete graph 599 through the Roundrobin coloring of the graph with `n+1` vertices, to 600 which one is removed. 589 If `n` is odd, one obtain a roundrobin coloring of the complete graph 590 through the roundrobin coloring of the graph with `n + 1` vertices. 601 591 602 592 INPUT: 603 593 … … 605 595 606 596 OUTPUT: 607 597 608  A CompleteGraph with labelled edges,such that the label of each598  A ``CompleteGraph`` with labelled edges such that the label of each 609 599 edge is its color. 610 600 611 601 EXAMPLES:: … … 638 628 True 639 629 sage: Set([e[2] for e in g.edge_iterator()]).cardinality() 640 630 9 641 642 643 631 """ 644 645 if not (n>1): 646 raise ValueError, "There must be at least two vertices in the graph." 647 648 mod = lambda x,y : x  y*(x//y) 649 632 if n <= 1: 633 raise ValueError("There must be at least two vertices in the graph.") 634 mod = lambda x, y: x  y*(x // y) 650 635 if n % 2 == 0: 651 g=GraphGenerators().CompleteGraph(n) 652 for i in range(n1): 653 g.set_edge_label(n1,i,i) 654 for j in range(1,(n1)//2+1): 655 g.set_edge_label(mod(ij,n1),mod(i+j,n1),i) 656 636 g = GraphGenerators().CompleteGraph(n) 637 for i in xrange(n  1): 638 g.set_edge_label(n  1, i, i) 639 for j in xrange(1, (n  1) // 2 + 1): 640 g.set_edge_label(mod(i  j, n  1), mod(i + j, n  1), i) 657 641 return g 658 659 642 else: 660 g =round_robin(n+1)643 g = round_robin(n + 1) 661 644 g.delete_vertex(n) 662 645 return g 663 646 664 665 647 class Test: 666 648 """ 667 649 This class performs randomized testing for all_graph_colorings.