Skip to content

Commit

Permalink
oper: minor fix to Dijkstra
Browse files Browse the repository at this point in the history
  • Loading branch information
james-d-mitchell committed Mar 18, 2020
1 parent c3fae09 commit 063023f
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 80 deletions.
74 changes: 37 additions & 37 deletions doc/oper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -989,17 +989,6 @@ gap> Display(shortest_distances);
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphDijkstraS">
<ManSection>
<Oper Name="DigraphDijkstraS" Arg="digraph, source"/>
<Oper Name="DigraphDijkstraST" Arg="digraph, source, target"/>
<Returns></Returns>
<Description>

</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphEdgeUnion">
<ManSection>
<Func Name="DigraphEdgeUnion" Arg="D1, D2, ..."
Expand Down Expand Up @@ -1711,30 +1700,41 @@ true
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphDijkstraST">
<#GAPDoc Label="DigraphDijkstra">
<ManSection>
<Oper Name="DigraphDijkstraST" Arg="digraph, source, target"/>
<Returns>Two lists.</Returns>
<Description>
If <A>digraph</A> is a digraph and <A>source</A> and <A>target</A> are vertices of <A>digraph</A>,
then <C>DigraphDijkstraST</C> calculates the shortest distance from <A>source</A> and returns two lists. Each element of the first list
is the distance of the corresponding element from <A>source</A>.
If a vertex was not visited in the process of calculating the shortest distance to <A>target</A> or if there is no path connecting that vertex
with <A>source</A> then the corresponding distance is infinity.
Each element of the second list gives the previous vertex in the shortest pahth from <A>source</A> to the corresponding vertex.
For <A>source</A> and for any vertices that remained unvisited this will be -1.

<Example><![CDATA[
gap> mat:= [ [0, 1, 1], [0, 0, 1], [0, 0, 0]];
[ [ 0, 1, 1 ], [ 0, 0, 1 ], [ 0, 0, 0 ] ]
gap> gr:=DigraphByAdjacencyMatrix(mat);
<immutable digraph with 3 vertices, 3 edges>
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 ] ] ]]></Example>
</Description>
</ManSection>
<#/GAPDoc>
<Oper Name="DigraphDijkstra" Arg="digraph, source, target"/>
<Oper Name="DigraphDijkstra" Arg="digraph, source"/>
<Returns>Two lists.</Returns>
<Description>
If <A>digraph</A> is a digraph and <A>source</A> and <A>target</A> are
vertices of <A>digraph</A>, then <C>DigraphDijkstra</C> calculates the
length of the shortest path from <A>source</A> to <A>target</A> and returns
two lists. Each element of the first list is the distance of the
corresponding element from <A>source</A>. If a vertex was not visited in
the process of calculating the shortest distance to <A>target</A> or if
there is no path connecting that vertex with <A>source</A>, then
the corresponding distance is <K>infinity</K>. Each element of the
second list gives the previous vertex in the shortest path
from <A>source</A> to the corresponding vertex. For
<A>source</A> and for any vertices that remained unvisited this
will be <C>-1</C>.<P/>

If the optional second argument <A>target</A> is not present, then
<C>DigraphDijkstra</C> returns the shortest path from <A>source</A> to
every vertex that is reachable from <A>source</A>.

<Example><![CDATA[
gap> mat := [[0, 1, 1], [0, 0, 1], [0, 0, 0]];
[ [ 0, 1, 1 ], [ 0, 0, 1 ], [ 0, 0, 0 ] ]
gap> D := DigraphByAdjacencyMatrix(mat);
<immutable digraph with 3 vertices, 3 edges>
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 ] ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>
1 change: 1 addition & 0 deletions doc/z-chap4.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
<#Include Label="DigraphDegeneracyOrdering">
<#Include Label="HamiltonianPath">
<#Include Label="NrSpanningTrees">
<#Include Label="DigraphDijkstra">
</Section>

<Section><Heading>Cayley graphs of groups</Heading>
Expand Down
4 changes: 2 additions & 2 deletions gap/oper.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
76 changes: 43 additions & 33 deletions gap/oper.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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 <source> must be a vertex of the ",
"1st argument <digraph>");
elif target <> fail and not target in DigraphVertices(digraph) then
ErrorNoReturn("the 3rd argument <target> must be a vertex of the ",
"1st argument <digraph>");
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],
Expand Down
16 changes: 8 additions & 8 deletions tst/standard/oper.tst
Original file line number Diff line number Diff line change
Expand Up @@ -2010,19 +2010,19 @@ 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 ] ]
gap> gr := DigraphByAdjacencyMatrix(mat);
<immutable digraph with 3 vertices, 3 edges>
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
Expand All @@ -2034,21 +2034,21 @@ gap> gr := DigraphByAdjacencyMatrix(mat);
<immutable digraph with 3 vertices, 2 edges>
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);
<immutable digraph with 4 vertices, 7 edges>
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);
<immutable digraph with 4 vertices, 7 edges>
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
Expand Down

0 comments on commit 063023f

Please sign in to comment.