Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic aliasing of archimedeans #82

Merged
merged 4 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
Cubature = "667455a9-e2ce-5579-9412-b964f529a492"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
LogExpFunctions = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
MvNormalCDF = "37188c8d-bc69-4638-b057-733e744175ec"
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
Expand Down
69 changes: 27 additions & 42 deletions src/ArchimedeanCopula.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,47 +155,34 @@ end
################ ################
################################################################################################

################################################################################################
# Deal with easy cases with meta-programming:
const AMHCopula{d,T} = ArchimedeanCopula{d,AMHGenerator{T}}
AMHCopula(d,θ) = ArchimedeanCopula(d,AMHGenerator(θ))
generatorof(::Type{AMHCopula}) = AMHGenerator

const ClaytonCopula{d,T} = ArchimedeanCopula{d,ClaytonGenerator{T}}
ClaytonCopula(d,θ) = ArchimedeanCopula(d,ClaytonGenerator(θ))
generatorof(::Type{ClaytonCopula}) = ClaytonGenerator

const FrankCopula{d,T} = ArchimedeanCopula{d,FrankGenerator{T}}
FrankCopula(d,θ) = ArchimedeanCopula(d,FrankGenerator(θ))
generatorof(::Type{FrankCopula}) = FrankGenerator

const GumbelBarnettCopula{d,T} = ArchimedeanCopula{d,GumbelBarnettGenerator{T}}
GumbelBarnettCopula(d,θ) = ArchimedeanCopula(d,GumbelBarnettGenerator(θ))
generatorof(::Type{GumbelBarnettCopula}) = GumbelBarnettGenerator

const GumbelCopula{d,T} = ArchimedeanCopula{d,GumbelGenerator{T}}
GumbelCopula(d,θ) = ArchimedeanCopula(d,GumbelGenerator(θ))
generatorof(::Type{GumbelCopula}) = GumbelGenerator

const InvGaussianCopula{d,T} = ArchimedeanCopula{d,InvGaussianGenerator{T}}
InvGaussianCopula(d,θ) = ArchimedeanCopula(d,InvGaussianGenerator(θ))
generatorof(::Type{InvGaussianCopula}) = InvGaussianGenerator

const JoeCopula{d,T} = ArchimedeanCopula{d,JoeGenerator{T}}
JoeCopula(d,θ) = ArchimedeanCopula(d,JoeGenerator(θ))
generatorof(::Type{JoeCopula}) = JoeGenerator

const IndependentCopula{d} = ArchimedeanCopula{d,IndependentGenerator}
IndependentCopula(d) = ArchimedeanCopula(d,IndependentGenerator())
generatorof(::Type{IndependentCopula}) = IndependentGenerator

const MCopula{d} = ArchimedeanCopula{d,MGenerator}
MCopula(d) = ArchimedeanCopula(d,MGenerator())
generatorof(::Type{MCopula}) = MGenerator

const WCopula{d} = ArchimedeanCopula{d,WGenerator}
WCopula(d) = ArchimedeanCopula(d,WGenerator())
generatorof(::Type{WCopula}) = WGenerator
## Automatic syntactic sugar for all ZeroVariateGenerators and UnivariateGenerators.
## see https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/38?u=lrnv
function generatorof(::Type{S}) where {S <: ArchimedeanCopula}
S2 = hasproperty(S,:body) ? S.body : S
S3 = hasproperty(S2, :body) ? S2.body : S2
try
return S3.parameters[2].name.wrapper
catch e
@error "There is no generator type associated with the archimedean type $S"
end
end
for T in InteractiveUtils.subtypes(ZeroVariateGenerator)
G = Symbol(last(split(string(T),'.')))
C = Symbol(string(G)[begin:end-9]*"Copula")
@eval begin
const ($C){d} = ArchimedeanCopula{d,($G)}
($C)(d) = ArchimedeanCopula(d,($G)())
end
end
for T in InteractiveUtils.subtypes(UnivariateGenerator)
G = Symbol(last(split(string(T),'.')))
C = Symbol(string(G)[begin:end-9]*"Copula")
@eval begin
const ($C){d,Tθ} = ArchimedeanCopula{d,($G){Tθ}}
($C)(d,θ) = ArchimedeanCopula(d,($G)(θ))
end
end

# The zero-variate ones just need a few more methods:
Distributions._logpdf(::ArchimedeanCopula{d,IndependentGenerator}, u) where {d} = all(0 .<= u .<= 1) ? zero(eltype(u)) : eltype(u)(-Inf)
Expand All @@ -217,8 +204,6 @@ function Distributions._rand!(rng::Distributions.AbstractRNG, ::ArchimedeanCopul
x[1] = rand(rng)
x[2] = 1-x[1]
end


function Distributions._rand!(rng::Distributions.AbstractRNG, C::ArchimedeanCopula{d,IndependentGenerator}, A::DenseMatrix{T}) where {T<:Real, d}
Random.rand!(rng,A)
return A
Expand Down
1 change: 1 addition & 0 deletions src/Copulas.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Copulas

import Base
import Random
import InteractiveUtils
import SpecialFunctions
import Roots
import Distributions
Expand Down
2 changes: 1 addition & 1 deletion src/Generator/ZeroVariateGenerator/IndependentGenerator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ It happends to be an Archimedean Copula, with generator :
\\phi(t) = \\exp{-t}
```
"""
struct IndependentGenerator <: Generator end
struct IndependentGenerator <: ZeroVariateGenerator end
max_monotony(::IndependentGenerator) = Inf
ϕ(::IndependentGenerator,t) = exp(-t)
ϕ⁻¹(::IndependentGenerator,t) = -log(t)
Expand Down
2 changes: 1 addition & 1 deletion src/Generator/ZeroVariateGenerator/MGenerator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ W(\\mathbf{u}) \\le C(\\mathbf{u}) \\le M(\\mathbf{u})

The two Frechet-Hoeffding bounds are also Archimedean copulas.
"""
struct MGenerator <: Generator end
struct MGenerator <: ZeroVariateGenerator end
max_monotony(::MGenerator) = Inf
τ(::MGenerator) = 1
ϕ(::MGenerator,t) = throw(ArgumentError("MGenerator cannot have a ϕ function"))
Expand Down
2 changes: 1 addition & 1 deletion src/Generator/ZeroVariateGenerator/WGenerator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ W(\\mathbf{u}) \\le C(\\mathbf{u}) \\le M(\\mathbf{u})

The two Frechet-Hoeffding bounds are also Archimedean copulas.
"""
struct WGenerator <: Generator end
struct WGenerator <: ZeroVariateGenerator end
max_monotony(G::WGenerator) = 2
τ(::WGenerator) = -1
ϕ(::WGenerator,t) = throw(MethodError("WGenerator cannot have a ϕ function"))
Expand Down