gonum.org/v1/gonum@v0.14.0/graph/topo/topo_test.go (about) 1 // Copyright ©2014 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 topo 6 7 import ( 8 "reflect" 9 "testing" 10 11 "gonum.org/v1/gonum/graph" 12 "gonum.org/v1/gonum/graph/internal/ordered" 13 "gonum.org/v1/gonum/graph/simple" 14 ) 15 16 func TestIsPath(t *testing.T) { 17 dg := simple.NewDirectedGraph() 18 if !IsPathIn(dg, nil) { 19 t.Error("IsPath returns false on nil path") 20 } 21 p := []graph.Node{simple.Node(0)} 22 if IsPathIn(dg, p) { 23 t.Error("IsPath returns true on nonexistent node") 24 } 25 dg.AddNode(p[0]) 26 if !IsPathIn(dg, p) { 27 t.Error("IsPath returns false on single-length path with existing node") 28 } 29 p = append(p, simple.Node(1)) 30 dg.AddNode(p[1]) 31 if IsPathIn(dg, p) { 32 t.Error("IsPath returns true on bad path of length 2") 33 } 34 dg.SetEdge(simple.Edge{F: p[0], T: p[1]}) 35 if !IsPathIn(dg, p) { 36 t.Error("IsPath returns false on correct path of length 2") 37 } 38 p[0], p[1] = p[1], p[0] 39 if IsPathIn(dg, p) { 40 t.Error("IsPath erroneously returns true for a reverse path") 41 } 42 p = []graph.Node{p[1], p[0], simple.Node(2)} 43 dg.SetEdge(simple.Edge{F: p[1], T: p[2]}) 44 if !IsPathIn(dg, p) { 45 t.Error("IsPath does not find a correct path for path > 2 nodes") 46 } 47 ug := simple.NewUndirectedGraph() 48 ug.SetEdge(simple.Edge{F: p[1], T: p[0]}) 49 ug.SetEdge(simple.Edge{F: p[1], T: p[2]}) 50 if !IsPathIn(dg, p) { 51 t.Error("IsPath does not correctly account for undirected behavior") 52 } 53 } 54 55 var pathExistsInUndirectedTests = []struct { 56 g []intset 57 from, to int 58 want bool 59 }{ 60 {g: batageljZaversnikGraph, from: 0, to: 0, want: true}, 61 {g: batageljZaversnikGraph, from: 0, to: 1, want: false}, 62 {g: batageljZaversnikGraph, from: 1, to: 2, want: true}, 63 {g: batageljZaversnikGraph, from: 2, to: 1, want: true}, 64 {g: batageljZaversnikGraph, from: 2, to: 12, want: false}, 65 {g: batageljZaversnikGraph, from: 20, to: 6, want: true}, 66 } 67 68 func TestPathExistsInUndirected(t *testing.T) { 69 for i, test := range pathExistsInUndirectedTests { 70 g := simple.NewUndirectedGraph() 71 72 for u, e := range test.g { 73 if g.Node(int64(u)) == nil { 74 g.AddNode(simple.Node(u)) 75 } 76 for v := range e { 77 if g.Node(v) == nil { 78 g.AddNode(simple.Node(v)) 79 } 80 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 81 } 82 } 83 84 got := PathExistsIn(g, simple.Node(test.from), simple.Node(test.to)) 85 if got != test.want { 86 t.Errorf("unexpected result for path existence in test %d: got:%t want %t", i, got, test.want) 87 } 88 } 89 } 90 91 var pathExistsInDirectedTests = []struct { 92 g []intset 93 from, to int 94 want bool 95 }{ 96 // The graph definition is such that from node IDs are 97 // less than to node IDs. 98 {g: batageljZaversnikGraph, from: 0, to: 0, want: true}, 99 {g: batageljZaversnikGraph, from: 0, to: 1, want: false}, 100 {g: batageljZaversnikGraph, from: 1, to: 2, want: true}, 101 {g: batageljZaversnikGraph, from: 2, to: 1, want: false}, 102 {g: batageljZaversnikGraph, from: 2, to: 12, want: false}, 103 {g: batageljZaversnikGraph, from: 20, to: 6, want: false}, 104 {g: batageljZaversnikGraph, from: 6, to: 20, want: true}, 105 } 106 107 func TestPathExistsInDirected(t *testing.T) { 108 for i, test := range pathExistsInDirectedTests { 109 g := simple.NewDirectedGraph() 110 111 for u, e := range test.g { 112 if g.Node(int64(u)) == nil { 113 g.AddNode(simple.Node(u)) 114 } 115 for v := range e { 116 if g.Node(v) == nil { 117 g.AddNode(simple.Node(v)) 118 } 119 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 120 } 121 } 122 123 got := PathExistsIn(g, simple.Node(test.from), simple.Node(test.to)) 124 if got != test.want { 125 t.Errorf("unexpected result for path existence in test %d: got:%t want %t", i, got, test.want) 126 } 127 } 128 } 129 130 var connectedComponentTests = []struct { 131 g []intset 132 want [][]int64 133 }{ 134 { 135 g: batageljZaversnikGraph, 136 want: [][]int64{ 137 {0}, 138 {1, 2, 3, 4, 5}, 139 {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, 140 }, 141 }, 142 } 143 144 func TestConnectedComponents(t *testing.T) { 145 for i, test := range connectedComponentTests { 146 g := simple.NewUndirectedGraph() 147 148 for u, e := range test.g { 149 if g.Node(int64(u)) == nil { 150 g.AddNode(simple.Node(u)) 151 } 152 for v := range e { 153 if g.Node(v) == nil { 154 g.AddNode(simple.Node(v)) 155 } 156 g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 157 } 158 } 159 cc := ConnectedComponents(g) 160 got := make([][]int64, len(cc)) 161 for j, c := range cc { 162 ids := make([]int64, len(c)) 163 for k, n := range c { 164 ids[k] = n.ID() 165 } 166 ordered.Int64s(ids) 167 got[j] = ids 168 } 169 ordered.BySliceValues(got) 170 if !reflect.DeepEqual(got, test.want) { 171 t.Errorf("unexpected connected components for test %d %T:\ngot: %v\nwant:%v", i, g, got, test.want) 172 } 173 } 174 } 175 176 var equalTests = []struct { 177 name string 178 a, b graph.Graph 179 want bool 180 }{ 181 {name: "empty g=g", a: simple.NewUndirectedGraph(), b: simple.NewUndirectedGraph(), want: true}, 182 {name: "empty dg=dg", a: simple.NewDirectedGraph(), b: simple.NewDirectedGraph(), want: true}, 183 {name: "empty g=dg", a: simple.NewUndirectedGraph(), b: simple.NewDirectedGraph(), want: true}, 184 185 { 186 name: "1 g=g", want: true, 187 a: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), 188 b: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), 189 }, 190 { 191 name: "1 dg=dg", want: true, 192 a: addNodes(simple.NewDirectedGraph(), simple.Node(1)), 193 b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), 194 }, 195 { 196 name: "1 g=dg", want: true, 197 a: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), 198 b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), 199 }, 200 201 { 202 name: "0/1 g≠g", want: false, 203 a: simple.NewUndirectedGraph(), 204 b: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), 205 }, 206 { 207 name: "0/1 dg≠dg", want: false, 208 a: simple.NewDirectedGraph(), 209 b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), 210 }, 211 { 212 name: "0/1 g≠dg", want: false, 213 a: simple.NewUndirectedGraph(), 214 b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), 215 }, 216 { 217 name: "0/1 g≠dg", want: false, 218 a: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), 219 b: simple.NewDirectedGraph(), 220 }, 221 222 { 223 name: "1 g≠g", want: false, 224 a: addNodes(simple.NewUndirectedGraph(), simple.Node(0)), 225 b: addNodes(simple.NewUndirectedGraph(), simple.Node(1)), 226 }, 227 { 228 name: "1 dg≠dg", want: false, 229 a: addNodes(simple.NewDirectedGraph(), simple.Node(0)), 230 b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), 231 }, 232 { 233 name: "1 g≠dg", want: false, 234 a: addNodes(simple.NewUndirectedGraph(), simple.Node(0)), 235 b: addNodes(simple.NewDirectedGraph(), simple.Node(1)), 236 }, 237 238 { 239 name: "box g=g", want: true, 240 a: setEdges(simple.NewUndirectedGraph(), 241 simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 242 simple.Edge{F: simple.Node(1), T: simple.Node(2)}, 243 simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 244 simple.Edge{F: simple.Node(3), T: simple.Node(0)}, 245 ), 246 b: setEdges(simple.NewUndirectedGraph(), 247 simple.Edge{F: simple.Node(3), T: simple.Node(0)}, 248 simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 249 simple.Edge{F: simple.Node(1), T: simple.Node(2)}, 250 simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 251 ), 252 }, 253 { 254 name: "box dg=dg", want: true, 255 a: setEdges(simple.NewDirectedGraph(), 256 simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 257 simple.Edge{F: simple.Node(1), T: simple.Node(2)}, 258 simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 259 simple.Edge{F: simple.Node(3), T: simple.Node(0)}, 260 ), 261 b: setEdges(simple.NewDirectedGraph(), 262 simple.Edge{F: simple.Node(3), T: simple.Node(0)}, 263 simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 264 simple.Edge{F: simple.Node(1), T: simple.Node(2)}, 265 simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 266 ), 267 }, 268 { 269 name: "box reversed dg≠dg", want: false, 270 a: setEdges(simple.NewDirectedGraph(), 271 simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 272 simple.Edge{F: simple.Node(1), T: simple.Node(2)}, 273 simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 274 simple.Edge{F: simple.Node(3), T: simple.Node(0)}, 275 ), 276 b: setEdges(simple.NewDirectedGraph(), 277 simple.Edge{F: simple.Node(1), T: simple.Node(0)}, 278 simple.Edge{F: simple.Node(2), T: simple.Node(1)}, 279 simple.Edge{F: simple.Node(3), T: simple.Node(2)}, 280 simple.Edge{F: simple.Node(0), T: simple.Node(3)}, 281 ), 282 }, 283 { 284 name: "box g=dg", want: true, 285 a: setEdges(simple.NewUndirectedGraph(), 286 simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 287 simple.Edge{F: simple.Node(1), T: simple.Node(2)}, 288 simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 289 simple.Edge{F: simple.Node(3), T: simple.Node(0)}, 290 ), 291 b: setEdges(simple.NewDirectedGraph(), 292 simple.Edge{F: simple.Node(0), T: simple.Node(1)}, 293 simple.Edge{F: simple.Node(1), T: simple.Node(0)}, 294 simple.Edge{F: simple.Node(1), T: simple.Node(2)}, 295 simple.Edge{F: simple.Node(2), T: simple.Node(3)}, 296 simple.Edge{F: simple.Node(2), T: simple.Node(1)}, 297 simple.Edge{F: simple.Node(3), T: simple.Node(2)}, 298 simple.Edge{F: simple.Node(3), T: simple.Node(0)}, 299 simple.Edge{F: simple.Node(0), T: simple.Node(3)}, 300 ), 301 }, 302 } 303 304 func TestEqual(t *testing.T) { 305 for _, test := range equalTests { 306 if got := Equal(test.a, test.b); got != test.want { 307 t.Errorf("unexpected result for %q equality test: got:%t want:%t", test.name, got, test.want) 308 } 309 if got := Equal(plainGraph{test.a}, plainGraph{test.b}); got != test.want { 310 t.Errorf("unexpected result for %q equality test with filtered method set: got:%t want:%t", test.name, got, test.want) 311 } 312 } 313 } 314 315 type plainGraph struct { 316 graph.Graph 317 } 318 319 type builder interface { 320 graph.Graph 321 graph.Builder 322 } 323 324 func addNodes(dst builder, nodes ...graph.Node) builder { 325 for _, n := range nodes { 326 dst.AddNode(n) 327 } 328 return dst 329 } 330 331 func setEdges(dst builder, edges ...graph.Edge) builder { 332 for _, e := range edges { 333 dst.SetEdge(e) 334 } 335 return dst 336 }