diff --git a/graph/graph_test.go b/graph/graph_test.go index 20f6487d..2ca96872 100644 --- a/graph/graph_test.go +++ b/graph/graph_test.go @@ -17,113 +17,113 @@ type graphBuilder interface { graph.Builder } -var copyTests = []struct { - desc string - - src graph.Graph - dst graphBuilder - - // If want is nil, compare to src. - want graph.Graph -}{ - { - desc: "undirected to undirected", - src: func() graph.Graph { - g := simple.NewUndirectedGraph() - g.AddNode(simple.Node(-1)) - for _, e := range []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - } { - g.SetEdge(e) - } - return g - }(), - dst: simple.NewUndirectedGraph(), - }, - { - desc: "undirected to directed", - src: func() graph.Graph { - g := simple.NewUndirectedGraph() - g.AddNode(simple.Node(-1)) - for _, e := range []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - } { - g.SetEdge(e) - } - return g - }(), - dst: simple.NewDirectedGraph(), - - want: func() graph.Graph { - g := simple.NewDirectedGraph() - g.AddNode(simple.Node(-1)) - for _, e := range []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - } { - // want is a directed graph copied from - // an undirected graph so we need to have - // all edges in both directions. - g.SetEdge(e) - e.T, e.F = e.F, e.T - g.SetEdge(e) - } - return g - }(), - }, - { - desc: "directed to undirected", - src: func() graph.Graph { - g := simple.NewDirectedGraph() - g.AddNode(simple.Node(-1)) - for _, e := range []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - } { - g.SetEdge(e) - } - return g - }(), - dst: simple.NewUndirectedGraph(), - - want: func() graph.Graph { - g := simple.NewUndirectedGraph() - g.AddNode(simple.Node(-1)) - for _, e := range []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - } { - g.SetEdge(e) - } - return g - }(), - }, - { - desc: "directed to directed", - src: func() graph.Graph { - g := simple.NewDirectedGraph() - g.AddNode(simple.Node(-1)) - for _, e := range []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - } { - g.SetEdge(e) - } - return g - }(), - dst: simple.NewDirectedGraph(), - }, -} - func TestCopy(t *testing.T) { + copyTests := []struct { + desc string + + src graph.Graph + dst graphBuilder + + // If want is nil, compare to src. + want graph.Graph + }{ + { + desc: "undirected to undirected", + src: func() graph.Graph { + g := simple.NewUndirectedGraph() + g.AddNode(simple.Node(-1)) + for _, e := range []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + } { + g.SetEdge(e) + } + return g + }(), + dst: simple.NewUndirectedGraph(), + }, + { + desc: "undirected to directed", + src: func() graph.Graph { + g := simple.NewUndirectedGraph() + g.AddNode(simple.Node(-1)) + for _, e := range []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + } { + g.SetEdge(e) + } + return g + }(), + dst: simple.NewDirectedGraph(), + + want: func() graph.Graph { + g := simple.NewDirectedGraph() + g.AddNode(simple.Node(-1)) + for _, e := range []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + } { + // want is a directed graph copied from + // an undirected graph so we need to have + // all edges in both directions. + g.SetEdge(e) + e.T, e.F = e.F, e.T + g.SetEdge(e) + } + return g + }(), + }, + { + desc: "directed to undirected", + src: func() graph.Graph { + g := simple.NewDirectedGraph() + g.AddNode(simple.Node(-1)) + for _, e := range []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + } { + g.SetEdge(e) + } + return g + }(), + dst: simple.NewUndirectedGraph(), + + want: func() graph.Graph { + g := simple.NewUndirectedGraph() + g.AddNode(simple.Node(-1)) + for _, e := range []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + } { + g.SetEdge(e) + } + return g + }(), + }, + { + desc: "directed to directed", + src: func() graph.Graph { + g := simple.NewDirectedGraph() + g.AddNode(simple.Node(-1)) + for _, e := range []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + } { + g.SetEdge(e) + } + return g + }(), + dst: simple.NewDirectedGraph(), + }, + } + for _, test := range copyTests { graph.Copy(test.dst, test.src) want := test.want @@ -141,113 +141,113 @@ type graphWeightedBuilder interface { graph.WeightedBuilder } -var copyWeightedTests = []struct { - desc string - - src graph.Weighted - dst graphWeightedBuilder - - // If want is nil, compare to src. - want graph.Graph -}{ - { - desc: "undirected to undirected", - src: func() graph.Weighted { - g := simple.NewWeightedUndirectedGraph(0, 0) - g.AddNode(simple.Node(-1)) - for _, e := range []simple.WeightedEdge{ - {F: simple.Node(0), T: simple.Node(1), W: 1}, - {F: simple.Node(0), T: simple.Node(3), W: 1}, - {F: simple.Node(1), T: simple.Node(2), W: 1}, - } { - g.SetWeightedEdge(e) - } - return g - }(), - dst: simple.NewWeightedUndirectedGraph(0, 0), - }, - { - desc: "undirected to directed", - src: func() graph.Weighted { - g := simple.NewWeightedUndirectedGraph(0, 0) - g.AddNode(simple.Node(-1)) - for _, e := range []simple.WeightedEdge{ - {F: simple.Node(0), T: simple.Node(1), W: 1}, - {F: simple.Node(0), T: simple.Node(3), W: 1}, - {F: simple.Node(1), T: simple.Node(2), W: 1}, - } { - g.SetWeightedEdge(e) - } - return g - }(), - dst: simple.NewWeightedDirectedGraph(0, 0), - - want: func() graph.Graph { - g := simple.NewWeightedDirectedGraph(0, 0) - g.AddNode(simple.Node(-1)) - for _, e := range []simple.WeightedEdge{ - {F: simple.Node(0), T: simple.Node(1), W: 1}, - {F: simple.Node(0), T: simple.Node(3), W: 1}, - {F: simple.Node(1), T: simple.Node(2), W: 1}, - } { - // want is a directed graph copied from - // an undirected graph so we need to have - // all edges in both directions. - g.SetWeightedEdge(e) - e.T, e.F = e.F, e.T - g.SetWeightedEdge(e) - } - return g - }(), - }, - { - desc: "directed to undirected", - src: func() graph.Weighted { - g := simple.NewWeightedDirectedGraph(0, 0) - g.AddNode(simple.Node(-1)) - for _, e := range []simple.WeightedEdge{ - {F: simple.Node(0), T: simple.Node(1), W: 1}, - {F: simple.Node(0), T: simple.Node(3), W: 1}, - {F: simple.Node(1), T: simple.Node(2), W: 1}, - } { - g.SetWeightedEdge(e) - } - return g - }(), - dst: simple.NewWeightedUndirectedGraph(0, 0), - - want: func() graph.Weighted { - g := simple.NewWeightedUndirectedGraph(0, 0) - g.AddNode(simple.Node(-1)) - for _, e := range []simple.WeightedEdge{ - {F: simple.Node(0), T: simple.Node(1), W: 1}, - {F: simple.Node(0), T: simple.Node(3), W: 1}, - {F: simple.Node(1), T: simple.Node(2), W: 1}, - } { - g.SetWeightedEdge(e) - } - return g - }(), - }, - { - desc: "directed to directed", - src: func() graph.Weighted { - g := simple.NewWeightedDirectedGraph(0, 0) - g.AddNode(simple.Node(-1)) - for _, e := range []simple.WeightedEdge{ - {F: simple.Node(0), T: simple.Node(1), W: 1}, - {F: simple.Node(0), T: simple.Node(3), W: 1}, - {F: simple.Node(1), T: simple.Node(2), W: 1}, - } { - g.SetWeightedEdge(e) - } - return g - }(), - dst: simple.NewWeightedDirectedGraph(0, 0), - }, -} - func TestCopyWeighted(t *testing.T) { + copyWeightedTests := []struct { + desc string + + src graph.Weighted + dst graphWeightedBuilder + + // If want is nil, compare to src. + want graph.Graph + }{ + { + desc: "undirected to undirected", + src: func() graph.Weighted { + g := simple.NewWeightedUndirectedGraph(0, 0) + g.AddNode(simple.Node(-1)) + for _, e := range []simple.WeightedEdge{ + {F: simple.Node(0), T: simple.Node(1), W: 1}, + {F: simple.Node(0), T: simple.Node(3), W: 1}, + {F: simple.Node(1), T: simple.Node(2), W: 1}, + } { + g.SetWeightedEdge(e) + } + return g + }(), + dst: simple.NewWeightedUndirectedGraph(0, 0), + }, + { + desc: "undirected to directed", + src: func() graph.Weighted { + g := simple.NewWeightedUndirectedGraph(0, 0) + g.AddNode(simple.Node(-1)) + for _, e := range []simple.WeightedEdge{ + {F: simple.Node(0), T: simple.Node(1), W: 1}, + {F: simple.Node(0), T: simple.Node(3), W: 1}, + {F: simple.Node(1), T: simple.Node(2), W: 1}, + } { + g.SetWeightedEdge(e) + } + return g + }(), + dst: simple.NewWeightedDirectedGraph(0, 0), + + want: func() graph.Graph { + g := simple.NewWeightedDirectedGraph(0, 0) + g.AddNode(simple.Node(-1)) + for _, e := range []simple.WeightedEdge{ + {F: simple.Node(0), T: simple.Node(1), W: 1}, + {F: simple.Node(0), T: simple.Node(3), W: 1}, + {F: simple.Node(1), T: simple.Node(2), W: 1}, + } { + // want is a directed graph copied from + // an undirected graph so we need to have + // all edges in both directions. + g.SetWeightedEdge(e) + e.T, e.F = e.F, e.T + g.SetWeightedEdge(e) + } + return g + }(), + }, + { + desc: "directed to undirected", + src: func() graph.Weighted { + g := simple.NewWeightedDirectedGraph(0, 0) + g.AddNode(simple.Node(-1)) + for _, e := range []simple.WeightedEdge{ + {F: simple.Node(0), T: simple.Node(1), W: 1}, + {F: simple.Node(0), T: simple.Node(3), W: 1}, + {F: simple.Node(1), T: simple.Node(2), W: 1}, + } { + g.SetWeightedEdge(e) + } + return g + }(), + dst: simple.NewWeightedUndirectedGraph(0, 0), + + want: func() graph.Weighted { + g := simple.NewWeightedUndirectedGraph(0, 0) + g.AddNode(simple.Node(-1)) + for _, e := range []simple.WeightedEdge{ + {F: simple.Node(0), T: simple.Node(1), W: 1}, + {F: simple.Node(0), T: simple.Node(3), W: 1}, + {F: simple.Node(1), T: simple.Node(2), W: 1}, + } { + g.SetWeightedEdge(e) + } + return g + }(), + }, + { + desc: "directed to directed", + src: func() graph.Weighted { + g := simple.NewWeightedDirectedGraph(0, 0) + g.AddNode(simple.Node(-1)) + for _, e := range []simple.WeightedEdge{ + {F: simple.Node(0), T: simple.Node(1), W: 1}, + {F: simple.Node(0), T: simple.Node(3), W: 1}, + {F: simple.Node(1), T: simple.Node(2), W: 1}, + } { + g.SetWeightedEdge(e) + } + return g + }(), + dst: simple.NewWeightedDirectedGraph(0, 0), + }, + } + for _, test := range copyWeightedTests { graph.CopyWeighted(test.dst, test.src) want := test.want diff --git a/graph/layout/eades_test.go b/graph/layout/eades_test.go index 1299492b..19c62cec 100644 --- a/graph/layout/eades_test.go +++ b/graph/layout/eades_test.go @@ -19,184 +19,184 @@ import ( . "gonum.org/v1/gonum/graph/layout" ) -var eadesR2Tests = []struct { - name string - g graph.Graph - param EadesR2 - wantIters int -}{ - { - name: "line", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, - wantIters: 100, - }, - { - name: "square", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(3)}, - {F: simple.Node(2), T: simple.Node(3)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, - wantIters: 100, - }, - { - name: "tetrahedron", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(2)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(3)}, - {F: simple.Node(2), T: simple.Node(3)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, - wantIters: 100, - }, - { - name: "sheet", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(4)}, - {F: simple.Node(2), T: simple.Node(5)}, - {F: simple.Node(3), T: simple.Node(4)}, - {F: simple.Node(3), T: simple.Node(6)}, - {F: simple.Node(4), T: simple.Node(5)}, - {F: simple.Node(4), T: simple.Node(7)}, - {F: simple.Node(5), T: simple.Node(8)}, - {F: simple.Node(6), T: simple.Node(7)}, - {F: simple.Node(7), T: simple.Node(8)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, - wantIters: 100, - }, - { - name: "tube", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(2)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(4)}, - {F: simple.Node(2), T: simple.Node(5)}, - {F: simple.Node(3), T: simple.Node(4)}, - {F: simple.Node(3), T: simple.Node(5)}, - {F: simple.Node(3), T: simple.Node(6)}, - {F: simple.Node(4), T: simple.Node(5)}, - {F: simple.Node(4), T: simple.Node(7)}, - {F: simple.Node(5), T: simple.Node(8)}, - {F: simple.Node(6), T: simple.Node(7)}, - {F: simple.Node(6), T: simple.Node(8)}, - {F: simple.Node(7), T: simple.Node(8)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, - wantIters: 100, - }, - { - // This test does not produce a good layout, but is here to - // ensure that Update does not panic with steep decent rates. - name: "tube-steep", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(2)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(4)}, - {F: simple.Node(2), T: simple.Node(5)}, - {F: simple.Node(3), T: simple.Node(4)}, - {F: simple.Node(3), T: simple.Node(5)}, - {F: simple.Node(3), T: simple.Node(6)}, - {F: simple.Node(4), T: simple.Node(5)}, - {F: simple.Node(4), T: simple.Node(7)}, - {F: simple.Node(5), T: simple.Node(8)}, - {F: simple.Node(6), T: simple.Node(7)}, - {F: simple.Node(6), T: simple.Node(8)}, - {F: simple.Node(7), T: simple.Node(8)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - param: EadesR2{Repulsion: 1, Rate: 1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, - wantIters: 99, - }, - - { - name: "wp_page", // https://en.wikipedia.org/wiki/PageRank#/media/File:PageRanks-Example.jpg - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(4)}, - {F: simple.Node(1), T: simple.Node(5)}, - {F: simple.Node(1), T: simple.Node(6)}, - {F: simple.Node(1), T: simple.Node(7)}, - {F: simple.Node(1), T: simple.Node(8)}, - {F: simple.Node(3), T: simple.Node(4)}, - {F: simple.Node(4), T: simple.Node(5)}, - {F: simple.Node(4), T: simple.Node(6)}, - {F: simple.Node(4), T: simple.Node(7)}, - {F: simple.Node(4), T: simple.Node(8)}, - {F: simple.Node(4), T: simple.Node(9)}, - {F: simple.Node(4), T: simple.Node(10)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, - wantIters: 100, - }, -} - func TestEadesR2(t *testing.T) { + eadesR2Tests := []struct { + name string + g graph.Graph + param EadesR2 + wantIters int + }{ + { + name: "line", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, + wantIters: 100, + }, + { + name: "square", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(3)}, + {F: simple.Node(2), T: simple.Node(3)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, + wantIters: 100, + }, + { + name: "tetrahedron", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(2)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(3)}, + {F: simple.Node(2), T: simple.Node(3)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, + wantIters: 100, + }, + { + name: "sheet", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(4)}, + {F: simple.Node(2), T: simple.Node(5)}, + {F: simple.Node(3), T: simple.Node(4)}, + {F: simple.Node(3), T: simple.Node(6)}, + {F: simple.Node(4), T: simple.Node(5)}, + {F: simple.Node(4), T: simple.Node(7)}, + {F: simple.Node(5), T: simple.Node(8)}, + {F: simple.Node(6), T: simple.Node(7)}, + {F: simple.Node(7), T: simple.Node(8)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, + wantIters: 100, + }, + { + name: "tube", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(2)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(4)}, + {F: simple.Node(2), T: simple.Node(5)}, + {F: simple.Node(3), T: simple.Node(4)}, + {F: simple.Node(3), T: simple.Node(5)}, + {F: simple.Node(3), T: simple.Node(6)}, + {F: simple.Node(4), T: simple.Node(5)}, + {F: simple.Node(4), T: simple.Node(7)}, + {F: simple.Node(5), T: simple.Node(8)}, + {F: simple.Node(6), T: simple.Node(7)}, + {F: simple.Node(6), T: simple.Node(8)}, + {F: simple.Node(7), T: simple.Node(8)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, + wantIters: 100, + }, + { + // This test does not produce a good layout, but is here to + // ensure that Update does not panic with steep decent rates. + name: "tube-steep", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(2)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(4)}, + {F: simple.Node(2), T: simple.Node(5)}, + {F: simple.Node(3), T: simple.Node(4)}, + {F: simple.Node(3), T: simple.Node(5)}, + {F: simple.Node(3), T: simple.Node(6)}, + {F: simple.Node(4), T: simple.Node(5)}, + {F: simple.Node(4), T: simple.Node(7)}, + {F: simple.Node(5), T: simple.Node(8)}, + {F: simple.Node(6), T: simple.Node(7)}, + {F: simple.Node(6), T: simple.Node(8)}, + {F: simple.Node(7), T: simple.Node(8)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + param: EadesR2{Repulsion: 1, Rate: 1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, + wantIters: 99, + }, + + { + name: "wp_page", // https://en.wikipedia.org/wiki/PageRank#/media/File:PageRanks-Example.jpg + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(4)}, + {F: simple.Node(1), T: simple.Node(5)}, + {F: simple.Node(1), T: simple.Node(6)}, + {F: simple.Node(1), T: simple.Node(7)}, + {F: simple.Node(1), T: simple.Node(8)}, + {F: simple.Node(3), T: simple.Node(4)}, + {F: simple.Node(4), T: simple.Node(5)}, + {F: simple.Node(4), T: simple.Node(6)}, + {F: simple.Node(4), T: simple.Node(7)}, + {F: simple.Node(4), T: simple.Node(8)}, + {F: simple.Node(4), T: simple.Node(9)}, + {F: simple.Node(4), T: simple.Node(10)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + param: EadesR2{Repulsion: 1, Rate: 0.1, Updates: 100, Theta: 0.1, Src: rand.NewSource(1)}, + wantIters: 100, + }, + } + for _, test := range eadesR2Tests { eades := test.param o := NewOptimizerR2(test.g, eades.Update) diff --git a/graph/layout/isomap_test.go b/graph/layout/isomap_test.go index 677c9014..5419d524 100644 --- a/graph/layout/isomap_test.go +++ b/graph/layout/isomap_test.go @@ -28,138 +28,138 @@ var ( arch string ) -var isomapR2Tests = []struct { - name string - g graph.Graph -}{ - { - name: "line_isomap", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - }, - { - name: "square_isomap", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(3)}, - {F: simple.Node(2), T: simple.Node(3)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - }, - { - name: "tetrahedron_isomap", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(2)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(3)}, - {F: simple.Node(2), T: simple.Node(3)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - }, - { - name: "sheet_isomap", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(4)}, - {F: simple.Node(2), T: simple.Node(5)}, - {F: simple.Node(3), T: simple.Node(4)}, - {F: simple.Node(3), T: simple.Node(6)}, - {F: simple.Node(4), T: simple.Node(5)}, - {F: simple.Node(4), T: simple.Node(7)}, - {F: simple.Node(5), T: simple.Node(8)}, - {F: simple.Node(6), T: simple.Node(7)}, - {F: simple.Node(7), T: simple.Node(8)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - }, - { - name: "tube_isomap", - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(1)}, - {F: simple.Node(0), T: simple.Node(2)}, - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(4)}, - {F: simple.Node(2), T: simple.Node(5)}, - {F: simple.Node(3), T: simple.Node(4)}, - {F: simple.Node(3), T: simple.Node(5)}, - {F: simple.Node(3), T: simple.Node(6)}, - {F: simple.Node(4), T: simple.Node(5)}, - {F: simple.Node(4), T: simple.Node(7)}, - {F: simple.Node(5), T: simple.Node(8)}, - {F: simple.Node(6), T: simple.Node(7)}, - {F: simple.Node(6), T: simple.Node(8)}, - {F: simple.Node(7), T: simple.Node(8)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - }, - { - name: "wp_page_isomap", // https://en.wikipedia.org/wiki/PageRank#/media/File:PageRanks-Example.jpg - g: func() graph.Graph { - edges := []simple.Edge{ - {F: simple.Node(0), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(2)}, - {F: simple.Node(1), T: simple.Node(3)}, - {F: simple.Node(1), T: simple.Node(4)}, - {F: simple.Node(1), T: simple.Node(5)}, - {F: simple.Node(1), T: simple.Node(6)}, - {F: simple.Node(1), T: simple.Node(7)}, - {F: simple.Node(1), T: simple.Node(8)}, - {F: simple.Node(3), T: simple.Node(4)}, - {F: simple.Node(4), T: simple.Node(5)}, - {F: simple.Node(4), T: simple.Node(6)}, - {F: simple.Node(4), T: simple.Node(7)}, - {F: simple.Node(4), T: simple.Node(8)}, - {F: simple.Node(4), T: simple.Node(9)}, - {F: simple.Node(4), T: simple.Node(10)}, - } - g := simple.NewUndirectedGraph() - for _, e := range edges { - g.SetEdge(e) - } - return orderedGraph{g} - }(), - }, -} - func TestIsomapR2(t *testing.T) { + isomapR2Tests := []struct { + name string + g graph.Graph + }{ + { + name: "line_isomap", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + }, + { + name: "square_isomap", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(3)}, + {F: simple.Node(2), T: simple.Node(3)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + }, + { + name: "tetrahedron_isomap", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(2)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(3)}, + {F: simple.Node(2), T: simple.Node(3)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + }, + { + name: "sheet_isomap", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(4)}, + {F: simple.Node(2), T: simple.Node(5)}, + {F: simple.Node(3), T: simple.Node(4)}, + {F: simple.Node(3), T: simple.Node(6)}, + {F: simple.Node(4), T: simple.Node(5)}, + {F: simple.Node(4), T: simple.Node(7)}, + {F: simple.Node(5), T: simple.Node(8)}, + {F: simple.Node(6), T: simple.Node(7)}, + {F: simple.Node(7), T: simple.Node(8)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + }, + { + name: "tube_isomap", + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(1)}, + {F: simple.Node(0), T: simple.Node(2)}, + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(4)}, + {F: simple.Node(2), T: simple.Node(5)}, + {F: simple.Node(3), T: simple.Node(4)}, + {F: simple.Node(3), T: simple.Node(5)}, + {F: simple.Node(3), T: simple.Node(6)}, + {F: simple.Node(4), T: simple.Node(5)}, + {F: simple.Node(4), T: simple.Node(7)}, + {F: simple.Node(5), T: simple.Node(8)}, + {F: simple.Node(6), T: simple.Node(7)}, + {F: simple.Node(6), T: simple.Node(8)}, + {F: simple.Node(7), T: simple.Node(8)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + }, + { + name: "wp_page_isomap", // https://en.wikipedia.org/wiki/PageRank#/media/File:PageRanks-Example.jpg + g: func() graph.Graph { + edges := []simple.Edge{ + {F: simple.Node(0), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(2)}, + {F: simple.Node(1), T: simple.Node(3)}, + {F: simple.Node(1), T: simple.Node(4)}, + {F: simple.Node(1), T: simple.Node(5)}, + {F: simple.Node(1), T: simple.Node(6)}, + {F: simple.Node(1), T: simple.Node(7)}, + {F: simple.Node(1), T: simple.Node(8)}, + {F: simple.Node(3), T: simple.Node(4)}, + {F: simple.Node(4), T: simple.Node(5)}, + {F: simple.Node(4), T: simple.Node(6)}, + {F: simple.Node(4), T: simple.Node(7)}, + {F: simple.Node(4), T: simple.Node(8)}, + {F: simple.Node(4), T: simple.Node(9)}, + {F: simple.Node(4), T: simple.Node(10)}, + } + g := simple.NewUndirectedGraph() + for _, e := range edges { + g.SetEdge(e) + } + return orderedGraph{g} + }(), + }, + } + for _, test := range isomapR2Tests { o := NewOptimizerR2(test.g, IsomapR2{}.Update) var n int diff --git a/graph/nodes_edges_test.go b/graph/nodes_edges_test.go index 6c49d609..e9381ebc 100644 --- a/graph/nodes_edges_test.go +++ b/graph/nodes_edges_test.go @@ -21,48 +21,48 @@ import ( // weightedlines // empty -var nodesOfTests = []struct { - name string - nodes graph.Nodes - want []graph.Node -}{ - { - name: "nil", - nodes: nil, - want: nil, - }, - { - name: "empty", - nodes: graph.Empty, - want: nil, - }, - { - name: "no nodes", - nodes: iterator.NewOrderedNodes(nil), - want: nil, - }, - { - name: "implicit nodes", - nodes: iterator.NewImplicitNodes(-1, 4, func(id int) graph.Node { return simple.Node(id) }), - want: []graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}, - }, - { - name: "no slice method", - nodes: basicNodes{iterator.NewOrderedNodes([]graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)})}, - want: []graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}, - }, - { - name: "explicit nodes", - nodes: iterator.NewOrderedNodes([]graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}), - want: []graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}, - }, -} - type basicNodes struct { graph.Nodes } func TestNodesOf(t *testing.T) { + nodesOfTests := []struct { + name string + nodes graph.Nodes + want []graph.Node + }{ + { + name: "nil", + nodes: nil, + want: nil, + }, + { + name: "empty", + nodes: graph.Empty, + want: nil, + }, + { + name: "no nodes", + nodes: iterator.NewOrderedNodes(nil), + want: nil, + }, + { + name: "implicit nodes", + nodes: iterator.NewImplicitNodes(-1, 4, func(id int) graph.Node { return simple.Node(id) }), + want: []graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}, + }, + { + name: "no slice method", + nodes: basicNodes{iterator.NewOrderedNodes([]graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)})}, + want: []graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}, + }, + { + name: "explicit nodes", + nodes: iterator.NewOrderedNodes([]graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}), + want: []graph.Node{simple.Node(-1), simple.Node(0), simple.Node(1), simple.Node(2), simple.Node(3)}, + }, + } + for _, test := range nodesOfTests { got := graph.NodesOf(test.nodes) if !reflect.DeepEqual(got, test.want) { @@ -71,59 +71,59 @@ func TestNodesOf(t *testing.T) { } } -var edgesOfTests = []struct { - name string - edges graph.Edges - want []graph.Edge -}{ - { - name: "nil", - edges: nil, - want: nil, - }, - { - name: "empty", - edges: graph.Empty, - want: nil, - }, - { - name: "no edges", - edges: iterator.NewOrderedEdges(nil), - want: nil, - }, - { - name: "no slice method", - edges: basicEdges{iterator.NewOrderedEdges([]graph.Edge{ - simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, - simple.Edge{F: simple.Node(1), T: simple.Node(2)}, - simple.Edge{F: simple.Node(3), T: simple.Node(4)}, - })}, - want: []graph.Edge{ - simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, - simple.Edge{F: simple.Node(1), T: simple.Node(2)}, - simple.Edge{F: simple.Node(3), T: simple.Node(4)}, - }, - }, - { - name: "explicit edges", - edges: iterator.NewOrderedEdges([]graph.Edge{ - simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, - simple.Edge{F: simple.Node(1), T: simple.Node(2)}, - simple.Edge{F: simple.Node(3), T: simple.Node(4)}, - }), - want: []graph.Edge{ - simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, - simple.Edge{F: simple.Node(1), T: simple.Node(2)}, - simple.Edge{F: simple.Node(3), T: simple.Node(4)}, - }, - }, -} - type basicEdges struct { graph.Edges } func TestEdgesOf(t *testing.T) { + edgesOfTests := []struct { + name string + edges graph.Edges + want []graph.Edge + }{ + { + name: "nil", + edges: nil, + want: nil, + }, + { + name: "empty", + edges: graph.Empty, + want: nil, + }, + { + name: "no edges", + edges: iterator.NewOrderedEdges(nil), + want: nil, + }, + { + name: "no slice method", + edges: basicEdges{iterator.NewOrderedEdges([]graph.Edge{ + simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, + simple.Edge{F: simple.Node(1), T: simple.Node(2)}, + simple.Edge{F: simple.Node(3), T: simple.Node(4)}, + })}, + want: []graph.Edge{ + simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, + simple.Edge{F: simple.Node(1), T: simple.Node(2)}, + simple.Edge{F: simple.Node(3), T: simple.Node(4)}, + }, + }, + { + name: "explicit edges", + edges: iterator.NewOrderedEdges([]graph.Edge{ + simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, + simple.Edge{F: simple.Node(1), T: simple.Node(2)}, + simple.Edge{F: simple.Node(3), T: simple.Node(4)}, + }), + want: []graph.Edge{ + simple.Edge{F: simple.Node(-1), T: simple.Node(0)}, + simple.Edge{F: simple.Node(1), T: simple.Node(2)}, + simple.Edge{F: simple.Node(3), T: simple.Node(4)}, + }, + }, + } + for _, test := range edgesOfTests { got := graph.EdgesOf(test.edges) if !reflect.DeepEqual(got, test.want) { @@ -132,59 +132,59 @@ func TestEdgesOf(t *testing.T) { } } -var weightedEdgesOfTests = []struct { - name string - edges graph.WeightedEdges - want []graph.WeightedEdge -}{ - { - name: "nil", - edges: nil, - want: nil, - }, - { - name: "empty", - edges: graph.Empty, - want: nil, - }, - { - name: "no edges", - edges: iterator.NewOrderedWeightedEdges(nil), - want: nil, - }, - { - name: "no slice method", - edges: basicWeightedEdges{iterator.NewOrderedWeightedEdges([]graph.WeightedEdge{ - simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, - simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, - simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, - })}, - want: []graph.WeightedEdge{ - simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, - simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, - simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, - }, - }, - { - name: "explicit edges", - edges: iterator.NewOrderedWeightedEdges([]graph.WeightedEdge{ - simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, - simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, - simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, - }), - want: []graph.WeightedEdge{ - simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, - simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, - simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, - }, - }, -} - type basicWeightedEdges struct { graph.WeightedEdges } func TestWeightedEdgesOf(t *testing.T) { + weightedEdgesOfTests := []struct { + name string + edges graph.WeightedEdges + want []graph.WeightedEdge + }{ + { + name: "nil", + edges: nil, + want: nil, + }, + { + name: "empty", + edges: graph.Empty, + want: nil, + }, + { + name: "no edges", + edges: iterator.NewOrderedWeightedEdges(nil), + want: nil, + }, + { + name: "no slice method", + edges: basicWeightedEdges{iterator.NewOrderedWeightedEdges([]graph.WeightedEdge{ + simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, + simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, + simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, + })}, + want: []graph.WeightedEdge{ + simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, + simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, + simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, + }, + }, + { + name: "explicit edges", + edges: iterator.NewOrderedWeightedEdges([]graph.WeightedEdge{ + simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, + simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, + simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, + }), + want: []graph.WeightedEdge{ + simple.WeightedEdge{F: simple.Node(-1), T: simple.Node(0), W: 1}, + simple.WeightedEdge{F: simple.Node(1), T: simple.Node(2), W: 2}, + simple.WeightedEdge{F: simple.Node(3), T: simple.Node(4), W: 3}, + }, + }, + } + for _, test := range weightedEdgesOfTests { got := graph.WeightedEdgesOf(test.edges) if !reflect.DeepEqual(got, test.want) { @@ -193,59 +193,59 @@ func TestWeightedEdgesOf(t *testing.T) { } } -var linesOfTests = []struct { - name string - lines graph.Lines - want []graph.Line -}{ - { - name: "nil", - lines: nil, - want: nil, - }, - { - name: "empty", - lines: graph.Empty, - want: nil, - }, - { - name: "no edges", - lines: iterator.NewOrderedLines(nil), - want: nil, - }, - { - name: "no slice method", - lines: basicLines{iterator.NewOrderedLines([]graph.Line{ - multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, - multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, - multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, - })}, - want: []graph.Line{ - multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, - multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, - multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, - }, - }, - { - name: "explicit edges", - lines: iterator.NewOrderedLines([]graph.Line{ - multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, - multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, - multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, - }), - want: []graph.Line{ - multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, - multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, - multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, - }, - }, -} - type basicLines struct { graph.Lines } func TestLinesOf(t *testing.T) { + linesOfTests := []struct { + name string + lines graph.Lines + want []graph.Line + }{ + { + name: "nil", + lines: nil, + want: nil, + }, + { + name: "empty", + lines: graph.Empty, + want: nil, + }, + { + name: "no edges", + lines: iterator.NewOrderedLines(nil), + want: nil, + }, + { + name: "no slice method", + lines: basicLines{iterator.NewOrderedLines([]graph.Line{ + multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, + multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, + multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, + })}, + want: []graph.Line{ + multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, + multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, + multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, + }, + }, + { + name: "explicit edges", + lines: iterator.NewOrderedLines([]graph.Line{ + multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, + multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, + multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, + }), + want: []graph.Line{ + multi.Line{F: multi.Node(-1), T: multi.Node(0), UID: -1}, + multi.Line{F: multi.Node(1), T: multi.Node(2), UID: 0}, + multi.Line{F: multi.Node(3), T: multi.Node(4), UID: 1}, + }, + }, + } + for _, test := range linesOfTests { got := graph.LinesOf(test.lines) if !reflect.DeepEqual(got, test.want) { @@ -254,59 +254,59 @@ func TestLinesOf(t *testing.T) { } } -var weightedLinesOfTests = []struct { - name string - lines graph.WeightedLines - want []graph.WeightedLine -}{ - { - name: "nil", - lines: nil, - want: nil, - }, - { - name: "empty", - lines: graph.Empty, - want: nil, - }, - { - name: "no edges", - lines: iterator.NewOrderedWeightedLines(nil), - want: nil, - }, - { - name: "no slice method", - lines: basicWeightedLines{iterator.NewOrderedWeightedLines([]graph.WeightedLine{ - multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, - multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, - multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, - })}, - want: []graph.WeightedLine{ - multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, - multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, - multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, - }, - }, - { - name: "explicit edges", - lines: iterator.NewOrderedWeightedLines([]graph.WeightedLine{ - multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, - multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, - multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, - }), - want: []graph.WeightedLine{ - multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, - multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, - multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, - }, - }, -} - type basicWeightedLines struct { graph.WeightedLines } func TestWeightedLinesOf(t *testing.T) { + weightedLinesOfTests := []struct { + name string + lines graph.WeightedLines + want []graph.WeightedLine + }{ + { + name: "nil", + lines: nil, + want: nil, + }, + { + name: "empty", + lines: graph.Empty, + want: nil, + }, + { + name: "no edges", + lines: iterator.NewOrderedWeightedLines(nil), + want: nil, + }, + { + name: "no slice method", + lines: basicWeightedLines{iterator.NewOrderedWeightedLines([]graph.WeightedLine{ + multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, + multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, + multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, + })}, + want: []graph.WeightedLine{ + multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, + multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, + multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, + }, + }, + { + name: "explicit edges", + lines: iterator.NewOrderedWeightedLines([]graph.WeightedLine{ + multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, + multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, + multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, + }), + want: []graph.WeightedLine{ + multi.WeightedLine{F: multi.Node(-1), T: multi.Node(0), W: 1, UID: -1}, + multi.WeightedLine{F: multi.Node(1), T: multi.Node(2), W: 2, UID: 0}, + multi.WeightedLine{F: multi.Node(3), T: multi.Node(4), W: 3, UID: 1}, + }, + }, + } + for _, test := range weightedLinesOfTests { got := graph.WeightedLinesOf(test.lines) if !reflect.DeepEqual(got, test.want) { diff --git a/stat/samplemv/sample_test.go b/stat/samplemv/sample_test.go index e8bba74b..eaf168f1 100644 --- a/stat/samplemv/sample_test.go +++ b/stat/samplemv/sample_test.go @@ -163,11 +163,12 @@ func TestMetropolisHastings(t *testing.T) { compareNormal(t, target, batch, nil, 5e-1, 5e-1) } -// randomNormal constructs a random Normal distribution. +// randomNormal constructs a random Normal distribution using the provided +// random source. func randomNormal(dim int, src *rand.Rand) (*distmv.Normal, bool) { data := make([]float64, dim*dim) for i := range data { - data[i] = rand.Float64() + data[i] = src.Float64() } a := mat.NewDense(dim, dim, data) var sigma mat.SymDense @@ -180,6 +181,8 @@ func randomNormal(dim int, src *rand.Rand) (*distmv.Normal, bool) { } func compareNormal(t *testing.T, want *distmv.Normal, batch *mat.Dense, weights []float64, meanTol, covTol float64) { + t.Helper() + dim := want.Dim() mu := want.Mean(nil) var sigma mat.SymDense @@ -224,10 +227,11 @@ func TestMetropolisHastingser(t *testing.T) { {3, 103, 11, 51}, {3, 103, 51, 11}, } { + src := rand.New(rand.NewSource(1)) dim := test.dim initial := make([]float64, dim) - target, ok := randomNormal(dim, nil) + target, ok := randomNormal(dim, src) if !ok { t.Fatal("bad test, sigma not pos def") } @@ -239,7 +243,7 @@ func TestMetropolisHastingser(t *testing.T) { // Test the Metropolis Hastingser by generating all the samples, then generating // the same samples with a burnin and rate. - src := rand.New(rand.NewSource(1)) + src = rand.New(rand.NewSource(1)) proposal, ok := NewProposalNormal(sigmaImp, src) if !ok { t.Fatal("bad test, sigma not pos def") diff --git a/unit/unit_test.go b/unit/unit_test.go index fb9dfd0f..c669dc48 100644 --- a/unit/unit_test.go +++ b/unit/unit_test.go @@ -185,20 +185,19 @@ func TestDimensionEquality(t *testing.T) { } } -var operationTests = []struct { - recvOp func(Uniter) *Unit - param Uniter - want Uniter -}{ - {Dimless(1).Unit().Add, Dimless(2), Dimless(3)}, - {Dimless(1).Unit().Mul, Dimless(2), Dimless(2)}, - {Dimless(1).Unit().Mul, Length(2), Length(2)}, - {Length(1).Unit().Mul, Dimless(2), Length(2)}, - {Dimless(1).Unit().Div, Length(2), New(0.5, Dimensions{LengthDim: -1})}, - {Length(1).Unit().Div, Dimless(2), Length(0.5)}, -} - func TestOperations(t *testing.T) { + operationTests := []struct { + recvOp func(Uniter) *Unit + param Uniter + want Uniter + }{ + {Dimless(1).Unit().Add, Dimless(2), Dimless(3)}, + {Dimless(1).Unit().Mul, Dimless(2), Dimless(2)}, + {Dimless(1).Unit().Mul, Length(2), Length(2)}, + {Length(1).Unit().Mul, Dimless(2), Length(2)}, + {Dimless(1).Unit().Div, Length(2), New(0.5, Dimensions{LengthDim: -1})}, + {Length(1).Unit().Div, Dimless(2), Length(0.5)}, + } t.Parallel() for i, test := range operationTests { var got Uniter