github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/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  	"github.com/jingcheng-WU/gonum/graph"
    11  	"github.com/jingcheng-WU/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  }