Ticket #9575: trac_9575.patch
File trac_9575.patch, 10.0 KB (added by , 11 years ago) |
---|
-
sage/graphs/graph_coloring.py
# HG changeset patch # User Nathann Cohen <nathann.cohen@gmail.com> # Date 1279782482 -28800 # Node ID be94a819ed703679bd9c3e2dfc89146792a93f3e # Parent cb1ad1ee5bd452850fde04d47f9618dec4c3e997 trac #9575 -- Grundy Coloring diff -r cb1ad1ee5bd4 -r be94a819ed70 sage/graphs/graph_coloring.py
a b 302 302 sage: vertex_coloring(g, value_only=True) 303 303 3 304 304 """ 305 from sage.numerical.mip import MixedIntegerLinearProgram 305 from sage.numerical.mip import MixedIntegerLinearProgram, Sum 306 306 from sage.plot.colors import rainbow 307 307 308 308 # If k==None, tries to find an optimal coloring … … 419 419 p = MixedIntegerLinearProgram(maximization=True) 420 420 color = p.new_variable(dim=2) 421 421 # a vertex has exactly one color 422 [p.add_constraint( sum([color[v][i] for i in xrange(k)]), min=1, max=1)422 [p.add_constraint(Sum([color[v][i] for i in xrange(k)]), min=1, max=1) 423 423 for v in g.vertices()] 424 424 # adjacent vertices have different colors 425 425 [p.add_constraint(color[u][i] + color[v][i], max=1) … … 451 451 else: 452 452 return classes 453 453 454 def grundy_coloring(g, k, value_only = True, solver = None, verbose = 0): 455 r""" 456 Computes the worst-case of a first-fit coloring with less than `k` 457 colors. 458 459 Definition : 460 461 A first-fit coloring is obtained by sequentially coloring the 462 vertices of a graph, assigning them the smallest color not already 463 assigned to one of its neighbors. The result is clearly a proper 464 coloring, which usually requires much more colors than an optimal 465 vertex coloring of the graph, and heavily depends on the ordering 466 of the vertices. 467 468 The number of colors required by the worst-case application of 469 this algorithm on a graph `G` is called the Grundy number, written 470 `\Gamma (G)`. 471 472 Equivalent formulation : 473 474 Equivalently, a Grundy coloring is a proper vertex coloring such 475 that any vertex colored with `i` has, for every `j<i`, a neighbor 476 colored with `j`. This can define a Linear Program, which is used 477 here to compute the Grundy number of a graph. 478 479 .. NOTE: 480 481 This method computes a grundy coloring using at *MOST* `k` 482 colors. If this method returns a value equal to `k`, it can not 483 be assumed that `k` is equal to `\Gamma(G)`. Meanwhile, if it 484 returns any value `k' < k`, this is a certificate that the 485 Grundy number of the given graph is `k'`. 486 487 As `\Gamma(G)\leq \Delta(G)+1`, it can also be assumed that 488 `\Gamma(G) = k` if ``grundy_coloring(g, k)`` returns `k` when 489 `k = \Delta(G) +1`. 490 491 INPUT: 492 493 - ``k`` (integer) -- Maximum number of colors 494 495 - ``solver`` -- (default: ``None``) Specify a Linear Program (LP) 496 solver to be used. If set to ``None``, the default one is used. For 497 more information on LP solvers and which default solver is used, see 498 the method 499 :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>` 500 of the class 501 :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`. 502 503 - ``value_only`` -- boolean (default: ``True``). When set to 504 ``True``, only the number of colors is returned. Otherwise, the 505 pair ``(nb_colors, coloring)`` is returned, where ``coloring`` 506 is a dictionary associating its color (integer) to each vertex 507 of the graph. 508 509 - ``verbose`` -- integer (default: ``0``). Sets the level of 510 verbosity. Set to 0 by default, which means quiet. 511 512 ALGORITHM: 513 514 Integer Linear Program. 515 516 EXAMPLES: 517 518 The Grundy number of a `P_4` is equal to 3:: 519 520 sage: from sage.graphs.graph_coloring import grundy_coloring 521 sage: g = graphs.PathGraph(4) 522 sage: grundy_coloring(g, 4) 523 3 524 525 The Grundy number of the PetersenGraph is equal to 4:: 526 527 sage: g = graphs.PetersenGraph() 528 sage: grundy_coloring(g, 5) 529 4 530 531 It would have been sufficient to set the value of ``k`` to 4 in 532 this case, as `4 = \Delta(G)+1`. 533 """ 534 from sage.numerical.mip import MixedIntegerLinearProgram 535 from sage.numerical.mip import MIPSolverException, Sum 536 537 p = MixedIntegerLinearProgram() 538 539 # List of colors 540 classes = range(k) 541 542 # b[v][i] is set to 1 if and only if v is colored with i 543 b = p.new_variable(dim=2) 544 545 # is_used[i] is set to 1 if and only if color [i] is used by some 546 # vertex 547 is_used = p.new_variable() 548 549 # Each vertex is in exactly one class 550 for v in g: 551 p.add_constraint(Sum( b[v][i] for i in classes ), max = 1, min = 1) 552 553 # Two adjacent vertices have different classes 554 for u,v in g.edges(labels = None): 555 for i in classes: 556 p.add_constraint(b[v][i] + b[u][i], max = 1) 557 558 # The following constraints ensure that if v is colored with i, 559 # then it has a neighbor colored with j for every j<i 560 561 for i in range(k): 562 for j in range(i): 563 for v in g: 564 565 # If b[v][i] == 0, then the following constraint is 566 # always satisfied, as a sum of binary variables is 567 # always positive. If it is equal to 1, then at least 568 # one of fthe other variables must be set to 1 too. 569 570 p.add_constraint( Sum( b[u][j] for u in g.neighbors(v) ) - b[v][i] ,min = 0) 571 572 # is_used[i] can be set to 1 only if the color is used 573 for i in classes: 574 p.add_constraint( Sum( b[v][i] for v in g ) - is_used[i], min = 0) 575 576 # Both variables are binary 577 p.set_binary(b) 578 p.set_binary(is_used) 579 580 # Trying to use as many colors as possible 581 p.set_objective( Sum( is_used[i] for i in classes ) ) 582 583 try: 584 obj = p.solve(solver = solver, log = verbose, objective_only = value_only) 585 from sage.rings.integer import Integer 586 obj = Integer(obj) 587 588 except MIPSolverException: 589 raise ValueError("This graph can not be colored with k colors") 590 591 if value_only: 592 return obj 593 594 # Building the dictionary associating its color to every vertex 595 596 b = p.get_values(b) 597 coloring = {} 598 599 for v in g: 600 for i in classes: 601 if b[v][i] == 1: 602 coloring[v] = i 603 break 604 605 return obj, coloring 606 607 454 608 def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, log=0): 455 609 r""" 456 610 Properly colors the edges of a graph. See the URL … … 529 683 """ 530 684 from sage.numerical.mip import MixedIntegerLinearProgram 531 685 from sage.plot.colors import rainbow 532 from sage.numerical.mip import MIPSolverException 686 from sage.numerical.mip import MIPSolverException, Sum 533 687 534 688 if g.is_clique(): 535 689 if value_only: … … 561 715 k += 1 562 716 # A vertex can not have two incident edges with the same color. 563 717 [p.add_constraint( 564 sum([color[R(e)][i] for e in g.edges_incident(v, labels=False)]), max=1)718 Sum([color[R(e)][i] for e in g.edges_incident(v, labels=False)]), max=1) 565 719 for v in g.vertex_iterator() 566 720 for i in xrange(k)] 567 721 # an edge must have a color 568 [p.add_constraint( sum([color[R(e)][i] for i in xrange(k)]), max=1, min=1)722 [p.add_constraint(Sum([color[R(e)][i] for i in xrange(k)]), max=1, min=1) 569 723 for e in g.edge_iterator(labels=False)] 570 724 # anything is good as an objective value as long as it is satisfiable 571 725 e = g.edge_iterator(labels=False).next() … … 715 869 function of ``MixedIntegerLinearProgram``. See the documentation 716 870 of ``MixedIntegerLinearProgram.solve`` for more informations. 717 871 718 719 872 ALGORITHM: 720 873 721 874 Linear Programming … … 769 922 elif k==0: 770 923 k = (Integer(max(g.degree()))/2).ceil() 771 924 772 from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException 925 from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException, Sum 773 926 from sage.plot.colors import rainbow 774 927 775 928 p = MixedIntegerLinearProgram() … … 787 940 788 941 # Partition of the edges 789 942 for u,v in g.edges(labels=None): 790 p.add_constraint( sum([c[i][E(u,v)] for i in range(k)]), max=1, min=1)943 p.add_constraint(Sum([c[i][E(u,v)] for i in range(k)]), max=1, min=1) 791 944 792 945 for i in range(k): 793 946 … … 798 951 799 952 # Maximum degree 2 800 953 for u in g.vertices(): 801 p.add_constraint( sum([c[i][E(u,v)] for v in g.neighbors(u)]),max = 2)954 p.add_constraint(Sum([c[i][E(u,v)] for v in g.neighbors(u)]),max = 2) 802 955 803 956 # no cycles 804 p.add_constraint( sum([r[i][(u,v)] for v in g.neighbors(u)]),max = MAD)957 p.add_constraint(Sum([r[i][(u,v)] for v in g.neighbors(u)]),max = MAD) 805 958 806 959 807 960 p.set_objective(None) … … 962 1115 elif k==0: 963 1116 k = max(g.degree())+2 964 1117 965 from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException 1118 from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException, Sum 966 1119 from sage.plot.colors import rainbow 967 1120 968 1121 p = MixedIntegerLinearProgram() … … 979 1132 980 1133 # Partition of the edges 981 1134 for u,v in g.edges(labels=None): 982 p.add_constraint( sum([c[i][E(u,v)] for i in range(k)]), max=1, min=1)1135 p.add_constraint(Sum([c[i][E(u,v)] for i in range(k)]), max=1, min=1) 983 1136 984 1137 985 1138 for i in range(k): 986 1139 987 1140 # Maximum degree 1 988 1141 for u in g.vertices(): 989 p.add_constraint( sum([c[i][E(u,v)] for v in g.neighbors(u)]),max = 1)1142 p.add_constraint(Sum([c[i][E(u,v)] for v in g.neighbors(u)]),max = 1) 990 1143 991 1144 for i,j in Subsets(range(k),2): 992 1145 # r is greater than c 993 1146 for u in g.vertices(): 994 p.add_constraint( sum([r[(i,j)][(u,v)] for v in g.neighbors(u)]),max = MAD)1147 p.add_constraint(Sum([r[(i,j)][(u,v)] for v in g.neighbors(u)]),max = MAD) 995 1148 996 1149 # r greater than c 997 1150 for u,v in g.edges(labels=None):