diff --git a/doc/oper.xml b/doc/oper.xml index 11ffbcebc..2edeee307 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -989,17 +989,6 @@ gap> Display(shortest_distances); <#/GAPDoc> -<#GAPDoc Label="DigraphDijkstraS"> - - - - - - - - -<#/GAPDoc> - <#GAPDoc Label="DigraphEdgeUnion"> <#/GAPDoc> -<#GAPDoc Label="DigraphDijkstraST"> +<#GAPDoc Label="DigraphDijkstra"> - - Two lists. - - If digraph is a digraph and source and target are vertices of digraph, - then DigraphDijkstraST calculates the shortest distance from source and returns two lists. Each element of the first list - is the distance of the corresponding element from source. - If a vertex was not visited in the process of calculating the shortest distance to target or if there is no path connecting that vertex - with source then the corresponding distance is infinity. - Each element of the second list gives the previous vertex in the shortest pahth from source to the corresponding vertex. - For source and for any vertices that remained unvisited this will be -1. - - mat:= [ [0, 1, 1], [0, 0, 1], [0, 0, 0]]; - [ [ 0, 1, 1 ], [ 0, 0, 1 ], [ 0, 0, 0 ] ] - gap> gr:=DigraphByAdjacencyMatrix(mat); - - gap> DigraphDijkstraST(gr,2,3); - [ [ infinity, 0, 1 ], [ -1, -1, 2 ] ] - gap> DigraphDijkstraST(gr,1,3); - [ [ 0, 1, 1 ], [ -1, 1, 1 ] ] - gap> DigraphDijkstraST(gr,1,2); - [ [ 0, 1, 1 ], [ -1, 1, 1 ] ] ]]> - - - <#/GAPDoc> + + + Two lists. + + If digraph is a digraph and source and target are + vertices of digraph, then DigraphDijkstra calculates the + length of the shortest path from source to target and returns + two lists. Each element of the first list is the distance of the + corresponding element from source. If a vertex was not visited in + the process of calculating the shortest distance to target or if + there is no path connecting that vertex with source, then + the corresponding distance is infinity. Each element of the + second list gives the previous vertex in the shortest path + from source to the corresponding vertex. For + source and for any vertices that remained unvisited this + will be -1.

+ + If the optional second argument target is not present, then + DigraphDijkstra returns the shortest path from source to + every vertex that is reachable from source. + + mat := [[0, 1, 1], [0, 0, 1], [0, 0, 0]]; +[ [ 0, 1, 1 ], [ 0, 0, 1 ], [ 0, 0, 0 ] ] +gap> D := DigraphByAdjacencyMatrix(mat); + +gap> DigraphDijkstra(D, 2, 3); +[ [ infinity, 0, 1 ], [ -1, -1, 2 ] ] +gap> DigraphDijkstra(D, 1, 3); +[ [ 0, 1, 1 ], [ -1, 1, 1 ] ] +gap> DigraphDijkstra(D, 1, 2); +[ [ 0, 1, 1 ], [ -1, 1, 1 ] ] +]]> + + +<#/GAPDoc> diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml index 3a4daedec..c8c7327db 100644 --- a/doc/z-chap4.xml +++ b/doc/z-chap4.xml @@ -67,6 +67,7 @@ <#Include Label="DigraphDegeneracyOrdering"> <#Include Label="HamiltonianPath"> <#Include Label="NrSpanningTrees"> + <#Include Label="DigraphDijkstra">

