Skip to content

Commit 1311c29

Browse files
committed
PR #35891: add deprecation warning in connected_component methods for sorting
1 parent 49b7a0d commit 1311c29

File tree

1 file changed

+104
-18
lines changed

1 file changed

+104
-18
lines changed

src/sage/graphs/connectivity.pyx

Lines changed: 104 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ Methods
5858
-------
5959
"""
6060

61+
# ****************************************************************************
62+
#
63+
# Copyright (C) 2023 David Coudert <[email protected]>
64+
#
65+
# This program is free software: you can redistribute it and/or modify
66+
# it under the terms of the GNU General Public License as published by
67+
# the Free Software Foundation, either version 2 of the License, or
68+
# (at your option) any later version.
69+
# https://www.gnu.org/licenses/
70+
# ****************************************************************************
71+
72+
from sage.misc.superseded import deprecation
6173

6274
def is_connected(G):
6375
"""
@@ -119,7 +131,7 @@ def is_connected(G):
119131
return len(conn_verts) == G.num_verts()
120132

121133

122-
def connected_components(G, sort=False):
134+
def connected_components(G, sort=None, key=None):
123135
"""
124136
Return the list of connected components.
125137
@@ -130,8 +142,16 @@ def connected_components(G, sort=False):
130142
131143
- ``G`` -- the input graph
132144
133-
- ``sort`` -- boolean (default: ``False``); whether to sort vertices inside
134-
each component
145+
- ``sort`` -- boolean (default: ``None``); if ``True``, vertices inside each
146+
component are sorted according to the default ordering
147+
148+
As of :trac:`35889`, this argument must be explicitly specified (unless a
149+
``key`` is given); otherwise a warning is printed and ``sort=True`` is
150+
used. The default will eventually be changed to ``False``.
151+
152+
- ``key`` -- a function (default: ``None``); a function that takes a
153+
vertex as its one argument and returns a value that can be used for
154+
comparisons in the sorting algorithm (we must have ``sort=True``)
135155
136156
EXAMPLES::
137157
@@ -142,8 +162,10 @@ def connected_components(G, sort=False):
142162
sage: G.connected_components(sort=True)
143163
[[0, 1, 2, 3], [4, 5, 6]]
144164
sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]})
145-
sage: connected_components(D, True)
165+
sage: connected_components(D, sort=True)
146166
[[0, 1, 2, 3], [4, 5, 6]]
167+
sage: connected_components(D, sort=True, key=lambda x: -x)
168+
[[3, 2, 1, 0], [6, 5, 4]]
147169
148170
TESTS:
149171
@@ -154,16 +176,40 @@ def connected_components(G, sort=False):
154176
Traceback (most recent call last):
155177
...
156178
TypeError: the input must be a Sage graph
179+
180+
When parameter ``key`` is set, parameter ``sort`` must be ``True``::
181+
182+
sage: G = Graph(2)
183+
sage: G.connected_components(sort=False, key=lambda x: x)
184+
Traceback (most recent call last):
185+
...
186+
ValueError: sort keyword is False, yet a key function is given
187+
188+
Deprecation warning for ``sort=None`` (:trac:`35889`)::
189+
190+
sage: G = graphs.HouseGraph()
191+
sage: G.connected_components()
192+
doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future
193+
See https://github.com/sagemath/sage/issues/35889 for details.
194+
[[0, 1, 2, 3, 4]]
157195
"""
158196
from sage.graphs.generic_graph import GenericGraph
159197
if not isinstance(G, GenericGraph):
160198
raise TypeError("the input must be a Sage graph")
161199

200+
if sort is None:
201+
if key is None:
202+
deprecation(35889, "parameter 'sort' will be set to False by default in the future")
203+
sort = True
204+
205+
if (not sort) and key:
206+
raise ValueError('sort keyword is False, yet a key function is given')
207+
162208
cdef set seen = set()
163209
cdef list components = []
164210
for v in G:
165211
if v not in seen:
166-
c = connected_component_containing_vertex(G, v, sort=sort)
212+
c = connected_component_containing_vertex(G, v, sort=sort, key=key)
167213
seen.update(c)
168214
components.append(c)
169215
components.sort(key=lambda comp: -len(comp))
@@ -236,7 +282,7 @@ def connected_components_subgraphs(G):
236282
return [G.subgraph(c, inplace=False) for c in connected_components(G, sort=False)]
237283

238284

