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 }