gonum.org/v1/gonum@v0.14.0/graph/encoding/graph6/graph6_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 graph6
     6  
     7  import (
     8  	"reflect"
     9  	"testing"
    10  
    11  	"gonum.org/v1/gonum/graph"
    12  	"gonum.org/v1/gonum/graph/iterator"
    13  	"gonum.org/v1/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 is available here: https://hog.grinvin.org/data/generators/decoders/showg
    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 : 3;
    35  		//   2 : 0;
    36  		//   3 : 1 4;
    37  		//   4 : 0 3;
    38  		g:   "DQc",
    39  		bin: "5:0100101001",
    40  		want: []set{
    41  			0: linksToInt(2, 4),
    42  			1: linksToInt(3),
    43  			2: linksToInt(0),
    44  			3: linksToInt(1, 4),
    45  			4: linksToInt(0, 3),
    46  		},
    47  	},
    48  	{
    49  		// Graph 1, order 4.
    50  		//   0 : 1 2 3;
    51  		//   1 : 0 2 3;
    52  		//   2 : 0 1 3;
    53  		//   3 : 0 1 2;
    54  		g:   "C~",
    55  		bin: "4:111111",
    56  		want: []set{
    57  			0: linksToInt(1, 2, 3),
    58  			1: linksToInt(0, 2, 3),
    59  			2: linksToInt(0, 1, 3),
    60  			3: linksToInt(0, 1, 2),
    61  		},
    62  	},
    63  	{
    64  		// Graph 1, order 6.
    65  		//   0 : 1 3 4;
    66  		//   1 : 0 2 5;
    67  		//   2 : 1 3 4;
    68  		//   3 : 0 2 5;
    69  		//   4 : 0 2 5;
    70  		//   5 : 1 3 4;
    71  		g:   "ElhW",
    72  		bin: "6:101101101001011",
    73  		want: []set{
    74  			0: linksToInt(1, 3, 4),
    75  			1: linksToInt(0, 2, 5),
    76  			2: linksToInt(1, 3, 4),
    77  			3: linksToInt(0, 2, 5),
    78  			4: linksToInt(0, 2, 5),
    79  			5: linksToInt(1, 3, 4),
    80  		},
    81  	},
    82  	{
    83  		// Graph 1, order 10.
    84  		//   0 : 1 2 3;
    85  		//   1 : 0 4 5;
    86  		//   2 : 0 6 7;
    87  		//   3 : 0 8 9;
    88  		//   4 : 1 6 8;
    89  		//   5 : 1 7 9;
    90  		//   6 : 2 4 9;
    91  		//   7 : 2 5 8;
    92  		//   8 : 3 4 7;
    93  		//   9 : 3 5 6;
    94  		g:   "IsP@PGXD_",
    95  		bin: "10:110100010001000001010001001000011001000101100",
    96  		want: []set{
    97  			0: linksToInt(1, 2, 3),
    98  			1: linksToInt(0, 4, 5),
    99  			2: linksToInt(0, 6, 7),
   100  			3: linksToInt(0, 8, 9),
   101  			4: linksToInt(1, 6, 8),
   102  			5: linksToInt(1, 7, 9),
   103  			6: linksToInt(2, 4, 9),
   104  			7: linksToInt(2, 5, 8),
   105  			8: linksToInt(3, 4, 7),
   106  			9: linksToInt(3, 5, 6),
   107  		},
   108  	},
   109  	{
   110  		// Graph 1, order 17.
   111  		//   0 : 1 15 16;
   112  		//   1 : 0 2 5;
   113  		//   2 : 1 3 14;
   114  		//   3 : 2 4 16;
   115  		//   4 : 3 5 15;
   116  		//   5 : 1 4 6;
   117  		//   6 : 5 7 16;
   118  		//   7 : 6 8 11;
   119  		//   8 : 7 9 13;
   120  		//   9 : 8 10 16;
   121  		//  10 : 9 11 14;
   122  		//  11 : 7 10 12;
   123  		//  12 : 11 13 16;
   124  		//  13 : 8 12 14;
   125  		//  14 : 2 10 13 15;
   126  		//  15 : 0 4 14;
   127  		//  16 : 0 3 6 9 12;
   128  		g:   "PhDGGC@?G?_H?@?Gc@KO@cc_",
   129  		bin: "17:1010010001010010000010000001000000010000000010000000001000000010010000000000010000000010001001000000010011000100000000011001001001001000",
   130  		want: []set{
   131  			0:  linksToInt(1, 15, 16),
   132  			1:  linksToInt(0, 2, 5),
   133  			2:  linksToInt(1, 3, 14),
   134  			3:  linksToInt(2, 4, 16),
   135  			4:  linksToInt(3, 5, 15),
   136  			5:  linksToInt(1, 4, 6),
   137  			6:  linksToInt(5, 7, 16),
   138  			7:  linksToInt(6, 8, 11),
   139  			8:  linksToInt(7, 9, 13),
   140  			9:  linksToInt(8, 10, 16),
   141  			10: linksToInt(9, 11, 14),
   142  			11: linksToInt(7, 10, 12),
   143  			12: linksToInt(11, 13, 16),
   144  			13: linksToInt(8, 12, 14),
   145  			14: linksToInt(2, 10, 13, 15),
   146  			15: linksToInt(0, 4, 14),
   147  			16: linksToInt(0, 3, 6, 9, 12),
   148  		},
   149  	},
   150  }
   151  
   152  func TestNumberOf(t *testing.T) {
   153  	for _, test := range testGraphs {
   154  		n := numberOf(Graph(test.g))
   155  		if n != int64(len(test.want)) {
   156  			t.Errorf("unexpected graph n: got:%d want:%d", n, len(test.want))
   157  		}
   158  	}
   159  }
   160  
   161  func TestGoString(t *testing.T) {
   162  	for _, test := range testGraphs {
   163  		gosyntax := Graph(test.g).GoString()
   164  		if gosyntax != test.bin {
   165  			t.Errorf("unexpected graph string: got:%s want:%s", gosyntax, test.bin)
   166  		}
   167  	}
   168  }
   169  
   170  func TestGraph(t *testing.T) {
   171  	for _, test := range testGraphs {
   172  		g := Graph(test.g)
   173  		if !IsValid(g) {
   174  			t.Errorf("unexpected invalid graph %q", g)
   175  		}
   176  		nodes := g.Nodes()
   177  		if nodes.Len() != len(test.want) {
   178  			t.Errorf("unexpected graph n: got:%d want:%d", nodes.Len(), len(test.want))
   179  		}
   180  		got := make([]set, nodes.Len())
   181  		for nodes.Next() {
   182  			n := nodes.Node()
   183  			got[n.ID()] = linksTo(graph.NodesOf(g.From(n.ID()))...)
   184  		}
   185  		if !reflect.DeepEqual(got, test.want) {
   186  			t.Errorf("unexpected graph: got:%v want:%v", got, test.want)
   187  		}
   188  		for i, s := range got {
   189  			f := g.From(int64(i)).Len()
   190  			if f != len(s) {
   191  				t.Errorf("unexpected number of nodes from %d: got:%d want:%d", i, f, len(s))
   192  			}
   193  		}
   194  
   195  		dst := simple.NewUndirectedGraph()
   196  		graph.Copy(dst, g)
   197  		enc := Encode(dst)
   198  		if enc != g {
   199  			t.Errorf("unexpected round trip: got:%q want:%q", enc, g)
   200  		}
   201  	}
   202  }
   203  
   204  type set map[int]struct{}
   205  
   206  func linksToInt(nodes ...int) map[int]struct{} {
   207  	s := make(map[int]struct{})
   208  	for _, n := range nodes {
   209  		s[n] = struct{}{}
   210  	}
   211  	return s
   212  }
   213  
   214  func linksTo(nodes ...graph.Node) map[int]struct{} {
   215  	s := make(map[int]struct{})
   216  	for _, n := range nodes {
   217  		s[int(n.ID())] = struct{}{}
   218  	}
   219  	return s
   220  }
   221  
   222  func TestLargeEncoding(t *testing.T) {
   223  	for _, l := range []int{
   224  		50, 60, 70, 80, 100, 1e4,
   225  	} {
   226  		g6 := Encode(implicitCycle(l))
   227  		if !IsValid(g6) {
   228  			t.Errorf("graph6-encoding unexpectedly invalid: %v", g6)
   229  		}
   230  		for i, b := range []byte(g6) {
   231  			if b < 63 || 126 < b {
   232  				t.Errorf("graph6-encoding contains invalid character at %d: %q", i, b)
   233  			}
   234  		}
   235  	}
   236  }
   237  
   238  type implicitCycle int32
   239  
   240  func (i implicitCycle) Node(id int64) graph.Node {
   241  	if id < int64(i) {
   242  		return node(id)
   243  	}
   244  	return nil
   245  }
   246  func (i implicitCycle) Nodes() graph.Nodes {
   247  	return iterator.NewImplicitNodes(0, int(i), func(id int) graph.Node { return node(id) })
   248  }
   249  func (i implicitCycle) From(id int64) graph.Nodes {
   250  	if i < 2 {
   251  		return graph.Empty
   252  	}
   253  	// This is not a valid undirected cycle, but it gets bits
   254  	// into the routine for testing and that is all we care about.
   255  	next := int(id+1) % int(i)
   256  	return iterator.NewImplicitNodes(next, next+1, func(id int) graph.Node { return node(id) })
   257  }
   258  func (i implicitCycle) HasEdgeBetween(xid, yid int64) bool { return false }
   259  func (i implicitCycle) Edge(xid, yid int64) graph.Edge     { return nil }
   260  
   261  type node int32
   262  
   263  func (n node) ID() int64 { return int64(n) }