graph/multi: wire up node and line addition and deletion tests
Fix failing case for RemoveLine in the undirected types.
MODIFY
graph/multi/directed_test.go
graph/multi/directed_test.go
@@ -8,8 +8,11 @@ import (
"math"
"testing"
+ "golang.org/x/exp/rand"
+
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/set"
+ "gonum.org/v1/gonum/graph/iterator"
"gonum.org/v1/gonum/graph/multi"
"gonum.org/v1/gonum/graph/testgraph"
)
@@ -64,6 +67,69 @@ func TestDirected(t *testing.T) {
t.Run("ReturnNodeSlice", func(t *testing.T) {
testgraph.ReturnNodeSlice(t, directedBuilder, true)
})
+
+ t.Run("AddNodes", func(t *testing.T) {
+ testgraph.AddNodes(t, multi.NewDirectedGraph(), 100)
+ })
+ t.Run("AddArbitraryNodes", func(t *testing.T) {
+ testgraph.AddArbitraryNodes(t,
+ multi.NewDirectedGraph(),
+ testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }),
+ )
+ })
+ t.Run("RemoveNodes", func(t *testing.T) {
+ g := multi.NewDirectedGraph()
+ it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) })
+ for it.Next() {
+ g.AddNode(it.Node())
+ }
+ it.Reset()
+ rnd := rand.New(rand.NewSource(1))
+ for it.Next() {
+ u := it.Node()
+ d := rnd.Intn(5)
+ vit := g.Nodes()
+ for d >= 0 && vit.Next() {
+ v := vit.Node()
+ d--
+ g.SetLine(g.NewLine(u, v))
+ }
+ }
+ testgraph.RemoveNodes(t, g)
+ })
+ t.Run("AddLines", func(t *testing.T) {
+ testgraph.AddLines(t, 100,
+ multi.NewDirectedGraph(),
+ func(id int64) graph.Node { return multi.Node(id) },
+ true, // Can update nodes.
+ )
+ })
+ t.Run("RemoveLines", func(t *testing.T) {
+ g := multi.NewDirectedGraph()
+ it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) })
+ for it.Next() {
+ g.AddNode(it.Node())
+ }
+ it.Reset()
+ var lines []graph.Line
+ rnd := rand.New(rand.NewSource(1))
+ for it.Next() {
+ u := it.Node()
+ d := rnd.Intn(5)
+ vit := g.Nodes()
+ for d >= 0 && vit.Next() {
+ v := vit.Node()
+ d--
+ l := g.NewLine(u, v)
+ g.SetLine(l)
+ lines = append(lines, l)
+ }
+ }
+ rnd.Shuffle(len(lines), func(i, j int) {
+ lines[i], lines[j] = lines[j], lines[i]
+ })
+ testgraph.RemoveLines(t, g, iterator.NewOrderedLines(lines))
+ })
}
// Tests Issue #27

MODIFY
graph/multi/undirected.go
graph/multi/undirected.go
@@ -196,8 +196,11 @@ func (g *UndirectedGraph) RemoveLine(fid, tid, id int64) {
return
}
+ delete(g.lines[fid][tid], id)
+ if len(g.lines[fid][tid]) == 0 {
delete(g.lines[fid], tid)
- delete(g.lines[tid], fid)
+ }
+ delete(g.lines[tid][fid], id)
if len(g.lines[tid][fid]) == 0 {
delete(g.lines[tid], fid)
}

