act/vendor/github.com/soniakeys/graph/dir.go

1060 lines
27 KiB
Go
Raw Normal View History

// Copyright 2014 Sonia Keys
// License MIT: http://opensource.org/licenses/MIT
package graph
import (
"math"
)
// dir.go has methods specific to directed graphs, types Directed and
// LabeledDirected, also Dominators.
//
// Methods on Directed are first, with exported methods alphabetized.
// Dominators type and methods are at the end.
//----------------------------
// Cycles emits all elementary cycles in a directed graph.
//
// The algorithm here is Johnson's. See also the equivalent but generally
// slower alt.TarjanCycles.
func (g Directed) Cycles(emit func([]NI) bool) {
// Johnsons "Finding all the elementary circuits of a directed graph",
// SIAM J. Comput. Vol. 4, No. 1, March 1975.
a := g.AdjacencyList
k := make(AdjacencyList, len(a))
B := make([]map[NI]bool, len(a))
blocked := make([]bool, len(a))
for i := range a {
blocked[i] = true
B[i] = map[NI]bool{}
}
var s NI
var stack []NI
var unblock func(NI)
unblock = func(u NI) {
blocked[u] = false
for w := range B[u] {
delete(B[u], w)
if blocked[w] {
unblock(w)
}
}
}
var circuit func(NI) (bool, bool)
circuit = func(v NI) (found, ok bool) {
f := false
stack = append(stack, v)
blocked[v] = true
for _, w := range k[v] {
if w == s {
if !emit(stack) {
return
}
f = true
} else if !blocked[w] {
switch found, ok = circuit(w); {
case !ok:
return
case found:
f = true
}
}
}
if f {
unblock(v)
} else {
for _, w := range k[v] {
B[w][v] = true
}
}
stack = stack[:len(stack)-1]
return f, true
}
for s = 0; int(s) < len(a); s++ {
// (so there's a little extra n^2 component introduced here that
// comes from not making a proper subgraph but just removing arcs
// and leaving isolated nodes. Iterating over the isolated nodes
// should be very fast though. It seems like it would be a net win
// over creating a subgraph.)
// shallow subgraph
for z := NI(0); z < s; z++ {
k[z] = nil
}
for z := int(s); z < len(a); z++ {
k[z] = a[z]
}
// find scc in k with s
var scc []NI
Directed{k}.StronglyConnectedComponents(func(c []NI) bool {
for _, n := range c {
if n == s { // this is it
scc = c
return false // stop scc search
}
}
return true // keep looking
})
// clear k
for n := range k {
k[n] = nil
}
// map component
for _, n := range scc {
blocked[n] = false
}
// copy component to k
for _, fr := range scc {
var kt []NI
for _, to := range a[fr] {
if !blocked[to] {
kt = append(kt, to)
}
}
k[fr] = kt
}
if _, ok := circuit(s); !ok {
return
}
// reblock component
for _, n := range scc {
blocked[n] = true
}
}
}
// 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, g.Order()) // 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...)
}
// FromList creates a spanning forest of a graph.
//
// The method populates the From members in f.Paths and returns the FromList.
// Also returned is a bool, true if the receiver is found to be a simple graph
// representing a tree or forest. Loops, or any case of multiple arcs going to
// a node will cause simpleForest to be false.
//
// The FromList return value f will always be a spanning forest of the entire
// graph. The bool return value simpleForest tells if the receiver graph g
// was a simple forest to begin with.
//
// Other members of the FromList are left as zero values.
// Use FromList.RecalcLen and FromList.RecalcLeaves as needed.
func (g Directed) FromList() (f *FromList, simpleForest bool) {
paths := make([]PathEnd, g.Order())
for i := range paths {
paths[i].From = -1
}
simpleForest = true
for fr, to := range g.AdjacencyList {
for _, to := range to {
if int(to) == fr || paths[to].From >= 0 {
simpleForest = false
} else {
paths[to].From = NI(fr)
}
}
}
return &FromList{Paths: paths}, simpleForest
}
// SpanTree builds a tree spanning nodes reachable from the given root.
//
// The component is spanned by breadth-first search from root.
// The resulting spanning tree in stored a FromList.
//
// If FromList.Paths is not the same length as g, it is allocated and
// initialized. This allows a zero value FromList to be passed as f.
// If FromList.Paths is the same length as g, it is used as is and is not
// reinitialized. This allows multiple trees to be spanned in the same
// FromList with successive calls.
//
// For nodes spanned, the Path member of the returned FromList is populated
// with both From and Len values. The MaxLen member will be updated but
// not Leaves.
//
// Returned is the number of nodes spanned, which will be the number of nodes
// reachable from root, and a bool indicating if these nodes were found to be
// a simply connected tree in the receiver graph g. Any cycles, loops,
// or parallel arcs in the component will cause simpleTree to be false, but
// FromList f will still be populated with a valid spanning tree.
func (g Directed) SpanTree(root NI, f *FromList) (nSpanned int, simpleTree bool) {
a := g.AdjacencyList
p := f.Paths
if len(p) != len(a) {
p = make([]PathEnd, len(a))
for i := range p {
p[i].From = -1
}
f.Paths = p
}
simpleTree = true
p[root].Len = 1
type arc struct {
from, to NI
}
var next []arc
frontier := []arc{{-1, root}}
for len(frontier) > 0 {
for _, fa := range frontier { // fa frontier arc
nSpanned++
l := p[fa.to].Len + 1
for _, to := range a[fa.to] {
if p[to].Len > 0 {
simpleTree = false
continue
}
p[to] = PathEnd{From: fa.to, Len: l}
if l > f.MaxLen {
f.MaxLen = l
}
next = append(next, arc{fa.to, to})
}
}
frontier, next = next, frontier[:0]
}
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, g.Order()) // "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}
}
// 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, g.Order())
for n, nbs := range g.AdjacencyList {
for _, nb := range nbs {
ta[nb] = append(ta[nb], NI(n))
ma++
}
}
return Directed{ta}, ma
}
// Cycles emits all elementary cycles in a directed graph.
//
// The algorithm here is Johnson's. See also the equivalent but generally
// slower alt.TarjanCycles.
func (g LabeledDirected) Cycles(emit func([]Half) bool) {
a := g.LabeledAdjacencyList
k := make(LabeledAdjacencyList, len(a))
B := make([]map[NI]bool, len(a))
blocked := make([]bool, len(a))
for i := range a {
blocked[i] = true
B[i] = map[NI]bool{}
}
var s NI
var stack []Half
var unblock func(NI)
unblock = func(u NI) {
blocked[u] = false
for w := range B[u] {
delete(B[u], w)
if blocked[w] {
unblock(w)
}
}
}
var circuit func(NI) (bool, bool)
circuit = func(v NI) (found, ok bool) {
f := false
blocked[v] = true
for _, w := range k[v] {
if w.To == s {
if !emit(append(stack, w)) {
return
}
f = true
} else if !blocked[w.To] {
stack = append(stack, w)
switch found, ok = circuit(w.To); {
case !ok:
return
case found:
f = true
}
stack = stack[:len(stack)-1]
}
}
if f {
unblock(v)
} else {
for _, w := range k[v] {
B[w.To][v] = true
}
}
return f, true
}
for s = 0; int(s) < len(a); s++ {
for z := NI(0); z < s; z++ {
k[z] = nil
}
for z := int(s); z < len(a); z++ {
k[z] = a[z]
}
var scc []NI
LabeledDirected{k}.StronglyConnectedComponents(func(c []NI) bool {
for _, n := range c {
if n == s {
scc = c
return false
}
}
return true
})
for n := range k {
k[n] = nil
}
for _, n := range scc {
blocked[n] = false
}
for _, fr := range scc {
var kt []Half
for _, to := range a[fr] {
if !blocked[to.To] {
kt = append(kt, to)
}
}
k[fr] = kt
}
if _, ok := circuit(s); !ok {
return
}
for _, n := range scc {
blocked[n] = true
}
}
}
// 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, g.Order()) // 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
}
// FromList creates a spanning forest of a graph.
//
// The method populates the From members in f.Paths and returns the FromList.
// Also returned is a list of labels corresponding to the from arcs, and a
// bool, true if the receiver is found to be a simple graph representing
// a tree or forest. Loops, or any case of multiple arcs going to a node
// will cause simpleForest to be false.
//
// The FromList return value f will always be a spanning forest of the entire
// graph. The bool return value simpleForest tells if the receiver graph g
// was a simple forest to begin with.
//
// Other members of the FromList are left as zero values.
// Use FromList.RecalcLen and FromList.RecalcLeaves as needed.
func (g LabeledDirected) FromList() (f *FromList, labels []LI, simpleForest bool) {
labels = make([]LI, g.Order())
paths := make([]PathEnd, g.Order())
for i := range paths {
paths[i].From = -1
}
simpleForest = true
for fr, to := range g.LabeledAdjacencyList {
for _, to := range to {
if int(to.To) == fr || paths[to.To].From >= 0 {
simpleForest = false
} else {
paths[to.To].From = NI(fr)
labels[to.To] = to.Label
}
}
}
return &FromList{Paths: paths}, labels, simpleForest
}
// NegativeCycles emits all cycles with negative cycle distance.
//
// The emit function is called for each cycle found. Emit must return true
// to continue cycle enumeration. If emit returns false, NegativeCycles
// stops and returns immediately.
//
// The method mutates receiver g while it runs. Access to g before
// NegativeCycles returns, such as during the emit callback, will find
// g altered. G is completely restored when NegativeCycles returns however,
// even if terminated early with a false return from emit.
//
// If mutations on g are unacceptable, use g.Copy and run NegativeCycles on
// the copy.
//
// See also:
//
// * NegativeCycle, which finds a single example of a negative cycle if
// one exists.
//
// * HasNegativeCycle, which detects if a negative cycle exists.
//
// * BellmanFord, which also detects negative cycles.
//
// * Cycles, from which negative cycles can be filtered.
//
// * alt.NegativeCycles, which uses less memory but is generally slower.
func (g LabeledDirected) NegativeCycles(w WeightFunc, emit func([]Half) bool) {
// Implementation of "Finding all the negative cycles in a directed graph"
// by Takeo Yamada and Harunobu Kinoshita, Discrete Applied Mathematics
// 118 (2002) 279291.
newNegCyc(g, w, emit).all_nc(LabeledPath{})
}
type negCyc struct {
g LabeledDirected
w WeightFunc
emit func([]Half) bool
a LabeledAdjacencyList
tr AdjacencyList
d0, d1 []float64
dc []float64
bt [][]fromHalf
btLast []int
}
func newNegCyc(g LabeledDirected, w WeightFunc, emit func([]Half) bool) *negCyc {
nc := &negCyc{g: g, w: w, emit: emit}
nc.a = g.LabeledAdjacencyList
// transpose to make it easier to find from-arcs.
lt, _ := g.UnlabeledTranspose()
nc.tr = lt.AdjacencyList
nc.d0 = make([]float64, len(nc.a))
nc.d1 = make([]float64, len(nc.a))
nc.dc = make([]float64, len(nc.a))
nc.btLast = make([]int, len(nc.a))
nc.bt = make([][]fromHalf, len(nc.a))
for i := range nc.bt {
nc.bt[i] = make([]fromHalf, len(nc.a))
}
return nc
}
func (nc *negCyc) all_nc(F LabeledPath) bool {
var C []Half
var R LabeledPath
// Step 1
if len(F.Path) != 0 {
return nc.step2(F)
}
C = nc.g.NegativeCycle(nc.w)
if len(C) == 0 {
return true
}
// prep step 4 with no F:
F.Start = C[len(C)-1].To
R = LabeledPath{F.Start, C}
return nc.step4(C, F, R)
}
func (nc *negCyc) step2(F LabeledPath) bool {
fEnd := F.Path[len(F.Path)-1].To
wF := F.Distance(nc.w)
dL, πL := nc.zL(F, fEnd, wF)
if !(dL < 0) {
return true
}
if len(πL) > 0 {
C := append(F.Path, πL...)
R := LabeledPath{fEnd, πL}
return nc.step4(C, F, R)
}
return nc.step3(F, fEnd, wF)
}
func (nc *negCyc) step3(F LabeledPath, fEnd NI, wF float64) bool {
πΓ := nc.(F, wF)
if len(πΓ) > 0 {
// prep for step 4
C := append(F.Path, πΓ...)
R := LabeledPath{fEnd, πΓ}
return nc.step4(C, F, R)
}
return nc.step5(F, fEnd)
}
func (nc *negCyc) step4(C []Half, F, R LabeledPath) (ok bool) {
// C is a new cycle.
// F is fixed path to be extended and is a prefix of C.
// R is the remainder of C
if ok = nc.emit(C); !ok {
return
}
// for each arc in R, if not the first arc,
// extend F by the arc of the previous iteration.
// remove arc from g,
// Then make the recursive call, then put the arc back in g.
//
// after loop, replace arcs from the two stacks.
type frto struct {
fr NI
to []Half
}
var frStack [][]arc
var toStack []frto
var fr0 NI
var to0 Half
for i, h := range R.Path {
if i > 0 {
// extend F by arc {fr0 to0}, the arc of the previous iteration.
// Remove arcs to to0.To and save on stack.
// Remove arcs from arc0.fr and save on stack.
F.Path = append(F.Path, to0)
frStack = append(frStack, nc.cutTo(to0.To))
toStack = append(toStack, frto{fr0, nc.a[fr0]})
nc.a[fr0] = nil
}
toList := nc.a[R.Start]
for j, to := range toList {
if to == h {
last := len(toList) - 1
toList[j], toList[last] = toList[last], toList[j]
nc.a[R.Start] = toList[:last]
ok = nc.all_nc(F) // return value
toList[last], toList[j] = toList[j], toList[last]
nc.a[R.Start] = toList
break
}
}
if !ok {
break
}
fr0 = R.Start
to0 = h
R.Start = h.To
}
for i := len(frStack) - 1; i >= 0; i-- {
nc.a[toStack[i].fr] = toStack[i].to
nc.restore(frStack[i])
}
return
}
func (nc *negCyc) step5(F LabeledPath, fEnd NI) (ok bool) {
// Step 5 (uncertain case)
//
// For each arc from end of F, search each case of extending
// F by that arc.
//
// before loop: save arcs from current path end,
// replace them with room for a single arc.
// extend F by room for one more arc,
ok = true
save := nc.a[fEnd]
nc.a[fEnd] = []Half{{}}
last := len(F.Path)
F.Path = append(F.Path, Half{})
for _, h := range save {
// in each iteration, set the final arc in F, and the single
// outgoing arc, and save and clear all inbound arcs to the
// new end node. make recursive call, then restore saved
// inbound arcs for the node.
F.Path[last] = h
nc.a[fEnd][0] = h
save := nc.cutTo(h.To)
ok = nc.all_nc(F)
nc.restore(save)
if !ok {
break
}
}
// after loop, restore saved outgoing arcs in g.
nc.a[fEnd] = save
return
}
type arc struct {
n NI // node that had an arc cut from its toList
x int // index of arc that was swapped to the end of the list
}
// modify a cutting all arcs to node n. return list of cut arcs than
// can be processed in reverse order to restore changes to a
func (nc *negCyc) cutTo(n NI) (c []arc) {
for _, fr := range nc.tr[n] {
toList := nc.a[fr]
for x := 0; x < len(toList); {
to := toList[x]
if to.To == n {
c = append(c, arc{fr, x})
last := len(toList) - 1
toList[x], toList[last] = toList[last], toList[x]
toList = toList[:last]
} else {
x++
}
}
nc.a[fr] = toList
}
return
}
func (nc *negCyc) restore(c []arc) {
for i := len(c) - 1; i >= 0; i-- {
r := c[i]
toList := nc.a[r.n]
last := len(toList)
toList = toList[:last+1]
toList[r.x], toList[last] = toList[last], toList[r.x]
nc.a[r.n] = toList
}
}
func (nc *negCyc) zL(F LabeledPath, fEnd NI, wp float64) (float64, []Half) {
π, c, d := nc.πj(len(nc.a)-len(F.Path), F.Start, fEnd)
if c < 0 {
return d + wp, π
}
j := len(nc.a) - len(F.Path) - 1
// G1: cut arcs going to c
saveFr := nc.cutTo(c)
for k := 1; k <= j; k++ {
nc.dc[k] = nc.dj(k, F.Start, c)
}
// G0: also cut arcs coming from c
saveTo := nc.a[c]
nc.a[c] = nil
min := nc.dj(j, F.Start, fEnd)
// G2: restore arcs going to c
nc.restore(saveFr)
for k := 1; k <= j; k++ {
d1 := nc.dc[k] + nc.dj(j+1-k, c, fEnd)
if d1 < min {
min = d1
}
}
nc.a[c] = saveTo
return min + wp, nil
}
func (nc *negCyc) dj(j int, v, v0 NI) float64 {
for i := range nc.d0 {
nc.d0[i] = math.Inf(1)
}
nc.d0[v0] = 0
for ; j > 0; j-- {
for i, d := range nc.d0 {
nc.d1[i] = d
}
for vʹ, d0vʹ := range nc.d0 {
if d0vʹ < math.Inf(1) {
for _, to := range nc.a[vʹ] {
if sum := d0vʹ + nc.w(to.Label); sum < nc.d1[to.To] {
nc.d1[to.To] = sum
}
}
}
}
nc.d0, nc.d1 = nc.d1, nc.d0
}
return nc.d0[v]
}
func (nc *negCyc) πj(j int, v, v0 NI) ([]Half, NI, float64) {
for i := range nc.d0 {
nc.d0[i] = math.Inf(1)
nc.btLast[i] = -1
}
nc.d0[v0] = 0
for k := 0; k < j; k++ {
for i, d := range nc.d0 {
nc.d1[i] = d
}
btk := nc.bt[k]
for vʹ, d0vʹ := range nc.d0 {
if d0vʹ < math.Inf(1) {
for _, to := range nc.a[vʹ] {
if sum := d0vʹ + nc.w(to.Label); sum < nc.d1[to.To] {
nc.d1[to.To] = sum
btk[to.To] = fromHalf{NI(vʹ), to.Label}
nc.btLast[to.To] = k
}
}
}
}
nc.d0, nc.d1 = nc.d1, nc.d0
}
p := make([]Half, nc.btLast[v]+1)
m := map[NI]bool{}
c := NI(-1)
to := v
for k := nc.btLast[v]; k >= 0; k-- {
fh := nc.bt[k][to]
p[k] = Half{to, fh.Label}
to = fh.From
if c < 0 {
if m[to] {
c = to
} else {
m[to] = true
}
}
}
return p, c, nc.d0[v]
}
func (nc *negCyc) (F LabeledPath, wp float64) []Half {
p, d := nc.a.DijkstraPath(F.Path[len(F.Path)-1].To, F.Start, nc.w)
if !(wp+d < 0) {
return nil
}
return p.Path
}
// SpanTree builds a tree spanning nodes reachable from the given root.
//
// The component is spanned by breadth-first search from root.
// The resulting spanning tree in stored a FromList, and arc labels optionally
// stored in a slice.
//
// If FromList.Paths is not the same length as g, it is allocated and
// initialized. This allows a zero value FromList to be passed as f.
// If FromList.Paths is the same length as g, it is used as is and is not
// reinitialized. This allows multiple trees to be spanned in the same
// FromList with successive calls.
//
// For nodes spanned, the Path member of the returned FromList is populated
// with both From and Len values. The MaxLen member will be updated but
// not Leaves.
//
// The labels slice will be populated only if it is same length as g.
// Nil can be passed for example if labels are not needed.
//
// Returned is the number of nodes spanned, which will be the number of nodes
// reachable from root, and a bool indicating if these nodes were found to be
// a simply connected tree in the receiver graph g. Any cycles, loops,
// or parallel arcs in the component will cause simpleTree to be false, but
// FromList f will still be populated with a valid spanning tree.
func (g LabeledDirected) SpanTree(root NI, f *FromList, labels []LI) (nSpanned int, simpleTree bool) {
a := g.LabeledAdjacencyList
p := f.Paths
if len(p) != len(a) {
p = make([]PathEnd, len(a))
for i := range p {
p[i].From = -1
}
f.Paths = p
}
simpleTree = true
p[root].Len = 1
type arc struct {
from NI
half Half
}
var next []arc
frontier := []arc{{-1, Half{root, -1}}}
for len(frontier) > 0 {
for _, fa := range frontier { // fa frontier arc
nSpanned++
l := p[fa.half.To].Len + 1
for _, to := range a[fa.half.To] {
if p[to.To].Len > 0 {
simpleTree = false
continue
}
p[to.To] = PathEnd{From: fa.half.To, Len: l}
if len(labels) == len(p) {
labels[to.To] = to.Label
}
if l > f.MaxLen {
f.MaxLen = l
}
next = append(next, arc{fa.half.To, to})
}
}
frontier, next = next, frontier[:0]
}
return
}
// 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, g.Order())
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, g.Order())
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, g.Order())
for n, nbs := range g.LabeledAdjacencyList {
for _, nb := range nbs {
ta[nb.To] = append(ta[nb.To], NI(n))
ma++
}
}
return Directed{ta}, ma
}
// DominanceFrontiers holds dominance frontiers for all nodes in some graph.
// The frontier for a given node is a set of nodes, represented here as a map.
type DominanceFrontiers []map[NI]struct{}
// Frontier computes the dominance frontier for a node set.
func (d DominanceFrontiers) Frontier(s map[NI]struct{}) map[NI]struct{} {
fs := map[NI]struct{}{}
for n := range s {
for f := range d[n] {
fs[f] = struct{}{}
}
}
return fs
}
// Closure computes the closure, or iterated dominance frontier for a node set.
func (d DominanceFrontiers) Closure(s map[NI]struct{}) map[NI]struct{} {
c := map[NI]struct{}{}
e := map[NI]struct{}{}
w := map[NI]struct{}{}
var n NI
for n = range s {
e[n] = struct{}{}
w[n] = struct{}{}
}
for len(w) > 0 {
for n = range w {
break
}
delete(w, n)
for f := range d[n] {
if _, ok := c[f]; !ok {
c[f] = struct{}{}
if _, ok := e[f]; !ok {
e[f] = struct{}{}
w[f] = struct{}{}
}
}
}
}
return c
}
// Dominators holds immediate dominators.
//
// Dominators is a return type from methods Dominators, PostDominators, and
// Doms. See those methods for construction examples.
//
// The list of immediate dominators represents the "dominator tree"
// (in the same way a FromList represents a tree, but somewhat lighter weight.)
//
// In addition to the exported immediate dominators, the type also retains
// the transpose graph that was used to compute the dominators.
// See PostDominators and Doms for a caution about modifying the transpose
// graph.
type Dominators struct {
Immediate []NI
from interface { // either Directed or LabeledDirected
domFrontiers(Dominators) DominanceFrontiers
}
}
// Frontiers constructs the dominator frontier for each node.
//
// The frontier for a node is a set of nodes, represented as a map. The
// returned slice has the length of d.Immediate, which is the length of
// the original graph. The frontier is valid however only for nodes of the
// reachable subgraph. Nodes not in the reachable subgraph, those with a
// d.Immediate value of -1, will have a nil map.
func (d Dominators) Frontiers() DominanceFrontiers {
return d.from.domFrontiers(d)
}
// Set constructs the dominator set for a given node.
//
// The dominator set for a node always includes the node itself as the first
// node in the returned slice, as long as the node was in the subgraph
// reachable from the start node used to construct the dominators.
// If the argument n is a node not in the subgraph, Set returns nil.
func (d Dominators) Set(n NI) []NI {
im := d.Immediate
if im[n] < 0 {
return nil
}
for s := []NI{n}; ; {
if p := im[n]; p < 0 || p == n {
return s
} else {
s = append(s, p)
n = p
}
}
}
// 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(int(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
}
}
func (e *labEulerian) push() {
for u := e.top().To; ; {
e.uv.SetBit(int(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.To
}
}