Ticket #8405: trac_8405.patch

File trac_8405.patch, 13.0 KB (added by ncohen, 3 years ago)
  • sage/graphs/graph_coloring.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1267402255 -3600
    # Node ID 8a9ba9a2bf689cea5261ba2e6ccfd1127a9d08aa
    # Parent  efdf887eeb279c193a08fd5252953cc691f385cf
    trac 8405 - linear arboricity, acyclic edge coloring
    
    diff -r efdf887eeb27 -r 8a9ba9a2bf68 sage/graphs/graph_coloring.py
    a b  
    653653        g.delete_vertex(n) 
    654654        return g 
    655655 
     656def linear_arboricity(g, hex_colors=False, value_only=False, k=1, **kwds): 
     657    r""" 
     658    Computes the linear arboricity of the given graph. 
     659 
     660    The linear arboricity of a graph `G` is the least 
     661    number `la(G)` such that the edges of `G` can be  
     662    partitioned into linear forests (i.e. into forests 
     663    of paths). 
     664 
     665    Obviously, `la(G)\geq \lceil \frac {\Delta(G)} 2 \rceil`. 
     666 
     667    It is conjectured in [Aki80]_ that 
     668    `la(G)\leq \lceil \frac {\Delta(G)+1} 2 \rceil`. 
     669 
     670    INPUT: 
     671 
     672    - ``hex_colors`` (boolean) 
     673 
     674        - If ``hex_colors = True``, the function returns a 
     675          dictionary associating to each color a list 
     676          of edges (meant as an argument to the ``edge_colors`` 
     677          keyword of the ``plot`` method). 
     678 
     679        - If ``hex_colors = False`` (default value), returns  
     680          a list of graphs corresponding to each color class. 
     681 
     682    - ``value_only`` (boolean) 
     683 
     684        - If ``value_only = True``, only returns the linear 
     685          arboricity as an integer value. 
     686 
     687        - If ``value_only = False``, returns the color classes 
     688          according to the value of ``hex_colors`` 
     689 
     690    - ``k`` (integer) -- the number of colors to use. 
     691 
     692        - If ``0``, computes a decomposition of `G` into  
     693          `\lceil \frac {\Delta(G)} 2 \rceil` 
     694          forests of paths 
     695 
     696        - If ``1`` (default), computes a decomposition of `G` into 
     697          `\lceil \frac {\Delta(G)+1} 2 \rceil` colors, 
     698          which is the conjectured general bound. 
     699 
     700        - If ``k=None``, computes a decomposition using the 
     701          least possible number of colors. 
     702 
     703    - ``**kwds`` -- arguments to be passed down to the ``solve``  
     704      function of ``MixedIntegerLinearProgram``. See the documentation  
     705      of ``MixedIntegerLinearProgram.solve`` for more informations.  
     706 
     707 
     708    ALGORITHM: 
     709 
     710    Linear Programming 
     711 
     712    COMPLEXITY: 
     713 
     714    NP-Hard 
     715 
     716    EXAMPLE: 
     717 
     718    Obviously, a square grid has a linear arboricity of 2, as 
     719    the set of horizontal lines and the set of vertical lines 
     720    are an admissible partition:: 
     721 
     722        sage: from sage.graphs.graph_coloring import linear_arboricity 
     723        sage: g = graphs.GridGraph([4,4])                                 # optional - requires GLPK CPLEX or CBC 
     724        sage: g1,g2 = linear_arboricity(g, k=0)                           # optional - requires GLPK CPLEX or CBC 
     725 
     726    Each graph is of course a forest:: 
     727 
     728        sage: g1.is_forest() and g2.is_forest()                           # optional - requires GLPK CPLEX or CBC 
     729        True 
     730 
     731    Of maximum degree 2:: 
     732 
     733        sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2             # optional - requires GLPK CPLEX or CBC 
     734        True 
     735 
     736    Which constitutes a partition of the whole edge set:: 
     737 
     738        sage: all([g1.has_edge(e) or g2.has_edge(e) for e in g.edges()])  # optional - requires GLPK CPLEX or CBC 
     739        True 
     740 
     741    REFERENCES: 
     742 
     743    .. [Aki80] Akiyama, J. and Exoo, G. and Harary, F. 
     744      Covering and packing in graphs. III: Cyclic and acyclic invariants 
     745      Mathematical Institute of the Slovak Academy of Sciences 
     746      Mathematica Slovaca vol30, n4, pages 405--417, 1980 
     747    """ 
     748     
     749    from sage.rings.integer import Integer 
     750 
     751    if k is None: 
     752        try: 
     753            return linear_arboricity(g, value_only = value_only,hex_colors = hex_colors, k = (Integer(max(g.degree()))/2).ceil() ) 
     754        except ValueError: 
     755            return linear_arboricity(g, value_only = value_only,hex_colors = hex_colors, k = 0) 
     756    elif k==1: 
     757        k = (Integer(1+max(g.degree()))/2).ceil() 
     758    elif k==0: 
     759        k = (Integer(max(g.degree()))/2).ceil() 
     760 
     761    from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException 
     762    from sage.plot.colors import rainbow 
     763 
     764    p = MixedIntegerLinearProgram() 
     765 
     766 
     767    # c is a boolean value such that c[i][(u,v)] = 1 if and only if (u,v) is colored with i 
     768    c = p.new_variable(dim=2) 
     769 
     770    # relaxed value 
     771    r = p.new_variable(dim=2) 
     772 
     773    E = lambda x,y : (x,y) if x<y else (y,x) 
     774 
     775    MAD = 1-1/(Integer(g.order())*2) 
     776 
     777    # Partition of the edges 
     778    for u,v in g.edges(labels=None): 
     779        p.add_constraint(sum([c[i][E(u,v)] for i in range(k)]), max=1, min=1) 
     780 
     781    for i in range(k): 
     782 
     783        # r greater than c 
     784        for u,v in g.edges(labels=None): 
     785            p.add_constraint(r[i][(u,v)] + r[i][(v,u)] - c[i][E(u,v)], max=0, min=0) 
     786 
     787 
     788        # Maximum degree 2 
     789        for u in g.vertices(): 
     790            p.add_constraint(sum([c[i][E(u,v)] for v in g.neighbors(u)]),max = 2) 
     791 
     792            # no cycles 
     793            p.add_constraint(sum([r[i][(u,v)] for v in g.neighbors(u)]),max = MAD) 
     794 
     795 
     796    p.set_objective(None) 
     797    p.set_binary(c) 
     798 
     799    try: 
     800        if value_only: 
     801            return p.solve(objective_only = True) 
     802        else: 
     803            p.solve() 
     804 
     805    except MIPSolverException: 
     806        if k == (Integer(max(g.degree()))/2).ceil(): 
     807            raise Exception("It looks like you have found a counterexample to a very old conjecture. Please do not loose it ! Please publish it, and send a post to sage-devel to warn us. I implore you ! Nathann Cohen ") 
     808        else: 
     809            raise ValueError("This graph can not be colored with the given number of colors.") 
     810     
     811    c = p.get_values(c) 
     812 
     813    if hex_colors: 
     814        answer = [[] for i in range(k)] 
     815        add = lambda (u,v),i : answer[i].append((u,v)) 
     816    else: 
     817        gg = g.copy() 
     818        gg.delete_edges(g.edges()) 
     819        answer = [gg.copy() for i in range(k)] 
     820        add = lambda (u,v),i : answer[i].add_edge((u,v)) 
     821 
     822    for i in range(k): 
     823        for u,v in g.edges(labels=None): 
     824            if c[i][E(u,v)] == 1: 
     825                add((u,v),i) 
     826 
     827    if hex_colors: 
     828        return dict(zip(rainbow(len(classes)),classes)) 
     829    else: 
     830        return answer 
     831 
     832def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, **kwds): 
     833    r""" 
     834    Computes an acyclic edge coloring of the current graph. 
     835 
     836    An edge coloring of a graph is a assignment of colors 
     837    to the edges of a graph such that : 
     838 
     839    - the coloring is proper (no adjacent edges share a  
     840      color) 
     841    - For any two colors `i,j`, the union of the edges 
     842      colored with `i` or `j` is a forest. 
     843 
     844    The least number of colors such that such a coloring  
     845    exists for a graph `G` is written `\chi'_a(G)`, also 
     846    called the acyclic chromatic index of `G`. 
     847 
     848    It is conjectured that this parameter can not be too different 
     849    from the obvious lower bound `\Delta(G)\leq \chi'_a(G)`, 
     850    `\Delta(G)` being the maximum degree of `G`, which is given 
     851    by the first of the two constraints. Indeed, it is conjectured 
     852    that `\Delta(G)\leq \chi'_a(G) \leq \Delta(G) + 2`. 
     853 
     854    INPUT: 
     855 
     856    - ``hex_colors`` (boolean) 
     857 
     858        - If ``hex_colors = True``, the function returns a 
     859          dictionary associating to each color a list 
     860          of edges (meant as an argument to the ``edge_colors`` 
     861          keyword of the ``plot`` method). 
     862 
     863        - If ``hex_colors = False`` (default value), returns  
     864          a list of graphs corresponding to each color class. 
     865 
     866    - ``value_only`` (boolean) 
     867 
     868        - If ``value_only = True``, only returns the acyclic 
     869          chromatic index as an integer value 
     870 
     871        - If ``value_only = False``, returns the color classes 
     872          according to the value of ``hex_colors`` 
     873 
     874    - ``k`` (integer) -- the number of colors to use. 
     875 
     876        - If ``k>0``, computes an acyclic edge coloring using 
     877          `k` colors. 
     878 
     879        - If ``k=0`` (default), computes a coloring of `G` into 
     880          `\Delta(G) + 2` colors, 
     881          which is the conjectured general bound. 
     882 
     883        - If ``k=None``, computes a decomposition using the 
     884          least possible number of colors. 
     885 
     886    - ``**kwds`` -- arguments to be passed down to the ``solve``  
     887      function of ``MixedIntegerLinearProgram``. See the documentation  
     888      of ``MixedIntegerLinearProgram.solve`` for more informations.  
     889 
     890    ALGORITHM: 
     891 
     892    Linear Programming 
     893 
     894    EXAMPLE: 
     895 
     896    The complete graph on 8 vertices can not be acyclically  
     897    edge-colored with less `\Delta+1` colors, but it can be 
     898    colored with `\Delta+2=9`:: 
     899 
     900        sage: from sage.graphs.graph_coloring import acyclic_edge_coloring 
     901        sage: g = graphs.CompleteGraph(8)    
     902        sage: colors = acyclic_edge_coloring(g)                                     # optional - requires GLPK CPLEX or CBC 
     903 
     904    Each color class is of course a matching :: 
     905 
     906        sage: all([max(gg.degree())<=1 for gg in colors])                           # optional - requires GLPK CPLEX or CBC 
     907        True 
     908 
     909    These matchings being a partition of the edge set:: 
     910 
     911        sage: all([ any([gg.has_edge(e) for gg in colors]) for e in g.edges()])     # optional - requires GLPK CPLEX or CBC 
     912        True 
     913 
     914    Besides, the union of any two of them is a forest :: 
     915 
     916        sage: all([g1.union(g2).is_forest() for g1 in colors for g2 in colors])     # optional - requires GLPK CPLEX or CBC 
     917        True 
     918 
     919    If one wants to acyclically color a cycle on `4` vertices,  
     920    at least 3 colors will be necessary. The function raises 
     921    an exception when asked to color it with only 2:: 
     922 
     923        sage: g = graphs.CycleGraph(4) 
     924        sage: acyclic_edge_coloring(g, k=2)                                         # optional - requires GLPK CPLEX or CBC 
     925        Traceback (most recent call last): 
     926        ... 
     927        ValueError: This graph can not be colored with the given number of colors. 
     928 
     929    The optimal coloring give us `3` classes:: 
     930 
     931        sage: colors = acyclic_edge_coloring(g, k=None)                             # optional - requires GLPK CPLEX or CBC 
     932        sage: len(colors)                                                           # optional - requires GLPK CPLEX or CBC 
     933        3 
     934 
     935    """ 
     936 
     937    from sage.rings.integer import Integer 
     938    from sage.combinat.subset import Subsets 
     939 
     940    if k is None: 
     941        k = max(g.degree()) 
     942 
     943        while True: 
     944            try: 
     945                return acyclic_edge_coloring(g, value_only = value_only,hex_colors = hex_colors, k = k) 
     946            except ValueError: 
     947                k = k+1 
     948 
     949        raise Exception("This should not happen. Please report a bug !") 
     950 
     951    elif k==0: 
     952        k = max(g.degree())+2 
     953     
     954    from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException 
     955    from sage.plot.colors import rainbow 
     956 
     957    p = MixedIntegerLinearProgram() 
     958 
     959    # c is a boolean value such that c[i][(u,v)] = 1 if and only if (u,v) is colored with i 
     960    c = p.new_variable(dim=2) 
     961 
     962    # relaxed value 
     963    r = p.new_variable(dim=2) 
     964 
     965    E = lambda x,y : (x,y) if x<y else (y,x) 
     966 
     967    MAD = 1-1/(Integer(g.order())*2) 
     968 
     969    # Partition of the edges 
     970    for u,v in g.edges(labels=None): 
     971        p.add_constraint(sum([c[i][E(u,v)] for i in range(k)]), max=1, min=1) 
     972 
     973 
     974    for i in range(k): 
     975 
     976        # Maximum degree 1 
     977        for u in g.vertices(): 
     978            p.add_constraint(sum([c[i][E(u,v)] for v in g.neighbors(u)]),max = 1) 
     979 
     980    for i,j in Subsets(range(k),2): 
     981        # r is greater than c 
     982        for u in g.vertices(): 
     983            p.add_constraint(sum([r[(i,j)][(u,v)] for v in g.neighbors(u)]),max = MAD) 
     984 
     985        # r greater than c 
     986        for u,v in g.edges(labels=None): 
     987            p.add_constraint(r[(i,j)][(u,v)] + r[(i,j)][(v,u)] - c[i][E(u,v)] - c[j][E(u,v)], max=0, min=0) 
     988 
     989    p.set_objective(None) 
     990    p.set_binary(c) 
     991 
     992    try: 
     993        if value_only: 
     994            return p.solve(objective_only = True, **kwds) 
     995        else: 
     996            p.solve(**kwds) 
     997 
     998    except MIPSolverException: 
     999        if k == max(g.degree()) + 2: 
     1000            raise Exception("It looks like you have found a counterexample to a very old conjecture. Please do not loose it ! Please publish it, and send a post to sage-devel to warn us. I implore you ! Nathann Cohen ") 
     1001        else: 
     1002            raise ValueError("This graph can not be colored with the given number of colors.") 
     1003 
     1004    c = p.get_values(c) 
     1005 
     1006    if hex_colors: 
     1007        answer = [[] for i in range(k)] 
     1008        add = lambda (u,v),i : answer[i].append((u,v)) 
     1009    else: 
     1010        gg = g.copy() 
     1011        gg.delete_edges(g.edges()) 
     1012        answer = [gg.copy() for i in range(k)] 
     1013        add = lambda (u,v),i : answer[i].add_edge((u,v)) 
     1014 
     1015    for i in range(k): 
     1016        for u,v in g.edges(labels=None): 
     1017            if c[i][E(u,v)] == 1: 
     1018                add((u,v),i) 
     1019 
     1020    if hex_colors: 
     1021        return dict(zip(rainbow(len(classes)),classes)) 
     1022    else: 
     1023        return answer 
     1024 
     1025 
    6561026class Test: 
    6571027    r""" 
    6581028    This class performs randomized testing for all_graph_colorings.