feat(modules): migrate to go modules and bump go version 1.14.4

- migrate to go module
- bump go version 1.14.4

Signed-off-by: prateekpandey14 <prateek.pandey@mayadata.io>
This commit is contained in:
prateekpandey14 2020-06-05 19:25:46 +05:30 committed by Pawan Prakash Sharma
parent f5ae3ff476
commit fa76b346a0
837 changed files with 104140 additions and 158314 deletions

250
vendor/gonum.org/v1/gonum/graph/topo/bron_kerbosch.go generated vendored Normal file
View file

@ -0,0 +1,250 @@
// 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 topo
import (
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/ordered"
"gonum.org/v1/gonum/graph/internal/set"
)
// DegeneracyOrdering returns the degeneracy ordering and the k-cores of
// the undirected graph g.
func DegeneracyOrdering(g graph.Undirected) (order []graph.Node, cores [][]graph.Node) {
order, offsets := degeneracyOrdering(g)
ordered.Reverse(order)
cores = make([][]graph.Node, len(offsets))
offset := len(order)
for i, n := range offsets {
cores[i] = order[offset-n : offset]
offset -= n
}
return order, cores
}
// KCore returns the k-core of the undirected graph g with nodes in an
// optimal ordering for the coloring number.
func KCore(k int, g graph.Undirected) []graph.Node {
order, offsets := degeneracyOrdering(g)
var offset int
for _, n := range offsets[:k] {
offset += n
}
core := make([]graph.Node, len(order)-offset)
copy(core, order[offset:])
return core
}
// degeneracyOrdering is the common code for DegeneracyOrdering and KCore. It
// returns l, the nodes of g in optimal ordering for coloring number and
// s, a set of relative offsets into l for each k-core, where k is an index
// into s.
func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) {
nodes := graph.NodesOf(g.Nodes())
// The algorithm used here is essentially as described at
// http://en.wikipedia.org/w/index.php?title=Degeneracy_%28graph_theory%29&oldid=640308710
// Initialize an output list L in return parameters.
// Compute a number d_v for each vertex v in G,
// the number of neighbors of v that are not already in L.
// Initially, these numbers are just the degrees of the vertices.
dv := make(map[int64]int, len(nodes))
var (
maxDegree int
neighbours = make(map[int64][]graph.Node)
)
for _, n := range nodes {
id := n.ID()
adj := graph.NodesOf(g.From(id))
neighbours[id] = adj
dv[id] = len(adj)
if len(adj) > maxDegree {
maxDegree = len(adj)
}
}
// Initialize an array D such that D[i] contains a list of the
// vertices v that are not already in L for which d_v = i.
d := make([][]graph.Node, maxDegree+1)
for _, n := range nodes {
deg := dv[n.ID()]
d[deg] = append(d[deg], n)
}
// Initialize k to 0.
k := 0
// Repeat n times:
s = []int{0}
for range nodes {
// Scan the array cells D[0], D[1], ... until
// finding an i for which D[i] is nonempty.
var (
i int
di []graph.Node
)
for i, di = range d {
if len(di) != 0 {
break
}
}
// Set k to max(k,i).
if i > k {
k = i
s = append(s, make([]int, k-len(s)+1)...)
}
// Select a vertex v from D[i]. Add v to the
// beginning of L and remove it from D[i].
var v graph.Node
v, d[i] = di[len(di)-1], di[:len(di)-1]
l = append(l, v)
s[k]++
delete(dv, v.ID())
// For each neighbor w of v not already in L,
// subtract one from d_w and move w to the
// cell of D corresponding to the new value of d_w.
for _, w := range neighbours[v.ID()] {
dw, ok := dv[w.ID()]
if !ok {
continue
}
for i, n := range d[dw] {
if n.ID() == w.ID() {
d[dw][i], d[dw] = d[dw][len(d[dw])-1], d[dw][:len(d[dw])-1]
dw--
d[dw] = append(d[dw], w)
break
}
}
dv[w.ID()] = dw
}
}
return l, s
}
// BronKerbosch returns the set of maximal cliques of the undirected graph g.
func BronKerbosch(g graph.Undirected) [][]graph.Node {
nodes := graph.NodesOf(g.Nodes())
// The algorithm used here is essentially BronKerbosch3 as described at
// http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858
p := set.NewNodesSize(len(nodes))
for _, n := range nodes {
p.Add(n)
}
x := set.NewNodes()
var bk bronKerbosch
order, _ := degeneracyOrdering(g)
ordered.Reverse(order)
for _, v := range order {
neighbours := graph.NodesOf(g.From(v.ID()))
nv := set.NewNodesSize(len(neighbours))
for _, n := range neighbours {
nv.Add(n)
}
bk.maximalCliquePivot(g, []graph.Node{v}, set.IntersectionOfNodes(p, nv), set.IntersectionOfNodes(x, nv))
p.Remove(v)
x.Add(v)
}
return bk
}
type bronKerbosch [][]graph.Node
func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p, x set.Nodes) {
if len(p) == 0 && len(x) == 0 {
*bk = append(*bk, r)
return
}
neighbours := bk.choosePivotFrom(g, p, x)
nu := set.NewNodesSize(len(neighbours))
for _, n := range neighbours {
nu.Add(n)
}
for _, v := range p {
if nu.Has(v) {
continue
}
vid := v.ID()
neighbours := graph.NodesOf(g.From(vid))
nv := set.NewNodesSize(len(neighbours))
for _, n := range neighbours {
nv.Add(n)
}
var found bool
for _, n := range r {
if n.ID() == vid {
found = true
break
}
}
var sr []graph.Node
if !found {
sr = append(r[:len(r):len(r)], v)
}
bk.maximalCliquePivot(g, sr, set.IntersectionOfNodes(p, nv), set.IntersectionOfNodes(x, nv))
p.Remove(v)
x.Add(v)
}
}
func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighbors []graph.Node) {
// TODO(kortschak): Investigate the impact of pivot choice that maximises
// |p ⋂ neighbours(u)| as a function of input size. Until then, leave as
// compile time option.
if !tomitaTanakaTakahashi {
for _, n := range p {
return graph.NodesOf(g.From(n.ID()))
}
for _, n := range x {
return graph.NodesOf(g.From(n.ID()))
}
panic("bronKerbosch: empty set")
}
var (
max = -1
pivot graph.Node
)
maxNeighbors := func(s set.Nodes) {
outer:
for _, u := range s {
nb := graph.NodesOf(g.From(u.ID()))
c := len(nb)
if c <= max {
continue
}
for n := range nb {
if _, ok := p[int64(n)]; ok {
continue
}
c--
if c <= max {
continue outer
}
}
max = c
pivot = u
neighbors = nb
}
}
maxNeighbors(p)
maxNeighbors(x)
if pivot == nil {
panic("bronKerbosch: empty set")
}
return neighbors
}

