From 6987d1636e599d7bdf9931857ee734c7c50a057d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller-Widmann?= Date: Mon, 22 Jun 2026 23:44:17 +0200 Subject: [PATCH 1/4] Define `partype` on types, mirroring `eltype` `partype` could previously only be called on instances: every distribution defined `partype(d::Dist{T}) = T` with a `Float64` fallback, so `partype(SomeDist{T})` on the type fell through to the default and returned the wrong answer. Mirror the `eltype` design: define `partype` on the type and provide an instance method `partype(d) = partype(typeof(d))` for convenience, documented with a `!!! note` callout. The generic default becomes `Real` (parameters are `<:Real` and `eltype(Real) === Real`, so `zero`/`one` work on it). - Migrate all distribution methods from `partype(d::Dist{T})` to `partype(::Type{<:Dist{T}})`; wrappers recover the wrapped distribution from their type parameter, as the matching `eltype` methods already do. - Give distributions that relied on the fallback an explicit method, fixing a latent bug where parametric distributions (`Dirac`, `DiscreteNonParametric`, `Product`, `UnivariateGMM`) reported `Float64`. Parameterless distributions (`Chernoff`, `Kolmogorov`) return `Union{}` (the empty parameter promotion); `KSDist`/`KSOneSided` return `Int`, `Soliton` returns `Float64`. - Fix `-(d::UnivariateDistribution)` to `-one(promote_type(Int, partype(d))) * d` so it stays well-typed when `partype(d) === Union{}`. - Add tests, including a general invariant in `testutils`: `partype(d) === partype(typeof(d)) === mapreduce(recursive_partype, promote_type, params(d); init=Union{})`. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/censored.jl | 4 +-- src/cholesky/lkjcholesky.jl | 2 +- src/matrix/inversewishart.jl | 2 +- src/matrix/lkj.jl | 2 +- src/matrix/matrixbeta.jl | 2 +- src/matrix/matrixfdist.jl | 2 +- src/matrix/matrixnormal.jl | 2 +- src/matrix/matrixtdist.jl | 2 +- src/matrix/wishart.jl | 2 +- src/mixtures/mixturemodel.jl | 2 +- src/mixtures/unigmm.jl | 1 + src/multivariate/dirichlet.jl | 2 +- src/multivariate/dirichletmultinomial.jl | 2 +- src/multivariate/jointorderstatistics.jl | 2 +- src/multivariate/multinomial.jl | 2 +- src/multivariate/mvlogitnormal.jl | 2 +- src/multivariate/mvlognormal.jl | 2 +- src/multivariate/mvnormal.jl | 2 +- src/multivariate/mvnormalcanon.jl | 2 +- src/multivariate/mvtdist.jl | 2 +- src/multivariate/product.jl | 1 + src/multivariate/vonmisesfisher.jl | 2 +- src/reshaped.jl | 2 +- src/truncate.jl | 2 +- src/univariate/continuous/arcsine.jl | 2 +- src/univariate/continuous/beta.jl | 2 +- src/univariate/continuous/betaprime.jl | 2 +- src/univariate/continuous/biweight.jl | 2 +- src/univariate/continuous/cauchy.jl | 2 +- src/univariate/continuous/chernoff.jl | 2 ++ src/univariate/continuous/chi.jl | 2 +- src/univariate/continuous/chisq.jl | 2 +- src/univariate/continuous/cosine.jl | 2 +- src/univariate/continuous/epanechnikov.jl | 2 +- src/univariate/continuous/erlang.jl | 2 +- src/univariate/continuous/exponential.jl | 2 +- src/univariate/continuous/fdist.jl | 2 +- src/univariate/continuous/frechet.jl | 2 +- src/univariate/continuous/gamma.jl | 2 +- .../continuous/generalizedextremevalue.jl | 2 +- .../continuous/generalizedpareto.jl | 2 +- src/univariate/continuous/gumbel.jl | 2 +- src/univariate/continuous/inversegamma.jl | 2 +- src/univariate/continuous/inversegaussian.jl | 2 +- src/univariate/continuous/johnsonsu.jl | 2 +- src/univariate/continuous/kolmogorov.jl | 1 + src/univariate/continuous/ksdist.jl | 1 + src/univariate/continuous/ksonesided.jl | 1 + src/univariate/continuous/kumaraswamy.jl | 2 +- src/univariate/continuous/laplace.jl | 2 +- src/univariate/continuous/levy.jl | 2 +- src/univariate/continuous/lindley.jl | 2 +- src/univariate/continuous/logistic.jl | 2 +- src/univariate/continuous/logitnormal.jl | 2 +- src/univariate/continuous/loglogistic.jl | 2 +- src/univariate/continuous/lognormal.jl | 3 +- src/univariate/continuous/loguniform.jl | 2 +- src/univariate/continuous/noncentralbeta.jl | 2 +- src/univariate/continuous/noncentralchisq.jl | 2 +- src/univariate/continuous/noncentralf.jl | 2 +- src/univariate/continuous/noncentralt.jl | 2 +- src/univariate/continuous/normal.jl | 2 +- src/univariate/continuous/normalcanon.jl | 2 +- .../continuous/normalinversegaussian.jl | 2 +- src/univariate/continuous/pareto.jl | 2 +- .../continuous/pgeneralizedgaussian.jl | 2 +- src/univariate/continuous/rayleigh.jl | 2 +- src/univariate/continuous/rician.jl | 2 +- src/univariate/continuous/semicircle.jl | 2 +- .../continuous/skewedexponentialpower.jl | 2 +- src/univariate/continuous/skewnormal.jl | 2 +- src/univariate/continuous/studentizedrange.jl | 2 +- src/univariate/continuous/symtriangular.jl | 2 +- src/univariate/continuous/tdist.jl | 2 +- src/univariate/continuous/triangular.jl | 2 +- src/univariate/continuous/triweight.jl | 2 +- src/univariate/continuous/uniform.jl | 2 +- src/univariate/continuous/vonmises.jl | 2 +- src/univariate/continuous/weibull.jl | 2 +- src/univariate/discrete/bernoulli.jl | 2 +- src/univariate/discrete/bernoullilogit.jl | 2 +- src/univariate/discrete/betabinomial.jl | 2 +- src/univariate/discrete/binomial.jl | 2 +- src/univariate/discrete/categorical.jl | 2 +- src/univariate/discrete/dirac.jl | 1 + .../discrete/discretenonparametric.jl | 1 + src/univariate/discrete/discreteuniform.jl | 2 +- src/univariate/discrete/geometric.jl | 2 +- src/univariate/discrete/hypergeometric.jl | 2 +- src/univariate/discrete/negativebinomial.jl | 2 +- .../discrete/noncentralhypergeometric.jl | 2 +- src/univariate/discrete/poisson.jl | 2 +- src/univariate/discrete/poissonbinomial.jl | 2 +- src/univariate/discrete/skellam.jl | 2 +- src/univariate/discrete/soliton.jl | 1 + src/univariate/locationscale.jl | 4 +-- src/univariate/orderstatistic.jl | 2 +- src/utils.jl | 18 ++++++++--- test/testutils.jl | 21 ++++++++++++ test/utils.jl | 32 ++++++++++++++++++- 100 files changed, 164 insertions(+), 98 deletions(-) diff --git a/src/censored.jl b/src/censored.jl index c86e52b7ae..fd853c7125 100644 --- a/src/censored.jl +++ b/src/censored.jl @@ -108,9 +108,7 @@ function params(d::Censored) return (d0params..., d.lower, d.upper) end -function partype(d::Censored{<:UnivariateDistribution,<:ValueSupport,T}) where {T} - return promote_type(partype(d.uncensored), T) -end +partype(::Type{<:Censored{D,S,T}}) where {D,S,T} = promote_type(partype(D), T) Base.eltype(::Type{<:Censored{D,S,T}}) where {D,S,T} = promote_type(T, eltype(D)) diff --git a/src/cholesky/lkjcholesky.jl b/src/cholesky/lkjcholesky.jl index 2672574a55..b691bf4052 100644 --- a/src/cholesky/lkjcholesky.jl +++ b/src/cholesky/lkjcholesky.jl @@ -121,7 +121,7 @@ end StatsBase.params(d::LKJCholesky) = (d.d, d.η, d.uplo) -@inline partype(::LKJCholesky{T}) where {T <: Real} = T +partype(::Type{<:LKJCholesky{T}}) where {T <: Real} = T # ----------------------------------------------------------------------------- # Evaluation diff --git a/src/matrix/inversewishart.jl b/src/matrix/inversewishart.jl index ec90aa30f9..78be597702 100644 --- a/src/matrix/inversewishart.jl +++ b/src/matrix/inversewishart.jl @@ -78,7 +78,7 @@ size(d::InverseWishart) = size(d.Ψ) rank(d::InverseWishart) = rank(d.Ψ) params(d::InverseWishart) = (d.df, d.Ψ) -@inline partype(d::InverseWishart{T}) where {T<:Real} = T +partype(::Type{<:InverseWishart{T}}) where {T<:Real} = T function mean(d::InverseWishart) df = d.df diff --git a/src/matrix/lkj.jl b/src/matrix/lkj.jl index e56b7888e0..895c9ba271 100644 --- a/src/matrix/lkj.jl +++ b/src/matrix/lkj.jl @@ -93,7 +93,7 @@ end params(d::LKJ) = (d.d, d.η) -@inline partype(d::LKJ{T}) where {T <: Real} = T +partype(::Type{<:LKJ{T}}) where {T <: Real} = T # ----------------------------------------------------------------------------- # Evaluation diff --git a/src/matrix/matrixbeta.jl b/src/matrix/matrixbeta.jl index 58044ad63e..eda29fddd4 100644 --- a/src/matrix/matrixbeta.jl +++ b/src/matrix/matrixbeta.jl @@ -82,7 +82,7 @@ params(d::MatrixBeta) = (size(d, 1), d.W1.df, d.W2.df) mean(d::MatrixBeta) = ((p, n1, n2) = params(d); Matrix((n1 / (n1 + n2)) * I, p, p)) -@inline partype(d::MatrixBeta{T}) where {T <: Real} = T +partype(::Type{<:MatrixBeta{T}}) where {T <: Real} = T # Konno (1988 JJSS) Corollary 3.3.i function cov(d::MatrixBeta, i::Integer, j::Integer, k::Integer, l::Integer) diff --git a/src/matrix/matrixfdist.jl b/src/matrix/matrixfdist.jl index 724cda62e5..207a1d1c32 100644 --- a/src/matrix/matrixfdist.jl +++ b/src/matrix/matrixfdist.jl @@ -93,7 +93,7 @@ function mean(d::MatrixFDist) return (n1 / (n2 - p - 1)) * Matrix(B) end -@inline partype(d::MatrixFDist{T}) where {T <: Real} = T +partype(::Type{<:MatrixFDist{T}}) where {T <: Real} = T # Konno (1988 JJSS) Corollary 2.4.i function cov(d::MatrixFDist, i::Integer, j::Integer, k::Integer, l::Integer) diff --git a/src/matrix/matrixnormal.jl b/src/matrix/matrixnormal.jl index 6e804c907b..fd61d31c21 100644 --- a/src/matrix/matrixnormal.jl +++ b/src/matrix/matrixnormal.jl @@ -98,7 +98,7 @@ var(d::MatrixNormal) = reshape(diag(cov(d)), size(d)) params(d::MatrixNormal) = (d.M, d.U, d.V) -@inline partype(d::MatrixNormal{T}) where {T<:Real} = T +partype(::Type{<:MatrixNormal{T}}) where {T<:Real} = T # ----------------------------------------------------------------------------- # Evaluation diff --git a/src/matrix/matrixtdist.jl b/src/matrix/matrixtdist.jl index c8e2d9fda6..550dc341df 100644 --- a/src/matrix/matrixtdist.jl +++ b/src/matrix/matrixtdist.jl @@ -120,7 +120,7 @@ var(d::MatrixTDist) = d.ν <= 2 ? throw(ArgumentError("var only defined for df > params(d::MatrixTDist) = (d.ν, d.M, d.Σ, d.Ω) -@inline partype(d::MatrixTDist{T}) where {T <: Real} = T +partype(::Type{<:MatrixTDist{T}}) where {T <: Real} = T # ----------------------------------------------------------------------------- # Evaluation diff --git a/src/matrix/wishart.jl b/src/matrix/wishart.jl index 7b0a98c5c1..1b4a377dec 100644 --- a/src/matrix/wishart.jl +++ b/src/matrix/wishart.jl @@ -104,7 +104,7 @@ size(d::Wishart) = size(d.S) rank(d::Wishart) = d.rank params(d::Wishart) = (d.df, d.S) -@inline partype(d::Wishart{T}) where {T<:Real} = T +partype(::Type{<:Wishart{T}}) where {T<:Real} = T mean(d::Wishart) = d.df * Matrix(d.S) diff --git a/src/mixtures/mixturemodel.jl b/src/mixtures/mixturemodel.jl index f0aeebce99..48231cbae0 100644 --- a/src/mixtures/mixturemodel.jl +++ b/src/mixtures/mixturemodel.jl @@ -167,7 +167,7 @@ component(d::MixtureModel, k::Int) = d.components[k] probs(d::MixtureModel) = probs(d.prior) params(d::MixtureModel) = ([params(c) for c in d.components], params(d.prior)[1]) -partype(d::MixtureModel) = promote_type(partype(d.prior), map(partype, d.components)...) +partype(::Type{<:MixtureModel{VF,VS,C,CT}}) where {VF,VS,C,CT} = promote_type(partype(CT), partype(C)) minimum(d::MixtureModel) = minimum([minimum(dci) for dci in d.components]) maximum(d::MixtureModel) = maximum([maximum(dci) for dci in d.components]) diff --git a/src/mixtures/unigmm.jl b/src/mixtures/unigmm.jl index f1d808ec18..1872dc7347 100644 --- a/src/mixtures/unigmm.jl +++ b/src/mixtures/unigmm.jl @@ -31,6 +31,7 @@ rand(rng::AbstractRNG, d::UnivariateGMM) = (k = rand(rng, d.prior); d.means[k] + randn(rng) * d.stds[k]) params(d::UnivariateGMM) = (d.means, d.stds, d.prior) +partype(::Type{<:UnivariateGMM{VT1,VT2,C}}) where {VT1,VT2,C} = promote_type(eltype(VT1), eltype(VT2), partype(C)) struct UnivariateGMMSampler{VT1<:AbstractVector{<:Real},VT2<:AbstractVector{<:Real}} <: Sampleable{Univariate,Continuous} means::VT1 diff --git a/src/multivariate/dirichlet.jl b/src/multivariate/dirichlet.jl index 0717cdfe1e..3b1c8333c0 100644 --- a/src/multivariate/dirichlet.jl +++ b/src/multivariate/dirichlet.jl @@ -72,7 +72,7 @@ Base.show(io::IO, d::Dirichlet) = show(io, d, (:alpha,)) length(d::Dirichlet) = length(d.alpha) mean(d::Dirichlet) = d.alpha .* inv(d.alpha0) params(d::Dirichlet) = (d.alpha,) -@inline partype(::Dirichlet{T}) where {T<:Real} = T +partype(::Type{<:Dirichlet{T}}) where {T<:Real} = T function var(d::Dirichlet) α0 = d.alpha0 diff --git a/src/multivariate/dirichletmultinomial.jl b/src/multivariate/dirichletmultinomial.jl index f3d210b005..dcab5d11af 100644 --- a/src/multivariate/dirichletmultinomial.jl +++ b/src/multivariate/dirichletmultinomial.jl @@ -55,7 +55,7 @@ ncategories(d::DirichletMultinomial) = length(d.α) length(d::DirichletMultinomial) = ncategories(d) ntrials(d::DirichletMultinomial) = d.n params(d::DirichletMultinomial) = (d.n, d.α) -@inline partype(d::DirichletMultinomial{T}) where {T} = T +partype(::Type{<:DirichletMultinomial{T}}) where {T} = T # Statistics mean(d::DirichletMultinomial) = d.α .* (d.n / d.α0) diff --git a/src/multivariate/jointorderstatistics.jl b/src/multivariate/jointorderstatistics.jl index 1fbed0d1b6..5675be04af 100644 --- a/src/multivariate/jointorderstatistics.jl +++ b/src/multivariate/jointorderstatistics.jl @@ -87,7 +87,7 @@ minimum(d::JointOrderStatistics) = Fill(minimum(d.dist), length(d)) maximum(d::JointOrderStatistics) = Fill(maximum(d.dist), length(d)) params(d::JointOrderStatistics) = tuple(params(d.dist)..., d.n, d.ranks) -partype(d::JointOrderStatistics) = partype(d.dist) +partype(::Type{<:JointOrderStatistics{D}}) where {D} = partype(D) Base.eltype(::Type{<:JointOrderStatistics{D}}) where {D} = Base.eltype(D) Base.eltype(d::JointOrderStatistics) = eltype(d.dist) diff --git a/src/multivariate/multinomial.jl b/src/multivariate/multinomial.jl index f365450cab..c70cc64a2c 100644 --- a/src/multivariate/multinomial.jl +++ b/src/multivariate/multinomial.jl @@ -47,7 +47,7 @@ probs(d::Multinomial) = d.p ntrials(d::Multinomial) = d.n params(d::Multinomial) = (d.n, d.p) -@inline partype(d::Multinomial{T}) where {T<:Real} = T +partype(::Type{<:Multinomial{T}}) where {T<:Real} = T ### Conversions convert(::Type{Multinomial{T, TV}}, d::Multinomial) where {T<:Real, TV<:AbstractVector{T}} = Multinomial(d.n, TV(d.p)) diff --git a/src/multivariate/mvlogitnormal.jl b/src/multivariate/mvlogitnormal.jl index 0d60ddf654..25ca95b522 100644 --- a/src/multivariate/mvlogitnormal.jl +++ b/src/multivariate/mvlogitnormal.jl @@ -55,7 +55,7 @@ length(d::MvLogitNormal) = length(d.normal) + 1 Base.eltype(::Type{<:MvLogitNormal{D}}) where {D} = eltype(D) Base.eltype(d::MvLogitNormal) = eltype(d.normal) params(d::MvLogitNormal) = params(d.normal) -@inline partype(d::MvLogitNormal) = partype(d.normal) +partype(::Type{<:MvLogitNormal{D}}) where {D} = partype(D) location(d::MvLogitNormal) = mean(d.normal) minimum(d::MvLogitNormal) = fill(zero(eltype(d)), length(d)) diff --git a/src/multivariate/mvlognormal.jl b/src/multivariate/mvlognormal.jl index 046f709493..c8f48421a4 100644 --- a/src/multivariate/mvlognormal.jl +++ b/src/multivariate/mvlognormal.jl @@ -190,7 +190,7 @@ end length(d::MvLogNormal) = length(d.normal) params(d::MvLogNormal) = params(d.normal) -@inline partype(d::MvLogNormal{T}) where {T<:Real} = T +partype(::Type{<:MvLogNormal{T}}) where {T<:Real} = T """ location(d::MvLogNormal) diff --git a/src/multivariate/mvnormal.jl b/src/multivariate/mvnormal.jl index 202f449f21..29eb518d14 100644 --- a/src/multivariate/mvnormal.jl +++ b/src/multivariate/mvnormal.jl @@ -249,7 +249,7 @@ Base.show(io::IO, d::MvNormal) = length(d::MvNormal) = length(d.μ) mean(d::MvNormal) = d.μ params(d::MvNormal) = (d.μ, d.Σ) -@inline partype(d::MvNormal{T}) where {T<:Real} = T +partype(::Type{<:MvNormal{T}}) where {T<:Real} = T var(d::MvNormal) = diag(d.Σ) cov(d::MvNormal) = d.Σ diff --git a/src/multivariate/mvnormalcanon.jl b/src/multivariate/mvnormalcanon.jl index 79b43e9ba9..c8f1f4155f 100644 --- a/src/multivariate/mvnormalcanon.jl +++ b/src/multivariate/mvnormalcanon.jl @@ -153,7 +153,7 @@ canonform(d::MvNormal{T,C,Zeros{T}}) where {C, T<:Real} = MvNormalCanon(inv(d.Σ length(d::MvNormalCanon) = length(d.μ) mean(d::MvNormalCanon) = convert(Vector{eltype(d.μ)}, d.μ) params(d::MvNormalCanon) = (d.μ, d.h, d.J) -@inline partype(d::MvNormalCanon{T}) where {T<:Real} = T +partype(::Type{<:MvNormalCanon{T}}) where {T<:Real} = T Base.eltype(::Type{<:MvNormalCanon{T}}) where {T} = T var(d::MvNormalCanon) = diag(inv(d.J)) diff --git a/src/multivariate/mvtdist.jl b/src/multivariate/mvtdist.jl index 9076c364b5..bbd7136542 100644 --- a/src/multivariate/mvtdist.jl +++ b/src/multivariate/mvtdist.jl @@ -100,7 +100,7 @@ invcov(d::GenericMvTDist) = d.df>2 ? ((d.df-2)/d.df)*Matrix(inv(d.Σ)) : NaN*one logdet_cov(d::GenericMvTDist) = d.df>2 ? logdet((d.df/(d.df-2))*d.Σ) : NaN params(d::GenericMvTDist) = (d.df, d.μ, d.Σ) -@inline partype(d::GenericMvTDist{T}) where {T} = T +partype(::Type{<:GenericMvTDist{T}}) where {T} = T Base.eltype(::Type{<:GenericMvTDist{T}}) where {T} = T # For entropy calculations see "Multivariate t Distributions and their Applications", S. Kotz & S. Nadarajah diff --git a/src/multivariate/product.jl b/src/multivariate/product.jl index ada1c4e5f4..ac47735f32 100644 --- a/src/multivariate/product.jl +++ b/src/multivariate/product.jl @@ -39,6 +39,7 @@ function Base.eltype(::Type{<:Product{S,T}}) where {S<:ValueSupport, T<:UnivariateDistribution{S}} return eltype(T) end +partype(::Type{<:Product{S,T}}) where {S,T} = partype(T) _rand!(rng::AbstractRNG, d::Product, x::AbstractVector{<:Real}) = map!(Base.Fix1(rand, rng), x, d.v) diff --git a/src/multivariate/vonmisesfisher.jl b/src/multivariate/vonmisesfisher.jl index e4fe981fe6..610c7e1856 100644 --- a/src/multivariate/vonmisesfisher.jl +++ b/src/multivariate/vonmisesfisher.jl @@ -57,7 +57,7 @@ concentration(d::VonMisesFisher) = d.κ insupport(d::VonMisesFisher, x::AbstractVector{T}) where {T<:Real} = isunitvec(x) params(d::VonMisesFisher) = (d.μ, d.κ) -@inline partype(d::VonMisesFisher{T}) where {T<:Real} = T +partype(::Type{<:VonMisesFisher{T}}) where {T<:Real} = T ### Evaluation diff --git a/src/reshaped.jl b/src/reshaped.jl index 1fdfde033d..3f635e6049 100644 --- a/src/reshaped.jl +++ b/src/reshaped.jl @@ -26,7 +26,7 @@ end Base.size(d::ReshapedDistribution) = d.dims Base.eltype(::Type{ReshapedDistribution{<:Any,<:ValueSupport,D}}) where {D} = eltype(D) -partype(d::ReshapedDistribution) = partype(d.dist) +partype(::Type{<:ReshapedDistribution{<:Any,<:ValueSupport,D}}) where {D} = partype(D) params(d::ReshapedDistribution) = (d.dist, d.dims) function insupport(d::ReshapedDistribution{N}, x::AbstractArray{<:Real,N}) where {N} diff --git a/src/truncate.jl b/src/truncate.jl index 48d62b015b..b323be9433 100644 --- a/src/truncate.jl +++ b/src/truncate.jl @@ -124,7 +124,7 @@ function truncated(d::Truncated, l::Real, ::Nothing) end params(d::Truncated) = tuple(params(d.untruncated)..., d.lower, d.upper) -partype(d::Truncated{<:UnivariateDistribution,<:ValueSupport,T}) where {T<:Real} = promote_type(partype(d.untruncated), T) +partype(::Type{<:Truncated{D,S,T}}) where {D,S,T} = promote_type(partype(D), T) Base.eltype(::Type{<:Truncated{D}}) where {D<:UnivariateDistribution} = eltype(D) Base.eltype(d::Truncated) = eltype(d.untruncated) diff --git a/src/univariate/continuous/arcsine.jl b/src/univariate/continuous/arcsine.jl index 9e055a67ff..d5381397fe 100644 --- a/src/univariate/continuous/arcsine.jl +++ b/src/univariate/continuous/arcsine.jl @@ -55,7 +55,7 @@ Base.convert(::Type{Arcsine{T}}, d::Arcsine{T}) where {T<:Real} = d location(d::Arcsine) = d.a scale(d::Arcsine) = d.b - d.a params(d::Arcsine) = (d.a, d.b) -partype(::Arcsine{T}) where {T} = T +partype(::Type{<:Arcsine{T}}) where {T} = T ### Statistics diff --git a/src/univariate/continuous/beta.jl b/src/univariate/continuous/beta.jl index fd2420d815..b4df5e17ca 100644 --- a/src/univariate/continuous/beta.jl +++ b/src/univariate/continuous/beta.jl @@ -57,7 +57,7 @@ Base.convert(::Type{Beta{T}}, d::Beta{T}) where {T<:Real} = d #### Parameters params(d::Beta) = (d.α, d.β) -@inline partype(d::Beta{T}) where {T<:Real} = T +partype(::Type{<:Beta{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/betaprime.jl b/src/univariate/continuous/betaprime.jl index 1ca65b5e85..a97ba14e20 100644 --- a/src/univariate/continuous/betaprime.jl +++ b/src/univariate/continuous/betaprime.jl @@ -57,7 +57,7 @@ Base.convert(::Type{BetaPrime{T}}, d::BetaPrime{T}) where {T<:Real} = d #### Parameters params(d::BetaPrime) = (d.α, d.β) -@inline partype(d::BetaPrime{T}) where {T<:Real} = T +partype(::Type{<:BetaPrime{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/biweight.jl b/src/univariate/continuous/biweight.jl index 93c6785ef4..7cea0ececb 100644 --- a/src/univariate/continuous/biweight.jl +++ b/src/univariate/continuous/biweight.jl @@ -20,7 +20,7 @@ Biweight(μ::Real=0.0) = Biweight(μ, one(μ); check_args=false) ## Parameters params(d::Biweight) = (d.μ, d.σ) -@inline partype(d::Biweight{T}) where {T<:Real} = T +partype(::Type{<:Biweight{T}}) where {T<:Real} = T ## Properties mean(d::Biweight) = d.μ diff --git a/src/univariate/continuous/cauchy.jl b/src/univariate/continuous/cauchy.jl index 85f8e592ca..488595f9c6 100644 --- a/src/univariate/continuous/cauchy.jl +++ b/src/univariate/continuous/cauchy.jl @@ -52,7 +52,7 @@ location(d::Cauchy) = d.μ scale(d::Cauchy) = d.σ params(d::Cauchy) = (d.μ, d.σ) -@inline partype(d::Cauchy{T}) where {T<:Real} = T +partype(::Type{<:Cauchy{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/chernoff.jl b/src/univariate/continuous/chernoff.jl index 3d319db252..6f9f1034da 100644 --- a/src/univariate/continuous/chernoff.jl +++ b/src/univariate/continuous/chernoff.jl @@ -33,6 +33,8 @@ cdf(Chernoff(),-x) # For tail probabilities, use this instead of 1- struct Chernoff <: ContinuousUnivariateDistribution end +partype(::Type{Chernoff}) = Union{} + module ChernoffComputations import QuadGK.quadgk # The following arrays of constants have been precomputed to speed up computation. diff --git a/src/univariate/continuous/chi.jl b/src/univariate/continuous/chi.jl index 0cdbdfbc00..5ec9adfd87 100644 --- a/src/univariate/continuous/chi.jl +++ b/src/univariate/continuous/chi.jl @@ -44,7 +44,7 @@ Base.convert(::Type{Chi{T}}, d::Chi{T}) where {T<:Real} = d dof(d::Chi) = d.ν params(d::Chi) = (d.ν,) -@inline partype(d::Chi{T}) where {T<:Real} = T +partype(::Type{<:Chi{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/chisq.jl b/src/univariate/continuous/chisq.jl index a7180c9200..19d4f85bab 100644 --- a/src/univariate/continuous/chisq.jl +++ b/src/univariate/continuous/chisq.jl @@ -38,7 +38,7 @@ Chisq(ν::Integer; check_args::Bool=true) = Chisq(float(ν); check_args=check_ar dof(d::Chisq) = d.ν params(d::Chisq) = (d.ν,) -@inline partype(d::Chisq{T}) where {T<:Real} = T +partype(::Type{<:Chisq{T}}) where {T<:Real} = T ### Conversions convert(::Type{Chisq{T}}, ν::Real) where {T<:Real} = Chisq(T(ν)) diff --git a/src/univariate/continuous/cosine.jl b/src/univariate/continuous/cosine.jl index 4d11a9ddde..50e4d58547 100644 --- a/src/univariate/continuous/cosine.jl +++ b/src/univariate/continuous/cosine.jl @@ -39,7 +39,7 @@ location(d::Cosine) = d.μ scale(d::Cosine) = d.σ params(d::Cosine) = (d.μ, d.σ) -@inline partype(d::Cosine{T}) where {T<:Real} = T +partype(::Type{<:Cosine{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/epanechnikov.jl b/src/univariate/continuous/epanechnikov.jl index ea75c09ea5..b13d768045 100644 --- a/src/univariate/continuous/epanechnikov.jl +++ b/src/univariate/continuous/epanechnikov.jl @@ -32,7 +32,7 @@ Base.convert(::Type{Epanechnikov{T}}, d::Epanechnikov{T}) where {T<:Real} = d location(d::Epanechnikov) = d.μ scale(d::Epanechnikov) = d.σ params(d::Epanechnikov) = (d.μ, d.σ) -@inline partype(d::Epanechnikov{T}) where {T<:Real} = T +partype(::Type{<:Epanechnikov{T}}) where {T<:Real} = T ## Properties mean(d::Epanechnikov) = d.μ diff --git a/src/univariate/continuous/erlang.jl b/src/univariate/continuous/erlang.jl index cd984415e0..f99469276d 100644 --- a/src/univariate/continuous/erlang.jl +++ b/src/univariate/continuous/erlang.jl @@ -53,7 +53,7 @@ shape(d::Erlang) = d.α scale(d::Erlang) = d.θ rate(d::Erlang) = inv(d.θ) params(d::Erlang) = (d.α, d.θ) -@inline partype(d::Erlang{T}) where {T<:Real} = T +partype(::Type{<:Erlang{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/exponential.jl b/src/univariate/continuous/exponential.jl index 96737c94a2..431cc77707 100644 --- a/src/univariate/continuous/exponential.jl +++ b/src/univariate/continuous/exponential.jl @@ -49,7 +49,7 @@ scale(d::Exponential) = d.θ rate(d::Exponential) = inv(d.θ) params(d::Exponential) = (d.θ,) -partype(::Exponential{T}) where {T<:Real} = T +partype(::Type{<:Exponential{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/fdist.jl b/src/univariate/continuous/fdist.jl index e3f2ba104f..6f905cd6ca 100644 --- a/src/univariate/continuous/fdist.jl +++ b/src/univariate/continuous/fdist.jl @@ -48,7 +48,7 @@ Base.convert(::Type{FDist{T}}, d::FDist{T}) where {T<:Real} = d #### Parameters params(d::FDist) = (d.ν1, d.ν2) -@inline partype(d::FDist{T}) where {T<:Real} = T +partype(::Type{<:FDist{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/frechet.jl b/src/univariate/continuous/frechet.jl index 46b6d40f9a..5aace63e2d 100644 --- a/src/univariate/continuous/frechet.jl +++ b/src/univariate/continuous/frechet.jl @@ -52,7 +52,7 @@ Base.convert(::Type{Frechet{T}}, d::Frechet{T}) where {T<:Real} = d shape(d::Frechet) = d.α scale(d::Frechet) = d.θ params(d::Frechet) = (d.α, d.θ) -partype(::Frechet{T}) where {T} = T +partype(::Type{<:Frechet{T}}) where {T} = T #### Statistics diff --git a/src/univariate/continuous/gamma.jl b/src/univariate/continuous/gamma.jl index fc452ba708..f420449ccd 100644 --- a/src/univariate/continuous/gamma.jl +++ b/src/univariate/continuous/gamma.jl @@ -54,7 +54,7 @@ scale(d::Gamma) = d.θ rate(d::Gamma) = 1 / d.θ params(d::Gamma) = (d.α, d.θ) -partype(::Gamma{T}) where {T} = T +partype(::Type{<:Gamma{T}}) where {T} = T #### Statistics diff --git a/src/univariate/continuous/generalizedextremevalue.jl b/src/univariate/continuous/generalizedextremevalue.jl index f8d0541b33..0136bacb9f 100644 --- a/src/univariate/continuous/generalizedextremevalue.jl +++ b/src/univariate/continuous/generalizedextremevalue.jl @@ -72,7 +72,7 @@ shape(d::GeneralizedExtremeValue) = d.ξ scale(d::GeneralizedExtremeValue) = d.σ location(d::GeneralizedExtremeValue) = d.μ params(d::GeneralizedExtremeValue) = (d.μ, d.σ, d.ξ) -@inline partype(d::GeneralizedExtremeValue{T}) where {T<:Real} = T +partype(::Type{<:GeneralizedExtremeValue{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/generalizedpareto.jl b/src/univariate/continuous/generalizedpareto.jl index 3a5f35ec83..b92f795b79 100644 --- a/src/univariate/continuous/generalizedpareto.jl +++ b/src/univariate/continuous/generalizedpareto.jl @@ -78,7 +78,7 @@ location(d::GeneralizedPareto) = d.μ scale(d::GeneralizedPareto) = d.σ shape(d::GeneralizedPareto) = d.ξ params(d::GeneralizedPareto) = (d.μ, d.σ, d.ξ) -partype(::GeneralizedPareto{T}) where {T} = T +partype(::Type{<:GeneralizedPareto{T}}) where {T} = T #### Statistics diff --git a/src/univariate/continuous/gumbel.jl b/src/univariate/continuous/gumbel.jl index 54090967fc..be659c46c8 100644 --- a/src/univariate/continuous/gumbel.jl +++ b/src/univariate/continuous/gumbel.jl @@ -54,7 +54,7 @@ Base.convert(::Type{Gumbel{T}}, d::Gumbel{T}) where {T<:Real} = d location(d::Gumbel) = d.μ scale(d::Gumbel) = d.θ params(d::Gumbel) = (d.μ, d.θ) -partype(::Gumbel{T}) where {T} = T +partype(::Type{<:Gumbel{T}}) where {T} = T function Base.rand(rng::Random.AbstractRNG, d::Gumbel) return d.μ - d.θ * log(randexp(rng, float(eltype(d)))) diff --git a/src/univariate/continuous/inversegamma.jl b/src/univariate/continuous/inversegamma.jl index 60bda1d740..4ea7be6760 100644 --- a/src/univariate/continuous/inversegamma.jl +++ b/src/univariate/continuous/inversegamma.jl @@ -57,7 +57,7 @@ scale(d::InverseGamma) = d.θ rate(d::InverseGamma) = scale(d.invd) params(d::InverseGamma) = (shape(d), scale(d)) -partype(::InverseGamma{T}) where {T} = T +partype(::Type{<:InverseGamma{T}}) where {T} = T #### Parameters diff --git a/src/univariate/continuous/inversegaussian.jl b/src/univariate/continuous/inversegaussian.jl index c3a5661b42..63c81302db 100644 --- a/src/univariate/continuous/inversegaussian.jl +++ b/src/univariate/continuous/inversegaussian.jl @@ -55,7 +55,7 @@ Base.convert(::Type{InverseGaussian{T}}, d::InverseGaussian{T}) where {T<:Real} shape(d::InverseGaussian) = d.λ params(d::InverseGaussian) = (d.μ, d.λ) -partype(::InverseGaussian{T}) where {T} = T +partype(::Type{<:InverseGaussian{T}}) where {T} = T #### Statistics diff --git a/src/univariate/continuous/johnsonsu.jl b/src/univariate/continuous/johnsonsu.jl index 65597adc2d..e7d0b657dd 100644 --- a/src/univariate/continuous/johnsonsu.jl +++ b/src/univariate/continuous/johnsonsu.jl @@ -51,7 +51,7 @@ shape(d::JohnsonSU) = d.ξ scale(d::JohnsonSU) = d.λ params(d::JohnsonSU) = (d.ξ, d.λ, d.γ, d.δ) -partype(d::JohnsonSU{T}) where {T<:Real} = T +partype(::Type{<:JohnsonSU{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/kolmogorov.jl b/src/univariate/continuous/kolmogorov.jl index f7bb373ab8..02d5c43d26 100644 --- a/src/univariate/continuous/kolmogorov.jl +++ b/src/univariate/continuous/kolmogorov.jl @@ -15,6 +15,7 @@ end @distr_support Kolmogorov 0.0 Inf params(d::Kolmogorov) = () +partype(::Type{Kolmogorov}) = Union{} #### Statistics diff --git a/src/univariate/continuous/ksdist.jl b/src/univariate/continuous/ksdist.jl index 1de09651a3..3001031c57 100644 --- a/src/univariate/continuous/ksdist.jl +++ b/src/univariate/continuous/ksdist.jl @@ -14,6 +14,7 @@ struct KSDist <: ContinuousUnivariateDistribution end @distr_support KSDist 1 / (2 * d.n) 1.0 +partype(::Type{KSDist}) = Int #### Evaluation diff --git a/src/univariate/continuous/ksonesided.jl b/src/univariate/continuous/ksonesided.jl index 82d1893929..0869f73064 100644 --- a/src/univariate/continuous/ksonesided.jl +++ b/src/univariate/continuous/ksonesided.jl @@ -12,6 +12,7 @@ struct KSOneSided <: ContinuousUnivariateDistribution end @distr_support KSOneSided 0.0 1.0 +partype(::Type{KSOneSided}) = Int #### Evaluation diff --git a/src/univariate/continuous/kumaraswamy.jl b/src/univariate/continuous/kumaraswamy.jl index 8a3fecfe71..1b37afe7b9 100644 --- a/src/univariate/continuous/kumaraswamy.jl +++ b/src/univariate/continuous/kumaraswamy.jl @@ -43,7 +43,7 @@ Base.convert(::Type{Kumaraswamy{T}}, d::Kumaraswamy{T}) where {T} = d ### Parameters params(d::Kumaraswamy) = (d.a, d.b) -partype(::Kumaraswamy{T}) where {T} = T +partype(::Type{<:Kumaraswamy{T}}) where {T} = T ### Evaluation diff --git a/src/univariate/continuous/laplace.jl b/src/univariate/continuous/laplace.jl index 2a7bf04a47..5c4fec7e3c 100644 --- a/src/univariate/continuous/laplace.jl +++ b/src/univariate/continuous/laplace.jl @@ -55,7 +55,7 @@ Base.convert(::Type{Laplace{T}}, d::Laplace{T}) where {T<:Real} = d location(d::Laplace) = d.μ scale(d::Laplace) = d.θ params(d::Laplace) = (d.μ, d.θ) -@inline partype(d::Laplace{T}) where {T<:Real} = T +partype(::Type{<:Laplace{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/levy.jl b/src/univariate/continuous/levy.jl index e1d80decfc..5085355fa2 100644 --- a/src/univariate/continuous/levy.jl +++ b/src/univariate/continuous/levy.jl @@ -48,7 +48,7 @@ Base.convert(::Type{Levy{T}}, d::Levy{T}) where {T<:Real} = d location(d::Levy) = d.μ params(d::Levy) = (d.μ, d.σ) -partype(::Levy{T}) where {T} = T +partype(::Type{<:Levy{T}}) where {T} = T #### Statistics diff --git a/src/univariate/continuous/lindley.jl b/src/univariate/continuous/lindley.jl index 9e6c3ee797..0dfdfc253d 100644 --- a/src/univariate/continuous/lindley.jl +++ b/src/univariate/continuous/lindley.jl @@ -42,7 +42,7 @@ Base.convert(::Type{Lindley{T}}, d::Lindley{T}) where {T} = d shape(d::Lindley) = d.θ params(d::Lindley) = (shape(d),) -partype(::Lindley{T}) where {T} = T +partype(::Type{<:Lindley{T}}) where {T} = T ### Statistics diff --git a/src/univariate/continuous/logistic.jl b/src/univariate/continuous/logistic.jl index 67e3608947..b3cf4f80cf 100644 --- a/src/univariate/continuous/logistic.jl +++ b/src/univariate/continuous/logistic.jl @@ -56,7 +56,7 @@ location(d::Logistic) = d.μ scale(d::Logistic) = d.θ params(d::Logistic) = (d.μ, d.θ) -@inline partype(d::Logistic{T}) where {T<:Real} = T +partype(::Type{<:Logistic{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/logitnormal.jl b/src/univariate/continuous/logitnormal.jl index 247d4774ce..694495d823 100644 --- a/src/univariate/continuous/logitnormal.jl +++ b/src/univariate/continuous/logitnormal.jl @@ -86,7 +86,7 @@ Base.convert(::Type{LogitNormal{T}}, d::LogitNormal{T}) where {T<:Real} = d params(d::LogitNormal) = (d.μ, d.σ) location(d::LogitNormal) = d.μ scale(d::LogitNormal) = d.σ -@inline partype(d::LogitNormal{T}) where {T<:Real} = T +partype(::Type{<:LogitNormal{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/loglogistic.jl b/src/univariate/continuous/loglogistic.jl index 96f4498688..84a30cfec8 100644 --- a/src/univariate/continuous/loglogistic.jl +++ b/src/univariate/continuous/loglogistic.jl @@ -43,7 +43,7 @@ convert(::Type{LogLogistic{T}}, d::LogLogistic) where {T<:Real} = LogLogistic{T} #### Parameters params(d::LogLogistic) = (d.α, d.β) -partype(::LogLogistic{T}) where {T} = T +partype(::Type{<:LogLogistic{T}}) where {T} = T #### Statistics diff --git a/src/univariate/continuous/lognormal.jl b/src/univariate/continuous/lognormal.jl index b852bb33f5..0da6ab983a 100644 --- a/src/univariate/continuous/lognormal.jl +++ b/src/univariate/continuous/lognormal.jl @@ -51,7 +51,7 @@ Base.convert(::Type{LogNormal{T}}, d::LogNormal{T}) where {T<:Real} = d #### Parameters params(d::LogNormal) = (d.μ, d.σ) -partype(::LogNormal{T}) where {T} = T +partype(::Type{<:LogNormal{T}}) where {T} = T #### Statistics @@ -62,7 +62,6 @@ stdlogx(d::LogNormal) = d.σ mean(d::LogNormal) = ((μ, σ) = params(d); exp(μ + σ^2/2)) median(d::LogNormal) = exp(d.μ) mode(d::LogNormal) = ((μ, σ) = params(d); exp(μ - σ^2)) -partype(::LogNormal{T}) where {T<:Real} = T function var(d::LogNormal) (μ, σ) = params(d) diff --git a/src/univariate/continuous/loguniform.jl b/src/univariate/continuous/loguniform.jl index 9257d8b30c..5630958aaf 100644 --- a/src/univariate/continuous/loguniform.jl +++ b/src/univariate/continuous/loguniform.jl @@ -31,7 +31,7 @@ Base.maximum(d::LogUniform) = d.b #### Parameters params(d::LogUniform) = (d.a, d.b) -partype(::LogUniform{T}) where {T<:Real} = T +partype(::Type{<:LogUniform{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/noncentralbeta.jl b/src/univariate/continuous/noncentralbeta.jl index eecc98c4fb..8aa0897a0d 100644 --- a/src/univariate/continuous/noncentralbeta.jl +++ b/src/univariate/continuous/noncentralbeta.jl @@ -30,7 +30,7 @@ Base.convert(::Type{NoncentralBeta{T}}, d::NoncentralBeta{T}) where {T<:Real} = ### Parameters params(d::NoncentralBeta) = (d.α, d.β, d.λ) -partype(::NoncentralBeta{T}) where {T} = T +partype(::Type{<:NoncentralBeta{T}}) where {T} = T ### Evaluation & Sampling diff --git a/src/univariate/continuous/noncentralchisq.jl b/src/univariate/continuous/noncentralchisq.jl index 99f56e3232..8f4b8d1f66 100644 --- a/src/univariate/continuous/noncentralchisq.jl +++ b/src/univariate/continuous/noncentralchisq.jl @@ -52,7 +52,7 @@ Base.convert(::Type{NoncentralChisq{T}}, d::NoncentralChisq{T}) where {T<:Real} ### Parameters params(d::NoncentralChisq) = (d.ν, d.λ) -@inline partype(d::NoncentralChisq{T}) where {T<:Real} = T +partype(::Type{<:NoncentralChisq{T}}) where {T<:Real} = T ### Statistics diff --git a/src/univariate/continuous/noncentralf.jl b/src/univariate/continuous/noncentralf.jl index 27406ce7bb..820422f07d 100644 --- a/src/univariate/continuous/noncentralf.jl +++ b/src/univariate/continuous/noncentralf.jl @@ -33,7 +33,7 @@ Base.convert(::Type{NoncentralF{T}}, d::NoncentralF{T}) where {T<:Real} = d ### Parameters params(d::NoncentralF) = (d.ν1, d.ν2, d.λ) -partype(::NoncentralF{T}) where {T} = T +partype(::Type{<:NoncentralF{T}}) where {T} = T ### Statistics diff --git a/src/univariate/continuous/noncentralt.jl b/src/univariate/continuous/noncentralt.jl index dfcdb6e3ca..18f1482028 100644 --- a/src/univariate/continuous/noncentralt.jl +++ b/src/univariate/continuous/noncentralt.jl @@ -27,7 +27,7 @@ Base.convert(::Type{NoncentralT{T}}, d::NoncentralT{T}) where {T<:Real} = d ### Parameters params(d::NoncentralT) = (d.ν, d.λ) -partype(::NoncentralT{T}) where {T} = T +partype(::Type{<:NoncentralT{T}}) where {T} = T ### Statistics diff --git a/src/univariate/continuous/normal.jl b/src/univariate/continuous/normal.jl index 063cc1d270..70b42e731a 100644 --- a/src/univariate/continuous/normal.jl +++ b/src/univariate/continuous/normal.jl @@ -55,7 +55,7 @@ Base.convert(::Type{Normal{T}}, d::Normal{T}) where {T<:Real} = d #### Parameters params(d::Normal) = (d.μ, d.σ) -@inline partype(d::Normal{T}) where {T<:Real} = T +partype(::Type{<:Normal{T}}) where {T<:Real} = T location(d::Normal) = d.μ scale(d::Normal) = d.σ diff --git a/src/univariate/continuous/normalcanon.jl b/src/univariate/continuous/normalcanon.jl index 89d45a4fa6..5c88700fc9 100644 --- a/src/univariate/continuous/normalcanon.jl +++ b/src/univariate/continuous/normalcanon.jl @@ -40,7 +40,7 @@ canonform(d::Normal) = convert(NormalCanon, d) #### Parameters params(d::NormalCanon) = (d.η, d.λ) -@inline partype(d::NormalCanon{T}) where {T<:Real} = T +partype(::Type{<:NormalCanon{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/normalinversegaussian.jl b/src/univariate/continuous/normalinversegaussian.jl index 4e2b89decb..d05dbbdf11 100644 --- a/src/univariate/continuous/normalinversegaussian.jl +++ b/src/univariate/continuous/normalinversegaussian.jl @@ -45,7 +45,7 @@ end Base.convert(::Type{NormalInverseGaussian{T}}, d::NormalInverseGaussian{T}) where {T<:Real} = d params(d::NormalInverseGaussian) = (d.μ, d.α, d.β, d.δ) -@inline partype(d::NormalInverseGaussian{T}) where {T<:Real} = T +partype(::Type{<:NormalInverseGaussian{T}}) where {T<:Real} = T mean(d::NormalInverseGaussian) = d.μ + d.δ * d.β / d.γ var(d::NormalInverseGaussian) = d.δ * d.α^2 / d.γ^3 diff --git a/src/univariate/continuous/pareto.jl b/src/univariate/continuous/pareto.jl index 249fa29eb7..52e239f2e4 100644 --- a/src/univariate/continuous/pareto.jl +++ b/src/univariate/continuous/pareto.jl @@ -50,7 +50,7 @@ shape(d::Pareto) = d.α scale(d::Pareto) = d.θ params(d::Pareto) = (d.α, d.θ) -@inline partype(d::Pareto{T}) where {T<:Real} = T +partype(::Type{<:Pareto{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/pgeneralizedgaussian.jl b/src/univariate/continuous/pgeneralizedgaussian.jl index e4e7b3c926..909a44ee68 100644 --- a/src/univariate/continuous/pgeneralizedgaussian.jl +++ b/src/univariate/continuous/pgeneralizedgaussian.jl @@ -72,7 +72,7 @@ Base.convert(::Type{PGeneralizedGaussian{T}}, d::PGeneralizedGaussian{T}) where #### Parameters -partype(::PGeneralizedGaussian{T}) where {T<:Real} = T +partype(::Type{<:PGeneralizedGaussian{T}}) where {T<:Real} = T params(d::PGeneralizedGaussian) = (d.μ, d.α, d.p) location(d::PGeneralizedGaussian) = d.μ diff --git a/src/univariate/continuous/rayleigh.jl b/src/univariate/continuous/rayleigh.jl index 9b475bf125..50b20cfaaf 100644 --- a/src/univariate/continuous/rayleigh.jl +++ b/src/univariate/continuous/rayleigh.jl @@ -48,7 +48,7 @@ Base.convert(::Type{Rayleigh{T}}, d::Rayleigh{T}) where {T<:Real} = d scale(d::Rayleigh) = d.σ params(d::Rayleigh) = (d.σ,) -partype(::Rayleigh{T}) where {T<:Real} = T +partype(::Type{<:Rayleigh{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/rician.jl b/src/univariate/continuous/rician.jl index f5c354f705..67c639ef20 100644 --- a/src/univariate/continuous/rician.jl +++ b/src/univariate/continuous/rician.jl @@ -59,7 +59,7 @@ shape(d::Rician) = d.ν^2 / (2 * d.σ^2) scale(d::Rician) = d.ν^2 + 2 * d.σ^2 params(d::Rician) = (d.ν, d.σ) -partype(d::Rician{T}) where {T<:Real} = T +partype(::Type{<:Rician{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/semicircle.jl b/src/univariate/continuous/semicircle.jl index 760164ea02..b94ea86b6c 100644 --- a/src/univariate/continuous/semicircle.jl +++ b/src/univariate/continuous/semicircle.jl @@ -34,7 +34,7 @@ Semicircle(r::Integer; check_args::Bool=true) = Semicircle(float(r); check_args= @distr_support Semicircle -d.r +d.r params(d::Semicircle) = (d.r,) -partype(::Semicircle{T}) where {T<:Real} = T +partype(::Type{<:Semicircle{T}}) where {T<:Real} = T mean(d::Semicircle) = zero(d.r) var(d::Semicircle) = d.r^2 / 4 diff --git a/src/univariate/continuous/skewedexponentialpower.jl b/src/univariate/continuous/skewedexponentialpower.jl index d771511142..c0bc4ba61b 100644 --- a/src/univariate/continuous/skewedexponentialpower.jl +++ b/src/univariate/continuous/skewedexponentialpower.jl @@ -56,7 +56,7 @@ end Base.convert(::Type{SkewedExponentialPower{T}}, d::SkewedExponentialPower{T}) where {T<:Real} = d ### Parameters -@inline partype(::SkewedExponentialPower{T}) where {T<:Real} = T +partype(::Type{<:SkewedExponentialPower{T}}) where {T<:Real} = T params(d::SkewedExponentialPower) = (d.μ, d.σ, d.p, d.α) location(d::SkewedExponentialPower) = d.μ diff --git a/src/univariate/continuous/skewnormal.jl b/src/univariate/continuous/skewnormal.jl index d2da841d76..5d923277fa 100644 --- a/src/univariate/continuous/skewnormal.jl +++ b/src/univariate/continuous/skewnormal.jl @@ -45,7 +45,7 @@ Base.convert(::Type{SkewNormal{T}}, d::SkewNormal{T}) where {T<:Real} = d #### Parameters params(d::SkewNormal) = (d.ξ, d.ω, d.α) -@inline partype(d::SkewNormal{T}) where {T<:Real} = T +partype(::Type{<:SkewNormal{T}}) where {T<:Real} = T #### Statistics delta(d::SkewNormal) = d.α / √(1 + d.α^2) diff --git a/src/univariate/continuous/studentizedrange.jl b/src/univariate/continuous/studentizedrange.jl index eea76386d0..c985a94be0 100644 --- a/src/univariate/continuous/studentizedrange.jl +++ b/src/univariate/continuous/studentizedrange.jl @@ -57,7 +57,7 @@ Base.convert(::Type{StudentizedRange{T}}, d::StudentizedRange{T}) where {T<:Real ### Parameters params(d::StudentizedRange) = (d.ν, d.k) -@inline partype(d::StudentizedRange{T}) where {T <: Real} = T +partype(::Type{<:StudentizedRange{T}}) where {T <: Real} = T ### Evaluation & Sampling diff --git a/src/univariate/continuous/symtriangular.jl b/src/univariate/continuous/symtriangular.jl index f94518b20d..4a5a7cb7d3 100644 --- a/src/univariate/continuous/symtriangular.jl +++ b/src/univariate/continuous/symtriangular.jl @@ -50,7 +50,7 @@ location(d::SymTriangularDist) = d.μ scale(d::SymTriangularDist) = d.σ params(d::SymTriangularDist) = (d.μ, d.σ) -@inline partype(d::SymTriangularDist{T}) where {T<:Real} = T +partype(::Type{<:SymTriangularDist{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/tdist.jl b/src/univariate/continuous/tdist.jl index 873925c3eb..33bbe960c9 100644 --- a/src/univariate/continuous/tdist.jl +++ b/src/univariate/continuous/tdist.jl @@ -43,7 +43,7 @@ Base.convert(::Type{TDist{T}}, d::TDist{T}) where {T<:Real} = d dof(d::TDist) = d.ν params(d::TDist) = (d.ν,) -@inline partype(d::TDist{T}) where {T<:Real} = T +partype(::Type{<:TDist{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/triangular.jl b/src/univariate/continuous/triangular.jl index 4eebb5a977..5ba2933832 100644 --- a/src/univariate/continuous/triangular.jl +++ b/src/univariate/continuous/triangular.jl @@ -56,7 +56,7 @@ Base.convert(::Type{TriangularDist{T}}, d::TriangularDist{T}) where {T<:Real} = #### Parameters params(d::TriangularDist) = (d.a, d.b, d.c) -partype(::TriangularDist{T}) where {T<:Real} = T +partype(::Type{<:TriangularDist{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/triweight.jl b/src/univariate/continuous/triweight.jl index e84642e3c1..62b9c19a01 100644 --- a/src/univariate/continuous/triweight.jl +++ b/src/univariate/continuous/triweight.jl @@ -29,7 +29,7 @@ Base.convert(::Type{Triweight{T}}, d::Triweight{T}) where {T<:Real} = d location(d::Triweight) = d.μ scale(d::Triweight) = d.σ params(d::Triweight) = (d.μ, d.σ) -@inline partype(d::Triweight{T}) where {T<:Real} = T +partype(::Type{<:Triweight{T}}) where {T<:Real} = T ## Properties diff --git a/src/univariate/continuous/uniform.jl b/src/univariate/continuous/uniform.jl index c865e966c6..87633fbdc0 100644 --- a/src/univariate/continuous/uniform.jl +++ b/src/univariate/continuous/uniform.jl @@ -48,7 +48,7 @@ Base.convert(::Type{Uniform{T}}, d::Uniform{T}) where {T<:Real} = d #### Parameters params(d::Uniform) = (d.a, d.b) -partype(::Uniform{T}) where {T<:Real} = T +partype(::Type{<:Uniform{T}}) where {T<:Real} = T location(d::Uniform) = d.a scale(d::Uniform) = d.b - d.a diff --git a/src/univariate/continuous/vonmises.jl b/src/univariate/continuous/vonmises.jl index 38a20408e7..e809b51319 100644 --- a/src/univariate/continuous/vonmises.jl +++ b/src/univariate/continuous/vonmises.jl @@ -47,7 +47,7 @@ Base.convert(::Type{VonMises{T}}, d::VonMises{T}) where {T<:Real} = d #### Parameters params(d::VonMises) = (d.μ, d.κ) -partype(::VonMises{T}) where {T<:Real} = T +partype(::Type{<:VonMises{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/continuous/weibull.jl b/src/univariate/continuous/weibull.jl index 3542350f9f..c241e4e881 100644 --- a/src/univariate/continuous/weibull.jl +++ b/src/univariate/continuous/weibull.jl @@ -55,7 +55,7 @@ shape(d::Weibull) = d.α scale(d::Weibull) = d.θ params(d::Weibull) = (d.α, d.θ) -partype(::Weibull{T}) where {T<:Real} = T +partype(::Type{<:Weibull{T}}) where {T<:Real} = T #### Statistics diff --git a/src/univariate/discrete/bernoulli.jl b/src/univariate/discrete/bernoulli.jl index c1dee968ce..74732dd796 100644 --- a/src/univariate/discrete/bernoulli.jl +++ b/src/univariate/discrete/bernoulli.jl @@ -53,7 +53,7 @@ succprob(d::Bernoulli) = d.p failprob(d::Bernoulli) = 1 - d.p params(d::Bernoulli) = (d.p,) -partype(::Bernoulli{T}) where {T} = T +partype(::Type{<:Bernoulli{T}}) where {T} = T #### Properties diff --git a/src/univariate/discrete/bernoullilogit.jl b/src/univariate/discrete/bernoullilogit.jl index f82059fed9..61c63043e5 100644 --- a/src/univariate/discrete/bernoullilogit.jl +++ b/src/univariate/discrete/bernoullilogit.jl @@ -38,7 +38,7 @@ logsuccprob(d::BernoulliLogit) = -log1pexp(-d.logitp) logfailprob(d::BernoulliLogit) = -log1pexp(d.logitp) params(d::BernoulliLogit) = (d.logitp,) -partype(::BernoulliLogit{T}) where {T} = T +partype(::Type{<:BernoulliLogit{T}}) where {T} = T #### Properties diff --git a/src/univariate/discrete/betabinomial.jl b/src/univariate/discrete/betabinomial.jl index 7f2a0ac0dc..58f0444e12 100644 --- a/src/univariate/discrete/betabinomial.jl +++ b/src/univariate/discrete/betabinomial.jl @@ -50,7 +50,7 @@ Base.convert(::Type{BetaBinomial{T}}, d::BetaBinomial{T}) where {T<:Real} = d ntrials(d::BetaBinomial) = d.n params(d::BetaBinomial) = (d.n, d.α, d.β) -partype(::BetaBinomial{T}) where {T} = T +partype(::Type{<:BetaBinomial{T}}) where {T} = T #### Properties diff --git a/src/univariate/discrete/binomial.jl b/src/univariate/discrete/binomial.jl index 74c90ee18c..df7c19ba5b 100644 --- a/src/univariate/discrete/binomial.jl +++ b/src/univariate/discrete/binomial.jl @@ -60,7 +60,7 @@ succprob(d::Binomial) = d.p failprob(d::Binomial{T}) where {T} = one(T) - d.p params(d::Binomial) = (d.n, d.p) -@inline partype(::Binomial{T}) where {T<:Real} = T +partype(::Type{<:Binomial{T}}) where {T<:Real} = T #### Properties diff --git a/src/univariate/discrete/categorical.jl b/src/univariate/discrete/categorical.jl index 64b850efca..2b4cee5b3c 100644 --- a/src/univariate/discrete/categorical.jl +++ b/src/univariate/discrete/categorical.jl @@ -50,7 +50,7 @@ convert(::Type{Categorical{P,Ps}}, x::AbstractVector{<:Real}) where { ncategories(d::Categorical) = support(d).stop params(d::Categorical{P,Ps}) where {P<:Real, Ps<:AbstractVector{P}} = (probs(d),) -partype(::Categorical{T}) where {T<:Real} = T +partype(::Type{<:Categorical{T}}) where {T<:Real} = T function Base.isapprox(c1::Categorical, c2::Categorical; kwargs...) # support are of type Base.OneTo, so comparing the cardinality of the support diff --git a/src/univariate/discrete/dirac.jl b/src/univariate/discrete/dirac.jl index 94d082b0fa..0a0640e214 100644 --- a/src/univariate/discrete/dirac.jl +++ b/src/univariate/discrete/dirac.jl @@ -23,6 +23,7 @@ struct Dirac{T} <: DiscreteUnivariateDistribution end Base.eltype(::Type{Dirac{T}}) where {T} = T +partype(::Type{<:Dirac{T}}) where {T} = T insupport(d::Dirac, x::Real) = x == d.value minimum(d::Dirac) = d.value diff --git a/src/univariate/discrete/discretenonparametric.jl b/src/univariate/discrete/discretenonparametric.jl index 72efae4866..a9d18c5750 100644 --- a/src/univariate/discrete/discretenonparametric.jl +++ b/src/univariate/discrete/discretenonparametric.jl @@ -41,6 +41,7 @@ DiscreteNonParametric(vs::AbstractVector{T}, ps::AbstractVector{P}; check_args:: DiscreteNonParametric{T,P,typeof(vs),typeof(ps)}(vs, ps; check_args=check_args) Base.eltype(::Type{<:DiscreteNonParametric{T}}) where T = T +partype(::Type{<:DiscreteNonParametric{T,P}}) where {T,P} = promote_type(T, P) # Conversion convert(::Type{DiscreteNonParametric{T,P,Ts,Ps}}, d::DiscreteNonParametric) where {T,P,Ts,Ps} = diff --git a/src/univariate/discrete/discreteuniform.jl b/src/univariate/discrete/discreteuniform.jl index 407f24aa38..b96c08a145 100644 --- a/src/univariate/discrete/discreteuniform.jl +++ b/src/univariate/discrete/discreteuniform.jl @@ -42,7 +42,7 @@ span(d::DiscreteUniform) = d.b - d.a + 1 probval(d::DiscreteUniform) = d.pv params(d::DiscreteUniform) = (d.a, d.b) -partype(::DiscreteUniform) = Int +partype(::Type{DiscreteUniform}) = Int ### Show diff --git a/src/univariate/discrete/geometric.jl b/src/univariate/discrete/geometric.jl index 20043e60fe..3d28b60248 100644 --- a/src/univariate/discrete/geometric.jl +++ b/src/univariate/discrete/geometric.jl @@ -48,7 +48,7 @@ Base.convert(::Type{Geometric{T}}, d::Geometric{T}) where {T<:Real} = d succprob(d::Geometric) = d.p failprob(d::Geometric) = 1 - d.p params(d::Geometric) = (d.p,) -partype(::Geometric{T}) where {T<:Real} = T +partype(::Type{<:Geometric{T}}) where {T<:Real} = T ### Statistics diff --git a/src/univariate/discrete/hypergeometric.jl b/src/univariate/discrete/hypergeometric.jl index 5534acae07..c90a04dd39 100644 --- a/src/univariate/discrete/hypergeometric.jl +++ b/src/univariate/discrete/hypergeometric.jl @@ -38,7 +38,7 @@ end @distr_support Hypergeometric max(d.n - d.nf, 0) min(d.ns, d.n) -partype(::Hypergeometric) = Int +partype(::Type{Hypergeometric}) = Int ### Parameters diff --git a/src/univariate/discrete/negativebinomial.jl b/src/univariate/discrete/negativebinomial.jl index 0ca8f3c9bd..b02afc3470 100644 --- a/src/univariate/discrete/negativebinomial.jl +++ b/src/univariate/discrete/negativebinomial.jl @@ -60,7 +60,7 @@ Base.convert(::Type{NegativeBinomial{T}}, d::NegativeBinomial{T}) where {T<:Real #### Parameters params(d::NegativeBinomial) = (d.r, d.p) -partype(::NegativeBinomial{T}) where {T} = T +partype(::Type{<:NegativeBinomial{T}}) where {T} = T succprob(d::NegativeBinomial) = d.p failprob(d::NegativeBinomial{T}) where {T} = one(T) - d.p diff --git a/src/univariate/discrete/noncentralhypergeometric.jl b/src/univariate/discrete/noncentralhypergeometric.jl index 10f0369310..4853efca0d 100644 --- a/src/univariate/discrete/noncentralhypergeometric.jl +++ b/src/univariate/discrete/noncentralhypergeometric.jl @@ -29,7 +29,7 @@ function quantile(d::NoncentralHypergeometric{T}, q::Real) where T<:Real end params(d::NoncentralHypergeometric) = (d.ns, d.nf, d.n, d.ω) -@inline partype(d::NoncentralHypergeometric{T}) where {T<:Real} = T +partype(::Type{<:NoncentralHypergeometric{T}}) where {T<:Real} = T ## Fisher's noncentral hypergeometric distribution diff --git a/src/univariate/discrete/poisson.jl b/src/univariate/discrete/poisson.jl index f098edd7b6..f57764d241 100644 --- a/src/univariate/discrete/poisson.jl +++ b/src/univariate/discrete/poisson.jl @@ -44,7 +44,7 @@ Base.convert(::Type{Poisson{T}}, d::Poisson{T}) where {T<:Real} = d ### Parameters params(d::Poisson) = (d.λ,) -partype(::Poisson{T}) where {T} = T +partype(::Type{<:Poisson{T}}) where {T} = T rate(d::Poisson) = d.λ diff --git a/src/univariate/discrete/poissonbinomial.jl b/src/univariate/discrete/poissonbinomial.jl index 66ace32cbb..24690f7ebd 100644 --- a/src/univariate/discrete/poissonbinomial.jl +++ b/src/univariate/discrete/poissonbinomial.jl @@ -78,7 +78,7 @@ succprob(d::PoissonBinomial) = d.p failprob(d::PoissonBinomial{T}) where {T} = one(T) .- d.p params(d::PoissonBinomial) = (d.p,) -partype(::PoissonBinomial{T}) where {T} = T +partype(::Type{<:PoissonBinomial{T}}) where {T} = T #### Properties diff --git a/src/univariate/discrete/skellam.jl b/src/univariate/discrete/skellam.jl index 3dc540063e..e684c62d62 100644 --- a/src/univariate/discrete/skellam.jl +++ b/src/univariate/discrete/skellam.jl @@ -56,7 +56,7 @@ Base.convert(::Type{Skellam{T}}, d::Skellam{T}) where {T<:Real} = d #### Parameters params(d::Skellam) = (d.μ1, d.μ2) -partype(::Skellam{T}) where {T} = T +partype(::Type{<:Skellam{T}}) where {T} = T #### Statistics diff --git a/src/univariate/discrete/soliton.jl b/src/univariate/discrete/soliton.jl index f13d9e3df2..8a8beec1f1 100644 --- a/src/univariate/discrete/soliton.jl +++ b/src/univariate/discrete/soliton.jl @@ -85,6 +85,7 @@ function soliton_ρ(K::Integer, i::Integer) end StatsBase.params(Ω::Soliton) = (Ω.K, Ω.M, Ω.δ, Ω.atol) +partype(::Type{Soliton}) = Float64 function pdf(Ω::Soliton, i::Real) j = searchsortedfirst(Ω.degrees, i) diff --git a/src/univariate/locationscale.jl b/src/univariate/locationscale.jl index ded6c2b2ac..f6057a8c4e 100644 --- a/src/univariate/locationscale.jl +++ b/src/univariate/locationscale.jl @@ -103,7 +103,7 @@ Base.convert(::Type{AffineDistribution{T}}, d::AffineDistribution{T}) where {T<: location(d::AffineDistribution) = d.μ scale(d::AffineDistribution) = d.σ params(d::AffineDistribution) = (d.μ,d.σ,d.ρ) -partype(d::AffineDistribution{T}) where {T} = promote_type(partype(d.ρ), T) +partype(::Type{<:AffineDistribution{T,S,D}}) where {T,S,D} = promote_type(partype(D), T) #### Statistics @@ -175,5 +175,5 @@ Base.:+(x::Real, d::UnivariateDistribution) = d + x Base.:*(x::Real, d::UnivariateDistribution) = AffineDistribution(zero(x), x, d) Base.:*(d::UnivariateDistribution, x::Real) = x * d Base.:-(d::UnivariateDistribution, x::Real) = d + -x -Base.:-(d::UnivariateDistribution) = -one(partype(d)) * d +Base.:-(d::UnivariateDistribution) = -one(promote_type(Int, partype(d))) * d Base.:/(d::UnivariateDistribution, x::Real) = inv(x) * d diff --git a/src/univariate/orderstatistic.jl b/src/univariate/orderstatistic.jl index 49fa5f1a1b..a50bb762e5 100644 --- a/src/univariate/orderstatistic.jl +++ b/src/univariate/orderstatistic.jl @@ -57,7 +57,7 @@ maximum(d::OrderStatistic) = maximum(d.dist) insupport(d::OrderStatistic, x::Real) = insupport(d.dist, x) params(d::OrderStatistic) = tuple(params(d.dist)..., d.n, d.rank) -partype(d::OrderStatistic) = partype(d.dist) +partype(::Type{<:OrderStatistic{D}}) where {D} = partype(D) Base.eltype(::Type{<:OrderStatistic{D}}) where {D} = Base.eltype(D) Base.eltype(d::OrderStatistic) = eltype(d.dist) diff --git a/src/utils.jl b/src/utils.jl index d6eb975241..5c453f40a0 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -122,11 +122,19 @@ function sqrt!!(x::Vector{<:Real}) return x end -# get a type wide enough to represent all a distributions's parameters -# (if the distribution is parametric) -# if the distribution is not parametric, we need this to be a float so that -# in-place pdf calculations, etc. allocate storage correctly -@inline partype(::Distribution) = Float64 +""" + partype(::Type{Distribution}) + +The element type of the parameters of a distribution, i.e. a type wide enough to represent +(the promotion of) all of the distribution's parameters. + +!!! note + The definition `partype(d) = partype(typeof(d))` is provided for convenience so that + instances can be passed instead of types. However the form that accepts a type argument + should be defined for new distribution types. +""" +partype(d::Distribution) = partype(typeof(d)) +partype(::Type{<:Distribution}) = Real # because X == X' keeps failing due to floating point nonsense function isApproxSymmmetric(a::AbstractMatrix{Float64}) diff --git a/test/testutils.jl b/test/testutils.jl index 8a62c52d3b..cd0f6d3208 100644 --- a/test/testutils.jl +++ b/test/testutils.jl @@ -665,6 +665,25 @@ function test_stats(d::ContinuousUnivariateDistribution, xs::AbstractVector{Floa end end +# The element type of a single parameter: a scalar is its own type, arrays/tuples promote +# their entries recursively, a distribution-valued parameter contributes its own `partype`, +# and an absent (`nothing`) optional parameter contributes nothing. +recursive_partype(x::Real) = typeof(x) +recursive_partype(::Nothing) = Union{} +recursive_partype(d::Distribution) = partype(d) +recursive_partype(x::Union{AbstractArray,Tuple}) = + mapreduce(recursive_partype, promote_type, x; init = Union{}) +recursive_partype(x) = eltype(x) + +function test_partype(d::Distribution) + # `partype` is the promotion of the element types of the parameters (the empty + # promotion, `Union{}`, being the identity for `promote_type`), and the instance method + # must agree with the type method + @test partype(d) === partype(typeof(d)) + @test partype(d) === + mapreduce(recursive_partype, promote_type, params(d); init = Union{}) +end + function test_params(d::Distribution) # simply test that params returns something sufficient to # reconstruct d @@ -673,6 +692,7 @@ function test_params(d::Distribution) d_new = D(pars...) @test d_new == d @test d_new == deepcopy(d) + test_partype(d) end function test_params(d::Truncated) @@ -684,6 +704,7 @@ function test_params(d::Truncated) d_new = truncated(D(pars...), d.lower, d.upper) @test d_new == d @test d == deepcopy(d) + test_partype(d) end # Finite difference differentiation diff --git a/test/utils.jl b/test/utils.jl index 2946689bcc..9a40440a3c 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -14,12 +14,42 @@ r = RealInterval(1.5, 4.0) @test partype(MvNormal(rand(Float32, 5), Matrix{Float32}(I, 5, 5))) == Float32 # special cases -@test partype(Kolmogorov()) == Float64 @test partype(Hypergeometric(2, 2, 2)) == Int @test partype(Hypergeometric(2.0, 2, 2)) == Int @test partype(DiscreteUniform(0, 4)) == Int @test partype(DiscreteUniform(0.0, 4)) == Int +# `partype` is defined on the type; the instance method forwards for convenience +@test partype(Normal{Float32}) === Float32 +@test partype(Normal(1.0f0, 2.0f0)) === partype(Normal{Float32}) === Float32 +@test partype(Gamma{Float64}) === Float64 +@test partype(DiscreteUniform) === Int +@test partype(Hypergeometric) === Int + +# wrapper distributions recover the parameter type from the wrapped type parameter +@test partype(Truncated{Normal{Float64},Continuous,Float64}) === Float64 +@test partype(truncated(Normal(0.0f0, 1.0f0), 0, 1)) === Float32 +@test partype(censored(Normal(0.0f0, 1.0f0); lower = 0)) === Float32 + +# parametric distributions that previously fell back to the `Float64` default +# now report their actual parameter type +@test partype(Dirac{Float32}) === Float32 +@test partype(Dirac(1.0f0)) === Float32 +@test partype(DiscreteNonParametric([1, 2], Float32[0.5, 0.5])) === Float32 + +# distributions without parameters have an empty parameter promotion (`Union{}`), +# which is the identity for `promote_type` and composes through wrappers +@test partype(Chernoff()) === Union{} +@test partype(Kolmogorov()) === Union{} +@test partype(truncated(Kolmogorov(); lower = 0.0, upper = 1.0)) === Float64 +# the sample size `n` is the only parameter of the Kolmogorov-Smirnov distributions +@test partype(KSDist(5)) === Int +@test partype(KSOneSided(5)) === Int + +# the generic default for an unknown distribution type: parameters are `<:Real`, and +# `eltype(Real) === Real`, so the fallback is `Real` (and `zero`/`one` work on it) +@test partype(Distribution) === Real + A = rand(1:10, 5, 5) B = rand(Float32, 4) C = 1//2 From 0ea502325f1b837ac1698dbda74ae0c5a4d4abf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller-Widmann?= Date: Tue, 23 Jun 2026 10:03:29 +0200 Subject: [PATCH 2/4] Add regression tests for `partype` on abstract types `partype` defined on types mirrors `eltype`: a specific method like `partype(::Type{<:Normal{T}}) where {T<:Real}` only matches a concrete subtype, so a bare UnionAll (`Normal`, whose parameter is only an upper bound) does not match and dispatch falls through to the generic `partype(::Type{<:Distribution}) = Real` default, just like `eltype(Vector)` returns `Any`. This was correct but untested. Add assertions covering bare parametric UnionAlls, abstract nodes in the type hierarchy, and the motivating `partype(eltype(container))` use for both concrete and abstract element types, so a future subtyping change can't silently regress the fallback. Co-Authored-By: Claude Opus 4.8 (1M context) --- test/utils.jl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/utils.jl b/test/utils.jl index 9a40440a3c..0249df568c 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -50,6 +50,26 @@ r = RealInterval(1.5, 4.0) # `eltype(Real) === Real`, so the fallback is `Real` (and `zero`/`one` work on it) @test partype(Distribution) === Real +# abstract types: the parameters are only upper bounds, so `partype` falls back to the +# generic default `Real`, mirroring `eltype(Vector) === Any` in Base +@test partype(Normal) === Real +@test partype(Gamma) === Real +@test partype(MvNormal) === Real +@test partype(Dirac) === Real +@test partype(DiscreteNonParametric) === Real +@test partype(Truncated) === Real +@test partype(Distributions.Censored) === Real +@test partype(Product) === Real +@test partype(MixtureModel) === Real +@test partype(UnivariateDistribution) === Real +@test partype(ContinuousUnivariateDistribution) === Real + +# the motivating use: `partype(eltype(container))` works whether or not the container is +# concretely typed +@test partype(eltype([Normal(0.0f0, 1.0f0)])) === Float32 # concrete eltype +@test partype(eltype(Normal[Normal(0.0, 1.0)])) === Real # abstract eltype -> fallback +@test partype(eltype(Distribution[Normal(0.0, 1.0)])) === Real + A = rand(1:10, 5, 5) B = rand(Float32, 4) C = 1//2 From 9d21a4ef9ee3390b2c004df62e01e3ff031b72f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller-Widmann?= Date: Tue, 23 Jun 2026 19:55:34 +0200 Subject: [PATCH 3/4] Test `partype` per distribution and assert inferribility Move the `partype` tests out of `test/utils.jl` and into each distribution's own test file, covering the methods that the standard `test_params` battery does not exercise. This fixes the patch-coverage gap for the newly type-based `partype` methods on `BernoulliLogit`, `Semicircle`, `PoissonBinomial`, `Soliton`, the deprecated `Product`, and the unary negation `-(d::UnivariateDistribution)`. - Enable `bernoullilogit`, `hypergeometric`, `ksdist`, and `ksonesided` in `runtests.jl`; the first was never run, the latter three had no test file (they are not part of the ref-data battery), so add minimal files for them. - Keep the generic-mechanism tests (the `Real` fallback for abstract types and `partype(eltype(container))`) in `normal.jl`. - Wrap every `partype` test in `@inferred` so the type-based design is asserted to stay constant-foldable. Co-Authored-By: Claude Opus 4.8 (1M context) --- test/censored.jl | 9 ++- test/mixture.jl | 5 ++ test/multivariate/mvnormal.jl | 4 ++ test/multivariate/product.jl | 3 + test/runtests.jl | 7 ++- test/truncate.jl | 10 +++ test/univariate/continuous/chernoff.jl | 3 + test/univariate/continuous/gamma.jl | 6 ++ test/univariate/continuous/kolmogorov.jl | 3 + test/univariate/continuous/ksdist.jl | 8 +++ test/univariate/continuous/ksonesided.jl | 8 +++ test/univariate/continuous/normal.jl | 18 ++++++ test/univariate/continuous/semicircle.jl | 5 ++ test/univariate/discrete/bernoullilogit.jl | 2 +- test/univariate/discrete/dirac.jl | 5 ++ .../discrete/discretenonparametric.jl | 4 ++ test/univariate/discrete/discreteuniform.jl | 7 +++ test/univariate/discrete/hypergeometric.jl | 9 +++ test/univariate/discrete/poissonbinomial.jl | 5 ++ test/univariate/discrete/soliton.jl | 3 + test/univariate/locationscale.jl | 7 +++ test/utils.jl | 62 ------------------- 22 files changed, 124 insertions(+), 69 deletions(-) create mode 100644 test/univariate/continuous/ksdist.jl create mode 100644 test/univariate/continuous/ksonesided.jl create mode 100644 test/univariate/discrete/hypergeometric.jl diff --git a/test/censored.jl b/test/censored.jl index 2488fb9ebb..c1281fc824 100644 --- a/test/censored.jl +++ b/test/censored.jl @@ -102,7 +102,10 @@ end @test d isa Censored @test eltype(d) === Float64 @test params(d) === (params(Normal(0.0, 1.0))..., -1, 2) - @test partype(d) === Float64 + @test @inferred(partype(d)) === Float64 + # promotes the wrapped `partype` with the bound types; bare `Censored` -> `Real` + @test @inferred(partype(censored(Normal(0.0f0, 1.0f0); lower = 0))) === Float32 + @test @inferred(partype(Censored)) === Real @test @inferred extrema(d) == (-1, 2) @test @inferred islowerbounded(d) @test @inferred isupperbounded(d) @@ -117,7 +120,7 @@ end @test d isa Censored @test eltype(d) === Base.promote_type(eltype(Cauchy(0, 1)), Int) @test params(d) === (params(Cauchy(0, 1))..., nothing, 2) - @test partype(d) === Float64 + @test @inferred(partype(d)) === Float64 @test extrema(d) == (-Inf, 2.0) @test @inferred !islowerbounded(d) @test @inferred isupperbounded(d) @@ -131,7 +134,7 @@ end @test d isa Censored @test eltype(d) === Base.promote_type(eltype(Gamma(1, 2)), Int) @test params(d) === (params(Gamma(1, 2))..., 2, nothing) - @test partype(d) === Float64 + @test @inferred(partype(d)) === Float64 @test extrema(d) == (2.0, Inf) @test @inferred islowerbounded(d) @test @inferred !isupperbounded(d) diff --git a/test/mixture.jl b/test/mixture.jl index d2b2742ebc..5f9baac957 100644 --- a/test/mixture.jl +++ b/test/mixture.jl @@ -291,3 +291,8 @@ end end end end + +@testset "partype" begin + # bare `MixtureModel` (a UnionAll) falls back to the generic `Real` default + @test @inferred(partype(MixtureModel)) === Real +end diff --git a/test/multivariate/mvnormal.jl b/test/multivariate/mvnormal.jl index 4af9275b3f..e9e802721c 100644 --- a/test/multivariate/mvnormal.jl +++ b/test/multivariate/mvnormal.jl @@ -131,6 +131,10 @@ end @test isa(logpdf(d32, X32), Float32) @test logpdf(d32, X32) ≈ logpdf(d, X) + + # bare `MvNormal` (a UnionAll) falls back to the generic `Real` default + @test @inferred(partype(MvNormal(rand(Float32, 5), Matrix{Float32}(I, 5, 5)))) === Float32 + @test @inferred(partype(MvNormal)) === Real end ##### Random sampling from MvNormalCanon with sparse precision matrix diff --git a/test/multivariate/product.jl b/test/multivariate/product.jl index ada4302c12..bf7c9e41e3 100644 --- a/test/multivariate/product.jl +++ b/test/multivariate/product.jl @@ -21,6 +21,9 @@ using Distributions: Product # Check that methods for `Product` are consistent. @test length(d_product) == length(ds) @test eltype(d_product) === eltype(ds[1]) + # bare `Product` (a UnionAll) falls back to the generic `Real` default + @test @inferred(partype(d_product)) === Float64 + @test @inferred(partype(Product)) === Real @test @inferred(logpdf(d_product, x)) ≈ sum(logpdf.(ds, x)) @test mean(d_product) == mean.(ds) @test std(d_product) == std.(ds) diff --git a/test/runtests.jl b/test/runtests.jl index ac2b4714a5..34ae9fb8c5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -48,6 +48,8 @@ const tests = [ "univariate/continuous/logitnormal", "multivariate/mvtdist", "univariate/continuous/kolmogorov", + "univariate/continuous/ksdist", + "univariate/continuous/ksonesided", "edgeworth", "matrixreshaped", # extra file compared to /src "matrixvariates", @@ -71,6 +73,8 @@ const tests = [ "univariate/discrete/negativebinomial", "univariate/discrete/geometric", "univariate/discrete/bernoulli", + "univariate/discrete/bernoullilogit", + "univariate/discrete/hypergeometric", "univariate/discrete/poisson", "univariate/discrete/soliton", "univariate/continuous/skewnormal", @@ -146,8 +150,6 @@ const tests = [ # "univariate/continuous/generalizedextremevalue", # "univariate/continuous/generalizedpareto", # "univariate/continuous/inversegamma", - # "univariate/continuous/ksdist", - # "univariate/continuous/ksonesided", # "univariate/continuous/noncentralbeta", # "univariate/continuous/noncentralf", # "univariate/continuous/normalinversegaussian", @@ -156,7 +158,6 @@ const tests = [ # "univariate/continuous/triweight", # "univariate/continuous/noncentralf", # "univariate/discrete/geometric", - # "univariate/discrete/hypergeometric", # "univariate/discrete/noncentralhypergeometric", # "univariate/discrete/poisson", # "univariate/discrete/skellam", diff --git a/test/truncate.jl b/test/truncate.jl index 8f3b3a6e09..ec6def0038 100644 --- a/test/truncate.jl +++ b/test/truncate.jl @@ -237,3 +237,13 @@ end @test @inferred(cdf(dist, 2.82)) === 1.0 @test @inferred(ccdf(dist, 2.82)) === 0.0 end + +@testset "partype" begin + # promotes the untruncated `partype` with the bound types + @test @inferred(partype(Truncated{Normal{Float64},Continuous,Float64})) === Float64 + @test @inferred(partype(truncated(Normal(0.0f0, 1.0f0), 0, 1))) === Float32 + # `Kolmogorov` has no parameters (`partype` is `Union{}`), so the bounds decide + @test @inferred(partype(truncated(Kolmogorov(); lower = 0.0, upper = 1.0))) === Float64 + # bare `Truncated` (a UnionAll) falls back to the generic `Real` default + @test @inferred(partype(Truncated)) === Real +end diff --git a/test/univariate/continuous/chernoff.jl b/test/univariate/continuous/chernoff.jl index a5f28d02bc..014a923e86 100644 --- a/test/univariate/continuous/chernoff.jl +++ b/test/univariate/continuous/chernoff.jl @@ -155,4 +155,7 @@ for i=1:size(pdftest, 1) @test isapprox(pdf(d, pdftest[i, 1]), pdftest[i, 2] ; atol = 1e-6) end + + # no parameters: `partype` is the empty promotion `Union{}` + @test @inferred(partype(Chernoff())) === Union{} end diff --git a/test/univariate/continuous/gamma.jl b/test/univariate/continuous/gamma.jl index 8c1887786e..bfdb1b49ee 100644 --- a/test/univariate/continuous/gamma.jl +++ b/test/univariate/continuous/gamma.jl @@ -30,4 +30,10 @@ using Test, Distributions, OffsetArrays @test @inferred(rand(Gamma(1/T(2), T(1)))) isa T @test @inferred(rand(Gamma(T(2), T(1)))) isa T end + + # bare `Gamma` (a UnionAll) falls back to the generic `Real` default + @test @inferred(partype(Gamma(1, 2))) === Float64 + @test @inferred(partype(Gamma(1.1, 2))) === Float64 + @test @inferred(partype(Gamma{Float64})) === Float64 + @test @inferred(partype(Gamma)) === Real end diff --git a/test/univariate/continuous/kolmogorov.jl b/test/univariate/continuous/kolmogorov.jl index 70c506eeba..374cb0e47f 100644 --- a/test/univariate/continuous/kolmogorov.jl +++ b/test/univariate/continuous/kolmogorov.jl @@ -14,3 +14,6 @@ d = Kolmogorov() @test round(cdf(d,2.00), digits=6) == .999_329 @test round(cdf(d,2.50), digits=7) == .999_992_5 @test round(cdf(d,3.00), digits=8) == .999_999_97 + +# no parameters: `partype` is the empty promotion `Union{}` +@test @inferred(partype(Kolmogorov())) === Union{} diff --git a/test/univariate/continuous/ksdist.jl b/test/univariate/continuous/ksdist.jl new file mode 100644 index 0000000000..4363f4748a --- /dev/null +++ b/test/univariate/continuous/ksdist.jl @@ -0,0 +1,8 @@ +using Distributions +using Test + +@testset "KSDist" begin + # the sample size `n` is the only parameter, so `partype` is `Int` + @test @inferred(partype(KSDist)) === Int + @test @inferred(partype(KSDist(5))) === Int +end diff --git a/test/univariate/continuous/ksonesided.jl b/test/univariate/continuous/ksonesided.jl new file mode 100644 index 0000000000..047b77a8e4 --- /dev/null +++ b/test/univariate/continuous/ksonesided.jl @@ -0,0 +1,8 @@ +using Distributions +using Test + +@testset "KSOneSided" begin + # the sample size `n` is the only parameter, so `partype` is `Int` + @test @inferred(partype(KSOneSided)) === Int + @test @inferred(partype(KSOneSided(5))) === Int +end diff --git a/test/univariate/continuous/normal.jl b/test/univariate/continuous/normal.jl index 0378e05486..b80008eae6 100644 --- a/test/univariate/continuous/normal.jl +++ b/test/univariate/continuous/normal.jl @@ -223,3 +223,21 @@ test_affine_transformations(NormalCanon, randn()^2, randn()^2) @test_throws DimensionMismatch suffstats(Normal, b, wa) end + +@testset "partype" begin + # defined on the type, with the instance method forwarding for convenience + @test @inferred(partype(Normal{Float32})) === Float32 + @test @inferred(partype(Normal(1.0f0, 2.0f0))) === @inferred(partype(Normal{Float32})) === Float32 + @test @inferred(partype(Normal(1//1, 2//1))) === Rational{Int} + + # abstract types fall back to the generic `Real` default + @test @inferred(partype(Distribution)) === Real + @test @inferred(partype(UnivariateDistribution)) === Real + @test @inferred(partype(ContinuousUnivariateDistribution)) === Real + @test @inferred(partype(Normal)) === Real + + # `partype(eltype(container))` works whether or not the container is concretely typed + @test @inferred(partype(eltype([Normal(0.0f0, 1.0f0)]))) === Float32 + @test @inferred(partype(eltype(Normal[Normal(0.0, 1.0)]))) === Real + @test @inferred(partype(eltype(Distribution[Normal(0.0, 1.0)]))) === Real +end diff --git a/test/univariate/continuous/semicircle.jl b/test/univariate/continuous/semicircle.jl index 7079aa9490..6a33032701 100644 --- a/test/univariate/continuous/semicircle.jl +++ b/test/univariate/continuous/semicircle.jl @@ -6,6 +6,11 @@ d = Semicircle(2.0) @test params(d) == (2.0,) +# bare `Semicircle` (a UnionAll) falls back to the generic `Real` default +@test @inferred(partype(d)) === Float64 +@test @inferred(partype(Semicircle(1.0f0))) === Float32 +@test @inferred(partype(Semicircle)) === Real + @test minimum(d) == -2.0 @test maximum(d) == +2.0 @test extrema(d) == (-2.0, 2.0) diff --git a/test/univariate/discrete/bernoullilogit.jl b/test/univariate/discrete/bernoullilogit.jl index 55560692a0..5a09f647d1 100644 --- a/test/univariate/discrete/bernoullilogit.jl +++ b/test/univariate/discrete/bernoullilogit.jl @@ -12,7 +12,7 @@ using Test, Random @test convert(BernoulliLogit{Float16}, d) === BernoulliLogit(Float16(logitp)) @test eltype(typeof(d)) === Bool @test params(d) == (logitp,) - @test partype(d) === typeof(logitp) + @test @inferred(partype(d)) === typeof(logitp) end end diff --git a/test/univariate/discrete/dirac.jl b/test/univariate/discrete/dirac.jl index cf027918b6..456fe638e8 100644 --- a/test/univariate/discrete/dirac.jl +++ b/test/univariate/discrete/dirac.jl @@ -64,4 +64,9 @@ using Test @test mgf(d, t) == exp(t * val) @test cf(d, t) == cis(t * val) end + + # bare `Dirac` falls back to the generic `Real` default + @test @inferred(partype(Dirac{Float32})) === Float32 + @test @inferred(partype(Dirac(1.0f0))) === Float32 + @test @inferred(partype(Dirac)) === Real end diff --git a/test/univariate/discrete/discretenonparametric.jl b/test/univariate/discrete/discretenonparametric.jl index 68354a064a..c48664829b 100644 --- a/test/univariate/discrete/discretenonparametric.jl +++ b/test/univariate/discrete/discretenonparametric.jl @@ -29,6 +29,10 @@ test_evaluation(d, vs, true) test_stats(d, vs) test_params(d) +# bare `DiscreteNonParametric` (a UnionAll) falls back to the generic `Real` default +@test @inferred(partype(DiscreteNonParametric([1, 2], Float32[0.5, 0.5]))) === Float32 +@test @inferred(partype(DiscreteNonParametric)) === Real + @test func[1](d) ∈ [40., 80., 120., -60.] @test func[1](sampler(d)) ∈ [40., 80., 120., -60.] diff --git a/test/univariate/discrete/discreteuniform.jl b/test/univariate/discrete/discreteuniform.jl index 008397f2f4..31a9a39a09 100644 --- a/test/univariate/discrete/discreteuniform.jl +++ b/test/univariate/discrete/discreteuniform.jl @@ -28,3 +28,10 @@ end @test fit(DiscreteUniform, data) == DiscreteUniform(10, 20) end end + +@testset "partype" begin + # the bounds are stored as `Int`, so `partype` is `Int` regardless of the input type + @test @inferred(partype(DiscreteUniform(0, 4))) === Int + @test @inferred(partype(DiscreteUniform(0.0, 4))) === Int + @test @inferred(partype(DiscreteUniform)) === Int +end diff --git a/test/univariate/discrete/hypergeometric.jl b/test/univariate/discrete/hypergeometric.jl new file mode 100644 index 0000000000..556e2e5e0c --- /dev/null +++ b/test/univariate/discrete/hypergeometric.jl @@ -0,0 +1,9 @@ +using Distributions +using Test + +@testset "Hypergeometric" begin + # the parameters are always stored as `Int`, so `partype` is `Int` + @test @inferred(partype(Hypergeometric)) === Int + @test @inferred(partype(Hypergeometric(2, 2, 2))) === Int + @test @inferred(partype(Hypergeometric(2.0, 2, 2))) === Int +end diff --git a/test/univariate/discrete/poissonbinomial.jl b/test/univariate/discrete/poissonbinomial.jl index 611a54c258..bd820950b8 100644 --- a/test/univariate/discrete/poissonbinomial.jl +++ b/test/univariate/discrete/poissonbinomial.jl @@ -36,6 +36,11 @@ naive_sol = naive_pb(p) @test Distributions.poissonbinomial_pdf_fft(p) ≈ Distributions.poissonbinomial_pdf(p) +# bare `PoissonBinomial` (a UnionAll) falls back to the generic `Real` default +@test @inferred(partype(PoissonBinomial(Float32[0.1, 0.2]))) === Float32 +@test @inferred(partype(PoissonBinomial(p))) === Float64 +@test @inferred(partype(PoissonBinomial)) === Real + # Test the special base where PoissonBinomial distribution reduces # to Binomial distribution for (p, n) in [(0.8, 6), (0.5, 10), (0.04, 20)] diff --git a/test/univariate/discrete/soliton.jl b/test/univariate/discrete/soliton.jl index af0aefddc1..4fb1e09dbc 100644 --- a/test/univariate/discrete/soliton.jl +++ b/test/univariate/discrete/soliton.jl @@ -3,6 +3,9 @@ using Distributions @testset "Soliton" begin K, M, δ, atol = 100, 60, 0.2, 0 Ω = Soliton(K, M, δ, atol) + # the degree distribution uses `Float64` probabilities, so `partype` is `Float64` + @test @inferred(partype(Ω)) === Float64 + @test @inferred(partype(Soliton)) === Float64 @test pdf(Ω, M) > pdf(Ω, M-1) @test pdf(Ω, M) > pdf(Ω, M+1) @test cumsum(Base.Fix1(pdf, Ω).(1:K)) ≈ Base.Fix1(cdf, Ω).(1:K) diff --git a/test/univariate/locationscale.jl b/test/univariate/locationscale.jl index 805589e8a1..31874da78b 100644 --- a/test/univariate/locationscale.jl +++ b/test/univariate/locationscale.jl @@ -164,6 +164,13 @@ end end end + @testset "unary negation" begin + # `-d` stays well-typed even when `partype(d) === Union{}` (e.g. `Kolmogorov`) + @test @inferred(partype(-Normal(1.0f0, 2.0f0))) === Float32 + @test @inferred(partype(-Kolmogorov())) === Int + @test -Kolmogorov() isa Distributions.AffineDistribution{Int} + end + @test_logs Distributions.AffineDistribution(1.0, 1, Normal()) @test_deprecated ls_norm = LocationScale(1.0, 1, Normal()) diff --git a/test/utils.jl b/test/utils.jl index 0249df568c..fbe8335f3c 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -8,68 +8,6 @@ r = RealInterval(1.5, 4.0) @test maximum(r) == 4.0 @test extrema(r) == (1.5, 4.0) -@test partype(Gamma(1, 2)) == Float64 -@test partype(Gamma(1.1, 2)) == Float64 -@test partype(Normal(1//1, 2//1)) == Rational{Int} -@test partype(MvNormal(rand(Float32, 5), Matrix{Float32}(I, 5, 5))) == Float32 - -# special cases -@test partype(Hypergeometric(2, 2, 2)) == Int -@test partype(Hypergeometric(2.0, 2, 2)) == Int -@test partype(DiscreteUniform(0, 4)) == Int -@test partype(DiscreteUniform(0.0, 4)) == Int - -# `partype` is defined on the type; the instance method forwards for convenience -@test partype(Normal{Float32}) === Float32 -@test partype(Normal(1.0f0, 2.0f0)) === partype(Normal{Float32}) === Float32 -@test partype(Gamma{Float64}) === Float64 -@test partype(DiscreteUniform) === Int -@test partype(Hypergeometric) === Int - -# wrapper distributions recover the parameter type from the wrapped type parameter -@test partype(Truncated{Normal{Float64},Continuous,Float64}) === Float64 -@test partype(truncated(Normal(0.0f0, 1.0f0), 0, 1)) === Float32 -@test partype(censored(Normal(0.0f0, 1.0f0); lower = 0)) === Float32 - -# parametric distributions that previously fell back to the `Float64` default -# now report their actual parameter type -@test partype(Dirac{Float32}) === Float32 -@test partype(Dirac(1.0f0)) === Float32 -@test partype(DiscreteNonParametric([1, 2], Float32[0.5, 0.5])) === Float32 - -# distributions without parameters have an empty parameter promotion (`Union{}`), -# which is the identity for `promote_type` and composes through wrappers -@test partype(Chernoff()) === Union{} -@test partype(Kolmogorov()) === Union{} -@test partype(truncated(Kolmogorov(); lower = 0.0, upper = 1.0)) === Float64 -# the sample size `n` is the only parameter of the Kolmogorov-Smirnov distributions -@test partype(KSDist(5)) === Int -@test partype(KSOneSided(5)) === Int - -# the generic default for an unknown distribution type: parameters are `<:Real`, and -# `eltype(Real) === Real`, so the fallback is `Real` (and `zero`/`one` work on it) -@test partype(Distribution) === Real - -# abstract types: the parameters are only upper bounds, so `partype` falls back to the -# generic default `Real`, mirroring `eltype(Vector) === Any` in Base -@test partype(Normal) === Real -@test partype(Gamma) === Real -@test partype(MvNormal) === Real -@test partype(Dirac) === Real -@test partype(DiscreteNonParametric) === Real -@test partype(Truncated) === Real -@test partype(Distributions.Censored) === Real -@test partype(Product) === Real -@test partype(MixtureModel) === Real -@test partype(UnivariateDistribution) === Real -@test partype(ContinuousUnivariateDistribution) === Real - -# the motivating use: `partype(eltype(container))` works whether or not the container is -# concretely typed -@test partype(eltype([Normal(0.0f0, 1.0f0)])) === Float32 # concrete eltype -@test partype(eltype(Normal[Normal(0.0, 1.0)])) === Real # abstract eltype -> fallback -@test partype(eltype(Distribution[Normal(0.0, 1.0)])) === Real - A = rand(1:10, 5, 5) B = rand(Float32, 4) C = 1//2 From 6a3c358fec5550ea624a0c6e47e80fd1aa9af3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller-Widmann?= Date: Thu, 25 Jun 2026 17:25:46 +0200 Subject: [PATCH 4/4] Update version from 0.25.127 to 0.25.129 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 092dfae81b..6fb3f92543 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Distributions" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" authors = ["JuliaStats"] -version = "0.25.127" +version = "0.25.129" [deps] AliasTables = "66dad0bd-aa9a-41b7-9441-69ab47430ed8"