mirror of
https://github.com/gonum/gonum.git
synced 2025-10-05 15:16:59 +08:00
graph: add Empty universal iterator for empty returns
This commit is contained in:
@@ -3,4 +3,7 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package graph defines graph interfaces.
|
||||
//
|
||||
// Routines to test contract compliance by user implemented graph types
|
||||
// are available in gonum.org/v1/gonum/graph/testgraph.
|
||||
package graph // import "gonum.org/v1/gonum/graph"
|
||||
|
@@ -32,10 +32,14 @@ type Graph interface {
|
||||
Node(id int64) Node
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
//
|
||||
// Nodes must not return nil.
|
||||
Nodes() Nodes
|
||||
|
||||
// From returns all nodes that can be reached directly
|
||||
// from the node with the given ID.
|
||||
//
|
||||
// From must not return nil.
|
||||
From(id int64) Nodes
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between
|
||||
@@ -99,6 +103,8 @@ type Directed interface {
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the node with the given ID.
|
||||
//
|
||||
// To must not return nil.
|
||||
To(id int64) Nodes
|
||||
}
|
||||
|
||||
@@ -113,6 +119,8 @@ type WeightedDirected interface {
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the node with the given ID.
|
||||
//
|
||||
// To must not return nil.
|
||||
To(id int64) Nodes
|
||||
}
|
||||
|
||||
|
@@ -73,7 +73,7 @@ func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
// is a multi.Edge.
|
||||
func (g *DirectedGraph) Edges() graph.Edges {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var edges []graph.Edge
|
||||
for _, u := range g.nodes {
|
||||
@@ -91,13 +91,16 @@ func (g *DirectedGraph) Edges() graph.Edges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *DirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
from := make([]graph.Node, len(g.from[id]))
|
||||
@@ -106,6 +109,9 @@ func (g *DirectedGraph) From(id int64) graph.Nodes {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
if len(from) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(from)
|
||||
}
|
||||
|
||||
@@ -130,7 +136,7 @@ func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||
func (g *DirectedGraph) Lines(uid, vid int64) graph.Lines {
|
||||
edge := g.from[uid][vid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var lines []graph.Line
|
||||
for _, l := range edge {
|
||||
@@ -167,7 +173,7 @@ func (g *DirectedGraph) Node(id int64) graph.Node {
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *DirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
i := 0
|
||||
@@ -256,7 +262,7 @@ func (g *DirectedGraph) SetLine(l graph.Line) {
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *DirectedGraph) To(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
to := make([]graph.Node, len(g.to[id]))
|
||||
@@ -265,5 +271,8 @@ func (g *DirectedGraph) To(id int64) graph.Nodes {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
if len(to) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
@@ -53,16 +53,16 @@ func TestDirected(t *testing.T) {
|
||||
testgraph.NodeExistence(t, directedBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, directedBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, directedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllLines", func(t *testing.T) {
|
||||
testgraph.ReturnAllLines(t, directedBuilder)
|
||||
testgraph.ReturnAllLines(t, directedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, directedBuilder)
|
||||
testgraph.ReturnAllNodes(t, directedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, directedBuilder)
|
||||
testgraph.ReturnNodeSlice(t, directedBuilder, true)
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -4,4 +4,6 @@
|
||||
|
||||
// Package multi provides a suite of multigraph implementations satisfying
|
||||
// the gonum/graph interfaces.
|
||||
//
|
||||
// All types in multi return the graph.Empty value for empty iterators.
|
||||
package multi // import "gonum.org/v1/gonum/graph/multi"
|
||||
|
@@ -75,7 +75,7 @@ func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
// is a multi.Edge.
|
||||
func (g *UndirectedGraph) Edges() graph.Edges {
|
||||
if len(g.lines) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var edges []graph.Edge
|
||||
seen := make(map[int64]struct{})
|
||||
@@ -99,13 +99,16 @@ func (g *UndirectedGraph) Edges() graph.Edges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *UndirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
nodes := make([]graph.Node, len(g.lines[id]))
|
||||
@@ -114,6 +117,9 @@ func (g *UndirectedGraph) From(id int64) graph.Nodes {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
@@ -132,7 +138,7 @@ func (g *UndirectedGraph) Lines(uid, vid int64) graph.Lines {
|
||||
// LinesBetween returns the lines between nodes x and y.
|
||||
func (g *UndirectedGraph) LinesBetween(xid, yid int64) graph.Lines {
|
||||
if !g.HasEdgeBetween(xid, yid) {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var lines []graph.Line
|
||||
for _, l := range g.lines[xid][yid] {
|
||||
@@ -169,7 +175,7 @@ func (g *UndirectedGraph) Node(id int64) graph.Node {
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *UndirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
i := 0
|
||||
|
@@ -53,16 +53,16 @@ func TestUndirected(t *testing.T) {
|
||||
testgraph.NodeExistence(t, undirectedBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, undirectedBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, undirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllLines", func(t *testing.T) {
|
||||
testgraph.ReturnAllLines(t, undirectedBuilder)
|
||||
testgraph.ReturnAllLines(t, undirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, undirectedBuilder)
|
||||
testgraph.ReturnAllNodes(t, undirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, undirectedBuilder)
|
||||
testgraph.ReturnNodeSlice(t, undirectedBuilder, true)
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -78,7 +78,7 @@ func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
// is a multi.WeightedEdge.
|
||||
func (g *WeightedDirectedGraph) Edges() graph.Edges {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var edges []graph.Edge
|
||||
for _, u := range g.nodes {
|
||||
@@ -97,13 +97,16 @@ func (g *WeightedDirectedGraph) Edges() graph.Edges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedDirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
from := make([]graph.Node, len(g.from[id]))
|
||||
@@ -112,6 +115,9 @@ func (g *WeightedDirectedGraph) From(id int64) graph.Nodes {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
if len(from) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(from)
|
||||
}
|
||||
|
||||
@@ -138,7 +144,7 @@ func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||
func (g *WeightedDirectedGraph) Lines(uid, vid int64) graph.Lines {
|
||||
edge := g.from[uid][vid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var lines []graph.Line
|
||||
for _, l := range edge {
|
||||
@@ -175,7 +181,7 @@ func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *WeightedDirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
i := 0
|
||||
@@ -265,7 +271,7 @@ func (g *WeightedDirectedGraph) SetWeightedLine(l graph.WeightedLine) {
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *WeightedDirectedGraph) To(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
to := make([]graph.Node, len(g.to[id]))
|
||||
@@ -274,6 +280,9 @@ func (g *WeightedDirectedGraph) To(id int64) graph.Nodes {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
if len(to) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
@@ -303,7 +312,7 @@ func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge
|
||||
// is a multi.WeightedEdge.
|
||||
func (g *WeightedDirectedGraph) WeightedEdges() graph.WeightedEdges {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var edges []graph.WeightedEdge
|
||||
for _, u := range g.nodes {
|
||||
@@ -322,6 +331,9 @@ func (g *WeightedDirectedGraph) WeightedEdges() graph.WeightedEdges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedWeightedEdges(edges)
|
||||
}
|
||||
|
||||
@@ -330,7 +342,7 @@ func (g *WeightedDirectedGraph) WeightedEdges() graph.WeightedEdges {
|
||||
func (g *WeightedDirectedGraph) WeightedLines(uid, vid int64) graph.WeightedLines {
|
||||
edge := g.from[uid][vid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var lines []graph.WeightedLine
|
||||
for _, l := range edge {
|
||||
|
@@ -65,19 +65,19 @@ func TestWeightedDirected(t *testing.T) {
|
||||
testgraph.NodeExistence(t, weightedDirectedBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllLines", func(t *testing.T) {
|
||||
testgraph.ReturnAllLines(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnAllLines(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnAllNodes(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllWeightedLines", func(t *testing.T) {
|
||||
testgraph.ReturnAllWeightedLines(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnAllWeightedLines(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnNodeSlice(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("Weight", func(t *testing.T) {
|
||||
testgraph.Weight(t, weightedDirectedBuilder)
|
||||
|
@@ -80,7 +80,7 @@ func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
// is a multi.Edge.
|
||||
func (g *WeightedUndirectedGraph) Edges() graph.Edges {
|
||||
if len(g.lines) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var edges []graph.Edge
|
||||
seen := make(map[int64]struct{})
|
||||
@@ -105,13 +105,16 @@ func (g *WeightedUndirectedGraph) Edges() graph.Edges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedUndirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
nodes := make([]graph.Node, len(g.lines[id]))
|
||||
@@ -120,6 +123,9 @@ func (g *WeightedUndirectedGraph) From(id int64) graph.Nodes {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
@@ -139,7 +145,7 @@ func (g *WeightedUndirectedGraph) Lines(uid, vid int64) graph.Lines {
|
||||
func (g *WeightedUndirectedGraph) LinesBetween(xid, yid int64) graph.Lines {
|
||||
edge := g.lines[xid][yid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var lines []graph.Line
|
||||
seen := make(map[int64]struct{})
|
||||
@@ -182,7 +188,7 @@ func (g *WeightedUndirectedGraph) Node(id int64) graph.Node {
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *WeightedUndirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
i := 0
|
||||
@@ -291,7 +297,7 @@ func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.Weig
|
||||
// is a multi.Edge.
|
||||
func (g *WeightedUndirectedGraph) WeightedEdges() graph.WeightedEdges {
|
||||
if len(g.lines) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var edges []graph.WeightedEdge
|
||||
seen := make(map[int64]struct{})
|
||||
@@ -316,6 +322,9 @@ func (g *WeightedUndirectedGraph) WeightedEdges() graph.WeightedEdges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedWeightedEdges(edges)
|
||||
}
|
||||
|
||||
@@ -329,7 +338,7 @@ func (g *WeightedUndirectedGraph) WeightedLines(uid, vid int64) graph.WeightedLi
|
||||
func (g *WeightedUndirectedGraph) WeightedLinesBetween(xid, yid int64) graph.WeightedLines {
|
||||
edge := g.lines[xid][yid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var lines []graph.WeightedLine
|
||||
seen := make(map[int64]struct{})
|
||||
|
@@ -65,19 +65,19 @@ func TestWeightedUndirected(t *testing.T) {
|
||||
testgraph.NodeExistence(t, weightedUndirectedBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllLines", func(t *testing.T) {
|
||||
testgraph.ReturnAllLines(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnAllLines(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnAllNodes(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllWeightedLines", func(t *testing.T) {
|
||||
testgraph.ReturnAllWeightedLines(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnAllWeightedLines(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnNodeSlice(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("Weight", func(t *testing.T) {
|
||||
testgraph.Weight(t, weightedUndirectedBuilder)
|
||||
|
@@ -24,10 +24,14 @@ type Multigraph interface {
|
||||
Node(id int64) Node
|
||||
|
||||
// Nodes returns all the nodes in the multigraph.
|
||||
//
|
||||
// Nodes must not return nil.
|
||||
Nodes() Nodes
|
||||
|
||||
// From returns all nodes that can be reached directly
|
||||
// from the node with the given ID.
|
||||
//
|
||||
// From must not return nil.
|
||||
From(id int64) Nodes
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between
|
||||
@@ -38,6 +42,8 @@ type Multigraph interface {
|
||||
// vid, if any such lines exist and nil otherwise. The
|
||||
// node v must be directly reachable from u as defined by
|
||||
// the From method.
|
||||
//
|
||||
// Lines must not return nil.
|
||||
Lines(uid, vid int64) Lines
|
||||
}
|
||||
|
||||
@@ -49,6 +55,8 @@ type WeightedMultigraph interface {
|
||||
// with IDs uid and vid if any such lines exist and nil
|
||||
// otherwise. The node v must be directly reachable
|
||||
// from u as defined by the From method.
|
||||
//
|
||||
// WeightedLines must not return nil.
|
||||
WeightedLines(uid, vid int64) WeightedLines
|
||||
}
|
||||
|
||||
@@ -58,6 +66,8 @@ type UndirectedMultigraph interface {
|
||||
|
||||
// LinesBetween returns the lines between nodes x and y
|
||||
// with IDs xid and yid.
|
||||
//
|
||||
// LinesBetween must not return nil.
|
||||
LinesBetween(xid, yid int64) Lines
|
||||
}
|
||||
|
||||
@@ -67,6 +77,8 @@ type WeightedUndirectedMultigraph interface {
|
||||
|
||||
// WeightedLinesBetween returns the lines between nodes
|
||||
// x and y with IDs xid and yid.
|
||||
//
|
||||
// WeightedLinesBetween must not return nil.
|
||||
WeightedLinesBetween(xid, yid int64) WeightedLines
|
||||
}
|
||||
|
||||
@@ -81,6 +93,8 @@ type DirectedMultigraph interface {
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the node with the given ID.
|
||||
//
|
||||
// To must not return nil.
|
||||
To(id int64) Nodes
|
||||
}
|
||||
|
||||
@@ -95,6 +109,8 @@ type WeightedDirectedMultigraph interface {
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the node with the given ID.
|
||||
//
|
||||
// To must not return nil.
|
||||
To(id int64) Nodes
|
||||
}
|
||||
|
||||
|
@@ -227,3 +227,40 @@ func WeightedLinesOf(it WeightedLines) []WeightedLine {
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Empty is an empty set of nodes, edges or lines. It should be used when
|
||||
// a graph returns a zero-length Iterator. Empty implements the slicer
|
||||
// interfaces for nodes, edges and lines, returning nil for each of these.
|
||||
const Empty = nothing
|
||||
|
||||
var (
|
||||
_ Iterator = Empty
|
||||
_ Nodes = Empty
|
||||
_ NodeSlicer = Empty
|
||||
_ Edges = Empty
|
||||
_ EdgeSlicer = Empty
|
||||
_ WeightedEdges = Empty
|
||||
_ WeightedEdgeSlicer = Empty
|
||||
_ Lines = Empty
|
||||
_ LineSlicer = Empty
|
||||
_ WeightedLines = Empty
|
||||
_ WeightedLineSlicer = Empty
|
||||
)
|
||||
|
||||
const nothing = empty(true)
|
||||
|
||||
type empty bool
|
||||
|
||||
func (empty) Next() bool { return false }
|
||||
func (empty) Len() int { return 0 }
|
||||
func (empty) Reset() {}
|
||||
func (empty) Node() Node { return nil }
|
||||
func (empty) NodeSlice() []Node { return nil }
|
||||
func (empty) Edge() Edge { return nil }
|
||||
func (empty) EdgeSlice() []Edge { return nil }
|
||||
func (empty) WeightedEdge() WeightedEdge { return nil }
|
||||
func (empty) WeightedEdgeSlice() []WeightedEdge { return nil }
|
||||
func (empty) Line() Line { return nil }
|
||||
func (empty) LineSlice() []Line { return nil }
|
||||
func (empty) WeightedLine() WeightedLine { return nil }
|
||||
func (empty) WeightedLineSlice() []WeightedLine { return nil }
|
||||
|
@@ -169,7 +169,7 @@ func (g *Grid) NodeAt(r, c int) graph.Node {
|
||||
// ends of an edge must be open.
|
||||
func (g *Grid) From(uid int64) graph.Nodes {
|
||||
if !g.HasOpen(uid) {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
nr, nc := g.RowCol(uid)
|
||||
var to []graph.Node
|
||||
@@ -180,6 +180,9 @@ func (g *Grid) From(uid int64) graph.Nodes {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(to) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
|
@@ -178,7 +178,7 @@ func (l *LimitedVisionGrid) has(id int64) bool {
|
||||
// From returns nodes that are optimistically reachable from u.
|
||||
func (l *LimitedVisionGrid) From(uid int64) graph.Nodes {
|
||||
if !l.has(uid) {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
nr, nc := l.RowCol(uid)
|
||||
@@ -190,6 +190,9 @@ func (l *LimitedVisionGrid) From(uid int64) graph.Nodes {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(to) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
|
@@ -93,13 +93,16 @@ func (g *DirectedMatrix) Edges() graph.Edges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *DirectedMatrix) From(id int64) graph.Nodes {
|
||||
if !g.has(id) {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var nodes []graph.Node
|
||||
_, c := g.mat.Dims()
|
||||
@@ -112,6 +115,9 @@ func (g *DirectedMatrix) From(id int64) graph.Nodes {
|
||||
nodes = append(nodes, g.Node(int64(j)))
|
||||
}
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
@@ -169,6 +175,7 @@ func (g *DirectedMatrix) Nodes() graph.Nodes {
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
r, _ := g.mat.Dims()
|
||||
// Matrix graphs must have at least one node.
|
||||
return iterator.NewImplicitNodes(0, r, newSimpleNode)
|
||||
}
|
||||
|
||||
@@ -224,7 +231,7 @@ func (g *DirectedMatrix) setWeightedEdge(e graph.Edge, weight float64) {
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *DirectedMatrix) To(id int64) graph.Nodes {
|
||||
if !g.has(id) {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var nodes []graph.Node
|
||||
r, _ := g.mat.Dims()
|
||||
@@ -237,6 +244,9 @@ func (g *DirectedMatrix) To(id int64) graph.Nodes {
|
||||
nodes = append(nodes, g.Node(int64(i)))
|
||||
}
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
@@ -279,6 +289,9 @@ func (g *DirectedMatrix) WeightedEdges() graph.WeightedEdges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedWeightedEdges(edges)
|
||||
}
|
||||
|
||||
|
@@ -95,13 +95,16 @@ func (g *UndirectedMatrix) Edges() graph.Edges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *UndirectedMatrix) From(id int64) graph.Nodes {
|
||||
if !g.has(id) {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var nodes []graph.Node
|
||||
r := g.mat.Symmetric()
|
||||
@@ -114,6 +117,9 @@ func (g *UndirectedMatrix) From(id int64) graph.Nodes {
|
||||
nodes = append(nodes, g.Node(int64(i)))
|
||||
}
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
@@ -156,6 +162,7 @@ func (g *UndirectedMatrix) Nodes() graph.Nodes {
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
r := g.mat.Symmetric()
|
||||
// Matrix graphs must have at least one node.
|
||||
return iterator.NewImplicitNodes(0, r, newSimpleNode)
|
||||
}
|
||||
|
||||
@@ -249,6 +256,9 @@ func (g *UndirectedMatrix) WeightedEdges() graph.WeightedEdges {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedWeightedEdges(edges)
|
||||
}
|
||||
|
||||
|
@@ -73,25 +73,25 @@ func TestDirectedMatrix(t *testing.T) {
|
||||
testgraph.NodeExistence(t, directedMatrixBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, directedMatrixBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, directedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllEdges(t, directedMatrixBuilder)
|
||||
testgraph.ReturnAllEdges(t, directedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, directedMatrixBuilder)
|
||||
testgraph.ReturnAllNodes(t, directedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllWeightedEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllWeightedEdges(t, directedMatrixBuilder)
|
||||
testgraph.ReturnAllWeightedEdges(t, directedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnEdgeSlice(t, directedMatrixBuilder)
|
||||
testgraph.ReturnEdgeSlice(t, directedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnWeightedEdgeSlice(t, directedMatrixBuilder)
|
||||
testgraph.ReturnWeightedEdgeSlice(t, directedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, directedMatrixBuilder)
|
||||
testgraph.ReturnNodeSlice(t, directedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("Weight", func(t *testing.T) {
|
||||
testgraph.Weight(t, directedMatrixBuilder)
|
||||
@@ -142,25 +142,25 @@ func TestDirectedMatrixFrom(t *testing.T) {
|
||||
testgraph.NodeExistence(t, directedMatrixFromBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, directedMatrixFromBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, directedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllEdges(t, directedMatrixFromBuilder)
|
||||
testgraph.ReturnAllEdges(t, directedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, directedMatrixFromBuilder)
|
||||
testgraph.ReturnAllNodes(t, directedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllWeightedEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllWeightedEdges(t, directedMatrixFromBuilder)
|
||||
testgraph.ReturnAllWeightedEdges(t, directedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnEdgeSlice(t, directedMatrixFromBuilder)
|
||||
testgraph.ReturnEdgeSlice(t, directedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnWeightedEdgeSlice(t, directedMatrixFromBuilder)
|
||||
testgraph.ReturnWeightedEdgeSlice(t, directedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, directedMatrixFromBuilder)
|
||||
testgraph.ReturnNodeSlice(t, directedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("Weight", func(t *testing.T) {
|
||||
testgraph.Weight(t, directedMatrixFromBuilder)
|
||||
@@ -211,25 +211,25 @@ func TestUnirectedMatrix(t *testing.T) {
|
||||
testgraph.NodeExistence(t, undirectedMatrixBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, undirectedMatrixBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, undirectedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllEdges(t, undirectedMatrixBuilder)
|
||||
testgraph.ReturnAllEdges(t, undirectedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, undirectedMatrixBuilder)
|
||||
testgraph.ReturnAllNodes(t, undirectedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllWeightedEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllWeightedEdges(t, undirectedMatrixBuilder)
|
||||
testgraph.ReturnAllWeightedEdges(t, undirectedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnEdgeSlice(t, undirectedMatrixBuilder)
|
||||
testgraph.ReturnEdgeSlice(t, undirectedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnWeightedEdgeSlice(t, undirectedMatrixBuilder)
|
||||
testgraph.ReturnWeightedEdgeSlice(t, undirectedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, undirectedMatrixBuilder)
|
||||
testgraph.ReturnNodeSlice(t, undirectedMatrixBuilder, true)
|
||||
})
|
||||
t.Run("Weight", func(t *testing.T) {
|
||||
testgraph.Weight(t, undirectedMatrixBuilder)
|
||||
@@ -280,25 +280,25 @@ func TestUndirectedMatrixFrom(t *testing.T) {
|
||||
testgraph.NodeExistence(t, undirectedMatrixFromBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, undirectedMatrixFromBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, undirectedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllEdges(t, undirectedMatrixFromBuilder)
|
||||
testgraph.ReturnAllEdges(t, undirectedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, undirectedMatrixFromBuilder)
|
||||
testgraph.ReturnAllNodes(t, undirectedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllWeightedEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllWeightedEdges(t, undirectedMatrixFromBuilder)
|
||||
testgraph.ReturnAllWeightedEdges(t, undirectedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnEdgeSlice(t, undirectedMatrixFromBuilder)
|
||||
testgraph.ReturnEdgeSlice(t, undirectedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnWeightedEdgeSlice(t, undirectedMatrixFromBuilder)
|
||||
testgraph.ReturnWeightedEdgeSlice(t, undirectedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, undirectedMatrixFromBuilder)
|
||||
testgraph.ReturnNodeSlice(t, undirectedMatrixFromBuilder, true)
|
||||
})
|
||||
t.Run("Weight", func(t *testing.T) {
|
||||
testgraph.Weight(t, undirectedMatrixFromBuilder)
|
||||
|
@@ -72,13 +72,16 @@ func (g *DirectedGraph) Edges() graph.Edges {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *DirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
from := make([]graph.Node, len(g.from[id]))
|
||||
@@ -87,6 +90,9 @@ func (g *DirectedGraph) From(id int64) graph.Nodes {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
if len(from) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(from)
|
||||
}
|
||||
|
||||
@@ -134,7 +140,7 @@ func (g *DirectedGraph) Node(id int64) graph.Node {
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *DirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
i := 0
|
||||
@@ -213,7 +219,7 @@ func (g *DirectedGraph) SetEdge(e graph.Edge) {
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *DirectedGraph) To(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
to := make([]graph.Node, len(g.to[id]))
|
||||
@@ -222,5 +228,8 @@ func (g *DirectedGraph) To(id int64) graph.Nodes {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
if len(to) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
@@ -59,19 +59,19 @@ func TestDirected(t *testing.T) {
|
||||
testgraph.NodeExistence(t, directedBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, directedBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, directedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllEdges(t, directedBuilder)
|
||||
testgraph.ReturnAllEdges(t, directedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, directedBuilder)
|
||||
testgraph.ReturnAllNodes(t, directedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnEdgeSlice(t, directedBuilder)
|
||||
testgraph.ReturnEdgeSlice(t, directedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, directedBuilder)
|
||||
testgraph.ReturnNodeSlice(t, directedBuilder, true)
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -4,4 +4,6 @@
|
||||
|
||||
// Package simple provides a suite of simple graph implementations satisfying
|
||||
// the gonum/graph interfaces.
|
||||
//
|
||||
// All types in simple return the graph.Empty value for empty iterators.
|
||||
package simple // import "gonum.org/v1/gonum/graph/simple"
|
||||
|
@@ -69,7 +69,7 @@ func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
// Edges returns all the edges in the graph.
|
||||
func (g *UndirectedGraph) Edges() graph.Edges {
|
||||
if len(g.edges) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var edges []graph.Edge
|
||||
seen := make(map[[2]int64]struct{})
|
||||
@@ -85,13 +85,16 @@ func (g *UndirectedGraph) Edges() graph.Edges {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *UndirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
nodes := make([]graph.Node, len(g.edges[id]))
|
||||
@@ -100,6 +103,9 @@ func (g *UndirectedGraph) From(id int64) graph.Nodes {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
@@ -135,7 +141,7 @@ func (g *UndirectedGraph) Node(id int64) graph.Node {
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *UndirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
i := 0
|
||||
|
@@ -59,19 +59,19 @@ func TestUndirected(t *testing.T) {
|
||||
testgraph.NodeExistence(t, undirectedBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, undirectedBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, undirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllEdges(t, undirectedBuilder)
|
||||
testgraph.ReturnAllEdges(t, undirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, undirectedBuilder)
|
||||
testgraph.ReturnAllNodes(t, undirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnEdgeSlice(t, undirectedBuilder)
|
||||
testgraph.ReturnEdgeSlice(t, undirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, undirectedBuilder)
|
||||
testgraph.ReturnNodeSlice(t, undirectedBuilder, true)
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -76,13 +76,16 @@ func (g *WeightedDirectedGraph) Edges() graph.Edges {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedDirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
from := make([]graph.Node, len(g.from[id]))
|
||||
@@ -91,6 +94,9 @@ func (g *WeightedDirectedGraph) From(id int64) graph.Nodes {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
if len(from) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(from)
|
||||
}
|
||||
|
||||
@@ -138,7 +144,7 @@ func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *WeightedDirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.from) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
i := 0
|
||||
@@ -217,7 +223,7 @@ func (g *WeightedDirectedGraph) SetWeightedEdge(e graph.WeightedEdge) {
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *WeightedDirectedGraph) To(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
to := make([]graph.Node, len(g.to[id]))
|
||||
@@ -226,6 +232,9 @@ func (g *WeightedDirectedGraph) To(id int64) graph.Nodes {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
if len(to) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
@@ -263,5 +272,8 @@ func (g *WeightedDirectedGraph) WeightedEdges() graph.WeightedEdges {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedWeightedEdges(edges)
|
||||
}
|
||||
|
@@ -59,25 +59,25 @@ func TestWeightedDirected(t *testing.T) {
|
||||
testgraph.NodeExistence(t, weightedDirectedBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllEdges(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnAllEdges(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnAllNodes(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllWeightedEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllWeightedEdges(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnAllWeightedEdges(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnEdgeSlice(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnEdgeSlice(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnWeightedEdgeSlice(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnWeightedEdgeSlice(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, weightedDirectedBuilder)
|
||||
testgraph.ReturnNodeSlice(t, weightedDirectedBuilder, true)
|
||||
})
|
||||
t.Run("Weight", func(t *testing.T) {
|
||||
testgraph.Weight(t, weightedDirectedBuilder)
|
||||
|
@@ -73,7 +73,7 @@ func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
// Edges returns all the edges in the graph.
|
||||
func (g *WeightedUndirectedGraph) Edges() graph.Edges {
|
||||
if len(g.edges) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
var edges []graph.Edge
|
||||
seen := make(map[[2]int64]struct{})
|
||||
@@ -89,13 +89,16 @@ func (g *WeightedUndirectedGraph) Edges() graph.Edges {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedUndirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
|
||||
nodes := make([]graph.Node, len(g.edges[id]))
|
||||
@@ -104,6 +107,9 @@ func (g *WeightedUndirectedGraph) From(id int64) graph.Nodes {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
@@ -139,7 +145,7 @@ func (g *WeightedUndirectedGraph) Node(id int64) graph.Node {
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *WeightedUndirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
i := 0
|
||||
@@ -257,5 +263,8 @@ func (g *WeightedUndirectedGraph) WeightedEdges() graph.WeightedEdges {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
if len(edges) == 0 {
|
||||
return graph.Empty
|
||||
}
|
||||
return iterator.NewOrderedWeightedEdges(edges)
|
||||
}
|
||||
|
@@ -59,25 +59,25 @@ func TestWeightedUndirected(t *testing.T) {
|
||||
testgraph.NodeExistence(t, weightedUndirectedBuilder)
|
||||
})
|
||||
t.Run("ReturnAdjacentNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAdjacentNodes(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnAdjacentNodes(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllEdges(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnAllEdges(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllNodes", func(t *testing.T) {
|
||||
testgraph.ReturnAllNodes(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnAllNodes(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnAllWeightedEdges", func(t *testing.T) {
|
||||
testgraph.ReturnAllWeightedEdges(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnAllWeightedEdges(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnEdgeSlice(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnEdgeSlice(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnWeightedEdgeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnWeightedEdgeSlice(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnWeightedEdgeSlice(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("ReturnNodeSlice", func(t *testing.T) {
|
||||
testgraph.ReturnNodeSlice(t, weightedUndirectedBuilder)
|
||||
testgraph.ReturnNodeSlice(t, weightedUndirectedBuilder, true)
|
||||
})
|
||||
t.Run("Weight", func(t *testing.T) {
|
||||
testgraph.Weight(t, weightedUndirectedBuilder)
|
||||
|
@@ -25,16 +25,23 @@ import (
|
||||
// compared with NaN-awareness, so they may be NaN when there is no edge
|
||||
// associated with the Weight call.
|
||||
|
||||
// BUG(kortschak): The approach of using a nil return for empty sets of nodes
|
||||
// and edges used prior to the introduction of the graph.Iterator types does
|
||||
// not interact well with interfaces. For example, it is not possible to simply
|
||||
// determine that an iterator is empty by calling it.Len without guarding that
|
||||
// with a nil check. The validity of nil iterators may change depending on the
|
||||
// outcome of https://github.com/gonum/gonum/issues/614.
|
||||
func isValidIterator(graph.Iterator) bool {
|
||||
// TODO(kortschak): Remove nil guards in iterator
|
||||
// loops and slicer tests if this changes.
|
||||
return true
|
||||
func isValidIterator(it graph.Iterator) bool {
|
||||
return it != nil
|
||||
}
|
||||
|
||||
func checkEmptyIterator(t *testing.T, it graph.Iterator, useEmpty bool) {
|
||||
if it.Len() != 0 {
|
||||
return
|
||||
}
|
||||
if it != graph.Empty {
|
||||
if useEmpty {
|
||||
t.Errorf("unexpected empty iterator: got:%T", it)
|
||||
return
|
||||
}
|
||||
// Only log this since we say that a graph should
|
||||
// return a graph.Empty when it is empty.
|
||||
t.Logf("unexpected empty iterator: got:%T", it)
|
||||
}
|
||||
}
|
||||
|
||||
// A Builder function returns a graph constructed from the nodes, edges and
|
||||
@@ -68,7 +75,9 @@ type matrixer interface {
|
||||
// ReturnAllNodes tests the constructed graph for the ability to return all
|
||||
// the nodes it claims it has used in its construction. This is a check of
|
||||
// the Nodes method of graph.Graph and the iterator that is returned.
|
||||
func ReturnAllNodes(t *testing.T, b Builder) {
|
||||
// If useEmpty is true, graph iterators will be checked for the use of
|
||||
// graph.Empty if they are empty.
|
||||
func ReturnAllNodes(t *testing.T, b Builder, useEmpty bool) {
|
||||
for _, test := range testCases {
|
||||
g, want, _, _, _, ok := b(test.nodes, test.edges, test.self, test.absent)
|
||||
if !ok {
|
||||
@@ -81,8 +90,9 @@ func ReturnAllNodes(t *testing.T, b Builder) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
var got []graph.Node
|
||||
for it != nil && it.Next() {
|
||||
for it.Next() {
|
||||
got = append(got, it.Node())
|
||||
}
|
||||
|
||||
@@ -99,7 +109,9 @@ func ReturnAllNodes(t *testing.T, b Builder) {
|
||||
// the nodes it claims it has used in its construction using the NodeSlicer
|
||||
// interface. This is a check of the Nodes method of graph.Graph and the
|
||||
// iterator that is returned.
|
||||
func ReturnNodeSlice(t *testing.T, b Builder) {
|
||||
// If useEmpty is true, graph iterators will be checked for the use of
|
||||
// graph.Empty if they are empty.
|
||||
func ReturnNodeSlice(t *testing.T, b Builder, useEmpty bool) {
|
||||
for _, test := range testCases {
|
||||
g, want, _, _, _, ok := b(test.nodes, test.edges, test.self, test.absent)
|
||||
if !ok {
|
||||
@@ -112,6 +124,7 @@ func ReturnNodeSlice(t *testing.T, b Builder) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
if it == nil {
|
||||
continue
|
||||
}
|
||||
@@ -168,7 +181,9 @@ func NodeExistence(t *testing.T, b Builder) {
|
||||
// the Edges method of graph.Graph and the iterator that is returned.
|
||||
// ReturnAllEdges also checks that the edge end nodes exist within the graph,
|
||||
// checking the Node method of graph.Graph.
|
||||
func ReturnAllEdges(t *testing.T, b Builder) {
|
||||
// If useEmpty is true, graph iterators will be checked for the use of
|
||||
// graph.Empty if they are empty.
|
||||
func ReturnAllEdges(t *testing.T, b Builder, useEmpty bool) {
|
||||
for _, test := range testCases {
|
||||
g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent)
|
||||
if !ok {
|
||||
@@ -184,7 +199,8 @@ func ReturnAllEdges(t *testing.T, b Builder) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
for it != nil && it.Next() {
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
for it.Next() {
|
||||
e := it.Edge()
|
||||
got = append(got, e)
|
||||
if g.Edge(e.From().ID(), e.To().ID()) == nil {
|
||||
@@ -212,7 +228,9 @@ func ReturnAllEdges(t *testing.T, b Builder) {
|
||||
// interface. This is a check of the Edges method of graph.Graph and the
|
||||
// iterator that is returned. ReturnEdgeSlice also checks that the edge end
|
||||
// nodes exist within the graph, checking the Node method of graph.Graph.
|
||||
func ReturnEdgeSlice(t *testing.T, b Builder) {
|
||||
// If useEmpty is true, graph iterators will be checked for the use of
|
||||
// graph.Empty if they are empty.
|
||||
func ReturnEdgeSlice(t *testing.T, b Builder, useEmpty bool) {
|
||||
for _, test := range testCases {
|
||||
g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent)
|
||||
if !ok {
|
||||
@@ -228,6 +246,7 @@ func ReturnEdgeSlice(t *testing.T, b Builder) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
if it == nil {
|
||||
continue
|
||||
}
|
||||
@@ -267,7 +286,9 @@ func ReturnEdgeSlice(t *testing.T, b Builder) {
|
||||
//
|
||||
// The edges used within and returned by the Builder function should be
|
||||
// graph.Line. The edge parameter passed to b will contain only graph.Line.
|
||||
func ReturnAllLines(t *testing.T, b Builder) {
|
||||
// If useEmpty is true, graph iterators will be checked for the use of
|
||||
// graph.Empty if they are empty.
|
||||
func ReturnAllLines(t *testing.T, b Builder, useEmpty bool) {
|
||||
for _, test := range testCases {
|
||||
g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent)
|
||||
if !ok {
|
||||
@@ -283,6 +304,7 @@ func ReturnAllLines(t *testing.T, b Builder) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
for _, e := range graph.EdgesOf(it) {
|
||||
if g.Edge(e.From().ID(), e.To().ID()) == nil {
|
||||
t.Errorf("missing edge for test %q: %v", test.name, e)
|
||||
@@ -294,11 +316,11 @@ func ReturnAllLines(t *testing.T, b Builder) {
|
||||
// and graph.Edges.
|
||||
switch lit := e.(type) {
|
||||
case graph.Lines:
|
||||
for lit != nil && lit.Next() {
|
||||
for lit.Next() {
|
||||
got = append(got, lit.Line())
|
||||
}
|
||||
case graph.WeightedLines:
|
||||
for lit != nil && lit.Next() {
|
||||
for lit.Next() {
|
||||
got = append(got, lit.WeightedLine())
|
||||
}
|
||||
default:
|
||||
@@ -331,7 +353,9 @@ func ReturnAllLines(t *testing.T, b Builder) {
|
||||
// The edges used within and returned by the Builder function should be
|
||||
// graph.WeightedEdge. The edge parameter passed to b will contain only
|
||||
// graph.WeightedEdge.
|
||||
func ReturnAllWeightedEdges(t *testing.T, b Builder) {
|
||||
// If useEmpty is true, graph iterators will be checked for the use of
|
||||
// graph.Empty if they are empty.
|
||||
func ReturnAllWeightedEdges(t *testing.T, b Builder, useEmpty bool) {
|
||||
for _, test := range testCases {
|
||||
g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent)
|
||||
if !ok {
|
||||
@@ -347,7 +371,8 @@ func ReturnAllWeightedEdges(t *testing.T, b Builder) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
for it != nil && it.Next() {
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
for it.Next() {
|
||||
e := it.WeightedEdge()
|
||||
got = append(got, e)
|
||||
switch g := g.(type) {
|
||||
@@ -388,7 +413,9 @@ func ReturnAllWeightedEdges(t *testing.T, b Builder) {
|
||||
// The edges used within and returned by the Builder function should be
|
||||
// graph.WeightedEdge. The edge parameter passed to b will contain only
|
||||
// graph.WeightedEdge.
|
||||
func ReturnWeightedEdgeSlice(t *testing.T, b Builder) {
|
||||
// If useEmpty is true, graph iterators will be checked for the use of
|
||||
// graph.Empty if they are empty.
|
||||
func ReturnWeightedEdgeSlice(t *testing.T, b Builder, useEmpty bool) {
|
||||
for _, test := range testCases {
|
||||
g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent)
|
||||
if !ok {
|
||||
@@ -404,6 +431,7 @@ func ReturnWeightedEdgeSlice(t *testing.T, b Builder) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
s, ok := it.(graph.WeightedEdgeSlicer)
|
||||
if !ok {
|
||||
t.Errorf("invalid type for test %T: cannot return weighted edge slice", g)
|
||||
@@ -442,7 +470,9 @@ func ReturnWeightedEdgeSlice(t *testing.T, b Builder) {
|
||||
// The edges used within and returned by the Builder function should be
|
||||
// graph.WeightedLine. The edge parameter passed to b will contain only
|
||||
// graph.WeightedLine.
|
||||
func ReturnAllWeightedLines(t *testing.T, b Builder) {
|
||||
// If useEmpty is true, graph iterators will be checked for the use of
|
||||
// graph.Empty if they are empty.
|
||||
func ReturnAllWeightedLines(t *testing.T, b Builder, useEmpty bool) {
|
||||
for _, test := range testCases {
|
||||
g, _, want, _, _, ok := b(test.nodes, test.edges, test.self, test.absent)
|
||||
if !ok {
|
||||
@@ -458,6 +488,7 @@ func ReturnAllWeightedLines(t *testing.T, b Builder) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
for _, e := range graph.WeightedEdgesOf(it) {
|
||||
if g.Edge(e.From().ID(), e.To().ID()) == nil {
|
||||
t.Errorf("missing edge for test %q: %v", test.name, e)
|
||||
@@ -469,11 +500,11 @@ func ReturnAllWeightedLines(t *testing.T, b Builder) {
|
||||
// and graph.Edges.
|
||||
switch lit := e.(type) {
|
||||
case graph.Lines:
|
||||
for lit != nil && lit.Next() {
|
||||
for lit.Next() {
|
||||
got = append(got, lit.Line())
|
||||
}
|
||||
case graph.WeightedLines:
|
||||
for lit != nil && lit.Next() {
|
||||
for lit.Next() {
|
||||
got = append(got, lit.WeightedLine())
|
||||
}
|
||||
default:
|
||||
@@ -602,7 +633,9 @@ func EdgeExistence(t *testing.T, b Builder) {
|
||||
// within the graph, checking the Node, Edge, EdgeBetween and HasEdgeBetween
|
||||
// methods of graph.Graph, the EdgeBetween method of graph.Undirected and the
|
||||
// HasEdgeFromTo method of graph.Directed.
|
||||
func ReturnAdjacentNodes(t *testing.T, b Builder) {
|
||||
// If useEmpty is true, graph iterators will be checked for the use of
|
||||
// graph.Empty if they are empty.
|
||||
func ReturnAdjacentNodes(t *testing.T, b Builder, useEmpty bool) {
|
||||
for _, test := range testCases {
|
||||
g, nodes, edges, _, _, ok := b(test.nodes, test.edges, test.self, test.absent)
|
||||
if !ok {
|
||||
@@ -620,7 +653,12 @@ func ReturnAdjacentNodes(t *testing.T, b Builder) {
|
||||
// Test forward.
|
||||
u := x
|
||||
it := g.From(u.ID())
|
||||
for i := 0; it != nil && it.Next(); i++ {
|
||||
if !isValidIterator(it) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
for i := 0; it.Next(); i++ {
|
||||
v := it.Node()
|
||||
if i == 0 && g.Node(u.ID()) == nil {
|
||||
t.Errorf("missing from node for test %q: %v", test.name, u.ID())
|
||||
@@ -645,7 +683,12 @@ func ReturnAdjacentNodes(t *testing.T, b Builder) {
|
||||
// Test backward.
|
||||
v := x
|
||||
it = g.To(v.ID())
|
||||
for i := 0; it != nil && it.Next(); i++ {
|
||||
if !isValidIterator(it) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
for i := 0; it.Next(); i++ {
|
||||
u := it.Node()
|
||||
if i == 0 && g.Node(v.ID()) == nil {
|
||||
t.Errorf("missing to node for test %q: %v", test.name, v.ID())
|
||||
@@ -673,7 +716,12 @@ func ReturnAdjacentNodes(t *testing.T, b Builder) {
|
||||
case graph.Undirected:
|
||||
u := x
|
||||
it := g.From(u.ID())
|
||||
for i := 0; it != nil && it.Next(); i++ {
|
||||
if !isValidIterator(it) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
for i := 0; it.Next(); i++ {
|
||||
v := it.Node()
|
||||
if i == 0 && g.Node(u.ID()) == nil {
|
||||
t.Errorf("missing from node for test %q: %v", test.name, u.ID())
|
||||
@@ -699,7 +747,12 @@ func ReturnAdjacentNodes(t *testing.T, b Builder) {
|
||||
default:
|
||||
u := x
|
||||
it := g.From(u.ID())
|
||||
for i := 0; it != nil && it.Next(); i++ {
|
||||
if !isValidIterator(it) {
|
||||
t.Errorf("invalid iterator for test %q: got:%#v", test.name, it)
|
||||
continue
|
||||
}
|
||||
checkEmptyIterator(t, it, useEmpty)
|
||||
for i := 0; it.Next(); i++ {
|
||||
v := it.Node()
|
||||
if i == 0 && g.Node(u.ID()) == nil {
|
||||
t.Errorf("missing from node for test %q: %v", test.name, u.ID())
|
||||
|
@@ -252,7 +252,7 @@ func (g johnsonGraph) Nodes() graph.Nodes {
|
||||
func (g johnsonGraph) From(id int64) graph.Nodes {
|
||||
adj := g.succ[id]
|
||||
if len(adj) == 0 {
|
||||
return nil
|
||||
return graph.Empty
|
||||
}
|
||||
succ := make([]graph.Node, 0, len(adj))
|
||||
for id := range adj {
|
||||
|
Reference in New Issue
Block a user