Skip to content

Commit dfc400f

Browse files
committed
Add iterator for K-Shortest-Paths in a weighted graph
1 parent 4b88960 commit dfc400f

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

gap/weights.gd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ DeclareGlobalFunction("DIGRAPHS_Edge_Weighted_Johnson");
3333
DeclareGlobalFunction("DIGRAPHS_Edge_Weighted_FloydWarshall");
3434
DeclareGlobalFunction("DIGRAPHS_Edge_Weighted_Bellman_Ford");
3535
DeclareGlobalFunction("DIGRAPHS_Edge_Weighted_Dijkstra");
36+
DeclareGlobalFunction("DIGRAPHS_ShortestPathsIterator");

gap/weights.gi

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,3 +616,75 @@ function(digraph, source)
616616

617617
return rec(distances := distances, parents := parents, edges := edges);
618618
end);
619+
620+
#############################################################################
621+
# 4. Shortest Paths Iterator
622+
#############################################################################
623+
#
624+
# returns an iterator that generates the (possibly empty) sequence of paths
625+
# between source and dest
626+
#
627+
# the iterator needs to store
628+
# - found paths
629+
# - candidates
630+
# -
631+
# rec( found_paths := [],
632+
InstallGlobalFunction(DIGRAPHS_ShortestPathsIterator,
633+
function(digraph, source, dest)
634+
local currentIterator, findNextPath;
635+
636+
currentIterator := rec(
637+
candidates := BinaryHeap(),
638+
foundPaths := [
639+
EdgeWeightedDigraphShortestPath(digraph, source, dest)
640+
]);
641+
642+
findNextPath := function(iter)
643+
local currentShortestPath, currentShortestPathLength, spurNode, rootPath,
644+
rootPathNode, modifiedGraph, foundPaths, i, p, spurPath, totalPath,
645+
nextPath;
646+
647+
currentShortestPath := Last(iter.foundPaths);
648+
currentShortestPathLength := Length(currentShortestPath[1]);
649+
foundPaths := iter.foundPaths;
650+
651+
for i in [1 .. currentShortestPathLength] do
652+
modifiedGraph := fail;
653+
654+
spurNode := currentShortestPath[1][i];
655+
rootPath := [
656+
currentShortestPath[1]{[1..i]},
657+
currentShortestPath[2]{[1..i-1]}
658+
];
659+
660+
for p in foundPaths do
661+
if rootPath = p[1]{[1..i]} then
662+
# remove p[2][i] from Graph;
663+
fi;
664+
od;
665+
666+
for rootPathNode in rootPath[1] do
667+
if rootPathNode <> spurNode then
668+
# remove rootPathNode from Graph;
669+
fi;
670+
od;
671+
672+
spurPath := EdgeWeightedDigraphShortestPath(modifiedGraph, spurNode, dest);
673+
totalPath := [ Concatenation(rootPath[1], spurPath[1]),
674+
Concatenation(rootPath[2], spurPath[2]) ];
675+
676+
Push(iter.candidatePaths, totalPath);
677+
od;
678+
679+
if IsEmpty(iter.candidatePaths) then
680+
return fail;
681+
fi;
682+
683+
nextPath := Pop(iter.candidatePaths);
684+
Push(iter.foundPaths, nextPath);
685+
686+
return nextPath;
687+
end;
688+
689+
return findNextPath(currentIterator);
690+
end);

tst/standard/weights.tst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,16 @@ t is the 1st argument,
272272
gap> EdgeWeightedDigraphShortestPath(d, 1, 3);
273273
[ [ 1, 2, 3 ], [ 1, 1 ] ]
274274
275+
# K Shortest Paths
276+
gap> d := EdgeWeightedDigraph([[2], [3], [4], []], [[1], [1], [1], []]);
277+
gap> shortest_path := EdgeWeightedDigraphShortestPath(d, 1, 4);
278+
[ [ 1, 2, 3, 4 ], [ 1, 1, 1 ] ]
279+
gap> iter := DIGRAPHS_ShortestPathsIterator(d, 1, 4);
280+
275281
# DIGRAPHS_UnbindVariables
276282
gap> Unbind(d);
277283
gap> Unbind(tree);
278284
279285
#
280286
gap> DIGRAPHS_StopTest();
281-
gap> STOP_TEST("Digraphs package: standard/weights.tst", 0);
287+
gap> STOP_TEST("Digraphs package: standard/weights.tst", 0);

0 commit comments

Comments
 (0)