114 lines
3.0 KiB
Go
114 lines
3.0 KiB
Go
// Copyright ©2020 The Gonum Authors. All rights reserved.
|
||
// Use of this source code is governed by a BSD-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
package distuv
|
||
|
||
import (
|
||
"math"
|
||
|
||
"golang.org/x/exp/rand"
|
||
)
|
||
|
||
// AlphaStable represents an α-stable distribution with four parameters.
|
||
// See https://en.wikipedia.org/wiki/Stable_distribution for more information.
|
||
type AlphaStable struct {
|
||
// Alpha is the stability parameter.
|
||
// It is valid within the range 0 < α ≤ 2.
|
||
Alpha float64
|
||
// Beta is the skewness parameter.
|
||
// It is valid within the range -1 ≤ β ≤ 1.
|
||
Beta float64
|
||
// C is the scale parameter.
|
||
// It is valid when positive.
|
||
C float64
|
||
// Mu is the location parameter.
|
||
Mu float64
|
||
Src rand.Source
|
||
}
|
||
|
||
// ExKurtosis returns the excess kurtosis of the distribution.
|
||
// ExKurtosis returns NaN when Alpha != 2.
|
||
func (a AlphaStable) ExKurtosis() float64 {
|
||
if a.Alpha == 2 {
|
||
return 0
|
||
}
|
||
return math.NaN()
|
||
}
|
||
|
||
// Mean returns the mean of the probability distribution.
|
||
// Mean returns NaN when Alpha <= 1.
|
||
func (a AlphaStable) Mean() float64 {
|
||
if a.Alpha > 1 {
|
||
return a.Mu
|
||
}
|
||
return math.NaN()
|
||
}
|
||
|
||
// Median returns the median of the distribution.
|
||
// Median panics when Beta != 0, because then the mode is not analytically
|
||
// expressible.
|
||
func (a AlphaStable) Median() float64 {
|
||
if a.Beta == 0 {
|
||
return a.Mu
|
||
}
|
||
panic("distuv: cannot compute Median for Beta != 0")
|
||
}
|
||
|
||
// Mode returns the mode of the distribution.
|
||
// Mode panics when Beta != 0, because then the mode is not analytically
|
||
// expressible.
|
||
func (a AlphaStable) Mode() float64 {
|
||
if a.Beta == 0 {
|
||
return a.Mu
|
||
}
|
||
panic("distuv: cannot compute Mode for Beta != 0")
|
||
}
|
||
|
||
// NumParameters returns the number of parameters in the distribution.
|
||
func (a AlphaStable) NumParameters() int {
|
||
return 4
|
||
}
|
||
|
||
// Rand returns a random sample drawn from the distribution.
|
||
func (a AlphaStable) Rand() float64 {
|
||
// From https://en.wikipedia.org/wiki/Stable_distribution#Simulation_of_stable_variables
|
||
const halfPi = math.Pi / 2
|
||
u := Uniform{-halfPi, halfPi, a.Src}.Rand()
|
||
w := Exponential{1, a.Src}.Rand()
|
||
if a.Alpha == 1 {
|
||
f := halfPi + a.Beta*u
|
||
x := (f*math.Tan(u) - a.Beta*math.Log(halfPi*w*math.Cos(u)/f)) / halfPi
|
||
return a.C*(x+a.Beta*math.Log(a.C)/halfPi) + a.Mu
|
||
}
|
||
zeta := -a.Beta * math.Tan(halfPi*a.Alpha)
|
||
xi := math.Atan(-zeta) / a.Alpha
|
||
f := a.Alpha * (u + xi)
|
||
g := math.Sqrt(1+zeta*zeta) * math.Pow(math.Cos(u-f)/w, 1-a.Alpha) / math.Cos(u)
|
||
x := math.Pow(g, 1/a.Alpha) * math.Sin(f)
|
||
return a.C*x + a.Mu
|
||
}
|
||
|
||
// Skewness returns the skewness of the distribution.
|
||
// Skewness returns NaN when Alpha != 2.
|
||
func (a AlphaStable) Skewness() float64 {
|
||
if a.Alpha == 2 {
|
||
return 0
|
||
}
|
||
return math.NaN()
|
||
}
|
||
|
||
// StdDev returns the standard deviation of the probability distribution.
|
||
func (a AlphaStable) StdDev() float64 {
|
||
return math.Sqrt(a.Variance())
|
||
}
|
||
|
||
// Variance returns the variance of the probability distribution.
|
||
// Variance returns +Inf when Alpha != 2.
|
||
func (a AlphaStable) Variance() float64 {
|
||
if a.Alpha == 2 {
|
||
return 2 * a.C * a.C
|
||
}
|
||
return math.Inf(1)
|
||
}
|