...
1 package growthbook
2
3
4 type Range struct {
5 Min float64
6 Max float64
7 }
8
9 func (r *Range) InRange(n float64) bool {
10 return n >= r.Min && n < r.Max
11 }
12
13
14
15 func getBucketRanges(numVariations int, coverage float64, weights []float64) []Range {
16
17 if coverage < 0 {
18 logWarn("Experiment coverage must be greater than or equal to 0")
19 coverage = 0
20 }
21 if coverage > 1 {
22 logWarn("Experiment coverage must be less than or equal to 1")
23 coverage = 1
24 }
25
26
27 if weights == nil || len(weights) == 0 {
28 weights = getEqualWeights(numVariations)
29 }
30 if len(weights) != numVariations {
31 logWarn("Experiment weights and variations arrays must be the same length")
32 weights = getEqualWeights(numVariations)
33 }
34
35
36 totalWeight := 0.0
37 for i := range weights {
38 totalWeight += weights[i]
39 }
40 if totalWeight < 0.99 || totalWeight > 1.01 {
41 logWarn("Experiment weights must add up to 1")
42 weights = getEqualWeights(numVariations)
43 }
44
45
46 cumulative := 0.0
47 ranges := make([]Range, len(weights))
48 for i := range weights {
49 start := cumulative
50 cumulative += weights[i]
51 ranges[i] = Range{start, start + coverage*weights[i]}
52 }
53 return ranges
54 }
55
56
57 func chooseVariation(n float64, ranges []Range) int {
58 for i := range ranges {
59 if ranges[i].InRange(n) {
60 return i
61 }
62 }
63 return -1
64 }
65
66 func jsonRange(v interface{}, typeName string, fieldName string) (*Range, bool) {
67 vals, ok := jsonFloatArray(v, typeName, fieldName)
68 if !ok || vals == nil || len(vals) != 2 {
69 logError("Invalid JSON data type", typeName, fieldName)
70 return nil, false
71 }
72 return &Range{vals[0], vals[1]}, true
73 }
74
75 func jsonRangeArray(v interface{}, typeName string, fieldName string) ([]Range, bool) {
76 vals, ok := v.([]interface{})
77 if !ok {
78 logError("Invalid JSON data type", typeName, fieldName)
79 return nil, false
80 }
81 ranges := make([]Range, len(vals))
82 for i := range vals {
83 tmp, ok := jsonRange(vals[i], typeName, fieldName)
84 if !ok || tmp == nil {
85 return nil, false
86 }
87 ranges[i] = *tmp
88 }
89 return ranges, true
90 }
91
View as plain text