From acaea65c5901185c509c791dd5a450970f894dfb Mon Sep 17 00:00:00 2001 From: Markus Pfeiffer Date: Thu, 29 Aug 2024 22:23:35 +0100 Subject: [PATCH] Separate code into testable functions --- gap/weights.gi | 157 ++++++++++++++++++++++++++------------- tst/standard/weights.tst | 1 + 2 files changed, 107 insertions(+), 51 deletions(-) diff --git a/gap/weights.gi b/gap/weights.gi index 988f43043..e5467a363 100644 --- a/gap/weights.gi +++ b/gap/weights.gi @@ -622,69 +622,124 @@ end); ############################################################################# # # returns an iterator that generates the (possibly empty) sequence of paths -# between source and dest +# between source and dest by increasing weight. # # the iterator needs to store # - found paths # - candidates -# - +# - reference to the digraph # rec( found_paths := [], -InstallGlobalFunction(DIGRAPHS_ShortestPathsIterator, -function(digraph, source, dest) - local currentIterator, findNextPath; - - currentIterator := rec( - candidates := BinaryHeap(), - foundPaths := [ - EdgeWeightedDigraphShortestPath(digraph, source, dest) - ]); - - findNextPath := function(iter) - local currentShortestPath, currentShortestPathLength, spurNode, rootPath, - rootPathNode, modifiedGraph, foundPaths, i, p, spurPath, totalPath, - nextPath; - - currentShortestPath := Last(iter.foundPaths); - currentShortestPathLength := Length(currentShortestPath[1]); - foundPaths := iter.foundPaths; - - for i in [1 .. currentShortestPathLength] do - modifiedGraph := fail; - - spurNode := currentShortestPath[1][i]; - rootPath := [ - currentShortestPath[1]{[1..i]}, - currentShortestPath[2]{[1..i-1]} - ]; - - for p in foundPaths do - if rootPath = p[1]{[1..i]} then - # remove p[2][i] from Graph; - fi; - od; - for rootPathNode in rootPath[1] do - if rootPathNode <> spurNode then - # remove rootPathNode from Graph; - fi; - od; +DIGRAPHS_SPI := function(digraph, source, dest) + local iter; - spurPath := EdgeWeightedDigraphShortestPath(modifiedGraph, spurNode, dest); - totalPath := [ Concatenation(rootPath[1], spurPath[1]), - Concatenation(rootPath[2], spurPath[2]) ]; + iter := rec( + NextIterator := function(iter) + local shortestPath; - Push(iter.candidatePaths, totalPath); + if IsEmpty(iter!.foundPaths) then + shortestPath := EdgeWeightedDigraphShortestPath(iter!.digraph, iter!.source, iter!.dest); + Add(iter!.foundPaths, shortestPath); + else + + fi; + end, + IsDoneIterator := function(iter) + return IsEmpty(iter!.candidatePaths); + end, + ShallowCopy := function(iter) + # TODO + return iter; + end, + PrintObj := function(iter) + Print(""); + end, + + foundPaths := [], + candidatePaths := BinaryHeap(), + digraph := digraph, + source := source, + dest := dest + ); + return IteratorByFunctions(iter); +end; + +# FIXME: find out how often paths are used as objects in +# their own right. +DIGRAPHS_ConcatenatePaths := function(a, b) + local a_length; + + a_length := Length(a); + + if a[1][a_length] <> b[1][1] then + ErrorNoReturn("concatenatePaths: last vertex on `a` is not equal to first vertex of `b`"); + fi; + + if a_length = 0 then + return StructuralCopy(b); + else + return [ Concatenation(a[1]{[1..a_length-1]}, b[1]), + Concatenation(b[2], b[2]) ]; + fi; +end; + +DIGRAPHS_ModifyGraph := function(digraph, root, foundPaths) + mutableWeights := EdgeWeightsMutableCopy(digraph); + for p in foundPaths do + if rootPath = p[1]{[1..i]} then + mutableWeights[p[2][i]] := infinity; + fi; od; - if IsEmpty(iter.candidatePaths) then - return fail; + rootNodes := currentShortestPath[1]{[1..i-1]}; + + o := OutNeighbours(digraph); + for i in [1..Length(o)] do + for j in [1..Length(o[i])] do + if o[i][j] in rootNodes then + mutableWeights[i][j] := infinity; + fi; + od; + od; + return EdgeWeightedDigraph(digraph, mutableWeights); +end; + +DIGRAPHS_NextShortestPath := function(iter) + local currentShortestPath, currentShortestPathLength, spurNode, rootPath, + rootPathNode, modifiedGraph, foundPaths, i, p, spurPath, totalPath, + nextPath, mutableWeights, mutableOuts, rootNodes, j, o; + + currentShortestPath := Last(iter.foundPaths); + currentShortestPathLength := Length(currentShortestPath[1]); + foundPaths := iter.foundPaths; + + for i in [1 .. currentShortestPathLength] do + spurNode := currentShortestPath[1][i]; + rootPath := [ + currentShortestPath[1]{[1..i]}, + currentShortestPath[2]{[1..i-1]} + ]; + + modifiedGraph := DIGRAPHS_ModifyGraph(digraph, rootPath, iter.foundPaths); + spurPath := EdgeWeightedDigraphShortestPath(modifiedGraph, spurNode, dest); + + if spurPath <> fail then + totalPath := DIGRAPHS_ConcatenatePaths(rootPath, spurPath); + Push(iter.candidatePaths, totalPath); fi; + od; + + if IsEmpty(iter.candidatePaths) then + return fail; + fi; - nextPath := Pop(iter.candidatePaths); - Push(iter.foundPaths, nextPath); + nextPath := Pop(iter.candidatePaths); + Add(iter.foundPaths, nextPath); - return nextPath; - end; + return nextPath; +end; - return findNextPath(currentIterator); +InstallGlobalFunction(DIGRAPHS_ShortestPathsIterator, +function(digraph, source, dest) + ErrorNoReturn("Not implemented yet"); end); diff --git a/tst/standard/weights.tst b/tst/standard/weights.tst index 3fd851d34..31cfb8c30 100644 --- a/tst/standard/weights.tst +++ b/tst/standard/weights.tst @@ -274,6 +274,7 @@ gap> EdgeWeightedDigraphShortestPath(d, 1, 3); # K Shortest Paths gap> d := EdgeWeightedDigraph([[2], [3], [4], []], [[1], [1], [1], []]); + gap> shortest_path := EdgeWeightedDigraphShortestPath(d, 1, 4); [ [ 1, 2, 3, 4 ], [ 1, 1, 1 ] ] gap> iter := DIGRAPHS_ShortestPathsIterator(d, 1, 4);