Ticket #6679: trac_6679.patch

File trac_6679.patch, 26.8 KB (added by ncohen, 11 years ago)
  • sage/graphs/graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1249571353 25200
    # Node ID bb3c4341b46006a7253fb8882efbae55381455a8
    # Parent  e3e1fef8095076a7934f053616d1f14129bbb452
    Functions vertex_coloring and edge_coloring in graph_colouring with the Symbolics from the new MIP class
    
    diff -r e3e1fef80950 -r bb3c4341b460 sage/graphs/graph.py
    a b  
    46824682            vertices = [v for v in vertices if vertex_property(v)]
    46834683
    46844684        if algorithm is not None and algorithm not in ("delete", "add"):
    4685             raise ValueError, 'algorithm should be None, "delete", or "add"'
     4685            raise ValueError('algorithm should be None, "delete", or "add"')
    46864686           
    46874687        if inplace or len(vertices)>0.05*self.order() or algorithm=="delete":
    46884688            return self._subgraph_by_deleting(vertices=vertices, edges=edges,
     
    81298129                try:
    81308130                    hash(perm[v])
    81318131                except TypeError:
    8132                     raise ValueError, "perm dictionary must be of the format {a:a1, b:b1, ...} where a,b,... are vertices and a1,b1,... are hashable"
     8132                    raise ValueError("perm dictionary must be of the format {a:a1, b:b1, ...} where a,b,... are vertices and a1,b1,... are hashable")
    81338133        self._backend.relabel(perm, self._directed)
    81348134
    81358135        attributes_to_update = ('_pos', '_assoc', '_embedding')
     
    94029402            if weighted   is None: weighted   = False
    94039403            if multiedges is None: multiedges = False
    94049404            if not isinstance(data, str):
    9405                 raise ValueError, 'If input format is graph6, then data must be a string.'
     9405                raise ValueError('If input format is graph6, then data must be a string.')
    94069406            n = data.find('\n')
    94079407            if n == -1:
    94089408                n = len(data)
     
    97459745        """
    97469746        n = self.order()
    97479747        if n > 262143:
    9748             raise ValueError, 'graph6 format supports graphs on 0 to 262143 vertices only.'
     9748            raise ValueError('graph6 format supports graphs on 0 to 262143 vertices only.')
    97499749        elif self.has_loops() or self.has_multiple_edges():
    9750             raise ValueError, 'graph6 format supports only simple graphs (no loops, no multiple edges)'
     9750            raise ValueError('graph6 format supports only simple graphs (no loops, no multiple edges)')
    97519751        else:
    97529752            return graph_fast.N(n) + graph_fast.R(self._bit_vector())
    97539753
     
    97799779        if n == 0:
    97809780            return ':?'
    97819781        if n > 262143:
    9782             raise ValueError, 'sparse6 format supports graphs on 0 to 262143 vertices only.'
     9782            raise ValueError('sparse6 format supports graphs on 0 to 262143 vertices only.')
    97839783        else:
    97849784            vertices = self.vertices()
    97859785            n = len(vertices)
     
    1002110021        from sage.graphs.chrompoly import chromatic_polynomial
    1002210022        return chromatic_polynomial(self)
    1002310023
    10024     def chromatic_number(self):
     10024    def chromatic_number(self, algorithm="DLX"):
    1002510025        """
    1002610026        Returns the minimal number of colors needed to color the vertices
    10027         of the graph G.
    10028        
     10027        of the graph `G`.
     10028
     10029        INPUT:
     10030
     10031        - ``algorithm`` -- Selects an algorithm
     10032
     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 a
     10037              very slow method, as it computes ALL the possible colorings to check
     10038              that one exists.
     10039
     10040            - If ``algorithm = "CP"``, the chromatic number is computed
     10041              through the coefficients of the Chromatic Polynomial.
     10042
     10043              Computing the chromatic number through the chromatic polynomial is a
     10044              very slow method, which will only be useful for small graphs.
     10045
     10046            - If ``algorithm = "MILP"``, the chromatic number
     10047              is computed through a Mixed Integer Linear Program.
     10048
     10049              Computing the chromatic number through a Mixed Integer Linear
     10050              Program may require to install an optional Sage package like GLPK
     10051              or Coin-OR's CBC.
     10052
     10053        For more functions related to graph coloring, see
     10054        the ``sage.graphs.graph_coloring`` module.
     10055
    1002910056        EXAMPLES::
    1003010057       
    1003110058            sage: G = Graph({0:[1,2,3],1:[2]})
    10032             sage: G.chromatic_number()
    10033             3
    10034         """
    10035         f = self.chromatic_polynomial()
    10036         i = 0
    10037         while f(i) == 0:
    10038             i += 1
    10039         return i
    10040 
    10041     def coloring(self, hex_colors=False):
    10042         """
    10043         Returns the first (optimal) coloring found.
    10044        
    10045         INPUT::
    10046        
    10047             hex_colors -- if True, return a dict which can
    10048                           easily be used for plotting
     10059            sage: G.chromatic_number(algorithm="DLX")
     10060            3
     10061            sage: G.chromatic_number(algorithm="MILP") # optional - requires GLPK or CBC
     10062            3
     10063            sage: G.chromatic_number(algorithm="CP")
     10064            3
     10065
     10066        TESTS::
     10067
     10068            sage: G = Graph({0:[1,2,3],1:[2]})
     10069            sage: G.chromatic_number(algorithm="foo")
     10070            Traceback (most recent call last):
     10071            ...
     10072            ValueError: The `algorithm` variable must be set to either `DLX`, `MILP` or `CP`.
     10073        """
     10074        if algorithm == "DLX":
     10075            from sage.graphs.graph_coloring import chromatic_number
     10076            return chromatic_number(self)
     10077
     10078        elif algorithm == "MILP":
     10079            from sage.graphs.graph_coloring import vertex_coloring
     10080            return vertex_coloring(self, value_only=True)
     10081
     10082        elif algorithm == "CP":
     10083            f = self.chromatic_polynomial()
     10084            i = 0
     10085            while f(i) == 0:
     10086                i += 1
     10087            return i
     10088        else:
     10089            raise ValueError("The `algorithm` variable must be set to either `DLX`, `MILP` or `CP`.")
     10090
     10091    def coloring(self, algorithm="DLX", hex_colors=False):
     10092        """
     10093        Returns the first (optimal) proper vertex-coloring found.
     10094       
     10095        INPUT:
     10096       
     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 Coin-OR'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.
    1004910112       
    1005010113        EXAMPLES::
    1005110114       
    1005210115            sage: G = Graph("Fooba")
    1005310116
    10054             sage: P = G.coloring(); P
     10117            sage: P = G.coloring(algorithm="MILP"); P  # optional - requires GLPK or CBC
     10118            [[2, 1, 3], [0, 6, 5], [4]]
     10119            sage: P = G.coloring(algorithm="DLX"); P
    1005510120            [[1, 2, 3], [0, 5, 6], [4]]
    1005610121            sage: G.plot(partition=P)
    1005710122
    10058             sage: H = G.coloring(hex_colors=True)
     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
     10126            #0000ff [4]
     10127            #00ff00 [0, 6, 5]
     10128            #ff0000 [2, 1, 3]
     10129            sage: H = G.coloring(hex_colors=True, algorithm="DLX")
    1005910130            sage: for c in sorted(H.keys()):
    1006010131            ...    print c, H[c]
    1006110132            #0000ff [4]
     
    1006310134            #ff0000 [0, 5, 6]
    1006410135            sage: G.plot(vertex_colors=H)
    1006510136
    10066         """
    10067         from sage.graphs.graph_coloring import all_graph_colorings
    10068         for C in all_graph_colorings(self, self.chromatic_number()):
    10069             if hex_colors:
    10070                 return C
    10071             else:
    10072                 return C.values()
    10073 
     10137        TESTS::
     10138
     10139            sage: G.coloring(algorithm="foo")
     10140            Traceback (most recent call last):
     10141            ...
     10142            ValueError: The `algorithm` variable must be set to either `DLX` or `MILP`.
     10143        """
     10144        if algorithm == "MILP":
     10145            from sage.graphs.graph_coloring import vertex_coloring
     10146            return vertex_coloring(self,hex_colors=hex_colors)
     10147        elif algorithm == "DLX":
     10148            from sage.graphs.graph_coloring import first_coloring
     10149            return first_coloring(self, hex_colors=hex_colors)
     10150        else:
     10151            raise ValueError("The `algorithm` variable must be set to either `DLX` or `MILP`.")
     10152   
    1007410153    ### Centrality
    10075    
     10154
    1007610155    def centrality_betweenness(self, normalized=True):
    1007710156        r"""
    1007810157        Returns the betweenness centrality (fraction of number of shortest
     
    1075910838
    1076010839        """
    1076110840        if self.is_directed() or self.has_loops() or self.has_multiple_edges():
    10762             raise ValueError, "Self must be an undirected simple graph to have a clique_complex."
     10841            raise ValueError("Self must be an undirected simple graph to have a clique_complex.")
    1076310842        import sage.homology.simplicial_complex
    1076410843        C = sage.homology.simplicial_complex.SimplicialComplex(self.vertices(),self.cliques_maximal(),maximality_check=True)
    1076510844        C._graph = self
     
    1125211331            if weighted   is None: weighted   = False
    1125311332            if multiedges is None: multiedges = False
    1125411333            if not isinstance(data, str):
    11255                 raise ValueError, 'If input format is dig6, then data must be a string.'
     11334                raise ValueError('If input format is dig6, then data must be a string.')
    1125611335            n = data.find('\n')
    1125711336            if n == -1:
    1125811337                n = len(data)
     
    1152411603        """
    1152511604        n = self.order()
    1152611605        if n > 262143:
    11527             raise ValueError, 'dig6 format supports graphs on 0 to 262143 vertices only.'
     11606            raise ValueError('dig6 format supports graphs on 0 to 262143 vertices only.')
    1152811607        elif self.has_multiple_edges():
    11529             raise ValueError, 'dig6 format does not support multiple edges.'
     11608            raise ValueError('dig6 format does not support multiple edges.')
    1153011609        else:
    1153111610            return graph_fast.N(n) + graph_fast.R(self._bit_vector())
    1153211611
  • sage/graphs/graph_coloring.py

    diff -r e3e1fef80950 -r bb3c4341b460 sage/graphs/graph_coloring.py
    a b  
    44AUTHORS:
    55    -- Tom Boothby   (2008-02-21): Initial version
    66    -- Carlo Hamalainen (2009-03-28): minor change: switch to C++ DLX solver
     7    -- Nathann Cohen (2009-10-24): Coloring methods using Linear Programming
    78"""
    89
    910#*****************************************************************************
     
    141142    except RuntimeError:
    142143        raise RuntimeError, "Too much recursion!  Graph coloring failed."
    143144
    144 def first_coloring(G,n=0):
     145def first_coloring(G,n=0, hex_colors=True):
    145146    """
    146     Given a graph, and optionally a natural number n, returns
    147     the first coloring we find with at least n colors.
     147    Given a graph, and optionally a natural number `n`, returns
     148    the first coloring we find with at least `n` colors.
     149
     150    INPUT:
     151
     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.
     156
    148157
    149158    EXAMPLES:
    150159        sage: from sage.graphs.graph_coloring import first_coloring
     
    155164    o = G.order()
    156165    for m in range(n,o+1):
    157166        for C in all_graph_colorings(G,m):
    158             return C
     167            if hex_colors:
     168                return C
     169            else:
     170                return C.values()
    159171
    160172def number_of_n_colorings(G,n):
    161173    """
     
    228240        for C in all_graph_colorings(G,n):
    229241            return n   
    230242
     243
     244def 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`-colorability
     247    ( cf. http://en.wikipedia.org/wiki/Graph_coloring )
     248   
     249    INPUT:
     250
     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
     255
     256    - ``k`` ( an integer ) -- Tests whether the graph is `k`-colorable.
     257      The function returns a partition of the vertex set in `k`
     258      independent sets if possible and ``False`` otherwise.
     259
     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 )
     263
     264    - ``log`` ( integer ) -- As vertex-coloring 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.
     269
     270    OUTPUT :
     271   
     272    - If ``k=None`` and ``value_only=None``:
     273      Returns a partition of the vertex set into the minimum possible of independent sets
     274
     275    - If ``k=None`` and ``value_only=True``:
     276      Returns the chromatic number
     277             
     278    - If ``k`` is set and ``value_only=None``:
     279      Returns False if the graph is not `k`-colorable, and a partition of the
     280      vertex set into `k` independent sets otherwise
     281
     282    - If ``k`` is set and ``value_only=True``:
     283      Test whether the graph is `k`-colorable and returns ``True`` or ``False`` accordingly
     284             
     285
     286    EXAMPLE::
     287   
     288       sage: from sage.graphs.graph_coloring import vertex_coloring
     289       sage: g=graphs.PetersenGraph()
     290       sage: vertex_coloring(g, value_only=True) # optional - requires GLPK or CBC
     291       3
     292       
     293    """
     294    from sage.numerical.mip import MixedIntegerLinearProgram
     295    from sage.plot.colors import rainbow
     296    g=self
     297
     298    # 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        #
     303        # - Independent set
     304        if g.size()==0:
     305            if value_only:
     306                return 1
     307            elif hex_colors:
     308                return dict(zip(rainbow(1),g.vertices()))
     309            else:
     310                return g.vertices()
     311
     312        # - Bipartite set
     313        if g.is_bipartite():
     314            if value_only==True:
     315                return 2
     316            if hex_colors:
     317                return dict(zip(rainbow(2),g.bipartite_sets()))
     318            else:
     319                return g.bipartite_sets()
     320
     321        # - No need to try any k smaller than the maximum clique in the graph
     322        # - max, because the graph could be triangle-free
     323
     324        k=max(3, g.clique_number() )
     325
     326        while True:
     327            # 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:
     330                if value_only:
     331                    return k
     332                else:
     333                    return tmp
     334            k=k+1
     335    else:
     336        # Is the graph empty ?
     337
     338        # If the graph is empty, something should be returned..
     339        # 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:
     343                return True
     344            elif hex_colors==True:
     345                return dict([(color,[]) for color in rainbow(k)])
     346            else:
     347                return [[] for i in range(k)]
     348
     349        # Is the graph connected ?
     350
     351        # 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:
     356                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:
     358                        return False
     359                return True
     360
     361            colorings=[]
     362            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:
     365                    return False
     366                colorings.append(tmp)
     367            value=[[] for color in range(k)]
     368            for color in range(k):
     369                for component in colorings:
     370                    value[color].extend(component[color])
     371
     372            if hex_colors:
     373                return dict(zip(rainbow(k),value))
     374            else:
     375                return value
     376                   
     377        # 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:
     389                    vertices.remove(v)
     390                    tmp.extend(neighbors)
     391                    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:
     398                return False
     399            while len(deg)>0:
     400                for classe in value:
     401                    if len(list(set(classe) & set(g.neighbors(deg[-1]))))==0:
     402                        classe.append(deg[-1])
     403                        deg.pop(-1)
     404                        break
     405            if hex_colors:
     406                return dict(zip(rainbow(k),value))
     407            else:
     408                return value
     409         
     410       
     411        p=MixedIntegerLinearProgram(maximization=True)
     412        color=p.new_variable(dim=2)
     413
     414        # 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)
     422        p.set_objective(color[g.vertex_iterator().next()][0])
     423
     424        p.set_binary(color)
     425        from sage.numerical.mip import MIPSolverException
     426
     427        try:
     428            if value_only==True:
     429                p.solve(objective_only=True,log=log)
     430                return True
     431            else:
     432                chi=p.solve(log=log)
     433        except MIPSolverException:
     434            return False
     435
     436        color=p.get_values(color)
     437
     438        # 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
     442        if hex_colors:
     443            return dict(zip(rainbow(len(classes)),classes))
     444        else:
     445            return classes
     446
     447def 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 )
     451   
     452    INPUT:
     453
     454    - ``value_only`` (boolean) --
     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
     459
     460    - ``vizing`` (boolean) --
     461        - When set to ``True``, tries to find a `\Delta+1`-edge-coloring ( where
     462          `\Delta` is equal to the maximum degree in the graph )
     463
     464        - When set to ``False``, tries to find a `\Delta`-edge-coloring ( where
     465          `\Delta` is equal to the maximum degree in the graph ). If impossible,
     466          tries to find and returns a `\Delta+1`-edge-coloring
     467                       
     468              --- Implies ``value_only = False`` ---
     469
     470    - ``hex_colors`` (boolean) --
     471
     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 )
     475
     476    - ``log`` ( integer ) --
     477      As edge-coloring is a `NP`-complete problem, its solving may take some time
     478      depending on the graph. Use ``log`` to define the level of verbosity you want
     479      from the linear program solver.
     480
     481      By default ``log=0``, meaning that there will be no message printed by the solver.
     482
     483    OUTPUT :
     484
     485    In the following, `\Delta` is equal to the maximum degree in the graph
     486   
     487    - If ``vizing=True`` and ``value_only=False``:
     488              Returns a partition of the edge set into Delta+1 matchings
     489
     490    - If ``vizing=False`` and ``value_only=True``:
     491              Returns the chromatic index
     492
     493    - If ``vizing=False`` and ``value_only=False``:
     494              Returns a partition of the edge set into the minimum number of matchings
     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`
     501
     502    EXAMPLE::
     503   
     504       sage: from sage.graphs.graph_coloring import edge_coloring
     505       sage: g=graphs.PetersenGraph()
     506       sage: edge_coloring(g, value_only=True) # optional - requires GLPK or CBC
     507       4
     508
     509    Completes graphs are colored using the linear-time Round-robin coloring ::
     510
     511       sage: from sage.graphs.graph_coloring import edge_coloring
     512       sage: len(edge_coloring(graphs.CompleteGraph(20)))
     513       19
     514       
     515    """
     516    from sage.numerical.mip import MixedIntegerLinearProgram
     517    from sage.plot.colors import rainbow
     518    g=self
     519
     520
     521    if g.is_clique():
     522        if value_only:
     523            return g.order() if g.order() % 2 ==0 else g.order()+1
     524        vertices=g.vertices()
     525        r = round_robin(g.order())
     526        classes=[[] for v in g]
     527        if g.order() % 2 == 0 and vizing == False:
     528            classes.pop()
     529
     530        for (u,v,c) in r.edge_iterator():
     531            classes[c].append((vertices[u], vertices[v]))
     532       
     533        if hex_colors:
     534            from sage.plot.colors import rainbow
     535            return zip(rainbow(len(classes)),classes)
     536        else:
     537            return classes             
     538       
     539
     540    p=MixedIntegerLinearProgram(maximization=True)
     541    color=p.new_variable(dim=2)
     542    obj={}
     543    k=max(g.degree())
     544
     545    # 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
     549    if vizing:
     550        value_only=False
     551        k=k+1
     552
     553    #  A vertex can not have two incident edges with
     554    # the same color
     555    [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 color
     558    [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 satisfiable
     561    e=g.edge_iterator().next()
     562    p.set_objective(color[R(e)][0])
     563
     564    p.set_binary(color)
     565    try:
     566        if value_only==True:
     567            p.solve(objective_only=True,log=log)
     568        else:
     569            chi=p.solve(log=log)
     570    except:
     571        if value_only:
     572            return k+1
     573        else:
     574            # if the coloring with Delta colors fails, tries Delta+1
     575            return edge_coloring(g,vizing=True,hex_colors=hex_colors,log=log)
     576    if value_only:
     577        return k
     578
     579    # 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]
     583    # if needed, builds a dictionary from the color classes adding colors
     584    if hex_colors:
     585        return dict(zip(rainbow(len(classes)),classes))
     586    else:
     587        return classes
     588
     589def round_robin(n):
     590    r"""
     591    Computes a Round-robin coloring of the complete graph on `n` vertices.
     592
     593    A Round-robin coloring of the complete graph `G` on
     594    `2n` vertices (`V=[0,\dots,2n-1]`) is a proper coloring of its edges
     595    such that the edges with color `i` are all the `(i+j,i-j)`, plus the
     596    edge `(2n-1,i)`.
     597
     598    If `n` is odd, one obtain a Round-robin coloring of the complete graph
     599    through the Round-robin coloring of the graph with `n+1` vertices, to
     600    which one is removed.
     601
     602    INPUT:
     603
     604    - ``n`` -- the number of vertices in the complete graph.
     605
     606    OUTPUT:
     607
     608    - A CompleteGraph with labelled edges, such that the label of each
     609      edge is its color.
     610
     611    EXAMPLES::
     612
     613        sage: from sage.graphs.graph_coloring import round_robin
     614        sage: round_robin(3).edges()
     615        [(0, 1, 2), (0, 2, 1), (1, 2, 0)]
     616
     617    ::
     618
     619        sage: round_robin(4).edges()
     620        [(0, 1, 2), (0, 2, 1), (0, 3, 0), (1, 2, 0), (1, 3, 1), (2, 3, 2)]
     621
     622
     623    For higher orders, the coloring is still proper and uses the expected
     624    number of colors.
     625
     626    ::
     627
     628        sage: g = round_robin(9)
     629        sage: sum([Set([e[2] for e in g.edges_incident(v)]).cardinality() for v in g]) == 2*g.size()
     630        True
     631        sage: Set([e[2] for e in g.edge_iterator()]).cardinality()
     632        9
     633
     634    ::
     635
     636        sage: g = round_robin(10)
     637        sage: sum([Set([e[2] for e in g.edges_incident(v)]).cardinality() for v in g]) == 2*g.size()
     638        True
     639        sage: Set([e[2] for e in g.edge_iterator()]).cardinality()
     640        9       
     641
     642
     643    """
     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
     650    if n % 2 == 0:
     651        g=GraphGenerators().CompleteGraph(n)
     652        for i in range(n-1):
     653            g.set_edge_label(n-1,i,i)
     654            for j in range(1,(n-1)//2+1):
     655                g.set_edge_label(mod(i-j,n-1),mod(i+j,n-1),i)
     656
     657        return g
     658           
     659    else:
     660        g=round_robin(n+1)
     661        g.delete_vertex(n)
     662        return g
     663
     664
    231665class Test:
    232666    """
    233667    This class performs randomized testing for all_graph_colorings.