123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- // 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
- }
|