Skip to content

Commit 53eb914

Browse files
author
Release Manager
committed
gh-39763: Updated methods concerning addition of edges in a matching covered graph <!-- ^ Please provide a concise and informative title. --> The objective of this issue is to update the methods concerning addition of edges in a matching covered graph. <!-- ^ Don't put issue numbers in the title, do this in the PR description below. --> <!-- ^ For example, instead of "Fixes #12345" use "Introduce new method to calculate 1 + 2". --> <!-- v Describe your changes below in detail. --> More specifically, this PR aims to updated the following methods: - [x] `add_edges()` | Add edges from an iterable container. <!-- v Why is this change required? What problem does it solve? --> Please note that earlier this method used to add only one multiple edge, even though the container contains several of those. <!-- v If this PR resolves an open issue, please link to it here. For example, "Fixes #12345". --> Fixes #38216. Note that this issue fixes a small part of the mentioned issue. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [x] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies Nothing as of now. <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - #12345: short description why this is a dependency --> <!-- - #34567: ... --> cc: @dcoudert. URL: #39763 Reported by: Janmenjaya Panda Reviewer(s): David Coudert, Janmenjaya Panda
2 parents 1319a52 + 4190432 commit 53eb914

File tree

1 file changed

+65
-36
lines changed

1 file changed

+65
-36
lines changed

