1060 lines
27 KiB
Go
1060 lines
27 KiB
Go
|
// 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) 279–291.
|
|||
|
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.zΓ(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) zΓ(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
|
|||
|
}
|
|||
|
}
|