aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/soniakeys/graph/dir_RO.go
diff options
context:
space:
mode:
authorPaul Zabelin2016-04-17 03:22:31 -0700
committerPaul Zabelin2016-04-17 03:22:31 -0700
commitb5eb2866cfceb69b0d4dd4948273d679a884fbb2 (patch)
tree1fdb61a7138642a1612bb201434e8ebda141cc8a /vendor/github.com/soniakeys/graph/dir_RO.go
parent8de8e05c483c6b5f23b14742315f1860211dcef7 (diff)
downloadgdrive-b5eb2866cfceb69b0d4dd4948273d679a884fbb2.tar.bz2
add Go dependencies by godep
see https://github.com/tools/godep
Diffstat (limited to 'vendor/github.com/soniakeys/graph/dir_RO.go')
-rw-r--r--vendor/github.com/soniakeys/graph/dir_RO.go395
1 files changed, 395 insertions, 0 deletions
diff --git a/vendor/github.com/soniakeys/graph/dir_RO.go b/vendor/github.com/soniakeys/graph/dir_RO.go
new file mode 100644
index 0000000..77558a9
--- /dev/null
+++ b/vendor/github.com/soniakeys/graph/dir_RO.go
@@ -0,0 +1,395 @@
+// Copyright 2014 Sonia Keys
+// License MIT: http://opensource.org/licenses/MIT
+
+package graph
+
+// dir_RO.go is code generated from dir_cg.go by directives in graph.go.
+// Editing dir_cg.go is okay. It is the code generation source.
+// DO NOT EDIT dir_RO.go.
+// The RO means read only and it is upper case RO to slow you down a bit
+// in case you start to edit the file.
+
+// Balanced returns true if for every node in g, in-degree equals out-degree.
+//
+// There are equivalent labeled and unlabeled versions of this method.
+func (g Directed) Balanced() bool {
+ for n, in := range g.InDegree() {
+ if in != len(g.AdjacencyList[n]) {
+ return false
+ }
+ }
+ return true
+}
+
+// Copy makes a deep copy of g.
+// Copy also computes the arc size ma, the number of arcs.
+//
+// There are equivalent labeled and unlabeled versions of this method.
+func (g Directed) Copy() (c Directed, ma int) {
+ l, s := g.AdjacencyList.Copy()
+ return Directed{l}, s
+}
+
+// Cyclic determines if g contains a cycle, a non-empty path from a node
+// back to itself.
+//
+// Cyclic returns true if g contains at least one cycle. It also returns
+// an example of an arc involved in a cycle.
+// Cyclic returns false if g is acyclic.
+//
+// Also see Topological, which detects cycles.
+//
+// There are equivalent labeled and unlabeled versions of this method.
+func (g Directed) Cyclic() (cyclic bool, fr NI, to NI) {
+ a := g.AdjacencyList
+ fr, to = -1, -1
+ var temp, perm Bits
+ var df func(NI)
+ df = func(n NI) {
+ switch {
+ case temp.Bit(n) == 1:
+ cyclic = true
+ return
+ case perm.Bit(n) == 1:
+ return
+ }
+ temp.SetBit(n, 1)
+ for _, nb := range a[n] {
+ df(nb)
+ if cyclic {
+ if fr < 0 {
+ fr, to = n, nb
+ }
+ return
+ }
+ }
+ temp.SetBit(n, 0)
+ perm.SetBit(n, 1)
+ }
+ for n := range a {
+ if perm.Bit(NI(n)) == 1 {
+ continue
+ }
+ if df(NI(n)); cyclic { // short circuit as soon as a cycle is found
+ break
+ }
+ }
+ return
+}
+
+// FromList transposes a labeled graph into a FromList.
+//
+// Receiver g should be connected as a tree or forest. Specifically no node
+// can have multiple incoming arcs. If any node n in g has multiple incoming
+// arcs, the method returns (nil, n) where n is a node with multiple
+// incoming arcs.
+//
+// Otherwise (normally) the method populates the From members in a
+// FromList.Path and returns the FromList and -1.
+//
+// Other members of the FromList are left as zero values.
+// Use FromList.RecalcLen and FromList.RecalcLeaves as needed.
+//
+// Unusual cases are parallel arcs and loops. A parallel arc represents
+// a case of multiple arcs going to some node and so will lead to a (nil, n)
+// return, even though a graph might be considered a multigraph tree.
+// A single loop on a node that would otherwise be a root node, though,
+// is not a case of multiple incoming arcs and so does not force a (nil, n)
+// result.
+//
+// There are equivalent labeled and unlabeled versions of this method.
+func (g Directed) FromList() (*FromList, NI) {
+ paths := make([]PathEnd, len(g.AdjacencyList))
+ for i := range paths {
+ paths[i].From = -1
+ }
+ for fr, to := range g.AdjacencyList {
+ for _, to := range to {
+ if paths[to].From >= 0 {
+ return nil, to
+ }
+ paths[to].From = NI(fr)
+ }
+ }
+ return &FromList{Paths: paths}, -1
+}
+
+// InDegree computes the in-degree of each node in g
+//
+// There are equivalent labeled and unlabeled versions of this method.
+func (g Directed) InDegree() []int {
+ ind := make([]int, len(g.AdjacencyList))
+ for _, nbs := range g.AdjacencyList {
+ for _, nb := range nbs {
+ ind[nb]++
+ }
+ }
+ return ind
+}
+
+// IsTree identifies trees in directed graphs.
+//
+// Return value isTree is true if the subgraph reachable from root is a tree.
+// Further, return value allTree is true if the entire graph g is reachable
+// from root.
+//
+// There are equivalent labeled and unlabeled versions of this method.
+func (g Directed) IsTree(root NI) (isTree, allTree bool) {
+ a := g.AdjacencyList
+ var v Bits
+ v.SetAll(len(a))
+ var df func(NI) bool
+ df = func(n NI) bool {
+ if v.Bit(n) == 0 {
+ return false
+ }
+ v.SetBit(n, 0)
+ for _, to := range a[n] {
+ if !df(to) {
+ return false
+ }
+ }
+ return true
+ }
+ isTree = df(root)
+ return isTree, isTree && v.Zero()
+}
+
+// Tarjan identifies strongly connected components in a directed graph using
+// Tarjan's algorithm.
+//
+// The method calls the emit argument for each component identified. Each
+// component is a list of nodes. A property of the algorithm is that
+// components are emitted in reverse topological order of the condensation.
+// (See https://en.wikipedia.org/wiki/Strongly_connected_component#Definitions
+// for description of condensation.)
+//
+// There are equivalent labeled and unlabeled versions of this method.
+//
+// See also TarjanForward and TarjanCondensation.
+func (g Directed) Tarjan(emit func([]NI) bool) {
+ // See "Depth-first search and linear graph algorithms", Robert Tarjan,
+ // SIAM J. Comput. Vol. 1, No. 2, June 1972.
+ //
+ // Implementation here from Wikipedia pseudocode,
+ // http://en.wikipedia.org/w/index.php?title=Tarjan%27s_strongly_connected_components_algorithm&direction=prev&oldid=647184742
+ var indexed, stacked Bits
+ a := g.AdjacencyList
+ index := make([]int, len(a))
+ lowlink := make([]int, len(a))
+ x := 0
+ var S []NI
+ var sc func(NI) bool
+ sc = func(n NI) bool {
+ index[n] = x
+ indexed.SetBit(n, 1)
+ lowlink[n] = x
+ x++
+ S = append(S, n)
+ stacked.SetBit(n, 1)
+ for _, nb := range a[n] {
+ if indexed.Bit(nb) == 0 {
+ if !sc(nb) {
+ return false
+ }
+ if lowlink[nb] < lowlink[n] {
+ lowlink[n] = lowlink[nb]
+ }
+ } else if stacked.Bit(nb) == 1 {
+ if index[nb] < lowlink[n] {
+ lowlink[n] = index[nb]
+ }
+ }
+ }
+ if lowlink[n] == index[n] {
+ var c []NI
+ for {
+ last := len(S) - 1
+ w := S[last]
+ S = S[:last]
+ stacked.SetBit(w, 0)
+ c = append(c, w)
+ if w == n {
+ if !emit(c) {
+ return false
+ }
+ break
+ }
+ }
+ }
+ return true
+ }
+ for n := range a {
+ if indexed.Bit(NI(n)) == 0 && !sc(NI(n)) {
+ return
+ }
+ }
+}
+
+// TarjanForward returns strongly connected components.
+//
+// It returns components in the reverse order of Tarjan, for situations
+// where a forward topological ordering is easier.
+func (g Directed) TarjanForward() [][]NI {
+ var r [][]NI
+ g.Tarjan(func(c []NI) bool {
+ r = append(r, c)
+ return true
+ })
+ scc := make([][]NI, len(r))
+ last := len(r) - 1
+ for i, ci := range r {
+ scc[last-i] = ci
+ }
+ return scc
+}
+
+// TarjanCondensation returns strongly connected components and their
+// condensation graph.
+//
+// Components are ordered in a forward topological ordering.
+func (g Directed) TarjanCondensation() (scc [][]NI, cd AdjacencyList) {
+ scc = g.TarjanForward()
+ cd = make(AdjacencyList, len(scc)) // return value
+ cond := make([]NI, len(g.AdjacencyList)) // mapping from g node to cd node
+ for cn := NI(len(scc) - 1); cn >= 0; cn-- {
+ c := scc[cn]
+ for _, n := range c {
+ cond[n] = NI(cn) // map g node to cd node
+ }
+ var tos []NI // list of 'to' nodes
+ var m Bits // tos map
+ m.SetBit(cn, 1)
+ for _, n := range c {
+ for _, to := range g.AdjacencyList[n] {
+ if ct := cond[to]; m.Bit(ct) == 0 {
+ m.SetBit(ct, 1)
+ tos = append(tos, ct)
+ }
+ }
+ }
+ cd[cn] = tos
+ }
+ return
+}
+
+// Topological computes a topological ordering of a directed acyclic graph.
+//
+// For an acyclic graph, return value ordering is a permutation of node numbers
+// in topologically sorted order and cycle will be nil. If the graph is found
+// to be cyclic, ordering will be nil and cycle will be the path of a found
+// cycle.
+//
+// There are equivalent labeled and unlabeled versions of this method.
+func (g Directed) Topological() (ordering, cycle []NI) {
+ a := g.AdjacencyList
+ ordering = make([]NI, len(a))
+ i := len(ordering)
+ var temp, perm Bits
+ var cycleFound bool
+ var cycleStart NI
+ var df func(NI)
+ df = func(n NI) {
+ switch {
+ case temp.Bit(n) == 1:
+ cycleFound = true
+ cycleStart = n
+ return
+ case perm.Bit(n) == 1:
+ return
+ }
+ temp.SetBit(n, 1)
+ for _, nb := range a[n] {
+ df(nb)
+ if cycleFound {
+ if cycleStart >= 0 {
+ // a little hack: orderng won't be needed so repurpose the
+ // slice as cycle. this is read out in reverse order
+ // as the recursion unwinds.
+ x := len(ordering) - 1 - len(cycle)
+ ordering[x] = n
+ cycle = ordering[x:]
+ if n == cycleStart {
+ cycleStart = -1
+ }
+ }
+ return
+ }
+ }
+ temp.SetBit(n, 0)
+ perm.SetBit(n, 1)
+ i--
+ ordering[i] = n
+ }
+ for n := range a {
+ if perm.Bit(NI(n)) == 1 {
+ continue
+ }
+ df(NI(n))
+ if cycleFound {
+ return nil, cycle
+ }
+ }
+ return ordering, nil
+}
+
+// TopologicalKahn computes a topological ordering of a directed acyclic graph.
+//
+// For an acyclic graph, return value ordering is a permutation of node numbers
+// in topologically sorted order and cycle will be nil. If the graph is found
+// to be cyclic, ordering will be nil and cycle will be the path of a found
+// cycle.
+//
+// This function is based on the algorithm by Arthur Kahn and requires the
+// transpose of g be passed as the argument.
+//
+// There are equivalent labeled and unlabeled versions of this method.
+func (g Directed) TopologicalKahn(tr Directed) (ordering, cycle []NI) {
+ // code follows Wikipedia pseudocode.
+ var L, S []NI
+ // rem for "remaining edges," this function makes a local copy of the
+ // in-degrees and consumes that instead of consuming an input.
+ rem := make([]int, len(g.AdjacencyList))
+ for n, fr := range tr.AdjacencyList {
+ if len(fr) == 0 {
+ // accumulate "set of all nodes with no incoming edges"
+ S = append(S, NI(n))
+ } else {
+ // initialize rem from in-degree
+ rem[n] = len(fr)
+ }
+ }
+ for len(S) > 0 {
+ last := len(S) - 1 // "remove a node n from S"
+ n := S[last]
+ S = S[:last]
+ L = append(L, n) // "add n to tail of L"
+ for _, m := range g.AdjacencyList[n] {
+ // WP pseudo code reads "for each node m..." but it means for each
+ // node m *remaining in the graph.* We consume rem rather than
+ // the graph, so "remaining in the graph" for us means rem[m] > 0.
+ if rem[m] > 0 {
+ rem[m]-- // "remove edge from the graph"
+ if rem[m] == 0 { // if "m has no other incoming edges"
+ S = append(S, m) // "insert m into S"
+ }
+ }
+ }
+ }
+ // "If graph has edges," for us means a value in rem is > 0.
+ for c, in := range rem {
+ if in > 0 {
+ // recover cyclic nodes
+ for _, nb := range g.AdjacencyList[c] {
+ if rem[nb] > 0 {
+ cycle = append(cycle, NI(c))
+ break
+ }
+ }
+ }
+ }
+ if len(cycle) > 0 {
+ return nil, cycle
+ }
+ return L, nil
+}