mirror of
https://github.com/gonum/gonum.git
synced 2025-10-06 15:47:01 +08:00
graph/path: indicate negative cycle weights with -Inf instead of NaN
The paths are undefined, but the limit of the path weight is -Inf.
This commit is contained in:
@@ -13,7 +13,7 @@ import (
|
|||||||
// FloydWarshall returns a shortest-path tree for the graph g or false indicating
|
// FloydWarshall returns a shortest-path tree for the graph g or false indicating
|
||||||
// that a negative cycle exists in the graph. If a negative cycle exists in the graph
|
// that a negative cycle exists in the graph. If a negative cycle exists in the graph
|
||||||
// the returned paths will be valid and edge weights on the negative cycle will be
|
// the returned paths will be valid and edge weights on the negative cycle will be
|
||||||
// set to NaN. If the graph does not implement Weighted, UniformCost is used.
|
// set to -Inf. If the graph does not implement Weighted, UniformCost is used.
|
||||||
//
|
//
|
||||||
// The time complexity of FloydWarshall is O(|V|^3).
|
// The time complexity of FloydWarshall is O(|V|^3).
|
||||||
func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
|
func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
|
||||||
@@ -65,7 +65,7 @@ func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
|
|||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
// If we have a negative cycle, mark all
|
// If we have a negative cycle, mark all
|
||||||
// the edges in the cycles with NaN weight.
|
// the edges in the cycles with -Inf weight.
|
||||||
d := paths.dist
|
d := paths.dist
|
||||||
for i := range nodes {
|
for i := range nodes {
|
||||||
for j := range nodes {
|
for j := range nodes {
|
||||||
@@ -73,9 +73,9 @@ func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
|
|||||||
if math.IsInf(d.At(i, k), 1) || math.IsInf(d.At(k, j), 1) {
|
if math.IsInf(d.At(i, k), 1) || math.IsInf(d.At(k, j), 1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if d.At(k, k) < 0 || math.IsNaN(d.At(k, k)) {
|
if d.At(k, k) < 0 {
|
||||||
d.Set(k, k, math.NaN())
|
d.Set(k, k, math.Inf(-1))
|
||||||
d.Set(i, j, math.NaN())
|
d.Set(i, j, math.Inf(-1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -46,7 +46,7 @@ func ExampleBellmanFordFrom_negativecycles() {
|
|||||||
}
|
}
|
||||||
for _, id := range []int64{'a', 'b', 'c', 'd', 'e', 'f'} {
|
for _, id := range []int64{'a', 'b', 'c', 'd', 'e', 'f'} {
|
||||||
p, w := pt.To(id)
|
p, w := pt.To(id)
|
||||||
if math.IsNaN(w) {
|
if math.IsInf(w, -1) {
|
||||||
fmt.Printf("negative cycle in path to %c path:%c\n", id, p)
|
fmt.Printf("negative cycle in path to %c path:%c\n", id, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ func ExampleFloydWarshall_negativecycles() {
|
|||||||
ids := []int64{'a', 'b', 'c', 'd', 'e', 'f'}
|
ids := []int64{'a', 'b', 'c', 'd', 'e', 'f'}
|
||||||
|
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
if math.IsNaN(pt.Weight(id, id)) {
|
if math.IsInf(pt.Weight(id, id), -1) {
|
||||||
fmt.Printf("%c is in a negative cycle\n", id)
|
fmt.Printf("%c is in a negative cycle\n", id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ func ExampleFloydWarshall_negativecycles() {
|
|||||||
for _, uid := range ids {
|
for _, uid := range ids {
|
||||||
for _, vid := range ids {
|
for _, vid := range ids {
|
||||||
_, w, unique := pt.Between(uid, vid)
|
_, w, unique := pt.Between(uid, vid)
|
||||||
if math.IsNaN(w) {
|
if math.IsInf(w, -1) {
|
||||||
fmt.Printf("negative cycle in path from %c to %c unique=%t\n", uid, vid, unique)
|
fmt.Printf("negative cycle in path from %c to %c unique=%t\n", uid, vid, unique)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -119,7 +119,7 @@ func (p Shortest) WeightTo(vid int64) float64 {
|
|||||||
|
|
||||||
// To returns a shortest path to v and the weight of the path. If the path
|
// To returns a shortest path to v and the weight of the path. If the path
|
||||||
// to v includes a negative cycle, one pass through the cycle will be included
|
// to v includes a negative cycle, one pass through the cycle will be included
|
||||||
// in path and weight will be returned as NaN.
|
// in path and weight will be returned as -Inf.
|
||||||
func (p Shortest) To(vid int64) (path []graph.Node, weight float64) {
|
func (p Shortest) To(vid int64) (path []graph.Node, weight float64) {
|
||||||
to, toOK := p.indexOf[vid]
|
to, toOK := p.indexOf[vid]
|
||||||
if !toOK || math.IsInf(p.dist[to], 1) {
|
if !toOK || math.IsInf(p.dist[to], 1) {
|
||||||
@@ -133,7 +133,7 @@ func (p Shortest) To(vid int64) (path []graph.Node, weight float64) {
|
|||||||
seen.Add(from)
|
seen.Add(from)
|
||||||
for to != from {
|
for to != from {
|
||||||
if seen.Has(to) {
|
if seen.Has(to) {
|
||||||
weight = math.NaN()
|
weight = math.Inf(-1)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
seen.Add(to)
|
seen.Add(to)
|
||||||
@@ -253,7 +253,7 @@ func (p AllShortest) Weight(uid, vid int64) float64 {
|
|||||||
// one shortest path exists between u and v, a randomly chosen path will be returned and
|
// one shortest path exists between u and v, a randomly chosen path will be returned and
|
||||||
// unique is returned false. If a cycle with zero weight exists in the path, it will not
|
// unique is returned false. If a cycle with zero weight exists in the path, it will not
|
||||||
// be included, but unique will be returned false. If a negative cycle exists on the path
|
// be included, but unique will be returned false. If a negative cycle exists on the path
|
||||||
// from u to v, path will be returned nil, weight will be NaN and unique will be false.
|
// from u to v, path will be returned nil, weight will be -Inf and unique will be false.
|
||||||
func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64, unique bool) {
|
func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64, unique bool) {
|
||||||
from, fromOK := p.indexOf[uid]
|
from, fromOK := p.indexOf[uid]
|
||||||
to, toOK := p.indexOf[vid]
|
to, toOK := p.indexOf[vid]
|
||||||
@@ -265,7 +265,7 @@ func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64,
|
|||||||
}
|
}
|
||||||
|
|
||||||
weight = p.dist.At(from, to)
|
weight = p.dist.At(from, to)
|
||||||
if math.IsNaN(weight) {
|
if math.IsInf(weight, -1) {
|
||||||
return nil, weight, false
|
return nil, weight, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +314,7 @@ func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64,
|
|||||||
|
|
||||||
// AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
|
// AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
|
||||||
// containing zero-weight cycles are not returned. If a negative cycle exists between
|
// containing zero-weight cycles are not returned. If a negative cycle exists between
|
||||||
// u and v, paths is returned nil and weight is returned as NaN.
|
// u and v, paths is returned nil and weight is returned as -Inf.
|
||||||
func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) {
|
func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) {
|
||||||
from, fromOK := p.indexOf[uid]
|
from, fromOK := p.indexOf[uid]
|
||||||
to, toOK := p.indexOf[vid]
|
to, toOK := p.indexOf[vid]
|
||||||
@@ -326,7 +326,7 @@ func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight fl
|
|||||||
}
|
}
|
||||||
|
|
||||||
weight = p.dist.At(from, to)
|
weight = p.dist.At(from, to)
|
||||||
if math.IsNaN(weight) {
|
if math.IsInf(weight, -1) {
|
||||||
return nil, weight
|
return nil, weight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user