Skip to content

Commit 6ed4894

Browse files
committed
First sketch of liouville copulas
1 parent 49dc233 commit 6ed4894

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

src/LiouvilleCopula.jl

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""
2+
LiouvilleCopula{d, T, TG}
3+
4+
Fields:
5+
- \alpha::NTuple{d,T} : the weights for each dimension
6+
- G::TG : the generator <: Generator.
7+
8+
Constructor:
9+
10+
LiouvilleCopula(α::Vector{T},G::Generator)
11+
12+
The Liouville copula has a structure that resembles the [`ArchimedeanCopula`](@ref), when you look at it from it's radial-simplex decomposition.
13+
14+
Recalling that, for C an archimedean copula with generator ``\\phi``, if ``\\mathbf U \\sim C``, then ``U \\equal R \\mathbf S`` for a random vector ``\\mathbf S \\sim`` `Dirichlet(ones(d))`, that is uniformity on the d-variate simplex, and a non-negative random variable ``R`` that is the Williamson d-transform of `\\phi`.
15+
16+
The Liouville copula has exactly the same expression but using another Dirichlet distribution instead than uniformity over the simplex.
17+
18+
References:
19+
McNeil, A. J., & Nešlehová, J. (2010). From archimedean to liouville copulas. Journal of Multivariate Analysis, 101(8), 1772-1790.
20+
"""
21+
struct LiouvilleCopula{d,TG} <: Copula{d}
22+
α::NTuple{d,Int}
23+
G::TG
24+
function LiouvilleCopula(α::Vector{Int},G::Generator)
25+
d = length(α)
26+
@assert sum(α) <= max_monotony(G) "The generator you provided is not monotonous enough (the monotony index must be greater than sum(α), and thus this copula does not exists."
27+
return new{d, typeof(G)}(G)
28+
end
29+
end
30+
williamson_dist(C::LiouvilleCopula{d,TG}) where {d,TG} = williamson_dist(C.G,sum(C.α))
31+
32+
function Distributions._rand!(rng::Distributions.AbstractRNG, C, x::AbstractVector{T})
33+
# By default, we use the williamson sampling.
34+
r = Distributions.rand(williamson_dist(C))
35+
for i in 1:length(C)
36+
x[i] = Distributions.rand(rng,Gamma(C.α[i],1))
37+
x[i] = x[i] * r
38+
x[i] = Distributions.cdf(williamson_dist(C.G,C.α[i]),x[i])
39+
end
40+
return x
41+
end
42+
function _cdf(C::CT,u) where {CT<:LiouvilleCopula}
43+
d = length(C)
44+
45+
sx = sum(Distributions.quantile(williamson_dist(C.G,C.α[i]),u[i]) for i in 1:d)
46+
r = zero(eltype(u))
47+
for i in CartesianIndices(α)
48+
ii = (ij-1 for ij in Tuple(i))
49+
sii = sum(ii)
50+
fii = prod(factorial.(ii))
51+
# This version is really not efficient as derivatives of the generator ϕ⁽ᵏ⁾(C.G, sii, sx) could be pre-computed since many sii will be the same and sx does never change.
52+
r += (-1)^sii / fii * ϕ⁽ᵏ⁾(C.G, sii, sx) * prod(x .^i)
53+
end
54+
return r
55+
end

0 commit comments

Comments
 (0)