gonum.org/v1/gonum@v0.14.0/graph/path/bellman_ford_moore_test.go (about)

     1  // Copyright ©2015 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
     6  
     7  import (
     8  	"math"
     9  	"reflect"
    10  	"testing"
    11  
    12  	"gonum.org/v1/gonum/graph"
    13  	"gonum.org/v1/gonum/graph/internal/ordered"
    14  	"gonum.org/v1/gonum/graph/path/internal/testgraphs"
    15  	"gonum.org/v1/gonum/graph/traverse"
    16  )
    17  
    18  func TestBellmanFordFrom(t *testing.T) {
    19  	t.Parallel()
    20  	for _, test := range testgraphs.ShortestPathTests {
    21  		g := test.Graph()
    22  		for _, e := range test.Edges {
    23  			g.SetWeightedEdge(e)
    24  		}
    25  
    26  		for _, tg := range []struct {
    27  			typ string
    28  			g   traverse.Graph
    29  		}{
    30  			{"complete", g.(graph.Graph)},
    31  			{"incremental", incremental{g.(graph.Weighted)}},
    32  		} {
    33  			pt, ok := BellmanFordFrom(test.Query.From(), tg.g)
    34  			if test.HasNegativeCycle {
    35  				if ok {
    36  					t.Errorf("%q %s: expected negative cycle", test.Name, tg.typ)
    37  				}
    38  			} else if !ok {
    39  				t.Fatalf("%q %s: unexpected negative cycle", test.Name, tg.typ)
    40  			}
    41  
    42  			if pt.From().ID() != test.Query.From().ID() {
    43  				t.Fatalf("%q %s: unexpected from node ID: got:%d want:%d", test.Name, tg.typ, pt.From().ID(), test.Query.From().ID())
    44  			}
    45  
    46  			p, weight := pt.To(test.Query.To().ID())
    47  			if weight != test.Weight {
    48  				t.Errorf("%q %s: unexpected weight from To: got:%f want:%f",
    49  					test.Name, tg.typ, weight, test.Weight)
    50  			}
    51  			if weight := pt.WeightTo(test.Query.To().ID()); !math.IsInf(test.Weight, -1) && weight != test.Weight {
    52  				t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f",
    53  					test.Name, tg.typ, weight, test.Weight)
    54  			}
    55  
    56  			var got []int64
    57  			for _, n := range p {
    58  				got = append(got, n.ID())
    59  			}
    60  			ok = len(got) == 0 && len(test.WantPaths) == 0
    61  			for _, sp := range test.WantPaths {
    62  				if reflect.DeepEqual(got, sp) {
    63  					ok = true
    64  					break
    65  				}
    66  			}
    67  			if !ok {
    68  				t.Errorf("%q %s: unexpected shortest path:\ngot: %v\nwant from:%v",
    69  					test.Name, tg.typ, p, test.WantPaths)
    70  			}
    71  
    72  			np, weight := pt.To(test.NoPathFor.To().ID())
    73  			if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
    74  				t.Errorf("%q %s: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
    75  					test.Name, tg.typ, np, weight)
    76  			}
    77  		}
    78  	}
    79  }
    80  
    81  func TestBellmanFordAllFrom(t *testing.T) {
    82  	t.Parallel()
    83  	for _, test := range testgraphs.ShortestPathTests {
    84  		g := test.Graph()
    85  		for _, e := range test.Edges {
    86  			g.SetWeightedEdge(e)
    87  		}
    88  
    89  		for _, tg := range []struct {
    90  			typ string
    91  			g   traverse.Graph
    92  		}{
    93  			{"complete", g.(graph.Graph)},
    94  			{"incremental", incremental{g.(graph.Weighted)}},
    95  		} {
    96  			pt, ok := BellmanFordAllFrom(test.Query.From(), tg.g)
    97  			if test.HasNegativeCycle {
    98  				if ok {
    99  					t.Errorf("%q %s: expected negative cycle", test.Name, tg.typ)
   100  				}
   101  			} else if !ok {
   102  				t.Fatalf("%q %s: unexpected negative cycle", test.Name, tg.typ)
   103  			}
   104  
   105  			if pt.From().ID() != test.Query.From().ID() {
   106  				t.Fatalf("%q %s: unexpected from node ID: got:%d want:%d", test.Name, tg.typ, pt.From().ID(), test.Query.From().ID())
   107  			}
   108  
   109  			// Test single path results.
   110  			p, weight, unique := pt.To(test.Query.To().ID())
   111  			if weight != test.Weight {
   112  				t.Errorf("%q %s: unexpected weight from To: got:%f want:%f",
   113  					test.Name, tg.typ, weight, test.Weight)
   114  			}
   115  			if weight := pt.WeightTo(test.Query.To().ID()); !math.IsInf(test.Weight, -1) && weight != test.Weight {
   116  				t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f",
   117  					test.Name, tg.typ, weight, test.Weight)
   118  			}
   119  
   120  			var gotPath []int64
   121  			for _, n := range p {
   122  				gotPath = append(gotPath, n.ID())
   123  			}
   124  			ok = len(gotPath) == 0 && len(test.WantPaths) == 0
   125  			for _, sp := range test.WantPaths {
   126  				if reflect.DeepEqual(gotPath, sp) {
   127  					ok = true
   128  					break
   129  				}
   130  			}
   131  			if !ok {
   132  				t.Errorf("%q %s: unexpected shortest path:\ngot: %v\nwant from:%v",
   133  					test.Name, tg.typ, p, test.WantPaths)
   134  			}
   135  			if unique != test.HasUniquePath {
   136  				t.Errorf("%q %s: unexpected uniqueness from To: got:%t want:%t (%d paths)",
   137  					test.Name, tg.typ, unique, test.HasUniquePath, len(test.WantPaths))
   138  			}
   139  
   140  			// Test multiple path results.
   141  			paths, weight := pt.AllTo(test.Query.To().ID())
   142  			if weight != test.Weight {
   143  				t.Errorf("%q %s: unexpected weight from AllTo: got:%f want:%f",
   144  					test.Name, tg.typ, weight, test.Weight)
   145  			}
   146  			if weight := pt.WeightTo(test.Query.To().ID()); !math.IsInf(test.Weight, -1) && weight != test.Weight {
   147  				t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f",
   148  					test.Name, tg.typ, weight, test.Weight)
   149  			}
   150  
   151  			var gotPaths [][]int64
   152  			if len(paths) != 0 {
   153  				gotPaths = make([][]int64, len(paths))
   154  			}
   155  			for i, p := range paths {
   156  				for _, v := range p {
   157  					gotPaths[i] = append(gotPaths[i], v.ID())
   158  				}
   159  			}
   160  			if test.HasNegativeCycleInPath {
   161  				if gotPaths != nil {
   162  					t.Errorf("testing %q %s: unexpected shortest paths:\ngot: %v\nwant: []",
   163  						test.Name, tg.typ, gotPaths)
   164  				}
   165  			} else {
   166  				ordered.BySliceValues(gotPaths)
   167  				if !reflect.DeepEqual(gotPaths, test.WantPaths) {
   168  					t.Errorf("testing %q %s: unexpected shortest paths:\ngot: %v\nwant:%v",
   169  						test.Name, tg.typ, gotPaths, test.WantPaths)
   170  				}
   171  			}
   172  
   173  			paths = paths[:0]
   174  			pt.AllToFunc(test.Query.To().ID(), func(path []graph.Node) {
   175  				paths = append(paths, append([]graph.Node(nil), path...))
   176  			})
   177  			if weight := pt.WeightTo(test.Query.To().ID()); !math.IsInf(test.Weight, -1) && weight != test.Weight {
   178  				t.Errorf("%q %s: unexpected weight from Weight: got:%f want:%f",
   179  					test.Name, tg.typ, weight, test.Weight)
   180  			}
   181  
   182  			gotPaths = nil
   183  			if len(paths) != 0 {
   184  				gotPaths = make([][]int64, len(paths))
   185  			}
   186  			for i, p := range paths {
   187  				for _, v := range p {
   188  					gotPaths[i] = append(gotPaths[i], v.ID())
   189  				}
   190  			}
   191  			if test.HasNegativeCycleInPath {
   192  				if gotPaths != nil {
   193  					t.Errorf("testing %q %s: unexpected shortest paths:\ngot: %v\nwant: []",
   194  						test.Name, tg.typ, gotPaths)
   195  				}
   196  			} else {
   197  				ordered.BySliceValues(gotPaths)
   198  				if !reflect.DeepEqual(gotPaths, test.WantPaths) {
   199  					t.Errorf("testing %q %s: unexpected shortest paths:\ngot: %v\nwant:%v",
   200  						test.Name, tg.typ, gotPaths, test.WantPaths)
   201  				}
   202  			}
   203  
   204  			// Test absent paths.
   205  			np, weight, unique := pt.To(test.NoPathFor.To().ID())
   206  			if pt.From().ID() == test.NoPathFor.From().ID() && !(np == nil && math.IsInf(weight, 1) && !unique) {
   207  				t.Errorf("%q %s: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
   208  					test.Name, tg.typ, np, weight, unique)
   209  			}
   210  		}
   211  	}
   212  }