mirror of
https://github.com/gonum/gonum.git
synced 2025-10-14 19:26:30 +08:00
graph: add node, edge and line iterators
This commit is contained in:
@@ -26,7 +26,7 @@ func KCliqueCommunities(k int, g graph.Undirected) [][]graph.Node {
|
||||
}
|
||||
switch k {
|
||||
case 1:
|
||||
return [][]graph.Node{g.Nodes()}
|
||||
return [][]graph.Node{graph.NodesOf(g.Nodes())}
|
||||
case 2:
|
||||
return topo.ConnectedComponents(g)
|
||||
default:
|
||||
|
@@ -95,11 +95,11 @@ func Modularize(g graph.Graph, resolution float64, src rand.Source) ReducedGraph
|
||||
|
||||
// Multiplex is a multiplex graph.
|
||||
type Multiplex interface {
|
||||
// Nodes returns the slice of nodes
|
||||
// Nodes returns the nodes
|
||||
// for the multiplex graph.
|
||||
// All layers must refer to the same
|
||||
// set of nodes.
|
||||
Nodes() []graph.Node
|
||||
Nodes() graph.Nodes
|
||||
|
||||
// Depth returns the number of layers
|
||||
// in the multiplex graph.
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||
"gonum.org/v1/gonum/graph/internal/set"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// qDirected returns the modularity Q score of the graph g subdivided into the
|
||||
@@ -24,7 +25,7 @@ import (
|
||||
// Q = 1/m \sum_{ij} [ A_{ij} - (\gamma k_i^in k_j^out)/m ] \delta(c_i,c_j)
|
||||
//
|
||||
func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64) float64 {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
weight := positiveWeightFuncFor(g)
|
||||
|
||||
// Calculate the total edge weight of the graph
|
||||
@@ -35,14 +36,16 @@ func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64)
|
||||
var wOut float64
|
||||
u := n
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
wOut += weight(uid, v.ID())
|
||||
to := g.From(uid)
|
||||
for to.Next() {
|
||||
wOut += weight(uid, to.Node().ID())
|
||||
}
|
||||
var wIn float64
|
||||
v := n
|
||||
vid := v.ID()
|
||||
for _, u := range g.To(vid) {
|
||||
wIn += weight(u.ID(), vid)
|
||||
from := g.To(vid)
|
||||
for from.Next() {
|
||||
wIn += weight(from.Node().ID(), vid)
|
||||
}
|
||||
id := n.ID()
|
||||
w := weight(id, id)
|
||||
@@ -177,7 +180,7 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
||||
return r
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
// TODO(kortschak) This sort is necessary really only
|
||||
// for testing. In practice we would not be using the
|
||||
// community provided by the user for a Q calculation.
|
||||
@@ -210,8 +213,9 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
||||
var out []int
|
||||
u := n
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
to := g.From(uid)
|
||||
for to.Next() {
|
||||
vid := to.Node().ID()
|
||||
vcid := communityOf[vid]
|
||||
if vcid != id {
|
||||
out = append(out, vcid)
|
||||
@@ -223,8 +227,9 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
||||
var in []int
|
||||
v := n
|
||||
vid := v.ID()
|
||||
for _, u := range g.To(vid) {
|
||||
uid := u.ID()
|
||||
from := g.To(vid)
|
||||
for from.Next() {
|
||||
uid := from.Node().ID()
|
||||
ucid := communityOf[uid]
|
||||
if ucid != id {
|
||||
in = append(in, ucid)
|
||||
@@ -285,8 +290,9 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
||||
r.nodes[id].weight += weight(uid, v.ID())
|
||||
}
|
||||
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
to := g.From(uid)
|
||||
for to.Next() {
|
||||
vid := to.Node().ID()
|
||||
vcid := communityOf[vid]
|
||||
found := false
|
||||
for _, e := range out {
|
||||
@@ -305,8 +311,9 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
||||
|
||||
v := n
|
||||
vid := v.ID()
|
||||
for _, u := range g.To(vid) {
|
||||
uid := u.ID()
|
||||
from := g.To(vid)
|
||||
for from.Next() {
|
||||
uid := from.Node().ID()
|
||||
ucid := communityOf[uid]
|
||||
found := false
|
||||
for _, e := range in {
|
||||
@@ -335,32 +342,32 @@ func (g *ReducedDirected) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *ReducedDirected) Nodes() []graph.Node {
|
||||
func (g *ReducedDirected) Nodes() graph.Nodes {
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
for i := range g.nodes {
|
||||
nodes[i] = node(i)
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g *ReducedDirected) From(uid int64) []graph.Node {
|
||||
func (g *ReducedDirected) From(uid int64) graph.Nodes {
|
||||
out := g.edgesFrom[uid]
|
||||
nodes := make([]graph.Node, len(out))
|
||||
for i, vid := range out {
|
||||
nodes[i] = g.nodes[vid]
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to v.
|
||||
func (g *ReducedDirected) To(vid int64) []graph.Node {
|
||||
func (g *ReducedDirected) To(vid int64) graph.Nodes {
|
||||
in := g.edgesTo[vid]
|
||||
nodes := make([]graph.Node, len(in))
|
||||
for i, uid := range in {
|
||||
nodes[i] = g.nodes[uid]
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -473,7 +480,7 @@ type directedWeights struct {
|
||||
// nodes.
|
||||
// If g has a zero edge weight sum, nil is returned.
|
||||
func newDirectedLocalMover(g *ReducedDirected, communities [][]graph.Node, resolution float64) *directedLocalMover {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
l := directedLocalMover{
|
||||
g: g,
|
||||
nodes: nodes,
|
||||
@@ -490,15 +497,17 @@ func newDirectedLocalMover(g *ReducedDirected, communities [][]graph.Node, resol
|
||||
u := n
|
||||
var wOut float64
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
wOut += l.weight(uid, v.ID())
|
||||
to := g.From(uid)
|
||||
for to.Next() {
|
||||
wOut += l.weight(uid, to.Node().ID())
|
||||
}
|
||||
|
||||
v := n
|
||||
var wIn float64
|
||||
vid := v.ID()
|
||||
for _, u := range g.To(vid) {
|
||||
wIn += l.weight(u.ID(), vid)
|
||||
from := g.To(vid)
|
||||
for from.Next() {
|
||||
wIn += l.weight(from.Node().ID(), vid)
|
||||
}
|
||||
|
||||
id := n.ID()
|
||||
|
@@ -14,6 +14,7 @@ import (
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||
"gonum.org/v1/gonum/graph/internal/set"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// DirectedMultiplex is a directed multiplex graph.
|
||||
@@ -43,7 +44,7 @@ type DirectedMultiplex interface {
|
||||
// Note that Q values for multiplex graphs are not scaled by the total layer edge weight.
|
||||
func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights, resolutions []float64) []float64 {
|
||||
q := make([]float64, g.Depth())
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
layerWeight := 1.0
|
||||
layerResolution := 1.0
|
||||
if len(resolutions) == 1 {
|
||||
@@ -78,14 +79,16 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
|
||||
var wOut float64
|
||||
u := n
|
||||
uid := u.ID()
|
||||
for _, v := range layer.From(uid) {
|
||||
wOut += weight(uid, v.ID())
|
||||
to := layer.From(uid)
|
||||
for to.Next() {
|
||||
wOut += weight(uid, to.Node().ID())
|
||||
}
|
||||
var wIn float64
|
||||
v := n
|
||||
vid := v.ID()
|
||||
for _, u := range layer.To(vid) {
|
||||
wIn += weight(u.ID(), vid)
|
||||
from := layer.To(vid)
|
||||
for from.Next() {
|
||||
wIn += weight(from.Node().ID(), vid)
|
||||
}
|
||||
id := n.ID()
|
||||
w := weight(id, id)
|
||||
@@ -132,13 +135,15 @@ func NewDirectedLayers(layers ...graph.Directed) (DirectedLayers, error) {
|
||||
return nil, nil
|
||||
}
|
||||
base := make(set.Int64s)
|
||||
for _, n := range layers[0].Nodes() {
|
||||
base.Add(n.ID())
|
||||
nodes := layers[0].Nodes()
|
||||
for nodes.Next() {
|
||||
base.Add(nodes.Node().ID())
|
||||
}
|
||||
for i, l := range layers[1:] {
|
||||
next := make(set.Int64s)
|
||||
for _, n := range l.Nodes() {
|
||||
next.Add(n.ID())
|
||||
nodes := l.Nodes()
|
||||
for nodes.Next() {
|
||||
next.Add(nodes.Node().ID())
|
||||
}
|
||||
if !set.Int64sEqual(base, next) {
|
||||
return nil, fmt.Errorf("community: layer ID mismatch between layers: %d", i+1)
|
||||
@@ -148,7 +153,7 @@ func NewDirectedLayers(layers ...graph.Directed) (DirectedLayers, error) {
|
||||
}
|
||||
|
||||
// Nodes returns the nodes of the receiver.
|
||||
func (g DirectedLayers) Nodes() []graph.Node {
|
||||
func (g DirectedLayers) Nodes() graph.Nodes {
|
||||
if len(g) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -219,12 +224,12 @@ var (
|
||||
)
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *ReducedDirectedMultiplex) Nodes() []graph.Node {
|
||||
func (g *ReducedDirectedMultiplex) Nodes() graph.Nodes {
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
for i := range g.nodes {
|
||||
nodes[i] = node(i)
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Depth returns the number of layers in the multiplex graph.
|
||||
@@ -288,7 +293,7 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
||||
return r
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
// TODO(kortschak) This sort is necessary really only
|
||||
// for testing. In practice we would not be using the
|
||||
// community provided by the user for a Q calculation.
|
||||
@@ -339,8 +344,9 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
||||
var out []int
|
||||
u := n
|
||||
uid := u.ID()
|
||||
for _, v := range layer.From(uid) {
|
||||
vid := v.ID()
|
||||
to := layer.From(uid)
|
||||
for to.Next() {
|
||||
vid := to.Node().ID()
|
||||
vcid := communityOf[vid]
|
||||
if vcid != id {
|
||||
out = append(out, vcid)
|
||||
@@ -352,8 +358,9 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
||||
var in []int
|
||||
v := n
|
||||
vid := v.ID()
|
||||
for _, u := range layer.To(vid) {
|
||||
uid := u.ID()
|
||||
from := layer.To(vid)
|
||||
for from.Next() {
|
||||
uid := from.Node().ID()
|
||||
ucid := communityOf[uid]
|
||||
if ucid != id {
|
||||
in = append(in, ucid)
|
||||
@@ -433,8 +440,9 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
||||
r.nodes[id].weights[l] += sign * weight(uid, v.ID())
|
||||
}
|
||||
|
||||
for _, v := range layer.From(uid) {
|
||||
vid := v.ID()
|
||||
to := layer.From(uid)
|
||||
for to.Next() {
|
||||
vid := to.Node().ID()
|
||||
vcid := communityOf[vid]
|
||||
found := false
|
||||
for _, e := range out {
|
||||
@@ -453,8 +461,9 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
||||
|
||||
v := n
|
||||
vid := v.ID()
|
||||
for _, u := range layer.To(vid) {
|
||||
uid := u.ID()
|
||||
from := layer.To(vid)
|
||||
for from.Next() {
|
||||
uid := from.Node().ID()
|
||||
ucid := communityOf[uid]
|
||||
found := false
|
||||
for _, e := range in {
|
||||
@@ -497,32 +506,32 @@ func (g directedLayerHandle) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g directedLayerHandle) Nodes() []graph.Node {
|
||||
func (g directedLayerHandle) Nodes() graph.Nodes {
|
||||
nodes := make([]graph.Node, len(g.multiplex.nodes))
|
||||
for i := range g.multiplex.nodes {
|
||||
nodes[i] = node(i)
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g directedLayerHandle) From(uid int64) []graph.Node {
|
||||
func (g directedLayerHandle) From(uid int64) graph.Nodes {
|
||||
out := g.multiplex.layers[g.layer].edgesFrom[uid]
|
||||
nodes := make([]graph.Node, len(out))
|
||||
for i, vid := range out {
|
||||
nodes[i] = g.multiplex.nodes[vid]
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to v.
|
||||
func (g directedLayerHandle) To(vid int64) []graph.Node {
|
||||
func (g directedLayerHandle) To(vid int64) graph.Nodes {
|
||||
in := g.multiplex.layers[g.layer].edgesTo[vid]
|
||||
nodes := make([]graph.Node, len(in))
|
||||
for i, uid := range in {
|
||||
nodes[i] = g.multiplex.nodes[uid]
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -643,7 +652,7 @@ type directedMultiplexLocalMover struct {
|
||||
// node IDs of g must be contiguous in [0,n) where n is the number of nodes.
|
||||
// If g has a zero edge weight sum, nil is returned.
|
||||
func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][]graph.Node, weights, resolutions []float64, all bool) *directedMultiplexLocalMover {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
l := directedMultiplexLocalMover{
|
||||
g: g,
|
||||
nodes: nodes,
|
||||
@@ -684,15 +693,17 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
|
||||
u := n
|
||||
uid := u.ID()
|
||||
var wOut float64
|
||||
for _, v := range layer.From(uid) {
|
||||
wOut += weight(uid, v.ID())
|
||||
to := layer.From(uid)
|
||||
for to.Next() {
|
||||
wOut += weight(uid, to.Node().ID())
|
||||
}
|
||||
|
||||
v := n
|
||||
vid := v.ID()
|
||||
var wIn float64
|
||||
for _, u := range layer.To(vid) {
|
||||
wIn += weight(u.ID(), vid)
|
||||
from := layer.To(vid)
|
||||
for from.Next() {
|
||||
wIn += weight(from.Node().ID(), vid)
|
||||
}
|
||||
|
||||
id := n.ID()
|
||||
|
@@ -244,7 +244,7 @@ func init() {
|
||||
// such that every edge dupGraph is replaced
|
||||
// with an edge that flows from the low node
|
||||
// ID to the high node ID.
|
||||
for _, e := range dupGraph.Edges() {
|
||||
for _, e := range graph.EdgesOf(dupGraph.Edges()) {
|
||||
if e.To().ID() < e.From().ID() {
|
||||
se := e.(simple.Edge)
|
||||
se.F, se.T = se.T, se.F
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||
"gonum.org/v1/gonum/graph/internal/set"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// qUndirected returns the modularity Q score of the graph g subdivided into the
|
||||
@@ -26,7 +27,7 @@ import (
|
||||
// graph.Undirect may be used as a shim to allow calculation of Q for
|
||||
// directed graphs.
|
||||
func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution float64) float64 {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
weight := positiveWeightFuncFor(g)
|
||||
|
||||
// Calculate the total edge weight of the graph
|
||||
@@ -36,8 +37,9 @@ func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution floa
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
w := weight(uid, uid)
|
||||
for _, v := range g.From(uid) {
|
||||
w += weight(uid, v.ID())
|
||||
to := g.From(uid)
|
||||
for to.Next() {
|
||||
w += weight(uid, to.Node().ID())
|
||||
}
|
||||
m2 += w
|
||||
k[uid] = w
|
||||
@@ -175,7 +177,7 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
|
||||
return r
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
// TODO(kortschak) This sort is necessary really only
|
||||
// for testing. In practice we would not be using the
|
||||
// community provided by the user for a Q calculation.
|
||||
@@ -205,8 +207,9 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
|
||||
uid := u.ID()
|
||||
ucid := communityOf[uid]
|
||||
var out []int
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
to := g.From(uid)
|
||||
for to.Next() {
|
||||
vid := to.Node().ID()
|
||||
vcid := communityOf[vid]
|
||||
if vcid != ucid {
|
||||
out = append(out, vcid)
|
||||
@@ -268,8 +271,9 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
|
||||
for _, v := range comm[i+1:] {
|
||||
r.nodes[ucid].weight += 2 * weight(uid, v.ID())
|
||||
}
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
to := g.From(uid)
|
||||
for to.Next() {
|
||||
vid := to.Node().ID()
|
||||
vcid := communityOf[vid]
|
||||
found := false
|
||||
for _, e := range out {
|
||||
@@ -298,22 +302,22 @@ func (g *ReducedUndirected) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *ReducedUndirected) Nodes() []graph.Node {
|
||||
func (g *ReducedUndirected) Nodes() graph.Nodes {
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
for i := range g.nodes {
|
||||
nodes[i] = node(i)
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g *ReducedUndirected) From(uid int64) []graph.Node {
|
||||
func (g *ReducedUndirected) From(uid int64) graph.Nodes {
|
||||
out := g.edges[uid]
|
||||
nodes := make([]graph.Node, len(out))
|
||||
for i, vid := range out {
|
||||
nodes[i] = g.nodes[vid]
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -427,7 +431,7 @@ type undirectedLocalMover struct {
|
||||
// node IDs of g must be contiguous in [0,n) where n is the number of nodes.
|
||||
// If g has a zero edge weight sum, nil is returned.
|
||||
func newUndirectedLocalMover(g *ReducedUndirected, communities [][]graph.Node, resolution float64) *undirectedLocalMover {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
l := undirectedLocalMover{
|
||||
g: g,
|
||||
nodes: nodes,
|
||||
@@ -443,8 +447,9 @@ func newUndirectedLocalMover(g *ReducedUndirected, communities [][]graph.Node, r
|
||||
for _, u := range l.nodes {
|
||||
uid := u.ID()
|
||||
w := l.weight(uid, uid)
|
||||
for _, v := range g.From(uid) {
|
||||
w += l.weight(uid, v.ID())
|
||||
to := g.From(uid)
|
||||
for to.Next() {
|
||||
w += l.weight(uid, to.Node().ID())
|
||||
}
|
||||
l.edgeWeightOf[uid] = w
|
||||
l.m2 += w
|
||||
|
@@ -14,6 +14,7 @@ import (
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||
"gonum.org/v1/gonum/graph/internal/set"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// UndirectedMultiplex is an undirected multiplex graph.
|
||||
@@ -46,7 +47,7 @@ type UndirectedMultiplex interface {
|
||||
// directed graphs.
|
||||
func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, weights, resolutions []float64) []float64 {
|
||||
q := make([]float64, g.Depth())
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
layerWeight := 1.0
|
||||
layerResolution := 1.0
|
||||
if len(resolutions) == 1 {
|
||||
@@ -80,8 +81,9 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
w := weight(uid, uid)
|
||||
for _, v := range layer.From(uid) {
|
||||
w += weight(uid, v.ID())
|
||||
to := layer.From(uid)
|
||||
for to.Next() {
|
||||
w += weight(uid, to.Node().ID())
|
||||
}
|
||||
m2 += w
|
||||
k[uid] = w
|
||||
@@ -129,13 +131,15 @@ func NewUndirectedLayers(layers ...graph.Undirected) (UndirectedLayers, error) {
|
||||
return nil, nil
|
||||
}
|
||||
base := make(set.Int64s)
|
||||
for _, n := range layers[0].Nodes() {
|
||||
base.Add(n.ID())
|
||||
nodes := layers[0].Nodes()
|
||||
for nodes.Next() {
|
||||
base.Add(nodes.Node().ID())
|
||||
}
|
||||
for i, l := range layers[1:] {
|
||||
next := make(set.Int64s)
|
||||
for _, n := range l.Nodes() {
|
||||
next.Add(n.ID())
|
||||
nodes := l.Nodes()
|
||||
for nodes.Next() {
|
||||
next.Add(nodes.Node().ID())
|
||||
}
|
||||
if !set.Int64sEqual(next, base) {
|
||||
return nil, fmt.Errorf("community: layer ID mismatch between layers: %d", i+1)
|
||||
@@ -145,7 +149,7 @@ func NewUndirectedLayers(layers ...graph.Undirected) (UndirectedLayers, error) {
|
||||
}
|
||||
|
||||
// Nodes returns the nodes of the receiver.
|
||||
func (g UndirectedLayers) Nodes() []graph.Node {
|
||||
func (g UndirectedLayers) Nodes() graph.Nodes {
|
||||
if len(g) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -216,12 +220,12 @@ var (
|
||||
)
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *ReducedUndirectedMultiplex) Nodes() []graph.Node {
|
||||
func (g *ReducedUndirectedMultiplex) Nodes() graph.Nodes {
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
for i := range g.nodes {
|
||||
nodes[i] = node(i)
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Depth returns the number of layers in the multiplex graph.
|
||||
@@ -285,7 +289,7 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
|
||||
return r
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
// TODO(kortschak) This sort is necessary really only
|
||||
// for testing. In practice we would not be using the
|
||||
// community provided by the user for a Q calculation.
|
||||
@@ -333,8 +337,9 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
|
||||
var out []int
|
||||
uid := u.ID()
|
||||
ucid := communityOf[uid]
|
||||
for _, v := range layer.From(uid) {
|
||||
vid := v.ID()
|
||||
to := layer.From(uid)
|
||||
for to.Next() {
|
||||
vid := to.Node().ID()
|
||||
vcid := communityOf[vid]
|
||||
if vcid != ucid {
|
||||
out = append(out, vcid)
|
||||
@@ -415,8 +420,9 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
|
||||
for _, v := range comm[i+1:] {
|
||||
r.nodes[ucid].weights[l] += 2 * sign * weight(uid, v.ID())
|
||||
}
|
||||
for _, v := range layer.From(uid) {
|
||||
vid := v.ID()
|
||||
to := layer.From(uid)
|
||||
for to.Next() {
|
||||
vid := to.Node().ID()
|
||||
vcid := communityOf[vid]
|
||||
found := false
|
||||
for _, e := range out {
|
||||
@@ -458,22 +464,22 @@ func (g undirectedLayerHandle) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g undirectedLayerHandle) Nodes() []graph.Node {
|
||||
func (g undirectedLayerHandle) Nodes() graph.Nodes {
|
||||
nodes := make([]graph.Node, len(g.multiplex.nodes))
|
||||
for i := range g.multiplex.nodes {
|
||||
nodes[i] = node(i)
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g undirectedLayerHandle) From(uid int64) []graph.Node {
|
||||
func (g undirectedLayerHandle) From(uid int64) graph.Nodes {
|
||||
out := g.multiplex.layers[g.layer].edges[uid]
|
||||
nodes := make([]graph.Node, len(out))
|
||||
for i, vid := range out {
|
||||
nodes[i] = g.multiplex.nodes[vid]
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -597,7 +603,7 @@ type undirectedMultiplexLocalMover struct {
|
||||
// node IDs of g must be contiguous in [0,n) where n is the number of nodes.
|
||||
// If g has a zero edge weight sum, nil is returned.
|
||||
func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities [][]graph.Node, weights, resolutions []float64, all bool) *undirectedMultiplexLocalMover {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
l := undirectedMultiplexLocalMover{
|
||||
g: g,
|
||||
nodes: nodes,
|
||||
@@ -637,8 +643,9 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
|
||||
for _, u := range l.nodes {
|
||||
uid := u.ID()
|
||||
w := weight(uid, uid)
|
||||
for _, v := range layer.From(uid) {
|
||||
w += weight(uid, v.ID())
|
||||
to := layer.From(uid)
|
||||
for to.Next() {
|
||||
w += weight(uid, to.Node().ID())
|
||||
}
|
||||
l.edgeWeightOf[i][uid] = w
|
||||
l.m2[i] += w
|
||||
|
@@ -109,7 +109,7 @@ type edge struct {
|
||||
}
|
||||
|
||||
func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool) error {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
sort.Sort(ordered.ByID(nodes))
|
||||
|
||||
p.buf.WriteString(p.prefix)
|
||||
@@ -156,7 +156,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
||||
if s, ok := n.(Subgrapher); ok {
|
||||
// If the node is not linked to any other node
|
||||
// the graph needs to be written now.
|
||||
if len(g.From(n.ID())) == 0 {
|
||||
if g.From(n.ID()).Len() == 0 {
|
||||
g := s.Subgraph()
|
||||
_, subIsDirected := g.(graph.Directed)
|
||||
if subIsDirected != isDirected {
|
||||
@@ -188,7 +188,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
||||
havePrintedEdgeHeader := false
|
||||
for _, n := range nodes {
|
||||
nid := n.ID()
|
||||
to := g.From(nid)
|
||||
to := graph.NodesOf(g.From(nid))
|
||||
sort.Sort(ordered.ByID(to))
|
||||
for _, t := range to {
|
||||
tid := t.ID()
|
||||
|
@@ -6,6 +6,7 @@ package main
|
||||
|
||||
import (
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/graph/simple"
|
||||
)
|
||||
|
||||
@@ -83,7 +84,7 @@ func (g *GraphNode) has(id int64, visited map[int64]struct{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *GraphNode) Nodes() []graph.Node {
|
||||
func (g *GraphNode) Nodes() graph.Nodes {
|
||||
toReturn := []graph.Node{g}
|
||||
visited := map[int64]struct{}{g.id: {}}
|
||||
|
||||
@@ -103,7 +104,7 @@ func (g *GraphNode) Nodes() []graph.Node {
|
||||
}
|
||||
}
|
||||
|
||||
return toReturn
|
||||
return iterator.NewOrderedNodes(toReturn)
|
||||
}
|
||||
|
||||
func (g *GraphNode) nodes(list []graph.Node, visited map[int64]struct{}) []graph.Node {
|
||||
@@ -131,9 +132,9 @@ func (g *GraphNode) nodes(list []graph.Node, visited map[int64]struct{}) []graph
|
||||
return list
|
||||
}
|
||||
|
||||
func (g *GraphNode) From(id int64) []graph.Node {
|
||||
func (g *GraphNode) From(id int64) graph.Nodes {
|
||||
if id == g.ID() {
|
||||
return g.neighbors
|
||||
return iterator.NewOrderedNodes(g.neighbors)
|
||||
}
|
||||
|
||||
visited := map[int64]struct{}{g.id: {}}
|
||||
@@ -141,7 +142,7 @@ func (g *GraphNode) From(id int64) []graph.Node {
|
||||
visited[root.ID()] = struct{}{}
|
||||
|
||||
if result := root.findNeighbors(id, visited); result != nil {
|
||||
return result
|
||||
return iterator.NewOrderedNodes(result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +151,7 @@ func (g *GraphNode) From(id int64) []graph.Node {
|
||||
|
||||
if gn, ok := neigh.(*GraphNode); ok {
|
||||
if result := gn.findNeighbors(id, visited); result != nil {
|
||||
return result
|
||||
return iterator.NewOrderedNodes(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -32,11 +32,11 @@ type Graph interface {
|
||||
Has(id int64) bool
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
Nodes() []Node
|
||||
Nodes() Nodes
|
||||
|
||||
// From returns all nodes that can be reached directly
|
||||
// from the node with the given ID.
|
||||
From(id int64) []Node
|
||||
From(id int64) Nodes
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between
|
||||
// nodes with IDs xid and yid without considering direction.
|
||||
@@ -99,7 +99,7 @@ type Directed interface {
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the node with the given ID.
|
||||
To(id int64) []Node
|
||||
To(id int64) Nodes
|
||||
}
|
||||
|
||||
// WeightedDirected is a weighted directed graph.
|
||||
@@ -113,7 +113,7 @@ type WeightedDirected interface {
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the node with the given ID.
|
||||
To(id int64) []Node
|
||||
To(id int64) Nodes
|
||||
}
|
||||
|
||||
// NodeAdder is an interface for adding arbitrary nodes to a graph.
|
||||
@@ -219,11 +219,15 @@ type DirectedWeightedBuilder interface {
|
||||
// be present in the destination after the copy is complete.
|
||||
func Copy(dst Builder, src Graph) {
|
||||
nodes := src.Nodes()
|
||||
for _, n := range nodes {
|
||||
dst.AddNode(n)
|
||||
for nodes.Next() {
|
||||
dst.AddNode(nodes.Node())
|
||||
}
|
||||
for _, u := range nodes {
|
||||
for _, v := range src.From(u.ID()) {
|
||||
nodes.Reset()
|
||||
for nodes.Next() {
|
||||
u := nodes.Node()
|
||||
to := src.From(u.ID())
|
||||
for to.Next() {
|
||||
v := to.Node()
|
||||
dst.SetEdge(dst.NewEdge(u, v))
|
||||
}
|
||||
}
|
||||
@@ -242,11 +246,15 @@ func Copy(dst Builder, src Graph) {
|
||||
// to resolve such conflicts, an UndirectWeighted may be used to do this.
|
||||
func CopyWeighted(dst WeightedBuilder, src Weighted) {
|
||||
nodes := src.Nodes()
|
||||
for _, n := range nodes {
|
||||
dst.AddNode(n)
|
||||
for nodes.Next() {
|
||||
dst.AddNode(nodes.Node())
|
||||
}
|
||||
for _, u := range nodes {
|
||||
for _, v := range src.From(u.ID()) {
|
||||
nodes.Reset()
|
||||
for nodes.Next() {
|
||||
u := nodes.Node()
|
||||
to := src.From(u.ID())
|
||||
for to.Next() {
|
||||
v := to.Node()
|
||||
dst.SetWeightedEdge(dst.NewWeightedEdge(u, v, src.WeightedEdge(u.ID(), v.ID()).Weight()))
|
||||
}
|
||||
}
|
||||
|
@@ -262,8 +262,8 @@ func TestCopyWeighted(t *testing.T) {
|
||||
}
|
||||
|
||||
func same(a, b graph.Graph) bool {
|
||||
aNodes := a.Nodes()
|
||||
bNodes := b.Nodes()
|
||||
aNodes := graph.NodesOf(a.Nodes())
|
||||
bNodes := graph.NodesOf(b.Nodes())
|
||||
sort.Sort(ordered.ByID(aNodes))
|
||||
sort.Sort(ordered.ByID(bNodes))
|
||||
for i, na := range aNodes {
|
||||
@@ -272,9 +272,9 @@ func same(a, b graph.Graph) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, u := range a.Nodes() {
|
||||
aFromU := a.From(u.ID())
|
||||
bFromU := b.From(u.ID())
|
||||
for _, u := range graph.NodesOf(a.Nodes()) {
|
||||
aFromU := graph.NodesOf(a.From(u.ID()))
|
||||
bFromU := graph.NodesOf(b.From(u.ID()))
|
||||
if len(aFromU) != len(bFromU) {
|
||||
return false
|
||||
}
|
||||
|
@@ -185,15 +185,16 @@ func TestPowerLawUndirected(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
if len(nodes) != n {
|
||||
t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, len(nodes))
|
||||
if nodes.Len() != n {
|
||||
t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, nodes.Len())
|
||||
}
|
||||
|
||||
for _, u := range nodes {
|
||||
for nodes.Next() {
|
||||
u := nodes.Node()
|
||||
uid := u.ID()
|
||||
var lines int
|
||||
for _, v := range g.From(uid) {
|
||||
lines += len(g.Lines(uid, v.ID()))
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
lines += g.Lines(uid, v.ID()).Len()
|
||||
}
|
||||
if lines < d {
|
||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||
@@ -214,15 +215,16 @@ func TestPowerLawDirected(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
if len(nodes) != n {
|
||||
t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, len(nodes))
|
||||
if nodes.Len() != n {
|
||||
t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, nodes.Len())
|
||||
}
|
||||
|
||||
for _, u := range nodes {
|
||||
for nodes.Next() {
|
||||
u := nodes.Node()
|
||||
uid := u.ID()
|
||||
var lines int
|
||||
for _, v := range g.From(uid) {
|
||||
lines += len(g.Lines(uid, v.ID()))
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
lines += g.Lines(uid, v.ID()).Len()
|
||||
}
|
||||
if lines < d {
|
||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||
@@ -243,8 +245,8 @@ func TestBipartitePowerLawUndirected(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
if len(nodes) != 2*n {
|
||||
t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, len(nodes))
|
||||
if nodes.Len() != 2*n {
|
||||
t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, nodes.Len())
|
||||
}
|
||||
if len(p1) != n {
|
||||
t.Errorf("unexpected number of nodes in p1: n=%d, d=%d: got:%d", n, d, len(p1))
|
||||
@@ -266,11 +268,12 @@ func TestBipartitePowerLawUndirected(t *testing.T) {
|
||||
t.Errorf("unexpected overlap in partition membership: n=%d, d=%d: got:%d", n, d, len(o))
|
||||
}
|
||||
|
||||
for _, u := range nodes {
|
||||
for nodes.Next() {
|
||||
u := nodes.Node()
|
||||
uid := u.ID()
|
||||
var lines int
|
||||
for _, v := range g.From(uid) {
|
||||
lines += len(g.Lines(uid, v.ID()))
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
lines += g.Lines(uid, v.ID()).Len()
|
||||
}
|
||||
if lines < d {
|
||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||
@@ -291,8 +294,8 @@ func TestBipartitePowerLawDirected(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
if len(nodes) != 2*n {
|
||||
t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, len(nodes))
|
||||
if nodes.Len() != 2*n {
|
||||
t.Errorf("unexpected number of nodes in graph: n=%d, d=%d: got:%d", n, d, nodes.Len())
|
||||
}
|
||||
if len(p1) != n {
|
||||
t.Errorf("unexpected number of nodes in p1: n=%d, d=%d: got:%d", n, d, len(p1))
|
||||
@@ -314,11 +317,12 @@ func TestBipartitePowerLawDirected(t *testing.T) {
|
||||
t.Errorf("unexpected overlap in partition membership: n=%d, d=%d: got:%d", n, d, len(o))
|
||||
}
|
||||
|
||||
for _, u := range nodes {
|
||||
for nodes.Next() {
|
||||
u := nodes.Node()
|
||||
uid := u.ID()
|
||||
var lines int
|
||||
for _, v := range g.From(uid) {
|
||||
lines += len(g.Lines(uid, v.ID()))
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
lines += g.Lines(uid, v.ID()).Len()
|
||||
}
|
||||
if lines < d {
|
||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||
|
@@ -56,7 +56,7 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
||||
rndN = r.Intn
|
||||
}
|
||||
|
||||
nodes := dst.Nodes()
|
||||
nodes := graph.NodesOf(dst.Nodes())
|
||||
sort.Sort(ordered.ByID(nodes))
|
||||
if len(nodes) == 0 {
|
||||
n--
|
||||
@@ -76,7 +76,7 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
||||
// into the rest of the graph.
|
||||
for {
|
||||
// Add edges to parent's neighbours.
|
||||
to := dst.From(u.ID())
|
||||
to := graph.NodesOf(dst.From(u.ID()))
|
||||
sort.Sort(ordered.ByID(to))
|
||||
for _, v := range to {
|
||||
vid := v.ID()
|
||||
@@ -119,7 +119,7 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
||||
}
|
||||
}
|
||||
|
||||
if len(dst.From(did)) != 0 {
|
||||
if dst.From(did).Len() != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@@ -69,7 +69,7 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
|
||||
for i := 0; i < m; i++ {
|
||||
// Triad formation.
|
||||
if i != 0 && rnd() < p {
|
||||
for _, w := range permute(dst.From(int64(u)), rndN) {
|
||||
for _, w := range permute(graph.NodesOf(dst.From(int64(u))), rndN) {
|
||||
wid := w.ID()
|
||||
if wid == int64(v) || dst.HasEdgeBetween(wid, int64(v)) {
|
||||
continue
|
||||
|
9
graph/iterator/doc.go
Normal file
9
graph/iterator/doc.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright ©2018 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package iterator provides node, edge and line iterators.
|
||||
//
|
||||
// The iterators provided satisfy the graph.Nodes, graph.Edges and
|
||||
// graph.Lines interfaces.
|
||||
package iterator
|
131
graph/iterator/edges.go
Normal file
131
graph/iterator/edges.go
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright ©2018 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package iterator
|
||||
|
||||
import "gonum.org/v1/gonum/graph"
|
||||
|
||||
// OrderedEdges implements the graph.Edges and graph.EdgeSlicer interfaces.
|
||||
// The iteration order of OrderedEdges is the order of edges passed to
|
||||
// NewEdgeIterator.
|
||||
type OrderedEdges struct {
|
||||
idx int
|
||||
edges []graph.Edge
|
||||
}
|
||||
|
||||
// NewOrderedEdges returns an OrderedEdges initialized with the provided edges.
|
||||
func NewOrderedEdges(edges []graph.Edge) *OrderedEdges {
|
||||
return &OrderedEdges{idx: -1, edges: edges}
|
||||
}
|
||||
|
||||
// Len returns the remaining number of edges to be iterated over.
|
||||
func (e *OrderedEdges) Len() int {
|
||||
if e.idx >= len(e.edges) {
|
||||
return 0
|
||||
}
|
||||
if e.idx <= 0 {
|
||||
return len(e.edges)
|
||||
}
|
||||
return len(e.edges[e.idx:])
|
||||
}
|
||||
|
||||
// Next returns whether the next call of Edge will return a valid edge.
|
||||
func (e *OrderedEdges) Next() bool {
|
||||
if uint(e.idx)+1 < uint(len(e.edges)) {
|
||||
e.idx++
|
||||
return true
|
||||
}
|
||||
e.idx = len(e.edges)
|
||||
return false
|
||||
}
|
||||
|
||||
// Edge returns the current edge of the iterator. Next must have been
|
||||
// called prior to a call to Edge.
|
||||
func (e *OrderedEdges) Edge() graph.Edge {
|
||||
if e.idx >= len(e.edges) || e.idx < 0 {
|
||||
return nil
|
||||
}
|
||||
return e.edges[e.idx]
|
||||
}
|
||||
|
||||
// EdgeSlice returns all the remaining edges in the iterator and advances
|
||||
// the iterator.
|
||||
func (e *OrderedEdges) EdgeSlice() []graph.Edge {
|
||||
if e.idx >= len(e.edges) {
|
||||
return nil
|
||||
}
|
||||
idx := e.idx
|
||||
if idx == -1 {
|
||||
idx = 0
|
||||
}
|
||||
e.idx = len(e.edges)
|
||||
return e.edges[idx:]
|
||||
}
|
||||
|
||||
// Reset returns the iterator to its initial state.
|
||||
func (e *OrderedEdges) Reset() {
|
||||
e.idx = -1
|
||||
}
|
||||
|
||||
// OrderedWeightedEdges implements the graph.Edges and graph.EdgeSlicer interfaces.
|
||||
// The iteration order of OrderedWeightedEdges is the order of edges passed to
|
||||
// NewEdgeIterator.
|
||||
type OrderedWeightedEdges struct {
|
||||
idx int
|
||||
edges []graph.WeightedEdge
|
||||
}
|
||||
|
||||
// NewOrderedWeightedEdges returns an OrderedWeightedEdges initialized with the provided edges.
|
||||
func NewOrderedWeightedEdges(edges []graph.WeightedEdge) *OrderedWeightedEdges {
|
||||
return &OrderedWeightedEdges{idx: -1, edges: edges}
|
||||
}
|
||||
|
||||
// Len returns the remaining number of edges to be iterated over.
|
||||
func (e *OrderedWeightedEdges) Len() int {
|
||||
if e.idx >= len(e.edges) {
|
||||
return 0
|
||||
}
|
||||
if e.idx <= 0 {
|
||||
return len(e.edges)
|
||||
}
|
||||
return len(e.edges[e.idx:])
|
||||
}
|
||||
|
||||
// Next returns whether the next call of WeightedEdge will return a valid edge.
|
||||
func (e *OrderedWeightedEdges) Next() bool {
|
||||
if uint(e.idx)+1 < uint(len(e.edges)) {
|
||||
e.idx++
|
||||
return true
|
||||
}
|
||||
e.idx = len(e.edges)
|
||||
return false
|
||||
}
|
||||
|
||||
// WeightedEdge returns the current edge of the iterator. Next must have been
|
||||
// called prior to a call to WeightedEdge.
|
||||
func (e *OrderedWeightedEdges) WeightedEdge() graph.WeightedEdge {
|
||||
if e.idx >= len(e.edges) || e.idx < 0 {
|
||||
return nil
|
||||
}
|
||||
return e.edges[e.idx]
|
||||
}
|
||||
|
||||
// WeightedEdgeSlice returns all the remaining edges in the iterator and advances
|
||||
// the iterator.
|
||||
func (e *OrderedWeightedEdges) WeightedEdgeSlice() []graph.WeightedEdge {
|
||||
if e.idx >= len(e.edges) {
|
||||
return nil
|
||||
}
|
||||
idx := e.idx
|
||||
if idx == -1 {
|
||||
idx = 0
|
||||
}
|
||||
e.idx = len(e.edges)
|
||||
return e.edges[idx:]
|
||||
}
|
||||
|
||||
// Reset returns the iterator to its initial state.
|
||||
func (e *OrderedWeightedEdges) Reset() {
|
||||
e.idx = -1
|
||||
}
|
114
graph/iterator/edges_test.go
Normal file
114
graph/iterator/edges_test.go
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright ©2018 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package iterator_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/graph/simple"
|
||||
)
|
||||
|
||||
type edge struct{ f, t int }
|
||||
|
||||
func (e edge) From() graph.Node { return simple.Node(e.f) }
|
||||
func (e edge) To() graph.Node { return simple.Node(e.t) }
|
||||
|
||||
var orderedEdgesTests = []struct {
|
||||
edges []graph.Edge
|
||||
}{
|
||||
{edges: nil},
|
||||
{edges: []graph.Edge{edge{f: 1, t: 2}}},
|
||||
{edges: []graph.Edge{edge{f: 1, t: 2}, edge{f: 2, t: 3}, edge{f: 3, t: 4}, edge{f: 4, t: 5}}},
|
||||
{edges: []graph.Edge{edge{f: 5, t: 4}, edge{f: 4, t: 3}, edge{f: 3, t: 2}, edge{f: 2, t: 1}}},
|
||||
}
|
||||
|
||||
func TestOrderedEdgesIterate(t *testing.T) {
|
||||
for _, test := range orderedEdgesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedEdges(test.edges)
|
||||
if it.Len() != len(test.edges) {
|
||||
t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.edges))
|
||||
}
|
||||
var got []graph.Edge
|
||||
for it.Next() {
|
||||
got = append(got, it.Edge())
|
||||
}
|
||||
want := test.edges
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrderedEdgesSlice(t *testing.T) {
|
||||
for _, test := range orderedEdgesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedEdges(test.edges)
|
||||
got := it.EdgeSlice()
|
||||
want := test.edges
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type weightedEdge struct {
|
||||
f, t int
|
||||
w float64
|
||||
}
|
||||
|
||||
func (e weightedEdge) From() graph.Node { return simple.Node(e.f) }
|
||||
func (e weightedEdge) To() graph.Node { return simple.Node(e.t) }
|
||||
func (e weightedEdge) Weight() float64 { return e.w }
|
||||
|
||||
var orderedWeightedEdgesTests = []struct {
|
||||
edges []graph.WeightedEdge
|
||||
}{
|
||||
{edges: nil},
|
||||
{edges: []graph.WeightedEdge{weightedEdge{f: 1, t: 2, w: 1}}},
|
||||
{edges: []graph.WeightedEdge{weightedEdge{f: 1, t: 2, w: 1}, weightedEdge{f: 2, t: 3, w: 2}, weightedEdge{f: 3, t: 4, w: 3}, weightedEdge{f: 4, t: 5, w: 4}}},
|
||||
{edges: []graph.WeightedEdge{weightedEdge{f: 5, t: 4, w: 4}, weightedEdge{f: 4, t: 3, w: 3}, weightedEdge{f: 3, t: 2, w: 2}, weightedEdge{f: 2, t: 1, w: 1}}},
|
||||
}
|
||||
|
||||
func TestOrderedWeightedEdgesIterate(t *testing.T) {
|
||||
for _, test := range orderedWeightedEdgesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedWeightedEdges(test.edges)
|
||||
if it.Len() != len(test.edges) {
|
||||
t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.edges))
|
||||
}
|
||||
var got []graph.WeightedEdge
|
||||
for it.Next() {
|
||||
got = append(got, it.WeightedEdge())
|
||||
}
|
||||
want := test.edges
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrderedWeightedEdgesSlice(t *testing.T) {
|
||||
for _, test := range orderedWeightedEdgesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedWeightedEdges(test.edges)
|
||||
got := it.WeightedEdgeSlice()
|
||||
want := test.edges
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
131
graph/iterator/lines.go
Normal file
131
graph/iterator/lines.go
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright ©2018 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package iterator
|
||||
|
||||
import "gonum.org/v1/gonum/graph"
|
||||
|
||||
// OrderedLines implements the graph.Lines and graph.LineSlicer interfaces.
|
||||
// The iteration order of OrderedLines is the order of lines passed to
|
||||
// NewLineIterator.
|
||||
type OrderedLines struct {
|
||||
idx int
|
||||
lines []graph.Line
|
||||
}
|
||||
|
||||
// NewOrderedLines returns an OrderedLines initialized with the provided lines.
|
||||
func NewOrderedLines(lines []graph.Line) *OrderedLines {
|
||||
return &OrderedLines{idx: -1, lines: lines}
|
||||
}
|
||||
|
||||
// Len returns the remaining number of lines to be iterated over.
|
||||
func (e *OrderedLines) Len() int {
|
||||
if e.idx >= len(e.lines) {
|
||||
return 0
|
||||
}
|
||||
if e.idx <= 0 {
|
||||
return len(e.lines)
|
||||
}
|
||||
return len(e.lines[e.idx:])
|
||||
}
|
||||
|
||||
// Next returns whether the next call of Line will return a valid line.
|
||||
func (e *OrderedLines) Next() bool {
|
||||
if uint(e.idx)+1 < uint(len(e.lines)) {
|
||||
e.idx++
|
||||
return true
|
||||
}
|
||||
e.idx = len(e.lines)
|
||||
return false
|
||||
}
|
||||
|
||||
// Line returns the current line of the iterator. Next must have been
|
||||
// called prior to a call to Line.
|
||||
func (e *OrderedLines) Line() graph.Line {
|
||||
if e.idx >= len(e.lines) || e.idx < 0 {
|
||||
return nil
|
||||
}
|
||||
return e.lines[e.idx]
|
||||
}
|
||||
|
||||
// LineSlice returns all the remaining lines in the iterator and advances
|
||||
// the iterator.
|
||||
func (e *OrderedLines) LineSlice() []graph.Line {
|
||||
if e.idx >= len(e.lines) {
|
||||
return nil
|
||||
}
|
||||
idx := e.idx
|
||||
if idx == -1 {
|
||||
idx = 0
|
||||
}
|
||||
e.idx = len(e.lines)
|
||||
return e.lines[idx:]
|
||||
}
|
||||
|
||||
// Reset returns the iterator to its initial state.
|
||||
func (e *OrderedLines) Reset() {
|
||||
e.idx = -1
|
||||
}
|
||||
|
||||
// OrderedWeightedLines implements the graph.Lines and graph.LineSlicer interfaces.
|
||||
// The iteration order of OrderedWeightedLines is the order of lines passed to
|
||||
// NewLineIterator.
|
||||
type OrderedWeightedLines struct {
|
||||
idx int
|
||||
lines []graph.WeightedLine
|
||||
}
|
||||
|
||||
// NewWeightedLineIterator returns an OrderedWeightedLines initialized with the provided lines.
|
||||
func NewOrderedWeightedLines(lines []graph.WeightedLine) *OrderedWeightedLines {
|
||||
return &OrderedWeightedLines{idx: -1, lines: lines}
|
||||
}
|
||||
|
||||
// Len returns the remaining number of lines to be iterated over.
|
||||
func (e *OrderedWeightedLines) Len() int {
|
||||
if e.idx >= len(e.lines) {
|
||||
return 0
|
||||
}
|
||||
if e.idx <= 0 {
|
||||
return len(e.lines)
|
||||
}
|
||||
return len(e.lines[e.idx:])
|
||||
}
|
||||
|
||||
// Next returns whether the next call of WeightedLine will return a valid line.
|
||||
func (e *OrderedWeightedLines) Next() bool {
|
||||
if uint(e.idx)+1 < uint(len(e.lines)) {
|
||||
e.idx++
|
||||
return true
|
||||
}
|
||||
e.idx = len(e.lines)
|
||||
return false
|
||||
}
|
||||
|
||||
// WeightedLine returns the current line of the iterator. Next must have been
|
||||
// called prior to a call to WeightedLine.
|
||||
func (e *OrderedWeightedLines) WeightedLine() graph.WeightedLine {
|
||||
if e.idx >= len(e.lines) || e.idx < 0 {
|
||||
return nil
|
||||
}
|
||||
return e.lines[e.idx]
|
||||
}
|
||||
|
||||
// WeightedLineSlice returns all the remaining lines in the iterator and advances
|
||||
// the iterator.
|
||||
func (e *OrderedWeightedLines) WeightedLineSlice() []graph.WeightedLine {
|
||||
if e.idx >= len(e.lines) {
|
||||
return nil
|
||||
}
|
||||
idx := e.idx
|
||||
if idx == -1 {
|
||||
idx = 0
|
||||
}
|
||||
e.idx = len(e.lines)
|
||||
return e.lines[idx:]
|
||||
}
|
||||
|
||||
// Reset returns the iterator to its initial state.
|
||||
func (e *OrderedWeightedLines) Reset() {
|
||||
e.idx = -1
|
||||
}
|
116
graph/iterator/lines_test.go
Normal file
116
graph/iterator/lines_test.go
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright ©2018 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package iterator_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/graph/simple"
|
||||
)
|
||||
|
||||
type line struct{ f, t int }
|
||||
|
||||
func (l line) From() graph.Node { return simple.Node(l.f) }
|
||||
func (l line) To() graph.Node { return simple.Node(l.t) }
|
||||
func (l line) ID() int64 { return 1 }
|
||||
|
||||
var orderedLinesTests = []struct {
|
||||
lines []graph.Line
|
||||
}{
|
||||
{lines: nil},
|
||||
{lines: []graph.Line{line{f: 1, t: 2}}},
|
||||
{lines: []graph.Line{line{f: 1, t: 2}, line{f: 2, t: 3}, line{f: 3, t: 4}, line{f: 4, t: 5}}},
|
||||
{lines: []graph.Line{line{f: 5, t: 4}, line{f: 4, t: 3}, line{f: 3, t: 2}, line{f: 2, t: 1}}},
|
||||
}
|
||||
|
||||
func TestOrderedLinesIterate(t *testing.T) {
|
||||
for _, test := range orderedLinesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedLines(test.lines)
|
||||
if it.Len() != len(test.lines) {
|
||||
t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.lines))
|
||||
}
|
||||
var got []graph.Line
|
||||
for it.Next() {
|
||||
got = append(got, it.Line())
|
||||
}
|
||||
want := test.lines
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrderedLinesSlice(t *testing.T) {
|
||||
for _, test := range orderedLinesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedLines(test.lines)
|
||||
got := it.LineSlice()
|
||||
want := test.lines
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type weightedLine struct {
|
||||
f, t int
|
||||
w float64
|
||||
}
|
||||
|
||||
func (l weightedLine) From() graph.Node { return simple.Node(l.f) }
|
||||
func (l weightedLine) To() graph.Node { return simple.Node(l.t) }
|
||||
func (l weightedLine) Weight() float64 { return l.w }
|
||||
func (l weightedLine) ID() int64 { return 1 }
|
||||
|
||||
var orderedWeightedLinesTests = []struct {
|
||||
lines []graph.WeightedLine
|
||||
}{
|
||||
{lines: nil},
|
||||
{lines: []graph.WeightedLine{weightedLine{f: 1, t: 2, w: 1}}},
|
||||
{lines: []graph.WeightedLine{weightedLine{f: 1, t: 2, w: 1}, weightedLine{f: 2, t: 3, w: 2}, weightedLine{f: 3, t: 4, w: 3}, weightedLine{f: 4, t: 5, w: 4}}},
|
||||
{lines: []graph.WeightedLine{weightedLine{f: 5, t: 4, w: 4}, weightedLine{f: 4, t: 3, w: 3}, weightedLine{f: 3, t: 2, w: 2}, weightedLine{f: 2, t: 1, w: 1}}},
|
||||
}
|
||||
|
||||
func TestOrderedWeightedLinesIterate(t *testing.T) {
|
||||
for _, test := range orderedWeightedLinesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedWeightedLines(test.lines)
|
||||
if it.Len() != len(test.lines) {
|
||||
t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.lines))
|
||||
}
|
||||
var got []graph.WeightedLine
|
||||
for it.Next() {
|
||||
got = append(got, it.WeightedLine())
|
||||
}
|
||||
want := test.lines
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrderedWeightedLinesSlice(t *testing.T) {
|
||||
for _, test := range orderedWeightedLinesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedWeightedLines(test.lines)
|
||||
got := it.WeightedLineSlice()
|
||||
want := test.lines
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
115
graph/iterator/nodes.go
Normal file
115
graph/iterator/nodes.go
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright ©2018 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package iterator
|
||||
|
||||
import "gonum.org/v1/gonum/graph"
|
||||
|
||||
// OrderedNodes implements the graph.Nodes and graph.NodeSlicer interfaces.
|
||||
// The iteration order of OrderedNodes is the order of nodes passed to
|
||||
// NewNodeIterator.
|
||||
type OrderedNodes struct {
|
||||
idx int
|
||||
nodes []graph.Node
|
||||
}
|
||||
|
||||
// NewOrderedNodes returns a OrderedNodes initialized with the provided nodes.
|
||||
func NewOrderedNodes(nodes []graph.Node) *OrderedNodes {
|
||||
return &OrderedNodes{idx: -1, nodes: nodes}
|
||||
}
|
||||
|
||||
// Len returns the remaining number of nodes to be iterated over.
|
||||
func (n *OrderedNodes) Len() int {
|
||||
if n.idx >= len(n.nodes) {
|
||||
return 0
|
||||
}
|
||||
if n.idx <= 0 {
|
||||
return len(n.nodes)
|
||||
}
|
||||
return len(n.nodes[n.idx:])
|
||||
}
|
||||
|
||||
// Next returns whether the next call of Node will return a valid node.
|
||||
func (n *OrderedNodes) Next() bool {
|
||||
if uint(n.idx)+1 < uint(len(n.nodes)) {
|
||||
n.idx++
|
||||
return true
|
||||
}
|
||||
n.idx = len(n.nodes)
|
||||
return false
|
||||
}
|
||||
|
||||
// Node returns the current node of the iterator. Next must have been
|
||||
// called prior to a call to Node.
|
||||
func (n *OrderedNodes) Node() graph.Node {
|
||||
if n.idx >= len(n.nodes) || n.idx < 0 {
|
||||
return nil
|
||||
}
|
||||
return n.nodes[n.idx]
|
||||
}
|
||||
|
||||
// NodeSlice returns all the remaining nodes in the iterator and advances
|
||||
// the iterator.
|
||||
func (n *OrderedNodes) NodeSlice() []graph.Node {
|
||||
if n.idx >= len(n.nodes) {
|
||||
return nil
|
||||
}
|
||||
idx := n.idx
|
||||
if idx == -1 {
|
||||
idx = 0
|
||||
}
|
||||
n.idx = len(n.nodes)
|
||||
return n.nodes[idx:]
|
||||
}
|
||||
|
||||
// Reset returns the iterator to its initial state.
|
||||
func (n *OrderedNodes) Reset() {
|
||||
n.idx = -1
|
||||
}
|
||||
|
||||
// ImplicitNodes implements the graph.Nodes interface for a set of nodes over
|
||||
// a contiguous ID range.
|
||||
type ImplicitNodes struct {
|
||||
beg, end int
|
||||
curr int
|
||||
newNode func(id int) graph.Node
|
||||
}
|
||||
|
||||
// NewImplicitNodes returns a new implicit node iterator spanning nodes in [beg,end).
|
||||
// The provided new func maps the id to a graph.Node. NewImplicitNodes will panic
|
||||
// if beg is greater than end.
|
||||
func NewImplicitNodes(beg, end int, new func(id int) graph.Node) *ImplicitNodes {
|
||||
if beg > end {
|
||||
panic("iterator: invalid range")
|
||||
}
|
||||
return &ImplicitNodes{beg: beg, end: end, curr: beg - 1, newNode: new}
|
||||
}
|
||||
|
||||
// Len returns the remaining number of nodes to be iterated over.
|
||||
func (n *ImplicitNodes) Len() int {
|
||||
return n.end - n.curr - 1
|
||||
}
|
||||
|
||||
// Next returns whether the next call of Node will return a valid node.
|
||||
func (n *ImplicitNodes) Next() bool {
|
||||
if n.curr == n.end {
|
||||
return false
|
||||
}
|
||||
n.curr++
|
||||
return n.curr < n.end
|
||||
}
|
||||
|
||||
// Node returns the current node of the iterator. Next must have been
|
||||
// called prior to a call to Node.
|
||||
func (n *ImplicitNodes) Node() graph.Node {
|
||||
if n.Len() == -1 || n.curr < n.beg {
|
||||
return nil
|
||||
}
|
||||
return n.newNode(n.curr)
|
||||
}
|
||||
|
||||
// Reset returns the iterator to its initial state.
|
||||
func (n *ImplicitNodes) Reset() {
|
||||
n.curr = n.beg - 1
|
||||
}
|
99
graph/iterator/nodes_test.go
Normal file
99
graph/iterator/nodes_test.go
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright ©2018 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package iterator_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/graph/simple"
|
||||
)
|
||||
|
||||
var orderedNodesTests = []struct {
|
||||
nodes []graph.Node
|
||||
}{
|
||||
{nodes: nil},
|
||||
{nodes: []graph.Node{simple.Node(1)}},
|
||||
{nodes: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(5)}},
|
||||
{nodes: []graph.Node{simple.Node(5), simple.Node(3), simple.Node(2), simple.Node(1)}},
|
||||
}
|
||||
|
||||
func TestOrderedNodesIterate(t *testing.T) {
|
||||
for _, test := range orderedNodesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedNodes(test.nodes)
|
||||
if it.Len() != len(test.nodes) {
|
||||
t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.nodes))
|
||||
}
|
||||
var got []graph.Node
|
||||
for it.Next() {
|
||||
got = append(got, it.Node())
|
||||
}
|
||||
want := test.nodes
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrderedNodesSlice(t *testing.T) {
|
||||
for _, test := range orderedNodesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewOrderedNodes(test.nodes)
|
||||
got := it.NodeSlice()
|
||||
want := test.nodes
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var implicitNodesTests = []struct {
|
||||
beg, end int
|
||||
new func(int) graph.Node
|
||||
want []graph.Node
|
||||
}{
|
||||
{
|
||||
beg: 1, end: 1,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
beg: 1, end: 2,
|
||||
new: newSimpleNode,
|
||||
want: []graph.Node{simple.Node(1)},
|
||||
},
|
||||
{
|
||||
beg: 1, end: 5,
|
||||
new: newSimpleNode,
|
||||
want: []graph.Node{simple.Node(1), simple.Node(2), simple.Node(3), simple.Node(4)},
|
||||
},
|
||||
}
|
||||
|
||||
func newSimpleNode(id int) graph.Node { return simple.Node(id) }
|
||||
|
||||
func TestImplicitNodesIterate(t *testing.T) {
|
||||
for _, test := range implicitNodesTests {
|
||||
for i := 0; i < 2; i++ {
|
||||
it := iterator.NewImplicitNodes(test.beg, test.end, test.new)
|
||||
if it.Len() != len(test.want) {
|
||||
t.Errorf("unexpected iterator length for round %d: got:%d want:%d", i, it.Len(), len(test.want))
|
||||
}
|
||||
var got []graph.Node
|
||||
for it.Next() {
|
||||
got = append(got, it.Node())
|
||||
}
|
||||
if !reflect.DeepEqual(got, test.want) {
|
||||
t.Errorf("unexpected iterator output for round %d: got:%#v want:%#v", i, got, test.want)
|
||||
}
|
||||
it.Reset()
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/uid"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -154,7 +155,7 @@ func (g *DirectedGraph) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *DirectedGraph) Nodes() []graph.Node {
|
||||
func (g *DirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -164,12 +165,12 @@ func (g *DirectedGraph) Nodes() []graph.Node {
|
||||
nodes[i] = n
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph. Each edge in the returned slice
|
||||
// is a multi.Edge.
|
||||
func (g *DirectedGraph) Edges() []graph.Edge {
|
||||
func (g *DirectedGraph) Edges() graph.Edges {
|
||||
var edges []graph.Edge
|
||||
for _, u := range g.nodes {
|
||||
for _, e := range g.from[u.ID()] {
|
||||
@@ -182,11 +183,11 @@ func (g *DirectedGraph) Edges() []graph.Edge {
|
||||
}
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *DirectedGraph) From(id int64) []graph.Node {
|
||||
func (g *DirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -197,11 +198,11 @@ func (g *DirectedGraph) From(id int64) []graph.Node {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
return from
|
||||
return iterator.NewOrderedNodes(from)
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *DirectedGraph) To(id int64) []graph.Node {
|
||||
func (g *DirectedGraph) To(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -212,7 +213,7 @@ func (g *DirectedGraph) To(id int64) []graph.Node {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
return to
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
@@ -229,7 +230,7 @@ func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.Edge is a multi.Edge if an edge exists.
|
||||
func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
lines := g.Lines(uid, vid)
|
||||
lines := graph.LinesOf(g.Lines(uid, vid))
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -238,7 +239,7 @@ func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
|
||||
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *DirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
func (g *DirectedGraph) Lines(uid, vid int64) graph.Lines {
|
||||
edge := g.from[uid][vid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
@@ -247,7 +248,7 @@ func (g *DirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
for _, l := range edge {
|
||||
lines = append(lines, l)
|
||||
}
|
||||
return lines
|
||||
return iterator.NewOrderedLines(lines)
|
||||
}
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||
@@ -255,18 +256,3 @@ func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||
_, ok := g.from[uid][vid]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *DirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
for _, e := range g.from[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
for _, e := range g.to[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
return deg
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ var (
|
||||
func TestEdgeOvercounting(t *testing.T) {
|
||||
g := generateDummyGraph()
|
||||
|
||||
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||
if neigh := graph.NodesOf(g.From(int64(2))); len(neigh) != 2 {
|
||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/uid"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -143,7 +144,7 @@ func (g *UndirectedGraph) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *UndirectedGraph) Nodes() []graph.Node {
|
||||
func (g *UndirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -153,12 +154,12 @@ func (g *UndirectedGraph) Nodes() []graph.Node {
|
||||
nodes[i] = n
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph. Each edge in the returned slice
|
||||
// is a multi.Edge.
|
||||
func (g *UndirectedGraph) Edges() []graph.Edge {
|
||||
func (g *UndirectedGraph) Edges() graph.Edges {
|
||||
if len(g.lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -180,11 +181,11 @@ func (g *UndirectedGraph) Edges() []graph.Edge {
|
||||
}
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *UndirectedGraph) From(id int64) []graph.Node {
|
||||
func (g *UndirectedGraph) From(id int64) graph.Nodes {
|
||||
if !g.Has(id) {
|
||||
return nil
|
||||
}
|
||||
@@ -195,7 +196,7 @@ func (g *UndirectedGraph) From(id int64) []graph.Node {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -213,7 +214,7 @@ func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.Edge is a multi.Edge if an edge exists.
|
||||
func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
lines := g.LinesBetween(uid, vid)
|
||||
lines := graph.LinesOf(g.LinesBetween(uid, vid))
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -222,27 +223,15 @@ func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
|
||||
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *UndirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
func (g *UndirectedGraph) Lines(uid, vid int64) graph.Lines {
|
||||
return g.LinesBetween(uid, vid)
|
||||
}
|
||||
|
||||
// LinesBetween returns the lines between nodes x and y.
|
||||
func (g *UndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
|
||||
func (g *UndirectedGraph) LinesBetween(xid, yid int64) graph.Lines {
|
||||
var lines []graph.Line
|
||||
for _, l := range g.lines[xid][yid] {
|
||||
lines = append(lines, l)
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *UndirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
for _, e := range g.lines[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
return deg
|
||||
return iterator.NewOrderedLines(lines)
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/uid"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -160,7 +161,7 @@ func (g *WeightedDirectedGraph) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *WeightedDirectedGraph) Nodes() []graph.Node {
|
||||
func (g *WeightedDirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -171,12 +172,12 @@ func (g *WeightedDirectedGraph) Nodes() []graph.Node {
|
||||
i++
|
||||
}
|
||||
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph. Each edge in the returned slice
|
||||
// is a multi.WeightedEdge.
|
||||
func (g *WeightedDirectedGraph) Edges() []graph.Edge {
|
||||
func (g *WeightedDirectedGraph) Edges() graph.Edges {
|
||||
var edges []graph.Edge
|
||||
for _, u := range g.nodes {
|
||||
for _, e := range g.from[u.ID()] {
|
||||
@@ -190,12 +191,12 @@ func (g *WeightedDirectedGraph) Edges() []graph.Edge {
|
||||
}
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// WeightedEdges returns all the edges in the graph. Each edge in the returned slice
|
||||
// is a multi.WeightedEdge.
|
||||
func (g *WeightedDirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
||||
func (g *WeightedDirectedGraph) WeightedEdges() graph.WeightedEdges {
|
||||
var edges []graph.WeightedEdge
|
||||
for _, u := range g.nodes {
|
||||
for _, e := range g.from[u.ID()] {
|
||||
@@ -209,11 +210,11 @@ func (g *WeightedDirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
||||
}
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedWeightedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
|
||||
func (g *WeightedDirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -224,11 +225,11 @@ func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
return from
|
||||
return iterator.NewOrderedNodes(from)
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
|
||||
func (g *WeightedDirectedGraph) To(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -239,7 +240,7 @@ func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
return to
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
@@ -271,7 +272,7 @@ func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
|
||||
func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
lines := g.WeightedLines(uid, vid)
|
||||
lines := graph.WeightedLinesOf(g.WeightedLines(uid, vid))
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -280,7 +281,7 @@ func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge
|
||||
|
||||
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedDirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
func (g *WeightedDirectedGraph) Lines(uid, vid int64) graph.Lines {
|
||||
edge := g.from[uid][vid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
@@ -289,12 +290,12 @@ func (g *WeightedDirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
for _, l := range edge {
|
||||
lines = append(lines, l)
|
||||
}
|
||||
return lines
|
||||
return iterator.NewOrderedLines(lines)
|
||||
}
|
||||
|
||||
// WeightedLines returns the weighted lines from u to v if such any such lines exists
|
||||
// and nil otherwise. The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedDirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
|
||||
func (g *WeightedDirectedGraph) WeightedLines(uid, vid int64) graph.WeightedLines {
|
||||
edge := g.from[uid][vid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
@@ -303,27 +304,12 @@ func (g *WeightedDirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLi
|
||||
for _, l := range edge {
|
||||
lines = append(lines, l)
|
||||
}
|
||||
return lines
|
||||
return iterator.NewOrderedWeightedLines(lines)
|
||||
}
|
||||
|
||||
// Weight returns the weight for the lines between x and y summarised by the receiver's
|
||||
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
|
||||
func (g *WeightedDirectedGraph) Weight(uid, vid int64) (w float64, ok bool) {
|
||||
lines := g.WeightedLines(uid, vid)
|
||||
lines := graph.WeightedLinesOf(g.WeightedLines(uid, vid))
|
||||
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *WeightedDirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
for _, e := range g.from[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
for _, e := range g.to[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
return deg
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ var (
|
||||
func TestWeightedEdgeOvercounting(t *testing.T) {
|
||||
g := generateDummyWeightedGraph()
|
||||
|
||||
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||
if neigh := graph.NodesOf(g.From(int64(2))); len(neigh) != 2 {
|
||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/uid"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -147,7 +148,7 @@ func (g *WeightedUndirectedGraph) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *WeightedUndirectedGraph) Nodes() []graph.Node {
|
||||
func (g *WeightedUndirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -157,12 +158,12 @@ func (g *WeightedUndirectedGraph) Nodes() []graph.Node {
|
||||
nodes[i] = n
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph. Each edge in the returned slice
|
||||
// is a multi.Edge.
|
||||
func (g *WeightedUndirectedGraph) Edges() []graph.Edge {
|
||||
func (g *WeightedUndirectedGraph) Edges() graph.Edges {
|
||||
if len(g.lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -184,11 +185,11 @@ func (g *WeightedUndirectedGraph) Edges() []graph.Edge {
|
||||
}
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
|
||||
func (g *WeightedUndirectedGraph) From(id int64) graph.Nodes {
|
||||
if !g.Has(id) {
|
||||
return nil
|
||||
}
|
||||
@@ -199,7 +200,7 @@ func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -210,12 +211,12 @@ func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
|
||||
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedUndirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
func (g *WeightedUndirectedGraph) Lines(uid, vid int64) graph.Lines {
|
||||
return g.LinesBetween(uid, vid)
|
||||
}
|
||||
|
||||
// LinesBetween returns the lines between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
|
||||
func (g *WeightedUndirectedGraph) LinesBetween(xid, yid int64) graph.Lines {
|
||||
edge := g.lines[xid][yid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
@@ -230,7 +231,7 @@ func (g *WeightedUndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
|
||||
seen[lid] = struct{}{}
|
||||
lines = append(lines, l)
|
||||
}
|
||||
return lines
|
||||
return iterator.NewOrderedLines(lines)
|
||||
}
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
@@ -249,7 +250,7 @@ func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
|
||||
func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
lines := g.WeightedLines(uid, vid)
|
||||
lines := graph.WeightedLinesOf(g.WeightedLines(uid, vid))
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -263,12 +264,12 @@ func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.Weig
|
||||
|
||||
// WeightedLines returns the lines from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedUndirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
|
||||
func (g *WeightedUndirectedGraph) WeightedLines(uid, vid int64) graph.WeightedLines {
|
||||
return g.WeightedLinesBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedLinesBetween returns the lines between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) WeightedLinesBetween(xid, yid int64) []graph.WeightedLine {
|
||||
func (g *WeightedUndirectedGraph) WeightedLinesBetween(xid, yid int64) graph.WeightedLines {
|
||||
edge := g.lines[xid][yid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
@@ -283,24 +284,12 @@ func (g *WeightedUndirectedGraph) WeightedLinesBetween(xid, yid int64) []graph.W
|
||||
seen[lid] = struct{}{}
|
||||
lines = append(lines, l)
|
||||
}
|
||||
return lines
|
||||
return iterator.NewOrderedWeightedLines(lines)
|
||||
}
|
||||
|
||||
// Weight returns the weight for the lines between x and y summarised by the receiver's
|
||||
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
|
||||
func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
lines := g.WeightedLines(xid, yid)
|
||||
lines := graph.WeightedLinesOf(g.WeightedLines(xid, yid))
|
||||
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *WeightedUndirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
for _, e := range g.lines[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
return deg
|
||||
}
|
||||
|
@@ -24,11 +24,11 @@ type Multigraph interface {
|
||||
Has(id int64) bool
|
||||
|
||||
// Nodes returns all the nodes in the multigraph.
|
||||
Nodes() []Node
|
||||
Nodes() Nodes
|
||||
|
||||
// From returns all nodes that can be reached directly
|
||||
// from the node with the given ID.
|
||||
From(id int64) []Node
|
||||
From(id int64) Nodes
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between
|
||||
// nodes with IDs xid and yid without considering direction.
|
||||
@@ -38,7 +38,7 @@ 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(uid, vid int64) []Line
|
||||
Lines(uid, vid int64) Lines
|
||||
}
|
||||
|
||||
// WeightedMultigraph is a weighted multigraph.
|
||||
@@ -49,7 +49,7 @@ 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(uid, vid int64) []WeightedLine
|
||||
WeightedLines(uid, vid int64) WeightedLines
|
||||
}
|
||||
|
||||
// UndirectedMultigraph is an undirected multigraph.
|
||||
@@ -58,7 +58,7 @@ type UndirectedMultigraph interface {
|
||||
|
||||
// LinesBetween returns the lines between nodes x and y
|
||||
// with IDs xid and yid.
|
||||
LinesBetween(xid, yid int64) []Line
|
||||
LinesBetween(xid, yid int64) Lines
|
||||
}
|
||||
|
||||
// WeightedUndirectedMultigraph is a weighted undirected multigraph.
|
||||
@@ -67,7 +67,7 @@ type WeightedUndirectedMultigraph interface {
|
||||
|
||||
// WeightedLinesBetween returns the lines between nodes
|
||||
// x and y with IDs xid and yid.
|
||||
WeightedLinesBetween(xid, yid int64) []WeightedLine
|
||||
WeightedLinesBetween(xid, yid int64) WeightedLines
|
||||
}
|
||||
|
||||
// DirectedMultigraph is a directed multigraph.
|
||||
@@ -81,7 +81,7 @@ type DirectedMultigraph interface {
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the node with the given ID.
|
||||
To(id int64) []Node
|
||||
To(id int64) Nodes
|
||||
}
|
||||
|
||||
// WeightedDirectedMultigraph is a weighted directed multigraph.
|
||||
@@ -95,7 +95,7 @@ type WeightedDirectedMultigraph interface {
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the node with the given ID.
|
||||
To(id int64) []Node
|
||||
To(id int64) Nodes
|
||||
}
|
||||
|
||||
// LineAdder is an interface for adding lines to a multigraph.
|
||||
|
@@ -90,7 +90,7 @@ func EdgeBetweenness(g graph.Graph) map[[2]int64]float64 {
|
||||
// the accumulation loop provided by the accumulate closure.
|
||||
func brandes(g graph.Graph, accumulate func(s graph.Node, stack linear.NodeStack, p map[int64][]graph.Node, delta, sigma map[int64]float64)) {
|
||||
var (
|
||||
nodes = g.Nodes()
|
||||
nodes = graph.NodesOf(g.Nodes())
|
||||
stack linear.NodeStack
|
||||
p = make(map[int64][]graph.Node, len(nodes))
|
||||
sigma = make(map[int64]float64, len(nodes))
|
||||
@@ -117,7 +117,7 @@ func brandes(g graph.Graph, accumulate func(s graph.Node, stack linear.NodeStack
|
||||
v := queue.Dequeue()
|
||||
vid := v.ID()
|
||||
stack.Push(v)
|
||||
for _, w := range g.From(vid) {
|
||||
for _, w := range graph.NodesOf(g.From(vid)) {
|
||||
wid := w.ID()
|
||||
// w found for the first time?
|
||||
if d[wid] < 0 {
|
||||
@@ -151,7 +151,7 @@ func brandes(g graph.Graph, accumulate func(s graph.Node, stack linear.NodeStack
|
||||
func BetweennessWeighted(g graph.Weighted, p path.AllShortest) map[int64]float64 {
|
||||
cb := make(map[int64]float64)
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
for i, s := range nodes {
|
||||
sid := s.ID()
|
||||
for j, t := range nodes {
|
||||
@@ -205,7 +205,7 @@ func EdgeBetweennessWeighted(g graph.Weighted, p path.AllShortest) map[[2]int64]
|
||||
cb := make(map[[2]int64]float64)
|
||||
|
||||
_, isUndirected := g.(graph.Undirected)
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
for i, s := range nodes {
|
||||
sid := s.ID()
|
||||
for j, t := range nodes {
|
||||
|
@@ -113,7 +113,7 @@ type Laplacian struct {
|
||||
// degree of each node and A is the graph adjacency matrix of the input graph.
|
||||
// If g contains self edges, NewLaplacian will panic.
|
||||
func NewLaplacian(g graph.Undirected) Laplacian {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
indexOf := make(map[int64]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
id := n.ID()
|
||||
@@ -123,7 +123,7 @@ func NewLaplacian(g graph.Undirected) Laplacian {
|
||||
l := mat.NewSymDense(len(nodes), nil)
|
||||
for j, u := range nodes {
|
||||
uid := u.ID()
|
||||
to := g.From(uid)
|
||||
to := graph.NodesOf(g.From(uid))
|
||||
l.SetSym(j, j, float64(len(to)))
|
||||
for _, v := range to {
|
||||
vid := v.ID()
|
||||
@@ -146,7 +146,7 @@ func NewLaplacian(g graph.Undirected) Laplacian {
|
||||
// matrix of the input graph.
|
||||
// If g contains self edges, NewSymNormLaplacian will panic.
|
||||
func NewSymNormLaplacian(g graph.Undirected) Laplacian {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
indexOf := make(map[int64]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
id := n.ID()
|
||||
@@ -156,7 +156,7 @@ func NewSymNormLaplacian(g graph.Undirected) Laplacian {
|
||||
l := mat.NewSymDense(len(nodes), nil)
|
||||
for j, u := range nodes {
|
||||
uid := u.ID()
|
||||
to := g.From(uid)
|
||||
to := graph.NodesOf(g.From(uid))
|
||||
if len(to) == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -168,7 +168,7 @@ func NewSymNormLaplacian(g graph.Undirected) Laplacian {
|
||||
panic("network: self edge in graph")
|
||||
}
|
||||
if uid < vid {
|
||||
l.SetSym(indexOf[vid], j, -1/(squdeg*math.Sqrt(float64(len(g.From(vid))))))
|
||||
l.SetSym(indexOf[vid], j, -1/(squdeg*math.Sqrt(float64(g.From(vid).Len()))))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,7 +183,7 @@ func NewSymNormLaplacian(g graph.Undirected) Laplacian {
|
||||
// graph.
|
||||
// If g contains self edges, NewRandomWalkLaplacian will panic.
|
||||
func NewRandomWalkLaplacian(g graph.Graph, damp float64) Laplacian {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
indexOf := make(map[int64]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
id := n.ID()
|
||||
@@ -193,7 +193,7 @@ func NewRandomWalkLaplacian(g graph.Graph, damp float64) Laplacian {
|
||||
l := mat.NewDense(len(nodes), len(nodes), nil)
|
||||
for j, u := range nodes {
|
||||
uid := u.ID()
|
||||
to := g.From(uid)
|
||||
to := graph.NodesOf(g.From(uid))
|
||||
if len(to) == 0 {
|
||||
continue
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"gonum.org/v1/gonum/floats"
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/graph/simple"
|
||||
"gonum.org/v1/gonum/mat"
|
||||
)
|
||||
@@ -304,10 +305,10 @@ type sortedNodeGraph struct {
|
||||
graph.Graph
|
||||
}
|
||||
|
||||
func (g sortedNodeGraph) Nodes() []graph.Node {
|
||||
n := g.Graph.Nodes()
|
||||
func (g sortedNodeGraph) Nodes() graph.Nodes {
|
||||
n := graph.NodesOf(g.Graph.Nodes())
|
||||
sort.Sort(ordered.ByID(n))
|
||||
return n
|
||||
return iterator.NewOrderedNodes(n)
|
||||
}
|
||||
|
||||
var diffuseToEquilibriumTests = []struct {
|
||||
|
@@ -19,7 +19,7 @@ import (
|
||||
// For directed graphs the incoming paths are used. Infinite distances are
|
||||
// not considered.
|
||||
func Closeness(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
c := make(map[int64]float64, len(nodes))
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
@@ -48,7 +48,7 @@ func Closeness(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
// For directed graphs the incoming paths are used. Infinite distances are
|
||||
// not considered.
|
||||
func Farness(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
f := make(map[int64]float64, len(nodes))
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
@@ -77,7 +77,7 @@ func Farness(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
// For directed graphs the incoming paths are used. Infinite distances are
|
||||
// not considered.
|
||||
func Harmonic(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
h := make(map[int64]float64, len(nodes))
|
||||
for i, u := range nodes {
|
||||
uid := u.ID()
|
||||
@@ -108,7 +108,7 @@ func Harmonic(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
// For directed graphs the incoming paths are used. Infinite distances are
|
||||
// not considered.
|
||||
func Residual(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
r := make(map[int64]float64, len(nodes))
|
||||
for i, u := range nodes {
|
||||
uid := u.ID()
|
||||
|
@@ -22,7 +22,7 @@ type HubAuthority struct {
|
||||
// vector difference between iterations is below tol. The returned map is
|
||||
// keyed on the graph node IDs.
|
||||
func HITS(g graph.Directed, tol float64) map[int64]HubAuthority {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
|
||||
// Make a topological copy of g with dense node IDs.
|
||||
indexOf := make(map[int64]int, len(nodes))
|
||||
@@ -33,10 +33,10 @@ func HITS(g graph.Directed, tol float64) map[int64]HubAuthority {
|
||||
nodesLinkedFrom := make([][]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
id := n.ID()
|
||||
for _, u := range g.To(id) {
|
||||
for _, u := range graph.NodesOf(g.To(id)) {
|
||||
nodesLinkingTo[i] = append(nodesLinkingTo[i], indexOf[u.ID()])
|
||||
}
|
||||
for _, v := range g.From(id) {
|
||||
for _, v := range graph.NodesOf(g.From(id)) {
|
||||
nodesLinkedFrom[i] = append(nodesLinkedFrom[i], indexOf[v.ID()])
|
||||
}
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ func edgeWeightedPageRank(g graph.WeightedDirected, damp, tol float64) map[int64
|
||||
//
|
||||
// http://www.ams.org/samplings/feature-column/fcarc-pagerank
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
indexOf := make(map[int64]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
indexOf[n.ID()] = i
|
||||
@@ -60,7 +60,7 @@ func edgeWeightedPageRank(g graph.WeightedDirected, damp, tol float64) map[int64
|
||||
m := mat.NewDense(len(nodes), len(nodes), nil)
|
||||
dangling := damp / float64(len(nodes))
|
||||
for j, u := range nodes {
|
||||
to := g.From(u.ID())
|
||||
to := graph.NodesOf(g.From(u.ID()))
|
||||
var z float64
|
||||
for _, v := range to {
|
||||
if w, ok := g.Weight(u.ID(), v.ID()); ok {
|
||||
@@ -134,7 +134,7 @@ func edgeWeightedPageRankSparse(g graph.WeightedDirected, damp, tol float64) map
|
||||
//
|
||||
// http://www.ams.org/samplings/feature-column/fcarc-pagerank
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
indexOf := make(map[int64]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
indexOf[n.ID()] = i
|
||||
@@ -144,7 +144,7 @@ func edgeWeightedPageRankSparse(g graph.WeightedDirected, damp, tol float64) map
|
||||
var dangling compressedRow
|
||||
df := damp / float64(len(nodes))
|
||||
for j, u := range nodes {
|
||||
to := g.From(u.ID())
|
||||
to := graph.NodesOf(g.From(u.ID()))
|
||||
var z float64
|
||||
for _, v := range to {
|
||||
if w, ok := g.Weight(u.ID(), v.ID()); ok {
|
||||
@@ -215,7 +215,7 @@ func pageRank(g graph.Directed, damp, tol float64) map[int64]float64 {
|
||||
//
|
||||
// http://www.ams.org/samplings/feature-column/fcarc-pagerank
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
indexOf := make(map[int64]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
indexOf[n.ID()] = i
|
||||
@@ -224,7 +224,7 @@ func pageRank(g graph.Directed, damp, tol float64) map[int64]float64 {
|
||||
m := mat.NewDense(len(nodes), len(nodes), nil)
|
||||
dangling := damp / float64(len(nodes))
|
||||
for j, u := range nodes {
|
||||
to := g.From(u.ID())
|
||||
to := graph.NodesOf(g.From(u.ID()))
|
||||
f := damp / float64(len(to))
|
||||
for _, v := range to {
|
||||
m.Set(indexOf[v.ID()], j, f)
|
||||
@@ -288,7 +288,7 @@ func pageRankSparse(g graph.Directed, damp, tol float64) map[int64]float64 {
|
||||
//
|
||||
// http://www.ams.org/samplings/feature-column/fcarc-pagerank
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
indexOf := make(map[int64]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
indexOf[n.ID()] = i
|
||||
@@ -298,7 +298,7 @@ func pageRankSparse(g graph.Directed, damp, tol float64) map[int64]float64 {
|
||||
var dangling compressedRow
|
||||
df := damp / float64(len(nodes))
|
||||
for j, u := range nodes {
|
||||
to := g.From(u.ID())
|
||||
to := graph.NodesOf(g.From(u.ID()))
|
||||
f := damp / float64(len(to))
|
||||
for _, v := range to {
|
||||
m.addTo(indexOf[v.ID()], j, f)
|
||||
|
209
graph/nodes_edges.go
Normal file
209
graph/nodes_edges.go
Normal file
@@ -0,0 +1,209 @@
|
||||
// Copyright ©2018 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package graph
|
||||
|
||||
// Iterator is an item iterator.
|
||||
type Iterator interface {
|
||||
// Next advances the iterator and returns whether
|
||||
// the next call to the item method will return a
|
||||
// non-nil item.
|
||||
//
|
||||
// Next should be called prior to any call to the
|
||||
// iterator's item retrieval method after the
|
||||
// iterator has been obtained or reset.
|
||||
//
|
||||
// The order of iteration is implementation
|
||||
// dependent.
|
||||
Next() bool
|
||||
|
||||
// Len returns the number of items remaining in the
|
||||
// iterator.
|
||||
Len() int
|
||||
|
||||
// Reset returns the iterator to its start position.
|
||||
Reset()
|
||||
}
|
||||
|
||||
// Nodes is a Node iterator.
|
||||
type Nodes interface {
|
||||
Iterator
|
||||
|
||||
// Node returns the current Node from the iterator.
|
||||
Node() Node
|
||||
}
|
||||
|
||||
// NodeSlicer wraps the NodeSlice method.
|
||||
type NodeSlicer interface {
|
||||
// NodeSlice returns the set of nodes remaining
|
||||
// to be iterated by a Nodes iterator.
|
||||
// The holder of the iterator may arbitrarily
|
||||
// change elements in the returned slice, but
|
||||
// those changes may be reflected to other
|
||||
// iterators.
|
||||
NodeSlice() []Node
|
||||
}
|
||||
|
||||
// NodesOf returns it.Len() nodes from it. If it is a NodeSlicer, the NodeSlice method
|
||||
// is used to obtain the nodes. It is safe to pass a nil Nodes to NodesOf.
|
||||
func NodesOf(it Nodes) []Node {
|
||||
if it == nil {
|
||||
return nil
|
||||
}
|
||||
switch it := it.(type) {
|
||||
case NodeSlicer:
|
||||
return it.NodeSlice()
|
||||
}
|
||||
n := make([]Node, 0, it.Len())
|
||||
for it.Next() {
|
||||
n = append(n, it.Node())
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Edges is an Edge iterator.
|
||||
type Edges interface {
|
||||
Iterator
|
||||
|
||||
// Edge returns the current Edge from the iterator.
|
||||
Edge() Edge
|
||||
}
|
||||
|
||||
// EdgeSlicer wraps the EdgeSlice method.
|
||||
type EdgeSlicer interface {
|
||||
// EdgeSlice returns the set of edges remaining
|
||||
// to be iterated by an Edges iterator.
|
||||
// The holder of the iterator may arbitrarily
|
||||
// change elements in the returned slice, but
|
||||
// those changes may be reflected to other
|
||||
// iterators.
|
||||
EdgeSlice() []Edge
|
||||
}
|
||||
|
||||
// EdgesOf returns it.Len() nodes from it. If it is an EdgeSlicer, the EdgeSlice method is used
|
||||
// to obtain the edges. It is safe to pass a nil Edges to EdgesOf.
|
||||
func EdgesOf(it Edges) []Edge {
|
||||
if it == nil {
|
||||
return nil
|
||||
}
|
||||
switch it := it.(type) {
|
||||
case EdgeSlicer:
|
||||
return it.EdgeSlice()
|
||||
}
|
||||
n := make([]Edge, 0, it.Len())
|
||||
for it.Next() {
|
||||
n = append(n, it.Edge())
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// WeightedEdges is a WeightedEdge iterator.
|
||||
type WeightedEdges interface {
|
||||
Iterator
|
||||
|
||||
// Edge returns the current Edge from the iterator.
|
||||
WeightedEdge() WeightedEdge
|
||||
}
|
||||
|
||||
// WeightedEdgeSlicer wraps the WeightedEdgeSlice method.
|
||||
type WeightedEdgeSlicer interface {
|
||||
// EdgeSlice returns the set of edges remaining
|
||||
// to be iterated by an Edges iterator.
|
||||
// The holder of the iterator may arbitrarily
|
||||
// change elements in the returned slice, but
|
||||
// those changes may be reflected to other
|
||||
// iterators.
|
||||
WeightedEdgeSlice() []WeightedEdge
|
||||
}
|
||||
|
||||
// WeightedEdgesOf returns it.Len() weighted edge from it. If it is a WeightedEdgeSlicer, the
|
||||
// WeightedEdgeSlice method is used to obtain the edges. It is safe to pass a nil WeightedEdges
|
||||
// to WeightedEdgesOf.
|
||||
func WeightedEdgesOf(it WeightedEdges) []WeightedEdge {
|
||||
if it == nil {
|
||||
return nil
|
||||
}
|
||||
switch it := it.(type) {
|
||||
case WeightedEdgeSlicer:
|
||||
return it.WeightedEdgeSlice()
|
||||
}
|
||||
n := make([]WeightedEdge, 0, it.Len())
|
||||
for it.Next() {
|
||||
n = append(n, it.WeightedEdge())
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Lines is a Line iterator.
|
||||
type Lines interface {
|
||||
Iterator
|
||||
|
||||
// Line returns the current Line from the iterator.
|
||||
Line() Line
|
||||
}
|
||||
|
||||
// LineSlicer wraps the LineSlice method.
|
||||
type LineSlicer interface {
|
||||
// LineSlice returns the set of lines remaining
|
||||
// to be iterated by an Lines iterator.
|
||||
// The holder of the iterator may arbitrarily
|
||||
// change elements in the returned slice, but
|
||||
// those changes may be reflected to other
|
||||
// iterators.
|
||||
LineSlice() []Line
|
||||
}
|
||||
|
||||
// LinesOf returns it.Len() nodes from it. If it is a LineSlicer, the LineSlice method is used
|
||||
// to obtain the lines. It is safe to pass a nil Lines to LinesOf.
|
||||
func LinesOf(it Lines) []Line {
|
||||
if it == nil {
|
||||
return nil
|
||||
}
|
||||
switch it := it.(type) {
|
||||
case LineSlicer:
|
||||
return it.LineSlice()
|
||||
}
|
||||
n := make([]Line, 0, it.Len())
|
||||
for it.Next() {
|
||||
n = append(n, it.Line())
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// WeightedLines is a WeightedLine iterator.
|
||||
type WeightedLines interface {
|
||||
Iterator
|
||||
|
||||
// Line returns the current Line from the iterator.
|
||||
WeightedLine() WeightedLine
|
||||
}
|
||||
|
||||
// WeightedLineSlicer wraps the WeightedLineSlice method.
|
||||
type WeightedLineSlicer interface {
|
||||
// LineSlice returns the set of lines remaining
|
||||
// to be iterated by an Lines iterator.
|
||||
// The holder of the iterator may arbitrarily
|
||||
// change elements in the returned slice, but
|
||||
// those changes may be reflected to other
|
||||
// iterators.
|
||||
WeightedLineSlice() []WeightedLine
|
||||
}
|
||||
|
||||
// WeightedLinesOf returns it.Len() weighted line from it. If it is a WeightedLineSlicer, the
|
||||
// WeightedLineSlice method is used to obtain the lines. It is safe to pass a nil WeightedLines
|
||||
// to WeightedLinesOf.
|
||||
func WeightedLinesOf(it WeightedLines) []WeightedLine {
|
||||
if it == nil {
|
||||
return nil
|
||||
}
|
||||
switch it := it.(type) {
|
||||
case WeightedLineSlicer:
|
||||
return it.WeightedLineSlice()
|
||||
}
|
||||
n := make([]WeightedLine, 0, it.Len())
|
||||
for it.Next() {
|
||||
n = append(n, it.WeightedLine())
|
||||
}
|
||||
return n
|
||||
}
|
@@ -41,7 +41,7 @@ func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded
|
||||
}
|
||||
}
|
||||
|
||||
path = newShortestFrom(s, g.Nodes())
|
||||
path = newShortestFrom(s, graph.NodesOf(g.Nodes()))
|
||||
tid := t.ID()
|
||||
|
||||
visited := make(set.Int64s)
|
||||
@@ -59,7 +59,7 @@ func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded
|
||||
}
|
||||
|
||||
visited.Add(uid)
|
||||
for _, v := range g.From(u.node.ID()) {
|
||||
for _, v := range graph.NodesOf(g.From(u.node.ID())) {
|
||||
vid := v.ID()
|
||||
if visited.Has(vid) {
|
||||
continue
|
||||
|
@@ -192,8 +192,8 @@ func TestExhaustiveAStar(t *testing.T) {
|
||||
}
|
||||
|
||||
ps := DijkstraAllPaths(g)
|
||||
for _, start := range g.Nodes() {
|
||||
for _, goal := range g.Nodes() {
|
||||
for _, start := range graph.NodesOf(g.Nodes()) {
|
||||
for _, goal := range graph.NodesOf(g.Nodes()) {
|
||||
pt, _ := AStar(start, goal, g, heuristic)
|
||||
gotPath, gotWeight := pt.To(goal.ID())
|
||||
wantPath, wantWeight, _ := ps.Between(start.ID(), goal.ID())
|
||||
@@ -226,8 +226,8 @@ func (e weightedEdge) To() graph.Node { return e.to }
|
||||
func (e weightedEdge) Weight() float64 { return e.cost }
|
||||
|
||||
func isMonotonic(g UndirectedWeightLister, h Heuristic) (ok bool, at graph.Edge, goal graph.Node) {
|
||||
for _, goal := range g.Nodes() {
|
||||
for _, edge := range g.WeightedEdges() {
|
||||
for _, goal := range graph.NodesOf(g.Nodes()) {
|
||||
for _, edge := range graph.WeightedEdgesOf(g.WeightedEdges()) {
|
||||
from := edge.From()
|
||||
to := edge.To()
|
||||
w, ok := g.Weight(from.ID(), to.ID())
|
||||
|
@@ -22,7 +22,7 @@ func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
||||
weight = UniformCost(g)
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
|
||||
path = newShortestFrom(u, nodes)
|
||||
path.dist[path.indexOf[u.ID()]] = 0
|
||||
@@ -33,7 +33,7 @@ func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
||||
changed := false
|
||||
for j, u := range nodes {
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
vid := v.ID()
|
||||
k := path.indexOf[vid]
|
||||
w, ok := weight(uid, vid)
|
||||
@@ -54,7 +54,7 @@ func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
||||
|
||||
for j, u := range nodes {
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
vid := v.ID()
|
||||
k := path.indexOf[vid]
|
||||
w, ok := weight(uid, vid)
|
||||
|
@@ -19,6 +19,7 @@ import (
|
||||
"gonum.org/v1/gonum/graph/encoding"
|
||||
"gonum.org/v1/gonum/graph/encoding/dot"
|
||||
"gonum.org/v1/gonum/graph/graphs/gen"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/graph/simple"
|
||||
"gonum.org/v1/gonum/graph/topo"
|
||||
)
|
||||
@@ -240,7 +241,7 @@ func duplication(n int, delta, alpha, sigma float64) func() *simple.DirectedGrap
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, e := range g.Edges() {
|
||||
for _, e := range graph.EdgesOf(g.Edges()) {
|
||||
if rnd.Intn(2) == 0 {
|
||||
g.RemoveEdge(e.From().ID(), e.To().ID())
|
||||
}
|
||||
@@ -253,8 +254,10 @@ type undirected struct {
|
||||
*simple.DirectedGraph
|
||||
}
|
||||
|
||||
func (g undirected) From(id int64) []graph.Node {
|
||||
return append(g.DirectedGraph.From(id), g.DirectedGraph.To(id)...)
|
||||
func (g undirected) From(id int64) graph.Nodes {
|
||||
return iterator.NewOrderedNodes(append(
|
||||
graph.NodesOf(g.DirectedGraph.From(id)),
|
||||
graph.NodesOf(g.DirectedGraph.To(id))...))
|
||||
}
|
||||
|
||||
func (g undirected) HasEdgeBetween(xid, yid int64) bool {
|
||||
|
@@ -140,7 +140,7 @@ func (lt *lengauerTarjan) dfs(g graph.Directed, v graph.Node) {
|
||||
ltv.label = ltv
|
||||
lt.nodes = append(lt.nodes, ltv)
|
||||
|
||||
for _, w := range g.From(v.ID()) {
|
||||
for _, w := range graph.NodesOf(g.From(v.ID())) {
|
||||
wid := w.ID()
|
||||
|
||||
idx, ok := lt.indexOf[wid]
|
||||
|
@@ -162,7 +162,7 @@ func (lt *sLengauerTarjan) dfs(g graph.Directed, v graph.Node) {
|
||||
ltv.label = ltv
|
||||
lt.nodes = append(lt.nodes, ltv)
|
||||
|
||||
for _, w := range g.From(v.ID()) {
|
||||
for _, w := range graph.NodesOf(g.From(v.ID())) {
|
||||
wid := w.ID()
|
||||
|
||||
idx, ok := lt.indexOf[wid]
|
||||
|
@@ -25,7 +25,7 @@ func DijkstraFrom(u graph.Node, g traverse.Graph) Shortest {
|
||||
if !h.Has(u.ID()) {
|
||||
return Shortest{from: u}
|
||||
}
|
||||
path = newShortestFrom(u, h.Nodes())
|
||||
path = newShortestFrom(u, graph.NodesOf(h.Nodes()))
|
||||
} else {
|
||||
if g.From(u.ID()) == nil {
|
||||
return Shortest{from: u}
|
||||
@@ -58,7 +58,7 @@ func DijkstraFrom(u graph.Node, g traverse.Graph) Shortest {
|
||||
continue
|
||||
}
|
||||
mnid := mid.node.ID()
|
||||
for _, v := range g.From(mnid) {
|
||||
for _, v := range graph.NodesOf(g.From(mnid)) {
|
||||
vid := v.ID()
|
||||
j, ok := path.indexOf[vid]
|
||||
if !ok {
|
||||
@@ -88,7 +88,7 @@ func DijkstraFrom(u graph.Node, g traverse.Graph) Shortest {
|
||||
//
|
||||
// The time complexity of DijkstrAllPaths is O(|V|.|E|+|V|^2.log|V|).
|
||||
func DijkstraAllPaths(g graph.Graph) (paths AllShortest) {
|
||||
paths = newAllShortest(g.Nodes(), false)
|
||||
paths = newAllShortest(graph.NodesOf(g.Nodes()), false)
|
||||
dijkstraAllPaths(g, paths)
|
||||
return paths
|
||||
}
|
||||
@@ -123,7 +123,7 @@ func dijkstraAllPaths(g graph.Graph, paths AllShortest) {
|
||||
paths.dist.Set(i, k, mid.dist)
|
||||
}
|
||||
mnid := mid.node.ID()
|
||||
for _, v := range g.From(mnid) {
|
||||
for _, v := range graph.NodesOf(g.From(mnid)) {
|
||||
vid := v.ID()
|
||||
j := paths.indexOf[vid]
|
||||
w, ok := weight(mnid, vid)
|
||||
|
@@ -88,7 +88,7 @@ func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel
|
||||
|
||||
d.queue.insert(d.t, key{d.heuristic(s, t), 0})
|
||||
|
||||
for _, n := range g.Nodes() {
|
||||
for _, n := range graph.NodesOf(g.Nodes()) {
|
||||
switch n.ID() {
|
||||
case d.s.ID():
|
||||
d.model.AddNode(d.s)
|
||||
@@ -98,9 +98,9 @@ func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel
|
||||
d.model.AddNode(newDStarLiteNode(n))
|
||||
}
|
||||
}
|
||||
for _, u := range d.model.Nodes() {
|
||||
for _, u := range graph.NodesOf(d.model.Nodes()) {
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
vid := v.ID()
|
||||
w := edgeWeight(d.weight, uid, vid)
|
||||
if w < 0 {
|
||||
@@ -196,7 +196,7 @@ func (d *DStarLite) findShortestPath() {
|
||||
case u.g > u.rhs:
|
||||
u.g = u.rhs
|
||||
d.queue.remove(u)
|
||||
for _, _s := range d.model.To(uid) {
|
||||
for _, _s := range graph.NodesOf(d.model.To(uid)) {
|
||||
s := _s.(*dStarLiteNode)
|
||||
sid := s.ID()
|
||||
if sid != d.t.ID() {
|
||||
@@ -207,13 +207,13 @@ func (d *DStarLite) findShortestPath() {
|
||||
default:
|
||||
gOld := u.g
|
||||
u.g = math.Inf(1)
|
||||
for _, _s := range append(d.model.To(uid), u) {
|
||||
for _, _s := range append(graph.NodesOf(d.model.To(uid)), u) {
|
||||
s := _s.(*dStarLiteNode)
|
||||
sid := s.ID()
|
||||
if s.rhs == edgeWeight(d.model.Weight, sid, uid)+gOld {
|
||||
if s.ID() != d.t.ID() {
|
||||
s.rhs = math.Inf(1)
|
||||
for _, t := range d.model.From(sid) {
|
||||
for _, t := range graph.NodesOf(d.model.From(sid)) {
|
||||
tid := t.ID()
|
||||
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, tid)+t.(*dStarLiteNode).g)
|
||||
}
|
||||
@@ -250,7 +250,7 @@ func (d *DStarLite) Step() bool {
|
||||
|
||||
var next *dStarLiteNode
|
||||
dsid := d.s.ID()
|
||||
for _, _s := range d.model.From(dsid) {
|
||||
for _, _s := range graph.NodesOf(d.model.From(dsid)) {
|
||||
s := _s.(*dStarLiteNode)
|
||||
w := edgeWeight(d.model.Weight, dsid, s.ID()) + s.g
|
||||
if w < min || (w == min && s.rhs < rhs) {
|
||||
@@ -320,7 +320,7 @@ func (d *DStarLite) UpdateWorld(changes []graph.Edge) {
|
||||
} else if u.rhs == cOld+v.g {
|
||||
if uid != d.t.ID() {
|
||||
u.rhs = math.Inf(1)
|
||||
for _, t := range d.model.From(uid) {
|
||||
for _, t := range graph.NodesOf(d.model.From(uid)) {
|
||||
u.rhs = math.Min(u.rhs, edgeWeight(d.model.Weight, uid, t.ID())+t.(*dStarLiteNode).g)
|
||||
}
|
||||
}
|
||||
@@ -365,7 +365,7 @@ func (d *DStarLite) Path() (p []graph.Node, weight float64) {
|
||||
cost float64
|
||||
)
|
||||
uid := u.ID()
|
||||
for _, _v := range d.model.From(uid) {
|
||||
for _, _v := range graph.NodesOf(d.model.From(uid)) {
|
||||
v := _v.(*dStarLiteNode)
|
||||
vid := v.ID()
|
||||
w := edgeWeight(d.model.Weight, uid, vid)
|
||||
|
@@ -387,7 +387,7 @@ var dynamicDStarLiteTests = []struct {
|
||||
modify: func(l *testgraphs.LimitedVisionGrid) {
|
||||
all := l.Grid.AllVisible
|
||||
l.Grid.AllVisible = false
|
||||
for _, n := range l.Nodes() {
|
||||
for _, n := range graph.NodesOf(l.Nodes()) {
|
||||
id := n.ID()
|
||||
l.Known[id] = !l.Grid.Has(id)
|
||||
}
|
||||
@@ -400,9 +400,9 @@ var dynamicDStarLiteTests = []struct {
|
||||
l.Known[l.NodeAt(wallRow, wallCol).ID()] = false
|
||||
|
||||
// Check we have a correctly modified representation.
|
||||
for _, u := range l.Nodes() {
|
||||
for _, u := range graph.NodesOf(l.Nodes()) {
|
||||
uid := u.ID()
|
||||
for _, v := range l.Nodes() {
|
||||
for _, v := range graph.NodesOf(l.Nodes()) {
|
||||
vid := v.ID()
|
||||
if l.HasEdgeBetween(uid, vid) != l.Grid.HasEdgeBetween(uid, vid) {
|
||||
ur, uc := l.RowCol(uid)
|
||||
@@ -598,7 +598,7 @@ func TestDStarLiteDynamic(t *testing.T) {
|
||||
}
|
||||
|
||||
dp.dump(true)
|
||||
dp.printEdges("Initial world knowledge: %s\n\n", simpleWeightedEdgesOf(l, world.Edges()))
|
||||
dp.printEdges("Initial world knowledge: %s\n\n", simpleWeightedEdgesOf(l, graph.EdgesOf(world.Edges())))
|
||||
for d.Step() {
|
||||
changes, _ := l.MoveTo(d.Here())
|
||||
got = append(got, l.Location)
|
||||
|
@@ -19,13 +19,14 @@ func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
|
||||
weight = UniformCost(g)
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
paths = newAllShortest(nodes, true)
|
||||
for i, u := range nodes {
|
||||
paths.dist.Set(i, i, 0)
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
to := g.From(uid)
|
||||
for to.Next() {
|
||||
vid := to.Node().ID()
|
||||
j := paths.indexOf[vid]
|
||||
w, ok := weight(uid, vid)
|
||||
if !ok {
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"math"
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/graph/simple"
|
||||
)
|
||||
|
||||
@@ -91,14 +92,14 @@ func NewGridFrom(rows ...string) *Grid {
|
||||
|
||||
// Nodes returns all the open nodes in the grid if AllVisible is
|
||||
// false, otherwise all nodes are returned.
|
||||
func (g *Grid) Nodes() []graph.Node {
|
||||
func (g *Grid) Nodes() graph.Nodes {
|
||||
var nodes []graph.Node
|
||||
for id, ok := range g.open {
|
||||
if ok || g.AllVisible {
|
||||
nodes = append(nodes, simple.Node(id))
|
||||
}
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Has returns whether n is a node in the grid. The state of
|
||||
@@ -158,7 +159,7 @@ func (g *Grid) NodeAt(r, c int) graph.Node {
|
||||
|
||||
// From returns all the nodes reachable from u. Reachabilty requires that both
|
||||
// ends of an edge must be open.
|
||||
func (g *Grid) From(uid int64) []graph.Node {
|
||||
func (g *Grid) From(uid int64) graph.Nodes {
|
||||
if !g.HasOpen(uid) {
|
||||
return nil
|
||||
}
|
||||
@@ -171,7 +172,7 @@ func (g *Grid) From(uid int64) []graph.Node {
|
||||
}
|
||||
}
|
||||
}
|
||||
return to
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether there is an edge between u and v.
|
||||
|
@@ -249,7 +249,7 @@ func TestGrid(t *testing.T) {
|
||||
}
|
||||
for _, test := range reach {
|
||||
g.AllowDiagonal = test.diagonal
|
||||
got := g.From(test.from.ID())
|
||||
got := graph.NodesOf(g.From(test.from.ID()))
|
||||
if !reflect.DeepEqual(got, test.to) {
|
||||
t.Fatalf("unexpected nodes from %d with allow diagonal=%t:\ngot: %v\nwant:%v",
|
||||
test.from, test.diagonal, got, test.to)
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"math"
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/graph/simple"
|
||||
)
|
||||
|
||||
@@ -147,12 +148,12 @@ func (l *LimitedVisionGrid) XY(id int64) (x, y float64) {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the grid.
|
||||
func (l *LimitedVisionGrid) Nodes() []graph.Node {
|
||||
func (l *LimitedVisionGrid) Nodes() graph.Nodes {
|
||||
nodes := make([]graph.Node, 0, len(l.Grid.open))
|
||||
for id := range l.Grid.open {
|
||||
nodes = append(nodes, simple.Node(id))
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// NodeAt returns the node at (r, c). The returned node may be open or closed.
|
||||
@@ -166,7 +167,7 @@ func (l *LimitedVisionGrid) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// From returns nodes that are optimistically reachable from u.
|
||||
func (l *LimitedVisionGrid) From(uid int64) []graph.Node {
|
||||
func (l *LimitedVisionGrid) From(uid int64) graph.Nodes {
|
||||
if !l.Has(uid) {
|
||||
return nil
|
||||
}
|
||||
@@ -180,7 +181,7 @@ func (l *LimitedVisionGrid) From(uid int64) []graph.Node {
|
||||
}
|
||||
}
|
||||
}
|
||||
return to
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
// HasEdgeBetween optimistically returns whether an edge is exists between u and v.
|
||||
|
@@ -1166,11 +1166,11 @@ func TestLimitedVisionGrid(t *testing.T) {
|
||||
l.Grid.AllowDiagonal = test.diag
|
||||
|
||||
x, y := l.XY(test.path[0].ID())
|
||||
for _, u := range l.Nodes() {
|
||||
for _, u := range graph.NodesOf(l.Nodes()) {
|
||||
uid := u.ID()
|
||||
ux, uy := l.XY(uid)
|
||||
uNear := math.Hypot(x-ux, y-uy) <= test.radius
|
||||
for _, v := range l.Nodes() {
|
||||
for _, v := range graph.NodesOf(l.Nodes()) {
|
||||
vid := v.ID()
|
||||
vx, vy := l.XY(vid)
|
||||
vNear := math.Hypot(x-vx, y-vy) <= test.radius
|
||||
|
@@ -29,7 +29,7 @@ func JohnsonAllPaths(g graph.Graph) (paths AllShortest, ok bool) {
|
||||
jg.weight = UniformCost(g)
|
||||
}
|
||||
|
||||
paths = newAllShortest(g.Nodes(), false)
|
||||
paths = newAllShortest(graph.NodesOf(g.Nodes()), false)
|
||||
|
||||
sign := int64(-1)
|
||||
for {
|
||||
@@ -69,7 +69,7 @@ type johnsonWeightAdjuster struct {
|
||||
q int64
|
||||
g graph.Graph
|
||||
|
||||
from func(id int64) []graph.Node
|
||||
from func(id int64) graph.Nodes
|
||||
edgeTo func(uid, vid int64) graph.Edge
|
||||
weight Weighting
|
||||
|
||||
@@ -93,14 +93,14 @@ func (g johnsonWeightAdjuster) Has(id int64) bool {
|
||||
panic("path: unintended use of johnsonWeightAdjuster")
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) Nodes() []graph.Node {
|
||||
func (g johnsonWeightAdjuster) Nodes() graph.Nodes {
|
||||
if g.bellmanFord {
|
||||
return append(g.g.Nodes(), johnsonGraphNode(g.q))
|
||||
return newJohnsonNodeIterator(g.q, g.g.Nodes())
|
||||
}
|
||||
return g.g.Nodes()
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) From(id int64) []graph.Node {
|
||||
func (g johnsonWeightAdjuster) From(id int64) graph.Nodes {
|
||||
if g.bellmanFord && id == g.q {
|
||||
return g.g.Nodes()
|
||||
}
|
||||
@@ -140,3 +140,59 @@ func (johnsonWeightAdjuster) HasEdgeBetween(_, _ int64) bool {
|
||||
type johnsonGraphNode int64
|
||||
|
||||
func (n johnsonGraphNode) ID() int64 { return int64(n) }
|
||||
|
||||
func newJohnsonNodeIterator(q int64, nodes graph.Nodes) *johnsonNodeIterator {
|
||||
return &johnsonNodeIterator{q: q, nodes: nodes}
|
||||
}
|
||||
|
||||
type johnsonNodeIterator struct {
|
||||
q int64
|
||||
nodes graph.Nodes
|
||||
qUsed, qOK bool
|
||||
}
|
||||
|
||||
func (it *johnsonNodeIterator) Len() int {
|
||||
var len int
|
||||
if it.nodes != nil {
|
||||
len = it.nodes.Len()
|
||||
}
|
||||
if !it.qUsed {
|
||||
len++
|
||||
}
|
||||
return len
|
||||
}
|
||||
|
||||
func (it *johnsonNodeIterator) Next() bool {
|
||||
if it.nodes != nil {
|
||||
ok := it.nodes.Next()
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if !it.qUsed {
|
||||
it.qOK = true
|
||||
it.qUsed = true
|
||||
return true
|
||||
}
|
||||
it.qOK = false
|
||||
return false
|
||||
}
|
||||
|
||||
func (it *johnsonNodeIterator) Node() graph.Node {
|
||||
if it.qOK {
|
||||
return johnsonGraphNode(it.q)
|
||||
}
|
||||
if it.nodes == nil {
|
||||
return nil
|
||||
}
|
||||
return it.nodes.Node()
|
||||
}
|
||||
|
||||
func (it *johnsonNodeIterator) Reset() {
|
||||
it.qOK = false
|
||||
it.qUsed = false
|
||||
if it.nodes == nil {
|
||||
return
|
||||
}
|
||||
it.nodes.Reset()
|
||||
}
|
||||
|
@@ -36,8 +36,9 @@ func ExampleBellmanFordFrom_negativecycles() {
|
||||
}
|
||||
|
||||
// Add a zero-cost path to all nodes from a new node Q.
|
||||
for _, n := range g.Nodes() {
|
||||
g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node('Q'), T: n})
|
||||
nodes := g.Nodes()
|
||||
for nodes.Next() {
|
||||
g.SetWeightedEdge(simple.WeightedEdge{F: simple.Node('Q'), T: nodes.Node()})
|
||||
}
|
||||
|
||||
// Find the shortest path to each node from Q.
|
||||
|
@@ -32,7 +32,7 @@ type WeightedBuilder interface {
|
||||
//
|
||||
// If dst has nodes that exist in g, Prim will panic.
|
||||
func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
if len(nodes) == 0 {
|
||||
return 0
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
|
||||
|
||||
u := nodes[0]
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
w, ok := g.Weight(uid, v.ID())
|
||||
if !ok {
|
||||
panic("prim: unexpected invalid weight")
|
||||
@@ -67,7 +67,7 @@ func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
|
||||
|
||||
u = e.From()
|
||||
uid := u.ID()
|
||||
for _, n := range g.From(uid) {
|
||||
for _, n := range graph.NodesOf(g.From(uid)) {
|
||||
if key, ok := q.key(n); ok {
|
||||
w, ok := g.Weight(uid, n.ID())
|
||||
if !ok {
|
||||
@@ -146,7 +146,7 @@ func (q *primQueue) update(u, v graph.Node, key float64) {
|
||||
// the set of edges in the graph.
|
||||
type UndirectedWeightLister interface {
|
||||
graph.WeightedUndirected
|
||||
WeightedEdges() []graph.WeightedEdge
|
||||
WeightedEdges() graph.WeightedEdges
|
||||
}
|
||||
|
||||
// Kruskal generates a minimum spanning tree of g by greedy tree coalescence, placing
|
||||
@@ -162,11 +162,11 @@ type UndirectedWeightLister interface {
|
||||
//
|
||||
// If dst has nodes that exist in g, Kruskal will panic.
|
||||
func Kruskal(dst WeightedBuilder, g UndirectedWeightLister) float64 {
|
||||
edges := g.WeightedEdges()
|
||||
edges := graph.WeightedEdgesOf(g.WeightedEdges())
|
||||
sort.Sort(byWeight(edges))
|
||||
|
||||
ds := newDisjointSet()
|
||||
for _, node := range g.Nodes() {
|
||||
for _, node := range graph.NodesOf(g.Nodes()) {
|
||||
dst.AddNode(node)
|
||||
ds.makeSet(node.ID())
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ func init() {
|
||||
type spanningGraph interface {
|
||||
graph.WeightedBuilder
|
||||
graph.WeightedUndirected
|
||||
WeightedEdges() []graph.WeightedEdge
|
||||
WeightedEdges() graph.WeightedEdges
|
||||
}
|
||||
|
||||
var spanningTreeTests = []struct {
|
||||
@@ -254,7 +254,7 @@ func testMinumumSpanning(mst func(dst WeightedBuilder, g spanningGraph) float64,
|
||||
test.name, w, test.want)
|
||||
}
|
||||
var got float64
|
||||
for _, e := range dst.WeightedEdges() {
|
||||
for _, e := range graph.WeightedEdgesOf(dst.WeightedEdges()) {
|
||||
got += e.Weight()
|
||||
}
|
||||
if got != test.want {
|
||||
@@ -262,7 +262,7 @@ func testMinumumSpanning(mst func(dst WeightedBuilder, g spanningGraph) float64,
|
||||
test.name, got, test.want)
|
||||
}
|
||||
|
||||
gotEdges := dst.Edges()
|
||||
gotEdges := graph.EdgesOf(dst.Edges())
|
||||
if len(gotEdges) != len(test.treeEdges) {
|
||||
t.Errorf("unexpected number of spanning tree edges for %q: got: %d want: %d",
|
||||
test.name, len(gotEdges), len(test.treeEdges))
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// YenKShortestPaths returns the k-shortest loopless paths from s to t in g.
|
||||
@@ -116,8 +117,8 @@ type yenKSPAdjuster struct {
|
||||
visitedEdges map[[2]int64]struct{}
|
||||
}
|
||||
|
||||
func (g yenKSPAdjuster) From(id int64) []graph.Node {
|
||||
nodes := g.Graph.From(id)
|
||||
func (g yenKSPAdjuster) From(id int64) graph.Nodes {
|
||||
nodes := graph.NodesOf(g.Graph.From(id))
|
||||
for i := 0; i < len(nodes); {
|
||||
if g.canWalk(id, nodes[i].ID()) {
|
||||
i++
|
||||
@@ -126,7 +127,7 @@ func (g yenKSPAdjuster) From(id int64) []graph.Node {
|
||||
nodes[i] = nodes[len(nodes)-1]
|
||||
nodes = nodes[:len(nodes)-1]
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
func (g yenKSPAdjuster) canWalk(u, v int64) bool {
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/mat"
|
||||
)
|
||||
|
||||
@@ -85,22 +86,18 @@ func (g *DirectedMatrix) has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *DirectedMatrix) Nodes() []graph.Node {
|
||||
func (g *DirectedMatrix) Nodes() graph.Nodes {
|
||||
if g.nodes != nil {
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
copy(nodes, g.nodes)
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
r, _ := g.mat.Dims()
|
||||
nodes := make([]graph.Node, r)
|
||||
for i := 0; i < r; i++ {
|
||||
nodes[i] = Node(i)
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewImplicitNodes(0, r, newSimpleNode)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph.
|
||||
func (g *DirectedMatrix) Edges() []graph.Edge {
|
||||
func (g *DirectedMatrix) Edges() graph.Edges {
|
||||
var edges []graph.Edge
|
||||
r, _ := g.mat.Dims()
|
||||
for i := 0; i < r; i++ {
|
||||
@@ -113,15 +110,15 @@ func (g *DirectedMatrix) Edges() []graph.Edge {
|
||||
}
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *DirectedMatrix) From(id int64) []graph.Node {
|
||||
func (g *DirectedMatrix) From(id int64) graph.Nodes {
|
||||
if !g.has(id) {
|
||||
return nil
|
||||
}
|
||||
var neighbors []graph.Node
|
||||
var nodes []graph.Node
|
||||
_, c := g.mat.Dims()
|
||||
for j := 0; j < c; j++ {
|
||||
if int64(j) == id {
|
||||
@@ -129,18 +126,18 @@ func (g *DirectedMatrix) From(id int64) []graph.Node {
|
||||
}
|
||||
// id is not greater than maximum int by this point.
|
||||
if !isSame(g.mat.At(int(id), j), g.absent) {
|
||||
neighbors = append(neighbors, g.Node(int64(j)))
|
||||
nodes = append(nodes, g.Node(int64(j)))
|
||||
}
|
||||
}
|
||||
return neighbors
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *DirectedMatrix) To(id int64) []graph.Node {
|
||||
func (g *DirectedMatrix) To(id int64) graph.Nodes {
|
||||
if !g.has(id) {
|
||||
return nil
|
||||
}
|
||||
var neighbors []graph.Node
|
||||
var nodes []graph.Node
|
||||
r, _ := g.mat.Dims()
|
||||
for i := 0; i < r; i++ {
|
||||
if int64(i) == id {
|
||||
@@ -148,10 +145,10 @@ func (g *DirectedMatrix) To(id int64) []graph.Node {
|
||||
}
|
||||
// id is not greater than maximum int by this point.
|
||||
if !isSame(g.mat.At(i, int(id)), g.absent) {
|
||||
neighbors = append(neighbors, g.Node(int64(i)))
|
||||
nodes = append(nodes, g.Node(int64(i)))
|
||||
}
|
||||
}
|
||||
return neighbors
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
@@ -251,34 +248,6 @@ func (g *DirectedMatrix) RemoveEdge(fid, tid int64) {
|
||||
g.mat.Set(int(fid), int(tid), g.absent)
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *DirectedMatrix) Degree(id int64) int {
|
||||
if !g.has(id) {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
r, c := g.mat.Dims()
|
||||
for i := 0; i < r; i++ {
|
||||
if int64(i) == id {
|
||||
continue
|
||||
}
|
||||
// id is not greater than maximum int by this point.
|
||||
if !isSame(g.mat.At(int(id), i), g.absent) {
|
||||
deg++
|
||||
}
|
||||
}
|
||||
for i := 0; i < c; i++ {
|
||||
if int64(i) == id {
|
||||
continue
|
||||
}
|
||||
// id is not greater than maximum int by this point.
|
||||
if !isSame(g.mat.At(i, int(id)), g.absent) {
|
||||
deg++
|
||||
}
|
||||
}
|
||||
return deg
|
||||
}
|
||||
|
||||
// Matrix returns the mat.Matrix representation of the graph. The orientation
|
||||
// of the matrix is such that the matrix entry at G_{ij} is the weight of the edge
|
||||
// from node i to node j.
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
"gonum.org/v1/gonum/mat"
|
||||
)
|
||||
|
||||
@@ -85,22 +86,18 @@ func (g *UndirectedMatrix) has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *UndirectedMatrix) Nodes() []graph.Node {
|
||||
func (g *UndirectedMatrix) Nodes() graph.Nodes {
|
||||
if g.nodes != nil {
|
||||
nodes := make([]graph.Node, len(g.nodes))
|
||||
copy(nodes, g.nodes)
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
r := g.mat.Symmetric()
|
||||
nodes := make([]graph.Node, r)
|
||||
for i := 0; i < r; i++ {
|
||||
nodes[i] = Node(i)
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewImplicitNodes(0, r, newSimpleNode)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph.
|
||||
func (g *UndirectedMatrix) Edges() []graph.Edge {
|
||||
func (g *UndirectedMatrix) Edges() graph.Edges {
|
||||
var edges []graph.Edge
|
||||
r, _ := g.mat.Dims()
|
||||
for i := 0; i < r; i++ {
|
||||
@@ -110,15 +107,15 @@ func (g *UndirectedMatrix) Edges() []graph.Edge {
|
||||
}
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *UndirectedMatrix) From(id int64) []graph.Node {
|
||||
func (g *UndirectedMatrix) From(id int64) graph.Nodes {
|
||||
if !g.has(id) {
|
||||
return nil
|
||||
}
|
||||
var neighbors []graph.Node
|
||||
var nodes []graph.Node
|
||||
r := g.mat.Symmetric()
|
||||
for i := 0; i < r; i++ {
|
||||
if int64(i) == id {
|
||||
@@ -126,10 +123,10 @@ func (g *UndirectedMatrix) From(id int64) []graph.Node {
|
||||
}
|
||||
// id is not greater than maximum int by this point.
|
||||
if !isSame(g.mat.At(int(id), i), g.absent) {
|
||||
neighbors = append(neighbors, g.Node(int64(i)))
|
||||
nodes = append(nodes, g.Node(int64(i)))
|
||||
}
|
||||
}
|
||||
return neighbors
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -226,25 +223,6 @@ func (g *UndirectedMatrix) RemoveEdge(fid, tid int64) {
|
||||
g.mat.SetSym(int(fid), int(tid), g.absent)
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *UndirectedMatrix) Degree(id int64) int {
|
||||
if !g.has(id) {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
r := g.mat.Symmetric()
|
||||
for i := 0; i < r; i++ {
|
||||
if int64(i) == id {
|
||||
continue
|
||||
}
|
||||
// id is not greater than maximum int by this point.
|
||||
if !isSame(g.mat.At(int(id), i), g.absent) {
|
||||
deg++
|
||||
}
|
||||
}
|
||||
return deg
|
||||
}
|
||||
|
||||
// Matrix returns the mat.Matrix representation of the graph.
|
||||
func (g *UndirectedMatrix) Matrix() mat.Matrix {
|
||||
// Prevent alteration of dimensions of the returned matrix.
|
||||
|
@@ -38,7 +38,7 @@ func TestBasicDenseImpassable(t *testing.T) {
|
||||
t.Errorf("Node that should exist doesn't: %d", i)
|
||||
}
|
||||
|
||||
if degree := dg.Degree(int64(i)); degree != 0 {
|
||||
if degree := dg.From(int64(i)).Len(); degree != 0 {
|
||||
t.Errorf("Node in impassable graph has a neighbor. Node: %d Degree: %d", i, degree)
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func TestBasicDensePassable(t *testing.T) {
|
||||
t.Errorf("Node that should exist doesn't: %d", i)
|
||||
}
|
||||
|
||||
if degree := dg.Degree(int64(i)); degree != 4 {
|
||||
if degree := dg.From(int64(i)).Len(); degree != 4 {
|
||||
t.Errorf("Node in passable graph missing neighbors. Node: %d Degree: %d", i, degree)
|
||||
}
|
||||
}
|
||||
@@ -77,18 +77,18 @@ func TestDirectedDenseAddRemove(t *testing.T) {
|
||||
dg := NewDirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
|
||||
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 1})
|
||||
|
||||
if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||
if neighbors := graph.NodesOf(dg.From(int64(0))); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||
dg.Edge(int64(0), int64(2)) == nil {
|
||||
t.Errorf("Adding edge didn't create successor")
|
||||
}
|
||||
|
||||
dg.RemoveEdge(int64(0), int64(2))
|
||||
|
||||
if neighbors := dg.From(int64(0)); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
|
||||
if neighbors := graph.NodesOf(dg.From(int64(0))); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
|
||||
t.Errorf("Removing edge didn't properly remove successor")
|
||||
}
|
||||
|
||||
if neighbors := dg.To(int64(2)); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
|
||||
if neighbors := graph.NodesOf(dg.To(int64(2))); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
|
||||
t.Errorf("Removing directed edge wrongly kept predecessor")
|
||||
}
|
||||
|
||||
@@ -109,12 +109,12 @@ func TestUndirectedDenseAddRemove(t *testing.T) {
|
||||
dg := NewUndirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
|
||||
dg.SetEdge(Edge{F: Node(0), T: Node(2)})
|
||||
|
||||
if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||
if neighbors := graph.NodesOf(dg.From(int64(0))); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||
dg.EdgeBetween(int64(0), int64(2)) == nil {
|
||||
t.Errorf("Couldn't add neighbor")
|
||||
}
|
||||
|
||||
if neighbors := dg.From(int64(2)); len(neighbors) != 1 || neighbors[0].ID() != 0 ||
|
||||
if neighbors := graph.NodesOf(dg.From(int64(2))); len(neighbors) != 1 || neighbors[0].ID() != 0 ||
|
||||
dg.EdgeBetween(int64(2), int64(0)) == nil {
|
||||
t.Errorf("Adding an undirected neighbor didn't add it reciprocally")
|
||||
}
|
||||
@@ -122,27 +122,27 @@ func TestUndirectedDenseAddRemove(t *testing.T) {
|
||||
|
||||
func TestDenseLists(t *testing.T) {
|
||||
dg := NewDirectedMatrix(15, 1, 0, math.Inf(1))
|
||||
nodes := dg.Nodes()
|
||||
nodes := graph.NodesOf(dg.Nodes())
|
||||
|
||||
if len(nodes) != 15 {
|
||||
t.Fatalf("Wrong number of nodes")
|
||||
t.Fatalf("Wrong number of nodes: got:%v want:%v", len(nodes), 15)
|
||||
}
|
||||
|
||||
sort.Sort(ordered.ByID(nodes))
|
||||
|
||||
for i, node := range dg.Nodes() {
|
||||
for i, node := range graph.NodesOf(dg.Nodes()) {
|
||||
if int64(i) != node.ID() {
|
||||
t.Errorf("Node list doesn't return properly id'd nodes")
|
||||
}
|
||||
}
|
||||
|
||||
edges := dg.Edges()
|
||||
edges := graph.EdgesOf(dg.Edges())
|
||||
if len(edges) != 15*14 {
|
||||
t.Errorf("Improper number of edges for passable dense graph")
|
||||
}
|
||||
|
||||
dg.RemoveEdge(int64(12), int64(11))
|
||||
edges = dg.Edges()
|
||||
edges = graph.EdgesOf(dg.Edges())
|
||||
if len(edges) != (15*14)-1 {
|
||||
t.Errorf("Removing edge didn't affect edge listing properly")
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/uid"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// DirectedGraph implements a generalized directed graph.
|
||||
@@ -131,7 +132,7 @@ func (g *DirectedGraph) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *DirectedGraph) Nodes() []graph.Node {
|
||||
func (g *DirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -141,22 +142,22 @@ func (g *DirectedGraph) Nodes() []graph.Node {
|
||||
nodes[i] = n
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph.
|
||||
func (g *DirectedGraph) Edges() []graph.Edge {
|
||||
func (g *DirectedGraph) Edges() graph.Edges {
|
||||
var edges []graph.Edge
|
||||
for _, u := range g.nodes {
|
||||
for _, e := range g.from[u.ID()] {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *DirectedGraph) From(id int64) []graph.Node {
|
||||
func (g *DirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -167,11 +168,11 @@ func (g *DirectedGraph) From(id int64) []graph.Node {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
return from
|
||||
return iterator.NewOrderedNodes(from)
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *DirectedGraph) To(id int64) []graph.Node {
|
||||
func (g *DirectedGraph) To(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -182,7 +183,7 @@ func (g *DirectedGraph) To(id int64) []graph.Node {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
return to
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
@@ -212,11 +213,3 @@ func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *DirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
return len(g.from[id]) + len(g.to[id])
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ var (
|
||||
func TestEdgeOvercounting(t *testing.T) {
|
||||
g := generateDummyGraph()
|
||||
|
||||
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||
if neigh := graph.NodesOf(g.From(int64(2))); len(neigh) != 2 {
|
||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,10 @@ func (n Node) ID() int64 {
|
||||
return int64(n)
|
||||
}
|
||||
|
||||
func newSimpleNode(id int) graph.Node {
|
||||
return Node(id)
|
||||
}
|
||||
|
||||
// Edge is a simple graph edge.
|
||||
type Edge struct {
|
||||
F, T graph.Node
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/uid"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// UndirectedGraph implements a generalized undirected graph.
|
||||
@@ -123,7 +124,7 @@ func (g *UndirectedGraph) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *UndirectedGraph) Nodes() []graph.Node {
|
||||
func (g *UndirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -133,11 +134,11 @@ func (g *UndirectedGraph) Nodes() []graph.Node {
|
||||
nodes[i] = n
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph.
|
||||
func (g *UndirectedGraph) Edges() []graph.Edge {
|
||||
func (g *UndirectedGraph) Edges() graph.Edges {
|
||||
if len(g.edges) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -155,11 +156,11 @@ func (g *UndirectedGraph) Edges() []graph.Edge {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *UndirectedGraph) From(id int64) []graph.Node {
|
||||
func (g *UndirectedGraph) From(id int64) graph.Nodes {
|
||||
if !g.Has(id) {
|
||||
return nil
|
||||
}
|
||||
@@ -170,7 +171,7 @@ func (g *UndirectedGraph) From(id int64) []graph.Node {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -193,11 +194,3 @@ func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
}
|
||||
return edge
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *UndirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
return len(g.edges[id])
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/uid"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// WeightedDirectedGraph implements a generalized weighted directed graph.
|
||||
@@ -137,7 +138,7 @@ func (g *WeightedDirectedGraph) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *WeightedDirectedGraph) Nodes() []graph.Node {
|
||||
func (g *WeightedDirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.from) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -147,18 +148,18 @@ func (g *WeightedDirectedGraph) Nodes() []graph.Node {
|
||||
nodes[i] = n
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph.
|
||||
func (g *WeightedDirectedGraph) Edges() []graph.Edge {
|
||||
func (g *WeightedDirectedGraph) Edges() graph.Edges {
|
||||
var edges []graph.Edge
|
||||
for _, u := range g.nodes {
|
||||
for _, e := range g.from[u.ID()] {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// WeightedEdges returns all the weighted edges in the graph.
|
||||
@@ -173,7 +174,7 @@ func (g *WeightedDirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
|
||||
func (g *WeightedDirectedGraph) From(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -184,11 +185,11 @@ func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
return from
|
||||
return iterator.NewOrderedNodes(from)
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
|
||||
func (g *WeightedDirectedGraph) To(id int64) graph.Nodes {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -199,7 +200,7 @@ func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
return to
|
||||
return iterator.NewOrderedNodes(to)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
@@ -251,11 +252,3 @@ func (g *WeightedDirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
}
|
||||
return g.absent, false
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *WeightedDirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
return len(g.from[id]) + len(g.to[id])
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ var (
|
||||
func TestWeightedEdgeOvercounting(t *testing.T) {
|
||||
g := generateDummyGraph()
|
||||
|
||||
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||
if neigh := graph.NodesOf(g.From(int64(2))); len(neigh) != 2 {
|
||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/uid"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// WeightedUndirectedGraph implements a generalized weighted undirected graph.
|
||||
@@ -129,7 +130,7 @@ func (g *WeightedUndirectedGraph) Has(id int64) bool {
|
||||
}
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g *WeightedUndirectedGraph) Nodes() []graph.Node {
|
||||
func (g *WeightedUndirectedGraph) Nodes() graph.Nodes {
|
||||
if len(g.nodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -139,11 +140,11 @@ func (g *WeightedUndirectedGraph) Nodes() []graph.Node {
|
||||
nodes[i] = n
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// Edges returns all the edges in the graph.
|
||||
func (g *WeightedUndirectedGraph) Edges() []graph.Edge {
|
||||
func (g *WeightedUndirectedGraph) Edges() graph.Edges {
|
||||
if len(g.edges) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -161,11 +162,11 @@ func (g *WeightedUndirectedGraph) Edges() []graph.Edge {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedEdges(edges)
|
||||
}
|
||||
|
||||
// WeightedEdges returns all the weighted edges in the graph.
|
||||
func (g *WeightedUndirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
||||
func (g *WeightedUndirectedGraph) WeightedEdges() graph.WeightedEdges {
|
||||
var edges []graph.WeightedEdge
|
||||
seen := make(map[[2]int64]struct{})
|
||||
for _, u := range g.edges {
|
||||
@@ -180,11 +181,11 @@ func (g *WeightedUndirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
}
|
||||
return edges
|
||||
return iterator.NewOrderedWeightedEdges(edges)
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
|
||||
func (g *WeightedUndirectedGraph) From(id int64) graph.Nodes {
|
||||
if !g.Has(id) {
|
||||
return nil
|
||||
}
|
||||
@@ -195,7 +196,7 @@ func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
return nodes
|
||||
return iterator.NewOrderedNodes(nodes)
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -245,11 +246,3 @@ func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
}
|
||||
return g.absent, false
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *WeightedUndirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
return len(g.edges[id])
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ func KCore(k int, g graph.Undirected) []graph.Node {
|
||||
// s, a set of relative offsets into l for each k-core, where k is an index
|
||||
// into s.
|
||||
func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
|
||||
// The algorithm used here is essentially as described at
|
||||
// http://en.wikipedia.org/w/index.php?title=Degeneracy_%28graph_theory%29&oldid=640308710
|
||||
@@ -61,7 +61,7 @@ func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) {
|
||||
)
|
||||
for _, n := range nodes {
|
||||
id := n.ID()
|
||||
adj := g.From(id)
|
||||
adj := graph.NodesOf(g.From(id))
|
||||
neighbours[id] = adj
|
||||
dv[id] = len(adj)
|
||||
if len(adj) > maxDegree {
|
||||
@@ -133,7 +133,7 @@ func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) {
|
||||
|
||||
// BronKerbosch returns the set of maximal cliques of the undirected graph g.
|
||||
func BronKerbosch(g graph.Undirected) [][]graph.Node {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
|
||||
// The algorithm used here is essentially BronKerbosch3 as described at
|
||||
// http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858
|
||||
@@ -147,7 +147,7 @@ func BronKerbosch(g graph.Undirected) [][]graph.Node {
|
||||
order, _ := degeneracyOrdering(g)
|
||||
ordered.Reverse(order)
|
||||
for _, v := range order {
|
||||
neighbours := g.From(v.ID())
|
||||
neighbours := graph.NodesOf(g.From(v.ID()))
|
||||
nv := make(set.Nodes, len(neighbours))
|
||||
for _, n := range neighbours {
|
||||
nv.Add(n)
|
||||
@@ -177,7 +177,7 @@ func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p
|
||||
continue
|
||||
}
|
||||
vid := v.ID()
|
||||
neighbours := g.From(vid)
|
||||
neighbours := graph.NodesOf(g.From(vid))
|
||||
nv := make(set.Nodes, len(neighbours))
|
||||
for _, n := range neighbours {
|
||||
nv.Add(n)
|
||||
@@ -207,10 +207,10 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
|
||||
// compile time option.
|
||||
if !tomitaTanakaTakahashi {
|
||||
for _, n := range p {
|
||||
return g.From(n.ID())
|
||||
return graph.NodesOf(g.From(n.ID()))
|
||||
}
|
||||
for _, n := range x {
|
||||
return g.From(n.ID())
|
||||
return graph.NodesOf(g.From(n.ID()))
|
||||
}
|
||||
panic("bronKerbosch: empty set")
|
||||
}
|
||||
@@ -222,7 +222,7 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
|
||||
maxNeighbors := func(s set.Nodes) {
|
||||
outer:
|
||||
for _, u := range s {
|
||||
nb := g.From(u.ID())
|
||||
nb := graph.NodesOf(g.From(u.ID()))
|
||||
c := len(nb)
|
||||
if c <= max {
|
||||
continue
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||
"gonum.org/v1/gonum/graph/internal/set"
|
||||
"gonum.org/v1/gonum/graph/iterator"
|
||||
)
|
||||
|
||||
// johnson implements Johnson's "Finding all the elementary
|
||||
@@ -132,7 +133,7 @@ type johnsonGraph struct {
|
||||
|
||||
// johnsonGraphFrom returns a deep copy of the graph g.
|
||||
func johnsonGraphFrom(g graph.Directed) johnsonGraph {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
sort.Sort(ordered.ByID(nodes))
|
||||
c := johnsonGraph{
|
||||
orig: nodes,
|
||||
@@ -144,7 +145,7 @@ func johnsonGraphFrom(g graph.Directed) johnsonGraph {
|
||||
for i, u := range nodes {
|
||||
uid := u.ID()
|
||||
c.index[uid] = i
|
||||
for _, v := range g.From(uid) {
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
if c.succ[uid] == nil {
|
||||
c.succ[uid] = make(set.Int64s)
|
||||
c.nodes.Add(uid)
|
||||
@@ -239,16 +240,16 @@ func (g johnsonGraph) sccSubGraph(sccs [][]graph.Node, min int) johnsonGraph {
|
||||
}
|
||||
|
||||
// Nodes is required to satisfy Tarjan.
|
||||
func (g johnsonGraph) Nodes() []graph.Node {
|
||||
func (g johnsonGraph) Nodes() graph.Nodes {
|
||||
n := make([]graph.Node, 0, len(g.nodes))
|
||||
for id := range g.nodes {
|
||||
n = append(n, johnsonGraphNode(id))
|
||||
}
|
||||
return n
|
||||
return iterator.NewOrderedNodes(n)
|
||||
}
|
||||
|
||||
// Successors is required to satisfy Tarjan.
|
||||
func (g johnsonGraph) From(id int64) []graph.Node {
|
||||
func (g johnsonGraph) From(id int64) graph.Nodes {
|
||||
adj := g.succ[id]
|
||||
if len(adj) == 0 {
|
||||
return nil
|
||||
@@ -257,7 +258,7 @@ func (g johnsonGraph) From(id int64) []graph.Node {
|
||||
for id := range adj {
|
||||
succ = append(succ, johnsonGraphNode(id))
|
||||
}
|
||||
return succ
|
||||
return iterator.NewOrderedNodes(succ)
|
||||
}
|
||||
|
||||
func (johnsonGraph) Has(int64) bool {
|
||||
@@ -272,7 +273,7 @@ func (johnsonGraph) Edge(_, _ int64) graph.Edge {
|
||||
func (johnsonGraph) HasEdgeFromTo(_, _ int64) bool {
|
||||
panic("topo: unintended use of johnsonGraph")
|
||||
}
|
||||
func (johnsonGraph) To(int64) []graph.Node {
|
||||
func (johnsonGraph) To(int64) graph.Nodes {
|
||||
panic("topo: unintended use of johnsonGraph")
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,9 @@ func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node {
|
||||
var cycles [][]graph.Node
|
||||
done := make(set.Int64s)
|
||||
var tree linear.NodeStack
|
||||
for _, n := range g.Nodes() {
|
||||
nodes := g.Nodes()
|
||||
for nodes.Next() {
|
||||
n := nodes.Node()
|
||||
id := n.ID()
|
||||
if done.Has(id) {
|
||||
continue
|
||||
@@ -35,7 +37,7 @@ func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node {
|
||||
u := tree.Pop()
|
||||
uid := u.ID()
|
||||
adj := from[uid]
|
||||
for _, v := range g.From(uid) {
|
||||
for _, v := range graph.NodesOf(g.From(uid)) {
|
||||
vid := v.ID()
|
||||
switch {
|
||||
case uid == vid:
|
||||
|
@@ -94,16 +94,18 @@ func TarjanSCC(g graph.Directed) [][]graph.Node {
|
||||
}
|
||||
|
||||
func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node {
|
||||
nodes := g.Nodes()
|
||||
nodes := graph.NodesOf(g.Nodes())
|
||||
var succ func(id int64) []graph.Node
|
||||
if order == nil {
|
||||
succ = g.From
|
||||
succ = func(id int64) []graph.Node {
|
||||
return graph.NodesOf(g.From(id))
|
||||
}
|
||||
} else {
|
||||
order(nodes)
|
||||
ordered.Reverse(nodes)
|
||||
|
||||
succ = func(id int64) []graph.Node {
|
||||
to := g.From(id)
|
||||
to := graph.NodesOf(g.From(id))
|
||||
order(to)
|
||||
ordered.Reverse(to)
|
||||
return to
|
||||
|
@@ -16,7 +16,7 @@ var _ Graph = graph.Graph(nil)
|
||||
type Graph interface {
|
||||
// From returns all nodes that can be reached directly
|
||||
// from the node with the given ID.
|
||||
From(id int64) []graph.Node
|
||||
From(id int64) graph.Nodes
|
||||
|
||||
// Edge returns the edge from u to v, with IDs uid and vid,
|
||||
// if such an edge exists and nil otherwise. The node v
|
||||
@@ -56,7 +56,9 @@ func (b *BreadthFirst) Walk(g Graph, from graph.Node, until func(n graph.Node, d
|
||||
return t
|
||||
}
|
||||
tid := t.ID()
|
||||
for _, n := range g.From(tid) {
|
||||
to := g.From(tid)
|
||||
for to.Next() {
|
||||
n := to.Node()
|
||||
nid := n.ID()
|
||||
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(tid, nid)) {
|
||||
continue
|
||||
@@ -87,7 +89,9 @@ func (b *BreadthFirst) Walk(g Graph, from graph.Node, until func(n graph.Node, d
|
||||
// during is called on each node as it is traversed.
|
||||
func (b *BreadthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) {
|
||||
b.Reset()
|
||||
for _, from := range g.Nodes() {
|
||||
nodes := g.Nodes()
|
||||
for nodes.Next() {
|
||||
from := nodes.Node()
|
||||
if b.Visited(from) {
|
||||
continue
|
||||
}
|
||||
@@ -143,7 +147,9 @@ func (d *DepthFirst) Walk(g Graph, from graph.Node, until func(graph.Node) bool)
|
||||
return t
|
||||
}
|
||||
tid := t.ID()
|
||||
for _, n := range g.From(tid) {
|
||||
to := g.From(tid)
|
||||
for to.Next() {
|
||||
n := to.Node()
|
||||
nid := n.ID()
|
||||
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(tid, nid)) {
|
||||
continue
|
||||
@@ -168,7 +174,9 @@ func (d *DepthFirst) Walk(g Graph, from graph.Node, until func(graph.Node) bool)
|
||||
// during is called on each node as it is traversed.
|
||||
func (d *DepthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) {
|
||||
d.Reset()
|
||||
for _, from := range g.Nodes() {
|
||||
nodes := g.Nodes()
|
||||
for nodes.Next() {
|
||||
from := nodes.Node()
|
||||
if d.Visited(from) {
|
||||
continue
|
||||
}
|
||||
|
@@ -371,7 +371,7 @@ func gnpUndirected(n int, p float64) graph.Undirected {
|
||||
}
|
||||
|
||||
func benchmarkWalkAllBreadthFirst(b *testing.B, g graph.Undirected) {
|
||||
n := len(g.Nodes())
|
||||
n := g.Nodes().Len()
|
||||
b.ResetTimer()
|
||||
var bft BreadthFirst
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -402,7 +402,7 @@ func BenchmarkWalkAllBreadthFirstGnp_1000_half(b *testing.B) {
|
||||
}
|
||||
|
||||
func benchmarkWalkAllDepthFirst(b *testing.B, g graph.Undirected) {
|
||||
n := len(g.Nodes())
|
||||
n := g.Nodes().Len()
|
||||
b.ResetTimer()
|
||||
var dft DepthFirst
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@@ -15,25 +15,11 @@ var _ Undirected = Undirect{}
|
||||
func (g Undirect) Has(id int64) bool { return g.G.Has(id) }
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g Undirect) Nodes() []Node { return g.G.Nodes() }
|
||||
func (g Undirect) Nodes() Nodes { return g.G.Nodes() }
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g Undirect) From(uid int64) []Node {
|
||||
var nodes []Node
|
||||
seen := make(map[int64]struct{})
|
||||
for _, n := range g.G.From(uid) {
|
||||
seen[n.ID()] = struct{}{}
|
||||
nodes = append(nodes, n)
|
||||
}
|
||||
for _, n := range g.G.To(uid) {
|
||||
id := n.ID()
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[n.ID()] = struct{}{}
|
||||
nodes = append(nodes, n)
|
||||
}
|
||||
return nodes
|
||||
func (g Undirect) From(uid int64) Nodes {
|
||||
return newNodeFilterIterator(g.G.From(uid), g.G.To(uid))
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -94,25 +80,11 @@ var (
|
||||
func (g UndirectWeighted) Has(id int64) bool { return g.G.Has(id) }
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g UndirectWeighted) Nodes() []Node { return g.G.Nodes() }
|
||||
func (g UndirectWeighted) Nodes() Nodes { return g.G.Nodes() }
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g UndirectWeighted) From(uid int64) []Node {
|
||||
var nodes []Node
|
||||
seen := make(map[int64]struct{})
|
||||
for _, n := range g.G.From(uid) {
|
||||
seen[n.ID()] = struct{}{}
|
||||
nodes = append(nodes, n)
|
||||
}
|
||||
for _, n := range g.G.To(uid) {
|
||||
id := n.ID()
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[n.ID()] = struct{}{}
|
||||
nodes = append(nodes, n)
|
||||
}
|
||||
return nodes
|
||||
func (g UndirectWeighted) From(uid int64) Nodes {
|
||||
return newNodeFilterIterator(g.G.From(uid), g.G.To(uid))
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
@@ -224,3 +196,54 @@ type WeightedEdgePair struct {
|
||||
|
||||
// Weight returns the merged edge weights of the two edges.
|
||||
func (e WeightedEdgePair) Weight() float64 { return e.W }
|
||||
|
||||
// nodeFilterIterator combines two Nodes to produce a single stream of
|
||||
// unique nodes.
|
||||
type nodeFilterIterator struct {
|
||||
a, b Nodes
|
||||
|
||||
// unique indicates the node in b with the key ID is unique.
|
||||
unique map[int64]bool
|
||||
}
|
||||
|
||||
func newNodeFilterIterator(a, b Nodes) *nodeFilterIterator {
|
||||
n := nodeFilterIterator{a: a, b: b, unique: make(map[int64]bool)}
|
||||
for n.b.Next() {
|
||||
n.unique[n.b.Node().ID()] = true
|
||||
}
|
||||
n.b.Reset()
|
||||
for n.a.Next() {
|
||||
n.unique[n.a.Node().ID()] = false
|
||||
}
|
||||
n.a.Reset()
|
||||
return &n
|
||||
}
|
||||
|
||||
func (n *nodeFilterIterator) Len() int {
|
||||
return len(n.unique)
|
||||
}
|
||||
|
||||
func (n *nodeFilterIterator) Next() bool {
|
||||
n.Len()
|
||||
if n.a.Next() {
|
||||
return true
|
||||
}
|
||||
for n.b.Next() {
|
||||
if n.unique[n.b.Node().ID()] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *nodeFilterIterator) Node() Node {
|
||||
if n.a.Len() != 0 {
|
||||
return n.a.Node()
|
||||
}
|
||||
return n.b.Node()
|
||||
}
|
||||
|
||||
func (n *nodeFilterIterator) Reset() {
|
||||
n.a.Reset()
|
||||
n.b.Reset()
|
||||
}
|
||||
|
@@ -121,9 +121,10 @@ func TestUndirect(t *testing.T) {
|
||||
}
|
||||
|
||||
src := graph.Undirect{G: g}
|
||||
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
|
||||
for _, u := range src.Nodes() {
|
||||
for _, v := range src.From(u.ID()) {
|
||||
nodes := graph.NodesOf(src.Nodes())
|
||||
dst := simple.NewUndirectedMatrixFrom(nodes, 0, 0, 0)
|
||||
for _, u := range nodes {
|
||||
for _, v := range graph.NodesOf(src.From(u.ID())) {
|
||||
dst.SetEdge(src.Edge(u.ID(), v.ID()))
|
||||
}
|
||||
}
|
||||
@@ -146,9 +147,10 @@ func TestUndirectWeighted(t *testing.T) {
|
||||
}
|
||||
|
||||
src := graph.UndirectWeighted{G: g, Absent: test.absent, Merge: test.merge}
|
||||
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
|
||||
for _, u := range src.Nodes() {
|
||||
for _, v := range src.From(u.ID()) {
|
||||
nodes := graph.NodesOf(src.Nodes())
|
||||
dst := simple.NewUndirectedMatrixFrom(nodes, 0, 0, 0)
|
||||
for _, u := range nodes {
|
||||
for _, v := range graph.NodesOf(src.From(u.ID())) {
|
||||
dst.SetWeightedEdge(src.WeightedEdge(u.ID(), v.ID()))
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user