mirror of
https://github.com/gonum/gonum.git
synced 2025-10-19 21:44:41 +08:00
176 lines
4.6 KiB
Go
176 lines
4.6 KiB
Go
// 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 topo
|
|
|
|
import (
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
|
|
"gonum.org/v1/gonum/graph"
|
|
"gonum.org/v1/gonum/graph/internal/ordered"
|
|
"gonum.org/v1/gonum/graph/simple"
|
|
)
|
|
|
|
func TestIsPath(t *testing.T) {
|
|
dg := simple.NewDirectedGraph()
|
|
if !IsPathIn(dg, nil) {
|
|
t.Error("IsPath returns false on nil path")
|
|
}
|
|
p := []graph.Node{simple.Node(0)}
|
|
if IsPathIn(dg, p) {
|
|
t.Error("IsPath returns true on nonexistant node")
|
|
}
|
|
dg.AddNode(p[0])
|
|
if !IsPathIn(dg, p) {
|
|
t.Error("IsPath returns false on single-length path with existing node")
|
|
}
|
|
p = append(p, simple.Node(1))
|
|
dg.AddNode(p[1])
|
|
if IsPathIn(dg, p) {
|
|
t.Error("IsPath returns true on bad path of length 2")
|
|
}
|
|
dg.SetEdge(simple.Edge{F: p[0], T: p[1]})
|
|
if !IsPathIn(dg, p) {
|
|
t.Error("IsPath returns false on correct path of length 2")
|
|
}
|
|
p[0], p[1] = p[1], p[0]
|
|
if IsPathIn(dg, p) {
|
|
t.Error("IsPath erroneously returns true for a reverse path")
|
|
}
|
|
p = []graph.Node{p[1], p[0], simple.Node(2)}
|
|
dg.SetEdge(simple.Edge{F: p[1], T: p[2]})
|
|
if !IsPathIn(dg, p) {
|
|
t.Error("IsPath does not find a correct path for path > 2 nodes")
|
|
}
|
|
ug := simple.NewUndirectedGraph()
|
|
ug.SetEdge(simple.Edge{F: p[1], T: p[0]})
|
|
ug.SetEdge(simple.Edge{F: p[1], T: p[2]})
|
|
if !IsPathIn(dg, p) {
|
|
t.Error("IsPath does not correctly account for undirected behavior")
|
|
}
|
|
}
|
|
|
|
var pathExistsInUndirectedTests = []struct {
|
|
g []intset
|
|
from, to int
|
|
want bool
|
|
}{
|
|
{g: batageljZaversnikGraph, from: 0, to: 0, want: true},
|
|
{g: batageljZaversnikGraph, from: 0, to: 1, want: false},
|
|
{g: batageljZaversnikGraph, from: 1, to: 2, want: true},
|
|
{g: batageljZaversnikGraph, from: 2, to: 1, want: true},
|
|
{g: batageljZaversnikGraph, from: 2, to: 12, want: false},
|
|
{g: batageljZaversnikGraph, from: 20, to: 6, want: true},
|
|
}
|
|
|
|
func TestPathExistsInUndirected(t *testing.T) {
|
|
for i, test := range pathExistsInUndirectedTests {
|
|
g := simple.NewUndirectedGraph()
|
|
|
|
for u, e := range test.g {
|
|
if g.Node(int64(u)) == nil {
|
|
g.AddNode(simple.Node(u))
|
|
}
|
|
for v := range e {
|
|
if g.Node(int64(v)) == nil {
|
|
g.AddNode(simple.Node(v))
|
|
}
|
|
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
|
}
|
|
}
|
|
|
|
got := PathExistsIn(g, simple.Node(test.from), simple.Node(test.to))
|
|
if got != test.want {
|
|
t.Errorf("unexpected result for path existence in test %d: got:%t want %t", i, got, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
var pathExistsInDirectedTests = []struct {
|
|
g []intset
|
|
from, to int
|
|
want bool
|
|
}{
|
|
// The graph definition is such that from node IDs are
|
|
// less than to node IDs.
|
|
{g: batageljZaversnikGraph, from: 0, to: 0, want: true},
|
|
{g: batageljZaversnikGraph, from: 0, to: 1, want: false},
|
|
{g: batageljZaversnikGraph, from: 1, to: 2, want: true},
|
|
{g: batageljZaversnikGraph, from: 2, to: 1, want: false},
|
|
{g: batageljZaversnikGraph, from: 2, to: 12, want: false},
|
|
{g: batageljZaversnikGraph, from: 20, to: 6, want: false},
|
|
{g: batageljZaversnikGraph, from: 6, to: 20, want: true},
|
|
}
|
|
|
|
func TestPathExistsInDirected(t *testing.T) {
|
|
for i, test := range pathExistsInDirectedTests {
|
|
g := simple.NewDirectedGraph()
|
|
|
|
for u, e := range test.g {
|
|
if g.Node(int64(u)) == nil {
|
|
g.AddNode(simple.Node(u))
|
|
}
|
|
for v := range e {
|
|
if g.Node(int64(v)) == nil {
|
|
g.AddNode(simple.Node(v))
|
|
}
|
|
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
|
}
|
|
}
|
|
|
|
got := PathExistsIn(g, simple.Node(test.from), simple.Node(test.to))
|
|
if got != test.want {
|
|
t.Errorf("unexpected result for path existence in test %d: got:%t want %t", i, got, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
var connectedComponentTests = []struct {
|
|
g []intset
|
|
want [][]int64
|
|
}{
|
|
{
|
|
g: batageljZaversnikGraph,
|
|
want: [][]int64{
|
|
{0},
|
|
{1, 2, 3, 4, 5},
|
|
{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
|
|
},
|
|
},
|
|
}
|
|
|
|
func TestConnectedComponents(t *testing.T) {
|
|
for i, test := range connectedComponentTests {
|
|
g := simple.NewUndirectedGraph()
|
|
|
|
for u, e := range test.g {
|
|
if g.Node(int64(u)) == nil {
|
|
g.AddNode(simple.Node(u))
|
|
}
|
|
for v := range e {
|
|
if g.Node(int64(v)) == nil {
|
|
g.AddNode(simple.Node(v))
|
|
}
|
|
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
|
}
|
|
}
|
|
cc := ConnectedComponents(g)
|
|
got := make([][]int64, len(cc))
|
|
for j, c := range cc {
|
|
ids := make([]int64, len(c))
|
|
for k, n := range c {
|
|
ids[k] = n.ID()
|
|
}
|
|
sort.Sort(ordered.Int64s(ids))
|
|
got[j] = ids
|
|
}
|
|
sort.Sort(ordered.BySliceValues(got))
|
|
if !reflect.DeepEqual(got, test.want) {
|
|
t.Errorf("unexpected connected components for test %d %T:\ngot: %v\nwant:%v", i, g, got, test.want)
|
|
}
|
|
}
|
|
}
|