forked from hagen1778/tsbs
-
Notifications
You must be signed in to change notification settings - Fork 5
/
distribution.go
165 lines (135 loc) · 4.49 KB
/
distribution.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
package common
import (
"math"
"math/rand"
)
// Distribution provides an interface to model a statistical distribution.
type Distribution interface {
Advance()
Get() float64 // should be idempotent
}
// NormalDistribution models a normal distribution (stateless).
type NormalDistribution struct {
Mean float64
StdDev float64
value float64
}
// ND creates a new normal distribution with the given mean/stddev
func ND(mean, stddev float64) *NormalDistribution {
return &NormalDistribution{Mean: mean, StdDev: stddev}
}
// Advance advances this distribution. Since the distribution is
// stateless, this just overwrites the internal cache value.
func (d *NormalDistribution) Advance() {
d.value = rand.NormFloat64()*d.StdDev + d.Mean
}
// Get returns the last computed value for this distribution.
func (d *NormalDistribution) Get() float64 {
return d.value
}
// UniformDistribution models a uniform distribution (stateless).
type UniformDistribution struct {
Low float64
High float64
value float64
}
// UD creates a new uniform distribution with the given range
func UD(low, high float64) *UniformDistribution {
return &UniformDistribution{Low: low, High: high}
}
// Advance advances this distribution. Since the distribution is
// stateless, this just overwrites the internal cache value.
func (d *UniformDistribution) Advance() {
x := rand.Float64() // uniform
x *= d.High - d.Low
x += d.Low
d.value = x
}
// Get returns the last computed value for this distribution.
func (d *UniformDistribution) Get() float64 {
return d.value
}
// RandomWalkDistribution is a stateful random walk. Initialize it with an
// underlying distribution, which is used to compute the new step value.
type RandomWalkDistribution struct {
Step Distribution
State float64 // optional
}
// WD creates a new RandomWalkDistribution based on a given distribution and starting state
func WD(step Distribution, state float64) *RandomWalkDistribution {
return &RandomWalkDistribution{Step: step, State: state}
}
// Advance computes the next value of this distribution and stores it.
func (d *RandomWalkDistribution) Advance() {
d.Step.Advance()
d.State += d.Step.Get()
}
// Get returns the last computed value for this distribution.
func (d *RandomWalkDistribution) Get() float64 {
return d.State
}
// ClampedRandomWalkDistribution is a stateful random walk, with minimum and
// maximum bounds. Initialize it with a Min, Max, and an underlying
// distribution, which is used to compute the new step value.
type ClampedRandomWalkDistribution struct {
Step Distribution
Min float64
Max float64
State float64 // optional
}
// CWD returns a new ClampedRandomWalkDistribution based on a given distribution and optional starting state
func CWD(step Distribution, min, max, state float64) *ClampedRandomWalkDistribution {
return &ClampedRandomWalkDistribution{
Step: step,
Min: min,
Max: max,
State: state,
}
}
// Advance computes the next value of this distribution and stores it.
func (d *ClampedRandomWalkDistribution) Advance() {
d.Step.Advance()
d.State += d.Step.Get()
if d.State > d.Max {
d.State = d.Max
}
if d.State < d.Min {
d.State = d.Min
}
}
// Get returns the last computed value for this distribution.
func (d *ClampedRandomWalkDistribution) Get() float64 {
return d.State
}
// MonotonicRandomWalkDistribution is a stateful random walk that only
// increases. Initialize it with a Start and an underlying distribution,
// which is used to compute the new step value. The sign of any value of the
// u.d. is always made positive.
type MonotonicRandomWalkDistribution struct {
Step Distribution
State float64
}
// Advance computes the next value of this distribution and stores it.
func (d *MonotonicRandomWalkDistribution) Advance() {
d.Step.Advance()
d.State += math.Abs(d.Step.Get())
}
// Get returns the last computed value for this distribution.
func (d *MonotonicRandomWalkDistribution) Get() float64 {
return d.State
}
// MWD creates a new MonotonicRandomWalkDistribution with a given distribution and initial state
func MWD(step Distribution, state float64) *MonotonicRandomWalkDistribution {
return &MonotonicRandomWalkDistribution{Step: step, State: state}
}
// ConstantDistribution is a stateful distribution that always returns the same value
type ConstantDistribution struct {
State float64
}
// Advance does nothing in a constant distribution
func (d *ConstantDistribution) Advance() {
}
// Get returns the last computed value for this distribution.
func (d *ConstantDistribution) Get() float64 {
return d.State
}