Content uploaded by Ken Hawick
Author content
All content in this area was uploaded by Ken Hawick on Aug 19, 2014
Content may be subject to copyright.
Enumerating Circuits and Loops in Graphs with Self-Arcs and
Multiple-Arcs
K.A. Hawick and H.A. James∗
Computer Science, Institute for Information and Mathematical Sciences,
Massey University, North Shore 102-904, Auckland, New Zealand
k.a.hawick@massey.ac.nz; heath.james@sapac.edu.au
Tel: +64 9 414 0800 Fax: +64 9 441 8181
Abstract
The problems of detecting and enumerating circuits in
graphs and networks are still of fundamental importance.
We extend the circuit enumeration algorithm of Johnson
for graphs with directed-arcs, multiple-arcs and self-arcs
and present a memory efficient and high-performance im-
plementation in the D programming language. We also
discuss other circuit applications including how the code
could be adapted as a cycle detection algorithm.
Keywords: graph; circuit; enumeration; algorithm.
1 Introduction
Recent applications involving complex network analysis
[1–3] and studies of workflow task graphs have rekindled
interest in the fundamental problems of detecting, counting
and enumerating circuits in graphs.
A circuit or loop as we discuss here is defined as a path in
which the first and last vertices are identical. A path is said
to be elementary if no vertex but the first and last appears
twice. We are only interested in unique circuits which are
said to be distinct if they are not merely cyclic permuta-
tions of one another. In a growing number of application
we are e not merely interested in counting the circuits but
also need to enumerate them to evaluate other properties
such as their length distribution.
Various algorithms have been formulated to count the cir-
cuits in a graph but these either use infeasible amounts of
memory or are time exponential [4, 5] with a time bound
of O(N.e(c+ 1)), where Nis the number of nodes, ethe
number of edges and cthe number of circuits.
∗Present Address: South Australian Partnership for Advanced Com-
puting (SAPAC), Adelaide, South Australia
In practical applications involving complex networks or
work-flow task graphs, the graph or network may in fact
dynamically change and can fragment into a number of
disconnected clusters. Clusters may also merge and so the
number of clusters NCcan also vary. A useful algorithm
needs to be used in tandem with a suitable data structure
and a cluster component tracking algorithm. Many appli-
cations graphs are either generated by simulation processes
or arise e with both multiple arcs and self arcs. A circuit
analysis algorithm and implementation needs to be able to
retain these independent arcs and interpret them appropri-
ately.
We develop a variation of Johnson’s algorithm [6] imple-
mented in the D programming language [7] and which
caters for directed graphs and which does not need to treat
each of the possible Nc>1components separately.
By treating each arc as a track-able entity, regardless of
whether it is a self-arc, a multiple-arc or an ordinary arc,
we have had to make modifications to the assumptions un-
derpinning Johnson’s algorithm.
For graphs of Nvertices, eedges, ccircuits and
1fully connected component, Johnson’s algorithm is
time bounded in time by O((N+e)(c+ 1)) and space
bounded by O(N+e). This is still a highly expensive pro-
cess since the number of circuits citself grows very rapidly
with (N, e).
In this article we describe the algorithm in section 2 and
our implementation in section 3. We present some results
and some worked examples in section 4. We report on
some performance timing values and suggest some areas
for future applications in section 5.
Figure 1: Test graph of 5 nodes and 6 arcs in a single com-
ponent with 2 circuits (1-2-4-1 and 1-2-3-4-1)
2 Data Structures and Algorithm
Johnson’s original algorithm was given in a Pascal-like
pseudo code and used a 1..N integer labeling scheme. That
work used an adjacency matrix structure that was incapable
to supporting self-arcs and multiple arcs. We employ a set
of arcs lists, where each to-arc is specified precisely by its
source and destination node indices.
Figure 1 shows a small test graph of 5 nodes and 6 arcs,
connected so as to yield just two circuits (1-2-4-1 and
1-2-3-4-1). Our storage structure for the adjacency list
Ak[i][j], where the i’th vertex has m=Ak[i][0] arcs
originating from it, with their destination vertices stored
in Ak[i][1..m]. The D list structures can be manipulated
as dynamical arrays and there size adjusted even for ap-
plications that may have multiple- and self-arcs and hence
m≥N.
The algorithm proceeds as Johnson’s from a starting ver-
tex from which it is assumed nodes that are involved in
some circuit are at least connected. The algorithm main-
tains a stack of nodes from which it has tried a recursive
tree search for circuits. The procedure circuit is called
recursively to search a circuit and the procedure unblock
which manages the elementary paths to avoid duplicating
circuits. The algorithm therefore exactly enumerates the
elementary circuits of the graph according to the order of
the vertices.
The termination conditions for the recursive calls to the
circuit function are therefor e important. Johnson’s algo-
rithm was expressed for a fully connected and fully reach-
able graph - effectively all arcs were two-way edges and
it choosing which vertex to start from would not affect the
total number of circuits found.
In our graphs, which can be fragmented but also can con-
tain islands of unreachability even in a single component
graph, the starting vertex does matter. Our algorithm ob-
tains all elementary circuits involving nodes that are reach-
able from the starting 0’th vertex. An elementary circuit
having eh usual definition of a circuit that contains no du-
plicate arcs. We can successfully count circuits that would
fail in Johnson’s algorithm due to multiple-arc effects. Self
arcs are less trouble since e they will give only give rise to
unit length elementary circuits.
3 Implementation Issues
In this section we list and comment on some D code frag-
ments that implement our algorithm. We include e some
auxiliary data structures and cod e for tracking: the ver-
tex popularity – which is a frequency count of how many
circuits a vertex appears in; the length and composition of
the longest circuit found so far; and a frequency count of
circuit lengths found.
The D code fragment 2 lists the global variables used in the
algorithmic code fragments which follow:
i n t n V e r t i c e s = 0 ; / / n umb er o f v e r t i c e s
i n t s t a r t = 0 ; / / s t a r t i n g v e r t e x i n d e x
i n t [ ] [ ] Ak ;
/ / i n t e g e r a r r ay s i z e n o f l i s t s
/ /
i e t h e a r c s f r om t h e v e r t e x
i n t [ ] [ ] B ;
/ / i n t e g e r a r r ay s i z e n o f l i s t s
b o o l [ ] b l o c k e d ;
/ / l o g i c a l a r r a y i n d e x e d b y v e r t e x
u lo n g n C i r c u i t s = 0 ;
/ / t o t a l nu mb er o f c i r c u i t s f o un d ;
u lo n g [ ] l e n g t h H i s t o g r a m ; / / h i st o g r a m o f c i r c u i t l e n g t h s
u lo n g [ ] [ ] v e r t e x P o p u l a r i t y ;
/ / a d j a c e n cy t a b l e o f o c c u r r e n c e s o f
/ / v e r t i c e s i n c i r c u i t s o f e ac h l e ng t h
i n t [] longestCircuit ;
/ / t h e ( f i r s t ) l o n g e s t c i r c u i t f ou n d
i n t l e n L o n g e s t = 0 ; / / i t s l e n g t h
b o o l e n u m e r a t i o n = false ;/ / e x p l i c i t l y e n u m e r a t e c i r c u i t s
Figure 2: Global Variables
The short code fragment 3 shows the use of leading row
elements in Ak to specify vertex out lists:
The unblock routine 4 shows how vertices are recur-
sively blocked and unblocked from elementary paths to
avoid double counting.
The circuit routine 5 is recursively called to chase
down a circuit We employ some control flags to determine
whether we wish to merely count circuits or to enumer-
i n t countAkArcs ( ){/ / r e t u r n nu mb er o f A r c s i n g ra ph
i n t n A r cs = 0 ;
for (i n t i = 0 ; i <n V e r t i c e s ; i + +){
nA rc s += Ak [ i ] [ 0 ] ; / / z e r o ’ t h e l e m e n t g i v e s n A r c s f o r i
}
r e t u r n nArcs ;
}
Figure 3: Counting Arcs
v o i d u n b l o c k ( i n t u ) {
b l o c k e d [ u ] = false ;
for (i n t wP os = 1 ; w Pos <= B [ u ] [ 0 ] ; w Pos ++) {
/ / f o r e ac h w i n B [ u ]
i n t w = B[ u ] [ w Pos ] ;
wPo s −= r e m o v eF r o m L is t ( B [ u ] , w ) ;
i f ( b l o c k e d [ w ] )
u n b l o c k (w ) ;
}
}
Figure 4: recursive unblock
ate them and print them out. We also track the longest
circuit found and the length frequencies and number of oc-
currences of particular vertices in circuits.
The code shown in figure 6 is used to initialise the global
variables:
We make use of some fairly simple stack and list proce-
dures. The main issue for performance concerns lists and
iteration over lists that change length mid iteration. We list
these for completeness, since they have some performance
optimisations.
The key routines for managing our stack - based on a D
dynamic array are shown in figure 7. This explicit inte-
ger array code was found considerably faster than using a
template library class for a generalised stack.
Similar code is used to manage a list of integers as shown
in figure 8.
There are various choices concerning bit precisions of var-
ious quantities. they can be int,uint or ulong. Gen-
erally in our applications there may be more circuits than
a 32-bit uint can hold, but anything held in an array will
typically only need an int. The code will typically hit
factorial time limitations before it runs out of word/address
space.
4 Examples Graphs with Circuits
Figure 9 shows a network with N= 16, K = 2. This
graph has been generated from complex networks study
using Kauffman NK networks [1]. The construction algo-
i n t [ ] s t a c k = n u l l ; / / s t a c k o f i n t e g e r s
static int stackTop = 0;
/ / t h e n um b er o f e l e m e n t s on t h e s t a c k
/ /
a l s o t h e i n d e x ” t o p u t t h e n e x t o ne ”
/ / i n i t i a l i s e th e s t ac k t o so me s i z e max
v o i d s t a c k I n i t ( i n t max ){
s t a c k . l e n g t h = ma x ;
a s s e r t ( s t a c k ! = n u l l ) ;
stackTop = 0;
}
/ / p u s h an i n t o n t o t h e s t a ck , e x t e n d i n g i f n e c e s s a r y
v o i d stackPush ( i n t v a l ) {
i f ( stackTop >= s t a c k . l e n g t h )
s t a c k . l e n g t h = s t a c k . l e n g t h + 1 ;
s t a c k [ s t a c k T o p + +] = v a l ;
}
i n t stackSize (){
r e t u r n stackTop ;
}
i n t stackPop (){/ / p op an i n t o f f t h e s t a ck
a s s e r t ( s t a c k T o p >0 ) ;
r e t u r n s t a c k [−−stackTop ];
}
v o i d stackClear (){/ / c l e a r t h e s t a c k
stackTop = 0;
}
Figure 7: Stack management code
rithm has allowed self-arcs – in other words the inputs for
each node have been chosen according to a flat uniform
distribution so they can connect to themselves.
The 22 circuits in the graph of figure 9 are shown in fig-
ure 10. There are repeated circuits due to the multiple arcs
connecting nodes 12 and 11. Johnson’s original algorithm
would therefore give an incorrectly low number of elemen-
tary circuits for this graph.
Note that in figure 10 the circuits are found (and enumer-
ated) in a vertex order. Starting with vertex 0, the vertices
are searched in a stack/unblock order giving rise to the ex-
act list shown.
Len Nodes Arcs Circuits Max Time
L Length (secs)
2 4 16 48 4 <0.1
3 9 36 642 9 <0.1
4 16 64 29,440 16 ≈0.1
5 25 100 4,367,030 25 5.5
6 36 144 1,991,637,504 36 3,271
Table 1: Nearest-Neighbour Periodic Square L×LMeshes
– Graph and Circuit Properties
A number of test graphs can be investigated. A interesting
base case, from which modifications such as small-world
b o o l c i r c u i t ( i n t v ) {/ / b a s e d on J o h n so n ’ s l o g i c a l p r o c e d u r e CI RCU IT
b o o l f = false ;
stackPush (v );
b l o c k e d [ v ] = t ru e ;
for (i n t wP os = 1 ; w Pos <= Ak [ v ] [ 0 ] ; wPo s+ +){/ / f o r e ac h w i n l i s t A k [ v ] :
i n t w = Ak [ v ] [ w Pos ] ;
i f ( w <start ) continue ;/ / i g n or e r e l e v a n t p a r t s o f Ak
i f ( w == s t a r t ) {/ / we h av e a c i r c u i t ,
i f ( e n u m e r a t i o n ) {
stackPrint3d (); / / p r i n t o u t t h e s t a c k t o r e c or d t h e c i r c u i t
f w r i t e f ( s td o u t , ”\%3d\n ” , s t a r t ) ; / / a nd ” s t a r t ” w h ic h c o m p l e t e s t h e p r i n t o u t o f t h e c i r c u i t
}
a s s e r t ( s t a c k T o p <= n V e r t i c e s ) ;
++ l e n g t h H i s t o g r a m [ s t a c k T op ]; / / a dd t h i s c i r c u i t ’ s l e n g t h t o t h e l e n g t h h i s t o gr a m
n C i r c u i t s + + ; / / a nd i n c r e m e n t c o u n t o f c i r c u i t s f ou n d
i f ( stackTop >l e n L o n g e s t ) {/ / k e ep a c o py o f t h e l o n g e s t c i r c u i t f o u nd
l e n L o n g e s t = s t a c k T o p ;
l o n g e s t C i r c u i t = s t a c k . d up ;
}
for (i n t i = 0 ; i <stackTop ; i ++) / / i n c r e m e n t [ c i r c u i t −l e n g th ] [ v e r t e x ] f o r a l l v e r t i c e s i n t h i s c i r c u i t
++ v e r t e x P o p u l a r i t y [ s t ac k T op ] [ s t a c k [ i ] ] ;
f = t r u e ;
}e l s e i f ( ! b l o c k e d [w ] ) {
i f ( c i r c u i t (w ) ) f = t r u e ;
}
}
i f ( f ) {
u n b l o c k ( v ) ;
}else{
for (i n t wP os = 1 ; w Po s <= Ak [v ] [ 0 ] ; w Pos ++) {/ / f o r e a ch w i n l i s t A k [ v ] :
i n t w = Ak [ v ] [ w Pos ] ;
i f ( w <start ) continue ;/ / i g n or e r e l e v a n t p a r t s o f Ak
i f ( n o t I n L i s t ( B [ w] , v ) ) a d d T o L i s t ( B [ w] , v ) ;
}
}
v = s t a c k P o p ( ) ;
r e t u r n f ;
}
Figure 5: Recursive circuit enumeration
v o i d setupGlobals (){/ / p r e s u p p o s e s n V e r t i c e s i s s e t up
Ak. length = nVertices ; / / A k[ i ] [ 0] i s t he n umb er o f m embe rs , Ak [ i ] [ 1 ] . . A k[ i ] [ n ] ARE t he me mbe rs , i >0
B. length = nVertices ; / / B [ i ] [ 0 ] i s t he n umb er o f m emb ers , B [ i ] [ 1 ] . . B [ i ] [ n ] ARE t he me mbe rs , i >0
b lo c k e d . l e n g t h = n V e r t i c e s ; / / we u s e b l o c k e d [ 0 ] . . b l o c k e d [ n −1] , i >=0
for (i n t i = 0 ; i<n V e r t i c e s ; i + +) {
Ak [ i ] = ne w L i st ( n V e r t i c e s ) ;
B[ i ] = ne w L i st ( n V e r t i c e s ) ;
b l o c k e d [ i ] = false ;
}
l e n gt h H i s t o g r a m . l e n g t h = n V e r t i c e s + 1 ; / / w i l l u s e as [ 1 ] . . . [ n ] t o h i st o gr a m c i r c u i t s by l e n gt h
/ / [ 0 ] f o r z e r o l e n g t h c i r c u i t s , w h ic h a r e i m p o s s i b l e
for (i n t l e n = 0 ; l e n <l e n g t h H i s t o g r a m . l e n g t h ; l e n + +) / / i n i t i a l i s e h is to g ra m b i ns t o e mp ty
l e n g t h H i s t o g r a m [ l e n ] = 0;
s t a c k I n i t ( n V e r t i c e s ) ;
v e r t e x P o p u l a r i t y . l e n g t h = n V e r t i c e s + 1 ; / / max e l e m e nt a r y c i r c u i t l e n g t h i s e x a c t l y n V e r t i c e s
for (i n t l e n = 0 ; l e n <=n V e r t i c e s ; l e n + +){
v e r t e x P o p u l a r i t y [ l e n ] . l e n g t h = n V e r t i c e s ;
for (i n t j = 0 ; j <n V e r t i c e s ; j + +) {
v e r t e x P o p u l a r i t y [ l e n ] [ j ] = 0 ;
}
}
}
ma in ( ) {
setupGlobals () ;
stackClear ();
s t a r t = 0 ;
while ( start <nVertices ){
i f ( v e r b o s e && e n u m e r a t i o n ) f w r i t e f ( s t d e r r , ” S t a r t i n g s =\%d\n” , s t a r t ) ;
for (i n t i = 0 ; i<n V e r t i c e s ; i ++ ){/ / f o r a l l i i n V k
b l o c k e d [ i ] = false ;
e m p t y L i s t ( B[ i ] ) ;
}
c i r c u i t ( s t a r t ) ;
start = start + 1;
}
}
Figure 6: Main calling code and initialisation of globals and measurement variables.
Figure 9: 16 Node Network with K= 2 inputs, showing the output degree of each node and one of the circuits in the
graph, connecting node 0 to node 15. This network allows self-arcs.
0 10 11 6 13 3 4 15 0 1 8 4 13 12 1
0 10 11 6 13 12 1 8 0 1 8 4 13 12 1
0 10 11 6 13 12 1 8 4 15 0 3 3
0 10 11 6 13 12 1 8 0 3 4 13 3
0 10 11 6 13 12 1 8 4 15 0 3 6 13 3
0 10 11 6 13 15 0 6 13 12 10 11 6
0 14 11 6 13 3 4 15 0 6 13 12 14 11 6
0 14 11 6 13 12 1 8 0 8 8
0 14 11 6 13 12 1 8 4 15 0 9 9
0 14 11 6 13 12 1 8 0 12 12
0 14 11 6 13 12 1 8 4 15 0
01411613150
Figure 10: 22 Circuits found in the network shown in figure 9 which has 16 nodes and 32 arcs and allows self-arcs. Note
there are repeated circuits due to the presence of a multiple-arc connecting nodes 12 and 1.
connections or other rewirings can be studied is the simple
square mesh. Table 1 shows some circuit measurements for
periodic square mesh graphs. This emphasises how rapidly
the number of circuits grows in well-connected graphs.
5 Discussion and Conclusions
There are a number of interesting graph applications for
which it is interesting to study elementary circuits. A sim-
ple one arises in work-flow applications with task graphs
where it is often important to determine if there are any
loops or circuits. Such a loop can mean the task graph or
work-flow is indeterminate and can therefore be flagged
as an error in its specification. The algorithm and code
we have presented can be readily adjusted to simple return
a boolean as soon as it finds such a loop or circuit or to
search all possibilities before returning a “false” as proof
that there are no such loops. This sort of routine could do
without with much of the measurements and support in-
frastructure code we have presented.
We have studied some highly regular graphs formed from
simple meshes. This gives us some heuristics and intu-
ition about the practical limitations on the size of graphs for
which we can study the number of circuits explicitly. On
a typical modern 64-bit word size workstation (2.66GHz)
and operating system with 4GBytes of memory we can
count exactly the number of circuits in a nearest-neighbour
connected mesh of 36 = 6 ×6nodes in less than an hour.
A mesh of 49 = 7 ×7is just possible, taking 3 days ex-
ecution time. Larger than this we run out or memory (and
indeed patience).
Another interesting issue concerns the presence of Hamil-
tonian circuits. These are circuits that include all nodes in
a graph. Random graphs or those generated according to a
statistical distribution or arising from some application can
have multiple Hamiltonian routes if there are multiple arcs
present. In our study of Kauffman networks [1] we found
that in highly complex networks, the presence of Hamil-
tonian circuits and also circuits of length greater than half
the number of nodes were interesting indicators of a phase
transitions.
The number of circuits grows very rapidly, particularly in
highly connected graphs. We were able to study Kauffman
systems of up to around 100 nodes but only for very low
connectivities of around K= 2,3. For higher connected
systems, only graphs with a small numbers of nodes such
as 30 −40 are possible in a practical execution time.
We have shown how Johnson’s algorithm can be adjusted
to cope with self- and multiple arcs and how a fast and
practical implementation can be implemented using the ca-
pabilities of a systems level object-oriented language like
D. Despite the practical limitations on graph size, we be-
lieve a exact study of circuits yields very interesting in-
sights into certain network problems such as small-world
systems, biological, social and Internet systems.
References
[1] Hawick, K., James, H., Scogings, C.: Structural cir-
cuits and attractors in kauffman networks. In Ab-
bass, H.A., Randall, M., eds.: Proc. Third Australian
Conference on Artificial Life. Volume 4828 of LNCS.,
Springer (2007) 189–200 978-3-540-76930-9.
[2] Hawick, K.A., James, H.A., Scogings, C.J.: Cir-
cuits, attractors and reachability in mixed-k kauff-
/ / r e t u r n a p o i n t e r t o a l i s t o f f i x e d m ax s i z e
i n t [ ] n e w L i s t ( i n t max ) {
i n t [ ] r e t v a l ; r e t v a l . l e n g t h = m ax + 1 ;
r e t v a l [ 0] = 0 ;
r e t u r n retval ;
}
/ / r e t u r n TRUE i f v a lu e i s NOT i n t h e l i s t
b o o l notInList ( i n t [ ] l i s t , i n t v a l ) {
a s s e r t ( l i s t ! = n u l l ) ;
a s s e r t ( l i s t [ 0 ] <l i s t . l e n g t h ) ;
for (i n t i = 1 ; i <=l i s t [ 0 ] ; i ++ ) {
i f ( l i s t [ i ] == v a l )
r et u rn f a l s e ;
}
r e t u r n t r u e ;
}
/ / r e t u r n TRUE i f v a lu e i s i n t h e l i s t
b o o l inList ( i n t [ ] l i s t , i n t v a l ) {
a s s e r t ( l i s t ! = n u l l ) ;
a s s e r t ( l i s t [ 0 ] <l i s t . l e n g t h ) ;
for (i n t i = 1 ; i <=l i s t [ 0 ] ; i ++ ) {
i f ( l i s t [ i ] == v a l )
r e t u r n t r u e ;
}
r et u rn f a l s e ;
}
/ / e m p t i e s a l i s t b y s i m p l y z e r o i n g i t s s i z e
v o i d e m p t y L i s t ( i n t [ ] l i s t ) {
a s s e r t ( l i s t ! = n u l l ) ;
a s s e r t ( l i s t [ 0 ] <l i s t . l e n g t h ) ;
l i s t [ 0] = 0 ;
}
/ / a dd s o n t o t h e e n d ( m a k in g e x t r a s p a c e i f n e e d e d )
v o i d a d d T o L i s t ( i n o u t i n t [ ] l i s t , i n t v a l ) {
a s s e r t ( l i s t ! = n u l l ) ;
a s s e r t ( l i s t [ 0 ] <l i s t . l e n g t h ) ;
i n t n ewPo s = l i s t [ 0] + 1 ;
i f ( newPos >= l i s t . l e n g t h )
l i s t . l e n g t h = l i s t . l e n g t h + 1 ;
l i s t [ ne wPo s ] = v a l ;
l i s t [ 0] = n ewP os ;
}
/ / r em o v e s a l l o c c u r e n c e s o f v a l i n t h e l i s t
i n t removeFromList ( i n t [ ] l i s t , i n t v a l ) {
a s s e r t ( l i s t ! = n u l l ) ;
a s s e r t ( l i s t [ 0 ] <l i s t . l e n g t h ) ;
i n t nOccurrences = 0;
for (i n t i = 1 ; i <= l i s t [ 0 ] ; i + +){
i f ( l i s t [ i ] == v a l ) {
nOccurrences++;
for (i n t j = i ; j <l i s t [ 0 ] ; j + +){
l i s t [ j ] = l i s t [ j + 1] ;
}
−−l i s t [ 0 ] ; / / s h o u l d b e s a f e a s l i s t [ 0 ] i s
/ / r e−e v a l u a t e d e a ch t i m e a r ou n d t h e i−l o o p
−− i ;
}
}
r e t u r n nOccurrences ;
}
Figure 8: List management code - note use of the D inout
qualifier which is required for addToList to change its
list argument.
man networks. Technical Report CSTN-046;
arXiv:0711.2426, Massey University (2007)
[3] Hawick, K.A., James, H.A.: Node importance rank-
ing and scaling properties of some complex road net-
works. Technical report, Information and Mathemati-
cal Sciences, Massey University, Albany, North Shore
102-904, Auckland, New Zealand (2005)
[4] Tiernan, J.C.: An efficient search algorithm to find the
elementary circuits of a graph. Communications of the
ACM 13 (1970) 722–726
[5] Tarjan, R.: Enumeration of the elementary circuits of a
directed graph. SIAM Journal on Computing 2(1973)
211–216
[6] Johnson, D.B.: Finding all the elementary circuits of a
directed graph. SIAM Journal on Computing 4(1975)
77–84
[7] Bright, W.: D Programming Language. Digital Mars.
(2008)