blob: 5633e391d71ff41c3c2f0b1e0d8562f47aed407c [file] [log] [blame]
// Copyright ©2014 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 path
import (
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/set"
)
// Dominators returns all dominators for all nodes in g. It does not
// prune for strict post-dominators, immediate dominators etc.
//
// A dominates B if and only if the only path through B travels through A.
func Dominators(start graph.Node, g graph.Graph) map[int64]set.Nodes {
allNodes := make(set.Nodes)
nlist := g.Nodes()
dominators := make(map[int64]set.Nodes, len(nlist))
for _, node := range nlist {
allNodes.Add(node)
}
var to func(graph.Node) []graph.Node
switch g := g.(type) {
case graph.Directed:
to = g.To
default:
to = g.From
}
for _, node := range nlist {
dominators[node.ID()] = make(set.Nodes)
if node.ID() == start.ID() {
dominators[node.ID()].Add(start)
} else {
dominators[node.ID()].Copy(allNodes)
}
}
for somethingChanged := true; somethingChanged; {
somethingChanged = false
for _, node := range nlist {
if node.ID() == start.ID() {
continue
}
preds := to(node)
if len(preds) == 0 {
continue
}
tmp := make(set.Nodes).Copy(dominators[preds[0].ID()])
for _, pred := range preds[1:] {
tmp.Intersect(tmp, dominators[pred.ID()])
}
dom := make(set.Nodes)
dom.Add(node)
dom.Union(dom, tmp)
if !set.Equal(dom, dominators[node.ID()]) {
dominators[node.ID()] = dom
somethingChanged = true
}
}
}
return dominators
}
// PostDominators returns all post-dominators for all nodes in g. It does not
// prune for strict post-dominators, immediate post-dominators etc.
//
// A post-dominates B if and only if all paths from B travel through A.
func PostDominators(end graph.Node, g graph.Graph) map[int64]set.Nodes {
allNodes := make(set.Nodes)
nlist := g.Nodes()
dominators := make(map[int64]set.Nodes, len(nlist))
for _, node := range nlist {
allNodes.Add(node)
}
for _, node := range nlist {
dominators[node.ID()] = make(set.Nodes)
if node.ID() == end.ID() {
dominators[node.ID()].Add(end)
} else {
dominators[node.ID()].Copy(allNodes)
}
}
for somethingChanged := true; somethingChanged; {
somethingChanged = false
for _, node := range nlist {
if node.ID() == end.ID() {
continue
}
succs := g.From(node)
if len(succs) == 0 {
continue
}
tmp := make(set.Nodes).Copy(dominators[succs[0].ID()])
for _, succ := range succs[1:] {
tmp.Intersect(tmp, dominators[succ.ID()])
}
dom := make(set.Nodes)
dom.Add(node)
dom.Union(dom, tmp)
if !set.Equal(dom, dominators[node.ID()]) {
dominators[node.ID()] = dom
somethingChanged = true
}
}
}
return dominators
}