gonum.org/v1/gonum@v0.14.0/graph/simple/undirected_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 const ( 20 usesEmpty = true 21 reversesEdges = true 22 ) 23 24 func undirectedBuilder(nodes []graph.Node, edges []testgraph.WeightedLine, _, _ float64) (g graph.Graph, n []graph.Node, e []testgraph.Edge, s, a float64, ok bool) { 25 seen := set.NewNodes() 26 ug := simple.NewUndirectedGraph() 27 for _, n := range nodes { 28 seen.Add(n) 29 ug.AddNode(n) 30 } 31 for _, edge := range edges { 32 if edge.From().ID() == edge.To().ID() { 33 continue 34 } 35 f := ug.Node(edge.From().ID()) 36 if f == nil { 37 f = edge.From() 38 } 39 t := ug.Node(edge.To().ID()) 40 if t == nil { 41 t = edge.To() 42 } 43 ce := simple.Edge{F: f, T: t} 44 seen.Add(ce.F) 45 seen.Add(ce.T) 46 e = append(e, ce) 47 ug.SetEdge(ce) 48 } 49 if len(e) == 0 && len(edges) != 0 { 50 return nil, nil, nil, math.NaN(), math.NaN(), false 51 } 52 if len(seen) != 0 { 53 n = make([]graph.Node, 0, len(seen)) 54 } 55 for _, sn := range seen { 56 n = append(n, sn) 57 } 58 return ug, n, e, math.NaN(), math.NaN(), true 59 } 60 61 func TestUndirected(t *testing.T) { 62 t.Run("EdgeExistence", func(t *testing.T) { 63 testgraph.EdgeExistence(t, undirectedBuilder, reversesEdges) 64 }) 65 t.Run("NodeExistence", func(t *testing.T) { 66 testgraph.NodeExistence(t, undirectedBuilder) 67 }) 68 t.Run("ReturnAdjacentNodes", func(t *testing.T) { 69 testgraph.ReturnAdjacentNodes(t, undirectedBuilder, usesEmpty, reversesEdges) 70 }) 71 t.Run("ReturnAllEdges", func(t *testing.T) { 72 testgraph.ReturnAllEdges(t, undirectedBuilder, usesEmpty) 73 }) 74 t.Run("ReturnAllNodes", func(t *testing.T) { 75 testgraph.ReturnAllNodes(t, undirectedBuilder, usesEmpty) 76 }) 77 t.Run("ReturnEdgeSlice", func(t *testing.T) { 78 testgraph.ReturnEdgeSlice(t, undirectedBuilder, usesEmpty) 79 }) 80 t.Run("ReturnNodeSlice", func(t *testing.T) { 81 testgraph.ReturnNodeSlice(t, undirectedBuilder, usesEmpty) 82 }) 83 84 t.Run("AddNodes", func(t *testing.T) { 85 testgraph.AddNodes(t, simple.NewUndirectedGraph(), 100) 86 }) 87 t.Run("AddArbitraryNodes", func(t *testing.T) { 88 testgraph.AddArbitraryNodes(t, 89 simple.NewUndirectedGraph(), 90 testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }), 91 ) 92 }) 93 t.Run("RemoveNodes", func(t *testing.T) { 94 g := simple.NewUndirectedGraph() 95 it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) 96 for it.Next() { 97 g.AddNode(it.Node()) 98 } 99 it.Reset() 100 rnd := rand.New(rand.NewSource(1)) 101 for it.Next() { 102 u := it.Node() 103 d := rnd.Intn(5) 104 vit := g.Nodes() 105 for d >= 0 && vit.Next() { 106 v := vit.Node() 107 if v.ID() == u.ID() { 108 continue 109 } 110 d-- 111 g.SetEdge(g.NewEdge(u, v)) 112 } 113 } 114 testgraph.RemoveNodes(t, g) 115 }) 116 t.Run("AddEdges", func(t *testing.T) { 117 testgraph.AddEdges(t, 100, 118 simple.NewUndirectedGraph(), 119 func(id int64) graph.Node { return simple.Node(id) }, 120 false, // Cannot set self-loops. 121 true, // Can update nodes. 122 ) 123 }) 124 t.Run("NoLoopAddEdges", func(t *testing.T) { 125 testgraph.NoLoopAddEdges(t, 100, 126 simple.NewUndirectedGraph(), 127 func(id int64) graph.Node { return simple.Node(id) }, 128 ) 129 }) 130 t.Run("RemoveEdges", func(t *testing.T) { 131 g := simple.NewUndirectedGraph() 132 it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return simple.Node(id) }) 133 for it.Next() { 134 g.AddNode(it.Node()) 135 } 136 it.Reset() 137 rnd := rand.New(rand.NewSource(1)) 138 for it.Next() { 139 u := it.Node() 140 d := rnd.Intn(5) 141 vit := g.Nodes() 142 for d >= 0 && vit.Next() { 143 v := vit.Node() 144 if v.ID() == u.ID() { 145 continue 146 } 147 d-- 148 g.SetEdge(g.NewEdge(u, v)) 149 } 150 } 151 testgraph.RemoveEdges(t, g, g.Edges()) 152 }) 153 } 154 155 func TestAssertMutableNotDirected(t *testing.T) { 156 var g graph.UndirectedBuilder = simple.NewUndirectedGraph() 157 if _, ok := g.(graph.Directed); ok { 158 t.Fatal("Graph is directed, but a MutableGraph cannot safely be directed!") 159 } 160 } 161 162 func TestMaxID(t *testing.T) { 163 g := simple.NewUndirectedGraph() 164 nodes := make(map[graph.Node]struct{}) 165 for i := simple.Node(0); i < 3; i++ { 166 g.AddNode(i) 167 nodes[i] = struct{}{} 168 } 169 g.RemoveNode(int64(0)) 170 delete(nodes, simple.Node(0)) 171 g.RemoveNode(int64(2)) 172 delete(nodes, simple.Node(2)) 173 n := g.NewNode() 174 g.AddNode(n) 175 if g.Node(n.ID()) == nil { 176 t.Error("added node does not exist in graph") 177 } 178 if _, exists := nodes[n]; exists { 179 t.Errorf("Created already existing node id: %v", n.ID()) 180 } 181 } 182 183 // Test for issue #123 https://github.com/gonum/graph/issues/123 184 func TestIssue123UndirectedGraph(t *testing.T) { 185 defer func() { 186 if r := recover(); r != nil { 187 t.Errorf("unexpected panic: %v", r) 188 } 189 }() 190 g := simple.NewUndirectedGraph() 191 192 n0 := g.NewNode() 193 g.AddNode(n0) 194 195 n1 := g.NewNode() 196 g.AddNode(n1) 197 198 g.RemoveNode(n0.ID()) 199 200 n2 := g.NewNode() 201 g.AddNode(n2) 202 }