|
| 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