gonum.org/v1/gonum@v0.14.0/graph/path/internal/testgraphs/shortest.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 testgraphs 6 7 import ( 8 "math" 9 10 "gonum.org/v1/gonum/graph" 11 "gonum.org/v1/gonum/graph/simple" 12 ) 13 14 // ShortestPathTests are graphs used to test the static shortest path routines in path: BellmanFord, 15 // DijkstraAllPaths, DijkstraFrom, FloydWarshall and Johnson, and the static degenerate case for the 16 // dynamic shortest path routine in path/dynamic: DStarLite. 17 var ShortestPathTests = []struct { 18 Name string 19 Graph func() graph.WeightedEdgeAdder 20 Edges []simple.WeightedEdge 21 HasNegativeWeight bool 22 HasNegativeCycle bool 23 HasNegativeCycleInPath bool 24 25 Query simple.Edge 26 Weight float64 27 WantPaths [][]int64 28 HasUniquePath bool 29 30 NoPathFor simple.Edge 31 }{ 32 // Positive weighted graphs. 33 { 34 Name: "empty directed", 35 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 36 37 Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 38 Weight: math.Inf(1), 39 40 NoPathFor: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 41 }, 42 { 43 Name: "empty undirected", 44 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, 45 46 Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 47 Weight: math.Inf(1), 48 49 NoPathFor: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 50 }, 51 { 52 Name: "one edge directed", 53 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 54 Edges: []simple.WeightedEdge{ 55 {F: simple.Node(0), T: simple.Node(1), W: 1}, 56 }, 57 58 Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 59 Weight: 1, 60 WantPaths: [][]int64{ 61 {0, 1}, 62 }, 63 HasUniquePath: true, 64 65 NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 66 }, 67 { 68 Name: "one edge self directed", 69 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 70 Edges: []simple.WeightedEdge{ 71 {F: simple.Node(0), T: simple.Node(1), W: 1}, 72 }, 73 74 Query: simple.Edge{F: simple.Node(0), T: simple.Node(0)}, 75 Weight: 0, 76 WantPaths: [][]int64{ 77 {0}, 78 }, 79 HasUniquePath: true, 80 81 NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 82 }, 83 { 84 Name: "one edge undirected", 85 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, 86 Edges: []simple.WeightedEdge{ 87 {F: simple.Node(0), T: simple.Node(1), W: 1}, 88 }, 89 90 Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 91 Weight: 1, 92 WantPaths: [][]int64{ 93 {0, 1}, 94 }, 95 HasUniquePath: true, 96 97 NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 98 }, 99 { 100 Name: "two paths directed", 101 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 102 Edges: []simple.WeightedEdge{ 103 {F: simple.Node(0), T: simple.Node(2), W: 2}, 104 {F: simple.Node(0), T: simple.Node(1), W: 1}, 105 {F: simple.Node(1), T: simple.Node(2), W: 1}, 106 }, 107 108 Query: simple.Edge{F: simple.Node(0), T: simple.Node(2)}, 109 Weight: 2, 110 WantPaths: [][]int64{ 111 {0, 1, 2}, 112 {0, 2}, 113 }, 114 HasUniquePath: false, 115 116 NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(1)}, 117 }, 118 { 119 Name: "two paths undirected", 120 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, 121 Edges: []simple.WeightedEdge{ 122 {F: simple.Node(0), T: simple.Node(2), W: 2}, 123 {F: simple.Node(0), T: simple.Node(1), W: 1}, 124 {F: simple.Node(1), T: simple.Node(2), W: 1}, 125 }, 126 127 Query: simple.Edge{F: simple.Node(0), T: simple.Node(2)}, 128 Weight: 2, 129 WantPaths: [][]int64{ 130 {0, 1, 2}, 131 {0, 2}, 132 }, 133 HasUniquePath: false, 134 135 NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(4)}, 136 }, 137 { 138 Name: "confounding paths directed", 139 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 140 Edges: []simple.WeightedEdge{ 141 // Add a path from 0->5 of weight 4 142 {F: simple.Node(0), T: simple.Node(1), W: 1}, 143 {F: simple.Node(1), T: simple.Node(2), W: 1}, 144 {F: simple.Node(2), T: simple.Node(3), W: 1}, 145 {F: simple.Node(3), T: simple.Node(5), W: 1}, 146 147 // Add direct edge to goal of weight 4 148 {F: simple.Node(0), T: simple.Node(5), W: 4}, 149 150 // Add edge to a node that's still optimal 151 {F: simple.Node(0), T: simple.Node(2), W: 2}, 152 153 // Add edge to 3 that's overpriced 154 {F: simple.Node(0), T: simple.Node(3), W: 4}, 155 156 // Add very cheap edge to 4 which is a dead end 157 {F: simple.Node(0), T: simple.Node(4), W: 0.25}, 158 }, 159 160 Query: simple.Edge{F: simple.Node(0), T: simple.Node(5)}, 161 Weight: 4, 162 WantPaths: [][]int64{ 163 {0, 1, 2, 3, 5}, 164 {0, 2, 3, 5}, 165 {0, 5}, 166 }, 167 HasUniquePath: false, 168 169 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 170 }, 171 { 172 Name: "confounding paths undirected", 173 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, 174 Edges: []simple.WeightedEdge{ 175 // Add a path from 0->5 of weight 4 176 {F: simple.Node(0), T: simple.Node(1), W: 1}, 177 {F: simple.Node(1), T: simple.Node(2), W: 1}, 178 {F: simple.Node(2), T: simple.Node(3), W: 1}, 179 {F: simple.Node(3), T: simple.Node(5), W: 1}, 180 181 // Add direct edge to goal of weight 4 182 {F: simple.Node(0), T: simple.Node(5), W: 4}, 183 184 // Add edge to a node that's still optimal 185 {F: simple.Node(0), T: simple.Node(2), W: 2}, 186 187 // Add edge to 3 that's overpriced 188 {F: simple.Node(0), T: simple.Node(3), W: 4}, 189 190 // Add very cheap edge to 4 which is a dead end 191 {F: simple.Node(0), T: simple.Node(4), W: 0.25}, 192 }, 193 194 Query: simple.Edge{F: simple.Node(0), T: simple.Node(5)}, 195 Weight: 4, 196 WantPaths: [][]int64{ 197 {0, 1, 2, 3, 5}, 198 {0, 2, 3, 5}, 199 {0, 5}, 200 }, 201 HasUniquePath: false, 202 203 NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(6)}, 204 }, 205 { 206 Name: "confounding paths directed 2-step", 207 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 208 Edges: []simple.WeightedEdge{ 209 // Add a path from 0->5 of weight 4 210 {F: simple.Node(0), T: simple.Node(1), W: 1}, 211 {F: simple.Node(1), T: simple.Node(2), W: 1}, 212 {F: simple.Node(2), T: simple.Node(3), W: 1}, 213 {F: simple.Node(3), T: simple.Node(5), W: 1}, 214 215 // Add two step path to goal of weight 4 216 {F: simple.Node(0), T: simple.Node(6), W: 2}, 217 {F: simple.Node(6), T: simple.Node(5), W: 2}, 218 219 // Add edge to a node that's still optimal 220 {F: simple.Node(0), T: simple.Node(2), W: 2}, 221 222 // Add edge to 3 that's overpriced 223 {F: simple.Node(0), T: simple.Node(3), W: 4}, 224 225 // Add very cheap edge to 4 which is a dead end 226 {F: simple.Node(0), T: simple.Node(4), W: 0.25}, 227 }, 228 229 Query: simple.Edge{F: simple.Node(0), T: simple.Node(5)}, 230 Weight: 4, 231 WantPaths: [][]int64{ 232 {0, 1, 2, 3, 5}, 233 {0, 2, 3, 5}, 234 {0, 6, 5}, 235 }, 236 HasUniquePath: false, 237 238 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 239 }, 240 { 241 Name: "confounding paths undirected 2-step", 242 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, 243 Edges: []simple.WeightedEdge{ 244 // Add a path from 0->5 of weight 4 245 {F: simple.Node(0), T: simple.Node(1), W: 1}, 246 {F: simple.Node(1), T: simple.Node(2), W: 1}, 247 {F: simple.Node(2), T: simple.Node(3), W: 1}, 248 {F: simple.Node(3), T: simple.Node(5), W: 1}, 249 250 // Add two step path to goal of weight 4 251 {F: simple.Node(0), T: simple.Node(6), W: 2}, 252 {F: simple.Node(6), T: simple.Node(5), W: 2}, 253 254 // Add edge to a node that's still optimal 255 {F: simple.Node(0), T: simple.Node(2), W: 2}, 256 257 // Add edge to 3 that's overpriced 258 {F: simple.Node(0), T: simple.Node(3), W: 4}, 259 260 // Add very cheap edge to 4 which is a dead end 261 {F: simple.Node(0), T: simple.Node(4), W: 0.25}, 262 }, 263 264 Query: simple.Edge{F: simple.Node(0), T: simple.Node(5)}, 265 Weight: 4, 266 WantPaths: [][]int64{ 267 {0, 1, 2, 3, 5}, 268 {0, 2, 3, 5}, 269 {0, 6, 5}, 270 }, 271 HasUniquePath: false, 272 273 NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(7)}, 274 }, 275 { 276 Name: "zero-weight cycle directed", 277 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 278 Edges: []simple.WeightedEdge{ 279 // Add a path from 0->4 of weight 4 280 {F: simple.Node(0), T: simple.Node(1), W: 1}, 281 {F: simple.Node(1), T: simple.Node(2), W: 1}, 282 {F: simple.Node(2), T: simple.Node(3), W: 1}, 283 {F: simple.Node(3), T: simple.Node(4), W: 1}, 284 285 // Add a zero-weight cycle. 286 {F: simple.Node(1), T: simple.Node(5), W: 0}, 287 {F: simple.Node(5), T: simple.Node(1), W: 0}, 288 }, 289 290 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 291 Weight: 4, 292 WantPaths: [][]int64{ 293 {0, 1, 2, 3, 4}, 294 }, 295 HasUniquePath: false, 296 297 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 298 }, 299 { 300 Name: "zero-weight cycle^2 directed", 301 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 302 Edges: []simple.WeightedEdge{ 303 // Add a path from 0->4 of weight 4 304 {F: simple.Node(0), T: simple.Node(1), W: 1}, 305 {F: simple.Node(1), T: simple.Node(2), W: 1}, 306 {F: simple.Node(2), T: simple.Node(3), W: 1}, 307 {F: simple.Node(3), T: simple.Node(4), W: 1}, 308 309 // Add a zero-weight cycle. 310 {F: simple.Node(1), T: simple.Node(5), W: 0}, 311 {F: simple.Node(5), T: simple.Node(1), W: 0}, 312 // With its own zero-weight cycle. 313 {F: simple.Node(5), T: simple.Node(6), W: 0}, 314 {F: simple.Node(6), T: simple.Node(5), W: 0}, 315 }, 316 317 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 318 Weight: 4, 319 WantPaths: [][]int64{ 320 {0, 1, 2, 3, 4}, 321 }, 322 HasUniquePath: false, 323 324 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 325 }, 326 { 327 Name: "zero-weight cycle^2 confounding directed", 328 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 329 Edges: []simple.WeightedEdge{ 330 // Add a path from 0->4 of weight 4 331 {F: simple.Node(0), T: simple.Node(1), W: 1}, 332 {F: simple.Node(1), T: simple.Node(2), W: 1}, 333 {F: simple.Node(2), T: simple.Node(3), W: 1}, 334 {F: simple.Node(3), T: simple.Node(4), W: 1}, 335 336 // Add a zero-weight cycle. 337 {F: simple.Node(1), T: simple.Node(5), W: 0}, 338 {F: simple.Node(5), T: simple.Node(1), W: 0}, 339 // With its own zero-weight cycle. 340 {F: simple.Node(5), T: simple.Node(6), W: 0}, 341 {F: simple.Node(6), T: simple.Node(5), W: 0}, 342 // But leading to the target. 343 {F: simple.Node(5), T: simple.Node(4), W: 3}, 344 }, 345 346 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 347 Weight: 4, 348 WantPaths: [][]int64{ 349 {0, 1, 2, 3, 4}, 350 {0, 1, 5, 4}, 351 }, 352 HasUniquePath: false, 353 354 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 355 }, 356 { 357 Name: "zero-weight cycle^3 directed", 358 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 359 Edges: []simple.WeightedEdge{ 360 // Add a path from 0->4 of weight 4 361 {F: simple.Node(0), T: simple.Node(1), W: 1}, 362 {F: simple.Node(1), T: simple.Node(2), W: 1}, 363 {F: simple.Node(2), T: simple.Node(3), W: 1}, 364 {F: simple.Node(3), T: simple.Node(4), W: 1}, 365 366 // Add a zero-weight cycle. 367 {F: simple.Node(1), T: simple.Node(5), W: 0}, 368 {F: simple.Node(5), T: simple.Node(1), W: 0}, 369 // With its own zero-weight cycle. 370 {F: simple.Node(5), T: simple.Node(6), W: 0}, 371 {F: simple.Node(6), T: simple.Node(5), W: 0}, 372 // With its own zero-weight cycle. 373 {F: simple.Node(6), T: simple.Node(7), W: 0}, 374 {F: simple.Node(7), T: simple.Node(6), W: 0}, 375 }, 376 377 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 378 Weight: 4, 379 WantPaths: [][]int64{ 380 {0, 1, 2, 3, 4}, 381 }, 382 HasUniquePath: false, 383 384 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 385 }, 386 { 387 Name: "zero-weight 3·cycle^2 confounding directed", 388 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 389 Edges: []simple.WeightedEdge{ 390 // Add a path from 0->4 of weight 4 391 {F: simple.Node(0), T: simple.Node(1), W: 1}, 392 {F: simple.Node(1), T: simple.Node(2), W: 1}, 393 {F: simple.Node(2), T: simple.Node(3), W: 1}, 394 {F: simple.Node(3), T: simple.Node(4), W: 1}, 395 396 // Add a zero-weight cycle. 397 {F: simple.Node(1), T: simple.Node(5), W: 0}, 398 {F: simple.Node(5), T: simple.Node(1), W: 0}, 399 // With 3 of its own zero-weight cycles. 400 {F: simple.Node(5), T: simple.Node(6), W: 0}, 401 {F: simple.Node(6), T: simple.Node(5), W: 0}, 402 {F: simple.Node(5), T: simple.Node(7), W: 0}, 403 {F: simple.Node(7), T: simple.Node(5), W: 0}, 404 // Each leading to the target. 405 {F: simple.Node(5), T: simple.Node(4), W: 3}, 406 {F: simple.Node(6), T: simple.Node(4), W: 3}, 407 {F: simple.Node(7), T: simple.Node(4), W: 3}, 408 }, 409 410 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 411 Weight: 4, 412 WantPaths: [][]int64{ 413 {0, 1, 2, 3, 4}, 414 {0, 1, 5, 4}, 415 {0, 1, 5, 6, 4}, 416 {0, 1, 5, 7, 4}, 417 }, 418 HasUniquePath: false, 419 420 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 421 }, 422 { 423 Name: "zero-weight reversed 3·cycle^2 confounding directed", 424 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 425 Edges: []simple.WeightedEdge{ 426 // Add a path from 0->4 of weight 4 427 {F: simple.Node(0), T: simple.Node(1), W: 1}, 428 {F: simple.Node(1), T: simple.Node(2), W: 1}, 429 {F: simple.Node(2), T: simple.Node(3), W: 1}, 430 {F: simple.Node(3), T: simple.Node(4), W: 1}, 431 432 // Add a zero-weight cycle. 433 {F: simple.Node(3), T: simple.Node(5), W: 0}, 434 {F: simple.Node(5), T: simple.Node(3), W: 0}, 435 // With 3 of its own zero-weight cycles. 436 {F: simple.Node(5), T: simple.Node(6), W: 0}, 437 {F: simple.Node(6), T: simple.Node(5), W: 0}, 438 {F: simple.Node(5), T: simple.Node(7), W: 0}, 439 {F: simple.Node(7), T: simple.Node(5), W: 0}, 440 // Each leading from the source. 441 {F: simple.Node(0), T: simple.Node(5), W: 3}, 442 {F: simple.Node(0), T: simple.Node(6), W: 3}, 443 {F: simple.Node(0), T: simple.Node(7), W: 3}, 444 }, 445 446 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 447 Weight: 4, 448 WantPaths: [][]int64{ 449 {0, 1, 2, 3, 4}, 450 {0, 5, 3, 4}, 451 {0, 6, 5, 3, 4}, 452 {0, 7, 5, 3, 4}, 453 }, 454 HasUniquePath: false, 455 456 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 457 }, 458 { 459 Name: "zero-weight |V|·cycle^(n/|V|) directed", 460 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 461 Edges: func() []simple.WeightedEdge { 462 e := []simple.WeightedEdge{ 463 // Add a path from 0->4 of weight 4 464 {F: simple.Node(0), T: simple.Node(1), W: 1}, 465 {F: simple.Node(1), T: simple.Node(2), W: 1}, 466 {F: simple.Node(2), T: simple.Node(3), W: 1}, 467 {F: simple.Node(3), T: simple.Node(4), W: 1}, 468 } 469 next := len(e) + 1 470 471 // Add n zero-weight cycles. 472 const n = 100 473 for i := 0; i < n; i++ { 474 e = append(e, 475 simple.WeightedEdge{F: simple.Node(next + i), T: simple.Node(i), W: 0}, 476 simple.WeightedEdge{F: simple.Node(i), T: simple.Node(next + i), W: 0}, 477 ) 478 } 479 return e 480 }(), 481 482 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 483 Weight: 4, 484 WantPaths: [][]int64{ 485 {0, 1, 2, 3, 4}, 486 }, 487 HasUniquePath: false, 488 489 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 490 }, 491 { 492 Name: "zero-weight n·cycle directed", 493 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 494 Edges: func() []simple.WeightedEdge { 495 e := []simple.WeightedEdge{ 496 // Add a path from 0->4 of weight 4 497 {F: simple.Node(0), T: simple.Node(1), W: 1}, 498 {F: simple.Node(1), T: simple.Node(2), W: 1}, 499 {F: simple.Node(2), T: simple.Node(3), W: 1}, 500 {F: simple.Node(3), T: simple.Node(4), W: 1}, 501 } 502 next := len(e) + 1 503 504 // Add n zero-weight cycles. 505 const n = 100 506 for i := 0; i < n; i++ { 507 e = append(e, 508 simple.WeightedEdge{F: simple.Node(next + i), T: simple.Node(1), W: 0}, 509 simple.WeightedEdge{F: simple.Node(1), T: simple.Node(next + i), W: 0}, 510 ) 511 } 512 return e 513 }(), 514 515 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 516 Weight: 4, 517 WantPaths: [][]int64{ 518 {0, 1, 2, 3, 4}, 519 }, 520 HasUniquePath: false, 521 522 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 523 }, 524 { 525 Name: "zero-weight bi-directional tree with single exit directed", 526 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 527 Edges: func() []simple.WeightedEdge { 528 e := []simple.WeightedEdge{ 529 // Add a path from 0->4 of weight 4 530 {F: simple.Node(0), T: simple.Node(1), W: 1}, 531 {F: simple.Node(1), T: simple.Node(2), W: 1}, 532 {F: simple.Node(2), T: simple.Node(3), W: 1}, 533 {F: simple.Node(3), T: simple.Node(4), W: 1}, 534 } 535 536 // Make a bi-directional tree rooted at node 2 with 537 // a single exit to node 4 and co-equal cost from 538 // 2 to 4. 539 const ( 540 depth = 4 541 branching = 4 542 ) 543 544 next := len(e) + 1 545 src := 2 546 var i, last int 547 for l := 0; l < depth; l++ { 548 for i = 0; i < branching; i++ { 549 last = next + i 550 e = append(e, simple.WeightedEdge{F: simple.Node(src), T: simple.Node(last), W: 0}) 551 e = append(e, simple.WeightedEdge{F: simple.Node(last), T: simple.Node(src), W: 0}) 552 } 553 src = next + 1 554 next += branching 555 } 556 e = append(e, simple.WeightedEdge{F: simple.Node(last), T: simple.Node(4), W: 2}) 557 return e 558 }(), 559 560 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 561 Weight: 4, 562 WantPaths: [][]int64{ 563 {0, 1, 2, 3, 4}, 564 {0, 1, 2, 6, 10, 14, 20, 4}, 565 }, 566 HasUniquePath: false, 567 568 NoPathFor: simple.Edge{F: simple.Node(4), T: simple.Node(5)}, 569 }, 570 571 // Negative weighted graphs. 572 { 573 Name: "one edge directed negative", 574 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 575 Edges: []simple.WeightedEdge{ 576 {F: simple.Node(0), T: simple.Node(1), W: -1}, 577 }, 578 HasNegativeWeight: true, 579 580 Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 581 Weight: -1, 582 WantPaths: [][]int64{ 583 {0, 1}, 584 }, 585 HasUniquePath: true, 586 587 NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 588 }, 589 { 590 Name: "one edge undirected negative", 591 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, 592 Edges: []simple.WeightedEdge{ 593 {F: simple.Node(0), T: simple.Node(1), W: -1}, 594 }, 595 HasNegativeWeight: true, 596 HasNegativeCycle: true, 597 598 Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 599 HasNegativeCycleInPath: true, 600 Weight: math.Inf(-1), 601 WantPaths: [][]int64{ 602 {0, 1}, // One loop around negative cycle and no lead-in path. 603 }, 604 605 NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 606 }, 607 { 608 Name: "two path directed negative cycle", 609 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 610 Edges: []simple.WeightedEdge{ 611 {F: simple.Node(0), T: simple.Node(1), W: 1}, 612 {F: simple.Node(1), T: simple.Node(2), W: -1}, 613 {F: simple.Node(2), T: simple.Node(1), W: -1}, 614 {F: simple.Node(1), T: simple.Node(3), W: 1}, 615 {F: simple.Node(0), T: simple.Node(4), W: 1}, 616 }, 617 HasNegativeWeight: true, 618 HasNegativeCycle: true, 619 620 Query: simple.Edge{F: simple.Node(0), T: simple.Node(3)}, 621 HasNegativeCycleInPath: true, 622 Weight: math.Inf(-1), 623 WantPaths: [][]int64{ 624 {1, 2, 1, 3}, // One loop around negative cycle and no lead-in path. 625 }, 626 627 NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(6)}, 628 }, 629 { 630 Name: "two path directed off-path negative cycle", 631 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 632 Edges: []simple.WeightedEdge{ 633 {F: simple.Node(0), T: simple.Node(1), W: 1}, 634 {F: simple.Node(1), T: simple.Node(2), W: -1}, 635 {F: simple.Node(2), T: simple.Node(1), W: -1}, 636 {F: simple.Node(1), T: simple.Node(3), W: 1}, 637 {F: simple.Node(0), T: simple.Node(4), W: 10}, // Push search into negative cycle. 638 }, 639 HasNegativeWeight: true, 640 HasNegativeCycle: true, 641 642 Query: simple.Edge{F: simple.Node(0), T: simple.Node(4)}, 643 HasNegativeCycleInPath: false, 644 Weight: 10, 645 WantPaths: [][]int64{ 646 {0, 4}, 647 }, 648 HasUniquePath: true, 649 650 NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(6)}, 651 }, 652 { 653 Name: "two path directed diamond negative cycle", 654 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 655 Edges: []simple.WeightedEdge{ 656 {F: simple.Node(0), T: simple.Node(1), W: 1}, 657 {F: simple.Node(1), T: simple.Node(2), W: -1}, 658 {F: simple.Node(2), T: simple.Node(1), W: -1}, 659 {F: simple.Node(1), T: simple.Node(3), W: 1}, 660 {F: simple.Node(0), T: simple.Node(3), W: 10}, // Push search into negative cycle. 661 }, 662 HasNegativeWeight: true, 663 HasNegativeCycle: true, 664 665 Query: simple.Edge{F: simple.Node(0), T: simple.Node(3)}, 666 HasNegativeCycleInPath: true, 667 Weight: math.Inf(-1), 668 WantPaths: [][]int64{ 669 {1, 2, 1, 3}, // One loop around negative cycle and no lead-in path. 670 }, 671 672 NoPathFor: simple.Edge{F: simple.Node(5), T: simple.Node(6)}, 673 }, 674 { 675 Name: "wp graph negative", // http://en.wikipedia.org/w/index.php?title=Johnson%27s_algorithm&oldid=564595231 676 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 677 Edges: []simple.WeightedEdge{ 678 {F: simple.Node('w'), T: simple.Node('z'), W: 2}, 679 {F: simple.Node('x'), T: simple.Node('w'), W: 6}, 680 {F: simple.Node('x'), T: simple.Node('y'), W: 3}, 681 {F: simple.Node('y'), T: simple.Node('w'), W: 4}, 682 {F: simple.Node('y'), T: simple.Node('z'), W: 5}, 683 {F: simple.Node('z'), T: simple.Node('x'), W: -7}, 684 {F: simple.Node('z'), T: simple.Node('y'), W: -3}, 685 }, 686 HasNegativeWeight: true, 687 688 Query: simple.Edge{F: simple.Node('z'), T: simple.Node('y')}, 689 Weight: -4, 690 WantPaths: [][]int64{ 691 {'z', 'x', 'y'}, 692 }, 693 HasUniquePath: true, 694 695 NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 696 }, 697 { 698 Name: "roughgarden negative", 699 Graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedDirectedGraph(0, math.Inf(1)) }, 700 Edges: []simple.WeightedEdge{ 701 {F: simple.Node('a'), T: simple.Node('b'), W: -2}, 702 {F: simple.Node('b'), T: simple.Node('c'), W: -1}, 703 {F: simple.Node('c'), T: simple.Node('a'), W: 4}, 704 {F: simple.Node('c'), T: simple.Node('x'), W: 2}, 705 {F: simple.Node('c'), T: simple.Node('y'), W: -3}, 706 {F: simple.Node('z'), T: simple.Node('x'), W: 1}, 707 {F: simple.Node('z'), T: simple.Node('y'), W: -4}, 708 }, 709 HasNegativeWeight: true, 710 711 Query: simple.Edge{F: simple.Node('a'), T: simple.Node('y')}, 712 Weight: -6, 713 WantPaths: [][]int64{ 714 {'a', 'b', 'c', 'y'}, 715 }, 716 HasUniquePath: true, 717 718 NoPathFor: simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 719 }, 720 }