Skip to content

Commit 2e0b083

Browse files
committed
update nc_k_shortest_simple_paths for undirected graphs
1 parent dfa5625 commit 2e0b083

File tree

1 file changed

+30
-21
lines changed

1 file changed

+30
-21
lines changed

src/sage/graphs/path_enumeration.pyx

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -471,13 +471,6 @@ def shortest_simple_paths(self, source, target, weight_function=None,
471471
('101', '011', 1),
472472
('011', '111', 1)])]
473473
474-
Feng's algorithm cannot be used on undirected graphs::
475-
476-
sage: list(graphs.PathGraph(2).shortest_simple_paths(0, 1, algorithm='Feng'))
477-
Traceback (most recent call last):
478-
...
479-
ValueError: Feng's algorithm works only for directed graphs
480-
481474
If the algorithm is not implemented::
482475
483476
sage: list(g.shortest_simple_paths(1, 5, algorithm='tip top'))
@@ -528,7 +521,7 @@ def shortest_simple_paths(self, source, target, weight_function=None,
528521
sage: s == t
529522
True
530523
531-
Check that "Yen" and "Feng" provide same results on random digraphs::
524+
Check that "Yen", "Feng" and "PNC" provide same results on random digraphs::
532525
533526
sage: G = digraphs.RandomDirectedGNP(30, .05)
534527
sage: while not G.is_strongly_connected():
@@ -546,6 +539,24 @@ def shortest_simple_paths(self, source, target, weight_function=None,
546539
....: raise ValueError(f"something goes wrong u={u}, v={v}, G={G.edges()}!")
547540
....: if i == 100:
548541
....: break
542+
543+
Check that "Yen", "Feng" and "PNC" provide same results on random undirected graphs::
544+
545+
sage: from sage.graphs.generators.random import RandomGNP
546+
sage: G = RandomGNP(30, .05)
547+
sage: for u, v in list(G.edges(labels=False, sort=False)):
548+
....: G.set_edge_label(u, v, randint(1, 10))
549+
sage: V = G.vertices(sort=False)
550+
sage: shuffle(V)
551+
sage: u, v = V[:2]
552+
sage: it_Y = G.shortest_simple_paths(u, v, by_weight=True, report_weight=True, algorithm='Yen')
553+
sage: it_F = G.shortest_simple_paths(u, v, by_weight=True, report_weight=True, algorithm='Feng')
554+
sage: it_P = G.shortest_simple_paths(u, v, by_weight=True, report_weight=True, algorithm='PNC')
555+
sage: for i, (y, f, p) in enumerate(zip(it_Y, it_F, it_P)):
556+
....: if y[0] != f[0] or y[0] != p[0]:
557+
....: raise ValueError(f"something goes wrong u={u}, v={v}, G={G.edges()}!")
558+
....: if i == 100:
559+
....: break
549560
"""
550561
if source not in self:
551562
raise ValueError("vertex '{}' is not in the graph".format(source))
@@ -569,9 +580,6 @@ def shortest_simple_paths(self, source, target, weight_function=None,
569580
algorithm = "Feng" if self.is_directed() else "Yen"
570581

571582
if algorithm in ("Feng", "PNC"):
572-
if not self.is_directed():
573-
raise ValueError(f"{algorithm}'s algorithm works only for directed graphs")
574-
575583
yield from nc_k_shortest_simple_paths(self, source=source, target=target,
576584
weight_function=weight_function,
577585
by_weight=by_weight, check_weight=check_weight,
@@ -897,8 +905,6 @@ def nc_k_shortest_simple_paths(self, source, target, weight_function=None,
897905
Return an iterator over the simple paths between a pair of vertices in
898906
increasing order of weights.
899907
900-
Works only for directed graphs.
901-
902908
For unweighted graphs, paths are returned in order of increasing number
903909
of edges.
904910
@@ -1001,6 +1007,14 @@ def nc_k_shortest_simple_paths(self, source, target, weight_function=None,
10011007
(40.0, [(1, 2, 20), (2, 5, 20)]),
10021008
(60.0, [(1, 4, 30), (4, 5, 30)])]
10031009
1010+
Algorithm works for undirected graphs as well::
1011+
1012+
sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30)])
1013+
sage: list(nc_k_shortest_simple_paths(g, 5, 1, by_weight=True))
1014+
[[5, 3, 1], [5, 2, 1], [5, 4, 1]]
1015+
sage: list(nc_k_shortest_simple_paths(g, 5, 1))
1016+
[[5, 2, 1], [5, 4, 1], [5, 3, 1]]
1017+
10041018
TESTS::
10051019
10061020
sage: from sage.graphs.path_enumeration import nc_k_shortest_simple_paths
@@ -1150,9 +1164,6 @@ def nc_k_shortest_simple_paths(self, source, target, weight_function=None,
11501164
sage: for i in range(len(A) - 1):
11511165
....: assert A[i] <= A[i + 1]
11521166
"""
1153-
if not self.is_directed():
1154-
raise ValueError("this algorithm works only for directed graphs")
1155-
11561167
if source not in self:
11571168
raise ValueError("vertex '{}' is not in the graph".format(source))
11581169
if target not in self:
@@ -1163,9 +1174,11 @@ def nc_k_shortest_simple_paths(self, source, target, weight_function=None,
11631174
return
11641175

11651176
if self.has_loops() or self.allows_multiple_edges():
1166-
G = self.to_simple(to_undirected=False, keep_label='min', immutable=False)
1177+
G = self.to_simple(to_undirected=self.is_directed(), keep_label='min', immutable=False)
11671178
else:
11681179
G = self.copy(immutable=False)
1180+
if not G.is_directed():
1181+
G = G.to_directed()
11691182

11701183
G.delete_edges(G.incoming_edges(source, labels=False))
11711184
G.delete_edges(G.outgoing_edges(target, labels=False))
@@ -1416,8 +1429,6 @@ def feng_k_shortest_simple_paths(self, source, target, weight_function=None,
14161429
Return an iterator over the simple paths between a pair of vertices in
14171430
increasing order of weights.
14181431
1419-
Works only for directed graphs.
1420-
14211432
For unweighted graphs, paths are returned in order of increasing number
14221433
of edges.
14231434
@@ -1487,8 +1498,6 @@ def pnc_k_shortest_simple_paths(self, source, target, weight_function=None,
14871498
Return an iterator over the simple paths between a pair of vertices in
14881499
increasing order of weights.
14891500
1490-
Works only for directed graphs.
1491-
14921501
In case of weighted graphs, negative weights are not allowed.
14931502
14941503
If ``source`` is the same vertex as ``target``, then ``[[source]]`` is

0 commit comments

Comments
 (0)