mirror of
https://github.com/gonum/gonum.git
synced 2025-10-05 23:26:52 +08:00

- use SetIterValue to reduce allocations - use explicit stored iterator length goos: linux goarch: amd64 pkg: gonum.org/v1/gonum/graph/traverse cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz │ old.bench │ new.bench │ │ sec/op │ sec/op vs base │ WalkAllBreadthFirstGnp_10_tenth-8 3.575µ ± 2% 2.961µ ± 2% -17.18% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_tenth-8 144.4µ ± 1% 132.4µ ± 1% -8.33% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_tenth-8 12.66m ± 2% 12.00m ± 2% -5.20% (p=0.000 n=20) WalkAllBreadthFirstGnp_10_half-8 8.415µ ± 1% 7.615µ ± 1% -9.51% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_half-8 628.0µ ± 1% 580.7µ ± 1% -7.54% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_half-8 58.74m ± 1% 55.79m ± 2% -5.03% (p=0.000 n=20) WalkAllDepthFirstGnp_10_tenth-8 3.539µ ± 2% 2.956µ ± 1% -16.49% (p=0.000 n=20) WalkAllDepthFirstGnp_100_tenth-8 144.8µ ± 2% 135.5µ ± 1% -6.40% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_tenth-8 12.40m ± 1% 12.02m ± 1% -3.10% (p=0.000 n=20) WalkAllDepthFirstGnp_10_half-8 8.210µ ± 1% 7.423µ ± 1% -9.59% (p=0.000 n=20) WalkAllDepthFirstGnp_100_half-8 625.8µ ± 1% 598.3µ ± 1% -4.40% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_half-8 58.28m ± 1% 55.65m ± 1% -4.52% (p=0.000 n=20) geomean 353.9µ 324.8µ -8.21% │ old.bench │ new.bench │ │ B/op │ B/op vs base │ WalkAllBreadthFirstGnp_10_tenth-8 1.533Ki ± 0% 1.486Ki ± 0% -3.06% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_tenth-8 29.58Ki ± 0% 29.61Ki ± 0% +0.11% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_tenth-8 1016.3Ki ± 0% 1016.4Ki ± 0% ~ (p=0.199 n=20) WalkAllBreadthFirstGnp_10_half-8 2.689Ki ± 0% 2.721Ki ± 0% +1.16% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_half-8 61.44Ki ± 0% 61.47Ki ± 0% +0.05% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_half-8 4.036Mi ± 0% 4.036Mi ± 0% ~ (p=0.080 n=20) WalkAllDepthFirstGnp_10_tenth-8 1.533Ki ± 0% 1.486Ki ± 0% -3.06% (p=0.000 n=20) WalkAllDepthFirstGnp_100_tenth-8 29.58Ki ± 0% 29.61Ki ± 0% +0.10% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_tenth-8 1.090Mi ± 1% 1.084Mi ± 1% ~ (p=0.081 n=20) WalkAllDepthFirstGnp_10_half-8 2.689Ki ± 0% 2.721Ki ± 0% +1.16% (p=0.000 n=20) WalkAllDepthFirstGnp_100_half-8 61.57Ki ± 0% 61.59Ki ± 0% +0.04% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_half-8 6.279Mi ± 0% 6.167Mi ± 0% -1.79% (p=0.000 n=20) geomean 58.77Ki 58.48Ki -0.49% │ old.bench │ new.bench │ │ allocs/op │ allocs/op vs base │ WalkAllBreadthFirstGnp_10_tenth-8 27.00 ± 0% 17.00 ± 0% -37.04% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_tenth-8 1.188k ± 0% 1.088k ± 0% -8.42% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_tenth-8 102.1k ± 0% 101.1k ± 0% -0.98% (p=0.000 n=20) WalkAllBreadthFirstGnp_10_half-8 70.00 ± 0% 60.00 ± 0% -14.29% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_half-8 5.266k ± 0% 5.166k ± 0% -1.90% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_half-8 500.9k ± 0% 499.9k ± 0% -0.20% (p=0.000 n=20) WalkAllDepthFirstGnp_10_tenth-8 27.00 ± 0% 17.00 ± 0% -37.04% (p=0.000 n=20) WalkAllDepthFirstGnp_100_tenth-8 1.188k ± 0% 1.088k ± 0% -8.42% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_tenth-8 102.1k ± 0% 101.1k ± 0% -0.98% (p=0.000 n=20) WalkAllDepthFirstGnp_10_half-8 70.00 ± 0% 60.00 ± 0% -14.29% (p=0.000 n=20) WalkAllDepthFirstGnp_100_half-8 5.266k ± 0% 5.166k ± 0% -1.90% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_half-8 500.9k ± 0% 499.9k ± 0% -0.20% (p=0.000 n=20) geomean 2.908k 2.572k -11.54%
207 lines
6.0 KiB
Go
207 lines
6.0 KiB
Go
// 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.
|
|
|
|
//go:build safe
|
|
// +build safe
|
|
|
|
package iterator
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"gonum.org/v1/gonum/graph"
|
|
)
|
|
|
|
// Nodes implements the graph.Nodes interfaces.
|
|
// The iteration order of Nodes is randomized.
|
|
type Nodes struct {
|
|
iter reflect.MapIter
|
|
pos, len int
|
|
curr graph.Node
|
|
value reflect.Value
|
|
nodes reflect.Value
|
|
}
|
|
|
|
// NewNodes returns a Nodes initialized with the provided nodes, a
|
|
// map of node IDs to graph.Nodes. No check is made that the keys
|
|
// match the graph.Node IDs, and the map keys are not used.
|
|
//
|
|
// Behavior of the Nodes is unspecified if nodes is mutated after
|
|
// the call to NewNodes.
|
|
func NewNodes(nodes map[int64]graph.Node) *Nodes {
|
|
rv := reflect.ValueOf(nodes)
|
|
n := &Nodes{nodes: rv, len: len(nodes)}
|
|
n.iter.Reset(rv)
|
|
n.value = reflect.ValueOf(&n.curr).Elem()
|
|
return n
|
|
}
|
|
|
|
// Len returns the remaining number of nodes to be iterated over.
|
|
func (n *Nodes) Len() int {
|
|
return n.len - n.pos
|
|
}
|
|
|
|
// Next returns whether the next call of Node will return a valid node.
|
|
func (n *Nodes) Next() bool {
|
|
if n.pos >= n.len {
|
|
return false
|
|
}
|
|
ok := n.iter.Next()
|
|
if ok {
|
|
n.pos++
|
|
n.value.SetIterValue(&n.iter)
|
|
}
|
|
return ok
|
|
}
|
|
|
|
// Node returns the current node of the iterator. Next must have been
|
|
// called prior to a call to Node.
|
|
func (n *Nodes) Node() graph.Node {
|
|
return n.curr
|
|
}
|
|
|
|
// Reset returns the iterator to its initial state.
|
|
func (n *Nodes) Reset() {
|
|
n.curr = nil
|
|
n.pos = 0
|
|
n.iter.Reset(n.nodes)
|
|
}
|
|
|
|
// NodeSlice returns all the remaining nodes in the iterator and advances
|
|
// the iterator. The order of nodes within the returned slice is not
|
|
// specified.
|
|
func (n *Nodes) NodeSlice() []graph.Node {
|
|
if n.Len() == 0 {
|
|
return nil
|
|
}
|
|
nodes := make([]graph.Node, 0, n.Len())
|
|
for n.iter.Next() {
|
|
n.value.SetIterValue(&n.iter)
|
|
nodes = append(nodes, n.curr)
|
|
}
|
|
n.pos = n.len
|
|
return nodes
|
|
}
|
|
|
|
// NodesByEdge implements the graph.Nodes interfaces.
|
|
// The iteration order of Nodes is randomized.
|
|
type NodesByEdge struct {
|
|
iter reflect.MapIter
|
|
pos, len int
|
|
edges reflect.Value
|
|
curr graph.Node
|
|
nodes map[int64]graph.Node
|
|
}
|
|
|
|
// NewNodesByEdge returns a NodesByEdge initialized with the
|
|
// provided nodes, a map of node IDs to graph.Nodes, and the set
|
|
// of edges, a map of to-node IDs to graph.Edge, that can be
|
|
// traversed to reach the nodes that the NodesByEdge will iterate
|
|
// over. No check is made that the keys match the graph.Node IDs,
|
|
// and the map keys are not used.
|
|
//
|
|
// Behavior of the NodesByEdge is unspecified if nodes or edges
|
|
// is mutated after the call to NewNodes.
|
|
func NewNodesByEdge(nodes map[int64]graph.Node, edges map[int64]graph.Edge) *NodesByEdge {
|
|
rv := reflect.ValueOf(edges)
|
|
n := &NodesByEdge{nodes: nodes, len: len(edges), edges: rv}
|
|
n.iter.Reset(rv)
|
|
return n
|
|
}
|
|
|
|
// NewNodesByWeightedEdge returns a NodesByEdge initialized with the
|
|
// provided nodes, a map of node IDs to graph.Nodes, and the set
|
|
// of edges, a map of to-node IDs to graph.WeightedEdge, that can be
|
|
// traversed to reach the nodes that the NodesByEdge will iterate
|
|
// over. No check is made that the keys match the graph.Node IDs,
|
|
// and the map keys are not used.
|
|
//
|
|
// Behavior of the NodesByEdge is unspecified if nodes or edges
|
|
// is mutated after the call to NewNodes.
|
|
func NewNodesByWeightedEdge(nodes map[int64]graph.Node, edges map[int64]graph.WeightedEdge) *NodesByEdge {
|
|
rv := reflect.ValueOf(edges)
|
|
n := &NodesByEdge{nodes: nodes, len: len(edges), edges: rv}
|
|
n.iter.Reset(rv)
|
|
return n
|
|
}
|
|
|
|
// NewNodesByLines returns a NodesByEdge initialized with the
|
|
// provided nodes, a map of node IDs to graph.Nodes, and the set
|
|
// of lines, a map to-node IDs to map of graph.Line, that can be
|
|
// traversed to reach the nodes that the NodesByEdge will iterate
|
|
// over. No check is made that the keys match the graph.Node IDs,
|
|
// and the map keys are not used.
|
|
//
|
|
// Behavior of the NodesByEdge is unspecified if nodes or lines
|
|
// is mutated after the call to NewNodes.
|
|
func NewNodesByLines(nodes map[int64]graph.Node, lines map[int64]map[int64]graph.Line) *NodesByEdge {
|
|
rv := reflect.ValueOf(lines)
|
|
n := &NodesByEdge{nodes: nodes, len: len(lines), edges: rv}
|
|
n.iter.Reset(rv)
|
|
return n
|
|
}
|
|
|
|
// NewNodesByWeightedLines returns a NodesByEdge initialized with the
|
|
// provided nodes, a map of node IDs to graph.Nodes, and the set
|
|
// of lines, a map to-node IDs to map of graph.WeightedLine, that can be
|
|
// traversed to reach the nodes that the NodesByEdge will iterate
|
|
// over. No check is made that the keys match the graph.Node IDs,
|
|
// and the map keys are not used.
|
|
//
|
|
// Behavior of the NodesByEdge is unspecified if nodes or lines
|
|
// is mutated after the call to NewNodes.
|
|
func NewNodesByWeightedLines(nodes map[int64]graph.Node, lines map[int64]map[int64]graph.WeightedLine) *NodesByEdge {
|
|
rv := reflect.ValueOf(lines)
|
|
n := &NodesByEdge{nodes: nodes, len: len(lines), edges: rv}
|
|
n.iter.Reset(rv)
|
|
return n
|
|
}
|
|
|
|
// Len returns the remaining number of nodes to be iterated over.
|
|
func (n *NodesByEdge) Len() int {
|
|
return n.len - n.pos
|
|
}
|
|
|
|
// Next returns whether the next call of Node will return a valid node.
|
|
func (n *NodesByEdge) Next() bool {
|
|
if n.pos >= n.len {
|
|
return false
|
|
}
|
|
ok := n.iter.Next()
|
|
if ok {
|
|
n.pos++
|
|
n.curr = n.nodes[n.iter.Key().Int()]
|
|
}
|
|
return ok
|
|
}
|
|
|
|
// Node returns the current node of the iterator. Next must have been
|
|
// called prior to a call to Node.
|
|
func (n *NodesByEdge) Node() graph.Node {
|
|
return n.curr
|
|
}
|
|
|
|
// Reset returns the iterator to its initial state.
|
|
func (n *NodesByEdge) Reset() {
|
|
n.curr = nil
|
|
n.pos = 0
|
|
n.iter.Reset(n.edges)
|
|
}
|
|
|
|
// NodeSlice returns all the remaining nodes in the iterator and advances
|
|
// the iterator. The order of nodes within the returned slice is not
|
|
// specified.
|
|
func (n *NodesByEdge) NodeSlice() []graph.Node {
|
|
if n.Len() == 0 {
|
|
return nil
|
|
}
|
|
nodes := make([]graph.Node, 0, n.Len())
|
|
for n.iter.Next() {
|
|
n.curr = n.nodes[n.iter.Key().Int()]
|
|
nodes = append(nodes, n.curr)
|
|
}
|
|
n.pos = n.len
|
|
return nodes
|
|
}
|