This is now trac ticket #34809 <https://trac.sagemath.org/ticket/34809>.

On Tuesday, November 29, 2022 at 9:11:31 AM UTC-7 Matheus Maldonado wrote:

> There are some other points I forgot to mention:
>
> Figuring out if the optimal edge coloring of a graph takes Delta or 
> Delta+1 colors is an NP-hard problem and can take exponential time. This is 
> not what my algorithm does. It may return a Delta coloring, but in a 
> non-deterministic way.
>
> What I suggest we do is: keep the current MILP implementation to find out 
> if a Delta coloring exists, this way if the user is interested in this 
> optimal coloring, he can set the flag Vizing to false and get what he 
> needs. If there is no Delta coloring, or the user doesn't really care about 
> the optimal solution, then we use my algorithm to find the coloring faster. 
> There is no situation where the MILP solution does not find a Delta 
> coloring and my algorithm does, so the only moment my implementation could 
> return a Delta coloring is when the flag Vizing == true, and it shouldn't 
> bother the user. I cannot think of any reason why someone would strictly 
> need a Delta+1 coloring, but if they really need one they can give a random 
> edge a new color.
>
> I also think we should keep the hex_colors implementation, so that no code 
> that depends on it breaks.
>
> If anyone opposes this, please let me know. I'll be opening the ticket in 
> a few hours.
>
> On Tuesday, 29 November 2022 at 10:32:54 UTC-3 Matheus Maldonado wrote:
>
>> On Tuesday, 29 November 2022 at 05:05:50 UTC-3 David Coudert wrote:
>>
>>> FYI, the current Vizing algorithm is not well tested and the returned 
>>> edge coloring may have an empty set of colors
>>>
>>> sage: from sage.graphs.graph_coloring import edge_coloring
>>> sage: G = graphs.PetersenGraph()
>>> sage: edge_coloring(G, vizing=True)
>>> [[(0, 1), (2, 3), (4, 9), (5, 7), (6, 8)],
>>>  [(0, 4), (1, 2), (3, 8), (6, 9)],
>>>  [(0, 5), (2, 7)],
>>>  [(1, 6), (3, 4), (5, 8), (7, 9)]]
>>> sage: G = graphs.StarGraph(4)
>>> sage: edge_coloring(G, vizing=True)
>>> [[(0, 1)], [(0, 2)], [(0, 3)], [(0, 4)], []]
>>>
>>
>> If I understand correctly, the algorithm does that because the only 
>> possible coloring for this graph takes Delta colors, and the Vizing flag 
>> forces Delta+1 colors, creating an "empty color". If that isn't intended, 
>> then does dmo's suggestion of maintaining this behavior for every graph 
>> make sense? If it is intended though,  I'd have to add an edge case that 
>> appends an empty array to the result if Delta == number of edges, which 
>> sounds a bit counter-intuitive, just like giving a random edge a new color 
>> to force a Delta+1 coloring. 
>>
>>>
>>>
>>> On Tuesday, November 29, 2022 at 7:13:43 AM UTC+1 Matheus Maldonado 
>>> wrote:
>>>
>>>> On Monday, 28 November 2022 at 03:48:18 UTC-3 dmo...@deductivepress.ca 
>>>> wrote:
>>>>
>>>>> I agree that this seems to be a good improvement.  I think it should 
>>>>> replace the current "vizing" algorithm, instead of adding a new function 
>>>>> to 
>>>>> the namespace.
>>>>>
>>>>> A minor issue is that (if I understand correctly) the current vizing 
>>>>> algorithm always gives a colouring with Delta + 1 colours.  If that is 
>>>>> correct, then the code may need to be modified to have an option that 
>>>>> matches this behaviour, until the traditional 1-year deprecation period 
>>>>> has 
>>>>> passed.
>>>>>
>>>>
>>>> I see. If the algorithm finds a Delta coloring, I just need to change 
>>>> the color of a random edge to a new one. Sounds a little 
>>>> counter-intuitive, 
>>>> but I understand the reason behind it. 
>>>>  
>>>>
>>>>>
>>>>> Also, I think the "hex_colors" option should be deleted. Instead, it 
>>>>> would be nice to put this code into the documentation as an example that 
>>>>> demonstrates how to print the colouring.
>>>>>
>>>>
>>>>  Any specific reason for this? 
>>>>  
>>>>
>>>>> On Sunday, November 27, 2022 at 11:20:35 PM UTC-7 David Coudert wrote:
>>>>>
>>>>>> Feel free to open a ticket for this code. It's seems a good 
>>>>>> improvement.
>>>>>>
>>>>>> On Sunday, November 27, 2022 at 5:39:34 PM UTC+1 Matheus Maldonado 
>>>>>> wrote:
>>>>>>
>>>>>>> Hello everyone,
>>>>>>>
>>>>>>> I just developed a new function for coloring graph edges based on 
>>>>>>> this article: 
>>>>>>> https://www.sciencedirect.com/science/article/abs/pii/002001909290041S 
>>>>>>> , and I'd like to know if you think it's a valuable contribution to 
>>>>>>> sage 
>>>>>>> and deserves a trac ticket. I compared the existing edge coloring 
>>>>>>> function 
>>>>>>> and the one I created, and it's a pretty good improvement in processing 
>>>>>>> time for graphs with a lot of edges:
>>>>>>>
>>>>>>> sage: g_list = [graphs RandomGNP(x, 0.7) for x in range(25)]
>>>>>>> sage: %time c = [vizing_edge_coloring(x) for x in g_list]
>>>>>>> CPU times: user 131 ms, sys: 9.94 ms, total: 141 ms
>>>>>>> Wall time: 140 ms
>>>>>>> sage: %time c = [edge_coloring(x, vizing=True) for x in g_list]
>>>>>>> CPU times: user 18.6 s, sys: 134 μs, total: 18.6 s
>>>>>>> Wall time: 18.6 s
>>>>>>>
>>>>>>> I still haven't decided if this function should be standalone or if 
>>>>>>> it should be called when the flag vizing is set on the existing 
>>>>>>> edge_coloring function. If you have an opinion on that, please share :)
>>>>>>>
>>>>>>> I'm pasting the code below for reference, since I haven't created a 
>>>>>>> ticket and pushed my branch yet. Feedback is much appreciated!
>>>>>>>
>>>>>>> def vizing_edge_coloring(g, hex_colors=False):
>>>>>>>     r"""
>>>>>>>     Compute an edge coloring with at most `\Delta + 1` colors.
>>>>>>>
>>>>>>>     INPUT:
>>>>>>>
>>>>>>>     - ``g`` -- a graph.
>>>>>>>
>>>>>>>     - ``hex_colors`` -- boolean (default: ``False``); when set to 
>>>>>>> ``True``, the
>>>>>>>       partition returned is a dictionary whose keys are colors and 
>>>>>>> whose values
>>>>>>>       are the color classes (ideal for plotting)
>>>>>>>
>>>>>>>     OUTPUT:
>>>>>>>
>>>>>>>     - Returns a partition of the edge set into at most `\Delta + 1` 
>>>>>>> matchings.
>>>>>>>
>>>>>>>     .. SEEALSO::
>>>>>>>
>>>>>>>         - :wikipedia:`Edge_coloring` for further details on edge 
>>>>>>> coloring
>>>>>>>         - :wikipedia:`Vizing's_theorem` for further details on 
>>>>>>> Vizing's theorem
>>>>>>>
>>>>>>>     ALGORITHM:
>>>>>>>
>>>>>>>     This function's implementation is based on the algorithm 
>>>>>>> described at [MG1992]_
>>>>>>>     
>>>>>>>     EXAMPLES:
>>>>>>>
>>>>>>>     Coloring the edges of the Petersen Graph::
>>>>>>>
>>>>>>>        sage: from sage.graphs.graph_coloring import 
>>>>>>> vizing_edge_coloring
>>>>>>>        sage: g = graphs.PetersenGraph()
>>>>>>>        sage: vizing_edge_coloring(g)
>>>>>>>        [[(0, 1), (2, 7), (3, 4), (6, 9)],
>>>>>>>          [(0, 4), (2, 3), (5, 7), (6, 8)],
>>>>>>>          [(0, 5), (1, 6), (3, 8), (7, 9)],
>>>>>>>          [(1, 2), (4, 9), (5, 8)]]
>>>>>>>        sage: vizing_edge_coloring(g, hex_colors=True)
>>>>>>>         {'#00ffff': [(0, 5), (1, 6), (3, 8), (7, 9)],
>>>>>>>         '#7f00ff': [(1, 2), (4, 9), (5, 8)],
>>>>>>>         '#7fff00': [(0, 4), (2, 3), (5, 7), (6, 8)],
>>>>>>>         '#ff0000': [(0, 1), (2, 7), (3, 4), (6, 9)]}
>>>>>>>
>>>>>>>     TESTS:
>>>>>>>
>>>>>>>     Graph without edge::
>>>>>>>
>>>>>>>        sage: g = Graph(2)
>>>>>>>        sage: vizing_edge_coloring(g)
>>>>>>>        []
>>>>>>>        sage: vizing_edge_coloring(g, hex_colors=True)
>>>>>>>        {}
>>>>>>>     """
>>>>>>>     # finds every color adjacent to vertex v
>>>>>>>     def colors_of(v):
>>>>>>>         return [x[2] for x in g.edges_incident(v) if x[2] is not 
>>>>>>> None]
>>>>>>>
>>>>>>>     # constructs a maximal fan <f..l> of X where X is edge[0] and f 
>>>>>>> is edge[1]
>>>>>>>     def maximal_fan(edge):
>>>>>>>         fan_center, rear = edge
>>>>>>>         rear_colors = colors_of(rear)
>>>>>>>         cdef list neighbors = [n for n in g.neighbors(fan_center) if 
>>>>>>> g.edge_label(fan_center, n) is not None]
>>>>>>>         cdef list fan = [rear]
>>>>>>>         can_extend_fan = True
>>>>>>>         while can_extend_fan:
>>>>>>>             can_extend_fan = False
>>>>>>>             for n in neighbors:
>>>>>>>                 if g.edge_label(fan_center, n) not in rear_colors:
>>>>>>>                     fan.append(n)
>>>>>>>                     rear = n
>>>>>>>                     rear_colors = colors_of(rear)
>>>>>>>                     can_extend_fan = True
>>>>>>>                     neighbors.remove(n)
>>>>>>>         return fan
>>>>>>>
>>>>>>>     # gives each edge Xu in the fan <f..w> the color of Xu+ and 
>>>>>>> uncolors Xw
>>>>>>>     def rotate_fan(fan_center, fan):
>>>>>>>         for i in range(1, len(fan)):
>>>>>>>             g.set_edge_label(fan_center, fan[i - 1], 
>>>>>>> g.edge_label(fan_center, fan[i]))
>>>>>>>         g.set_edge_label(fan_center, fan[-1], None)
>>>>>>>
>>>>>>>     # computes the maximal ab-path starting at v
>>>>>>>     def find_path(v, a, b, path=[]):
>>>>>>>         path_edge = [x for x in g.edges_incident(v) if x[2] == a]
>>>>>>>         if path_edge and path_edge[0] not in path:
>>>>>>>             path.append(path_edge[0][0] if path_edge[0][1] == v else 
>>>>>>> path_edge[0][1])
>>>>>>>             find_path(path[-1], b, a, path)
>>>>>>>         return path
>>>>>>>
>>>>>>>     # exchanges the color of every edge on the ab-path starting at v
>>>>>>>     def invert_path(v, a, b):
>>>>>>>         path = [v] + find_path(v, a, b, [])
>>>>>>>         for i in range(1, len(path)):
>>>>>>>             g.set_edge_label(path[i-1], path[i], a if 
>>>>>>> g.edge_label(path[i-1], path[i]) == b else b)
>>>>>>>
>>>>>>>     # returns the ´smallest´ color free at v
>>>>>>>     def find_free_color(v):
>>>>>>>         colors = [x[2] for x in g.edges_incident(v) if x[2] is not 
>>>>>>> None]
>>>>>>>         for c in range(g.degree(v) + 1):
>>>>>>>             if c not in colors:
>>>>>>>                 return c
>>>>>>>
>>>>>>>     g._scream_if_not_simple()
>>>>>>>     # as to not overwrite the original graph's labels
>>>>>>>     g = copy(g)
>>>>>>>     for e in g.edge_iterator(labels=False):
>>>>>>>         fan = maximal_fan(e)
>>>>>>>         fan_center = e[0]
>>>>>>>         rear = fan[-1]
>>>>>>>         c = find_free_color(fan_center)
>>>>>>>         d = find_free_color(rear)
>>>>>>>         invert_path(fan_center, d, c)
>>>>>>>         for i in range(len(fan)):
>>>>>>>             if d not in colors_of(fan[i]):
>>>>>>>                 fan = fan[:i + 1]
>>>>>>>                 break
>>>>>>>         rotate_fan(fan_center, fan)
>>>>>>>         g.set_edge_label(fan_center, fan[-1], d)
>>>>>>>
>>>>>>>     matchings = dict()
>>>>>>>     for e in g.edge_iterator():
>>>>>>>         matchings[e[2]] = matchings.get(e[2], []) + [(e[0], e[1])]
>>>>>>>     classes = list(matchings.values())
>>>>>>>
>>>>>>>     if hex_colors:
>>>>>>>         from sage.plot.colors import rainbow
>>>>>>>         return dict(zip(rainbow(len(classes)), classes))
>>>>>>>     else:
>>>>>>>         return classes
>>>>>>>
>>>>>>

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sage-devel/f2faa5d9-5240-4f10-9e88-86fa036dd170n%40googlegroups.com.

Reply via email to