-
Notifications
You must be signed in to change notification settings - Fork 419
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
Add Generalized chi-squared distribution #1806
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1806 +/- ##
==========================================
+ Coverage 86.00% 86.19% +0.18%
==========================================
Files 144 145 +1
Lines 8646 8798 +152
==========================================
+ Hits 7436 7583 +147
- Misses 1210 1215 +5 ☔ View full report in Codecov by Sentry. |
When this will be added to the main branch ? |
Hi, I have played around with this extension. In general it seems to work very well and I will use for future research. However, I notice that while doing my own tests the quadgk.jl package/function used inside the file generalizedchisq.jl " in the following explained cases. Lets say that X ~ N_(µ, Σ) with particular vector dimension D = 2, 3, 4. The parameter values (w, ν, λ, m, s) = T(q0, q1, Q, µ, Σ) are obtained accordingly with the transformation, say T, One can just run the below code and check the results. The error also seems to be exactly the same one appearing in here. mutable struct parGChisq
w::Vector{<: Real}
ν::Vector{<: Real}
λ::Vector{<: Real}
m::Real
s::Real
end
function mapGChisqpar(
q0::Real,
q1::Vector{<: Real},
Q ::AbstractMatrix,
µ ::Vector{<: Real},
Σ ::AbstractMatrix,
ch::Bool = false)::parGChisq
"""
if X ~ N(µ, Σ)
then Υ = q0 + q1' X + X'QX ~ GChisq(w, ν, λ, m, s)
see https://arxiv.org/pdf/2012.14331.pdf
the option with ch = true
does not work. why ?
"""
# check dimensionality match
dimQ = size(Q, 1)
dimq = length(q1)
dimΣ = size(Σ, 1)
dimµ = length(µ)
dimQ !== dimq ? @error("dims mismatch Q, q1") : nothing
dimΣ !== dimq ? @error("dims mismatch Σ, q1") : nothing
dimΣ !== dimµ ? @error("dims mismatch Σ, µ") : nothing
# check matrix conditions
!issymmetric(Q) ? @error("Q is not symmetric") : nothing
!isposdef(Σ) ? @error("Σ is not PD") : nothing
# take the square root matrix
S = !ch ? sqrt(Σ) : cholesky(Σ).L
# standartize the space
t_Q² = !ch ? Symmetric(S * Q * S) : Symmetric(S * Q * S')
t_q1 = S * (2.0 * Q * µ + q1)
t_q0 = q0 + dot(q1, µ) + dot(µ, Q, µ)
# get the generalized Chi-squared parameters
d, R = eigen(t_Q²)
d .= trunc.(d, digits = 9)
# d[abs.(d) .< eps()] .= 0.0
# compute b terms
b = R' * t_q1
# unique nonzeros eigenvalues
# the unique function returns an ordered set
iz = d .!= 0.0
w = unique(d[iz])
ew = !isempty(w)
# warn if there are only zero eigenvalues
ew ? nothing : @warn("Y will follow a Gaussian distribution")
# total dof of each nonzero eigenvalue
ν = ew ? [sum(d .== i) for i in w] : Float64[]
# total non-centrality for each nonzero eigenvalue
λ = ew ? [sum(b[d .== x].^2.0) for x in w] ./ (4.0.*w.^2.0) : Float64[]
# Gaussian parameters
m = t_q0 - dot(w, λ)
s = norm(b[.!iz])
return parGChisq(w, ν, λ, m, s)
end
using Distributions,
LinearAlgebra,
Plots
# tests
# dimension
D = 3 # 2 or 4
# set parameter of the const + linear + quadratic form
q0 = randn()
q1 = rand(D)
Q = Diagonal(randn(D))
µ = randn(D)
Σ = rand(Wishart(D, Matrix(I, D, D)), 1)[];
# set the correspondent parameters of the GChisq
th = mapGChisqpar(q0, q1, Q, µ, Σ)
# set the GChisq distribution
π = GeneralizedChisq(th.w, th.ν, th.λ, th.m, th.s)
# test
@time pdf(π, mean(π)) |
Adding the generalized chi-squared distribution would be highly appreciated! |
If there is anything blocking the merging of this PR that could be solved, I'd love to help. Regarding the issue reported by @mahaa2, maybe it is related to what I had mentioned:
I see that this problem also happens in other functions of the package, as Let aside that, there were some CI errors for nightly, but those also happened to other unrelated PR when this one was submitted, so I think they are not related to real issues in the code. |
This extends the collection of univariate continuous distributions with the Generalized chi-squared. All required methods are added, and some of the recommended ones, as indicated in https://juliastats.org/Distributions.jl/stable/extends/#Univariate-Distribution
Some notes:
cdf
function, using Davies' algorithm to integrate the characteristic function. But I don't know if a more explicit attribution in the code or in the license should be made.GChisqComputations
, after the example of the Chernoff distribution.cf_explicit
that implements the explicit formula, andcf_inherit
that composes the results ofcf(::Normal)
andcf(::NoncentralChisq)
. Both are equivalent, and the code of the second is clearer, butcf(::GeneralizedChisq)
calls the first one, because in a few tests that I have done, it is slightly (but not much) faster.cdf
andpdf
are calculated by integration, using the Gil-Pelaez theorem (the algorithm for the CDF is given in Davies' paper, and the algorithm for the PDF has been indirectly derived from it). The integration is done using QuadGK.jl, which was already in the dependencies of Distributions.jl. The default tolerances ofQuadGK.quadgk
made the calculation ofcdf
at the median very slow, because there the integral is zero. Since in the ends of the distribution the integral is±π/2
, which is in the order of magnitude of the unit, I have used a fixed absolute tolerance ofeps(one(T))
for the integration in the calculation of the CDF. I have not, however, changed the defaults for the calculation of the PDF.quantile
is calculated usingDistributions.quantile_newton
. However, there is no analytic solution to find the mode, which is the recommended starting point, so this is searched using the following strategy: (1) start at the mean of the distribution, and use it if it meets the convergence criteria; (2) otherwise define a bracket between that point and another at one standard deviation from the mean, in the direction towards the target probability (and if the bracket does not contain the target probability, extend it until it does); (3) bisect the bracket until one of the ends meets the convergence criteria, and then use that as the starting point. This seems to work fine, but it's a self-made algorithm, and perhaps there is a more efficient one that might be used instead.