Remove fenwick tree
- Id
- 320f2503f4739951db868159a3a3d87036aa2c57
- Author
- Vladimir Mihailenco
- Commit time
- 2018-11-08T12:26:17+02:00
Modified summary.go
package tdigest
import (
"fmt"
"math"
"sort"
-
- "github.com/caio/go-tdigest/internal/fenwick"
)
type summary struct {
- initialCapacity int
- means []float64
- counts []uint32
- bitree *fenwick.List
+ means []float64
+ counts []uint32
}
func newSummary(initialCapacity int) *summary {
s := &summary{
- initialCapacity: initialCapacity,
- means: make([]float64, 0, initialCapacity),
- counts: make([]uint32, 0, initialCapacity),
+ means: make([]float64, 0, initialCapacity),
+ counts: make([]uint32, 0, initialCapacity),
}
- s.rebuildFenwickTree(-1)
return s
}
s.means[idx] = key
s.counts[idx] = value
- s.rebuildFenwickTree(idx)
-
return nil
-}
-
-func (s *summary) rebuildFenwickTree(idx int) {
- if !s.useFenwickTree() {
- return
- }
-
- if s.bitree == nil || s.bitree.Len() < len(s.counts) {
- s.bitree = fenwick.New(s.counts[:cap(s.counts)]...)
- return
- }
-
- for i := idx; i < len(s.counts); i++ {
- s.bitree.Set(i, s.counts[i])
- }
-}
-
-func (s *summary) useFenwickTree() bool {
- return s.initialCapacity > 100 && len(s.counts) >= s.initialCapacity
}
func (s summary) Floor(x float64) int {
// This method is the hotspot when calling Add(), which in turn is called by
// Compress() and Merge().
func (s summary) HeadSum(idx int) (sum float64) {
- if s.bitree != nil {
- return float64(s.bitree.Sum(idx))
- }
return float64(sumUntilIndex(s.counts, idx))
}
s.counts[index] = count
s.adjustRight(index)
s.adjustLeft(index)
- if s.bitree != nil {
- s.bitree.Set(index, count)
- }
}
func (s *summary) adjustRight(index int) {
Modified tdigest.go
// Clone returns a deep copy of a TDigest.
func (t *TDigest) Clone() *TDigest {
- summary := t.summary.Clone()
- summary.rebuildFenwickTree(-1)
return &TDigest{
- summary: summary,
+ summary: t.summary.Clone(),
compression: t.compression,
count: t.count,
rng: t.rng,
Modified tdigest_test.go
"sort"
"testing"
- "github.com/caio/go-tdigest/internal/fenwick"
"github.com/leesper/go_rng"
"gonum.org/v1/gonum/stat"
)
count: 1250,
rng: &globalRNG{},
}
- td.summary.rebuildFenwickTree(-1)
if cdf := td.CDF(7.144560976650238e+06); cdf > 1 {
t.Fatalf("invalid: %v", cdf)
}
var sumSizes = []int{10, 100, 1000, 10000}
-
-func BenchmarkSumFenwickTree(b *testing.B) {
- for _, size := range sumSizes {
- size := size
- b.Run(fmt.Sprint(size), func(b *testing.B) {
- benchmarkSumFenwickTree(b, size)
- })
- }
-}
-
-func benchmarkSumFenwickTree(b *testing.B, size int) {
- counts := generateCounts(size)
- indexes := generateIndexes(size)
- tree := fenwick.New(counts...)
-
- b.ReportAllocs()
- b.ResetTimer()
- for n := 0; n < b.N; n++ {
- for _, idx := range indexes {
- _ = tree.Sum(idx)
- }
- }
-}
func BenchmarkSumLoopSimple(b *testing.B) {
for _, size := range sumSizes {
Deleted internal/fenwick/LICENSE
-BSD 2-Clause License
-
-Copyright (c) 2017, Stefan Nilsson
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Deleted internal/fenwick/README.md
-This is https://github.com/yourbasic/fenwick with int64 replaced with uint32 to avoid constructing temporary []int64 slice just for the lib.
Deleted internal/fenwick/list.go
-// Package fenwick provides a list data structure supporting prefix sums.
-//
-// A Fenwick tree, or binary indexed tree, is a space-efficient list
-// data structure that can efficiently update elements and calculate
-// prefix sums in a list of numbers.
-//
-// Compared to a common array, a Fenwick tree achieves better balance
-// between element update and prefix sum calculation – both operations
-// run in O(log n) time – while using the same amount of memory.
-// This is achieved by representing the list as an implicit tree,
-// where the value of each node is the sum of the numbers in that
-// subtree.
-//
-package fenwick
-
-// List represents a list of numbers with support for efficient
-// prefix sum computation. The zero value is an empty list.
-type List struct {
- // The tree slice stores range sums of an underlying array t.
- // To compute the prefix sum t[0] + t[1] + t[k-1], add elements
- // which correspond to each 1 bit in the binary expansion of k.
- //
- // For example, this is how the sum of the 13 first elements
- // in t is computed: 13 is 1101₂ in binary, so the elements
- // at indices 1101₂ - 1, 1100₂ - 1, and 1000₂ - 1 are added;
- // they contain the range sums t[12], t[8] + … t[11], and
- // t[0] + … + t[7], respectively.
- //
- tree []uint32
-}
-
-// New creates a new list with the given elements.
-func New(n ...uint32) *List {
- len := len(n)
- t := make([]uint32, len)
- copy(t, n)
- for i := range t {
- if j := i | (i + 1); j < len {
- t[j] += t[i]
- }
- }
- return &List{
- tree: t,
- }
-}
-
-// Len returns the number of elements in the list.
-func (l *List) Len() int {
- return len(l.tree)
-}
-
-// Get returns the element at index i.
-func (l *List) Get(i int) uint32 {
- sum := l.tree[i]
- j := i + 1
- j -= j & -j
- for i > j {
- sum -= l.tree[i-1]
- i -= i & -i
- }
- return sum
-}
-
-// Set sets the element at index i to n.
-func (l *List) Set(i int, n uint32) {
- n -= l.Get(i)
- for len := len(l.tree); i < len; i |= i + 1 {
- l.tree[i] += n
- }
-}
-
-// Add adds n to the element at index i.
-func (l *List) Add(i int, n uint32) {
- for len := len(l.tree); i < len; i |= i + 1 {
- l.tree[i] += n
- }
-}
-
-// Sum returns the sum of the elements from index 0 to index i-1.
-func (l *List) Sum(i int) uint32 {
- var sum uint32
- for i > 0 {
- sum += l.tree[i-1]
- i -= i & -i
- }
- return sum
-}
-
-// SumRange returns the sum of the elements from index i to index j-1.
-func (l *List) SumRange(i, j int) uint32 {
- var sum uint32
- for j > i {
- sum += l.tree[j-1]
- j -= j & -j
- }
- for i > j {
- sum -= l.tree[i-1]
- i -= i & -i
- }
- return sum
-}
-
-// Append appends a new element to the end of the list.
-func (l *List) Append(n uint32) {
- i := len(l.tree)
- l.tree = append(l.tree, 0)
- l.tree[i] = n - l.Get(i)
-}