-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathweight_sampler.go
More file actions
55 lines (45 loc) · 1.22 KB
/
weight_sampler.go
File metadata and controls
55 lines (45 loc) · 1.22 KB
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
package mutator
import (
"math/rand"
"google.golang.org/protobuf/reflect/protoreflect"
)
const defaultMutateWeight = 1000000
type mutateSample struct {
mutate func(message protoreflect.Message, field protoreflect.FieldDescriptor) error
message protoreflect.Message
field protoreflect.FieldDescriptor
}
// Algorithm pick one item from the sequence of weighted items.
// https://en.wikipedia.org/wiki/Reservoir_sampling#Algorithm_A-Chao
//
// Example:
//
// weightedReservoirSampler sampler;
// for(int i = 0; i < size; i++)
// sampler.Pick(weight[i], i);
// return sampler.Value();
func newWeightedReservoirSampler(src *rand.Rand) *weightedReservoirSampler {
return &weightedReservoirSampler{
src: src,
}
}
type weightedReservoirSampler struct {
TotalWeight int
src *rand.Rand
selected *mutateSample
}
func (w *weightedReservoirSampler) Value() *mutateSample {
return w.selected
}
func (w *weightedReservoirSampler) pick(weight int) bool {
if weight == 0 {
return false
}
w.TotalWeight += weight
return weight == w.TotalWeight || getRandomRange(w.src, w.TotalWeight) <= weight
}
func (w *weightedReservoirSampler) Try(value mutateSample) {
if w.pick(defaultMutateWeight) {
w.selected = &value
}
}