111
vendor/gonum.org/v1/gonum/graph/topo/clique_graph.go generated vendored Normal file
View file

@ -0,0 +1,111 @@
// Copyright ©2017 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 topo
import (
"sort"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/ordered"
"gonum.org/v1/gonum/graph/internal/set"
)
// Builder is a pure topological graph construction type.
type Builder interface {
AddNode(graph.Node)
SetEdge(graph.Edge)
}
// CliqueGraph builds the clique graph of g in dst using Clique and CliqueGraphEdge
// nodes and edges. The nodes returned by calls to Nodes on the nodes and edges of
// the constructed graph are the cliques and the common nodes between cliques
// respectively. The dst graph is not cleared.
func CliqueGraph(dst Builder, g graph.Undirected) {
cliques := BronKerbosch(g)
// Construct a consistent view of cliques in g. Sorting costs
// us a little, but not as much as the cliques themselves.
for _, c := range cliques {
sort.Sort(ordered.ByID(c))
}
sort.Sort(ordered.BySliceIDs(cliques))
cliqueNodes := make(cliqueNodeSets, len(cliques))
for id, c := range cliques {
s := set.NewNodesSize(len(c))
for _, n := range c {
s.Add(n)
}
ns := &nodeSet{Clique: Clique{id: int64(id), nodes: c}, nodes: s}
dst.AddNode(ns.Clique)
for _, n := range c {
nid := n.ID()
cliqueNodes[nid] = append(cliqueNodes[nid], ns)
}
}
for _, cliques := range cliqueNodes {
for i, uc := range cliques {
for _, vc := range cliques[i+1:] {
// Retain the nodes that contribute to the
// edge between the cliques.
var edgeNodes []graph.Node
switch 1 {
case len(uc.Clique.nodes):
edgeNodes = []graph.Node{uc.Clique.nodes[0]}
case len(vc.Clique.nodes):
edgeNodes = []graph.Node{vc.Clique.nodes[0]}
default:
for _, n := range set.IntersectionOfNodes(uc.nodes, vc.nodes) {
edgeNodes = append(edgeNodes, n)
}
sort.Sort(ordered.ByID(edgeNodes))
}
dst.SetEdge(CliqueGraphEdge{from: uc.Clique, to: vc.Clique, nodes: edgeNodes})
}
}
}
}
type cliqueNodeSets map[int64][]*nodeSet
type nodeSet struct {
Clique
nodes set.Nodes
}
// Clique is a node in a clique graph.
type Clique struct {
id int64
nodes []graph.Node
}
// ID returns the node ID.
func (n Clique) ID() int64 { return n.id }
// Nodes returns the nodes in the clique.
func (n Clique) Nodes() []graph.Node { return n.nodes }
// CliqueGraphEdge is an edge in a clique graph.
type CliqueGraphEdge struct {
from, to Clique
nodes []graph.Node
}
// From returns the from node of the edge.
func (e CliqueGraphEdge) From() graph.Node { return e.from }
// To returns the to node of the edge.
func (e CliqueGraphEdge) To() graph.Node { return e.to }
// ReversedEdge returns a new CliqueGraphEdge with
// the edge end points swapped. The nodes of the
// new edge are shared with the receiver.
func (e CliqueGraphEdge) ReversedEdge() graph.Edge { e.from, e.to = e.to, e.from; return e }
// Nodes returns the common nodes in the cliques of the underlying graph
// corresponding to the from and to nodes in the clique graph.
func (e CliqueGraphEdge) Nodes() []graph.Node { return e.nodes }

