// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package plotter // johnson implements Johnson's "Finding all the elementary // circuits of a directed graph" algorithm. SIAM J. Comput. 4(1):1975. // // Comments in the johnson methods are kept in sync with the comments // and labels from the paper. type johnson struct { adjacent graph // SCC adjacency list. b []set // Johnson's "B-list". blocked []bool s int stack []int result [][]int } // cyclesIn returns the set of elementary cycles in the graph g. func cyclesIn(g graph) [][]int { j := johnson{ adjacent: g.clone(), b: make([]set, len(g)), blocked: make([]bool, len(g)), } // len(j.adjacent) will be the order of g until Tarjan's analysis // finds no SCC, at which point t.sccSubGraph returns nil and the // loop breaks. for j.s < len(j.adjacent)-1 { // We use the previous SCC adjacency to reduce the work needed. t := newTarjan(j.adjacent.subgraph(j.s)) // A_k = adjacency structure of strong component K with least // vertex in subgraph of G induced by {s, s+1, ... ,n}. j.adjacent = t.sccSubGraph(2) // Only allow SCCs with >= 2 vertices. if len(j.adjacent) == 0 { break } // s = least vertex in V_k for _, v := range j.adjacent { s := len(j.adjacent) for n := range v { if n < s { s = n } } if s < j.s { j.s = s } } for i, v := range j.adjacent { if len(v) > 0 { j.blocked[i] = false j.b[i] = make(set) } } //L3: _ = j.circuit(j.s) j.s++ } return j.result } // circuit is the CIRCUIT sub-procedure in the paper. func (j *johnson) circuit(v int) bool { f := false j.stack = append(j.stack, v) j.blocked[v] = true //L1: for w := range j.adjacent[v] { if w == j.s { // Output circuit composed of stack followed by s. r := make([]int, len(j.stack)+1) copy(r, j.stack) r[len(r)-1] = j.s j.result = append(j.result, r) f = true } else if !j.blocked[w] { if j.circuit(w) { f = true } } } //L2: if f { j.unblock(v) } else { for w := range j.adjacent[v] { j.b[w][v] = struct{}{} } } j.stack = j.stack[:len(j.stack)-1] return f } // unblock is the UNBLOCK sub-procedure in the paper. func (j *johnson) unblock(u int) { j.blocked[u] = false for w := range j.b[u] { delete(j.b[u], w) if j.blocked[w] { j.unblock(w) } } } func min(a, b int) int { if a < b { return a } return b } // tarjan implements Tarjan's strongly connected component finding // algorithm. The implementation is from the pseudocode at // // http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644 type tarjan struct { g graph index int indexTable []int lowLink []int onStack []bool stack []int sccs [][]int } // newTarjan returns a tarjan with the sccs field filled with the // strongly connected components of the directed graph g. func newTarjan(g graph) *tarjan { t := tarjan{ g: g, indexTable: make([]int, len(g)), lowLink: make([]int, len(g)), onStack: make([]bool, len(g)), } for v := range t.g { if t.indexTable[v] == 0 { t.strongconnect(v) } } return &t } // strongconnect is the strongconnect function described in the // wikipedia article. func (t *tarjan) strongconnect(v int) { // Set the depth index for v to the smallest unused index. t.index++ t.indexTable[v] = t.index t.lowLink[v] = t.index t.stack = append(t.stack, v) t.onStack[v] = true // Consider successors of v. for w := range t.g[v] { if t.indexTable[w] == 0 { // Successor w has not yet been visited; recur on it. t.strongconnect(w) t.lowLink[v] = min(t.lowLink[v], t.lowLink[w]) } else if t.onStack[w] { // Successor w is in stack s and hence in the current SCC. t.lowLink[v] = min(t.lowLink[v], t.indexTable[w]) } } // If v is a root node, pop the stack and generate an SCC. if t.lowLink[v] == t.indexTable[v] { // Start a new strongly connected component. var ( scc []int w int ) for { w, t.stack = t.stack[len(t.stack)-1], t.stack[:len(t.stack)-1] t.onStack[w] = false // Add w to current strongly connected component. scc = append(scc, w) if w == v { break } } // Output the current strongly connected component. t.sccs = append(t.sccs, scc) } } // sccSubGraph returns the graph of the tarjan's strongly connected // components with each SCC containing at least min vertices. // sccSubGraph returns nil if there is no SCC with at least min // members. func (t *tarjan) sccSubGraph(min int) graph { if len(t.g) == 0 { return nil } sub := make(graph, len(t.g)) var n int for _, scc := range t.sccs { if len(scc) < min { continue } n++ for _, u := range scc { for _, v := range scc { if _, ok := t.g[u][v]; ok { if sub[u] == nil { sub[u] = make(set) } sub[u][v] = struct{}{} } } } } if n == 0 { return nil } return sub } // set is an integer set. type set map[int]struct{} // graph is an edge list representation of a graph. type graph []set // remove deletes edges that make up the given paths from the graph. func (g graph) remove(paths [][]int) { for _, p := range paths { for i, u := range p[:len(p)-1] { delete(g[u], p[i+1]) } } } // subgraph returns a subgraph of g induced by {s, s+1, ... , n}. The // subgraph is destructively generated in g. func (g graph) subgraph(s int) graph { for u := range g[:s] { g[u] = nil } for u, e := range g[s:] { for v := range e { if v < s { delete(g[u+s], v) } } } return g } // clone returns a deep copy of the graph g. func (g graph) clone() graph { c := make(graph, len(g)) for u, e := range g { for v := range e { if c[u] == nil { c[u] = make(set) } c[u][v] = struct{}{} } } return c }