MODIFY
graph/multi/undirected_test.go
graph/multi/undirected_test.go
@@ -8,8 +8,11 @@ import (
"math"
"testing"
+ "golang.org/x/exp/rand"
+
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/set"
+ "gonum.org/v1/gonum/graph/iterator"
"gonum.org/v1/gonum/graph/multi"
"gonum.org/v1/gonum/graph/testgraph"
)
@@ -64,6 +67,69 @@ func TestUndirected(t *testing.T) {
t.Run("ReturnNodeSlice", func(t *testing.T) {
testgraph.ReturnNodeSlice(t, undirectedBuilder, true)
})
+
+ t.Run("AddNodes", func(t *testing.T) {
+ testgraph.AddNodes(t, multi.NewUndirectedGraph(), 100)
+ })
+ t.Run("AddArbitraryNodes", func(t *testing.T) {
+ testgraph.AddArbitraryNodes(t,
+ multi.NewUndirectedGraph(),
+ testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }),
+ )
+ })
+ t.Run("RemoveNodes", func(t *testing.T) {
+ g := multi.NewUndirectedGraph()
+ it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) })
+ for it.Next() {
+ g.AddNode(it.Node())
+ }
+ it.Reset()
+ rnd := rand.New(rand.NewSource(1))
+ for it.Next() {
+ u := it.Node()
+ d := rnd.Intn(5)
+ vit := g.Nodes()
+ for d >= 0 && vit.Next() {
+ v := vit.Node()
+ d--
+ g.SetLine(g.NewLine(u, v))
+ }
+ }
+ testgraph.RemoveNodes(t, g)
+ })
+ t.Run("AddLines", func(t *testing.T) {
+ testgraph.AddLines(t, 100,
+ multi.NewUndirectedGraph(),
+ func(id int64) graph.Node { return multi.Node(id) },
+ true, // Can update nodes.
+ )
+ })
+ t.Run("RemoveLines", func(t *testing.T) {
+ g := multi.NewUndirectedGraph()
+ it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) })
+ for it.Next() {
+ g.AddNode(it.Node())
+ }
+ it.Reset()
+ var lines []graph.Line
+ rnd := rand.New(rand.NewSource(1))
+ for it.Next() {
+ u := it.Node()
+ d := rnd.Intn(5)
+ vit := g.Nodes()
+ for d >= 0 && vit.Next() {
+ v := vit.Node()
+ d--
+ l := g.NewLine(u, v)
+ g.SetLine(l)
+ lines = append(lines, l)
+ }
+ }
+ rnd.Shuffle(len(lines), func(i, j int) {
+ lines[i], lines[j] = lines[j], lines[i]
+ })
+ testgraph.RemoveLines(t, g, iterator.NewOrderedLines(lines))
+ })
}
func TestMaxID(t *testing.T) {

MODIFY
graph/multi/weighted_directed_test.go
graph/multi/weighted_directed_test.go
@@ -7,8 +7,11 @@ package multi_test
import (
"testing"
+ "golang.org/x/exp/rand"
+
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/set"
+ "gonum.org/v1/gonum/graph/iterator"
"gonum.org/v1/gonum/graph/multi"
"gonum.org/v1/gonum/graph/testgraph"
)
@@ -80,6 +83,70 @@ func TestWeightedDirected(t *testing.T) {
t.Run("Weight", func(t *testing.T) {
testgraph.Weight(t, weightedDirectedBuilder)
})
+
+ t.Run("AddNodes", func(t *testing.T) {
+ testgraph.AddNodes(t, multi.NewWeightedDirectedGraph(), 100)
+ })
+ t.Run("AddArbitraryNodes", func(t *testing.T) {
+ testgraph.AddArbitraryNodes(t,
+ multi.NewWeightedDirectedGraph(),
+ testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }),
+ )
+ })
+ t.Run("RemoveNodes", func(t *testing.T) {
+ g := multi.NewWeightedDirectedGraph()
+ it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) })
+ for it.Next() {
+ g.AddNode(it.Node())
+ }
+ it.Reset()
+ rnd := rand.New(rand.NewSource(1))
+ for it.Next() {
+ u := it.Node()
+ d := rnd.Intn(5)
+ vit := g.Nodes()
+ for d >= 0 && vit.Next() {
+ v := vit.Node()
+ d--
+ g.SetWeightedLine(g.NewWeightedLine(u, v, 1))
+ }
+ }
+ testgraph.RemoveNodes(t, g)
+ })
+ t.Run("AddWeightedLines", func(t *testing.T) {
+ testgraph.AddWeightedLines(t, 100,
+ multi.NewWeightedDirectedGraph(),
+ 0.5,
+ func(id int64) graph.Node { return multi.Node(id) },
+ true, // Can update nodes.
+ )
+ })
+ t.Run("RemoveLines", func(t *testing.T) {
+ g := multi.NewWeightedDirectedGraph()
+ it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) })
+ for it.Next() {
+ g.AddNode(it.Node())
+ }
+ it.Reset()
+ var lines []graph.Line
+ rnd := rand.New(rand.NewSource(1))
+ for it.Next() {
+ u := it.Node()
+ d := rnd.Intn(5)
+ vit := g.Nodes()
+ for d >= 0 && vit.Next() {
+ v := vit.Node()
+ d--
+ l := g.NewWeightedLine(u, v, 1)
+ g.SetWeightedLine(l)
+ lines = append(lines, l)
+ }
+ }
+ rnd.Shuffle(len(lines), func(i, j int) {
+ lines[i], lines[j] = lines[j], lines[i]
+ })
+ testgraph.RemoveLines(t, g, iterator.NewOrderedLines(lines))
+ })
}
// Tests Issue #27

