gonum.org/v1/gonum@v0.14.0/graph/simple/weighted_directed_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 simple_test 6 7 import ( 8 "math" 9 "testing" 10 11 "golang.org/x/exp/rand" 12 13 "gonum.org/v1/gonum/graph" 14 "gonum.org/v1/gonum/graph/internal/set" 15 "gonum.org/v1/gonum/graph/simple" 16 "gonum.org/v1/gonum/graph/testgraph" 17 ) 18 19 func weightedDirectedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, self, absent float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { 20 seen := set.NewNodes() 21 dg := simple.NewWeightedDirectedGraph(self, absent) 22 for _, n := range nodes { 23 seen.Add(n) 24 dg.AddNode(n) 25 } 26 for _, edge := range edges { 27 if edge.From().ID() == edge.To().ID() { 28 continue 29 } 30 f := dg.Node(edge.From().ID()) 31 if f == nil { 32 f = edge.From() 33 } 34 t := dg.Node(edge.To().ID()) 35 if t == nil { 36 t = edge.To() 37 } 38 ce := simple.WeightedEdge{F: f, T: t, W: edge.Weight()} 39 seen.Add(ce.F) 40 seen.Add(ce.T) 41 e = append(e, ce) 42 dg.SetWeightedEdge(ce) 43 } 44 if len(e) == 0 && len(edges) != 0 { 45 return nil, nil, nil, math.NaN(), math.NaN(), false 46 } 47 if len(seen) != 0 { 48 n = make([]graph.Node, 0, len(seen)) 49 } 50 for _, sn := range seen { 51 n = append(n, sn) 52 } 53 return dg, n, e, self, absent, true 54 } 55 56 func TestWeightedDirected(t *testing.T) { 57 t.Run("EdgeExistence", func(t *testing.T) { 58 testgraph.EdgeExistence(t, weightedDirectedBuilder, reversesEdges) 59 }) 60 t.Run("NodeExistence", func(t *testing.T) { 61 testgraph.NodeExistence(t, weightedDirectedBuilder) 62 }) 63 t.Run("ReturnAdjacentNodes", func(t *testing.T) { 64 testgraph.ReturnAdjacentNodes(t, weightedDirectedBuilder, usesEmpty, reversesEdges) 65 }) 66 t.Run("ReturnAllEdges", func(t *testing.T) { 67 testgraph.ReturnAllEdges(t, weightedDirectedBuilder, usesEmpty) 68 }) 69 t.Run("ReturnAllNodes", func(t *testing.T) { 70 testgraph.ReturnAllNodes(t, weightedDirectedBuilder, usesEmpty) 71 }) 72 t.Run("ReturnAllWeightedEdges", func(t *testing.T) { 73 testgraph.ReturnAllWeightedEdges(t, weightedDirectedBuilder, usesEmpty) 74 }) 75 t.Run("ReturnEdgeSlice", func(t *testing.T) { 76 testgraph.ReturnEdgeSlice(t, weightedDirectedBuilder, usesEmpty) 77 }) 78 t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) { 79 testgraph.ReturnWeightedEdgeSlice(t, weightedDirectedBuilder, usesEmpty) 80 }) 81 t.Run("ReturnNodeSlice", func(t *testing.T) { 82 testgraph.ReturnNodeSlice(t, weightedDirectedBuilder, usesEmpty) 83 }) 84 t.Run("Weight", func(t *testing.T) { 85 testgraph.Weight(t, weightedDirectedBuilder) 86 }) 87 88 t.Run("AddNodes", func(t *testing.T) { 89 testgraph.AddNodes(t, simple.NewWeightedDirectedGraph(1, 0), 100) 90 }) 91 t.Run("AddArbitraryNodes", func(t *testing.T) { 92 testgraph.AddArbitraryNodes(t, 93 simple.NewWeightedDirectedGraph(1, 0), 94 testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }), 95 ) 96 }) 97 t.Run("RemoveNodes", func(t *testing.T) { 98 g := simple.NewWeightedDirectedGraph(1, 0) 99 it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) 100 for it.Next() { 101 g.AddNode(it.Node()) 102 } 103 it.Reset() 104 rnd := rand.New(rand.NewSource(1)) 105 for it.Next() { 106 u := it.Node() 107 d := rnd.Intn(5) 108 vit := g.Nodes() 109 for d >= 0 && vit.Next() { 110 v := vit.Node() 111 if v.ID() == u.ID() { 112 continue 113 } 114 d-- 115 g.SetWeightedEdge(g.NewWeightedEdge(u, v, 1)) 116 } 117 } 118 testgraph.RemoveNodes(t, g) 119 }) 120 t.Run("AddWeightedEdges", func(t *testing.T) { 121 testgraph.AddWeightedEdges(t, 100, 122 simple.NewWeightedDirectedGraph(1, 0), 123 0.5, 124 func(id int64) graph.Node { return simple.Node(id) }, 125 false, // Cannot set self-loops. 126 true, // Can update nodes. 127 ) 128 }) 129 t.Run("NoLoopAddWeightedEdges", func(t *testing.T) { 130 testgraph.NoLoopAddWeightedEdges(t, 100, 131 simple.NewWeightedDirectedGraph(1, 0), 132 0.5, 133 func(id int64) graph.Node { return simple.Node(id) }, 134 ) 135 }) 136 t.Run("RemoveEdges", func(t *testing.T) { 137 g := simple.NewWeightedDirectedGraph(1, 0) 138 it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) 139 for it.Next() { 140 g.AddNode(it.Node()) 141 } 142 it.Reset() 143 rnd := rand.New(rand.NewSource(1)) 144 for it.Next() { 145 u := it.Node() 146 d := rnd.Intn(5) 147 vit := g.Nodes() 148 for d >= 0 && vit.Next() { 149 v := vit.Node() 150 if v.ID() == u.ID() { 151 continue 152 } 153 d-- 154 g.SetWeightedEdge(g.NewWeightedEdge(u, v, 1)) 155 } 156 } 157 testgraph.RemoveEdges(t, g, g.Edges()) 158 }) 159 } 160 161 // Tests Issue #27 162 func TestWeightedEdgeOvercounting(t *testing.T) { 163 g := generateDummyWeightedGraph() 164 165 if neigh := graph.NodesOf(g.From(int64(2))); len(neigh) != 2 { 166 t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh)) 167 } 168 } 169 170 func generateDummyWeightedGraph() *simple.WeightedDirectedGraph { 171 nodes := [4]struct{ srcID, targetID int }{ 172 {2, 1}, 173 {1, 0}, 174 {2, 0}, 175 {0, 2}, 176 } 177 178 g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) 179 180 for _, n := range nodes { 181 g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node(n.srcID), T: simple.Node(n.targetID), W: 1}) 182 } 183 184 return g 185 } 186 187 // Test for issue #123 https://github.com/gonum/graph/issues/123 188 func TestIssue123WeightedDirectedGraph(t *testing.T) { 189 defer func() { 190 if r := recover(); r != nil { 191 t.Errorf("unexpected panic: %v", r) 192 } 193 }() 194 g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) 195 196 n0 := g.NewNode() 197 g.AddNode(n0) 198 199 n1 := g.NewNode() 200 g.AddNode(n1) 201 202 g.RemoveNode(n0.ID()) 203 204 n2 := g.NewNode() 205 g.AddNode(n2) 206 }