Skip to content

Commit c031507

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

File tree

13 files changed

+801
-175
lines changed

13 files changed

+801
-175
lines changed

Makefile.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ KEXT_SOURCES += src/perms.c
2626
KEXT_SOURCES += src/planar.c
2727
KEXT_SOURCES += src/schreier-sims.c
2828
KEXT_SOURCES += src/safemalloc.c
29+
KEXT_SOURCES += src/dfs.c
2930

3031
ifdef WITH_INCLUDED_BLISS
3132
KEXT_SOURCES += extern/bliss-0.73/defs.cc

doc/oper.xml

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1440,7 +1440,7 @@ gap> D := CompleteDigraph(5);
14401440
gap> VerticesReachableFrom(D, 1);
14411441
[ 1, 2, 3, 4, 5 ]
14421442
gap> VerticesReachableFrom(D, 3);
1443-
[ 1, 2, 3, 4, 5 ]
1443+
[ 1, 3, 2, 4, 5 ]
14441444
gap> D := EmptyDigraph(5);
14451445
<immutable empty digraph with 5 vertices>
14461446
gap> VerticesReachableFrom(D, 1);
@@ -2329,6 +2329,173 @@ gap> LexicographicProduct(NullDigraph(0), CompleteDigraph(10));
23292329
</ManSection>
23302330
<#/GAPDoc>
23312331

