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  }