Skip to content
This repository has been archived by the owner on Apr 26, 2019. It is now read-only.

Commit

Permalink
Re-add Tarjan tests
Browse files Browse the repository at this point in the history
Clobbered by a rebase on the wrong working machine. Recovered from the
commit ref from travis:

https://travis-ci.org/gonum/graph/builds/51771511
  • Loading branch information
kortschak committed Feb 26, 2015
1 parent 3b84acc commit f6ac2b0
Showing 1 changed file with 147 additions and 0 deletions.
147 changes: 147 additions & 0 deletions search/search_test.go
Expand Up @@ -7,6 +7,8 @@ package search_test
import (
"fmt"
"math"
"reflect"
"sort"
"testing"

"github.com/gonum/graph"
Expand Down Expand Up @@ -273,3 +275,148 @@ func TestIsPath(t *testing.T) {
t.Error("IsPath does not correctly account for undirected behavior")
}
}

type interval struct{ start, end int }

var tarjanTests = []struct {
g []set

ambiguousOrder []interval
want [][]int
}{

{
g: []set{
0: linksTo(1),
1: linksTo(2, 7),
2: linksTo(3, 6),
3: linksTo(4),
4: linksTo(2, 5),
6: linksTo(3, 5),
7: linksTo(0, 6),
},

want: [][]int{
{5},
{2, 3, 4, 6},
{0, 1, 7},
},
},
{
g: []set{
0: linksTo(1, 2, 3),
1: linksTo(2),
2: linksTo(3),
3: linksTo(1),
},

want: [][]int{
{1, 2, 3},
{0},
},
},
{
g: []set{
0: linksTo(1),
1: linksTo(0, 2),
2: linksTo(1),
},

want: [][]int{
{0, 1, 2},
},
},
{
g: []set{
0: linksTo(1),
1: linksTo(2, 3),
2: linksTo(4, 5),
3: linksTo(4, 5),
4: linksTo(6),
5: nil,
6: nil,
},

// Node pairs (2, 3) and (4, 5) are not
// relatively orderable within each pair.
ambiguousOrder: []interval{
{0, 3}, // This includes node 6 since it only needs to be before 4 in topo sort.
{3, 5},
},
want: [][]int{
{6}, {5}, {4}, {3}, {2}, {1}, {0},
},
},
{
g: []set{
0: linksTo(1),
1: linksTo(2, 3, 4),
2: linksTo(0, 3),
3: linksTo(4),
4: linksTo(3),
},

// SCCs are not relatively ordable.
ambiguousOrder: []interval{
{0, 2},
},
want: [][]int{
{3, 4}, {0, 1, 2},
},
},
}

func TestTarjan(t *testing.T) {
for i, test := range tarjanTests {
g := concrete.NewDirectedGraph()
for u, e := range test.g {
g.AddNode(concrete.Node(u))
for v := range e {
if !g.NodeExists(concrete.Node(v)) {
g.AddNode(concrete.Node(v))
}
g.AddDirectedEdge(concrete.Edge{H: concrete.Node(u), T: concrete.Node(v)}, 0)
}
}
gotSCCs := search.Tarjan(g)
// tarjan.strongconnect does range iteration over maps,
// so sort SCC members to ensure consistent ordering.
gotIDs := make([][]int, len(gotSCCs))
for i, scc := range gotSCCs {
gotIDs[i] = make([]int, len(scc))
for j, id := range scc {
gotIDs[i][j] = id.ID()
}
sort.Ints(gotIDs[i])
}
for _, iv := range test.ambiguousOrder {
sort.Sort(byComponentLengthOrStart(test.want[iv.start:iv.end]))
sort.Sort(byComponentLengthOrStart(gotIDs[iv.start:iv.end]))
}
if !reflect.DeepEqual(gotIDs, test.want) {
t.Errorf("unexpected Tarjan scc result for %d:\n\tgot:%v\n\twant:%v", i, gotIDs, test.want)
}
}
}

// set is an integer set.
type set map[int]struct{}

func linksTo(i ...int) set {
if len(i) == 0 {
return nil
}
s := make(set)
for _, v := range i {
s[v] = struct{}{}
}
return s
}

type byComponentLengthOrStart [][]int

func (c byComponentLengthOrStart) Len() int { return len(c) }
func (c byComponentLengthOrStart) Less(i, j int) bool {
return len(c[i]) < len(c[j]) || (len(c[i]) == len(c[j]) && c[i][0] < c[j][0])
}
func (c byComponentLengthOrStart) Swap(i, j int) { c[i], c[j] = c[j], c[i] }

0 comments on commit f6ac2b0

Please sign in to comment.