Skip to content

Commit d650fea

Browse files
committed
Re-add PR #459: ExecuteDFS (generic depth first search)
1 parent 2ce34d8 commit d650fea

13 files changed

Lines changed: 803 additions & 183 deletions

File tree

Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pkginclude_HEADERS += src/cliques.h
3131
pkginclude_HEADERS += src/perms.h
3232
pkginclude_HEADERS += src/planar.h
3333
pkginclude_HEADERS += src/schreier-sims.h
34+
pkginclude_HEADERS += src/dfs.h
3435

3536
if WITH_INCLUDED_BLISS
3637
pkginclude_HEADERS += extern/bliss-0.73/bignum.hh
@@ -56,6 +57,7 @@ digraphs_la_SOURCES += src/homos-graphs.c
5657
digraphs_la_SOURCES += src/perms.c
5758
digraphs_la_SOURCES += src/planar.c
5859
digraphs_la_SOURCES += src/schreier-sims.c
60+
digraphs_la_SOURCES += src/dfs.c
5961

6062
if WITH_INCLUDED_BLISS
6163
digraphs_la_SOURCES += extern/bliss-0.73/defs.cc

doc/oper.xml

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1321,7 +1321,7 @@ gap> D := CompleteDigraph(5);
13211321
gap> VerticesReachableFrom(D, 1);
13221322
[ 2, 1, 3, 4, 5 ]
13231323
gap> VerticesReachableFrom(D, 3);
1324-
[ 1, 2, 3, 4, 5 ]
1324+
[ 1, 3, 2, 4, 5 ]
13251325
gap> D := EmptyDigraph(5);
13261326
<immutable empty digraph with 5 vertices>
13271327
gap> VerticesReachableFrom(D, 1);
@@ -2126,6 +2126,173 @@ gap> LexicographicProduct(NullDigraph(0), CompleteDigraph(10));
21262126
</ManSection>
21272127
<#/GAPDoc>
21282128