239-
def connected_component_containing_vertex(G, vertex, sort=False):
285+
def connected_component_containing_vertex(G, vertex, sort=None, key=None):
240286
"""
241287
Return a list of the vertices connected to vertex.
242288
@@ -246,8 +292,16 @@ def connected_component_containing_vertex(G, vertex, sort=False):
246292
247293
- ``v`` -- the vertex to search for
248294
249-
- ``sort`` -- boolean (default: ``False``); whether to sort vertices inside
250-
the component
295+
- ``sort`` -- boolean (default: ``None``); if ``True``, vertices inside the
296+
component are sorted according to the default ordering
297+
298+
As of :trac:`35889`, this argument must be explicitly specified (unless a
299+
``key`` is given); otherwise a warning is printed and ``sort=True`` is
300+
used. The default will eventually be changed to ``False``.
301+
302+
- ``key`` -- a function (default: ``None``); a function that takes a
303+
vertex as its one argument and returns a value that can be used for
304+
comparisons in the sorting algorithm (we must have ``sort=True``)
251305
252306
EXAMPLES::
253307
@@ -260,6 +314,8 @@ def connected_component_containing_vertex(G, vertex, sort=False):
260314
sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]})
261315
sage: connected_component_containing_vertex(D, 0, sort=True)
262316
[0, 1, 2, 3]
317+
sage: connected_component_containing_vertex(D, 0, sort=True, key=lambda x: -x)
318+
[3, 2, 1, 0]
263319
264320
TESTS:
265321
@@ -274,24 +330,48 @@ def connected_component_containing_vertex(G, vertex, sort=False):
274330
:trac:`35889` is fixed::
275331
276332
sage: G = Graph([('A', 1)])
277-
sage: G.connected_component_containing_vertex(1)
333+
sage: G.connected_component_containing_vertex(1, sort=False)
278334
[1, 'A']
279335
sage: G.connected_component_containing_vertex(1, sort=True)
280336
Traceback (most recent call last):
281337
...
282338
TypeError: '<' not supported between instances of 'str' and 'int'
339+
340+
When parameter ``key`` is set, parameter ``sort`` must be ``True``::
341+
342+
sage: G = Graph(2)
343+
sage: G.connected_component_containing_vertex(1, sort=False, key=lambda x: x)
344+
Traceback (most recent call last):
345+
...
346+
ValueError: sort keyword is False, yet a key function is given
347+
348+
Deprecation warning for ``sort=None`` (:trac:`35889`)::
349+
350+
sage: G = graphs.HouseGraph()
351+
sage: G.connected_component_containing_vertex(1)
352+
doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future
353+
See https://github.com/sagemath/sage/issues/35889 for details.
354+
[0, 1, 2, 3, 4]
283355
"""
284356
from sage.graphs.generic_graph import GenericGraph
285357
if not isinstance(G, GenericGraph):
286358
raise TypeError("the input must be a Sage graph")
287359

360+
if sort is None:
361+
if key is None:
362+
deprecation(35889, "parameter 'sort' will be set to False by default in the future")
363+
sort = True
364+
365+
if (not sort) and key:
366+
raise ValueError('sort keyword is False, yet a key function is given')
367+
288368
try:
289369
c = list(G._backend.depth_first_search(vertex, ignore_direction=True))
290370
except AttributeError:
291371
c = list(G.depth_first_search(vertex, ignore_direction=True))
292372

293373
if sort:
294-
c.sort()
374+
return sorted(c, key=key)
295375
return c
296376

297377

@@ -335,7 +415,7 @@ def connected_components_sizes(G):
335415
return [len(cc) for cc in connected_components(G, sort=False)]
336416

337417

338-
def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False):
418+
def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False, key=None):
339419
"""
340420
Return the blocks and cut vertices of the graph.
341421
@@ -361,6 +441,10 @@ def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False):
361441
the components and the list of cut vertices
362442
**currently only available for ``"Tarjan_Sage"``**
363443
444+
- ``key`` -- a function (default: ``None``); a function that takes a
445+
vertex as its one argument and returns a value that can be used for
446+
comparisons in the sorting algorithm (we must have ``sort=True``)
447+
364448
OUTPUT: ``(B, C)``, where ``B`` is a list of blocks - each is a list of
365449
vertices and the blocks are the corresponding induced subgraphs - and
366450
``C`` is a list of cut vertices.
@@ -449,6 +533,9 @@ def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False):
449533
raise NotImplementedError("blocks and cut vertices algorithm '%s' is not implemented" % algorithm)
450534

451535
# If algorithm is "Tarjan_Sage"
536+
if (not sort) and key:
537+
raise ValueError('sort keyword is False, yet a key function is given')
538+
452539
blocks = []
453540
cut_vertices = set()
454541

@@ -541,7 +628,7 @@ def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False):
541628
u1, u2 = edge_stack.pop()
542629
new_block.add(u1)
543630
if sort:
544-
this_block = sorted(new_block)
631+
this_block = sorted(new_block, key=key)
545632
else:
546633
this_block = list(new_block)
547634
blocks.append(this_block)
@@ -556,9 +643,8 @@ def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False):
556643
start_already_seen = True
557644

558645
if sort:
559-
return blocks, sorted(cut_vertices)
560-
else:
561-
return blocks, list(cut_vertices)
646+
return blocks, sorted(cut_vertices, key=key)
647+
return blocks, list(cut_vertices)
562648

563649

564650
def blocks_and_cuts_tree(G):
@@ -1113,9 +1199,9 @@ def edge_connectivity(G,
11131199
b = set(H).difference(a)
11141200
val.append([a, b])
11151201
else:
1116-
val.append(connected_components(H))
1202+
val.append([set(c) for c in connected_components(H, sort=False)])
11171203
elif vertices:
1118-
val.append([set(c) for c in connected_components(G)])
1204+
val.append([set(c) for c in connected_components(G, sort=False)])
11191205

11201206
return val
11211207

@@ -2137,7 +2223,7 @@ def cleave(G, cut_vertices=None, virtual_edges=True, solver=None, verbose=0,
21372223

21382224
H = G.copy(immutable=False)
21392225
H.delete_vertices(cut_vertices)
2140-
CC = H.connected_components()
2226+
CC = H.connected_components(sort=False)
21412227
if len(CC) == 1:
21422228
raise ValueError("the set cut_vertices is not a vertex cut of the graph")
21432229

0 commit comments

Comments
 (0)