diff options
Diffstat (limited to 'vendor/github.com/soniakeys/graph/dir.go')
| -rw-r--r-- | vendor/github.com/soniakeys/graph/dir.go | 538 |
1 files changed, 0 insertions, 538 deletions
diff --git a/vendor/github.com/soniakeys/graph/dir.go b/vendor/github.com/soniakeys/graph/dir.go deleted file mode 100644 index 508306d..0000000 --- a/vendor/github.com/soniakeys/graph/dir.go +++ /dev/null @@ -1,538 +0,0 @@ -// Copyright 2014 Sonia Keys -// License MIT: http://opensource.org/licenses/MIT - -package graph - -// dir.go has methods specific to directed graphs, types Directed and -// LabeledDirected. -// -// Methods on Directed are first, with exported methods alphabetized. - -import "errors" - -// DAGMaxLenPath finds a maximum length path in a directed acyclic graph. -// -// Argument ordering must be a topological ordering of g. -func (g Directed) DAGMaxLenPath(ordering []NI) (path []NI) { - // dynamic programming. visit nodes in reverse order. for each, compute - // longest path as one plus longest of 'to' nodes. - // Visits each arc once. O(m). - // - // Similar code in label.go - var n NI - mlp := make([][]NI, len(g.AdjacencyList)) // index by node number - for i := len(ordering) - 1; i >= 0; i-- { - fr := ordering[i] // node number - to := g.AdjacencyList[fr] - if len(to) == 0 { - continue - } - mt := to[0] - for _, to := range to[1:] { - if len(mlp[to]) > len(mlp[mt]) { - mt = to - } - } - p := append([]NI{mt}, mlp[mt]...) - mlp[fr] = p - if len(p) > len(path) { - n = fr - path = p - } - } - return append([]NI{n}, path...) -} - -// EulerianCycle finds an Eulerian cycle in a directed multigraph. -// -// * If g has no nodes, result is nil, nil. -// -// * If g is Eulerian, result is an Eulerian cycle with err = nil. -// The cycle result is a list of nodes, where the first and last -// nodes are the same. -// -// * Otherwise, result is nil, error -// -// Internally, EulerianCycle copies the entire graph g. -// See EulerianCycleD for a more space efficient version. -func (g Directed) EulerianCycle() ([]NI, error) { - c, m := g.Copy() - return c.EulerianCycleD(m) -} - -// EulerianCycleD finds an Eulerian cycle in a directed multigraph. -// -// EulerianCycleD is destructive on its receiver g. See EulerianCycle for -// a non-destructive version. -// -// Argument ma must be the correct arc size, or number of arcs in g. -// -// * If g has no nodes, result is nil, nil. -// -// * If g is Eulerian, result is an Eulerian cycle with err = nil. -// The cycle result is a list of nodes, where the first and last -// nodes are the same. -// -// * Otherwise, result is nil, error -func (g Directed) EulerianCycleD(ma int) ([]NI, error) { - if len(g.AdjacencyList) == 0 { - return nil, nil - } - e := newEulerian(g.AdjacencyList, ma) - for e.s >= 0 { - v := e.top() // v is node that starts cycle - e.push() - // if Eulerian, we'll always come back to starting node - if e.top() != v { - return nil, errors.New("not balanced") - } - e.keep() - } - if !e.uv.Zero() { - return nil, errors.New("not strongly connected") - } - return e.p, nil -} - -// EulerianPath finds an Eulerian path in a directed multigraph. -// -// * If g has no nodes, result is nil, nil. -// -// * If g has an Eulerian path, result is an Eulerian path with err = nil. -// The path result is a list of nodes, where the first node is start. -// -// * Otherwise, result is nil, error -// -// Internally, EulerianPath copies the entire graph g. -// See EulerianPathD for a more space efficient version. -func (g Directed) EulerianPath() ([]NI, error) { - ind := g.InDegree() - var start NI - for n, to := range g.AdjacencyList { - if len(to) > ind[n] { - start = NI(n) - break - } - } - c, m := g.Copy() - return c.EulerianPathD(m, start) -} - -// EulerianPathD finds an Eulerian path in a directed multigraph. -// -// EulerianPathD is destructive on its receiver g. See EulerianPath for -// a non-destructive version. -// -// Argument ma must be the correct arc size, or number of arcs in g. -// Argument start must be a valid start node for the path. -// -// * If g has no nodes, result is nil, nil. -// -// * If g has an Eulerian path, result is an Eulerian path with err = nil. -// The path result is a list of nodes, where the first node is start. -// -// * Otherwise, result is nil, error -func (g Directed) EulerianPathD(ma int, start NI) ([]NI, error) { - if len(g.AdjacencyList) == 0 { - return nil, nil - } - e := newEulerian(g.AdjacencyList, ma) - e.p[0] = start - // unlike EulerianCycle, the first path doesn't have be a cycle. - e.push() - e.keep() - for e.s >= 0 { - start = e.top() - e.push() - // paths after the first must be cycles though - // (as long as there are nodes on the stack) - if e.top() != start { - return nil, errors.New("no Eulerian path") - } - e.keep() - } - if !e.uv.Zero() { - return nil, errors.New("no Eulerian path") - } - return e.p, nil -} - -// starting at the node on the top of the stack, follow arcs until stuck. -// mark nodes visited, push nodes on stack, remove arcs from g. -func (e *eulerian) push() { - for u := e.top(); ; { - e.uv.SetBit(u, 0) // reset unvisited bit - arcs := e.g[u] - if len(arcs) == 0 { - return // stuck - } - w := arcs[0] // follow first arc - e.s++ // push followed node on stack - e.p[e.s] = w - e.g[u] = arcs[1:] // consume arc - u = w - } -} - -// like push, but for for undirected graphs. -func (e *eulerian) pushUndir() { - for u := e.top(); ; { - e.uv.SetBit(u, 0) - arcs := e.g[u] - if len(arcs) == 0 { - return - } - w := arcs[0] - e.s++ - e.p[e.s] = w - e.g[u] = arcs[1:] // consume arc - // here is the only difference, consume reciprocal arc as well: - a2 := e.g[w] - for x, rx := range a2 { - if rx == u { // here it is - last := len(a2) - 1 - a2[x] = a2[last] // someone else gets the seat - e.g[w] = a2[:last] // and it's gone. - break - } - } - u = w - } -} - -// starting with the node on top of the stack, move nodes with no arcs. -func (e *eulerian) keep() { - for e.s >= 0 { - n := e.top() - if len(e.g[n]) > 0 { - break - } - e.p[e.m] = n - e.s-- - e.m-- - } -} - -type eulerian struct { - g AdjacencyList // working copy of graph, it gets consumed - m int // number of arcs in g, updated as g is consumed - uv Bits // unvisited - // low end of p is stack of unfinished nodes - // high end is finished path - p []NI // stack + path - s int // stack pointer -} - -func (e *eulerian) top() NI { - return e.p[e.s] -} - -func newEulerian(g AdjacencyList, m int) *eulerian { - e := &eulerian{ - g: g, - m: m, - p: make([]NI, m+1), - } - e.uv.SetAll(len(g)) - return e -} - -// MaximalNonBranchingPaths finds all paths in a directed graph that are -// "maximal" and "non-branching". -// -// A non-branching path is one where path nodes other than the first and last -// have exactly one arc leading to the node and one arc leading from the node, -// thus there is no possibility to branch away to a different path. -// -// A maximal non-branching path cannot be extended to a longer non-branching -// path by including another node at either end. -// -// In the case of a cyclic non-branching path, the first and last elements -// of the path will be the same node, indicating an isolated cycle. -// -// The method calls the emit argument for each path or isolated cycle in g, -// as long as emit returns true. If emit returns false, -// MaximalNonBranchingPaths returns immediately. -func (g Directed) MaximalNonBranchingPaths(emit func([]NI) bool) { - ind := g.InDegree() - var uv Bits - uv.SetAll(len(g.AdjacencyList)) - for v, vTo := range g.AdjacencyList { - if !(ind[v] == 1 && len(vTo) == 1) { - for _, w := range vTo { - n := []NI{NI(v), w} - uv.SetBit(NI(v), 0) - uv.SetBit(w, 0) - wTo := g.AdjacencyList[w] - for ind[w] == 1 && len(wTo) == 1 { - u := wTo[0] - n = append(n, u) - uv.SetBit(u, 0) - w = u - wTo = g.AdjacencyList[w] - } - if !emit(n) { // n is a path - return - } - } - } - } - // use uv.From rather than uv.Iterate. - // Iterate doesn't work here because we're modifying uv - for b := uv.From(0); b >= 0; b = uv.From(b + 1) { - v := NI(b) - n := []NI{v} - for w := v; ; { - w = g.AdjacencyList[w][0] - uv.SetBit(w, 0) - n = append(n, w) - if w == v { - break - } - } - if !emit(n) { // n is an isolated cycle - return - } - } -} - -// Undirected returns copy of g augmented as needed to make it undirected. -func (g Directed) Undirected() Undirected { - c, _ := g.AdjacencyList.Copy() // start with a copy - rw := make(AdjacencyList, len(g.AdjacencyList)) // "reciprocals wanted" - for fr, to := range g.AdjacencyList { - arc: // for each arc in g - for _, to := range to { - if to == NI(fr) { - continue // loop - } - // search wanted arcs - wf := rw[fr] - for i, w := range wf { - if w == to { // found, remove - last := len(wf) - 1 - wf[i] = wf[last] - rw[fr] = wf[:last] - continue arc - } - } - // arc not found, add to reciprocal to wanted list - rw[to] = append(rw[to], NI(fr)) - } - } - // add missing reciprocals - for fr, to := range rw { - c[fr] = append(c[fr], to...) - } - return Undirected{c} -} - -// StronglyConnectedComponents identifies strongly connected components -// in a directed graph. -// -// Algorithm by David J. Pearce, from "An Improved Algorithm for Finding the -// Strongly Connected Components of a Directed Graph". It is algorithm 3, -// PEA_FIND_SCC2 in -// http://homepages.mcs.vuw.ac.nz/~djp/files/P05.pdf, accessed 22 Feb 2015. -// -// Returned is a list of components, each component is a list of nodes. -/* -func (g Directed) StronglyConnectedComponents() []int { - rindex := make([]int, len(g)) - S := []int{} - index := 1 - c := len(g) - 1 - visit := func(v int) { - root := true - rindex[v] = index - index++ - for _, w := range g[v] { - if rindex[w] == 0 { - visit(w) - } - if rindex[w] < rindex[v] { - rindex[v] = rindex[w] - root = false - } - } - if root { - index-- - for top := len(S) - 1; top >= 0 && rindex[v] <= rindex[top]; top-- { - w = rindex[top] - S = S[:top] - rindex[w] = c - index-- - } - rindex[v] = c - c-- - } else { - S = append(S, v) - } - } - for v := range g { - if rindex[v] == 0 { - visit(v) - } - } - return rindex -} -*/ - -// Transpose constructs a new adjacency list with all arcs reversed. -// -// For every arc from->to of g, the result will have an arc to->from. -// Transpose also counts arcs as it traverses and returns ma the number of arcs -// in g (equal to the number of arcs in the result.) -func (g Directed) Transpose() (t Directed, ma int) { - ta := make(AdjacencyList, len(g.AdjacencyList)) - for n, nbs := range g.AdjacencyList { - for _, nb := range nbs { - ta[nb] = append(ta[nb], NI(n)) - ma++ - } - } - return Directed{ta}, ma -} - -// DAGMaxLenPath finds a maximum length path in a directed acyclic graph. -// -// Length here means number of nodes or arcs, not a sum of arc weights. -// -// Argument ordering must be a topological ordering of g. -// -// Returned is a node beginning a maximum length path, and a path of arcs -// starting from that node. -func (g LabeledDirected) DAGMaxLenPath(ordering []NI) (n NI, path []Half) { - // dynamic programming. visit nodes in reverse order. for each, compute - // longest path as one plus longest of 'to' nodes. - // Visits each arc once. Time complexity O(m). - // - // Similar code in dir.go. - mlp := make([][]Half, len(g.LabeledAdjacencyList)) // index by node number - for i := len(ordering) - 1; i >= 0; i-- { - fr := ordering[i] // node number - to := g.LabeledAdjacencyList[fr] - if len(to) == 0 { - continue - } - mt := to[0] - for _, to := range to[1:] { - if len(mlp[to.To]) > len(mlp[mt.To]) { - mt = to - } - } - p := append([]Half{mt}, mlp[mt.To]...) - mlp[fr] = p - if len(p) > len(path) { - n = fr - path = p - } - } - return -} - -// FromListLabels transposes a labeled graph into a FromList and associated -// list of labels. -// -// 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, nil, n) where n is a node with multiple -// incoming arcs. -// -// Otherwise (normally) the method populates the From members in a -// FromList.Path, populates a slice of labels, and returns the FromList, -// labels, and -1. -// -// Other members of the FromList are left as zero values. -// Use FromList.RecalcLen and FromList.RecalcLeaves as needed. -func (g LabeledDirected) FromListLabels() (*FromList, []LI, NI) { - labels := make([]LI, len(g.LabeledAdjacencyList)) - paths := make([]PathEnd, len(g.LabeledAdjacencyList)) - for i := range paths { - paths[i].From = -1 - } - for fr, to := range g.LabeledAdjacencyList { - for _, to := range to { - if paths[to.To].From >= 0 { - return nil, nil, to.To - } - paths[to.To].From = NI(fr) - labels[to.To] = to.Label - } - } - return &FromList{Paths: paths}, labels, -1 -} - -// Transpose constructs a new adjacency list that is the transpose of g. -// -// For every arc from->to of g, the result will have an arc to->from. -// Transpose also counts arcs as it traverses and returns ma the number of -// arcs in g (equal to the number of arcs in the result.) -func (g LabeledDirected) Transpose() (t LabeledDirected, ma int) { - ta := make(LabeledAdjacencyList, len(g.LabeledAdjacencyList)) - for n, nbs := range g.LabeledAdjacencyList { - for _, nb := range nbs { - ta[nb.To] = append(ta[nb.To], Half{To: NI(n), Label: nb.Label}) - ma++ - } - } - return LabeledDirected{ta}, ma -} - -// Undirected returns a new undirected graph derived from g, augmented as -// needed to make it undirected, with reciprocal arcs having matching labels. -func (g LabeledDirected) Undirected() LabeledUndirected { - c, _ := g.LabeledAdjacencyList.Copy() // start with a copy - // "reciprocals wanted" - rw := make(LabeledAdjacencyList, len(g.LabeledAdjacencyList)) - for fr, to := range g.LabeledAdjacencyList { - arc: // for each arc in g - for _, to := range to { - if to.To == NI(fr) { - continue // arc is a loop - } - // search wanted arcs - wf := rw[fr] - for i, w := range wf { - if w == to { // found, remove - last := len(wf) - 1 - wf[i] = wf[last] - rw[fr] = wf[:last] - continue arc - } - } - // arc not found, add to reciprocal to wanted list - rw[to.To] = append(rw[to.To], Half{To: NI(fr), Label: to.Label}) - } - } - // add missing reciprocals - for fr, to := range rw { - c[fr] = append(c[fr], to...) - } - return LabeledUndirected{c} -} - -// Unlabeled constructs the unlabeled directed graph corresponding to g. -func (g LabeledDirected) Unlabeled() Directed { - return Directed{g.LabeledAdjacencyList.Unlabeled()} -} - -// UnlabeledTranspose constructs a new adjacency list that is the unlabeled -// transpose of g. -// -// For every arc from->to of g, the result will have an arc to->from. -// Transpose also counts arcs as it traverses and returns ma, the number of -// arcs in g (equal to the number of arcs in the result.) -// -// It is equivalent to g.Unlabeled().Transpose() but constructs the result -// directly. -func (g LabeledDirected) UnlabeledTranspose() (t Directed, ma int) { - ta := make(AdjacencyList, len(g.LabeledAdjacencyList)) - for n, nbs := range g.LabeledAdjacencyList { - for _, nb := range nbs { - ta[nb.To] = append(ta[nb.To], NI(n)) - ma++ - } - } - return Directed{ta}, ma -} |
