/
fractional_brownian_motion.go
83 lines (77 loc) · 2.65 KB
/
fractional_brownian_motion.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
package phenomena
import (
"math"
"github.com/umbralcalc/stochadex/pkg/simulator"
"golang.org/x/exp/rand"
"gonum.org/v1/gonum/stat/distuv"
"scientificgo.org/special"
)
// FractionalBrownianMotionIntegral computes the integral term in the fractional
// Brownian motion process defined here: https://en.wikipedia.org/wiki/Fractional_Brownian_motion
func FractionalBrownianMotionIntegral(
currentTime float64,
nextTime float64,
hurstExponent float64,
numberOfIntegrationSteps int,
) float64 {
integralStepSize := (nextTime - currentTime) / float64(numberOfIntegrationSteps)
a := []float64{hurstExponent - 0.5, 0.5 - hurstExponent}
b := []float64{hurstExponent + 0.5}
integralValue := 0.0
// implements the trapezium rule in a loop over the steps
// between the current and the next point in time
for t := 0; t < numberOfIntegrationSteps; t++ {
t1 := currentTime + float64(t)*integralStepSize
t2 := t1 + integralStepSize
functionValue1 := (math.Pow(t1-currentTime, hurstExponent-0.5) /
math.Gamma(hurstExponent+0.5)) *
special.HypPFQ(a, b, 1.0-t1/currentTime)
functionValue2 := (math.Pow(t2-currentTime, hurstExponent-0.5) /
math.Gamma(hurstExponent+0.5)) *
special.HypPFQ(a, b, 1.0-t2/currentTime)
integralValue += 0.5 * (functionValue1 + functionValue2) * integralStepSize
}
return integralValue
}
// FractionalBrownianMotionIteration defines an iteration for fractional
// Brownian motion.
type FractionalBrownianMotionIteration struct {
unitNormalDist *distuv.Normal
numberOfIntegrationSteps int
}
func (f *FractionalBrownianMotionIteration) Configure(
partitionIndex int,
settings *simulator.Settings,
) {
f.unitNormalDist = &distuv.Normal{
Mu: 0.0,
Sigma: 1.0,
Src: rand.NewSource(settings.Seeds[partitionIndex]),
}
f.numberOfIntegrationSteps = int(
settings.OtherParams[partitionIndex].
IntParams["number_of_integration_steps"][0],
)
}
func (f *FractionalBrownianMotionIteration) Iterate(
params *simulator.OtherParams,
partitionIndex int,
stateHistories []*simulator.StateHistory,
timestepsHistory *simulator.CumulativeTimestepsHistory,
) []float64 {
stateHistory := stateHistories[partitionIndex]
values := make([]float64, stateHistory.StateWidth)
for i := range values {
values[i] = stateHistory.Values.At(0, i) +
math.Sqrt(params.FloatParams["variances"][i]*
timestepsHistory.NextIncrement)*f.unitNormalDist.Rand()*
FractionalBrownianMotionIntegral(
timestepsHistory.Values.AtVec(0),
timestepsHistory.Values.AtVec(0)+
timestepsHistory.NextIncrement,
params.FloatParams["hurst_exponents"][i],
f.numberOfIntegrationSteps,
)/timestepsHistory.NextIncrement
}
return values
}