Files
gonum/graph/encoding/digraph6/digraph6_test.go

323 lines
8.2 KiB
Go

// Copyright ©2018 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 digraph6
import (
"reflect"
"testing"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/iterator"
"gonum.org/v1/gonum/graph/simple"
)
var testGraphs = []struct {
g string
bin string
want []set
}{
// Wanted graphs were obtained from showg using the input graph string.
// The showg output is included for comparison.
//
// showg with dgraph6 support, in nauty v2.7, is available here: http://pallini.di.uniroma1.it/
{
// Graph 1, order 0.
g: "&?",
bin: "0:0",
want: []set{},
},
{
// Graph 1, order 5.
// 0 : 2 4;
// 1 : ;
// 2 : ;
// 3 : 1 4;
// 4 : ;
g: "&DI?AO?",
bin: "5:0010100000000000100100000",
want: []set{
0: linksToInt(2, 4),
1: linksToInt(),
2: linksToInt(),
3: linksToInt(1, 4),
4: linksToInt(),
},
},
{
// Graph 1, order 5.
// 0 : 1 3;
// 1 : 0 2 3 4;
// 2 : 0 1 3 4;
// 3 : 0 2;
// 4 : 0 1 2 3;
g: "&DT^\\N?",
bin: "5:0101010111110111010011110",
want: []set{
0: linksToInt(1, 3),
1: linksToInt(0, 2, 3, 4),
2: linksToInt(0, 1, 3, 4),
3: linksToInt(0, 2),
4: linksToInt(0, 1, 2, 3),
},
},
{
// Graph 1, order 5.
// 0 : ;
// 1 : 3;
// 2 : 0;
// 3 : ;
// 4 : 0 3;
g: "&D?I?H?",
bin: "5:0000000010100000000010010",
want: []set{
0: linksToInt(),
1: linksToInt(3),
2: linksToInt(0),
3: linksToInt(),
4: linksToInt(0, 3),
},
},
{
// Graph 1, order 6.
// 0 : 1 2 5;
// 1 : 2 3 4 5;
// 2 : 3 4;
// 3 : 0 4 5;
// 4 : 0 5;
// 5 : 2;
g: "&EXNEb`G",
bin: "6:011001001111000110100011100001001000",
want: []set{
0: linksToInt(1, 2, 5),
1: linksToInt(2, 3, 4, 5),
2: linksToInt(3, 4),
3: linksToInt(0, 4, 5),
4: linksToInt(0, 5),
5: linksToInt(2),
},
},
{
// Graph 1, order 9.
// 0 : 1 3 5 7 8;
// 1 : 2 3 4 7 8;
// 2 : 0 3 4;
// 3 : 4 5 6 7 8;
// 4 : 0 5 6 8;
// 5 : 1 2 6 7 8;
// 6 : 0 1 2 7 8;
// 7 : 2 4 8;
// 8 : 2;
g: "&HTXre?^`jFwXPG?",
bin: "9:010101011001110011100110000000011111100001101011000111111000011001010001001000000",
want: []set{
0: linksToInt(1, 3, 5, 7, 8),
1: linksToInt(2, 3, 4, 7, 8),
2: linksToInt(0, 3, 4),
3: linksToInt(4, 5, 6, 7, 8),
4: linksToInt(0, 5, 6, 8),
5: linksToInt(1, 2, 6, 7, 8),
6: linksToInt(0, 1, 2, 7, 8),
7: linksToInt(2, 4, 8),
8: linksToInt(2),
},
},
{
// Graph 1, order 12.
// 0 : 1 2 3 4 5 6 7 8 9 10 11;
// 1 : 2 3 4 5 6 7 8 11;
// 2 : 3 4 5 6 7 8 9 11;
// 3 : 4 5 6 7 8 10 11;
// 4 : 5 6 7 8 9 11;
// 5 : 6 7 9 10;
// 6 : 7 8 9 10 11;
// 7 : 8 9 10 11;
// 8 : 5 9 10;
// 9 : 1 3 10;
// 10 : 1 2 4 11;
// 11 : 5 8 9;
g: "&K^~NxF|Bz@|?u?^?N@ESAY@@K",
bin: "12:011111111111001111111001000111111101000011111011000001111101000000110110000000011111000000001111000001000110010100000010011010000001000001001100",
want: []set{
0: linksToInt(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
1: linksToInt(2, 3, 4, 5, 6, 7, 8, 11),
2: linksToInt(3, 4, 5, 6, 7, 8, 9, 11),
3: linksToInt(4, 5, 6, 7, 8, 10, 11),
4: linksToInt(5, 6, 7, 8, 9, 11),
5: linksToInt(6, 7, 9, 10),
6: linksToInt(7, 8, 9, 10, 11),
7: linksToInt(8, 9, 10, 11),
8: linksToInt(5, 9, 10),
9: linksToInt(1, 3, 10),
10: linksToInt(1, 2, 4, 11),
11: linksToInt(5, 8, 9),
},
},
{
// Graph 1, order 17.
// 0 : 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16;
// 1 : 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16;
// 2 : 3 4 5 6 7 8 9 10 11 12 13 14 16;
// 3 : 4 5 6 7 8 9 10 11 12 13 14 15 16;
// 4 : 5 6 7 8 9 10 11 12 13 14 15 16;
// 5 : 6 7 8 9 10 11 12 13 14 15 16;
// 6 : 7 8 9 10 11 12 13 14 15;
// 7 : 8 9 10 11 12 13 14 15 16;
// 8 : 9 10 11 12 13 15 16;
// 9 : 10 11 12 13 14 15 16;
// 10 : 11 12 13 14 16;
// 11 : 12 13 14 15 16;
// 12 : 13 14 15 16;
// 13 : 0 14 15 16;
// 14 : 8 15;
// 15 : 2 10 16;
// 16 : 6 14;
g: "&P^~m^~{^~g^~o^~_^~?^{?^{?^W?^o?]_?^??^??[?_P?OOGA?",
bin: "17:0111111111111011100111111111111111000111111111111010000111111111111100000111111111111000000111111111110000000111111111000000000111111111000000000111110110000000000111111100000000000111101000000000000111110000000000000111110000000000000111000000001000000100010000000100000100000010000000100",
want: []set{
0: linksToInt(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16),
1: linksToInt(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
2: linksToInt(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16),
3: linksToInt(4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
4: linksToInt(5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
5: linksToInt(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
6: linksToInt(7, 8, 9, 10, 11, 12, 13, 14, 15),
7: linksToInt(8, 9, 10, 11, 12, 13, 14, 15, 16),
8: linksToInt(9, 10, 11, 12, 13, 15, 16),
9: linksToInt(10, 11, 12, 13, 14, 15, 16),
10: linksToInt(11, 12, 13, 14, 16),
11: linksToInt(12, 13, 14, 15, 16),
12: linksToInt(13, 14, 15, 16),
13: linksToInt(0, 14, 15, 16),
14: linksToInt(8, 15),
15: linksToInt(2, 10, 16),
16: linksToInt(6, 14),
},
},
}
func TestNumberOf(t *testing.T) {
for _, test := range testGraphs {
n := numberOf(Graph(test.g))
if n != int64(len(test.want)) {
t.Errorf("unexpected graph n: got:%d want:%d", n, len(test.want))
}
}
}
func TestGoString(t *testing.T) {
for _, test := range testGraphs {
gosyntax := Graph(test.g).GoString()
if gosyntax != test.bin {
t.Errorf("unexpected graph string: got:%s want:%s", gosyntax, test.bin)
}
}
}
func TestGraph(t *testing.T) {
for _, test := range testGraphs {
g := Graph(test.g)
if !IsValid(g) {
t.Errorf("unexpected invalid graph %q", g)
}
nodes := g.Nodes()
if nodes.Len() != len(test.want) {
t.Errorf("unexpected graph n: got:%d want:%d", nodes.Len(), len(test.want))
}
got := make([]set, nodes.Len())
for nodes.Next() {
n := nodes.Node()
got[n.ID()] = linksTo(graph.NodesOf(g.From(n.ID()))...)
}
if !reflect.DeepEqual(got, test.want) {
t.Errorf("unexpected graph:\ngot: %v\nwant:%v", got, test.want)
}
reverse := make([]set, len(got))
for i := range reverse {
reverse[i] = make(set)
}
for i, s := range got {
for j := range s {
reverse[j][i] = struct{}{}
}
}
for i, s := range got {
from := g.From(int64(i)).Len()
if from != len(s) {
t.Errorf("unexpected number of nodes from %d: got:%d want:%d", i, from, len(s))
}
to := g.To(int64(i)).Len()
if to != len(reverse[i]) {
t.Errorf("unexpected number of nodes to %d: got:%d want:%d", i, to, len(reverse))
}
}
dst := simple.NewDirectedGraph()
graph.Copy(dst, g)
enc := Encode(dst)
if enc != g {
t.Errorf("unexpected round trip: got:%q want:%q", enc, g)
}
}
}
type set map[int]struct{}
func linksToInt(nodes ...int) map[int]struct{} {
s := make(map[int]struct{})
for _, n := range nodes {
s[n] = struct{}{}
}
return s
}
func linksTo(nodes ...graph.Node) map[int]struct{} {
s := make(map[int]struct{})
for _, n := range nodes {
s[int(n.ID())] = struct{}{}
}
return s
}
func TestLargeEncoding(t *testing.T) {
for _, l := range []int{
50, 60, 70, 80, 100, 1e4,
} {
d6 := Encode(implicitCycle(l))
if !IsValid(d6) {
t.Errorf("digraph6-encoding unexpectedly invalid: %v", d6)
}
for i, b := range []byte(d6[1:]) {
if b < 63 || 126 < b {
t.Errorf("digraph6-encoding contains invalid character at %d: %q", i, b)
}
}
}
}
type implicitCycle int32
func (i implicitCycle) Node(id int64) graph.Node {
if id < int64(i) {
return node(id)
}
return nil
}
func (i implicitCycle) Nodes() graph.Nodes {
return iterator.NewImplicitNodes(0, int(i), func(id int) graph.Node { return node(id) })
}
func (i implicitCycle) From(id int64) graph.Nodes {
if i < 2 {
return graph.Empty
}
next := int(id+1) % int(i)
return iterator.NewImplicitNodes(next, next+1, func(id int) graph.Node { return node(id) })
}
func (i implicitCycle) HasEdgeBetween(xid, yid int64) bool { return false }
func (i implicitCycle) Edge(xid, yid int64) graph.Edge { return nil }
type node int32
func (n node) ID() int64 { return int64(n) }