Skip to content

Commit

Permalink
Add DigraphRandomWalk with doc and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mtorpey committed Apr 20, 2022
1 parent 2bb7f17 commit 69a6d9d
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 0 deletions.
30 changes: 30 additions & 0 deletions doc/oper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,36 @@ gap> DigraphShortestPath(D, 1, 1);
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphRandomWalk">
<ManSection>
<Oper Name="DigraphRandomWalk" Arg="digraph, v, t"/>
<Returns>A pair of lists.</Returns>
<Description>
Returns a directed path corresponding to a <E>random walk</E> in the digraph
<A>digraph</A>, starting at vertex <A>v</A> and having length no more than
<A>t</A>.
<P/>

A random walk is defined as follows. The path begins at <A>v</A>, and at
each step it follows a random edge leaving the current vertex. It continues
through the digraph in this way until it has traversed <A>t</A> edges, or
until it reaches a vertex with no out-edges (a <E>sink</E>) and therefore
cannot continue.
<P/>

The output has the same form as that of <Ref Oper="DigraphPath"/>.
<P/>

<Log><![CDATA[
gap> D := Digraph([[1, 2], [3], [2, 4], [1], [2, 4]]);
<immutable digraph with 5 vertices, 8 edges>
gap> DigraphRandomWalk(D, 1, 4);
[ [ 1, 2, 3, 2, 3 ], [ 2, 1, 1, 1 ] ]
]]></Log>
</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 @@ -68,6 +68,7 @@
<#Include Label="VerticesReachableFrom">
<#Include Label="DigraphPath">
<#Include Label="DigraphShortestPath">
<#Include Label="DigraphRandomWalk">
<#Include Label="Dominators">
<#Include Label="DominatorTree">
<#Include Label="IteratorOfPaths">
Expand Down
1 change: 1 addition & 0 deletions gap/oper.gd
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ DeclareOperation("IteratorOfPaths", [IsList, IsPosInt, IsPosInt]);
DeclareOperation("IteratorOfPathsNC", [IsList, IsPosInt, IsPosInt]);
DeclareOperation("IsReachable", [IsDigraph, IsPosInt, IsPosInt]);
DeclareOperation("DigraphLongestDistanceFromVertex", [IsDigraph, IsPosInt]);
DeclareOperation("DigraphRandomWalk", [IsDigraph, IsPosInt, IsInt]);

DeclareOperation("DigraphLayers", [IsDigraph, IsPosInt]);
DeclareAttribute("DIGRAPHS_Layers", IsDigraph, "mutable");
Expand Down
35 changes: 35 additions & 0 deletions gap/oper.gi
Original file line number Diff line number Diff line change
Expand Up @@ -1727,6 +1727,41 @@ function(D, v)
return dist;
end);

InstallMethod(DigraphRandomWalk,
"for a digraph, a pos int and a non-negative int",
[IsDigraph, IsPosInt, IsInt],
function(D, v, t)
local vertices, edge_indices, i, neighbours, index;

# Check input
if v > DigraphNrVertices(D) then
ErrorNoReturn("the 2nd argument <v> must be ",
"a vertex of the 1st argument <D>,");
elif t < 0 then
ErrorNoReturn("the 3rd argument <t> must be a non-negative int,");
fi;

# Prepare output lists
vertices := [v];
edge_indices := [];

# Iterate to desired length
for i in [1 .. t] do
neighbours := OutNeighboursOfVertex(D, v);
if IsEmpty(neighbours) then
break; # Sink: path ends here
fi;
# Follow a random edge
index := Random(1, Length(neighbours));
v := neighbours[index];
vertices[i + 1] := v;
edge_indices[i] := index;
od;

# Format matches that of DigraphPath
return [vertices, edge_indices];
end);

InstallMethod(DigraphLayers, "for a digraph, and a positive integer",
[IsDigraph, IsPosInt],
function(D, v)
Expand Down
30 changes: 30 additions & 0 deletions tst/standard/oper.tst
Original file line number Diff line number Diff line change
Expand Up @@ -1443,6 +1443,36 @@ infinity
gap> DigraphLongestDistanceFromVertex(gr, 16);
Error, the 2nd argument <v> must be a vertex of the 1st argument <D>,

# DigraphRandomWalk
gap> gr := CompleteDigraph(5);
<immutable complete digraph with 5 vertices>
gap> path := DigraphRandomWalk(gr, 1, 100);;
gap> Length(path[1]);
101
gap> ForAll(path[1], i -> i in [1 .. 5]);
true
gap> Length(path[2]);
100
gap> ForAll(path[2], i -> i in [1 .. 4]);
true
gap> gr := ChainDigraph(5);
<immutable chain digraph with 5 vertices>
gap> DigraphRandomWalk(gr, 2, 100);
[ [ 2, 3, 4, 5 ], [ 1, 1, 1 ] ]
gap> DigraphRandomWalk(gr, 2, 2);
[ [ 2, 3, 4 ], [ 1, 1 ] ]
gap> DigraphRandomWalk(gr, 5, 100);
[ [ 5 ], [ ] ]
gap> gr := CompleteBipartiteDigraph(10, 8);;
gap> DigraphRandomWalk(gr, 3, 0);
[ [ 3 ], [ ] ]
gap> DigraphRandomWalk(gr, 19, 5);
Error, the 2nd argument <v> must be a vertex of the 1st argument <D>,
gap> DigraphRandomWalk(gr, 123, 5);
Error, the 2nd argument <v> must be a vertex of the 1st argument <D>,
gap> DigraphRandomWalk(gr, 3, -1);
Error, the 3rd argument <t> must be a non-negative int,

# DigraphLayers
gap> gr := CompleteDigraph(4);
<immutable complete digraph with 4 vertices>
Expand Down

0 comments on commit 69a6d9d

Please sign in to comment.