6
vendor/gonum.org/v1/gonum/graph/topo/doc.go generated vendored Normal file
View file

@ -0,0 +1,6 @@
// Copyright ©2017 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 topo provides graph topology analysis functions.
package topo // import "gonum.org/v1/gonum/graph/topo"

285
vendor/gonum.org/v1/gonum/graph/topo/johnson_cycles.go generated vendored Normal file
View file

@ -0,0 +1,285 @@
// 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 topo
import (
"sort"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/ordered"
"gonum.org/v1/gonum/graph/internal/set"
"gonum.org/v1/gonum/graph/iterator"
)
// 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 johnsonGraph // SCC adjacency list.
b []set.Ints // Johnson's "B-list".
blocked []bool
s int
stack []graph.Node
result [][]graph.Node
}
// DirectedCyclesIn returns the set of elementary cycles in the graph g.
func DirectedCyclesIn(g graph.Directed) [][]graph.Node {
jg := johnsonGraphFrom(g)
j := johnson{
adjacent: jg,
b: make([]set.Ints, len(jg.orig)),
blocked: make([]bool, len(jg.orig)),
}
// len(j.nodes) is the order of g.
for j.s < len(j.adjacent.orig)-1 {
// We use the previous SCC adjacency to reduce the work needed.
sccs := TarjanSCC(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 = j.adjacent.sccSubGraph(sccs, 2) // Only allow SCCs with >= 2 vertices.
if j.adjacent.order() == 0 {
break
}
// s = least vertex in V_k
if s := j.adjacent.leastVertexIndex(); s < j.s {
j.s = s
}
for i, v := range j.adjacent.orig {
if !j.adjacent.nodes.Has(v.ID()) {
continue
}
if len(j.adjacent.succ[v.ID()]) > 0 {
j.blocked[i] = false
j.b[i] = make(set.Ints)
}
}
//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
n := j.adjacent.orig[v]
j.stack = append(j.stack, n)
j.blocked[v] = true
//L1:
for w := range j.adjacent.succ[n.ID()] {
w := j.adjacent.indexOf(w)
if w == j.s {
// Output circuit composed of stack followed by s.
r := make([]graph.Node, len(j.stack)+1)
copy(r, j.stack)
r[len(r)-1] = j.adjacent.orig[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.succ[n.ID()] {
j.b[j.adjacent.indexOf(w)].Add(v)
}
}
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] {
j.b[u].Remove(w)
if j.blocked[w] {
j.unblock(w)
}
}
}
// johnsonGraph is an edge list representation of a graph with helpers
// necessary for Johnson's algorithm
type johnsonGraph struct {
// Keep the original graph nodes and a
// look-up to into the non-sparse
// collection of potentially sparse IDs.
orig []graph.Node
index map[int64]int
nodes set.Int64s
succ map[int64]set.Int64s
}
// johnsonGraphFrom returns a deep copy of the graph g.
func johnsonGraphFrom(g graph.Directed) johnsonGraph {
nodes := graph.NodesOf(g.Nodes())
sort.Sort(ordered.ByID(nodes))
c := johnsonGraph{
orig: nodes,
index: make(map[int64]int, len(nodes)),
nodes: make(set.Int64s, len(nodes)),
succ: make(map[int64]set.Int64s),
}
for i, u := range nodes {
uid := u.ID()
c.index[uid] = i
for _, v := range graph.NodesOf(g.From(uid)) {
if c.succ[uid] == nil {
c.succ[uid] = make(set.Int64s)
c.nodes.Add(uid)
}
c.nodes.Add(v.ID())
c.succ[uid].Add(v.ID())
}
}
return c
}
// order returns the order of the graph.
func (g johnsonGraph) order() int { return g.nodes.Count() }
// indexOf returns the index of the retained node for the given node ID.
func (g johnsonGraph) indexOf(id int64) int {
return g.index[id]
}
// leastVertexIndex returns the index into orig of the least vertex.
func (g johnsonGraph) leastVertexIndex() int {
for _, v := range g.orig {
if g.nodes.Has(v.ID()) {
return g.indexOf(v.ID())
}
}
panic("johnsonCycles: empty set")
}
// subgraph returns a subgraph of g induced by {s, s+1, ... , n}. The
// subgraph is destructively generated in g.
func (g johnsonGraph) subgraph(s int) johnsonGraph {
sn := g.orig[s].ID()
for u, e := range g.succ {
if u < sn {
g.nodes.Remove(u)
delete(g.succ, u)
continue
}
for v := range e {
if v < sn {
g.succ[u].Remove(v)
}
}
}
return g
}
// 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 (g johnsonGraph) sccSubGraph(sccs [][]graph.Node, min int) johnsonGraph {
if len(g.nodes) == 0 {
g.nodes = nil
g.succ = nil
return g
}
sub := johnsonGraph{
orig: g.orig,
index: g.index,
nodes: make(set.Int64s),
succ: make(map[int64]set.Int64s),
}
var n int
for _, scc := range sccs {
if len(scc) < min {
continue
}
n++
for _, u := range scc {
for _, v := range scc {
if _, ok := g.succ[u.ID()][v.ID()]; ok {
if sub.succ[u.ID()] == nil {
sub.succ[u.ID()] = make(set.Int64s)
sub.nodes.Add(u.ID())
}
sub.nodes.Add(v.ID())
sub.succ[u.ID()].Add(v.ID())
}
}
}
}
if n == 0 {
g.nodes = nil
g.succ = nil
return g
}
return sub
}
// Nodes is required to satisfy Tarjan.
func (g johnsonGraph) Nodes() graph.Nodes {
n := make([]graph.Node, 0, len(g.nodes))
for id := range g.nodes {
n = append(n, johnsonGraphNode(id))
}
return iterator.NewOrderedNodes(n)
}
// Successors is required to satisfy Tarjan.
func (g johnsonGraph) From(id int64) graph.Nodes {
adj := g.succ[id]
if len(adj) == 0 {
return graph.Empty
}
succ := make([]graph.Node, 0, len(adj))
for id := range adj {
succ = append(succ, johnsonGraphNode(id))
}
return iterator.NewOrderedNodes(succ)
}
func (johnsonGraph) Has(int64) bool {
panic("topo: unintended use of johnsonGraph")
}
func (johnsonGraph) Node(int64) graph.Node {
panic("topo: unintended use of johnsonGraph")
}
func (johnsonGraph) HasEdgeBetween(_, _ int64) bool {
panic("topo: unintended use of johnsonGraph")
}
func (johnsonGraph) Edge(_, _ int64) graph.Edge {
panic("topo: unintended use of johnsonGraph")
}
func (johnsonGraph) HasEdgeFromTo(_, _ int64) bool {
panic("topo: unintended use of johnsonGraph")
}
func (johnsonGraph) To(int64) graph.Nodes {
panic("topo: unintended use of johnsonGraph")
}
type johnsonGraphNode int64
func (n johnsonGraphNode) ID() int64 { return int64(n) }

View file

@ -0,0 +1,9 @@
// 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.
// +build !tomita
package topo
const tomitaTanakaTakahashi = false

83
vendor/gonum.org/v1/gonum/graph/topo/paton_cycles.go generated vendored Normal file
View file

@ -0,0 +1,83 @@
// Copyright ©2017 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 topo
import (
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/linear"
"gonum.org/v1/gonum/graph/internal/set"
)
// UndirectedCyclesIn returns a set of cycles that forms a cycle basis in the graph g.
// Any cycle in g can be constructed as a symmetric difference of its elements.
func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node {
// From "An algorithm for finding a fundamental set of cycles of a graph"
// https://doi.org/10.1145/363219.363232
var cycles [][]graph.Node
done := make(set.Int64s)
var tree linear.NodeStack
nodes := g.Nodes()
for nodes.Next() {
n := nodes.Node()
id := n.ID()
if done.Has(id) {
continue
}
done.Add(id)
tree = tree[:0]
tree.Push(n)
from := sets{id: set.Int64s{}}
to := map[int64]graph.Node{id: n}
for tree.Len() != 0 {
u := tree.Pop()
uid := u.ID()
adj := from[uid]
for _, v := range graph.NodesOf(g.From(uid)) {
vid := v.ID()
switch {
case uid == vid:
cycles = append(cycles, []graph.Node{u})
case !from.has(vid):
done.Add(vid)
to[vid] = u
tree.Push(v)
from.add(uid, vid)
case !adj.Has(vid):
c := []graph.Node{v, u}
adj := from[vid]
p := to[uid]
for !adj.Has(p.ID()) {
c = append(c, p)
p = to[p.ID()]
}
c = append(c, p, c[0])
cycles = append(cycles, c)
adj.Add(uid)
}
}
}
}
return cycles
}
type sets map[int64]set.Int64s
func (s sets) add(uid, vid int64) {
e, ok := s[vid]
if !ok {
e = make(set.Int64s)
s[vid] = e
}
e.Add(uid)
}
func (s sets) has(uid int64) bool {
_, ok := s[uid]
return ok
}

199
vendor/gonum.org/v1/gonum/graph/topo/tarjan.go generated vendored Normal file
View file

@ -0,0 +1,199 @@
// 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 topo
import (
"fmt"
"sort"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/ordered"
"gonum.org/v1/gonum/graph/internal/set"
)
// Unorderable is an error containing sets of unorderable graph.Nodes.
type Unorderable [][]graph.Node
// Error satisfies the error interface.
func (e Unorderable) Error() string {
const maxNodes = 10
var n int
for _, c := range e {
n += len(c)
}
if n > maxNodes {
// Don't return errors that are too long.
return fmt.Sprintf("topo: no topological ordering: %d nodes in %d cyclic components", n, len(e))
}
return fmt.Sprintf("topo: no topological ordering: cyclic components: %v", [][]graph.Node(e))
}
func lexical(nodes []graph.Node) { sort.Sort(ordered.ByID(nodes)) }
// Sort performs a topological sort of the directed graph g returning the 'from' to 'to'
// sort order. If a topological ordering is not possible, an Unorderable error is returned
// listing cyclic components in g with each cyclic component's members sorted by ID. When
// an Unorderable error is returned, each cyclic component's topological position within
// the sorted nodes is marked with a nil graph.Node.
func Sort(g graph.Directed) (sorted []graph.Node, err error) {
sccs := TarjanSCC(g)
return sortedFrom(sccs, lexical)
}
// SortStabilized performs a topological sort of the directed graph g returning the 'from'
// to 'to' sort order, or the order defined by the in place order sort function where there
// is no unambiguous topological ordering. If a topological ordering is not possible, an
// Unorderable error is returned listing cyclic components in g with each cyclic component's
// members sorted by the provided order function. If order is nil, nodes are ordered lexically
// by node ID. When an Unorderable error is returned, each cyclic component's topological
// position within the sorted nodes is marked with a nil graph.Node.
func SortStabilized(g graph.Directed, order func([]graph.Node)) (sorted []graph.Node, err error) {
if order == nil {
order = lexical
}
sccs := tarjanSCCstabilized(g, order)
return sortedFrom(sccs, order)
}
func sortedFrom(sccs [][]graph.Node, order func([]graph.Node)) ([]graph.Node, error) {
sorted := make([]graph.Node, 0, len(sccs))
var sc Unorderable
for _, s := range sccs {
if len(s) != 1 {
order(s)
sc = append(sc, s)
sorted = append(sorted, nil)
continue
}
sorted = append(sorted, s[0])
}
var err error
if sc != nil {
for i, j := 0, len(sc)-1; i < j; i, j = i+1, j-1 {
sc[i], sc[j] = sc[j], sc[i]
}
err = sc
}
ordered.Reverse(sorted)
return sorted, err
}
// TarjanSCC returns the strongly connected components of the graph g using Tarjan's algorithm.
//
// A strongly connected component of a graph is a set of vertices where it's possible to reach any
// vertex in the set from any other (meaning there's a cycle between them.)
//
// Generally speaking, a directed graph where the number of strongly connected components is equal
// to the number of nodes is acyclic, unless you count reflexive edges as a cycle (which requires
// only a little extra testing.)
//
func TarjanSCC(g graph.Directed) [][]graph.Node {
return tarjanSCCstabilized(g, nil)
}
func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node {
nodes := graph.NodesOf(g.Nodes())
var succ func(id int64) []graph.Node
if order == nil {
succ = func(id int64) []graph.Node {
return graph.NodesOf(g.From(id))
}
} else {
order(nodes)
ordered.Reverse(nodes)
succ = func(id int64) []graph.Node {
to := graph.NodesOf(g.From(id))
order(to)
ordered.Reverse(to)
return to
}
}
t := tarjan{
succ: succ,
indexTable: make(map[int64]int, len(nodes)),
lowLink: make(map[int64]int, len(nodes)),
onStack: make(set.Int64s),
}
for _, v := range nodes {
if t.indexTable[v.ID()] == 0 {
t.strongconnect(v)
}
}
return t.sccs
}
// 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 {
succ func(id int64) []graph.Node
index int
indexTable map[int64]int
lowLink map[int64]int
onStack set.Int64s
stack []graph.Node
sccs [][]graph.Node
}
// strongconnect is the strongconnect function described in the
// wikipedia article.
func (t *tarjan) strongconnect(v graph.Node) {
vID := v.ID()
// Set the depth index for v to the smallest unused index.
t.index++
t.indexTable[vID] = t.index
t.lowLink[vID] = t.index
t.stack = append(t.stack, v)
t.onStack.Add(vID)
// Consider successors of v.
for _, w := range t.succ(vID) {
wID := w.ID()
if t.indexTable[wID] == 0 {
// Successor w has not yet been visited; recur on it.
t.strongconnect(w)
t.lowLink[vID] = min(t.lowLink[vID], t.lowLink[wID])
} else if t.onStack.Has(wID) {
// Successor w is in stack s and hence in the current SCC.
t.lowLink[vID] = min(t.lowLink[vID], t.indexTable[wID])
}
}
// If v is a root node, pop the stack and generate an SCC.
if t.lowLink[vID] == t.indexTable[vID] {
// Start a new strongly connected component.
var (
scc []graph.Node
w graph.Node
)
for {
w, t.stack = t.stack[len(t.stack)-1], t.stack[:len(t.stack)-1]
t.onStack.Remove(w.ID())
// Add w to current strongly connected component.
scc = append(scc, w)
if w.ID() == vID {
break
}
}
// Output the current strongly connected component.
t.sccs = append(t.sccs, scc)
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}

View file

@ -0,0 +1,9 @@
// 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.
// +build tomita
package topo
const tomitaTanakaTakahashi = true

68
vendor/gonum.org/v1/gonum/graph/topo/topo.go generated vendored Normal file
View file

@ -0,0 +1,68 @@
// Copyright ©2014 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 topo
import (
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/traverse"
)
// IsPathIn returns whether path is a path in g.
//
// As special cases, IsPathIn returns true for a zero length path or for
// a path of length 1 when the node in path exists in the graph.
func IsPathIn(g graph.Graph, path []graph.Node) bool {
switch len(path) {
case 0:
return true
case 1:
return g.Node(path[0].ID()) != nil
default:
var canReach func(uid, vid int64) bool
switch g := g.(type) {
case graph.Directed:
canReach = g.HasEdgeFromTo
default:
canReach = g.HasEdgeBetween
}
for i, u := range path[:len(path)-1] {
if !canReach(u.ID(), path[i+1].ID()) {
return false
}
}
return true
}
}
// PathExistsIn returns whether there is a path in g starting at from extending
// to to.
//
// PathExistsIn exists as a helper function. If many tests for path existence
// are being performed, other approaches will be more efficient.
func PathExistsIn(g graph.Graph, from, to graph.Node) bool {
var t traverse.BreadthFirst
return t.Walk(g, from, func(n graph.Node, _ int) bool { return n.ID() == to.ID() }) != nil
}
// ConnectedComponents returns the connected components of the undirected graph g.
func ConnectedComponents(g graph.Undirected) [][]graph.Node {
var (
w traverse.DepthFirst
c []graph.Node
cc [][]graph.Node
)
during := func(n graph.Node) {
c = append(c, n)
}
after := func() {
cc = append(cc, []graph.Node(nil))
cc[len(cc)-1] = append(cc[len(cc)-1], c...)
c = c[:0]
}
w.WalkAll(g, nil, after, during)
return cc
}