gonum.org/v1/gonum@v0.14.0/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 "gonum.org/v1/gonum/graph" 11 "gonum.org/v1/gonum/graph/internal/ordered" 12 "gonum.org/v1/gonum/graph/simple" 13 ) 14 15 type graphBuilder interface { 16 graph.Graph 17 graph.Builder 18 } 19 20 func TestCopy(t *testing.T) { 21 copyTests := []struct { 22 desc string 23 24 src graph.Graph 25 dst graphBuilder 26 27 // If want is nil, compare to src. 28 want graph.Graph 29 }{ 30 { 31 desc: "undirected to undirected", 32 src: func() graph.Graph { 33 g := simple.NewUndirectedGraph() 34 g.AddNode(simple.Node(-1)) 35 for _, e := range []simple.Edge{ 36 {F: simple.Node(0), T: simple.Node(1)}, 37 {F: simple.Node(0), T: simple.Node(3)}, 38 {F: simple.Node(1), T: simple.Node(2)}, 39 } { 40 g.SetEdge(e) 41 } 42 return g 43 }(), 44 dst: simple.NewUndirectedGraph(), 45 }, 46 { 47 desc: "undirected to directed", 48 src: func() graph.Graph { 49 g := simple.NewUndirectedGraph() 50 g.AddNode(simple.Node(-1)) 51 for _, e := range []simple.Edge{ 52 {F: simple.Node(0), T: simple.Node(1)}, 53 {F: simple.Node(0), T: simple.Node(3)}, 54 {F: simple.Node(1), T: simple.Node(2)}, 55 } { 56 g.SetEdge(e) 57 } 58 return g 59 }(), 60 dst: simple.NewDirectedGraph(), 61 62 want: func() graph.Graph { 63 g := simple.NewDirectedGraph() 64 g.AddNode(simple.Node(-1)) 65 for _, e := range []simple.Edge{ 66 {F: simple.Node(0), T: simple.Node(1)}, 67 {F: simple.Node(0), T: simple.Node(3)}, 68 {F: simple.Node(1), T: simple.Node(2)}, 69 } { 70 // want is a directed graph copied from 71 // an undirected graph so we need to have 72 // all edges in both directions. 73 g.SetEdge(e) 74 e.T, e.F = e.F, e.T 75 g.SetEdge(e) 76 } 77 return g 78 }(), 79 }, 80 { 81 desc: "directed to undirected", 82 src: func() graph.Graph { 83 g := simple.NewDirectedGraph() 84 g.AddNode(simple.Node(-1)) 85 for _, e := range []simple.Edge{ 86 {F: simple.Node(0), T: simple.Node(1)}, 87 {F: simple.Node(0), T: simple.Node(3)}, 88 {F: simple.Node(1), T: simple.Node(2)}, 89 } { 90 g.SetEdge(e) 91 } 92 return g 93 }(), 94 dst: simple.NewUndirectedGraph(), 95 96 want: func() graph.Graph { 97 g := simple.NewUndirectedGraph() 98 g.AddNode(simple.Node(-1)) 99 for _, e := range []simple.Edge{ 100 {F: simple.Node(0), T: simple.Node(1)}, 101 {F: simple.Node(0), T: simple.Node(3)}, 102 {F: simple.Node(1), T: simple.Node(2)}, 103 } { 104 g.SetEdge(e) 105 } 106 return g 107 }(), 108 }, 109 { 110 desc: "directed to directed", 111 src: func() graph.Graph { 112 g := simple.NewDirectedGraph() 113 g.AddNode(simple.Node(-1)) 114 for _, e := range []simple.Edge{ 115 {F: simple.Node(0), T: simple.Node(1)}, 116 {F: simple.Node(0), T: simple.Node(3)}, 117 {F: simple.Node(1), T: simple.Node(2)}, 118 } { 119 g.SetEdge(e) 120 } 121 return g 122 }(), 123 dst: simple.NewDirectedGraph(), 124 }, 125 } 126 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 func TestCopyWeighted(t *testing.T) { 145 copyWeightedTests := []struct { 146 desc string 147 148 src graph.Weighted 149 dst graphWeightedBuilder 150 151 // If want is nil, compare to src. 152 want graph.Graph 153 }{ 154 { 155 desc: "undirected to undirected", 156 src: func() graph.Weighted { 157 g := simple.NewWeightedUndirectedGraph(0, 0) 158 g.AddNode(simple.Node(-1)) 159 for _, e := range []simple.WeightedEdge{ 160 {F: simple.Node(0), T: simple.Node(1), W: 1}, 161 {F: simple.Node(0), T: simple.Node(3), W: 1}, 162 {F: simple.Node(1), T: simple.Node(2), W: 1}, 163 } { 164 g.SetWeightedEdge(e) 165 } 166 return g 167 }(), 168 dst: simple.NewWeightedUndirectedGraph(0, 0), 169 }, 170 { 171 desc: "undirected to directed", 172 src: func() graph.Weighted { 173 g := simple.NewWeightedUndirectedGraph(0, 0) 174 g.AddNode(simple.Node(-1)) 175 for _, e := range []simple.WeightedEdge{ 176 {F: simple.Node(0), T: simple.Node(1), W: 1}, 177 {F: simple.Node(0), T: simple.Node(3), W: 1}, 178 {F: simple.Node(1), T: simple.Node(2), W: 1}, 179 } { 180 g.SetWeightedEdge(e) 181 } 182 return g 183 }(), 184 dst: simple.NewWeightedDirectedGraph(0, 0), 185 186 want: func() graph.Graph { 187 g := simple.NewWeightedDirectedGraph(0, 0) 188 g.AddNode(simple.Node(-1)) 189 for _, e := range []simple.WeightedEdge{ 190 {F: simple.Node(0), T: simple.Node(1), W: 1}, 191 {F: simple.Node(0), T: simple.Node(3), W: 1}, 192 {F: simple.Node(1), T: simple.Node(2), W: 1}, 193 } { 194 // want is a directed graph copied from 195 // an undirected graph so we need to have 196 // all edges in both directions. 197 g.SetWeightedEdge(e) 198 e.T, e.F = e.F, e.T 199 g.SetWeightedEdge(e) 200 } 201 return g 202 }(), 203 }, 204 { 205 desc: "directed to undirected", 206 src: func() graph.Weighted { 207 g := simple.NewWeightedDirectedGraph(0, 0) 208 g.AddNode(simple.Node(-1)) 209 for _, e := range []simple.WeightedEdge{ 210 {F: simple.Node(0), T: simple.Node(1), W: 1}, 211 {F: simple.Node(0), T: simple.Node(3), W: 1}, 212 {F: simple.Node(1), T: simple.Node(2), W: 1}, 213 } { 214 g.SetWeightedEdge(e) 215 } 216 return g 217 }(), 218 dst: simple.NewWeightedUndirectedGraph(0, 0), 219 220 want: func() graph.Weighted { 221 g := simple.NewWeightedUndirectedGraph(0, 0) 222 g.AddNode(simple.Node(-1)) 223 for _, e := range []simple.WeightedEdge{ 224 {F: simple.Node(0), T: simple.Node(1), W: 1}, 225 {F: simple.Node(0), T: simple.Node(3), W: 1}, 226 {F: simple.Node(1), T: simple.Node(2), W: 1}, 227 } { 228 g.SetWeightedEdge(e) 229 } 230 return g 231 }(), 232 }, 233 { 234 desc: "directed to directed", 235 src: func() graph.Weighted { 236 g := simple.NewWeightedDirectedGraph(0, 0) 237 g.AddNode(simple.Node(-1)) 238 for _, e := range []simple.WeightedEdge{ 239 {F: simple.Node(0), T: simple.Node(1), W: 1}, 240 {F: simple.Node(0), T: simple.Node(3), W: 1}, 241 {F: simple.Node(1), T: simple.Node(2), W: 1}, 242 } { 243 g.SetWeightedEdge(e) 244 } 245 return g 246 }(), 247 dst: simple.NewWeightedDirectedGraph(0, 0), 248 }, 249 } 250 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 }