Skip to content

Commit 21de468

Browse files
authored
[Internals] Switch to TaylorDiff.jl (#16)
1 parent 86ba544 commit 21de468

File tree

5 files changed

+49
-41
lines changed

5 files changed

+49
-41
lines changed

.github/workflows/CI.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
version:
22-
- '1.6'
22+
- 'lts'
2323
- '1'
2424
os:
2525
- ubuntu-latest
2626
arch:
2727
- x64
2828
steps:
2929
- uses: actions/checkout@v3
30-
- uses: julia-actions/setup-julia@v1
30+
- uses: julia-actions/setup-julia@v2
3131
with:
3232
version: ${{ matrix.version }}
3333
arch: ${{ matrix.arch }}

Project.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
name = "WilliamsonTransforms"
22
uuid = "48feb556-9bdd-43a2-8e10-96100ec25e22"
3+
version = "0.2"
34
authors = ["Oskar Laverny <[email protected]> and contributors"]
4-
version = "0.1.7"
55

66
[deps]
77
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
88
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
9-
TaylorSeries = "6aa5eb33-94cf-58f4-a9d0-e4b2c4fc25ea"
9+
TaylorDiff = "b36ab563-344f-407b-a36a-4f200bebf99c"
1010

1111
[compat]
1212
Distributions = "0.25"
1313
Roots = "1, 2"
14-
TaylorSeries = "0.15, 0.16, 0.17, 0.18, 0.19, 0.20"
14+
TaylorDiff = "0.3"
1515
julia = "1"
1616

1717
[extras]

docs/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
[deps]
22
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3+
LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589"
34
WilliamsonTransforms = "48feb556-9bdd-43a2-8e10-96100ec25e22"

src/WilliamsonTransforms.jl

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ module WilliamsonTransforms
77
end WilliamsonTransforms
88

99
import Distributions
10-
import TaylorSeries
11-
import Base.minimum
10+
import TaylorDiff
1211
import Roots
1312
import Base: minimum, maximum
14-
1513
export 𝒲, 𝒲₋₁
1614

1715
"""
@@ -36,29 +34,40 @@ References:
3634
- Williamson, R. E. (1956). Multiply monotone functions and their Laplace transforms. Duke Math. J. 23 189–207. MR0077581
3735
- McNeil, Alexander J., and Johanna Nešlehová. "Multivariate Archimedean copulas, d-monotone functions and ℓ 1-norm symmetric distributions." (2009): 3059-3097.
3836
"""
39-
struct 𝒲{TX}
37+
struct 𝒲{TX, d}
4038
X::TX
41-
d::Int
42-
# E::TE
43-
function 𝒲(X::TX,d) where TX<:Distributions.UnivariateDistribution
39+
function 𝒲(X::TX, ::Val{d}) where {TX<:Distributions.UnivariateDistribution, d}
4440
@assert minimum(X) 0 && maximum(X) Inf
4541
@assert d 2 && isinteger(d)
46-
return new{typeof(X)}(X,d)
42+
return new{typeof(X), d}(X)
4743
end
44+
𝒲(X, d::Int) = 𝒲(X, Val(d))
4845
end
4946

50-
function::𝒲)(x)
47+
function::𝒲{TX, d})(x) where {TX,d}
5148
if x <= 0
5249
return 1 - Distributions.cdf(ϕ.X,0)
5350
else
54-
return Distributions.expectation(y -> (1 - x/y)^.d-1) * (y > x), ϕ.X)
55-
# We need to compute the expectation of (1 - x/X)^{d-1}
56-
# return ϕ.E(y -> (y > x) * (1 - x/y)^(ϕ.d-1))
51+
return Distributions.expectation(y -> (1 - x/y)^(d-1) * (y > x), ϕ.X)
5752
end
5853
end
5954

60-
function taylor(f, x, d)
61-
return f(x + TaylorSeries.Taylor1([zero(x), one(x)],d)).coeffs
55+
"""
56+
taylor(f::F, x₀, ::Val{d}) where {F,d}
57+
58+
Compute the Taylor series expansion of the function `f` around the point `x₀` up to order `d`, and gives you back all the successive derivatives.
59+
60+
# Arguments
61+
- `f`: A function to be expanded.
62+
- `x₀`: The point around which to expand the Taylor series.
63+
- `d`: The order up to which the Taylor series is computed.
64+
65+
# Returns
66+
A tuple with value ``(f(x₀), f'(x₀),...,f^{(d)}(x₀))``.
67+
"""
68+
function taylor(f::F, x₀, D::Val{d}) where {F,d}
69+
r = TaylorDiff.derivatives(f, x₀, one(x₀), D)
70+
return (r.value, r.partials...)
6271
end
6372

