gonum.org/v1/gonum@v0.14.0/graph/path/negative_cycles_example_test.go (about) 1 // Copyright ©2017 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 path_test 6 7 import ( 8 "fmt" 9 "math" 10 11 "gonum.org/v1/gonum/graph" 12 "gonum.org/v1/gonum/graph/path" 13 "gonum.org/v1/gonum/graph/simple" 14 ) 15 16 func ExampleBellmanFordFrom_negativecycles() { 17 // BellmanFordFrom can be used to find a non-exhaustive 18 // set of negative cycles in a graph. 19 20 // Construct a graph with a negative cycle. 21 edges := []simple.WeightedEdge{ 22 {F: simple.Node('a'), T: simple.Node('b'), W: -2}, 23 {F: simple.Node('a'), T: simple.Node('f'), W: 2}, 24 {F: simple.Node('b'), T: simple.Node('c'), W: 6}, 25 {F: simple.Node('c'), T: simple.Node('a'), W: -5}, 26 {F: simple.Node('d'), T: simple.Node('c'), W: -3}, 27 {F: simple.Node('d'), T: simple.Node('e'), W: 8}, 28 {F: simple.Node('e'), T: simple.Node('b'), W: 9}, 29 {F: simple.Node('e'), T: simple.Node('c'), W: 2}, 30 } 31 g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) 32 for _, e := range edges { 33 g.SetWeightedEdge(e) 34 } 35 36 // Add a zero-cost path to all nodes from a new node Q. 37 // Since the graph is being mutated, we get a range over 38 // a slice of the graph's nodes rather than using the 39 // graph.Nodes iterator directly. 40 for _, n := range graph.NodesOf(g.Nodes()) { 41 g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node('Q'), T: n}) 42 } 43 44 // Find the shortest path to each node from Q. 45 pt, ok := path.BellmanFordFrom(simple.Node('Q'), g) 46 if ok { 47 fmt.Println("no negative cycle present") 48 return 49 } 50 for _, id := range []int64{'a', 'b', 'c', 'd', 'e', 'f'} { 51 p, w := pt.To(id) 52 if math.IsInf(w, -1) { 53 fmt.Printf("negative cycle in path to %c path:%c\n", id, p) 54 } 55 } 56 57 // Output: 58 // negative cycle in path to a path:[a b c a] 59 // negative cycle in path to b path:[b c a b] 60 // negative cycle in path to c path:[c a b c] 61 // negative cycle in path to f path:[a b c a f] 62 } 63 64 func ExampleFloydWarshall_negativecycles() { 65 // FloydWarshall can be used to find an exhaustive 66 // set of nodes in negative cycles in a graph. 67 68 // Construct a graph with a negative cycle. 69 edges := []simple.WeightedEdge{ 70 {F: simple.Node('a'), T: simple.Node('f'), W: -1}, 71 {F: simple.Node('b'), T: simple.Node('a'), W: 1}, 72 {F: simple.Node('b'), T: simple.Node('c'), W: -1}, 73 {F: simple.Node('b'), T: simple.Node('d'), W: 1}, 74 {F: simple.Node('c'), T: simple.Node('b'), W: 0}, 75 {F: simple.Node('e'), T: simple.Node('a'), W: 1}, 76 {F: simple.Node('f'), T: simple.Node('e'), W: -1}, 77 } 78 g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) 79 for _, e := range edges { 80 g.SetWeightedEdge(e) 81 } 82 83 // Find the shortest path to each node from Q. 84 pt, ok := path.FloydWarshall(g) 85 if ok { 86 fmt.Println("no negative cycle present") 87 return 88 } 89 90 ids := []int64{'a', 'b', 'c', 'd', 'e', 'f'} 91 92 for _, id := range ids { 93 if math.IsInf(pt.Weight(id, id), -1) { 94 fmt.Printf("%c is in a negative cycle\n", id) 95 } 96 } 97 98 for _, uid := range ids { 99 for _, vid := range ids { 100 _, w, unique := pt.Between(uid, vid) 101 if math.IsInf(w, -1) { 102 fmt.Printf("negative cycle in path from %c to %c unique=%t\n", uid, vid, unique) 103 } 104 } 105 } 106 107 // Output: 108 // a is in a negative cycle 109 // b is in a negative cycle 110 // c is in a negative cycle 111 // e is in a negative cycle 112 // f is in a negative cycle 113 // negative cycle in path from a to a unique=false 114 // negative cycle in path from a to e unique=false 115 // negative cycle in path from a to f unique=false 116 // negative cycle in path from b to a unique=false 117 // negative cycle in path from b to b unique=false 118 // negative cycle in path from b to c unique=false 119 // negative cycle in path from b to d unique=false 120 // negative cycle in path from b to e unique=false 121 // negative cycle in path from b to f unique=false 122 // negative cycle in path from c to a unique=false 123 // negative cycle in path from c to b unique=false 124 // negative cycle in path from c to c unique=false 125 // negative cycle in path from c to d unique=false 126 // negative cycle in path from c to e unique=false 127 // negative cycle in path from c to f unique=false 128 // negative cycle in path from e to a unique=false 129 // negative cycle in path from e to e unique=false 130 // negative cycle in path from e to f unique=false 131 // negative cycle in path from f to a unique=false 132 // negative cycle in path from f to e unique=false 133 // negative cycle in path from f to f unique=false 134 }