gonum.org/v1/gonum@v0.14.0/graph/undirect_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 graph_test 6 7 import ( 8 "math" 9 "testing" 10 11 "gonum.org/v1/gonum/graph" 12 "gonum.org/v1/gonum/graph/iterator" 13 "gonum.org/v1/gonum/graph/simple" 14 "gonum.org/v1/gonum/mat" 15 ) 16 17 type weightedDirectedBuilder interface { 18 graph.WeightedBuilder 19 graph.WeightedDirected 20 } 21 22 var weightedDirectedGraphs = []struct { 23 skipUnweighted bool 24 25 g func() weightedDirectedBuilder 26 edges []simple.WeightedEdge 27 absent float64 28 merge func(x, y float64, xe, ye graph.Edge) float64 29 30 want mat.Matrix 31 }{ 32 { 33 g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, 34 edges: []simple.WeightedEdge{ 35 {F: simple.Node(0), T: simple.Node(1), W: 2}, 36 {F: simple.Node(1), T: simple.Node(0), W: 1}, 37 {F: simple.Node(1), T: simple.Node(2), W: 1}, 38 }, 39 want: mat.NewSymDense(3, []float64{ 40 0, (1. + 2.) / 2., 0, 41 (1. + 2.) / 2., 0, 1. / 2., 42 0, 1. / 2., 0, 43 }), 44 }, 45 { 46 g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, 47 edges: []simple.WeightedEdge{ 48 {F: simple.Node(0), T: simple.Node(1), W: 2}, 49 {F: simple.Node(1), T: simple.Node(0), W: 1}, 50 {F: simple.Node(1), T: simple.Node(2), W: 1}, 51 }, 52 absent: 1, 53 merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Sqrt(x * y) }, 54 want: mat.NewSymDense(3, []float64{ 55 0, math.Sqrt(1 * 2), 0, 56 math.Sqrt(1 * 2), 0, math.Sqrt(1 * 1), 57 0, math.Sqrt(1 * 1), 0, 58 }), 59 }, 60 { 61 skipUnweighted: true, // The min merge function cannot be used in the unweighted case. 62 63 g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, 64 edges: []simple.WeightedEdge{ 65 {F: simple.Node(0), T: simple.Node(1), W: 2}, 66 {F: simple.Node(1), T: simple.Node(0), W: 1}, 67 {F: simple.Node(1), T: simple.Node(2), W: 1}, 68 }, 69 merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Min(x, y) }, 70 want: mat.NewSymDense(3, []float64{ 71 0, math.Min(1, 2), 0, 72 math.Min(1, 2), 0, math.Min(1, 0), 73 0, math.Min(1, 0), 0, 74 }), 75 }, 76 { 77 g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, 78 edges: []simple.WeightedEdge{ 79 {F: simple.Node(0), T: simple.Node(1), W: 2}, 80 {F: simple.Node(1), T: simple.Node(0), W: 1}, 81 {F: simple.Node(1), T: simple.Node(2), W: 1}, 82 }, 83 merge: func(x, y float64, xe, ye graph.Edge) float64 { 84 if xe == nil { 85 return y 86 } 87 if ye == nil { 88 return x 89 } 90 return math.Min(x, y) 91 }, 92 want: mat.NewSymDense(3, []float64{ 93 0, math.Min(1, 2), 0, 94 math.Min(1, 2), 0, 1, 95 0, 1, 0, 96 }), 97 }, 98 { 99 g: func() weightedDirectedBuilder { return simple.NewWeightedDirectedGraph(0, 0) }, 100 edges: []simple.WeightedEdge{ 101 {F: simple.Node(0), T: simple.Node(1), W: 2}, 102 {F: simple.Node(1), T: simple.Node(0), W: 1}, 103 {F: simple.Node(1), T: simple.Node(2), W: 1}, 104 }, 105 merge: func(x, y float64, _, _ graph.Edge) float64 { return math.Max(x, y) }, 106 want: mat.NewSymDense(3, []float64{ 107 0, math.Max(1, 2), 0, 108 math.Max(1, 2), 0, math.Max(1, 0), 109 0, math.Max(1, 0), 0, 110 }), 111 }, 112 } 113 114 func TestUndirect(t *testing.T) { 115 for i, test := range weightedDirectedGraphs { 116 if test.skipUnweighted { 117 continue 118 } 119 g := test.g() 120 for _, e := range test.edges { 121 g.SetWeightedEdge(e) 122 } 123 124 src := graph.Undirect{G: g} 125 nodes := graph.NodesOf(src.Nodes()) 126 dst := simple.NewUndirectedMatrixFrom(nodes, 0, 0, 0) 127 for _, u := range nodes { 128 for _, v := range graph.NodesOf(src.From(u.ID())) { 129 dst.SetEdge(src.Edge(u.ID(), v.ID())) 130 } 131 } 132 133 want := unit{test.want} 134 if !mat.Equal(dst.Matrix(), want) { 135 t.Errorf("unexpected result for case %d:\ngot:\n%.4v\nwant:\n%.4v", i, 136 mat.Formatted(dst.Matrix()), 137 mat.Formatted(want), 138 ) 139 } 140 } 141 } 142 143 func TestUndirectWeighted(t *testing.T) { 144 for i, test := range weightedDirectedGraphs { 145 g := test.g() 146 for _, e := range test.edges { 147 g.SetWeightedEdge(e) 148 } 149 150 src := graph.UndirectWeighted{G: g, Absent: test.absent, Merge: test.merge} 151 nodes := graph.NodesOf(src.Nodes()) 152 dst := simple.NewUndirectedMatrixFrom(nodes, 0, 0, 0) 153 for _, u := range nodes { 154 for _, v := range graph.NodesOf(src.From(u.ID())) { 155 dst.SetWeightedEdge(src.WeightedEdge(u.ID(), v.ID())) 156 } 157 } 158 159 if !mat.Equal(dst.Matrix(), test.want) { 160 t.Errorf("unexpected result for case %d:\ngot:\n%.4v\nwant:\n%.4v", i, 161 mat.Formatted(dst.Matrix()), 162 mat.Formatted(test.want), 163 ) 164 } 165 } 166 } 167 168 type unit struct { 169 mat.Matrix 170 } 171 172 func (m unit) At(i, j int) float64 { 173 v := m.Matrix.At(i, j) 174 if v == 0 { 175 return 0 176 } 177 return 1 178 } 179 180 var nodeIteratorPairTests = []struct { 181 a, b graph.Nodes 182 len int 183 }{ 184 {a: graph.Empty, b: graph.Empty, len: 0}, 185 {a: iterator.NewOrderedNodes(nil), b: iterator.NewOrderedNodes(nil), len: 0}, 186 {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), b: graph.Empty, len: 1}, 187 {a: graph.Empty, b: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), len: 1}, 188 {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), b: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), len: 1}, 189 {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(0)}), b: iterator.NewOrderedNodes([]graph.Node{simple.Node(1)}), len: 2}, 190 {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(0), simple.Node(1)}), b: iterator.NewOrderedNodes([]graph.Node{simple.Node(1)}), len: 2}, 191 {a: iterator.NewOrderedNodes([]graph.Node{simple.Node(1)}), b: iterator.NewOrderedNodes([]graph.Node{simple.Node(0), simple.Node(1)}), len: 2}, 192 } 193 194 func TestNodeIteratorPair(t *testing.T) { 195 for _, test := range nodeIteratorPairTests { 196 it := graph.NewNodeIteratorPair(test.a, test.b) 197 for i := 0; i < 2; i++ { 198 n := it.Len() 199 if n != test.len { 200 t.Errorf("unexpected length of iterator construction/reset: got:%d want:%d", n, test.len) 201 } 202 for it.Next() { 203 n-- 204 } 205 if n != 0 { 206 t.Errorf("unexpected remaining nodes after iterator completion: got:%d want:0", n) 207 } 208 it.Reset() 209 } 210 } 211 }