github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/traverse/traverse_test.go (about)

     1  // Copyright ©2015 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 traverse
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"sort"
    11  	"testing"
    12  
    13  	"github.com/jingcheng-WU/gonum/graph"
    14  	"github.com/jingcheng-WU/gonum/graph/graphs/gen"
    15  	"github.com/jingcheng-WU/gonum/graph/internal/ordered"
    16  	"github.com/jingcheng-WU/gonum/graph/simple"
    17  )
    18  
    19  var (
    20  	// batageljZaversnikGraph is the example graph from
    21  	// figure 1 of http://arxiv.org/abs/cs/0310049v1
    22  	batageljZaversnikGraph = []intset{
    23  		0: nil,
    24  
    25  		1: linksTo(2, 3),
    26  		2: linksTo(4),
    27  		3: linksTo(4),
    28  		4: linksTo(5),
    29  		5: nil,
    30  
    31  		6:  linksTo(7, 8, 14),
    32  		7:  linksTo(8, 11, 12, 14),
    33  		8:  linksTo(14),
    34  		9:  linksTo(11),
    35  		10: linksTo(11),
    36  		11: linksTo(12),
    37  		12: linksTo(18),
    38  		13: linksTo(14, 15),
    39  		14: linksTo(15, 17),
    40  		15: linksTo(16, 17),
    41  		16: nil,
    42  		17: linksTo(18, 19, 20),
    43  		18: linksTo(19, 20),
    44  		19: linksTo(20),
    45  		20: nil,
    46  	}
    47  
    48  	// wpBronKerboschGraph is the example given in the Bron-Kerbosch article on wikipedia (renumbered).
    49  	// http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858
    50  	wpBronKerboschGraph = []intset{
    51  		0: linksTo(1, 4),
    52  		1: linksTo(2, 4),
    53  		2: linksTo(3),
    54  		3: linksTo(4, 5),
    55  		4: nil,
    56  		5: nil,
    57  	}
    58  )
    59  
    60  var breadthFirstTests = []struct {
    61  	g     []intset
    62  	from  graph.Node
    63  	edge  func(graph.Edge) bool
    64  	until func(graph.Node, int) bool
    65  	final map[graph.Node]bool
    66  	want  [][]int64
    67  }{
    68  	{
    69  		g:     wpBronKerboschGraph,
    70  		from:  simple.Node(1),
    71  		final: map[graph.Node]bool{nil: true},
    72  		want: [][]int64{
    73  			{1},
    74  			{0, 2, 4},
    75  			{3},
    76  			{5},
    77  		},
    78  	},
    79  	{
    80  		g: wpBronKerboschGraph,
    81  		edge: func(e graph.Edge) bool {
    82  			// Do not traverse an edge between 3 and 5.
    83  			return (e.From().ID() != 3 || e.To().ID() != 5) && (e.From().ID() != 5 || e.To().ID() != 3)
    84  		},
    85  		from:  simple.Node(1),
    86  		final: map[graph.Node]bool{nil: true},
    87  		want: [][]int64{
    88  			{1},
    89  			{0, 2, 4},
    90  			{3},
    91  		},
    92  	},
    93  	{
    94  		g:     wpBronKerboschGraph,
    95  		from:  simple.Node(1),
    96  		until: func(n graph.Node, _ int) bool { return n == simple.Node(3) },
    97  		final: map[graph.Node]bool{simple.Node(3): true},
    98  		want: [][]int64{
    99  			{1},
   100  			{0, 2, 4},
   101  		},
   102  	},
   103  	{
   104  		g:     batageljZaversnikGraph,
   105  		from:  simple.Node(13),
   106  		final: map[graph.Node]bool{nil: true},
   107  		want: [][]int64{
   108  			{13},
   109  			{14, 15},
   110  			{6, 7, 8, 16, 17},
   111  			{11, 12, 18, 19, 20},
   112  			{9, 10},
   113  		},
   114  	},
   115  	{
   116  		g:     batageljZaversnikGraph,
   117  		from:  simple.Node(13),
   118  		until: func(_ graph.Node, d int) bool { return d > 2 },
   119  		final: map[graph.Node]bool{
   120  			simple.Node(11): true,
   121  			simple.Node(12): true,
   122  			simple.Node(18): true,
   123  			simple.Node(19): true,
   124  			simple.Node(20): true,
   125  		},
   126  		want: [][]int64{
   127  			{13},
   128  			{14, 15},
   129  			{6, 7, 8, 16, 17},
   130  		},
   131  	},
   132  }
   133  
   134  func TestBreadthFirst(t *testing.T) {
   135  	for i, test := range breadthFirstTests {
   136  		g := simple.NewUndirectedGraph()
   137  		for u, e := range test.g {
   138  			// Add nodes that are not defined by an edge.
   139  			if g.Node(int64(u)) == nil {
   140  				g.AddNode(simple.Node(u))
   141  			}
   142  			for v := range e {
   143  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
   144  			}
   145  		}
   146  		w := BreadthFirst{
   147  			Traverse: test.edge,
   148  		}
   149  		var got [][]int64
   150  		final := w.Walk(g, test.from, func(n graph.Node, d int) bool {
   151  			if test.until != nil && test.until(n, d) {
   152  				return true
   153  			}
   154  			if d >= len(got) {
   155  				got = append(got, []int64(nil))
   156  			}
   157  			got[d] = append(got[d], n.ID())
   158  			return false
   159  		})
   160  		if !test.final[final] {
   161  			t.Errorf("unexepected final node for test %d:\ngot:  %v\nwant: %v", i, final, test.final)
   162  		}
   163  		for _, l := range got {
   164  			sort.Sort(ordered.Int64s(l))
   165  		}
   166  		if !reflect.DeepEqual(got, test.want) {
   167  			t.Errorf("unexepected BFS level structure for test %d:\ngot:  %v\nwant: %v", i, got, test.want)
   168  		}
   169  	}
   170  }
   171  
   172  var depthFirstTests = []struct {
   173  	g     []intset
   174  	from  graph.Node
   175  	edge  func(graph.Edge) bool
   176  	until func(graph.Node) bool
   177  	final map[graph.Node]bool
   178  	want  []int64
   179  }{
   180  	{
   181  		g:     wpBronKerboschGraph,
   182  		from:  simple.Node(1),
   183  		final: map[graph.Node]bool{nil: true},
   184  		want:  []int64{0, 1, 2, 3, 4, 5},
   185  	},
   186  	{
   187  		g: wpBronKerboschGraph,
   188  		edge: func(e graph.Edge) bool {
   189  			// Do not traverse an edge between 3 and 5.
   190  			return (e.From().ID() != 3 || e.To().ID() != 5) && (e.From().ID() != 5 || e.To().ID() != 3)
   191  		},
   192  		from:  simple.Node(1),
   193  		final: map[graph.Node]bool{nil: true},
   194  		want:  []int64{0, 1, 2, 3, 4},
   195  	},
   196  	{
   197  		g:     wpBronKerboschGraph,
   198  		from:  simple.Node(1),
   199  		until: func(n graph.Node) bool { return n == simple.Node(3) },
   200  		final: map[graph.Node]bool{simple.Node(3): true},
   201  	},
   202  	{
   203  		g:     batageljZaversnikGraph,
   204  		from:  simple.Node(0),
   205  		final: map[graph.Node]bool{nil: true},
   206  		want:  []int64{0},
   207  	},
   208  	{
   209  		g:     batageljZaversnikGraph,
   210  		from:  simple.Node(3),
   211  		final: map[graph.Node]bool{nil: true},
   212  		want:  []int64{1, 2, 3, 4, 5},
   213  	},
   214  	{
   215  		g:     batageljZaversnikGraph,
   216  		from:  simple.Node(13),
   217  		final: map[graph.Node]bool{nil: true},
   218  		want:  []int64{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
   219  	},
   220  }
   221  
   222  func TestDepthFirst(t *testing.T) {
   223  	for i, test := range depthFirstTests {
   224  		g := simple.NewUndirectedGraph()
   225  		for u, e := range test.g {
   226  			// Add nodes that are not defined by an edge.
   227  			if g.Node(int64(u)) == nil {
   228  				g.AddNode(simple.Node(u))
   229  			}
   230  			for v := range e {
   231  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
   232  			}
   233  		}
   234  		w := DepthFirst{
   235  			Traverse: test.edge,
   236  		}
   237  		var got []int64
   238  		final := w.Walk(g, test.from, func(n graph.Node) bool {
   239  			if test.until != nil && test.until(n) {
   240  				return true
   241  			}
   242  			got = append(got, n.ID())
   243  			return false
   244  		})
   245  		if !test.final[final] {
   246  			t.Errorf("unexepected final node for test %d:\ngot:  %v\nwant: %v", i, final, test.final)
   247  		}
   248  		sort.Sort(ordered.Int64s(got))
   249  		if test.want != nil && !reflect.DeepEqual(got, test.want) {
   250  			t.Errorf("unexepected DFS traversed nodes for test %d:\ngot:  %v\nwant: %v", i, got, test.want)
   251  		}
   252  	}
   253  }
   254  
   255  var walkAllTests = []struct {
   256  	g    []intset
   257  	edge func(graph.Edge) bool
   258  	want [][]int64
   259  }{
   260  	{
   261  		g: batageljZaversnikGraph,
   262  		want: [][]int64{
   263  			{0},
   264  			{1, 2, 3, 4, 5},
   265  			{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
   266  		},
   267  	},
   268  	{
   269  		g: batageljZaversnikGraph,
   270  		edge: func(e graph.Edge) bool {
   271  			// Do not traverse an edge between 3 and 5.
   272  			return (e.From().ID() != 4 || e.To().ID() != 5) && (e.From().ID() != 5 || e.To().ID() != 4)
   273  		},
   274  		want: [][]int64{
   275  			{0},
   276  			{1, 2, 3, 4},
   277  			{5},
   278  			{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
   279  		},
   280  	},
   281  }
   282  
   283  func TestWalkAll(t *testing.T) {
   284  	for i, test := range walkAllTests {
   285  		g := simple.NewUndirectedGraph()
   286  
   287  		for u, e := range test.g {
   288  			if g.Node(int64(u)) == nil {
   289  				g.AddNode(simple.Node(u))
   290  			}
   291  			for v := range e {
   292  				if g.Node(int64(v)) == nil {
   293  					g.AddNode(simple.Node(v))
   294  				}
   295  				g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
   296  			}
   297  		}
   298  		type walker interface {
   299  			WalkAll(g graph.Undirected, before, after func(), during func(graph.Node))
   300  		}
   301  		for _, w := range []walker{
   302  			&BreadthFirst{},
   303  			&DepthFirst{},
   304  		} {
   305  			var (
   306  				c  []graph.Node
   307  				cc [][]graph.Node
   308  			)
   309  			switch w := w.(type) {
   310  			case *BreadthFirst:
   311  				w.Traverse = test.edge
   312  			case *DepthFirst:
   313  				w.Traverse = test.edge
   314  			default:
   315  				panic(fmt.Sprintf("bad walker type: %T", w))
   316  			}
   317  			during := func(n graph.Node) {
   318  				c = append(c, n)
   319  			}
   320  			after := func() {
   321  				cc = append(cc, []graph.Node(nil))
   322  				cc[len(cc)-1] = append(cc[len(cc)-1], c...)
   323  				c = c[:0]
   324  			}
   325  			w.WalkAll(g, nil, after, during)
   326  
   327  			got := make([][]int64, len(cc))
   328  			for j, c := range cc {
   329  				ids := make([]int64, len(c))
   330  				for k, n := range c {
   331  					ids[k] = n.ID()
   332  				}
   333  				sort.Sort(ordered.Int64s(ids))
   334  				got[j] = ids
   335  			}
   336  			sort.Sort(ordered.BySliceValues(got))
   337  			if !reflect.DeepEqual(got, test.want) {
   338  				t.Errorf("unexpected connected components for test %d using %T:\ngot: %v\nwant:%v", i, w, got, test.want)
   339  			}
   340  		}
   341  	}
   342  }
   343  
   344  // intset is an integer set.
   345  type intset map[int]struct{}
   346  
   347  func linksTo(i ...int) intset {
   348  	if len(i) == 0 {
   349  		return nil
   350  	}
   351  	s := make(intset)
   352  	for _, v := range i {
   353  		s[v] = struct{}{}
   354  	}
   355  	return s
   356  }
   357  
   358  var (
   359  	gnpUndirected_10_tenth   = gnpUndirected(10, 0.1)
   360  	gnpUndirected_100_tenth  = gnpUndirected(100, 0.1)
   361  	gnpUndirected_1000_tenth = gnpUndirected(1000, 0.1)
   362  	gnpUndirected_10_half    = gnpUndirected(10, 0.5)
   363  	gnpUndirected_100_half   = gnpUndirected(100, 0.5)
   364  	gnpUndirected_1000_half  = gnpUndirected(1000, 0.5)
   365  )
   366  
   367  func gnpUndirected(n int, p float64) graph.Undirected {
   368  	g := simple.NewUndirectedGraph()
   369  	err := gen.Gnp(g, n, p, nil)
   370  	if err != nil {
   371  		panic(fmt.Sprintf("traverse: bad test: %v", err))
   372  	}
   373  	return g
   374  }
   375  
   376  func benchmarkWalkAllBreadthFirst(b *testing.B, g graph.Undirected) {
   377  	n := g.Nodes().Len()
   378  	b.ResetTimer()
   379  	var bft BreadthFirst
   380  	for i := 0; i < b.N; i++ {
   381  		bft.WalkAll(g, nil, nil, nil)
   382  	}
   383  	if len(bft.visited) != n {
   384  		b.Fatalf("unexpected number of nodes visited: want: %d got %d", n, len(bft.visited))
   385  	}
   386  }
   387  
   388  func BenchmarkWalkAllBreadthFirstGnp_10_tenth(b *testing.B) {
   389  	benchmarkWalkAllBreadthFirst(b, gnpUndirected_10_tenth)
   390  }
   391  func BenchmarkWalkAllBreadthFirstGnp_100_tenth(b *testing.B) {
   392  	benchmarkWalkAllBreadthFirst(b, gnpUndirected_100_tenth)
   393  }
   394  func BenchmarkWalkAllBreadthFirstGnp_1000_tenth(b *testing.B) {
   395  	benchmarkWalkAllBreadthFirst(b, gnpUndirected_1000_tenth)
   396  }
   397  func BenchmarkWalkAllBreadthFirstGnp_10_half(b *testing.B) {
   398  	benchmarkWalkAllBreadthFirst(b, gnpUndirected_10_half)
   399  }
   400  func BenchmarkWalkAllBreadthFirstGnp_100_half(b *testing.B) {
   401  	benchmarkWalkAllBreadthFirst(b, gnpUndirected_100_half)
   402  }
   403  func BenchmarkWalkAllBreadthFirstGnp_1000_half(b *testing.B) {
   404  	benchmarkWalkAllBreadthFirst(b, gnpUndirected_1000_half)
   405  }
   406  
   407  func benchmarkWalkAllDepthFirst(b *testing.B, g graph.Undirected) {
   408  	n := g.Nodes().Len()
   409  	b.ResetTimer()
   410  	var dft DepthFirst
   411  	for i := 0; i < b.N; i++ {
   412  		dft.WalkAll(g, nil, nil, nil)
   413  	}
   414  	if len(dft.visited) != n {
   415  		b.Fatalf("unexpected number of nodes visited: want: %d got %d", n, len(dft.visited))
   416  	}
   417  }
   418  
   419  func BenchmarkWalkAllDepthFirstGnp_10_tenth(b *testing.B) {
   420  	benchmarkWalkAllDepthFirst(b, gnpUndirected_10_tenth)
   421  }
   422  func BenchmarkWalkAllDepthFirstGnp_100_tenth(b *testing.B) {
   423  	benchmarkWalkAllDepthFirst(b, gnpUndirected_100_tenth)
   424  }
   425  func BenchmarkWalkAllDepthFirstGnp_1000_tenth(b *testing.B) {
   426  	benchmarkWalkAllDepthFirst(b, gnpUndirected_1000_tenth)
   427  }
   428  func BenchmarkWalkAllDepthFirstGnp_10_half(b *testing.B) {
   429  	benchmarkWalkAllDepthFirst(b, gnpUndirected_10_half)
   430  }
   431  func BenchmarkWalkAllDepthFirstGnp_100_half(b *testing.B) {
   432  	benchmarkWalkAllDepthFirst(b, gnpUndirected_100_half)
   433  }
   434  func BenchmarkWalkAllDepthFirstGnp_1000_half(b *testing.B) {
   435  	benchmarkWalkAllDepthFirst(b, gnpUndirected_1000_half)
   436  }