aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/soniakeys/graph/undir.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/soniakeys/graph/undir.go')
-rw-r--r--vendor/github.com/soniakeys/graph/undir.go321
1 files changed, 321 insertions, 0 deletions
diff --git a/vendor/github.com/soniakeys/graph/undir.go b/vendor/github.com/soniakeys/graph/undir.go
new file mode 100644
index 0000000..75a7f24
--- /dev/null
+++ b/vendor/github.com/soniakeys/graph/undir.go
@@ -0,0 +1,321 @@
+// Copyright 2014 Sonia Keys
+// License MIT: http://opensource.org/licenses/MIT
+
+package graph
+
+// undir.go has methods specific to undirected graphs, Undirected and
+// LabeledUndirected.
+
+import "errors"
+
+// AddEdge adds an edge to a graph.
+//
+// It can be useful for constructing undirected graphs.
+//
+// When n1 and n2 are distinct, it adds the arc n1->n2 and the reciprocal
+// n2->n1. When n1 and n2 are the same, it adds a single arc loop.
+//
+// The pointer receiver allows the method to expand the graph as needed
+// to include the values n1 and n2. If n1 or n2 happen to be greater than
+// len(*p) the method does not panic, but simply expands the graph.
+func (p *Undirected) AddEdge(n1, n2 NI) {
+ // Similar code in LabeledAdjacencyList.AddEdge.
+
+ // determine max of the two end points
+ max := n1
+ if n2 > max {
+ max = n2
+ }
+ // expand graph if needed, to include both
+ g := p.AdjacencyList
+ if int(max) >= len(g) {
+ p.AdjacencyList = make(AdjacencyList, max+1)
+ copy(p.AdjacencyList, g)
+ g = p.AdjacencyList
+ }
+ // create one half-arc,
+ g[n1] = append(g[n1], n2)
+ // and except for loops, create the reciprocal
+ if n1 != n2 {
+ g[n2] = append(g[n2], n1)
+ }
+}
+
+// EulerianCycleD for undirected graphs is a bit of an experiment.
+//
+// It is about the same as the directed version, but modified for an undirected
+// multigraph.
+//
+// Parameter m in this case must be the size of the undirected graph -- the
+// number of edges. Use Undirected.Size if the size is unknown.
+//
+// It works, but contains an extra loop that I think spoils the time
+// complexity. Probably still pretty fast in practice, but a different
+// graph representation might be better.
+func (g Undirected) EulerianCycleD(m int) ([]NI, error) {
+ if len(g.AdjacencyList) == 0 {
+ return nil, nil
+ }
+ e := newEulerian(g.AdjacencyList, m)
+ for e.s >= 0 {
+ v := e.top()
+ e.pushUndir() // call modified method
+ 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
+}
+
+// TarjanBiconnectedComponents decomposes a graph into maximal biconnected
+// components, components for which if any node were removed the component
+// would remain connected.
+//
+// The receiver g must be a simple graph. The method calls the emit argument
+// for each component identified, as long as emit returns true. If emit
+// returns false, TarjanBiconnectedComponents returns immediately.
+//
+// See also the eqivalent labeled TarjanBiconnectedComponents.
+func (g Undirected) TarjanBiconnectedComponents(emit func([]Edge) bool) {
+ // Implemented closely to pseudocode in "Depth-first search and linear
+ // graph algorithms", Robert Tarjan, SIAM J. Comput. Vol. 1, No. 2,
+ // June 1972.
+ //
+ // Note Tarjan's "adjacency structure" is graph.AdjacencyList,
+ // His "adjacency list" is an element of a graph.AdjacencyList, also
+ // termed a "to-list", "neighbor list", or "child list."
+ number := make([]int, len(g.AdjacencyList))
+ lowpt := make([]int, len(g.AdjacencyList))
+ var stack []Edge
+ var i int
+ var biconnect func(NI, NI) bool
+ biconnect = func(v, u NI) bool {
+ i++
+ number[v] = i
+ lowpt[v] = i
+ for _, w := range g.AdjacencyList[v] {
+ if number[w] == 0 {
+ stack = append(stack, Edge{v, w})
+ if !biconnect(w, v) {
+ return false
+ }
+ if lowpt[w] < lowpt[v] {
+ lowpt[v] = lowpt[w]
+ }
+ if lowpt[w] >= number[v] {
+ var bcc []Edge
+ top := len(stack) - 1
+ for number[stack[top].N1] >= number[w] {
+ bcc = append(bcc, stack[top])
+ stack = stack[:top]
+ top--
+ }
+ bcc = append(bcc, stack[top])
+ stack = stack[:top]
+ top--
+ if !emit(bcc) {
+ return false
+ }
+ }
+ } else if number[w] < number[v] && w != u {
+ stack = append(stack, Edge{v, w})
+ if number[w] < lowpt[v] {
+ lowpt[v] = number[w]
+ }
+ }
+ }
+ return true
+ }
+ for w := range g.AdjacencyList {
+ if number[w] == 0 && !biconnect(NI(w), 0) {
+ return
+ }
+ }
+}
+
+/* half-baked. Read the 72 paper. Maybe revisit at some point.
+type BiconnectedComponents struct {
+ Graph AdjacencyList
+ Start int
+ Cuts big.Int // bitmap of node cuts
+ From []int // from-tree
+ Leaves []int // leaves of from-tree
+}
+
+func NewBiconnectedComponents(g Undirected) *BiconnectedComponents {
+ return &BiconnectedComponents{
+ Graph: g,
+ From: make([]int, len(g)),
+ }
+}
+
+func (b *BiconnectedComponents) Find(start int) {
+ g := b.Graph
+ depth := make([]int, len(g))
+ low := make([]int, len(g))
+ // reset from any previous run
+ b.Cuts.SetInt64(0)
+ bf := b.From
+ for n := range bf {
+ bf[n] = -1
+ }
+ b.Leaves = b.Leaves[:0]
+ d := 1 // depth. d > 0 means visited
+ depth[start] = d
+ low[start] = d
+ d++
+ var df func(int, int)
+ df = func(from, n int) {
+ bf[n] = from
+ depth[n] = d
+ dn := d
+ l := d
+ d++
+ cut := false
+ leaf := true
+ for _, nb := range g[n] {
+ if depth[nb] == 0 {
+ leaf = false
+ df(n, nb)
+ if low[nb] < l {
+ l = low[nb]
+ }
+ if low[nb] >= dn {
+ cut = true
+ }
+ } else if nb != from && depth[nb] < l {
+ l = depth[nb]
+ }
+ }
+ low[n] = l
+ if cut {
+ b.Cuts.SetBit(&b.Cuts, n, 1)
+ }
+ if leaf {
+ b.Leaves = append(b.Leaves, n)
+ }
+ d--
+ }
+ nbs := g[start]
+ if len(nbs) == 0 {
+ return
+ }
+ df(start, nbs[0])
+ var rc uint
+ for _, nb := range nbs[1:] {
+ if depth[nb] == 0 {
+ rc = 1
+ df(start, nb)
+ }
+ }
+ b.Cuts.SetBit(&b.Cuts, start, rc)
+ return
+}
+*/
+
+// AddEdge adds an edge to a labeled graph.
+//
+// It can be useful for constructing undirected graphs.
+//
+// When n1 and n2 are distinct, it adds the arc n1->n2 and the reciprocal
+// n2->n1. When n1 and n2 are the same, it adds a single arc loop.
+//
+// If the edge already exists in *p, a parallel edge is added.
+//
+// The pointer receiver allows the method to expand the graph as needed
+// to include the values n1 and n2. If n1 or n2 happen to be greater than
+// len(*p) the method does not panic, but simply expands the graph.
+func (p *LabeledUndirected) AddEdge(e Edge, l LI) {
+ // Similar code in AdjacencyList.AddEdge.
+
+ // determine max of the two end points
+ max := e.N1
+ if e.N2 > max {
+ max = e.N2
+ }
+ // expand graph if needed, to include both
+ g := p.LabeledAdjacencyList
+ if max >= NI(len(g)) {
+ p.LabeledAdjacencyList = make(LabeledAdjacencyList, max+1)
+ copy(p.LabeledAdjacencyList, g)
+ g = p.LabeledAdjacencyList
+ }
+ // create one half-arc,
+ g[e.N1] = append(g[e.N1], Half{To: e.N2, Label: l})
+ // and except for loops, create the reciprocal
+ if e.N1 != e.N2 {
+ g[e.N2] = append(g[e.N2], Half{To: e.N1, Label: l})
+ }
+}
+
+// TarjanBiconnectedComponents decomposes a graph into maximal biconnected
+// components, components for which if any node were removed the component
+// would remain connected.
+//
+// The receiver g must be a simple graph. The method calls the emit argument
+// for each component identified, as long as emit returns true. If emit
+// returns false, TarjanBiconnectedComponents returns immediately.
+//
+// See also the eqivalent unlabeled TarjanBiconnectedComponents.
+func (g LabeledUndirected) TarjanBiconnectedComponents(emit func([]LabeledEdge) bool) {
+ // Implemented closely to pseudocode in "Depth-first search and linear
+ // graph algorithms", Robert Tarjan, SIAM J. Comput. Vol. 1, No. 2,
+ // June 1972.
+ //
+ // Note Tarjan's "adjacency structure" is graph.AdjacencyList,
+ // His "adjacency list" is an element of a graph.AdjacencyList, also
+ // termed a "to-list", "neighbor list", or "child list."
+ //
+ // Nearly identical code in undir.go.
+ number := make([]int, len(g.LabeledAdjacencyList))
+ lowpt := make([]int, len(g.LabeledAdjacencyList))
+ var stack []LabeledEdge
+ var i int
+ var biconnect func(NI, NI) bool
+ biconnect = func(v, u NI) bool {
+ i++
+ number[v] = i
+ lowpt[v] = i
+ for _, w := range g.LabeledAdjacencyList[v] {
+ if number[w.To] == 0 {
+ stack = append(stack, LabeledEdge{Edge{v, w.To}, w.Label})
+ if !biconnect(w.To, v) {
+ return false
+ }
+ if lowpt[w.To] < lowpt[v] {
+ lowpt[v] = lowpt[w.To]
+ }
+ if lowpt[w.To] >= number[v] {
+ var bcc []LabeledEdge
+ top := len(stack) - 1
+ for number[stack[top].N1] >= number[w.To] {
+ bcc = append(bcc, stack[top])
+ stack = stack[:top]
+ top--
+ }
+ bcc = append(bcc, stack[top])
+ stack = stack[:top]
+ top--
+ if !emit(bcc) {
+ return false
+ }
+ }
+ } else if number[w.To] < number[v] && w.To != u {
+ stack = append(stack, LabeledEdge{Edge{v, w.To}, w.Label})
+ if number[w.To] < lowpt[v] {
+ lowpt[v] = number[w.To]
+ }
+ }
+ }
+ return true
+ }
+ for w := range g.LabeledAdjacencyList {
+ if number[w] == 0 && !biconnect(NI(w), 0) {
+ return
+ }
+ }
+}