github.com/gopherd/gonum@v0.0.4/graph/encoding/digraph6/digraph6_test.go (about)

     1  // Copyright ©2018 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package digraph6
     6  
     7  import (
     8  	"reflect"
     9  	"testing"
    10  
    11  	"github.com/gopherd/gonum/graph"
    12  	"github.com/gopherd/gonum/graph/iterator"
    13  	"github.com/gopherd/gonum/graph/simple"
    14  )
    15  
    16  var testGraphs = []struct {
    17  	g    string
    18  	bin  string
    19  	want []set
    20  }{
    21  	// Wanted graphs were obtained from showg using the input graph string.
    22  	// The showg output is included for comparison.
    23  	//
    24  	// showg with dgraph6 support, in nauty v2.7, is available here: http://pallini.di.uniroma1.it/
    25  	{
    26  		// Graph 1, order 0.
    27  		g:    "&?",
    28  		bin:  "0:0",
    29  		want: []set{},
    30  	},
    31  	{
    32  		// Graph 1, order 5.
    33  		//   0 : 2 4;
    34  		//   1 : ;
    35  		//   2 : ;
    36  		//   3 : 1 4;
    37  		//   4 : ;
    38  		g:   "&DI?AO?",
    39  		bin: "5:0010100000000000100100000",
    40  		want: []set{
    41  			0: linksToInt(2, 4),
    42  			1: linksToInt(),
    43  			2: linksToInt(),
    44  			3: linksToInt(1, 4),
    45  			4: linksToInt(),
    46  		},
    47  	},
    48  	{
    49  		// Graph 1, order 5.
    50  		//   0 : 1 3;
    51  		//   1 : 0 2 3 4;
    52  		//   2 : 0 1 3 4;
    53  		//   3 : 0 2;
    54  		//   4 : 0 1 2 3;
    55  		g:   "&DT^\\N?",
    56  		bin: "5:0101010111110111010011110",
    57  		want: []set{
    58  			0: linksToInt(1, 3),
    59  			1: linksToInt(0, 2, 3, 4),
    60  			2: linksToInt(0, 1, 3, 4),
    61  			3: linksToInt(0, 2),
    62  			4: linksToInt(0, 1, 2, 3),
    63  		},
    64  	},
    65  	{
    66  		// Graph 1, order 5.
    67  		//   0 : ;
    68  		//   1 : 3;
    69  		//   2 : 0;
    70  		//   3 : ;
    71  		//   4 : 0 3;
    72  		g:   "&D?I?H?",
    73  		bin: "5:0000000010100000000010010",
    74  		want: []set{
    75  			0: linksToInt(),
    76  			1: linksToInt(3),
    77  			2: linksToInt(0),
    78  			3: linksToInt(),
    79  			4: linksToInt(0, 3),
    80  		},
    81  	},
    82  	{
    83  		// Graph 1, order 6.
    84  		//   0 : 1 2 5;
    85  		//   1 : 2 3 4 5;
    86  		//   2 : 3 4;
    87  		//   3 : 0 4 5;
    88  		//   4 : 0 5;
    89  		//   5 : 2;
    90  		g:   "&EXNEb`G",
    91  		bin: "6:011001001111000110100011100001001000",
    92  		want: []set{
    93  			0: linksToInt(1, 2, 5),
    94  			1: linksToInt(2, 3, 4, 5),
    95  			2: linksToInt(3, 4),
    96  			3: linksToInt(0, 4, 5),
    97  			4: linksToInt(0, 5),
    98  			5: linksToInt(2),
    99  		},
   100  	},
   101  	{
   102  		// Graph 1, order 9.
   103  		//   0 : 1 3 5 7 8;
   104  		//   1 : 2 3 4 7 8;
   105  		//   2 : 0 3 4;
   106  		//   3 : 4 5 6 7 8;
   107  		//   4 : 0 5 6 8;
   108  		//   5 : 1 2 6 7 8;
   109  		//   6 : 0 1 2 7 8;
   110  		//   7 : 2 4 8;
   111  		//   8 : 2;
   112  		g:   "&HTXre?^`jFwXPG?",
   113  		bin: "9:010101011001110011100110000000011111100001101011000111111000011001010001001000000",
   114  		want: []set{
   115  			0: linksToInt(1, 3, 5, 7, 8),
   116  			1: linksToInt(2, 3, 4, 7, 8),
   117  			2: linksToInt(0, 3, 4),
   118  			3: linksToInt(4, 5, 6, 7, 8),
   119  			4: linksToInt(0, 5, 6, 8),
   120  			5: linksToInt(1, 2, 6, 7, 8),
   121  			6: linksToInt(0, 1, 2, 7, 8),
   122  			7: linksToInt(2, 4, 8),
   123  			8: linksToInt(2),
   124  		},
   125  	},
   126  	{
   127  		// Graph 1, order 12.
   128  		//   0 : 1 2 3 4 5 6 7 8 9 10 11;
   129  		//   1 : 2 3 4 5 6 7 8 11;
   130  		//   2 : 3 4 5 6 7 8 9 11;
   131  		//   3 : 4 5 6 7 8 10 11;
   132  		//   4 : 5 6 7 8 9 11;
   133  		//   5 : 6 7 9 10;
   134  		//   6 : 7 8 9 10 11;
   135  		//   7 : 8 9 10 11;
   136  		//   8 : 5 9 10;
   137  		//   9 : 1 3 10;
   138  		//  10 : 1 2 4 11;
   139  		//  11 : 5 8 9;
   140  		g:   "&K^~NxF|Bz@|?u?^?N@ESAY@@K",
   141  		bin: "12:011111111111001111111001000111111101000011111011000001111101000000110110000000011111000000001111000001000110010100000010011010000001000001001100",
   142  		want: []set{
   143  			0:  linksToInt(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
   144  			1:  linksToInt(2, 3, 4, 5, 6, 7, 8, 11),
   145  			2:  linksToInt(3, 4, 5, 6, 7, 8, 9, 11),
   146  			3:  linksToInt(4, 5, 6, 7, 8, 10, 11),
   147  			4:  linksToInt(5, 6, 7, 8, 9, 11),
   148  			5:  linksToInt(6, 7, 9, 10),
   149  			6:  linksToInt(7, 8, 9, 10, 11),
   150  			7:  linksToInt(8, 9, 10, 11),
   151  			8:  linksToInt(5, 9, 10),
   152  			9:  linksToInt(1, 3, 10),
   153  			10: linksToInt(1, 2, 4, 11),
   154  			11: linksToInt(5, 8, 9),
   155  		},
   156  	},
   157  	{
   158  		// Graph 1, order 17.
   159  		//   0 : 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16;
   160  		//   1 : 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16;
   161  		//   2 : 3 4 5 6 7 8 9 10 11 12 13 14 16;
   162  		//   3 : 4 5 6 7 8 9 10 11 12 13 14 15 16;
   163  		//   4 : 5 6 7 8 9 10 11 12 13 14 15 16;
   164  		//   5 : 6 7 8 9 10 11 12 13 14 15 16;
   165  		//   6 : 7 8 9 10 11 12 13 14 15;
   166  		//   7 : 8 9 10 11 12 13 14 15 16;
   167  		//   8 : 9 10 11 12 13 15 16;
   168  		//   9 : 10 11 12 13 14 15 16;
   169  		//  10 : 11 12 13 14 16;
   170  		//  11 : 12 13 14 15 16;
   171  		//  12 : 13 14 15 16;
   172  		//  13 : 0 14 15 16;
   173  		//  14 : 8 15;
   174  		//  15 : 2 10 16;
   175  		//  16 : 6 14;
   176  		g:   "&P^~m^~{^~g^~o^~_^~?^{?^{?^W?^o?]_?^??^??[?_P?OOGA?",
   177  		bin: "17:0111111111111011100111111111111111000111111111111010000111111111111100000111111111111000000111111111110000000111111111000000000111111111000000000111110110000000000111111100000000000111101000000000000111110000000000000111110000000000000111000000001000000100010000000100000100000010000000100",
   178  		want: []set{
   179  			0:  linksToInt(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16),
   180  			1:  linksToInt(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
   181  			2:  linksToInt(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16),
   182  			3:  linksToInt(4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
   183  			4:  linksToInt(5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
   184  			5:  linksToInt(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
   185  			6:  linksToInt(7, 8, 9, 10, 11, 12, 13, 14, 15),
   186  			7:  linksToInt(8, 9, 10, 11, 12, 13, 14, 15, 16),
   187  			8:  linksToInt(9, 10, 11, 12, 13, 15, 16),
   188  			9:  linksToInt(10, 11, 12, 13, 14, 15, 16),
   189  			10: linksToInt(11, 12, 13, 14, 16),
   190  			11: linksToInt(12, 13, 14, 15, 16),
   191  			12: linksToInt(13, 14, 15, 16),
   192  			13: linksToInt(0, 14, 15, 16),
   193  			14: linksToInt(8, 15),
   194  			15: linksToInt(2, 10, 16),
   195  			16: linksToInt(6, 14),
   196  		},
   197  	},
   198  }
   199  
   200  func TestNumberOf(t *testing.T) {
   201  	for _, test := range testGraphs {
   202  		n := numberOf(Graph(test.g))
   203  		if n != int64(len(test.want)) {
   204  			t.Errorf("unexpected graph n: got:%d want:%d", n, len(test.want))
   205  		}
   206  	}
   207  }
   208  
   209  func TestGoString(t *testing.T) {
   210  	for _, test := range testGraphs {
   211  		gosyntax := Graph(test.g).GoString()
   212  		if gosyntax != test.bin {
   213  			t.Errorf("unexpected graph string: got:%s want:%s", gosyntax, test.bin)
   214  		}
   215  	}
   216  }
   217  
   218  func TestGraph(t *testing.T) {
   219  	for _, test := range testGraphs {
   220  		g := Graph(test.g)
   221  		if !IsValid(g) {
   222  			t.Errorf("unexpected invalid graph %q", g)
   223  		}
   224  		nodes := g.Nodes()
   225  		if nodes.Len() != len(test.want) {
   226  			t.Errorf("unexpected graph n: got:%d want:%d", nodes.Len(), len(test.want))
   227  		}
   228  		got := make([]set, nodes.Len())
   229  		for nodes.Next() {
   230  			n := nodes.Node()
   231  			got[n.ID()] = linksTo(graph.NodesOf(g.From(n.ID()))...)
   232  		}
   233  		if !reflect.DeepEqual(got, test.want) {
   234  			t.Errorf("unexpected graph:\ngot: %v\nwant:%v", got, test.want)
   235  		}
   236  		reverse := make([]set, len(got))
   237  		for i := range reverse {
   238  			reverse[i] = make(set)
   239  		}
   240  		for i, s := range got {
   241  			for j := range s {
   242  				reverse[j][i] = struct{}{}
   243  			}
   244  		}
   245  		for i, s := range got {
   246  			from := g.From(int64(i)).Len()
   247  			if from != len(s) {
   248  				t.Errorf("unexpected number of nodes from %d: got:%d want:%d", i, from, len(s))
   249  			}
   250  			to := g.To(int64(i)).Len()
   251  			if to != len(reverse[i]) {
   252  				t.Errorf("unexpected number of nodes to %d: got:%d want:%d", i, to, len(reverse))
   253  			}
   254  		}
   255  
   256  		dst := simple.NewDirectedGraph()
   257  		graph.Copy(dst, g)
   258  		enc := Encode(dst)
   259  		if enc != g {
   260  			t.Errorf("unexpected round trip: got:%q want:%q", enc, g)
   261  		}
   262  	}
   263  }
   264  
   265  type set map[int]struct{}
   266  
   267  func linksToInt(nodes ...int) map[int]struct{} {
   268  	s := make(map[int]struct{})
   269  	for _, n := range nodes {
   270  		s[n] = struct{}{}
   271  	}
   272  	return s
   273  }
   274  
   275  func linksTo(nodes ...graph.Node) map[int]struct{} {
   276  	s := make(map[int]struct{})
   277  	for _, n := range nodes {
   278  		s[int(n.ID())] = struct{}{}
   279  	}
   280  	return s
   281  }
   282  
   283  func TestLargeEncoding(t *testing.T) {
   284  	for _, l := range []int{
   285  		50, 60, 70, 80, 100, 1e4,
   286  	} {
   287  		d6 := Encode(implicitCycle(l))
   288  		if !IsValid(d6) {
   289  			t.Errorf("digraph6-encoding unexpectedly invalid: %v", d6)
   290  		}
   291  		for i, b := range []byte(d6[1:]) {
   292  			if b < 63 || 126 < b {
   293  				t.Errorf("digraph6-encoding contains invalid character at %d: %q", i, b)
   294  			}
   295  		}
   296  	}
   297  }
   298  
   299  type implicitCycle int32
   300  
   301  func (i implicitCycle) Node(id int64) graph.Node {
   302  	if id < int64(i) {
   303  		return node(id)
   304  	}
   305  	return nil
   306  }
   307  func (i implicitCycle) Nodes() graph.Nodes {
   308  	return iterator.NewImplicitNodes(0, int(i), func(id int) graph.Node { return node(id) })
   309  }
   310  func (i implicitCycle) From(id int64) graph.Nodes {
   311  	if i < 2 {
   312  		return graph.Empty
   313  	}
   314  	next := int(id+1) % int(i)
   315  	return iterator.NewImplicitNodes(next, next+1, func(id int) graph.Node { return node(id) })
   316  }
   317  func (i implicitCycle) HasEdgeBetween(xid, yid int64) bool { return false }
   318  func (i implicitCycle) Edge(xid, yid int64) graph.Edge     { return nil }
   319  
   320  type node int32
   321  
   322  func (n node) ID() int64 { return int64(n) }