Skip to content

Commit 72e641d

Browse files
authored
Merge pull request #35 from jw3126/cf
implement cf for (Symmetric)AlphaStable
2 parents c199d9b + 7e616d5 commit 72e641d

File tree

2 files changed

+95
-12
lines changed

2 files changed

+95
-12
lines changed

src/AlphaStableDistributions.jl

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ Base.@kwdef struct AlphaStable{T} <: Distributions.ContinuousUnivariateDistribut
1515
end
1616

1717
AlphaStable::Integer, β::Integer, scale::Integer, location::Integer) = AlphaStable(float(α), float(β), float(scale), float(location))
18-
18+
function AlphaStable(α,β,scale,location)
19+
αT,βT,scaleT,locationT = promote(α,β,scale,location)
20+
AlphaStable(αT,βT,scaleT,locationT)
21+
end
22+
Distributions.params(d::AlphaStable) = (d.α, d.β, d.scale, d.location)
1923

2024
# sampler(d::AlphaStable) = error("Not implemented")
2125
# pdf(d::AlphaStable, x::Real) = error("Not implemented")
@@ -33,7 +37,17 @@ Statistics.var(d::AlphaStable) = d.α == 2 ? 2d.scale^2 : Inf
3337
# kurtosis(d::Distribution, ::Bool) = error("Not implemented")
3438
# entropy(d::AlphaStable, ::Real) = error("Not implemented")
3539
# mgf(d::AlphaStable, ::Any) = error("Not implemented")
36-
# cf(d::AlphaStable, ::Any) = error("Not implemented")
40+
41+
function Distributions.cf(d::AlphaStable{S}, t::Real) where {S}
42+
T = float(promote_type(S, typeof(t)))
43+
α,β,c,δ = params(d)
44+
Φ = if α == one(α)
45+
T(-2/π * log(abs(t)))
46+
else
47+
T(tan*α/2))
48+
end
49+
exp(im*t*δ - abs(c*t)^α * (1 - im*β*sign(t)*Φ))
50+
end
3751

3852
# lookup tables from McCulloch (1986)
3953
const _ena = [
@@ -220,6 +234,12 @@ Base.@kwdef struct SymmetricAlphaStable{T} <: Distributions.ContinuousUnivariate
220234
scale::T = one(α)
221235
location::T = zero(α)
222236
end
237+
Distributions.params(d::SymmetricAlphaStable) = (d.α, d.scale, d.location)
238+
Distributions.cf(d::SymmetricAlphaStable, t::Real) = cf(AlphaStable(d), t)
239+
240+
function AlphaStable(d::SymmetricAlphaStable)
241+
AlphaStable=d.α,scale=d.scale,location=d.location)
242+
end
223243

