github.com/gopherd/gonum@v0.0.4/graph/simple/densegraph_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 simple_test 6 7 import ( 8 "math" 9 "testing" 10 11 "math/rand" 12 13 "github.com/gopherd/gonum/graph" 14 "github.com/gopherd/gonum/graph/internal/ordered" 15 "github.com/gopherd/gonum/graph/internal/set" 16 "github.com/gopherd/gonum/graph/simple" 17 "github.com/gopherd/gonum/graph/testgraph" 18 ) 19 20 func isZeroContiguousSet(nodes []graph.Node) bool { 21 t := make([]graph.Node, len(nodes)) 22 copy(t, nodes) 23 nodes = t 24 ordered.ByID(nodes) 25 for i, n := range nodes { 26 if int64(i) != n.ID() { 27 return false 28 } 29 } 30 return true 31 } 32 33 func directedMatrixBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { 34 if len(nodes) == 0 { 35 return 36 } 37 if !isZeroContiguousSet(nodes) { 38 return 39 } 40 seen := set.NewNodes() 41 dg := simple.NewDirectedMatrix(len(nodes), absent, self, absent) 42 for i := range nodes { 43 seen.Add(simple.Node(i)) 44 } 45 for _, edge := range edges { 46 if edge.From().ID() == edge.To().ID() { 47 continue 48 } 49 if !seen.Has(edge.From()) || !seen.Has(edge.To()) { 50 continue 51 } 52 ce := simple.WeightedEdge{F: dg.Node(edge.From().ID()), T: dg.Node(edge.To().ID()), W: edge.Weight()} 53 e = append(e, ce) 54 dg.SetWeightedEdge(ce) 55 } 56 if len(e) == 0 && len(edges) != 0 { 57 return nil, nil, nil, math.NaN(), math.NaN(), false 58 } 59 n = make([]graph.Node, 0, len(seen)) 60 for _, sn := range seen { 61 n = append(n, sn) 62 } 63 return dg, n, e, self, absent, true 64 } 65 66 func TestDirectedMatrix(t *testing.T) { 67 t.Run("AdjacencyMatrix", func(t *testing.T) { 68 testgraph.AdjacencyMatrix(t, directedMatrixBuilder) 69 }) 70 t.Run("EdgeExistence", func(t *testing.T) { 71 testgraph.EdgeExistence(t, directedMatrixBuilder, reversesEdges) 72 }) 73 t.Run("NodeExistence", func(t *testing.T) { 74 testgraph.NodeExistence(t, directedMatrixBuilder) 75 }) 76 t.Run("ReturnAdjacentNodes", func(t *testing.T) { 77 testgraph.ReturnAdjacentNodes(t, directedMatrixBuilder, usesEmpty, reversesEdges) 78 }) 79 t.Run("ReturnAllEdges", func(t *testing.T) { 80 testgraph.ReturnAllEdges(t, directedMatrixBuilder, usesEmpty) 81 }) 82 t.Run("ReturnAllNodes", func(t *testing.T) { 83 testgraph.ReturnAllNodes(t, directedMatrixBuilder, usesEmpty) 84 }) 85 t.Run("ReturnAllWeightedEdges", func(t *testing.T) { 86 testgraph.ReturnAllWeightedEdges(t, directedMatrixBuilder, usesEmpty) 87 }) 88 t.Run("ReturnEdgeSlice", func(t *testing.T) { 89 testgraph.ReturnEdgeSlice(t, directedMatrixBuilder, usesEmpty) 90 }) 91 t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { 92 testgraph.ReturnWeightedEdgeSlice(t, directedMatrixBuilder, usesEmpty) 93 }) 94 t.Run("ReturnNodeSlice", func(t *testing.T) { 95 testgraph.ReturnNodeSlice(t, directedMatrixBuilder, usesEmpty) 96 }) 97 t.Run("Weight", func(t *testing.T) { 98 testgraph.Weight(t, directedMatrixBuilder) 99 }) 100 101 t.Run("AddEdges", func(t *testing.T) { 102 testgraph.AddEdges(t, 100, 103 newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)}, 104 func(id int64) graph.Node { return simple.Node(id) }, 105 false, // Cannot set self-loops. 106 false, // Cannot update nodes. 107 ) 108 }) 109 t.Run("NoLoopAddEdges", func(t *testing.T) { 110 testgraph.NoLoopAddEdges(t, 100, 111 newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)}, 112 func(id int64) graph.Node { return simple.Node(id) }, 113 ) 114 }) 115 t.Run("AddWeightedEdges", func(t *testing.T) { 116 testgraph.AddWeightedEdges(t, 100, 117 newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)}, 118 0.5, 119 func(id int64) graph.Node { return simple.Node(id) }, 120 false, // Cannot set self-loops. 121 false, // Cannot update nodes. 122 ) 123 }) 124 t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { 125 testgraph.NoLoopAddWeightedEdges(t, 100, 126 newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)}, 127 0.5, 128 func(id int64) graph.Node { return simple.Node(id) }, 129 ) 130 }) 131 t.Run("RemoveEdges", func(t *testing.T) { 132 g := newEdgeShimDir{simple.NewDirectedMatrix(100, 0, 1, 0)} 133 rnd := rand.New(rand.NewSource(1)) 134 it := g.Nodes() 135 for it.Next() { 136 u := it.Node() 137 d := rnd.Intn(5) 138 vit := g.Nodes() 139 for d >= 0 && vit.Next() { 140 v := vit.Node() 141 if v.ID() == u.ID() { 142 continue 143 } 144 d-- 145 g.SetEdge(g.NewEdge(u, v)) 146 } 147 } 148 testgraph.RemoveEdges(t, g, g.Edges()) 149 }) 150 } 151 152 func directedMatrixFromBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { 153 if len(nodes) == 0 { 154 return 155 } 156 if !isZeroContiguousSet(nodes) { 157 return 158 } 159 seen := set.NewNodes() 160 dg := simple.NewDirectedMatrixFrom(nodes, absent, self, absent) 161 for _, n := range nodes { 162 seen.Add(n) 163 } 164 for _, edge := range edges { 165 if edge.From().ID() == edge.To().ID() { 166 continue 167 } 168 if !seen.Has(edge.From()) || !seen.Has(edge.To()) { 169 continue 170 } 171 ce := simple.WeightedEdge{F: dg.Node(edge.From().ID()), T: dg.Node(edge.To().ID()), W: edge.Weight()} 172 e = append(e, ce) 173 dg.SetWeightedEdge(ce) 174 } 175 if len(e) == 0 && len(edges) != 0 { 176 return nil, nil, nil, math.NaN(), math.NaN(), false 177 } 178 n = make([]graph.Node, 0, len(seen)) 179 for _, sn := range seen { 180 n = append(n, sn) 181 } 182 return dg, n, e, self, absent, true 183 } 184 185 func TestDirectedMatrixFrom(t *testing.T) { 186 t.Run("AdjacencyMatrix", func(t *testing.T) { 187 testgraph.AdjacencyMatrix(t, directedMatrixFromBuilder) 188 }) 189 t.Run("EdgeExistence", func(t *testing.T) { 190 testgraph.EdgeExistence(t, directedMatrixFromBuilder, reversesEdges) 191 }) 192 t.Run("NodeExistence", func(t *testing.T) { 193 testgraph.NodeExistence(t, directedMatrixFromBuilder) 194 }) 195 t.Run("ReturnAdjacentNodes", func(t *testing.T) { 196 testgraph.ReturnAdjacentNodes(t, directedMatrixFromBuilder, usesEmpty, reversesEdges) 197 }) 198 t.Run("ReturnAllEdges", func(t *testing.T) { 199 testgraph.ReturnAllEdges(t, directedMatrixFromBuilder, usesEmpty) 200 }) 201 t.Run("ReturnAllNodes", func(t *testing.T) { 202 testgraph.ReturnAllNodes(t, directedMatrixFromBuilder, usesEmpty) 203 }) 204 t.Run("ReturnAllWeightedEdges", func(t *testing.T) { 205 testgraph.ReturnAllWeightedEdges(t, directedMatrixFromBuilder, usesEmpty) 206 }) 207 t.Run("ReturnEdgeSlice", func(t *testing.T) { 208 testgraph.ReturnEdgeSlice(t, directedMatrixFromBuilder, usesEmpty) 209 }) 210 t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { 211 testgraph.ReturnWeightedEdgeSlice(t, directedMatrixFromBuilder, usesEmpty) 212 }) 213 t.Run("ReturnNodeSlice", func(t *testing.T) { 214 testgraph.ReturnNodeSlice(t, directedMatrixFromBuilder, usesEmpty) 215 }) 216 t.Run("Weight", func(t *testing.T) { 217 testgraph.Weight(t, directedMatrixFromBuilder) 218 }) 219 220 const numNodes = 100 221 222 t.Run("AddEdges", func(t *testing.T) { 223 testgraph.AddEdges(t, numNodes, 224 newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 225 func(id int64) graph.Node { return simple.Node(id) }, 226 false, // Cannot set self-loops. 227 true, // Can update nodes. 228 ) 229 }) 230 t.Run("NoLoopAddEdges", func(t *testing.T) { 231 testgraph.NoLoopAddEdges(t, numNodes, 232 newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 233 func(id int64) graph.Node { return simple.Node(id) }, 234 ) 235 }) 236 t.Run("AddWeightedEdges", func(t *testing.T) { 237 testgraph.AddWeightedEdges(t, numNodes, 238 newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 239 1, 240 func(id int64) graph.Node { return simple.Node(id) }, 241 false, // Cannot set self-loops. 242 true, // Can update nodes. 243 ) 244 }) 245 t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { 246 testgraph.NoLoopAddWeightedEdges(t, numNodes, 247 newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 248 1, 249 func(id int64) graph.Node { return simple.Node(id) }, 250 ) 251 }) 252 t.Run("RemoveEdges", func(t *testing.T) { 253 g := newEdgeShimDir{simple.NewDirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)} 254 rnd := rand.New(rand.NewSource(1)) 255 it := g.Nodes() 256 for it.Next() { 257 u := it.Node() 258 d := rnd.Intn(5) 259 vit := g.Nodes() 260 for d >= 0 && vit.Next() { 261 v := vit.Node() 262 if v.ID() == u.ID() { 263 continue 264 } 265 d-- 266 g.SetEdge(g.NewEdge(u, v)) 267 } 268 } 269 testgraph.RemoveEdges(t, g, g.Edges()) 270 }) 271 } 272 273 type newEdgeShimDir struct { 274 *simple.DirectedMatrix 275 } 276 277 func (g newEdgeShimDir) NewEdge(u, v graph.Node) graph.Edge { 278 return simple.Edge{F: u, T: v} 279 } 280 func (g newEdgeShimDir) NewWeightedEdge(u, v graph.Node, w float64) graph.WeightedEdge { 281 return simple.WeightedEdge{F: u, T: v, W: w} 282 } 283 284 func undirectedMatrixBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { 285 if len(nodes) == 0 { 286 return 287 } 288 if !isZeroContiguousSet(nodes) { 289 return 290 } 291 seen := set.NewNodes() 292 dg := simple.NewUndirectedMatrix(len(nodes), absent, self, absent) 293 for i := range nodes { 294 seen.Add(simple.Node(i)) 295 } 296 for _, edge := range edges { 297 if edge.From().ID() == edge.To().ID() { 298 continue 299 } 300 if !seen.Has(edge.From()) || !seen.Has(edge.To()) { 301 continue 302 } 303 ce := simple.WeightedEdge{F: dg.Node(edge.From().ID()), T: dg.Node(edge.To().ID()), W: edge.Weight()} 304 e = append(e, ce) 305 dg.SetWeightedEdge(ce) 306 } 307 if len(e) == 0 && len(edges) != 0 { 308 return nil, nil, nil, math.NaN(), math.NaN(), false 309 } 310 n = make([]graph.Node, 0, len(seen)) 311 for _, sn := range seen { 312 n = append(n, sn) 313 } 314 return dg, n, e, self, absent, true 315 } 316 317 func TestUnirectedMatrix(t *testing.T) { 318 t.Run("AdjacencyMatrix", func(t *testing.T) { 319 testgraph.AdjacencyMatrix(t, undirectedMatrixBuilder) 320 }) 321 t.Run("EdgeExistence", func(t *testing.T) { 322 testgraph.EdgeExistence(t, undirectedMatrixBuilder, reversesEdges) 323 }) 324 t.Run("NodeExistence", func(t *testing.T) { 325 testgraph.NodeExistence(t, undirectedMatrixBuilder) 326 }) 327 t.Run("ReturnAdjacentNodes", func(t *testing.T) { 328 testgraph.ReturnAdjacentNodes(t, undirectedMatrixBuilder, usesEmpty, reversesEdges) 329 }) 330 t.Run("ReturnAllEdges", func(t *testing.T) { 331 testgraph.ReturnAllEdges(t, undirectedMatrixBuilder, usesEmpty) 332 }) 333 t.Run("ReturnAllNodes", func(t *testing.T) { 334 testgraph.ReturnAllNodes(t, undirectedMatrixBuilder, usesEmpty) 335 }) 336 t.Run("ReturnAllWeightedEdges", func(t *testing.T) { 337 testgraph.ReturnAllWeightedEdges(t, undirectedMatrixBuilder, usesEmpty) 338 }) 339 t.Run("ReturnEdgeSlice", func(t *testing.T) { 340 testgraph.ReturnEdgeSlice(t, undirectedMatrixBuilder, usesEmpty) 341 }) 342 t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { 343 testgraph.ReturnWeightedEdgeSlice(t, undirectedMatrixBuilder, usesEmpty) 344 }) 345 t.Run("ReturnNodeSlice", func(t *testing.T) { 346 testgraph.ReturnNodeSlice(t, undirectedMatrixBuilder, usesEmpty) 347 }) 348 t.Run("Weight", func(t *testing.T) { 349 testgraph.Weight(t, undirectedMatrixBuilder) 350 }) 351 352 t.Run("AddEdges", func(t *testing.T) { 353 testgraph.AddEdges(t, 100, 354 newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)}, 355 func(id int64) graph.Node { return simple.Node(id) }, 356 false, // Cannot set self-loops. 357 false, // Cannot update nodes. 358 ) 359 }) 360 t.Run("NoLoopAddEdges", func(t *testing.T) { 361 testgraph.NoLoopAddEdges(t, 100, 362 newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)}, 363 func(id int64) graph.Node { return simple.Node(id) }, 364 ) 365 }) 366 t.Run("AddWeightedEdges", func(t *testing.T) { 367 testgraph.AddWeightedEdges(t, 100, 368 newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)}, 369 1, 370 func(id int64) graph.Node { return simple.Node(id) }, 371 false, // Cannot set self-loops. 372 false, // Cannot update nodes. 373 ) 374 }) 375 t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { 376 testgraph.NoLoopAddWeightedEdges(t, 100, 377 newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)}, 378 1, 379 func(id int64) graph.Node { return simple.Node(id) }, 380 ) 381 }) 382 t.Run("RemoveEdges", func(t *testing.T) { 383 g := newEdgeShimUndir{simple.NewUndirectedMatrix(100, 0, 1, 0)} 384 rnd := rand.New(rand.NewSource(1)) 385 it := g.Nodes() 386 for it.Next() { 387 u := it.Node() 388 d := rnd.Intn(5) 389 vit := g.Nodes() 390 for d >= 0 && vit.Next() { 391 v := vit.Node() 392 if v.ID() == u.ID() { 393 continue 394 } 395 d-- 396 g.SetEdge(g.NewEdge(u, v)) 397 } 398 } 399 testgraph.RemoveEdges(t, g, g.Edges()) 400 }) 401 } 402 403 func undirectedMatrixFromBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { 404 if len(nodes) == 0 { 405 return 406 } 407 if !isZeroContiguousSet(nodes) { 408 return 409 } 410 seen := set.NewNodes() 411 dg := simple.NewUndirectedMatrixFrom(nodes, absent, self, absent) 412 for _, n := range nodes { 413 seen.Add(n) 414 } 415 for _, edge := range edges { 416 if edge.From().ID() == edge.To().ID() { 417 continue 418 } 419 if !seen.Has(edge.From()) || !seen.Has(edge.To()) { 420 continue 421 } 422 ce := simple.WeightedEdge{F: dg.Node(edge.From().ID()), T: dg.Node(edge.To().ID()), W: edge.Weight()} 423 e = append(e, ce) 424 dg.SetWeightedEdge(ce) 425 } 426 if len(e) == 0 && len(edges) != 0 { 427 return nil, nil, nil, math.NaN(), math.NaN(), false 428 } 429 n = make([]graph.Node, 0, len(seen)) 430 for _, sn := range seen { 431 n = append(n, sn) 432 } 433 return dg, n, e, self, absent, true 434 } 435 436 func TestUndirectedMatrixFrom(t *testing.T) { 437 t.Run("AdjacencyMatrix", func(t *testing.T) { 438 testgraph.AdjacencyMatrix(t, undirectedMatrixFromBuilder) 439 }) 440 t.Run("EdgeExistence", func(t *testing.T) { 441 testgraph.EdgeExistence(t, undirectedMatrixFromBuilder, reversesEdges) 442 }) 443 t.Run("NodeExistence", func(t *testing.T) { 444 testgraph.NodeExistence(t, undirectedMatrixFromBuilder) 445 }) 446 t.Run("ReturnAdjacentNodes", func(t *testing.T) { 447 testgraph.ReturnAdjacentNodes(t, undirectedMatrixFromBuilder, usesEmpty, reversesEdges) 448 }) 449 t.Run("ReturnAllEdges", func(t *testing.T) { 450 testgraph.ReturnAllEdges(t, undirectedMatrixFromBuilder, usesEmpty) 451 }) 452 t.Run("ReturnAllNodes", func(t *testing.T) { 453 testgraph.ReturnAllNodes(t, undirectedMatrixFromBuilder, usesEmpty) 454 }) 455 t.Run("ReturnAllWeightedEdges", func(t *testing.T) { 456 testgraph.ReturnAllWeightedEdges(t, undirectedMatrixFromBuilder, usesEmpty) 457 }) 458 t.Run("ReturnEdgeSlice", func(t *testing.T) { 459 testgraph.ReturnEdgeSlice(t, undirectedMatrixFromBuilder, usesEmpty) 460 }) 461 t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { 462 testgraph.ReturnWeightedEdgeSlice(t, undirectedMatrixFromBuilder, usesEmpty) 463 }) 464 t.Run("ReturnNodeSlice", func(t *testing.T) { 465 testgraph.ReturnNodeSlice(t, undirectedMatrixFromBuilder, usesEmpty) 466 }) 467 t.Run("Weight", func(t *testing.T) { 468 testgraph.Weight(t, undirectedMatrixFromBuilder) 469 }) 470 471 const numNodes = 100 472 473 t.Run("AddEdges", func(t *testing.T) { 474 testgraph.AddEdges(t, numNodes, 475 newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 476 func(id int64) graph.Node { return simple.Node(id) }, 477 false, // Cannot set self-loops. 478 true, // Can update nodes. 479 ) 480 }) 481 t.Run("NoLoopAddEdges", func(t *testing.T) { 482 testgraph.NoLoopAddEdges(t, numNodes, 483 newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 484 func(id int64) graph.Node { return simple.Node(id) }, 485 ) 486 }) 487 t.Run("AddWeightedEdges", func(t *testing.T) { 488 testgraph.AddWeightedEdges(t, numNodes, 489 newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 490 1, 491 func(id int64) graph.Node { return simple.Node(id) }, 492 false, // Cannot set self-loops. 493 true, // Can update nodes. 494 ) 495 }) 496 t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { 497 testgraph.NoLoopAddWeightedEdges(t, numNodes, 498 newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)}, 499 1, 500 func(id int64) graph.Node { return simple.Node(id) }, 501 ) 502 }) 503 t.Run("RemoveEdges", func(t *testing.T) { 504 g := newEdgeShimUndir{simple.NewUndirectedMatrixFrom(makeNodes(numNodes), 0, 1, 0)} 505 rnd := rand.New(rand.NewSource(1)) 506 it := g.Nodes() 507 for it.Next() { 508 u := it.Node() 509 d := rnd.Intn(5) 510 vit := g.Nodes() 511 for d >= 0 && vit.Next() { 512 v := vit.Node() 513 if v.ID() == u.ID() { 514 continue 515 } 516 d-- 517 g.SetEdge(g.NewEdge(u, v)) 518 } 519 } 520 testgraph.RemoveEdges(t, g, g.Edges()) 521 }) 522 } 523 524 type newEdgeShimUndir struct { 525 *simple.UndirectedMatrix 526 } 527 528 func (g newEdgeShimUndir) NewEdge(u, v graph.Node) graph.Edge { 529 return simple.Edge{F: u, T: v} 530 } 531 func (g newEdgeShimUndir) NewWeightedEdge(u, v graph.Node, w float64) graph.WeightedEdge { 532 return simple.WeightedEdge{F: u, T: v, W: w} 533 } 534 535 func makeNodes(n int) []graph.Node { 536 nodes := make([]graph.Node, n) 537 for i := range nodes { 538 nodes[i] = simple.Node(i) 539 } 540 return nodes 541 } 542 543 func TestBasicDenseImpassable(t *testing.T) { 544 dg := simple.NewUndirectedMatrix(5, math.Inf(1), 0, math.Inf(1)) 545 if dg == nil { 546 t.Fatal("Directed graph could not be made") 547 } 548 549 for i := 0; i < 5; i++ { 550 if dg.Node(int64(i)) == nil { 551 t.Errorf("Node that should exist doesn't: %d", i) 552 } 553 554 if degree := dg.From(int64(i)).Len(); degree != 0 { 555 t.Errorf("Node in impassable graph has a neighbor. Node: %d Degree: %d", i, degree) 556 } 557 } 558 559 for i := 5; i < 10; i++ { 560 if dg.Node(int64(i)) != nil { 561 t.Errorf("Node exists that shouldn't: %d", i) 562 } 563 } 564 } 565 566 func TestBasicDensePassable(t *testing.T) { 567 dg := simple.NewUndirectedMatrix(5, 1, 0, math.Inf(1)) 568 if dg == nil { 569 t.Fatal("Directed graph could not be made") 570 } 571 572 for i := 0; i < 5; i++ { 573 if dg.Node(int64(i)) == nil { 574 t.Errorf("Node that should exist doesn't: %d", i) 575 } 576 577 if degree := dg.From(int64(i)).Len(); degree != 4 { 578 t.Errorf("Node in passable graph missing neighbors. Node: %d Degree: %d", i, degree) 579 } 580 } 581 582 for i := 5; i < 10; i++ { 583 if dg.Node(int64(i)) != nil { 584 t.Errorf("Node exists that shouldn't: %d", i) 585 } 586 } 587 } 588 589 func TestDirectedDenseAddRemove(t *testing.T) { 590 dg := simple.NewDirectedMatrix(10, math.Inf(1), 0, math.Inf(1)) 591 dg.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(0), T: simple.Node(2), W: 1}) 592 593 if neighbors := graph.NodesOf(dg.From(int64(0))); len(neighbors) != 1 || neighbors[0].ID() != 2 || 594 dg.Edge(int64(0), int64(2)) == nil { 595 t.Errorf("Adding edge didn't create successor") 596 } 597 598 dg.RemoveEdge(int64(0), int64(2)) 599 600 if neighbors := graph.NodesOf(dg.From(int64(0))); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil { 601 t.Errorf("Removing edge didn't properly remove successor") 602 } 603 604 if neighbors := graph.NodesOf(dg.To(int64(2))); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil { 605 t.Errorf("Removing directed edge wrongly kept predecessor") 606 } 607 608 dg.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(0), T: simple.Node(2), W: 2}) 609 // I figure we've torture tested From/To at this point 610 // so we'll just use the bool functions now 611 if dg.Edge(int64(0), int64(2)) == nil { 612 t.Fatal("Adding directed edge didn't change successor back") 613 } 614 c1, _ := dg.Weight(int64(2), int64(0)) 615 c2, _ := dg.Weight(int64(0), int64(2)) 616 if c1 == c2 { 617 t.Error("Adding directed edge affected cost in undirected manner") 618 } 619 } 620 621 func TestUndirectedDenseAddRemove(t *testing.T) { 622 dg := simple.NewUndirectedMatrix(10, math.Inf(1), 0, math.Inf(1)) 623 dg.SetEdge(simple.Edge{F: simple.Node(0), T: simple.Node(2)}) 624 625 if neighbors := graph.NodesOf(dg.From(int64(0))); len(neighbors) != 1 || neighbors[0].ID() != 2 || 626 dg.EdgeBetween(int64(0), int64(2)) == nil { 627 t.Errorf("Couldn't add neighbor") 628 } 629 630 if neighbors := graph.NodesOf(dg.From(int64(2))); len(neighbors) != 1 || neighbors[0].ID() != 0 || 631 dg.EdgeBetween(int64(2), int64(0)) == nil { 632 t.Errorf("Adding an undirected neighbor didn't add it reciprocally") 633 } 634 } 635 636 func TestDenseLists(t *testing.T) { 637 dg := simple.NewDirectedMatrix(15, 1, 0, math.Inf(1)) 638 nodes := graph.NodesOf(dg.Nodes()) 639 640 if len(nodes) != 15 { 641 t.Fatalf("Wrong number of nodes: got:%v want:%v", len(nodes), 15) 642 } 643 644 ordered.ByID(nodes) 645 646 for i, node := range graph.NodesOf(dg.Nodes()) { 647 if int64(i) != node.ID() { 648 t.Errorf("Node list doesn't return properly id'd nodes") 649 } 650 } 651 652 edges := graph.EdgesOf(dg.Edges()) 653 if len(edges) != 15*14 { 654 t.Errorf("Improper number of edges for passable dense graph") 655 } 656 657 dg.RemoveEdge(int64(12), int64(11)) 658 edges = graph.EdgesOf(dg.Edges()) 659 if len(edges) != (15*14)-1 { 660 t.Errorf("Removing edge didn't affect edge listing properly") 661 } 662 }