Files
gonum/graph/iterator/lines_map_safe.go
Dan Kortschak 2bef024c93 graph/iterator: improve reflect-based iterators
- 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%
2024-05-24 20:49:39 +09:30

157 lines
3.9 KiB
Go

// Copyright ©2021 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"
)
// Lines implements the graph.Lines interfaces.
// The iteration order of Lines is randomized.
type Lines struct {
iter reflect.MapIter
pos, len int
curr graph.Line
value reflect.Value
lines reflect.Value
}
// NewLines returns a Lines initialized with the provided lines, a
// map of line IDs to graph.Lines. No check is made that the keys
// match the graph.Line IDs, and the map keys are not used.
//
// Behavior of the Lines is unspecified if lines is mutated after
// the call to NewLines.
func NewLines(lines map[int64]graph.Line) *Lines {
rv := reflect.ValueOf(lines)
l := &Lines{lines: rv, len: len(lines)}
l.iter.Reset(rv)
l.value = reflect.ValueOf(&l.curr).Elem()
return l
}
// Len returns the remaining number of lines to be iterated over.
func (l *Lines) Len() int {
return l.len - l.pos
}
// Next returns whether the next call of Line will return a valid line.
func (l *Lines) Next() bool {
if l.pos >= l.len {
return false
}
ok := l.iter.Next()
if ok {
l.pos++
l.value.SetIterValue(&l.iter)
}
return ok
}
// Line returns the current line of the iterator. Next must have been
// called prior to a call to Line.
func (l *Lines) Line() graph.Line {
return l.curr
}
// Reset returns the iterator to its initial state.
func (l *Lines) Reset() {
l.curr = nil
l.pos = 0
l.iter.Reset(l.lines)
}
// LineSlice returns all the remaining lines in the iterator and advances
// the iterator. The order of lines within the returned slice is not
// specified.
func (l *Lines) LineSlice() []graph.Line {
if l.Len() == 0 {
return nil
}
lines := make([]graph.Line, 0, l.Len())
for l.iter.Next() {
l.value.SetIterValue(&l.iter)
lines = append(lines, l.curr)
}
l.pos = l.len
return lines
}
// WeightedLines implements the graph.WeightedLines interfaces.
// The iteration order of WeightedLines is randomized.
type WeightedLines struct {
iter reflect.MapIter
pos, len int
curr graph.WeightedLine
value reflect.Value
lines reflect.Value
}
// NewWeightedLines returns a WeightedLines initialized with the provided lines, a
// map of line IDs to graph.WeightedLines. No check is made that the keys
// match the graph.WeightedLine IDs, and the map keys are not used.
//
// Behavior of the WeightedLines is unspecified if lines is mutated after
// the call to NewWeightedLines.
func NewWeightedLines(lines map[int64]graph.WeightedLine) *WeightedLines {
rv := reflect.ValueOf(lines)
l := &WeightedLines{lines: rv, len: len(lines)}
l.iter.Reset(rv)
l.value = reflect.ValueOf(&l.curr).Elem()
return l
}
// Len returns the remaining number of lines to be iterated over.
func (l *WeightedLines) Len() int {
return l.len - l.pos
}
// Next returns whether the next call of WeightedLine will return a valid line.
func (l *WeightedLines) Next() bool {
if l.pos >= l.len {
return false
}
ok := l.iter.Next()
if ok {
l.pos++
l.value.SetIterValue(&l.iter)
}
return ok
}
// WeightedLine returns the current line of the iterator. Next must have been
// called prior to a call to WeightedLine.
func (l *WeightedLines) WeightedLine() graph.WeightedLine {
return l.curr
}
// Reset returns the iterator to its initial state.
func (l *WeightedLines) Reset() {
l.curr = nil
l.pos = 0
l.iter.Reset(l.lines)
}
// WeightedLineSlice returns all the remaining lines in the iterator and advances
// the iterator. The order of lines within the returned slice is not
// specified.
func (l *WeightedLines) WeightedLineSlice() []graph.WeightedLine {
if l.Len() == 0 {
return nil
}
lines := make([]graph.WeightedLine, 0, l.Len())
for l.iter.Next() {
l.value.SetIterValue(&l.iter)
lines = append(lines, l.curr)
}
l.pos = l.len
return lines
}