Cayley graphs of groups diff --git a/gap/oper.gd b/gap/oper.gd index 88d90b6b0..a773d4e67 100644 --- a/gap/oper.gd +++ b/gap/oper.gd @@ -94,9 +94,9 @@ DeclareOperation("IsPerfectMatching", [IsDigraph, IsHomogeneousList]); # 9. Connectivity . . . DeclareOperation("DigraphFloydWarshall", [IsDigraph, IsFunction, IsObject, IsObject]); -DeclareOperation("DigraphDijkstraS", +DeclareOperation("DigraphDijkstra", [IsDigraph, IsPosInt]); -DeclareOperation("DigraphDijkstraST", +DeclareOperation("DigraphDijkstra", [IsDigraph, IsPosInt, IsPosInt]); DeclareOperation("DigraphConnectedComponent", [IsDigraph, IsPosInt]); diff --git a/gap/oper.gi b/gap/oper.gi index 20380da6e..87b1d0f72 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -1314,47 +1314,57 @@ function(D, u, v) return fail; end); -InstallMethod(DigraphDijkstraS, "for a digraph, and a vertex", -[IsDigraph, IsPosInt], -{digraph, source} -> DigraphDijkstraST(digraph, source, fail)); - -InstallMethod(DigraphDijkstraST, "for a digraph, a vertex, and a vertex", -[IsDigraph, IsPosInt, IsPosInt], +BindGlobal("DIGRAPHS_DijkstraST", function(digraph, source, target) - local dist, prev, queue, u, v, alt; + local dist, prev, queue, u, v, alt; - dist := []; - prev := []; - queue := BinaryHeap({x, y} -> x[1] < y[1]); + if not source in DigraphVertices(digraph) then + ErrorNoReturn("the 2nd argument must be a vertex of the ", + "1st argument "); + elif target <> fail and not target in DigraphVertices(digraph) then + ErrorNoReturn("the 3rd argument must be a vertex of the ", + "1st argument "); + fi; - for v in DigraphVertices(digraph) do - dist[v] := infinity; - prev[v] := -1; - od; + dist := []; + prev := []; + queue := BinaryHeap({x, y} -> x[1] < y[1]); - dist[source] := 0; - Push(queue, [0, source]); + for v in DigraphVertices(digraph) do + dist[v] := infinity; + prev[v] := -1; + od; - while not IsEmpty(queue) do - u := Pop(queue); - u := u[2]; - # TODO: this has a small performance impact for DigraphDijkstraS, - # but do we care? - if u = target then - return [dist, prev]; - fi; - for v in OutNeighbours(digraph)[u] do - alt := dist[u] + DigraphEdgeLabel(digraph, u, v); - if alt < dist[v] then - dist[v] := alt; - prev[v] := u; - Push(queue, [dist[v], v]); - fi; - od; + dist[source] := 0; + Push(queue, [0, source]); + + while not IsEmpty(queue) do + u := Pop(queue); + u := u[2]; + # TODO: this has a small performance impact for DigraphDijkstraS, + # but do we care? + if u = target then + return [dist, prev]; + fi; + for v in OutNeighbours(digraph)[u] do + alt := dist[u] + DigraphEdgeLabel(digraph, u, v); + if alt < dist[v] then + dist[v] := alt; + prev[v] := u; + Push(queue, [dist[v], v]); + fi; od; - return [dist, prev]; + od; + return [dist, prev]; end); +InstallMethod(DigraphDijkstra, "for a digraph, a vertex, and a vertex", +[IsDigraph, IsPosInt, IsPosInt], DIGRAPHS_DijkstraST); + +InstallMethod(DigraphDijkstra, "for a digraph, and a vertex", +[IsDigraph, IsPosInt], +{digraph, source} -> DIGRAPHS_DijkstraST(digraph, source, fail)); + InstallMethod(IteratorOfPaths, "for a digraph by out-neighbours and two pos ints", [IsDigraphByOutNeighboursRep, IsPosInt, IsPosInt], diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index ce25eb6ce..3fc7f5efb 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -2010,7 +2010,7 @@ gap> OutNeighbours(C); [ [ 5, 6, 7 ], [ 7 ], [ 7 ], [ 7 ], [ 1, 6, 7 ], [ 1, 5, 7 ], [ 3, 2, 1, 6, 5, 4 ] ] -#DigraphDijkstraST +#DigraphDijkstra # When there is one path to target gap> mat := [[0, 1, 1], [0, 0, 1], [0, 0, 0]]; [ [ 0, 1, 1 ], [ 0, 0, 1 ], [ 0, 0, 0 ] ] @@ -2018,11 +2018,11 @@ gap> gr := DigraphByAdjacencyMatrix(mat); gap> DigraphShortestDistance(gr, 2, 3); 1 -gap> DigraphDijkstraST(gr, 2, 3); +gap> DigraphDijkstra(gr, 2, 3); [ [ infinity, 0, 1 ], [ -1, -1, 2 ] ] -gap> DigraphDijkstraST(gr, 1, 3); +gap> DigraphDijkstra(gr, 1, 3); [ [ 0, 1, 1 ], [ -1, 1, 1 ] ] -gap> DigraphDijkstraST(gr, 1, 2); +gap> DigraphDijkstra(gr, 1, 2); [ [ 0, 1, 1 ], [ -1, 1, 1 ] ] gap> DigraphShortestDistance(gr, 1, 3); 1 @@ -2034,21 +2034,21 @@ gap> gr := DigraphByAdjacencyMatrix(mat); gap> DigraphShortestDistance(gr, 2, 3); fail -gap> DigraphDijkstraST(gr, 2, 3); +gap> DigraphDijkstra(gr, 2, 3); [ [ infinity, 0, infinity ], [ -1, -1, -1 ] ] gap> mat := [[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 0, 0], [1, 0, 0, 0]]; [ [ 0, 1, 1, 1 ], [ 0, 0, 1, 1 ], [ 0, 1, 0, 0 ], [ 1, 0, 0, 0 ] ] gap> gr := DigraphByAdjacencyMatrix(mat); -gap> DigraphDijkstraST(gr, 1, 4); +gap> DigraphDijkstra(gr, 1, 4); [ [ 0, 1, 1, 1 ], [ -1, 1, 1, 1 ] ] gap> mat := [[0, 1, 1, 1], [0, 0, 1, 1], [0, 1, 0, 0], [1, 0, 0, 0]]; [ [ 0, 1, 1, 1 ], [ 0, 0, 1, 1 ], [ 0, 1, 0, 0 ], [ 1, 0, 0, 0 ] ] gap> gr := DigraphByAdjacencyMatrix(mat); -gap> DigraphDijkstraST(gr, 1, 2); +gap> DigraphDijkstra(gr, 1, 2); [ [ 0, 1, 1, 1 ], [ -1, 1, 1, 1 ] ] -gap> DigraphDijkstraST(gr, 1, 3); +gap> DigraphDijkstra(gr, 1, 3); [ [ 0, 1, 1, 1 ], [ -1, 1, 1, 1 ] ] #DIGRAPHS_UnbindVariables