From 204e438929b6fd6fd7b7267439e64f21a77177ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller-Widmann?= Date: Fri, 26 Jun 2026 14:26:08 +0200 Subject: [PATCH 1/3] More flexible and less brittle `MvNormal` and `MvNormalCanon` type aliases --- src/multivariate/mvnormal.jl | 24 ++++++------------------ src/multivariate/mvnormalcanon.jl | 24 ++++++------------------ 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/multivariate/mvnormal.jl b/src/multivariate/mvnormal.jl index 202f449f21..63888f01aa 100644 --- a/src/multivariate/mvnormal.jl +++ b/src/multivariate/mvnormal.jl @@ -54,18 +54,6 @@ of any subtype of `AbstractPDMat`. Particularly, one can use `PDMat` for full co in the form of ``\\sigma^2 \\mathbf{I}``. (See the Julia package [PDMats](https://github.com/JuliaStats/PDMats.jl/) for details). -We also define a set of aliases for the types using different combinations of mean vectors and covariance: - -```julia -const IsoNormal = MvNormal{Float64, ScalMat{Float64}, Vector{Float64}} -const DiagNormal = MvNormal{Float64, PDiagMat{Float64,Vector{Float64}}, Vector{Float64}} -const FullNormal = MvNormal{Float64, PDMat{Float64,Matrix{Float64}}, Vector{Float64}} - -const ZeroMeanIsoNormal{Axes} = MvNormal{Float64, ScalMat{Float64}, Zeros{Float64,1,Axes}} -const ZeroMeanDiagNormal{Axes} = MvNormal{Float64, PDiagMat{Float64,Vector{Float64}}, Zeros{Float64,1,Axes}} -const ZeroMeanFullNormal{Axes} = MvNormal{Float64, PDMat{Float64,Matrix{Float64}}, Zeros{Float64,1,Axes}} -``` - Multivariate normal distributions support affine transformations: ```julia d = MvNormal(μ, Σ) @@ -169,13 +157,13 @@ end const MultivariateNormal = MvNormal # for the purpose of backward compatibility -const IsoNormal = MvNormal{Float64,ScalMat{Float64},Vector{Float64}} -const DiagNormal = MvNormal{Float64,PDiagMat{Float64,Vector{Float64}},Vector{Float64}} -const FullNormal = MvNormal{Float64,PDMat{Float64,Matrix{Float64}},Vector{Float64}} +const IsoNormal{T} = MvNormal{T,<:ScalMat{T},<:AbstractVector{T}} +const DiagNormal{T} = MvNormal{T,<:PDiagMat{T},<:AbstractVector{T}} +const FullNormal{T} = MvNormal{T,<:PDMat{T},<:AbstractVector{T}} -const ZeroMeanIsoNormal{Axes} = MvNormal{Float64,ScalMat{Float64},Zeros{Float64,1,Axes}} -const ZeroMeanDiagNormal{Axes} = MvNormal{Float64,PDiagMat{Float64,Vector{Float64}},Zeros{Float64,1,Axes}} -const ZeroMeanFullNormal{Axes} = MvNormal{Float64,PDMat{Float64,Matrix{Float64}},Zeros{Float64,1,Axes}} +const ZeroMeanIsoNormal{T} = MvNormal{T,<:ScalMat{T},<:Zeros{T,1}} +const ZeroMeanDiagNormal{T} = MvNormal{T,<:PDiagMat{T},<:Zeros{T,1}} +const ZeroMeanFullNormal{T} = MvNormal{T,<:PDMat{T},<:Zeros{T,1}} ### Construction function MvNormal(μ::AbstractVector{T}, Σ::AbstractPDMat{T}) where {T<:Real} diff --git a/src/multivariate/mvnormalcanon.jl b/src/multivariate/mvnormalcanon.jl index 79b43e9ba9..65381177f7 100644 --- a/src/multivariate/mvnormalcanon.jl +++ b/src/multivariate/mvnormalcanon.jl @@ -26,18 +26,6 @@ struct MvNormalCanon{T<:Real,P<:AbstractPDMat,V<:AbstractVector} <: AbstractMvNo end ``` -We also define aliases for common specializations of this parametric type: - -```julia -const FullNormalCanon = MvNormalCanon{Float64, PDMat{Float64,Matrix{Float64}}, Vector{Float64}} -const DiagNormalCanon = MvNormalCanon{Float64, PDiagMat{Float64,Vector{Float64}}, Vector{Float64}} -const IsoNormalCanon = MvNormalCanon{Float64, ScalMat{Float64}, Vector{Float64}} - -const ZeroMeanFullNormalCanon{Axes} = MvNormalCanon{Float64, PDMat{Float64,Matrix{Float64}}, Zeros{Float64,1,Axes}} -const ZeroMeanDiagNormalCanon{Axes} = MvNormalCanon{Float64, PDiagMat{Float64,Vector{Float64}}, Zeros{Float64,1,Axes}} -const ZeroMeanIsoNormalCanon{Axes} = MvNormalCanon{Float64, ScalMat{Float64}, Zeros{Float64,1,Axes}} -``` - **Note:** `MvNormalCanon` share the same set of methods as `MvNormal`. """ struct MvNormalCanon{T<:Real,P<:AbstractPDMat,V<:AbstractVector} <: AbstractMvNormal @@ -46,13 +34,13 @@ struct MvNormalCanon{T<:Real,P<:AbstractPDMat,V<:AbstractVector} <: AbstractMvNo J::P # precision matrix, i.e. inv(Σ) end -const FullNormalCanon = MvNormalCanon{Float64,PDMat{Float64,Matrix{Float64}},Vector{Float64}} -const DiagNormalCanon = MvNormalCanon{Float64,PDiagMat{Float64,Vector{Float64}},Vector{Float64}} -const IsoNormalCanon = MvNormalCanon{Float64,ScalMat{Float64},Vector{Float64}} +const FullNormalCanon{T} = MvNormalCanon{T,<:PDMat{T},<:AbstractVector{T}} +const DiagNormalCanon{T} = MvNormalCanon{T,<:PDiagMat{T},<:AbstractVector{T}} +const IsoNormalCanon{T} = MvNormalCanon{T,<:ScalMat{T},<:AbstractVector{T}} -const ZeroMeanFullNormalCanon{Axes} = MvNormalCanon{Float64,PDMat{Float64,Matrix{Float64}},Zeros{Float64,1,Axes}} -const ZeroMeanDiagNormalCanon{Axes} = MvNormalCanon{Float64,PDiagMat{Float64,Vector{Float64}},Zeros{Float64,1,Axes}} -const ZeroMeanIsoNormalCanon{Axes} = MvNormalCanon{Float64,ScalMat{Float64},Zeros{Float64,1,Axes}} +const ZeroMeanFullNormalCanon{T} = MvNormalCanon{T,<:PDMat{T},<:Zeros{T,1}} +const ZeroMeanDiagNormalCanon{T} = MvNormalCanon{T,<:PDiagMat{T},<:Zeros{T,1}} +const ZeroMeanIsoNormalCanon{T} = MvNormalCanon{T,<:ScalMat{T},<:Zeros{T,1}} ### Constructors From ad7e09ed17215dc570c4c19d8a06d19c54da7cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller-Widmann?= Date: Fri, 26 Jun 2026 16:40:09 +0200 Subject: [PATCH 2/3] Fix tests for parametric MvNormal aliases The aliases (IsoNormal, DiagNormal, ...) are now abstract parametric UnionAlls rather than concrete types, which broke two pieces of test code that relied on their concreteness: - test/mixture.jl: `IsoNormal[...]` built an abstract-eltype vector, making the MixtureModel component type abstract and the mean/pdf/ logpdf `@inferred` checks fail. Let Julia infer the concrete eltype and relax the type assertion to `<:IsoNormal`. - MvLogitNormal had no `distrname` method and fell back to the generic `string(typeof(d))`, which now renders the inner alias verbosely via Julia's type printer. Add `distrname(::MvLogitNormal)` delegating to `distrname(d.normal)`, matching how MvNormal already prints. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/multivariate/mvlogitnormal.jl | 2 ++ test/mixture.jl | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/multivariate/mvlogitnormal.jl b/src/multivariate/mvlogitnormal.jl index 0d60ddf654..6c5747b033 100644 --- a/src/multivariate/mvlogitnormal.jl +++ b/src/multivariate/mvlogitnormal.jl @@ -29,6 +29,8 @@ end MvLogitNormal(d::AbstractMvNormal) = MvLogitNormal{typeof(d)}(d) MvLogitNormal(args...) = MvLogitNormal(MvNormal(args...)) +distrname(d::MvLogitNormal) = string("MvLogitNormal{", distrname(d.normal), "}") + function Base.show(io::IO, d::MvLogitNormal; indent::String=" ") print(io, distrname(d)) println(io, "(") diff --git a/test/mixture.jl b/test/mixture.jl index 92493f1a03..8a555b7e12 100644 --- a/test/mixture.jl +++ b/test/mixture.jl @@ -255,11 +255,11 @@ end @testset "Testing MultivariatevariateMixture" begin for T in (Float32, Float64) g_m = MixtureModel( - IsoNormal[ MvNormal([0.0, 0.0], I), - MvNormal([0.2, 1.0], I), - MvNormal([-0.5, -3.0], 1.6 * I) ], + [ MvNormal([0.0, 0.0], I), + MvNormal([0.2, 1.0], I), + MvNormal([-0.5, -3.0], 1.6 * I) ], T[0.2, 0.5, 0.3]) - @test isa(g_m, MixtureModel{Multivariate, Continuous, IsoNormal}) + @test isa(g_m, MixtureModel{Multivariate, Continuous, <:IsoNormal}) @test length(components(g_m)) == 3 @test length(g_m) == 2 @test insupport(g_m, [0.0, 0.0]) From e92048390997d4e156c529bd2dd290f21a15bb1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller-Widmann?= Date: Fri, 26 Jun 2026 20:35:20 +0200 Subject: [PATCH 3/3] Bump version from 0.25.128 to 0.25.129 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 72e8e16959..91f32761e6 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Distributions" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" authors = ["JuliaStats"] -version = "0.25.128" +version = "0.25.129" [deps] AliasTables = "66dad0bd-aa9a-41b7-9441-69ab47430ed8"