@@ -471,13 +471,6 @@ def shortest_simple_paths(self, source, target, weight_function=None,
471
471
('101', '011', 1),
472
472
('011', '111', 1) ]) ]
473
473
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
474
If the algorithm is not implemented::
482
475
483
476
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,
528
521
sage: s == t
529
522
True
530
523
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::
532
525
533
526
sage: G = digraphs. RandomDirectedGNP( 30, . 05)
534
527
sage: while not G. is_strongly_connected( ) :
@@ -546,6 +539,24 @@ def shortest_simple_paths(self, source, target, weight_function=None,
546
539
.... : raise ValueError( f"something goes wrong u={u}, v={v}, G={G. edges( ) }!")
547
540
.... : if i == 100:
548
541
.... : 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
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: list( nc_k_shortest_simple_paths( g, 5, 1))
1016
+ [[5, 2, 1 ], [5, 4, 1 ], [5, 3, 1 ]]
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 :
@@ -1163,9 +1174,11 @@ def nc_k_shortest_simple_paths(self, source, target, weight_function=None,
1163
1174
return
1164
1175
1165
1176
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 )
1167
1178
else :
1168
1179
G = self .copy(immutable = False )
1180
+ if not G.is_directed():
1181
+ G = G.to_directed()
1169
1182
1170
1183
G.delete_edges(G.incoming_edges(source, labels = False ))
1171
1184
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,
1416
1429
Return an iterator over the simple paths between a pair of vertices in
1417
1430
increasing order of weights.
1418
1431
1419
- Works only for directed graphs.
1420
-
1421
1432
For unweighted graphs, paths are returned in order of increasing number
1422
1433
of edges.
1423
1434
@@ -1487,8 +1498,6 @@ def pnc_k_shortest_simple_paths(self, source, target, weight_function=None,
1487
1498
Return an iterator over the simple paths between a pair of vertices in
1488
1499
increasing order of weights.
1489
1500
1490
- Works only for directed graphs.
1491
-
1492
1501
In case of weighted graphs, negative weights are not allowed.
1493
1502
1494
1503
If ``source`` is the same vertex as ``target``, then ``[[source ]]`` is
0 commit comments