diff --git a/doc/oper.xml b/doc/oper.xml index d150670df..a7f5ba7ad 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -1203,6 +1203,41 @@ fail <#/GAPDoc> +<#GAPDoc Label="DigraphShortestPath"> + + + A pair of lists, or fail. + + If there exists a non-trivial directed path (or a non-trivial cycle, in the + case that u = v) from vertex u to vertex + v in the digraph digraph, then this operation returns such a + directed path (or directed cycle) of minimum length. Otherwise, this operation returns + fail. See Section for the + definition of a directed path and a directed cycle. +

+ + See for details on the output. + + The method for DigraphShortestPath has worst case complexity of O(m + + n) where m is the number of edges and n the number of + vertices in digraph. + + gr := Digraph([[1, 2], [3], [2, 4], [1], [2, 4]]); + +gap> DigraphShortestPath(gr, 5, 1); +[ [ 5, 4, 1 ], [ 2, 1 ] ] +gap> DigraphShortestPath(gr, 3, 3); +[ [ 3, 2, 3 ], [ 1, 1 ] ] +gap> DigraphShortestPath(gr, 5, 5); +fail +gap> DigraphShortestPath(gr, 1, 1); +[ [ 1, 1 ], [ 1 ] ] +]]> + + +<#/GAPDoc> + <#GAPDoc Label="IteratorOfPaths"> diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml index fae693463..02b993e49 100644 --- a/doc/z-chap4.xml +++ b/doc/z-chap4.xml @@ -52,6 +52,7 @@ <#Include Label="DigraphFloydWarshall"> <#Include Label="IsReachable"> <#Include Label="DigraphPath"> + <#Include Label="DigraphShortestPath"> <#Include Label="IteratorOfPaths"> <#Include Label="DigraphAllSimpleCircuits"> <#Include Label="DigraphLongestSimpleCircuit"> diff --git a/gap/oper.gd b/gap/oper.gd index 99c093604..4754b0f2f 100644 --- a/gap/oper.gd +++ b/gap/oper.gd @@ -106,3 +106,4 @@ DeclareOperation("IsMaximalMatching", [IsDigraph, IsHomogeneousList]); DeclareOperation("AsSemigroup", [IsFunction, IsDigraph]); DeclareOperation("AsMonoid", [IsFunction, IsDigraph]); +DeclareOperation("DigraphShortestPath", [IsDigraph, IsPosInt, IsPosInt]); diff --git a/gap/oper.gi b/gap/oper.gi index 90858661d..77b699b6a 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -1239,6 +1239,67 @@ function(digraph, u, v) return DIGRAPH_PATH(OutNeighbours(digraph), u, v); end); +# DigraphShortestPath + +InstallMethod(DigraphShortestPath, "for a digraph and two pos ints", +[IsDigraph, IsPosInt, IsPosInt], +function(digraph, u, v) + local current, next, parent, distance, falselist, verts, nbs, n, a, b, i, path; + + verts := DigraphVertices(digraph); + nbs := OutNeighbors(digraph); + distance := []; + + if u = v and v in nbs[v] then # Considers the trivial path from v to v + return [[v, v], [Position(nbs[v], v)]]; + fi; + + # Setting up objects useful in the function. + for i in verts do + Add(distance, -1); + od; + parent := []; + current := [u]; + next := []; + falselist := []; + for i in verts do + Add(next, false); + Add(falselist, false); + od; + + n := 0; # Counts the loops + while current <> [] do + n := n + 1; + for a in current do + for b in nbs[a] do + if distance[b] = -1 then + distance[b] := n; + next[b] := true; + parent[b] := a; + fi; + + if b = v then + path := [[], []]; + # Finds the path + for i in [1 .. n] do + Add(path[1], b); + Add(path[2], Position(nbs[parent[b]], b)); + b := parent[b]; + od; + Add(path[1], u); # Adds the starting vertex to the list of vertices. + return [Reversed(path[1]), Reversed(path[2])]; + fi; + + od; + od; + + current := ListBlist(verts, next); + next := IntersectionBlist(next, falselist); + + od; + return fail; +end); + # IteratorOfPaths: for a digraph and two pos ints InstallMethod(IteratorOfPaths, "for a digraph and two pos ints", diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 8dc76598c..562cf6e9e 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -2039,6 +2039,32 @@ gap> S := AsMonoid(IsTransformation, di);; Error, Digraphs: AsMonoid usage, the first argument must be IsPartialPermMonoid or IsPartialPermSemigroup, +#T# DigraphShortestPath +gap> gr := Digraph([[1], [3, 4], [5, 6], [4, 2, 3], [4, 5], [1]]);; +gap> DigraphShortestPath(gr, 1, 6); +fail +gap> DigraphShortestPath(gr, 2, 5); +[ [ 2, 3, 5 ], [ 1, 1 ] ] +gap> DigraphShortestPath(gr, 3, 3); +[ [ 3, 5, 4, 3 ], [ 1, 1, 3 ] ] +gap> DigraphShortestPath(gr, 6, 6); +fail +gap> DigraphShortestPath(gr, 5, 5); +[ [ 5, 5 ], [ 2 ] ] +gap> gr := Digraph([[]]);; +gap> DigraphShortestPath(gr, 1, 1); +fail +gap> gr := Digraph([[], []]);; +gap> DigraphShortestPath(gr, 2, 1); +fail +gap> gr := Digraph([[2], [1], [3]]);; +gap> DigraphShortestPath(gr, 1, 2); +[ [ 1, 2 ], [ 1 ] ] +gap> gr := CayleyDigraph(SymmetricGroup(7));; +gap> DigraphShortestPath(gr, 12, 5014); +[ [ 12, 912, 1919, 3595, 4915, 3433, 4153, 3242, 2522, 2886, 23, 743, 238, + 1558, 713, 5014 ], [ 2, 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 2 ] ] + #T# DIGRAPHS_UnbindVariables gap> Unbind(a); gap> Unbind(adj);