Skip to content

Commit

Permalink
Add ShortestPath method
Browse files Browse the repository at this point in the history
  • Loading branch information
Murray Whyte committed Nov 21, 2018
1 parent 5ab6b3d commit 2d7d29a
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 0 deletions.
35 changes: 35 additions & 0 deletions doc/oper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,41 @@ fail
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphShortestPath">
<ManSection>
<Oper Name="DigraphShortestPath" Arg="digraph, u, v"/>
<Returns>A pair of lists, or <K>fail</K>.</Returns>
<Description>
If there exists a non-trivial directed path (or a non-trivial cycle, in the
case that <A>u</A> <C>=</C> <A>v</A>) from vertex <A>u</A> to vertex
<A>v</A> in the digraph <A>digraph</A>, then this operation returns such a
directed path (or directed cycle) of minimum length. Otherwise, this operation returns
<K>fail</K>. See Section <Ref Subsect="Definitions" Style="Text"/> for the
definition of a directed path and a directed cycle.
<P/>

See <Ref Oper="DigraphPath"/> for details on the output.

The method for <C>DigraphShortestPath</C> has worst case complexity of <M>O(m +
n)</M> where <M>m</M> is the number of edges and <M>n</M> the number of
vertices in <A>digraph</A>.

<Example><![CDATA[
gap> gr := Digraph([[1, 2], [3], [2, 4], [1], [2, 4]]);
<digraph with 5 vertices, 8 edges>
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 ] ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="IteratorOfPaths">
<ManSection>
<Oper Name="IteratorOfPaths" Arg="digraph, u, v"/>
Expand Down
1 change: 1 addition & 0 deletions doc/z-chap4.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
1 change: 1 addition & 0 deletions gap/oper.gd
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,4 @@ DeclareOperation("IsMaximalMatching", [IsDigraph, IsHomogeneousList]);

DeclareOperation("AsSemigroup", [IsFunction, IsDigraph]);
DeclareOperation("AsMonoid", [IsFunction, IsDigraph]);
DeclareOperation("DigraphShortestPath", [IsDigraph, IsPosInt, IsPosInt]);
61 changes: 61 additions & 0 deletions gap/oper.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
26 changes: 26 additions & 0 deletions tst/standard/oper.tst
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 2d7d29a

Please sign in to comment.