This repository has been archived by the owner on Aug 30, 2019. It is now read-only.
/
weighted.go
84 lines (70 loc) · 1.86 KB
/
weighted.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
72
73
74
75
76
77
78
79
80
81
82
83
84
package quantile
import (
"math"
"math/rand"
)
var randomFloats []float64
func init() {
// generate a list of guaranteed random numbers for the probabilistic round
randomFloats = make([]float64, 100)
r := rand.New(rand.NewSource(7337))
for i := 0; i < 100; i++ {
randomFloats[i] = r.Float64()
}
}
// WeightedSliceSummary associates a weight to a slice summary.
type WeightedSliceSummary struct {
Weight float64
*SliceSummary
}
func probabilisticRound(g int, weight float64, randFloat func() float64) int {
raw := weight * float64(g)
decimal := raw - math.Floor(raw)
limit := randFloat()
iraw := int(raw)
if limit > decimal {
iraw++
}
return iraw
}
// WeighSummary applies a weight factor to a slice summary and return it as a
// new slice.
func WeighSummary(s *SliceSummary, weight float64) *SliceSummary {
// Deterministic random number generation based on a list because rand.Seed
// is expensive to run
i := 0
randFloat := func() float64 {
i++
return randomFloats[i%len(randomFloats)]
}
sw := NewSliceSummary()
sw.Entries = make([]Entry, 0, len(s.Entries))
gsum := 0
for _, e := range s.Entries {
newg := probabilisticRound(e.G, weight, randFloat)
// if an entry is down to 0 delete it
if newg != 0 {
sw.Entries = append(sw.Entries,
Entry{V: e.V, G: newg, Delta: e.Delta},
)
gsum += newg
}
}
sw.N = gsum
return sw
}
// BySlicesWeighted BySlices() is the BySlices version but combines multiple
// weighted slice summaries before returning the histogram
func BySlicesWeighted(summaries ...WeightedSliceSummary) []SummarySlice {
if len(summaries) == 0 {
return []SummarySlice{}
}
mergeSummary := WeighSummary(summaries[0].SliceSummary, summaries[0].Weight)
if len(summaries) > 1 {
for _, s := range summaries[1:] {
sw := WeighSummary(s.SliceSummary, s.Weight)
mergeSummary.Merge(sw)
}
}
return mergeSummary.BySlices()
}