@@ -332,12 +332,13 @@ def shortest_simple_paths(self, source, target, weight_function=None,
332
332
supported:
333
333
334
334
- ``'Yen'`` -- Yen's algorithm [Yen1970 ]_
335
+ ( :meth:`~sage. graphs. path_enumeration. yen_k_shortest_simple_paths`)
335
336
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` )
338
339
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` )
341
342
342
343
- ``report_edges`` -- boolean ( default: ``False``) ; whether to report paths
343
344
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,
471
472
('101', '011', 1),
472
473
('011', '111', 1) ]) ]
473
474
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
-
481
475
If the algorithm is not implemented::
482
476
483
477
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,
528
522
sage: s == t
529
523
True
530
524
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::
532
526
533
527
sage: G = digraphs. RandomDirectedGNP( 30, . 05)
534
528
sage: while not G. is_strongly_connected( ) :
@@ -546,6 +540,23 @@ def shortest_simple_paths(self, source, target, weight_function=None,
546
540
.... : raise ValueError( f"something goes wrong u={u}, v={v}, G={G. edges( ) }!")
547
541
.... : if i == 100:
548
542
.... : 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
549
560
"""
550
561
if source not in self :
551
562
raise ValueError (" vertex '{}' is not in the graph" .format(source))
@@ -569,9 +580,6 @@ def shortest_simple_paths(self, source, target, weight_function=None,
569
580
algorithm = " Feng" if self .is_directed() else " Yen"
570
581
571
582
if algorithm in (" Feng" , " PNC" ):
572
- if not self .is_directed():
573
- raise ValueError (f" {algorithm}'s algorithm works only for directed graphs" )
574
-
575
583
yield from nc_k_shortest_simple_paths(self , source = source, target = target,
576
584
weight_function = weight_function,
577
585
by_weight = by_weight, check_weight = check_weight,
@@ -897,8 +905,6 @@ def nc_k_shortest_simple_paths(self, source, target, weight_function=None,
897
905
Return an iterator over the simple paths between a pair of vertices in
898
906
increasing order of weights.
899
907
900
- Works only for directed graphs.
901
-
902
908
For unweighted graphs, paths are returned in order of increasing number
903
909
of edges.
904
910
@@ -1001,6 +1007,14 @@ def nc_k_shortest_simple_paths(self, source, target, weight_function=None,
1001
1007
( 40. 0, [(1, 2, 20), (2, 5, 20) ]) ,
1002
1008
( 60. 0, [(1, 4, 30), (4, 5, 30) ]) ]
1003
1009
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
+
1004
1018
TESTS::
1005
1019
1006
1020
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,
1150
1164
sage: for i in range( len( A) - 1) :
1151
1165
.... : assert A[i ] <= A[i + 1 ]
1152
1166
"""
1153
- if not self .is_directed():
1154
- raise ValueError (" this algorithm works only for directed graphs" )
1155
-
1156
1167
if source not in self :
1157
1168
raise ValueError (" vertex '{}' is not in the graph" .format(source))
1158
1169
if target not in self :
@@ -1164,6 +1175,11 @@ def nc_k_shortest_simple_paths(self, source, target, weight_function=None,
1164
1175
1165
1176
if self .has_loops() or self .allows_multiple_edges():
1166
1177
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' )
1167
1183
else :
1168
1184
G = self .copy(immutable = False )
1169
1185
@@ -1416,8 +1432,6 @@ def feng_k_shortest_simple_paths(self, source, target, weight_function=None,
1416
1432
Return an iterator over the simple paths between a pair of vertices in
1417
1433
increasing order of weights.
1418
1434
1419
- Works only for directed graphs.
1420
-
1421
1435
For unweighted graphs, paths are returned in order of increasing number
1422
1436
of edges.
1423
1437
@@ -1487,8 +1501,6 @@ def pnc_k_shortest_simple_paths(self, source, target, weight_function=None,
1487
1501
Return an iterator over the simple paths between a pair of vertices in
1488
1502
increasing order of weights.
1489
1503
1490
- Works only for directed graphs.
1491
-
1492
1504
In case of weighted graphs, negative weights are not allowed.
1493
1505
1494
1506
If ``source`` is the same vertex as ``target``, then ``[[source ]]`` is
0 commit comments