6473
"""
@@ -87,38 +96,36 @@ References:
8796
- Williamson, R. E. (1956). Multiply monotone functions and their Laplace transforms. Duke Math. J. 23 189–207. MR0077581
8897
- McNeil, Alexander J., and Johanna Nešlehová. "Multivariate Archimedean copulas, d-monotone functions and ℓ 1-norm symmetric distributions." (2009): 3059-3097.
8998
"""
90-
struct 𝒲₋₁{Tϕ} <: Distributions.ContinuousUnivariateDistribution
99+
struct 𝒲₋₁{Tϕ, d} <: Distributions.ContinuousUnivariateDistribution
91100
ϕ::Tϕ
92-
d::Int
93-
function 𝒲₋₁(ϕ,d)
101+
function 𝒲₋₁(ϕ, ::Val{d}) where d
94102
@assert ϕ(0.0) == 1.0
95103
@assert ϕ(float(Inf)) == 0.0
96-
# And assertion about d-monotony... how can this be check ? this is hard.
97-
return new{typeof(ϕ)}(ϕ,d)
104+
@assert isinteger(d)
105+
return new{typeof(ϕ),d}(ϕ)
98106
end
107+
𝒲₋₁(ϕ, d::Int) = 𝒲₋₁(ϕ, Val(d))
99108
end
100-
function Distributions.cdf(d::𝒲₋₁, x)
101-
rez = zero(x)
102-
c_ϕ = taylor(d.ϕ, x, d.d)
103-
c_ϕ[end] = max(c_ϕ[end], 0)
104-
for k in 0:(d.d-1)
105-
if c_ϕ[k+1] != 0 # We need c_ϕ = 0 to dominate x = Inf
106-
rez += (-1)^k * x^k * c_ϕ[k+1]
107-
end
109+
function Distributions.cdf(dist::𝒲₋₁{Tϕ, d}, x) where {Tϕ, d}
110+
x 0 && return zero(x)
111+
rez, x_pow = zero(x), one(x)
112+
c = taylor(dist.ϕ, x, Val(d-1))
113+
for k in 1:d
114+
rez += iszero(c[k]) ? 0 : x_pow * c[k]
115+
x_pow *= -x
108116
end
109-
# simple hack to ensure convergence :
110117
return isnan(rez) ? one(x) : 1 - rez
111-
# return 1-rez
112118
end
113-
Distributions.logpdf(d::𝒲₋₁, x::Real) = log(max(0,taylor(x -> Distributions.cdf(d,x), x, 1)[end]))
114-
_quantile(d::𝒲₋₁, p) = Roots.find_zero(x -> (Distributions.cdf(d, x) - p), (0.0, Inf))
115-
Distributions.rand(rng::Distributions.AbstractRNG, d::𝒲₋₁) = _quantile(d,rand(rng))
119+
120+
Distributions.logpdf(dist::𝒲₋₁{Tϕ, d}, x) where {Tϕ, d} = log(max(0,taylor(x -> Distributions.cdf(dist,x), x, Val(1))[end]))
121+
_quantile(dist::𝒲₋₁, p) = Roots.find_zero(x -> (Distributions.cdf(dist, x) - p), (0.0, Inf))
122+
Distributions.rand(rng::Distributions.AbstractRNG, dist::𝒲₋₁) = _quantile(dist, rand(rng))
116123
Base.minimum(::𝒲₋₁) = 0.0
117124
Base.maximum(::𝒲₋₁) = Inf
118-
function Distributions.quantile(d::𝒲₋₁, p::Real)
119-
# Validate that p is in the range [0, 1]
125+
function Distributions.quantile(dist::𝒲₋₁, p::Real)
126+
# Validate that p is in the range [0, 1]
120127
@assert 0 <= p <= 1
121-
return _quantile(d,p)
128+
return _quantile(dist, p)
122129
end
123130
end
124131

test/testing_the_paper.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,5 @@ end
127127
@testitem "testing fractional-dimensional williamson transformation" begin
128128
using Distributions
129129
ϕ(x) = exp(-x)
130-
@test_throws InexactError 𝒲₋₁(ϕ, 0.7)
130+
@test_throws MethodError 𝒲₋₁(ϕ, 0.7)
131131
end

0 commit comments

Comments
 (0)