@@ -332,12 +332,13 @@ def shortest_simple_paths(self, source, target, weight_function=None,
332332 supported:
333333
334334 - ``'Yen'`` -- Yen's algorithm [Yen1970 ]_
335+ ( :meth:`~sage. graphs. path_enumeration. yen_k_shortest_simple_paths`)
335336
336- - ``'Feng'`` -- an improved version of Yen's algorithm but that works only
337- for directed graphs [ Feng2014 ]_
337+ - ``'Feng'`` -- an improved version of Yen's algorithm [ Feng2014 ]_
338+ ( :meth:`~sage . graphs. path_enumeration . feng_k_shortest_simple_paths` )
338339
339- - ``'PNC'`` -- an improved version of Feng's algorithm. This also works only
340- for directed graphs [ ACN2023 ]_
340+ - ``'PNC'`` -- an improved version of Feng's algorithm [ ACN2023 ]_
341+ ( :meth:`~sage . graphs. path_enumeration . pnc_k_shortest_simple_paths` )
341342
342343 - ``report_edges`` -- boolean ( default: ``False``) ; whether to report paths
343344 as list of vertices ( default) or list of edges. When set to ``False``, the
@@ -471,13 +472,6 @@ def shortest_simple_paths(self, source, target, weight_function=None,
471472 ('101', '011', 1),
472473 ('011', '111', 1) ]) ]
473474
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-
481475 If the algorithm is not implemented::
482476
483477 sage: list( g. shortest_simple_paths( 1, 5, algorithm='tip top'))
@@ -528,7 +522,7 @@ def shortest_simple_paths(self, source, target, weight_function=None,
528522 sage: s == t
529523 True
530524
531- Check that "Yen" and "Feng " provide same results on random digraphs::
525+ Check that "Yen", "Feng" and "PNC " provide same results on random digraphs::
532526
533527 sage: G = digraphs. RandomDirectedGNP( 30, . 05)
534528 sage: while not G. is_strongly_connected( ) :
@@ -546,6 +540,23 @@ def shortest_simple_paths(self, source, target, weight_function=None,
546540 .... : raise ValueError( f"something goes wrong u={u}, v={v}, G={G. edges( ) }!")
547541 .... : if i == 100:
548542 .... : break
543+
544+ Check that "Yen", "Feng" and "PNC" provide same results on random undirected graphs::
545+
546+ sage: G = graphs. RandomGNP( 30, . 5)
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: [len(P) for P in nc_k_shortest_simple_paths(g, 5, 1) ]
1016+ [3, 3, 3 ]
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 :
@@ -1164,6 +1175,11 @@ def nc_k_shortest_simple_paths(self, source, target, weight_function=None,
11641175
11651176 if self .has_loops() or self .allows_multiple_edges():
11661177 G = self .to_simple(to_undirected = False , keep_label = ' min' , immutable = False )
1178+ if not G.is_directed():
1179+ G = G.to_directed()
1180+ elif not self .is_directed():
1181+ # Turn the graph into a mutable directed graph
1182+ G = self .to_directed(data_structure = ' sparse' )
11671183 else :
11681184 G = self .copy(immutable = False )
11691185
@@ -1416,8 +1432,6 @@ def feng_k_shortest_simple_paths(self, source, target, weight_function=None,
14161432 Return an iterator over the simple paths between a pair of vertices in
14171433 increasing order of weights.
14181434
1419- Works only for directed graphs.
1420-
14211435 For unweighted graphs, paths are returned in order of increasing number
14221436 of edges.
14231437
@@ -1487,8 +1501,6 @@ def pnc_k_shortest_simple_paths(self, source, target, weight_function=None,
14871501 Return an iterator over the simple paths between a pair of vertices in
14881502 increasing order of weights.
14891503
1490- Works only for directed graphs.
1491-
14921504 In case of weighted graphs, negative weights are not allowed.
14931505
14941506 If ``source`` is the same vertex as ``target``, then ``[[source ]]`` is
0 commit comments