-
Notifications
You must be signed in to change notification settings - Fork 0
/
random_bofry.go
202 lines (177 loc) · 5.91 KB
/
random_bofry.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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package random
import (
"math/rand"
)
// Uint64n returns a non-negative pseudo-random uint64 value in [0, n).
// Panics if n <= 0.
func (r *Random) Uint64n(n uint64) uint64 {
if n <= 0 {
panic("invalid argument to Uint64n")
}
return r.rand.Uint64() % n
}
// Uint32n returns a non-negative pseudo-random uint32 value in [0, n).
// Panics if n <= 0.
func (r *Random) Uint32n(n uint32) uint32 {
if n <= 0 {
panic("invalid argument to Uint32n")
}
return r.rand.Uint32() % n
}
// Float64n returns a pseudo-random float64 value in [0.0, n).
func (r *Random) Float64n(n float64) float64 {
return n * r.rand.Float64()
}
// Float32n returns a pseudo-random float32 value in [0.0, n).
// Panics if n <= 0.
func (r *Random) Float32n(n float32) float32 {
if n <= 0 {
panic("invalid argument to Float32n")
}
return n * r.rand.Float32()
}
// ----------------------------------------------------------------------------
// Weighted Random Selection
// ----------------------------------------------------------------------------
// Float64w randomly picks an index in the range [0, len(w)-1] based on the weights in slice w.
// The probability of picking index i is w[i] / sum(w).
// Panics if w is empty or contains non-positive values.
func (r *Random) Float64w(w []float64) int {
return weightedRandomIndexFloat64(r.rand, w)
}
// Float32w randomly picks an index in the range [0, len(w)-1] based on the weights in slice w.
// The probability of picking index i is w[i] / sum(w).
// Panics if w is empty or contains non-positive values.
func (r *Random) Float32w(w []float32) int {
return weightedRandomIndexFloat32(r.rand, w)
}
// Uint64w randomly picks an index in the range [0, len(w)-1] based on the weights in slice w.
// The probability of picking index i is w[i] / sum(w).
// Panics if w is empty.
func (r *Random) Uint64w(w []uint64) int {
return weightedRandomIndexUint64(r.rand, w)
}
// Uint32w randomly picks an index in the range [0, len(w)-1] based on the weights in slice w.
// The probability of picking index i is w[i] / sum(w).
// Panics if w is empty.
func (r *Random) Uint32w(w []uint32) int {
return weightedRandomIndexUint32(r.rand, w)
}
// Int64w randomly picks an index in the range [0, len(w)-1] based on the weights in slice w.
// The probability of picking index i is w[i] / sum(w).
// Panics if w is empty or contains non-positive values.
func (r *Random) Int64w(w []int64) int {
return weightedRandomIndexInt64(r.rand, w)
}
// Int32w randomly picks an index in the range [0, len(w)-1] based on the weights in slice w.
// The probability of picking index i is w[i] / sum(w).
// Panics if w is empty or contains non-positive values.
func (r *Random) Int32w(w []int32) int {
return weightedRandomIndexInt32(r.rand, w)
}
// Intw randomly picks an index in the range [0, len(w)-1] based on the weights in slice w.
// The probability of picking index i is w[i] / sum(w).
// Panics if w is empty or contains non-positive values.
func (r *Random) Intw(w []int) int {
return weightedRandomIndexInt(r.rand, w)
}
// weightedRandomIndexFloat64 selects a random index based on float64 weights.
func weightedRandomIndexFloat64(rng *rand.Rand, weights []float64) int {
if len(weights) == 0 {
panic("empty weights slice")
}
if len(weights) == 1 {
return 0
}
var totalWeight float64
for _, w := range weights {
if w <= 0 {
panic("weights must be positive")
}
totalWeight += w
}
target := rng.Float64() * totalWeight
for i, w := range weights {
if target < w {
return i
}
target -= w
}
return len(weights) - 1 // Should not reach here if weights are valid
}
// weightedRandomIndexFloat32 selects a random index based on float32 weights.
func weightedRandomIndexFloat32(rng *rand.Rand, weights []float32) int {
// Convert float32 weights to float64
weights64 := make([]float64, len(weights))
for i, w := range weights {
weights64[i] = float64(w)
}
return weightedRandomIndexFloat64(rng, weights64)
}
// weightedRandomIndexUint64 selects a random index based on uint64 weights.
func weightedRandomIndexUint64(rng *rand.Rand, weights []uint64) int {
if len(weights) == 0 {
panic("empty weights slice")
}
if len(weights) == 1 {
return 0
}
var totalWeight uint64
for _, w := range weights {
totalWeight += w
}
// Scale random value to the total weight range
target := rng.Uint64() % totalWeight
for i, w := range weights {
if target < w {
return i
}
target -= w
}
return len(weights) - 1 // Should not reach here if weights are valid
}
// weightedRandomIndexUint32 selects a random index based on uint32 weights.
func weightedRandomIndexUint32(rng *rand.Rand, weights []uint32) int {
// Convert uint32 weights to uint64
weights64 := make([]uint64, len(weights))
for i, w := range weights {
weights64[i] = uint64(w)
}
return weightedRandomIndexUint64(rng, weights64)
}
// weightedRandomIndexInt64 selects a random index based on int64 weights.
func weightedRandomIndexInt64(rng *rand.Rand, weights []int64) int {
// Convert int64 weights to float64
weightsF64 := make([]float64, len(weights))
for i, w := range weights {
if w < 0 {
panic("weights must be positive")
}
weightsF64[i] = float64(w)
}
return weightedRandomIndexFloat64(rng, weightsF64)
}
// weightedRandomIndexInt32 selects a random index based on int32 weights.
func weightedRandomIndexInt32(rng *rand.Rand, weights []int32) int {
// Convert int32 weights to int64
weights64 := make([]int64, len(weights))
for i, w := range weights {
if w < 0 {
panic("weights must be positive")
}
weights64[i] = int64(w)
}
return weightedRandomIndexInt64(rng, weights64)
}
// weightedRandomIndexInt selects a random index based on int weights.
func weightedRandomIndexInt(rng *rand.Rand, weights []int) int {
// Convert int weights to float64
weightsF64 := make([]float64, len(weights))
for i, w := range weights {
if w < 0 {
panic("weights must be positive")
}
weightsF64[i] = float64(w)
}
return weightedRandomIndexFloat64(rng, weightsF64)
}