280 lines
5.8 KiB
Go
280 lines
5.8 KiB
Go
// 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
|
|
}
|