dag: Validate for DAGs

This commit is contained in:
Mitchell Hashimoto 2015-02-04 10:36:33 -05:00
parent e94c43e0dc
commit d59ced3c57
3 changed files with 49 additions and 1 deletions

View File

@ -37,6 +37,26 @@ func (g *AcyclicGraph) Root() (Vertex, error) {
return roots[0], nil
}
// Validate validates the DAG. A DAG is valid if it has a single root
// with no cycles.
func (g *AcyclicGraph) Validate() error {
if _, err := g.Root(); err != nil {
return err
}
var cycles [][]Vertex
for _, cycle := range StronglyConnected(&g.Graph) {
if len(cycle) > 1 {
cycles = append(cycles, cycle)
}
}
if len(cycles) > 0 {
return fmt.Errorf("cycles: %#v", cycles)
}
return nil
}
// Walk walks the graph, calling your callback as each node is visited.
// This will walk nodes in parallel if it can.
func (g *AcyclicGraph) Walk(cb WalkFunc) error {

View File

@ -47,6 +47,34 @@ func TestAcyclicGraphRoot_multiple(t *testing.T) {
}
}
func TestAcyclicGraphValidate(t *testing.T) {
var g AcyclicGraph
g.Add(1)
g.Add(2)
g.Add(3)
g.Connect(BasicEdge(3, 2))
g.Connect(BasicEdge(3, 1))
if err := g.Validate(); err != nil {
t.Fatalf("err: %s", err)
}
}
func TestAcyclicGraphValidate_cycle(t *testing.T) {
var g AcyclicGraph
g.Add(1)
g.Add(2)
g.Add(3)
g.Connect(BasicEdge(3, 2))
g.Connect(BasicEdge(3, 1))
g.Connect(BasicEdge(1, 2))
g.Connect(BasicEdge(2, 1))
if err := g.Validate(); err == nil {
t.Fatal("should error")
}
}
func TestAcyclicGraphWalk(t *testing.T) {
var g AcyclicGraph
g.Add(1)

View File

@ -58,7 +58,7 @@ func strongConnect(g *Graph, v Vertex, data *tarjanData) *tarjanVertex {
if tv.Lowlink == index {
vs := make([]Vertex, 0, 2)
for i := len(data.stack) - 1; ; i-- {
for i := len(data.stack) - 1; i >= 0; i-- {
v := data.stack[i]
data.stack[i] = nil
data.stack = data.stack[:i]