fixed dependencies
This commit is contained in:
279
vendor/gonum.org/v1/plot/plotter/johnson.go
generated
vendored
Normal file
279
vendor/gonum.org/v1/plot/plotter/johnson.go
generated
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
// 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
|
||||
}
|
||||
Reference in New Issue
Block a user