diff --git a/graph/path/yen_ksp.go b/graph/path/yen_ksp.go index 04f6e50c..82b1b808 100644 --- a/graph/path/yen_ksp.go +++ b/graph/path/yen_ksp.go @@ -85,7 +85,18 @@ func YenKShortestPaths(g graph.Graph, k int, cost float64, s, t graph.Node) [][] spath = append(root[:len(root)-1], spath...) weight += rootWeight } - pot = append(pot, yenShortest{spath, weight}) + + // Add the potential k-shortest path if it is new. + isNewPot := true + for x := range pot { + if isSamePath(pot[x].path, spath) { + isNewPot = false + break + } + } + if isNewPot { + pot = append(pot, yenShortest{spath, weight}) + } } if len(pot) == 0 { @@ -104,6 +115,19 @@ func YenKShortestPaths(g graph.Graph, k int, cost float64, s, t graph.Node) [][] return paths } +func isSamePath(a, b []graph.Node) bool { + if len(a) != len(b) { + return false + } + + for i, x := range a { + if x.ID() != b[i].ID() { + return false + } + } + return true +} + // yenShortest holds a path and its weight for sorting. type yenShortest struct { path []graph.Node diff --git a/graph/path/yen_ksp_test.go b/graph/path/yen_ksp_test.go index eabf4a91..70702c66 100644 --- a/graph/path/yen_ksp_test.go +++ b/graph/path/yen_ksp_test.go @@ -306,6 +306,28 @@ var yenShortestPathTests = []struct { {8, 2, 4, 3, 7, 5}, }, }, + { + name: "grid", // This is the failing case in gonum/gonum#1920. + graph: func() graph.WeightedEdgeAdder { return simple.NewWeightedUndirectedGraph(0, math.Inf(1)) }, + edges: []simple.WeightedEdge{ + {F: simple.Node(1), T: simple.Node(2), W: 1}, + {F: simple.Node(2), T: simple.Node(3), W: 2}, + {F: simple.Node(3), T: simple.Node(6), W: 5}, + {F: simple.Node(1), T: simple.Node(4), W: 5}, + {F: simple.Node(2), T: simple.Node(5), W: 4}, + {F: simple.Node(4), T: simple.Node(5), W: 6}, + {F: simple.Node(5), T: simple.Node(6), W: 7}, + }, + query: simple.Edge{F: simple.Node(1), T: simple.Node(6)}, + k: -1, + cost: math.Inf(1), + wantPaths: [][]int64{ + {1, 2, 3, 6}, + {1, 2, 5, 6}, + {1, 4, 5, 6}, + {1, 4, 5, 2, 3, 6}, + }, + }, } func bipartite(n int, weight, inc float64) []simple.WeightedEdge {