github.com/gopherd/gonum@v0.0.4/graph/graph_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 graph_test 6 7 import ( 8 "testing" 9 10 "github.com/gopherd/gonum/graph" 11 "github.com/gopherd/gonum/graph/internal/ordered" 12 "github.com/gopherd/gonum/graph/simple" 13 ) 14 15 type graphBuilder interface { 16 graph.Graph 17 graph.Builder 18 } 19 20 var copyTests = []struct { 21 desc string 22 23 src graph.Graph 24 dst graphBuilder 25 26 // If want is nil, compare to src. 27 want graph.Graph 28 }{ 29 { 30 desc: "undirected to undirected", 31 src: func() graph.Graph { 32 g := simple.NewUndirectedGraph() 33 g.AddNode(simple.Node(-1)) 34 for _, e := range []simple.Edge{ 35 {F: simple.Node(0), T: simple.Node(1)}, 36 {F: simple.Node(0), T: simple.Node(3)}, 37 {F: simple.Node(1), T: simple.Node(2)}, 38 } { 39 g.SetEdge(e) 40 } 41 return g 42 }(), 43 dst: simple.NewUndirectedGraph(), 44 }, 45 { 46 desc: "undirected to directed", 47 src: func() graph.Graph { 48 g := simple.NewUndirectedGraph() 49 g.AddNode(simple.Node(-1)) 50 for _, e := range []simple.Edge{ 51 {F: simple.Node(0), T: simple.Node(1)}, 52 {F: simple.Node(0), T: simple.Node(3)}, 53 {F: simple.Node(1), T: simple.Node(2)}, 54 } { 55 g.SetEdge(e) 56 } 57 return g 58 }(), 59 dst: simple.NewDirectedGraph(), 60 61 want: func() graph.Graph { 62 g := simple.NewDirectedGraph() 63 g.AddNode(simple.Node(-1)) 64 for _, e := range []simple.Edge{ 65 {F: simple.Node(0), T: simple.Node(1)}, 66 {F: simple.Node(0), T: simple.Node(3)}, 67 {F: simple.Node(1), T: simple.Node(2)}, 68 } { 69 // want is a directed graph copied from 70 // an undirected graph so we need to have 71 // all edges in both directions. 72 g.SetEdge(e) 73 e.T, e.F = e.F, e.T 74 g.SetEdge(e) 75 } 76 return g 77 }(), 78 }, 79 { 80 desc: "directed to undirected", 81 src: func() graph.Graph { 82 g := simple.NewDirectedGraph() 83 g.AddNode(simple.Node(-1)) 84 for _, e := range []simple.Edge{ 85 {F: simple.Node(0), T: simple.Node(1)}, 86 {F: simple.Node(0), T: simple.Node(3)}, 87 {F: simple.Node(1), T: simple.Node(2)}, 88 } { 89 g.SetEdge(e) 90 } 91 return g 92 }(), 93 dst: simple.NewUndirectedGraph(), 94 95 want: func() graph.Graph { 96 g := simple.NewUndirectedGraph() 97 g.AddNode(simple.Node(-1)) 98 for _, e := range []simple.Edge{ 99 {F: simple.Node(0), T: simple.Node(1)}, 100 {F: simple.Node(0), T: simple.Node(3)}, 101 {F: simple.Node(1), T: simple.Node(2)}, 102 } { 103 g.SetEdge(e) 104 } 105 return g 106 }(), 107 }, 108 { 109 desc: "directed to directed", 110 src: func() graph.Graph { 111 g := simple.NewDirectedGraph() 112 g.AddNode(simple.Node(-1)) 113 for _, e := range []simple.Edge{ 114 {F: simple.Node(0), T: simple.Node(1)}, 115 {F: simple.Node(0), T: simple.Node(3)}, 116 {F: simple.Node(1), T: simple.Node(2)}, 117 } { 118 g.SetEdge(e) 119 } 120 return g 121 }(), 122 dst: simple.NewDirectedGraph(), 123 }, 124 } 125 126 func TestCopy(t *testing.T) { 127 for _, test := range copyTests { 128 graph.Copy(test.dst, test.src) 129 want := test.want 130 if want == nil { 131 want = test.src 132 } 133 if !same(test.dst, want) { 134 t.Errorf("unexpected copy result for %s", test.desc) 135 } 136 } 137 } 138 139 type graphWeightedBuilder interface { 140 graph.Graph 141 graph.WeightedBuilder 142 } 143 144 var copyWeightedTests = []struct { 145 desc string 146 147 src graph.Weighted 148 dst graphWeightedBuilder 149 150 // If want is nil, compare to src. 151 want graph.Graph 152 }{ 153 { 154 desc: "undirected to undirected", 155 src: func() graph.Weighted { 156 g := simple.NewWeightedUndirectedGraph(0, 0) 157 g.AddNode(simple.Node(-1)) 158 for _, e := range []simple.WeightedEdge{ 159 {F: simple.Node(0), T: simple.Node(1), W: 1}, 160 {F: simple.Node(0), T: simple.Node(3), W: 1}, 161 {F: simple.Node(1), T: simple.Node(2), W: 1}, 162 } { 163 g.SetWeightedEdge(e) 164 } 165 return g 166 }(), 167 dst: simple.NewWeightedUndirectedGraph(0, 0), 168 }, 169 { 170 desc: "undirected to directed", 171 src: func() graph.Weighted { 172 g := simple.NewWeightedUndirectedGraph(0, 0) 173 g.AddNode(simple.Node(-1)) 174 for _, e := range []simple.WeightedEdge{ 175 {F: simple.Node(0), T: simple.Node(1), W: 1}, 176 {F: simple.Node(0), T: simple.Node(3), W: 1}, 177 {F: simple.Node(1), T: simple.Node(2), W: 1}, 178 } { 179 g.SetWeightedEdge(e) 180 } 181 return g 182 }(), 183 dst: simple.NewWeightedDirectedGraph(0, 0), 184 185 want: func() graph.Graph { 186 g := simple.NewWeightedDirectedGraph(0, 0) 187 g.AddNode(simple.Node(-1)) 188 for _, e := range []simple.WeightedEdge{ 189 {F: simple.Node(0), T: simple.Node(1), W: 1}, 190 {F: simple.Node(0), T: simple.Node(3), W: 1}, 191 {F: simple.Node(1), T: simple.Node(2), W: 1}, 192 } { 193 // want is a directed graph copied from 194 // an undirected graph so we need to have 195 // all edges in both directions. 196 g.SetWeightedEdge(e) 197 e.T, e.F = e.F, e.T 198 g.SetWeightedEdge(e) 199 } 200 return g 201 }(), 202 }, 203 { 204 desc: "directed to undirected", 205 src: func() graph.Weighted { 206 g := simple.NewWeightedDirectedGraph(0, 0) 207 g.AddNode(simple.Node(-1)) 208 for _, e := range []simple.WeightedEdge{ 209 {F: simple.Node(0), T: simple.Node(1), W: 1}, 210 {F: simple.Node(0), T: simple.Node(3), W: 1}, 211 {F: simple.Node(1), T: simple.Node(2), W: 1}, 212 } { 213 g.SetWeightedEdge(e) 214 } 215 return g 216 }(), 217 dst: simple.NewWeightedUndirectedGraph(0, 0), 218 219 want: func() graph.Weighted { 220 g := simple.NewWeightedUndirectedGraph(0, 0) 221 g.AddNode(simple.Node(-1)) 222 for _, e := range []simple.WeightedEdge{ 223 {F: simple.Node(0), T: simple.Node(1), W: 1}, 224 {F: simple.Node(0), T: simple.Node(3), W: 1}, 225 {F: simple.Node(1), T: simple.Node(2), W: 1}, 226 } { 227 g.SetWeightedEdge(e) 228 } 229 return g 230 }(), 231 }, 232 { 233 desc: "directed to directed", 234 src: func() graph.Weighted { 235 g := simple.NewWeightedDirectedGraph(0, 0) 236 g.AddNode(simple.Node(-1)) 237 for _, e := range []simple.WeightedEdge{ 238 {F: simple.Node(0), T: simple.Node(1), W: 1}, 239 {F: simple.Node(0), T: simple.Node(3), W: 1}, 240 {F: simple.Node(1), T: simple.Node(2), W: 1}, 241 } { 242 g.SetWeightedEdge(e) 243 } 244 return g 245 }(), 246 dst: simple.NewWeightedDirectedGraph(0, 0), 247 }, 248 } 249 250 func TestCopyWeighted(t *testing.T) { 251 for _, test := range copyWeightedTests { 252 graph.CopyWeighted(test.dst, test.src) 253 want := test.want 254 if want == nil { 255 want = test.src 256 } 257 if !same(test.dst, want) { 258 t.Errorf("unexpected copy result for %s", test.desc) 259 } 260 } 261 } 262 263 func same(a, b graph.Graph) bool { 264 aNodes := graph.NodesOf(a.Nodes()) 265 bNodes := graph.NodesOf(b.Nodes()) 266 ordered.ByID(aNodes) 267 ordered.ByID(bNodes) 268 for i, na := range aNodes { 269 nb := bNodes[i] 270 if na != nb { 271 return false 272 } 273 } 274 for _, u := range graph.NodesOf(a.Nodes()) { 275 aFromU := graph.NodesOf(a.From(u.ID())) 276 bFromU := graph.NodesOf(b.From(u.ID())) 277 if len(aFromU) != len(bFromU) { 278 return false 279 } 280 ordered.ByID(aFromU) 281 ordered.ByID(bFromU) 282 for i, va := range aFromU { 283 vb := bFromU[i] 284 if va != vb { 285 return false 286 } 287 aW, aWok := a.(graph.Weighted) 288 bW, bWok := b.(graph.Weighted) 289 if aWok && bWok { 290 if aW.WeightedEdge(u.ID(), va.ID()).Weight() != bW.WeightedEdge(u.ID(), vb.ID()).Weight() { 291 return false 292 } 293 } 294 } 295 } 296 type edger interface { 297 Edges() graph.Edges 298 } 299 type weightedEdger interface { 300 WeightedEdges() graph.WeightedEdges 301 } 302 var sizeA, sizeB int 303 switch a := a.(type) { 304 case edger: 305 sizeA = len(graph.EdgesOf(a.Edges())) 306 case weightedEdger: 307 sizeA = len(graph.WeightedEdgesOf(a.WeightedEdges())) 308 } 309 switch b := b.(type) { 310 case edger: 311 sizeB = len(graph.EdgesOf(b.Edges())) 312 case weightedEdger: 313 sizeB = len(graph.WeightedEdgesOf(b.WeightedEdges())) 314 } 315 return sizeA == sizeB 316 }