gonum.org/v1/gonum@v0.14.0/graph/topo/topo_test.go (about)

     1  // Copyright ©2014 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 topo
     6  
     7  import (
     8  	"reflect"
     9  	"testing"
    10  
    11  	"gonum.org/v1/gonum/graph"
    12  	"gonum.org/v1/gonum/graph/internal/ordered"
    13  	"gonum.org/v1/gonum/graph/simple"
    14  )
    15  
    16  func TestIsPath(t *testing.T) {
    17  	dg := simple.NewDirectedGraph()
    18  	if !IsPathIn(dg, nil) {
    19  		t.Error("IsPath returns false on nil path")
    20  	}
    21  	p := []graph.Node{simple.Node(0)}
    22  	if IsPathIn(dg, p) {
    23  		t.Error("IsPath returns true on nonexistent node")
    24  	}
    25  	dg.AddNode(p[0])
    26  	if !IsPathIn(dg, p) {
    27  		t.Error("IsPath returns false on single-length path with existing node")
    28  	}
    29  	p = append(p, simple.Node(1))
    30  	dg.AddNode(p[1])
    31  	if IsPathIn(dg, p) {
    32  		t.Error("IsPath returns true on bad path of length 2")
    33  	}
    34  	dg.SetEdge(simple.Edge{F: p[0], T: p[1]})
    35  	if !IsPathIn(dg, p) {
    36  		t.Error("IsPath returns false on correct path of length 2")
    37  	}
    38  	p[0], p[1] = p[1], p[0]
    39  	if IsPathIn(dg, p) {
    40  		t.Error("IsPath erroneously returns true for a reverse path")
    41  	}
    42  	p = []graph.Node{p[1], p[0], simple.Node(2)}
    43  	dg.SetEdge(simple.Edge{F: p[1], T: p[2]})
    44  	if !IsPathIn(dg, p) {
    45  		t.Error("IsPath does not find a correct path for path > 2 nodes")
    46  	}
    47  	ug := simple.NewUndirectedGraph()
    48  	ug.SetEdge(simple.Edge{F: p[1], T: p[0]})
    49  	ug.SetEdge(simple.Edge{F: p[1], T: p[2]})
    50  	if !IsPathIn(dg, p) {
    51  		t.Error("IsPath does not correctly account for undirected behavior")
    52  	}
    53  }
    54  
    55  var pathExistsInUndirectedTests = []struct {
    56  	g        []intset
    57  	from, to int
    58  	want     bool
    59  }{
    60  	{g: batageljZaversnikGraph, from: 0, to: 0, want: true},
    61  	{g: batageljZaversnikGraph, from: 0, to: 1, want: false},
    62  	{g: batageljZaversnikGraph, from: 1, to: 2, want: true},
    63  	{g: batageljZaversnikGraph, from: 2, to: 1, want: true},
    64  	{g: batageljZaversnikGraph, from: 2, to: 12, want: false},
    65  	{g: batageljZaversnikGraph, from: 20, to: 6, want: true},
    66  }
    67  
    68  func TestPathExistsInUndirected(t *testing.T) {
    69  	for i, test := range pathExistsInUndirectedTests {
    70  		g := simple.NewUndirectedGraph()
    71  
    72  		for u, e := range test.g {
    73  			if g.Node(int64(u)) == nil {
    74  				g.AddNode(simple.Node(u))
    75  			}
    76  			for v := range e {
    77  				if g.Node(v) == nil {
    78  					g.AddNode(simple.Node(v))
    79  				}
    80  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
    81  			}
    82  		}
    83  
    84  		got := PathExistsIn(g, simple.Node(test.from), simple.Node(test.to))
    85  		if got != test.want {
    86  			t.Errorf("unexpected result for path existence in test %d: got:%t want %t", i, got, test.want)
    87  		}
    88  	}
    89  }
    90  
    91  var pathExistsInDirectedTests = []struct {
    92  	g        []intset
    93  	from, to int
    94  	want     bool
    95  }{
    96  	// The graph definition is such that from node IDs are
    97  	// less than to node IDs.
    98  	{g: batageljZaversnikGraph, from: 0, to: 0, want: true},
    99  	{g: batageljZaversnikGraph, from: 0, to: 1, want: false},
   100  	{g: batageljZaversnikGraph, from: 1, to: 2, want: true},
   101  	{g: batageljZaversnikGraph, from: 2, to: 1, want: false},
   102  	{g: batageljZaversnikGraph, from: 2, to: 12, want: false},
   103  	{g: batageljZaversnikGraph, from: 20, to: 6, want: false},
   104  	{g: batageljZaversnikGraph, from: 6, to: 20, want: true},
   105  }
   106  
   107  func TestPathExistsInDirected(t *testing.T) {
   108  	for i, test := range pathExistsInDirectedTests {
   109  		g := simple.NewDirectedGraph()
   110  
   111  		for u, e := range test.g {
   112  			if g.Node(int64(u)) == nil {
   113  				g.AddNode(simple.Node(u))
   114  			}
   115  			for v := range e {
   116  				if g.Node(v) == nil {
   117  					g.AddNode(simple.Node(v))
   118  				}
   119  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
   120  			}
   121  		}
   122  
   123  		got := PathExistsIn(g, simple.Node(test.from), simple.Node(test.to))
   124  		if got != test.want {
   125  			t.Errorf("unexpected result for path existence in test %d: got:%t want %t", i, got, test.want)
   126  		}
   127  	}
   128  }
   129  
   130  var connectedComponentTests = []struct {
   131  	g    []intset
   132  	want [][]int64
   133  }{
   134  	{
   135  		g: batageljZaversnikGraph,
   136  		want: [][]int64{
   137  			{0},
   138  			{1, 2, 3, 4, 5},
   139  			{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
   140  		},
   141  	},
   142  }
   143  
   144  func TestConnectedComponents(t *testing.T) {
   145  	for i, test := range connectedComponentTests {
   146  		g := simple.NewUndirectedGraph()
   147  
   148  		for u, e := range test.g {
   149  			if g.Node(int64(u)) == nil {
   150  				g.AddNode(simple.Node(u))
   151  			}
   152  			for v := range e {
   153  				if g.Node(v) == nil {
   154  					g.AddNode(simple.Node(v))
   155  				}
   156  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
   157  			}
   158  		}
   159  		cc := ConnectedComponents(g)
   160  		got := make([][]int64, len(cc))
   161  		for j, c := range cc {
   162  			ids := make([]int64, len(c))
   163  			for k, n := range c {
   164  				ids[k] = n.ID()
   165  			}
   166  			ordered.Int64s(ids)
   167  			got[j] = ids
   168  		}
   169  		ordered.BySliceValues(got)
   170  		if !reflect.DeepEqual(got, test.want) {
   171  			t.Errorf("unexpected connected components for test %d %T:\ngot: %v\nwant:%v", i, g, got, test.want)
   172  		}
   173  	}
   174  }
   175  
   176  var equalTests = []struct {
   177  	name string
   178  	a, b graph.Graph
   179  	want bool
   180  }{
   181  	{name: "empty g=g", a: simple.NewUndirectedGraph(), b: simple.NewUndirectedGraph(), want: true},
   182  	{name: "empty dg=dg", a: simple.NewDirectedGraph(), b: simple.NewDirectedGraph(), want: true},
   183  	{name: "empty g=dg", a: simple.NewUndirectedGraph(), b: simple.NewDirectedGraph(), want: true},
   184  
   185  	{
   186  		name: "1 g=g", want: true,
   187  		a: addNodes(simple.NewUndirectedGraph(), simple.Node(1)),
   188  		b: addNodes(simple.NewUndirectedGraph(), simple.Node(1)),
   189  	},
   190  	{
   191  		name: "1 dg=dg", want: true,
   192  		a: addNodes(simple.NewDirectedGraph(), simple.Node(1)),
   193  		b: addNodes(simple.NewDirectedGraph(), simple.Node(1)),
   194  	},
   195  	{
   196  		name: "1 g=dg", want: true,
   197  		a: addNodes(simple.NewUndirectedGraph(), simple.Node(1)),
   198  		b: addNodes(simple.NewDirectedGraph(), simple.Node(1)),
   199  	},
   200  
   201  	{
   202  		name: "0/1 g≠g", want: false,
   203  		a: simple.NewUndirectedGraph(),
   204  		b: addNodes(simple.NewUndirectedGraph(), simple.Node(1)),
   205  	},
   206  	{
   207  		name: "0/1 dg≠dg", want: false,
   208  		a: simple.NewDirectedGraph(),
   209  		b: addNodes(simple.NewDirectedGraph(), simple.Node(1)),
   210  	},
   211  	{
   212  		name: "0/1 g≠dg", want: false,
   213  		a: simple.NewUndirectedGraph(),
   214  		b: addNodes(simple.NewDirectedGraph(), simple.Node(1)),
   215  	},
   216  	{
   217  		name: "0/1 g≠dg", want: false,
   218  		a: addNodes(simple.NewUndirectedGraph(), simple.Node(1)),
   219  		b: simple.NewDirectedGraph(),
   220  	},
   221  
   222  	{
   223  		name: "1 g≠g", want: false,
   224  		a: addNodes(simple.NewUndirectedGraph(), simple.Node(0)),
   225  		b: addNodes(simple.NewUndirectedGraph(), simple.Node(1)),
   226  	},
   227  	{
   228  		name: "1 dg≠dg", want: false,
   229  		a: addNodes(simple.NewDirectedGraph(), simple.Node(0)),
   230  		b: addNodes(simple.NewDirectedGraph(), simple.Node(1)),
   231  	},
   232  	{
   233  		name: "1 g≠dg", want: false,
   234  		a: addNodes(simple.NewUndirectedGraph(), simple.Node(0)),
   235  		b: addNodes(simple.NewDirectedGraph(), simple.Node(1)),
   236  	},
   237  
   238  	{
   239  		name: "box g=g", want: true,
   240  		a: setEdges(simple.NewUndirectedGraph(),
   241  			simple.Edge{F: simple.Node(0), T: simple.Node(1)},
   242  			simple.Edge{F: simple.Node(1), T: simple.Node(2)},
   243  			simple.Edge{F: simple.Node(2), T: simple.Node(3)},
   244  			simple.Edge{F: simple.Node(3), T: simple.Node(0)},
   245  		),
   246  		b: setEdges(simple.NewUndirectedGraph(),
   247  			simple.Edge{F: simple.Node(3), T: simple.Node(0)},
   248  			simple.Edge{F: simple.Node(0), T: simple.Node(1)},
   249  			simple.Edge{F: simple.Node(1), T: simple.Node(2)},
   250  			simple.Edge{F: simple.Node(2), T: simple.Node(3)},
   251  		),
   252  	},
   253  	{
   254  		name: "box dg=dg", want: true,
   255  		a: setEdges(simple.NewDirectedGraph(),
   256  			simple.Edge{F: simple.Node(0), T: simple.Node(1)},
   257  			simple.Edge{F: simple.Node(1), T: simple.Node(2)},
   258  			simple.Edge{F: simple.Node(2), T: simple.Node(3)},
   259  			simple.Edge{F: simple.Node(3), T: simple.Node(0)},
   260  		),
   261  		b: setEdges(simple.NewDirectedGraph(),
   262  			simple.Edge{F: simple.Node(3), T: simple.Node(0)},
   263  			simple.Edge{F: simple.Node(0), T: simple.Node(1)},
   264  			simple.Edge{F: simple.Node(1), T: simple.Node(2)},
   265  			simple.Edge{F: simple.Node(2), T: simple.Node(3)},
   266  		),
   267  	},
   268  	{
   269  		name: "box reversed dg≠dg", want: false,
   270  		a: setEdges(simple.NewDirectedGraph(),
   271  			simple.Edge{F: simple.Node(0), T: simple.Node(1)},
   272  			simple.Edge{F: simple.Node(1), T: simple.Node(2)},
   273  			simple.Edge{F: simple.Node(2), T: simple.Node(3)},
   274  			simple.Edge{F: simple.Node(3), T: simple.Node(0)},
   275  		),
   276  		b: setEdges(simple.NewDirectedGraph(),
   277  			simple.Edge{F: simple.Node(1), T: simple.Node(0)},
   278  			simple.Edge{F: simple.Node(2), T: simple.Node(1)},
   279  			simple.Edge{F: simple.Node(3), T: simple.Node(2)},
   280  			simple.Edge{F: simple.Node(0), T: simple.Node(3)},
   281  		),
   282  	},
   283  	{
   284  		name: "box g=dg", want: true,
   285  		a: setEdges(simple.NewUndirectedGraph(),
   286  			simple.Edge{F: simple.Node(0), T: simple.Node(1)},
   287  			simple.Edge{F: simple.Node(1), T: simple.Node(2)},
   288  			simple.Edge{F: simple.Node(2), T: simple.Node(3)},
   289  			simple.Edge{F: simple.Node(3), T: simple.Node(0)},
   290  		),
   291  		b: setEdges(simple.NewDirectedGraph(),
   292  			simple.Edge{F: simple.Node(0), T: simple.Node(1)},
   293  			simple.Edge{F: simple.Node(1), T: simple.Node(0)},
   294  			simple.Edge{F: simple.Node(1), T: simple.Node(2)},
   295  			simple.Edge{F: simple.Node(2), T: simple.Node(3)},
   296  			simple.Edge{F: simple.Node(2), T: simple.Node(1)},
   297  			simple.Edge{F: simple.Node(3), T: simple.Node(2)},
   298  			simple.Edge{F: simple.Node(3), T: simple.Node(0)},
   299  			simple.Edge{F: simple.Node(0), T: simple.Node(3)},
   300  		),
   301  	},
   302  }
   303  
   304  func TestEqual(t *testing.T) {
   305  	for _, test := range equalTests {
   306  		if got := Equal(test.a, test.b); got != test.want {
   307  			t.Errorf("unexpected result for %q equality test: got:%t want:%t", test.name, got, test.want)
   308  		}
   309  		if got := Equal(plainGraph{test.a}, plainGraph{test.b}); got != test.want {
   310  			t.Errorf("unexpected result for %q equality test with filtered method set: got:%t want:%t", test.name, got, test.want)
   311  		}
   312  	}
   313  }
   314  
   315  type plainGraph struct {
   316  	graph.Graph
   317  }
   318  
   319  type builder interface {
   320  	graph.Graph
   321  	graph.Builder
   322  }
   323  
   324  func addNodes(dst builder, nodes ...graph.Node) builder {
   325  	for _, n := range nodes {
   326  		dst.AddNode(n)
   327  	}
   328  	return dst
   329  }
   330  
   331  func setEdges(dst builder, edges ...graph.Edge) builder {
   332  	for _, e := range edges {
   333  		dst.SetEdge(e)
   334  	}
   335  	return dst
   336  }