224244
"""
225245
fit(d::Type{<:SymmetricAlphaStable}, x; alg=QuickSort)
@@ -465,4 +485,4 @@ function Distributions.fit(d::Type{<:AlphaSubGaussian}, x::AbstractVector{T}, m:
465485
AlphaSubGaussian=α, R=cov, n=length(x))
466486
end
467487

468-
end # module
488+
end # module

test/runtests.jl

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,80 @@
11
using AlphaStableDistributions
22
using Test, Random, Distributions
33

4-
@testset "AlphaStableDistributions.jl" begin
4+
@testset "cf" begin
5+
rng = MersenneTwister(1)
6+
for _ in 1:100
7+
d = AlphaStable(
8+
α=rand(rng,Uniform(0,2)),
9+
β=rand(rng,Uniform(-1,1)),
10+
scale=rand(rng,Uniform(0,10)),
11+
location=rand(rng,Uniform(0,10)),
12+
)
13+
@test cf(d,0) 1
14+
x = rand(rng,Uniform(-10,10))
15+
@test abs(cf(d, x)) <= 1
16+
17+
d32 = AlphaStable(Float32.(Distributions.params(d))...)
18+
@test cf(d32, Float32(x)) isa Complex{Float32}
19+
@test cf(d32, Float32(x)) cf(d,x) atol=100*eps(Float32)
20+
end
21+
for _ in 1:100
22+
# test stability under convolution
23+
d = AlphaStable(
24+
α=rand(rng,Uniform(0.1,2)),
25+
scale=1.0,
26+
location=0.0,
27+
)
28+
x = rand(rng,Uniform(-1,1))
29+
n = rand(rng,1:10^6)
30+
s = n^inv(d.α)
31+
@test cf(d, x) cf(d, x/s)^n
32+
end
33+
xs = range(-1,1,length=100)
34+
d1 = SymmetricAlphaStable=2.0, scale=1/sqrt(2), location=0.0)
35+
d2 = AlphaStable(d1)
36+
d_ref = Normal(0.0,1.0)
37+
@test cf.(Ref(d1),xs) cf.(Ref(d_ref),xs)
38+
@test cf.(Ref(d2),xs) cf.(Ref(d_ref),xs)
39+
40+
xs = range(-10,10,length=100)
41+
d1 = SymmetricAlphaStable=1.0, scale=1.0, location=0.0)
42+
d2 = AlphaStable(d1)
43+
d_ref = Cauchy(0.0,1.0)
44+
@test cf.(Ref(d1),xs) cf.(Ref(d_ref),xs)
45+
@test cf.(Ref(d2),xs) cf.(Ref(d_ref),xs)
46+
47+
d1 = SymmetricAlphaStable=1.0, scale=17.9, location=42.0)
48+
d2 = AlphaStable(d1)
49+
d_ref = Cauchy(42.0,17.9)
50+
@test cf.(Ref(d1),xs) cf.(Ref(d_ref),xs)
51+
@test cf.(Ref(d2),xs) cf.(Ref(d_ref),xs)
52+
53+
d1 = AlphaStable=1/2, β=1.0, scale=12.0, location=-7.2)
54+
d_ref = Levy(-7.2, 12.0)
55+
@test cf.(Ref(d1),xs) cf.(Ref(d_ref),xs)
556

57+
@test @inferred(cf(AlphaStable= 1.0) , 1.0)) isa Complex{Float64}
58+
@test @inferred(cf(AlphaStable= 1 ) , 1 )) isa Complex{Float64}
59+
@test @inferred(cf(AlphaStable= 1.0) , 1f0)) isa Complex{Float64}
60+
@test @inferred(cf(AlphaStable= 1f0) , 1 )) isa Complex{Float32}
61+
@test @inferred(cf(AlphaStable= 1f0) , 1f0)) isa Complex{Float32}
62+
end
63+
64+
65+
@testset "AlphaStableDistributions.jl" begin
66+
@test AlphaStable=1, scale=1.5) === AlphaStable=1.0, scale=1.5)
67+
@test Distributions.params(AlphaStable()) === (1.5, 0.0, 1.0, 0.0)
68+
@test Distributions.params(SymmetricAlphaStable()) === (1.5, 1.0, 0.0)
69+
rng = MersenneTwister(0)
670
sampletypes = [Float32,Float64]
771
stabletypes = [AlphaStable,SymmetricAlphaStable]
872
αs = [0.6:0.1:2,1:0.1:2]
973
for sampletype sampletypes
1074
for (i, stabletype) in enumerate(stabletypes)
1175
for α in αs[i]
1276
d1 = AlphaStable=sampletype(α))
13-
s = rand(d1, 200000)
77+
s = rand(rng,d1, 200000)
1478
@test eltype(s) == sampletype
1579

1680
d2 = fit(stabletype, s)
@@ -22,14 +86,14 @@ using Test, Random, Distributions
2286
@test d1.location d2.location atol=0.1
2387
end
2488

25-
xnormal = rand(Normal(3.0, 4.0), 96000)
89+
xnormal = rand(rng,Normal(3.0, 4.0), 96000)
2690
d = fit(stabletype, xnormal)
2791
@test d.α 2 rtol=0.2
2892
stabletype != SymmetricAlphaStable && @test d.β 0 atol=0.2
2993
@test d.scale 4/√2 rtol=0.2
3094
@test d.location 3 rtol=0.1
3195

32-
xcauchy = rand(Cauchy(3.0, 4.0), 96000)
96+
xcauchy = rand(rng,Cauchy(3.0, 4.0), 96000)
3397
d = fit(stabletype, xcauchy)
3498
@test d.α 1 rtol=0.2
3599
stabletype != SymmetricAlphaStable && @test d.β 0 atol=0.2
@@ -40,9 +104,9 @@ using Test, Random, Distributions
40104

41105
for α in 1.1:0.1:1.9
42106
d = AlphaSubGaussian=α, n=96000)
43-
x = rand(d)
107+
x = rand(rng,d)
44108
x2 = copy(x)
45-
rand!(d, x2)
109+
rand!(rng,d, x2)
46110
@test x != x2
47111

48112
d3 = fit(AlphaStable, x)
@@ -54,13 +118,12 @@ using Test, Random, Distributions
54118

55119
d4 = AlphaSubGaussian=1.5, n=96000)
56120
m = size(d4.R, 1) - 1
57-
x = rand(d4)
121+
x = rand(rng,d4)
58122
d5 = fit(AlphaSubGaussian, x, m, p=1.0)
59123
@test d4.α d5.α rtol=0.1
60124
@test d4.R d5.R rtol=0.1
61125

62126
end
63-
64127
# 362.499 ms (4620903 allocations: 227.64 MiB)
65128
# 346.520 ms (4621052 allocations: 209.62 MiB) # StaticArrays in outer fun
66129
# 345.925 ms (4225524 allocations: 167.66 MiB) # tempind to tuple
@@ -114,4 +177,4 @@ end
114177
# d1 = AlphaStable(α=1.5)
115178
# s = rand(d1, 100000)
116179
# using ThreadsX
117-
# @btime fit($AlphaStable, $s, $ThreadsX.MergeSort)
180+
# @btime fit($AlphaStable, $s, $ThreadsX.MergeSort)

0 commit comments

Comments
 (0)