2332+
<#GAPDoc Label="NewDFSRecord">
2333+
<ManSection>
2334+
<Oper Name="NewDFSRecord" Arg="digraph"/>
2335+
<Returns>A record.</Returns>
2336+
<Description>
2337+
This record contains three lists (parent, preorder and postorder) with their length
2338+
equal to the number of verticies in the <A>digraph</A>. Each index of the lists maps to the
2339+
vertex within the <A>digraph</A> equating to the vertex number. These lists store
2340+
the following:
2341+
<List>
2342+
<Mark>parent</Mark>
2343+
<Item>at each index, the parent of the vertex is stored</Item>
2344+
<Mark>preorder</Mark>
2345+
<Item>at each index, the preorder number (order in which the vertex is visited)
2346+
is stored</Item>
2347+
<Mark>postorder</Mark>
2348+
<Item>at each index, the postorder number (order in which the vertex is backtracked on)
2349+
is stored</Item>
2350+
</List>
2351+
2352+
The record also stores a further 4 attributes.
2353+
<List>
2354+
<Mark>current</Mark>
2355+
<Item>the current vertex that is being visited</Item>
2356+
<Mark>child</Mark>
2357+
<Item>the child of the current vertex</Item>
2358+
<Mark>graph</Mark>
2359+
<Item>the <A>digraph</A></Item>
2360+
<Mark>stop</Mark>
2361+
<Item>whether to stop the depth first search</Item>
2362+
</List>
2363+
2364+
Initially, the <C>current</C> and <C>child</C> attributes will have <C>-1</C> values and the lists (<C>parent</C>,
2365+
<C>preorder</C> and <C>postorder</C>) will have <C>-1</C> values at all of their indicies as no vertex has
2366+
been visited. The <C>stop</C> attribute will initially be <C>false</C>.
2367+
<E>This record should be passed into the <C>ExecuteDFS</C> function.</E>
2368+
See <Ref Oper="ExecuteDFS"/>.
2369+
<Example><![CDATA[
2370+
gap> record := NewDFSRecord(CompleteDigraph(2));
2371+
rec( child := -1, current := -1,
2372+
graph := <immutable complete digraph with 2 vertices>,
2373+
parent := [ -1, -1 ], postorder := [ -1, -1 ],
2374+
preorder := [ -1, -1 ], stop := false )
2375+
gap> record.preorder;
2376+
[ -1, -1 ]
2377+
gap> record.postorder;
2378+
[ -1, -1 ]
2379+
gap> record.stop;
2380+
false
2381+
gap> record.parent;
2382+
[ -1, -1 ]
2383+
gap> record.child;
2384+
-1
2385+
gap> record.current;
2386+
-1
2387+
gap> record.graph;
2388+
<immutable complete digraph with 2 vertices>
2389+
]]></Example>
2390+
</Description>
2391+
</ManSection>
2392+
<#/GAPDoc>
2393+
2394+
<#GAPDoc Label="DFSDefault">
2395+
<ManSection>
2396+
<Oper Name="DFSDefault" Arg="record, data"/>
2397+
<Description>
2398+
This is a default function to be passed into the <C>ExecuteDFS</C> function.
2399+
This does nothing and can be used in place of the <C>PreOrderFunc</C>, <C>PostOrderFunc</C>,
2400+
<C>AncestorFunc</C> and/or <C>CrossFunc</C> of the <C>ExecuteDFS</C> function.
2401+
See <Ref Oper="ExecuteDFS"/>.
2402+
<Example><![CDATA[
2403+
gap> PreOrderFunc := function(record, data)
2404+
> data.num_vertices := data.num_vertices + 1;
2405+
> end;;
2406+
gap> record := NewDFSRecord(CompleteDigraph(2));;
2407+
gap> data := rec(num_vertices := 0);;
2408+
gap> ExecuteDFS(record, data, 1, PreOrderFunc,
2409+
> DFSDefault, DFSDefault, DFSDefault);
2410+
gap> data;
2411+
rec( num_vertices := 2 )
2412+
gap> record := NewDFSRecord(CompleteDigraph(2));;
2413+
gap> ExecuteDFS(record, [], 1, DFSDefault,
2414+
> DFSDefault, DFSDefault, DFSDefault);
2415+
gap> record;
2416+
rec( child := 1, current := 1,
2417+
graph := <immutable complete digraph with 2 vertices>,
2418+
parent := [ 1, 1 ], postorder := [ 2, 1 ], preorder := [ 1, 2 ],
2419+
stop := false )
2420+
]]></Example>
2421+
</Description>
2422+
</ManSection>
2423+
<#/GAPDoc>
2424+
2425+
<#GAPDoc Label="ExecuteDFS">
2426+
<ManSection>
2427+
<Oper Name="ExecuteDFS"
2428+
Arg="record, data, start, PreOrderFunc, PostOrderFunc, AncestorFunc, CrossFunc"/>
2429+
<Description>
2430+
This performs a full depth first search from the <A>start</A> vertex (where <A>start</A> is a vertex within the graph).
2431+
The depth first search can be terminated by changing the <A>record</A>.stop attribute to true in the
2432+
<A>PreOrderFunc</A>, <A>PostOrderFunc</A>, <A>AncestorFunc</A> or <A>CrossFunc</A> functions.
2433+
<C>ExecuteDFS</C> takes 7 arguments:
2434+
<List>
2435+
<Mark>record</Mark>
2436+
<Item>the depth first search record (created using NewDFSRecord)</Item>
2437+
<Mark>data</Mark>
2438+
<Item>an object that you want to manipulate in the functions passed.</Item>
2439+
<Mark>start</Mark>
2440+
<Item>the vertex where we begin the depth first search.</Item>
2441+
<Mark>PreOrderFunc</Mark>
2442+
<Item>this function is called when a vertex is first visited. This vertex
2443+
is stored in <A>record</A>.current</Item>
2444+
<Mark>PostOrderFunc</Mark>
2445+
<Item>this function is called when a vertex has no more unvisited children
2446+
causing us to backtrack. This vertex is stored in <A>record</A>.child and its parent is stored
2447+
in <A>record</A>.current</Item>
2448+
<Mark>AncestorFunc</Mark>
2449+
<Item>this function is called when (<C><A>record</A>.current</C>,
2450+
<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
2451+
<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>
2452+
<Mark>CrossFunc</Mark>
2453+
<Item>this function is called when (<C><A>record</A>.current</C>,
2454+
<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>
2455+
and it is not an ancestor of <C><A>record</A>.current</C></Item>
2456+
</List>
2457+
Note that this function only performs a depth first search on the vertices reachable from <A>start</A>.
2458+
It is also important to note that all functions passed need to accept arguments <A>record</A> and <A>data</A>.
2459+
Finally, for the <A>start</A> vertex, its parent is itself and the <A>PreOrderFunc</A>
2460+
will be called on it.
2461+
See <Ref Oper="NewDFSRecord"/>.
2462+
<Example><![CDATA[
2463+
gap> record := NewDFSRecord(CycleDigraph(10));;
2464+
gap> ExecuteDFS(record, [], 1, DFSDefault,
2465+
> DFSDefault, DFSDefault, DFSDefault);
2466+
gap> record.preorder;
2467+
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
2468+
gap> record := NewDFSRecord(CompleteDigraph(10));;
2469+
gap> data := rec(cycle_vertex := 0);;
2470+
gap> AncestorFunc := function(record, data)
2471+
> record.stop := true;
2472+
> data.cycle_vertex := record.child;
2473+
> end;;
2474+
gap> ExecuteDFS(record, data, 1, DFSDefault,
2475+
> DFSDefault, AncestorFunc, DFSDefault);
2476+
gap> record.stop;
2477+
true
2478+
gap> data.cycle_vertex;
2479+
1
2480+
gap> record.preorder;
2481+
[ 1, 2, 3, -1, -1, -1, -1, -1, -1, -1 ]
2482+
gap> record := NewDFSRecord(Digraph([[2, 3], [4], [5], [], [4]]));;
2483+
gap> CrossFunc := function(record, data)
2484+
> record.stop := true;
2485+
> Add(data, record.child);
2486+
> end;;
2487+
gap> data := [];;
2488+
gap> ExecuteDFS(record, data, 1, DFSDefault,
2489+
> DFSDefault, DFSDefault, CrossFunc);
2490+
gap> record.stop;
2491+
true
2492+
gap> data;
2493+
[ 4 ]
2494+
]]></Example>
2495+
</Description>
2496+
</ManSection>
2497+
<#/GAPDoc>
2498+
23322499
<#GAPDoc Label="IsDigraphPath">
23332500
<ManSection>
23342501
<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
@@ -20,6 +20,9 @@
2020
<#Include Label="IsMatching">
2121
<#Include Label="DigraphMaximalMatching">
2222
<#Include Label="DigraphMaximumMatching">
23+
<#Include Label="NewDFSRecord">
24+
<#Include Label="DFSDefault">
25+
<#Include Label="ExecuteDFS">
2326
</Section>
2427

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

0 commit comments

Comments
 (0)