src/sage/graphs/matching_covered_graph.py

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,14 +1174,18 @@ def add_edges(self, edges, loops=False):
11741174
INPUT:
11751175
11761176
- ``edges`` -- an iterable of edges, given either as ``(u, v)``
1177-
or ``(u, v, 'label')``
1177+
or ``(u, v, 'label')``. If an edge is provided in the format
1178+
``(u, v)``, the label is set to ``None``.
11781179
11791180
- ``loops`` -- boolean (default: ``False``); note that this shall
11801181
always be set to either ``False`` or ``None`` (since matching covered
11811182
graphs are free of loops), in which case all the loops
11821183
``(v, v, 'label')`` are removed from the iterator. If ``loops`` is
11831184
set to ``True``, a :exc:`ValueError` is thrown.
11841185
1186+
- Please note that all the loops present in the iterator are ignored,
1187+
provided that ``loops`` is set to ``False`` or ``None``.
1188+
11851189
OUTPUT:
11861190
11871191
- If ``loops`` is set to ``True``, a :exc:`ValueError` is returned.
@@ -1213,7 +1217,7 @@ def add_edges(self, edges, loops=False):
12131217
sage: G = MatchingCoveredGraph(S)
12141218
sage: F = [(0, 4), (2, 4), (4, 6), (4, 7)]
12151219
sage: G.add_edges(F)
1216-
sage: G.edges(sort=True)
1220+
sage: G.edges(sort=True, sort_vertices=True)
12171221
[(0, 1, None), (0, 3, None), (0, 4, None), (0, 6, None),
12181222
(1, 2, None), (1, 4, None), (2, 4, None), (2, 5, None),
12191223
(2, 7, None), (3, 4, None), (3, 6, None), (4, 5, None),
@@ -1228,7 +1232,7 @@ def add_edges(self, edges, loops=False):
12281232
sage: F = [(0, 9), (1, 8), (2, 9), (3, 8),
12291233
....: (4, 9), (5, 8), (6, 9), (7, 8)]
12301234
sage: G.add_edges(F)
1231-
sage: G.edges(sort=True)
1235+
sage: G.edges(sort=True, sort_vertices=True)
12321236
[(0, 1, None), (0, 7, None), (0, 9, None), (1, 2, None),
12331237
(1, 8, None), (2, 3, None), (2, 9, None), (3, 4, None),
12341238
(3, 8, None), (4, 5, None), (4, 9, None), (5, 6, None),
@@ -1243,7 +1247,7 @@ def add_edges(self, edges, loops=False):
12431247
sage: F = {(0, 8, None), (1, 10), (4, 11, 'label'),
12441248
....: (5, 9), (8, 9), (10, 11)}
12451249
sage: G.add_edges(F)
1246-
sage: G.edges(sort=True)
1250+
sage: G.edges(sort=True, sort_vertices=True)
12471251
[(0, 1, None), (0, 3, None), (0, 4, None), (0, 8, None),
12481252
(1, 2, None), (1, 5, None), (1, 10, None), (2, 3, None),
12491253
(2, 6, None), (3, 7, None), (4, 5, None), (4, 7, None),
@@ -1289,7 +1293,7 @@ def add_edges(self, edges, loops=False):
12891293
sage: G = MatchingCoveredGraph(W)
12901294
sage: F = [(0, 0), (1, 3), (2, 4)]
12911295
sage: G.add_edges(edges=F, loops=False)
1292-
sage: G.edges(sort=True)
1296+
sage: G.edges(sort=True, sort_vertices=True)
12931297
[(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None),
12941298
(0, 5, None), (1, 2, None), (1, 3, None), (1, 5, None),
12951299
(2, 3, None), (2, 4, None), (3, 4, None), (4, 5, None)]
@@ -1298,7 +1302,7 @@ def add_edges(self, edges, loops=False):
12981302
Traceback (most recent call last):
12991303
...
13001304
ValueError: loops are not allowed in matching covered graphs
1301-
sage: G.edges(sort=True)
1305+
sage: G.edges(sort=True, sort_vertices=True)
13021306
[(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None),
13031307
(0, 5, None), (1, 2, None), (1, 3, None), (1, 5, None),
13041308
(2, 3, None), (2, 4, None), (3, 4, None), (4, 5, None)]
@@ -1325,17 +1329,31 @@ def add_edges(self, edges, loops=False):
13251329
(0, 6, None), (1, 2, None), (1, 2, None), (1, 4, None),
13261330
(2, 5, None), (2, 7, None), (3, 4, None), (3, 6, None),
13271331
(4, 5, None), (5, 7, None), (6, 7, None)]
1332+
sage: H = [(0, 1)] * 4
1333+
sage: G.add_edges(H)
1334+
sage: G.edge_label(0, 1)
1335+
[None, None, None, None, None, 'label']
13281336
13291337
TESTS:
13301338
1339+
Providing with a non-iterable of edges::
1340+
1341+
sage: K2 = graphs.CompleteGraph(2)
1342+
sage: G = MatchingCoveredGraph(K2)
1343+
sage: G.add_edges(1234)
1344+
Traceback (most recent call last):
1345+
...
1346+
ValueError: expected an iterable of edges,
1347+
but got a non-iterable object
1348+
13311349
Providing with an edge in ``edges`` that has 0 values to unpack::
13321350
13331351
sage: W = graphs.WagnerGraph()
13341352
sage: G = MatchingCoveredGraph(W)
13351353
sage: G.add_edges([()])
13361354
Traceback (most recent call last):
13371355
...
1338-
ValueError: need more than 0 values to unpack
1356+
ValueError: need more than 1 value to unpack for edge: ()
13391357
13401358
Providing with an edge in ``edges`` that has precisely one value to unpack::
13411359
@@ -1344,7 +1362,7 @@ def add_edges(self, edges, loops=False):
13441362
sage: G.add_edges([(0, )])
13451363
Traceback (most recent call last):
13461364
...
1347-
ValueError: need more than 1 value to unpack
1365+
ValueError: need more than 1 value to unpack for edge: (0,)
13481366
13491367
Providing with an edge in ``edges`` that has more than 3 values to unpack::
13501368
@@ -1353,17 +1371,17 @@ def add_edges(self, edges, loops=False):
13531371
sage: G.add_edges([(0, 1, 2, 3, 4)])
13541372
Traceback (most recent call last):
13551373
...
1356-
ValueError: too many values to unpack (expected 2)
1374+
ValueError: too many values to unpack (expected 2) for edge: (0, 1, 2, 3, 4)
13571375
13581376
Providing with an edge of unknown data type::
13591377
13601378
sage: M = graphs.MurtyGraph()
13611379
sage: G = MatchingCoveredGraph(M)
1362-
sage: F = ['', 'edge', None, 1234]
1380+
sage: F = [None, 'edge', None]
13631381
sage: G.add_edges(F)
13641382
Traceback (most recent call last):
13651383
...
1366-
TypeError: input edges is of unknown type
1384+
TypeError: input edge None is of unknown type
13671385
"""
13681386
if loops:
13691387
raise ValueError('loops are not allowed in '
@@ -1372,34 +1390,45 @@ def add_edges(self, edges, loops=False):
13721390
if not edges: # do nothing
13731391
return
13741392

1375-
for edge in edges:
1376-
if isinstance(edge, tuple):
1377-
if len(edge) == 0:
1378-
raise ValueError('need more than 0 values to unpack')
1393+
from collections.abc import Iterable
1394+
if not isinstance(edges, Iterable):
1395+
raise ValueError('expected an iterable of edges, '
1396+
'but got a non-iterable object')
13791397

1380-
elif len(edge) == 1:
1381-
raise ValueError('need more than 1 value to unpack')
1398+
links = [] # to extract the nonloop input edges
1399+
for edge in edges:
1400+
if hasattr(edge, '__len__'):
1401+
if len(edge) <= 1:
1402+
raise ValueError('need more than 1 value to unpack '
1403+
f'for edge: {edge}')
13821404

13831405
elif len(edge) > 3:
1384-
raise ValueError('too many values to unpack (expected 2)')
1406+
raise ValueError('too many values to unpack (expected 2) '
1407+
f'for edge: {edge}')
13851408

13861409
else:
1387-
raise TypeError('input edges is of unknown type')
1410+
raise TypeError(f'input edge {edge} is of unknown type')
13881411

1389-
# Remove potentially duplicated edges
1390-
edges = list(set(edges))
1412+
u, v, l = None, None, None
13911413

1392-
# Remove all the loops from edges
1393-
for edge in edges:
1394-
if edge[0] == edge[1]:
1395-
edges.remove(edge)
1414+
if len(edge) == 2:
1415+
u, v = edge
13961416

1397-
# Check if all the incident vertices of the input edges are existent
1398-
new_vertices = list(set([x for u, v, *_ in edges for x in [u, v]]))
1417+
else:
1418+
u, v, l = edge
1419+
1420+
if u != v:
1421+
links.append((u, v, l))
13991422

1400-
for vertex in new_vertices[:]:
1401-
if vertex in self:
1402-
new_vertices.remove(vertex)
1423+
# If each of the input edges is existent
1424+
if (self.allows_multiple_edges()
1425+
and all(self.has_edge(*edge) for edge in links)):
1426+
self._backend.add_edges(links, self._directed)
1427+
return
1428+
1429+
# Check if all the incident vertices of the input edges are existent
1430+
new_vertices = {x for u, v, _ in links for x in (u, v)
1431+
if x not in self}
14031432

14041433
# Throw error if the no. of new vertices is odd
14051434
if len(new_vertices) % 2:
@@ -1408,7 +1437,7 @@ def add_edges(self, edges, loops=False):
14081437

14091438
try:
14101439
G = Graph(self, multiedges=self.allows_multiple_edges())
1411-
G.add_edges(edges=edges, loops=loops)
1440+
G.add_edges(edges=links, loops=loops)
14121441

14131442
# Check if G has a vertex with at most 1 neighbor
14141443
if any(len(G.neighbors(v)) <= 1 for v in G):
@@ -1423,14 +1452,14 @@ def add_edges(self, edges, loops=False):
14231452
else:
14241453
# Check if the existing perfect matching may be extended to a
14251454
# perfect matching of the new graph
1426-
edges_with_two_new_vertices = []
1455+
links_with_two_new_vertices = []
14271456

1428-
for edge in edges:
1457+
for edge in links:
14291458
if edge[0] in new_vertices and edge[1] in new_vertices:
1430-
edges_with_two_new_vertices.append(edge)
1459+
links_with_two_new_vertices.append(edge)
14311460

1432-
H = Graph(data=edges_with_two_new_vertices, format='list_of_edges')
1433-
M = Graph(self.get_matching()).union(Graph(H.matching()))
1461+
M = Graph(data=links_with_two_new_vertices, format='list_of_edges')
1462+
M.add_edges(self.get_matching())
14341463

14351464
# Check if M is a perfect matching of the resulting graph
14361465
if (G.order() != 2*M.size()):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy