-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsketch.go
71 lines (57 loc) · 1.18 KB
/
sketch.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package pcsa
import (
"math"
"math/bits"
"github.com/dgryski/go-metro"
)
const (
phi = 0.77350
kappa = 1.4
)
// Sketch ...
type Sketch struct {
b uint8
m uint64
bitmaps *TailCutBitmap
}
// New ...
func New(b uint8) (*Sketch, error) {
m := uint64(1) << b
return &Sketch{
b: b,
m: m,
bitmaps: NewTailCutBitmap(m),
}, nil
}
// NewDefault ...
func NewDefault() *Sketch {
sk, _ := New(14)
return sk
}
// Add ...
func (sk *Sketch) Add(val []byte) {
sk.AddHash(metro.Hash64(val, 1337))
}
// AddHash ...
func (sk *Sketch) AddHash(x uint64) {
idx := x >> (64 - sk.b)
lz := bits.TrailingZeros64(x)
sk.bitmaps.Flip(idx, uint8(lz))
}
func (sk *Sketch) sum() uint64 {
sum := uint64(0)
for i := uint64(0); i < sk.m; i++ {
sum += uint64(sk.bitmaps.LZ(i))
}
// TODO: We are always over estimating, so I am trying to subtract something based on our current base
//sum -= 1 << sk.bitmaps.base
return sum
}
// Cardinality ...
func (sk *Sketch) Cardinality() uint64 {
sum := float64(sk.sum())
m := float64(sk.m)
// TODO: Trying another correction here
res := m/phi*(math.Pow(2, float64(sum)/m)) - math.Pow(2, -kappa*sum/m)
return uint64(res + 0.5)
}