MODIFY
graph/multi/weighted_undirected.go
graph/multi/weighted_undirected.go
@@ -209,8 +209,11 @@ func (g *WeightedUndirectedGraph) RemoveLine(fid, tid, id int64) {
return
}
+ delete(g.lines[fid][tid], id)
+ if len(g.lines[fid][tid]) == 0 {
delete(g.lines[fid], tid)
- delete(g.lines[tid], fid)
+ }
+ delete(g.lines[tid][fid], id)
if len(g.lines[tid][fid]) == 0 {
delete(g.lines[tid], fid)
}

MODIFY
graph/multi/weighted_undirected_test.go
graph/multi/weighted_undirected_test.go
@@ -7,8 +7,11 @@ package multi_test
import (
"testing"
+ "golang.org/x/exp/rand"
+
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/set"
+ "gonum.org/v1/gonum/graph/iterator"
"gonum.org/v1/gonum/graph/multi"
"gonum.org/v1/gonum/graph/testgraph"
)
@@ -80,6 +83,70 @@ func TestWeightedUndirected(t *testing.T) {
t.Run("Weight", func(t *testing.T) {
testgraph.Weight(t, weightedUndirectedBuilder)
})
+
+ t.Run("AddNodes", func(t *testing.T) {
+ testgraph.AddNodes(t, multi.NewWeightedUndirectedGraph(), 100)
+ })
+ t.Run("AddArbitraryNodes", func(t *testing.T) {
+ testgraph.AddArbitraryNodes(t,
+ multi.NewWeightedUndirectedGraph(),
+ testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) }),
+ )
+ })
+ t.Run("RemoveNodes", func(t *testing.T) {
+ g := multi.NewWeightedUndirectedGraph()
+ it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) })
+ for it.Next() {
+ g.AddNode(it.Node())
+ }
+ it.Reset()
+ rnd := rand.New(rand.NewSource(1))
+ for it.Next() {
+ u := it.Node()
+ d := rnd.Intn(5)
+ vit := g.Nodes()
+ for d >= 0 && vit.Next() {
+ v := vit.Node()
+ d--
+ g.SetWeightedLine(g.NewWeightedLine(u, v, 1))
+ }
+ }
+ testgraph.RemoveNodes(t, g)
+ })
+ t.Run("AddWeightedLines", func(t *testing.T) {
+ testgraph.AddWeightedLines(t, 100,
+ multi.NewWeightedUndirectedGraph(),
+ 0.5,
+ func(id int64) graph.Node { return multi.Node(id) },
+ true, // Can update nodes.
+ )
+ })
+ t.Run("RemoveLines", func(t *testing.T) {
+ g := multi.NewWeightedUndirectedGraph()
+ it := testgraph.NewRandomNodes(100, 1, func(id int64) graph.Node { return multi.Node(id) })
+ for it.Next() {
+ g.AddNode(it.Node())
+ }
+ it.Reset()
+ var lines []graph.Line
+ rnd := rand.New(rand.NewSource(1))
+ for it.Next() {
+ u := it.Node()
+ d := rnd.Intn(5)
+ vit := g.Nodes()
+ for d >= 0 && vit.Next() {
+ v := vit.Node()
+ d--
+ l := g.NewWeightedLine(u, v, 1)
+ g.SetWeightedLine(l)
+ lines = append(lines, l)
+ }
+ }
+ rnd.Shuffle(len(lines), func(i, j int) {
+ lines[i], lines[j] = lines[j], lines[i]
+ })
+ testgraph.RemoveLines(t, g, iterator.NewOrderedLines(lines))
+ })
}
func TestWeightedMaxID(t *testing.T) {

graph/multi: wire up node and line addition and deletion tests

Fix failing case for RemoveLine in the undirected types.