2129+
<#GAPDoc Label="NewDFSRecord">
2130+
<ManSection>
2131+
<Oper Name="NewDFSRecord" Arg="digraph"/>
2132+
<Returns>A record.</Returns>
2133+
<Description>
2134+
This record contains three lists (parent, preorder and postorder) with their length
2135+
equal to the number of verticies in the <A>digraph</A>. Each index of the lists maps to the
2136+
vertex within the <A>digraph</A> equating to the vertex number. These lists store
2137+
the following:
2138+
<List>
2139+
<Mark>parent</Mark>
2140+
<Item>at each index, the parent of the vertex is stored</Item>
2141+
<Mark>preorder</Mark>
2142+
<Item>at each index, the preorder number (order in which the vertex is visited)
2143+
is stored</Item>
2144+
<Mark>postorder</Mark>
2145+
<Item>at each index, the postorder number (order in which the vertex is backtracked on)
2146+
is stored</Item>
2147+
</List>
2148+
2149+
The record also stores a further 4 attributes.
2150+
<List>
2151+
<Mark>current</Mark>
2152+
<Item>the current vertex that is being visited</Item>
2153+
<Mark>child</Mark>
2154+
<Item>the child of the current vertex</Item>
2155+
<Mark>graph</Mark>
2156+
<Item>the <A>digraph</A></Item>
2157+
<Mark>stop</Mark>
2158+
<Item>whether to stop the depth first search</Item>
2159+
</List>
2160+
2161+
Initially, the <C>current</C> and <C>child</C> attributes will have <C>-1</C> values and the lists (<C>parent</C>,
2162+
<C>preorder</C> and <C>postorder</C>) will have <C>-1</C> values at all of their indicies as no vertex has
2163+
been visited. The <C>stop</C> attribute will initially be <C>false</C>.
2164+
<E>This record should be passed into the <C>ExecuteDFS</C> function.</E>
2165+
See <Ref Oper="ExecuteDFS"/>.
2166+
<Example><![CDATA[
2167+
gap> record := NewDFSRecord(CompleteDigraph(2));
2168+
rec( child := -1, current := -1,
2169+
graph := <immutable complete digraph with 2 vertices>,
2170+
parent := [ -1, -1 ], postorder := [ -1, -1 ],
2171+
preorder := [ -1, -1 ], stop := false )
2172+
gap> record.preorder;
2173+
[ -1, -1 ]
2174+
gap> record.postorder;
2175+
[ -1, -1 ]
2176+
gap> record.stop;
2177+
false
2178+
gap> record.parent;
2179+
[ -1, -1 ]
2180+
gap> record.child;
2181+
-1
2182+
gap> record.current;
2183+
-1
2184+
gap> record.graph;
2185+
<immutable complete digraph with 2 vertices>
2186+
]]></Example>
2187+
</Description>
2188+
</ManSection>
2189+
<#/GAPDoc>
2190+
2191+
<#GAPDoc Label="DFSDefault">
2192+
<ManSection>
2193+
<Oper Name="DFSDefault" Arg="record, data"/>
2194+
<Description>
2195+
This is a default function to be passed into the <C>ExecuteDFS</C> function.
2196+
This does nothing and can be used in place of the <C>PreOrderFunc</C>, <C>PostOrderFunc</C>,
2197+
<C>AncestorFunc</C> and/or <C>CrossFunc</C> of the <C>ExecuteDFS</C> function.
2198+
See <Ref Oper="ExecuteDFS"/>.
2199+
<Example><![CDATA[
2200+
gap> PreOrderFunc := function(record, data)
2201+
> data.num_vertices := data.num_vertices + 1;
2202+
> end;;
2203+
gap> record := NewDFSRecord(CompleteDigraph(2));;
2204+
gap> data := rec(num_vertices := 0);;
2205+
gap> ExecuteDFS(record, data, 1, PreOrderFunc,
2206+
> DFSDefault, DFSDefault, DFSDefault);
2207+
gap> data;
2208+
rec( num_vertices := 2 )
2209+
gap> record := NewDFSRecord(CompleteDigraph(2));;
2210+
gap> ExecuteDFS(record, [], 1, DFSDefault,
2211+
> DFSDefault, DFSDefault, DFSDefault);
2212+
gap> record;
2213+
rec( child := 1, current := 1,
2214+
graph := <immutable complete digraph with 2 vertices>,
2215+
parent := [ 1, 1 ], postorder := [ 2, 1 ], preorder := [ 1, 2 ],
2216+
stop := false )
2217+
]]></Example>
2218+
</Description>
2219+
</ManSection>
2220+
<#/GAPDoc>
2221+
2222+
<#GAPDoc Label="ExecuteDFS">
2223+
<ManSection>
2224+
<Oper Name="ExecuteDFS"
2225+
Arg="record, data, start, PreOrderFunc, PostOrderFunc, AncestorFunc, CrossFunc"/>
2226+
<Description>
2227+
This performs a full depth first search from the <A>start</A> vertex (where <A>start</A> is a vertex within the graph).
2228+
The depth first search can be terminated by changing the <A>record</A>.stop attribute to true in the
2229+
<A>PreOrderFunc</A>, <A>PostOrderFunc</A>, <A>AncestorFunc</A> or <A>CrossFunc</A> functions.
2230+
<C>ExecuteDFS</C> takes 7 arguments:
2231+
<List>
2232+
<Mark>record</Mark>
2233+
<Item>the depth first search record (created using NewDFSRecord)</Item>
2234+
<Mark>data</Mark>
2235+
<Item>an object that you want to manipulate in the functions passed.</Item>
2236+
<Mark>start</Mark>
2237+
<Item>the vertex where we begin the depth first search.</Item>
2238+
<Mark>PreOrderFunc</Mark>
2239+
<Item>this function is called when a vertex is first visited. This vertex
2240+
is stored in <A>record</A>.current</Item>
2241+
<Mark>PostOrderFunc</Mark>
2242+
<Item>this function is called when a vertex has no more unvisited children
2243+
causing us to backtrack. This vertex is stored in <A>record</A>.child and its parent is stored
2244+
in <A>record</A>.current</Item>
2245+
<Mark>AncestorFunc</Mark>
2246+
<Item>this function is called when (<C><A>record</A>.current</C>,
2247+
<C><A>record</A>.child</C>) is an edge and <C><A>record</A>.child</C> is an ancestor of <C><A>record</A>.current</C>. An ancestor here means that
2248+
<C><A>record</A>.child</C> is on the same branch as <C><A>record</A>.current</C> but was visited prior to <C><A>record</A>.current</C></Item>
2249+
<Mark>CrossFunc</Mark>
2250+
<Item>this function is called when (<C><A>record</A>.current</C>,
2251+
<C><A>record</A>.child</C>) is an edge and <C><A>record</A>.child</C> has been visited before <C><A>record</A>.current</C>
2252+
and it is not an ancestor of <C><A>record</A>.current</C></Item>
2253+
</List>
2254+
Note that this function only performs a depth first search on the vertices reachable from <A>start</A>.
2255+
It is also important to note that all functions passed need to accept arguments <A>record</A> and <A>data</A>.
2256+
Finally, for the <A>start</A> vertex, its parent is itself and the <A>PreOrderFunc</A>
2257+
will be called on it.
2258+
See <Ref Oper="NewDFSRecord"/>.
2259+
<Example><![CDATA[
2260+
gap> record := NewDFSRecord(CycleDigraph(10));;
2261+
gap> ExecuteDFS(record, [], 1, DFSDefault,
2262+
> DFSDefault, DFSDefault, DFSDefault);
2263+
gap> record.preorder;
2264+
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
2265+
gap> record := NewDFSRecord(CompleteDigraph(10));;
2266+
gap> data := rec(cycle_vertex := 0);;
2267+
gap> AncestorFunc := function(record, data)
2268+
> record.stop := true;
2269+
> data.cycle_vertex := record.child;
2270+
> end;;
2271+
gap> ExecuteDFS(record, data, 1, DFSDefault,
2272+
> DFSDefault, AncestorFunc, DFSDefault);
2273+
gap> record.stop;
2274+
true
2275+
gap> data.cycle_vertex;
2276+
1
2277+
gap> record.preorder;
2278+
[ 1, 2, 3, -1, -1, -1, -1, -1, -1, -1 ]
2279+
gap> record := NewDFSRecord(Digraph([[2, 3], [4], [5], [], [4]]));;
2280+
gap> CrossFunc := function(record, data)
2281+
> record.stop := true;
2282+
> Add(data, record.child);
2283+
> end;;
2284+
gap> data := [];;
2285+
gap> ExecuteDFS(record, data, 1, DFSDefault,
2286+
> DFSDefault, DFSDefault, CrossFunc);
2287+
gap> record.stop;
2288+
true
2289+
gap> data;
2290+
[ 4 ]
2291+
]]></Example>
2292+
</Description>
2293+
</ManSection>
2294+
<#/GAPDoc>
2295+
21292296
<#GAPDoc Label="IsDigraphPath">
21302297
<ManSection>
21312298
<Oper Name="IsDigraphPath" Arg="D, v, a"/>

doc/z-chap4.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
<#Include Label="IsMatching">
1919
<#Include Label="DigraphMaximalMatching">
2020
<#Include Label="DigraphMaximumMatching">
21+
<#Include Label="NewDFSRecord">
22+
<#Include Label="DFSDefault">
23+
<#Include Label="ExecuteDFS">
2124
</Section>
2225

2326
<Section><Heading>Neighbours and degree</Heading>

0 commit comments

Comments
 (0)