Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Vector-version for PDBijector #271

Merged
merged 27 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
14f053d
initial work on PDVecBijector
torfjelde Jun 17, 2023
3396d33
added output_length and output_size to compute output, well, leengths
torfjelde Jun 17, 2023
57988a2
added tests for size of transformed dist using VcCorrBijector
torfjelde Jun 17, 2023
6b65c75
use already constructed transfrormation
torfjelde Jun 17, 2023
367f261
TransformedDistribution should now also have correct variate form
torfjelde Jun 17, 2023
fcee1fe
added proper variateform handling for VecCholeskyBijector too
torfjelde Jun 17, 2023
bc38e64
Apply suggestions from code review
torfjelde Jun 17, 2023
977f39b
added output_size impl for Reshape too
torfjelde Jun 17, 2023
2d27739
added output_size for PDVecBijector annd tests
torfjelde Jun 18, 2023
3194e17
made bijector for PD distributions use PDVecBijcetor
torfjelde Jun 18, 2023
42209be
bump minor version
torfjelde Jun 18, 2023
ee550b2
Update src/bijectors/pd.jl
torfjelde Jun 18, 2023
7867bc6
move utilities from bijectors/corr.jl to utils.jl
torfjelde Jun 18, 2023
1424e2c
fixed Tracker for PD matrices
torfjelde Jun 18, 2023
4beb7a6
Apply suggestions from code review
torfjelde Jun 18, 2023
2885937
fix for matrix AD tests
torfjelde Jun 18, 2023
c92af34
Merge branch 'master' into torfjelde/pd-vec
torfjelde Jun 18, 2023
d6faf97
Merge branch 'master' into torfjelde/pd-vec
torfjelde Jun 19, 2023
5a5ce4a
bumped patch version
torfjelde Jun 19, 2023
0677529
revert patch version
torfjelde Jun 19, 2023
c78c80e
Apply suggestions from code review
torfjelde Jun 20, 2023
70ebe5b
Update src/utils.jl
torfjelde Jun 20, 2023
eb63c2b
removed unnecessary hacks for importing chainrules rule into ReverseDiff
torfjelde Jun 20, 2023
85d188c
markk triu_mask as non-differentiable
torfjelde Jun 20, 2023
35e38b7
shiften some methods around to help with readability
torfjelde Jun 20, 2023
fa2000b
removed redundant wrap_chainrules_output in BijectorsReverseDiffExt
torfjelde Jun 20, 2023
0f04fb5
renamed confusing name in pd tests
torfjelde Jun 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Bijectors"
uuid = "76274a88-744f-5084-9051-94815aaf08c4"
version = "0.12.8"
version = "0.13.0"

[deps]
ArgCheck = "dce04be8-c92d-5529-be00-80e4d2c0e197"
Expand Down
16 changes: 16 additions & 0 deletions src/bijectors/corr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,17 @@ function logabsdetjac(::Inverse{VecCorrBijector}, y::AbstractVector{<:Real})
return _logabsdetjac_inv_corr(y)
end

function output_size(::VecCorrBijector, sz::NTuple{2})
@assert sz[1] == sz[2]
n = sz[1]
return (n * (n - 1)) ÷ 2
end

function output_size(::Inverse{VecCorrBijector}, sz::NTuple{1})
n = _triu1_dim_from_length(first(sz))
return (n, n)
end

"""
VecCholeskyBijector <: Bijector

Expand Down Expand Up @@ -317,6 +328,11 @@ function logabsdetjac(::Inverse{VecCholeskyBijector}, y::AbstractVector{<:Real})
return _logabsdetjac_inv_chol(y)
end

output_size(::VecCholeskyBijector, sz::NTuple{2}) = output_size(VecCorrBijector(), sz)
function output_size(::Inverse{<:VecCholeskyBijector}, sz::NTuple{1})
return output_size(inverse(VecCorrBijector()), sz)
end

"""
function _link_chol_lkj(w)

Expand Down
46 changes: 46 additions & 0 deletions src/bijectors/pd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,49 @@ end
function with_logabsdet_jacobian(b::PDBijector, X)
return transform(b, X), logabsdetjac(b, X)
end


torfjelde marked this conversation as resolved.
Show resolved Hide resolved
struct PDVecBijector <: Bijector end

function _triu_dim_from_length(d)
harisorgn marked this conversation as resolved.
Show resolved Hide resolved
# (n^2 + n) / 2 = d
# n² + n - 2d = 0
# n = (-1 + sqrt(1 + 8d)) / 2
return (-1 + isqrt(1 + 8 * d)) ÷ 2
end

"""
vec_to_triu(x::AbstractVector{<:Real})

Constructs a matrix from a vector `x` by filling the upper triangle.
"""
function vec_to_triu(x::AbstractVector)
n = _triu_dim_from_length(length(x))
X = update_triu_from_vec(x, 0, n)
return upper_triangular(X)
end

transform(::PDVecBijector, X::AbstractMatrix{<:Real}) = pd_vec_link(X)
pd_vec_link(X) = triu_to_vec(transpose(pd_link(X)), 0)

function transform(::Inverse{PDVecBijector}, y::AbstractVector{<:Real})
Y = permutedims(vec_to_triu(y))
return transform(inverse(PDBijector()), Y)
end

logabsdetjac(::PDVecBijector, X::AbstractMatrix{<:Real}) = logabsdetjac(PDBijector(), X)

function with_logabsdet_jacobian(b::PDVecBijector, X)
return transform(b, X), logabsdetjac(b, X)
end

function output_size(::PDVecBijector, sz::Tuple{Int,Int})
n = first(sz)
d = (n^2 + n) ÷ 2
return (d,)
end

function output_size(::Inverse{PDVecBijector}, sz::Tuple{Int})
n = _triu_dim_from_length(first(sz))
return (n, n)
end
2 changes: 2 additions & 0 deletions src/bijectors/reshape.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ end
inverse(b::Reshape) = Reshape(b.out_shape, b.in_shape)

with_logabsdet_jacobian(b::Reshape, x) = reshape(x, b.out_shape), zero(eltype(x))

output_size(b::Reshape, in_size) = b.out_shape
20 changes: 20 additions & 0 deletions src/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@ function logabsdetjac(f::Columnwise, x::AbstractMatrix)
end
with_logabsdet_jacobian(f::Columnwise, x::AbstractMatrix) = (f(x), logabsdetjac(f, x))

"""
output_size(f, sz)

Returns the output size of `f` given the input size `sz`.
"""
output_size(f, sz) = sz

"""
output_length(f, len::Int)
output_length(f, sz::Tuple)

Returns the output length of `f` given the input length `len` or size `sz`.
"""
output_length(f, len::Int) = len
function output_length(f, len::Tuple)
sz = output_size(f, len)
@assert length(sz) == 1
return first(sz)
end

######################
# Bijector interface #
######################
Expand Down
31 changes: 15 additions & 16 deletions src/transformed_distribution.jl
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
function variateform(d::Distribution, b)
sz_in = size(d)
sz_out = output_size(b, sz_in)
return ArrayLikeVariate{length(sz_out)}
end

variateform(::MultivariateDistribution, ::Inverse{VecCholeskyBijector}) = CholeskyVariate

# Transformed distributions
struct TransformedDistribution{D,B,V} <:
Distribution{V,Continuous} where {D<:Distribution{V,Continuous},B}
Distribution{V,Continuous} where {D<:ContinuousDistribution,B}
dist::D
transform::B

function TransformedDistribution(d::UnivariateDistribution, b)
return new{typeof(d),typeof(b),Univariate}(d, b)
end
function TransformedDistribution(d::MultivariateDistribution, b)
return new{typeof(d),typeof(b),Multivariate}(d, b)
end
function TransformedDistribution(d::MatrixDistribution, b)
return new{typeof(d),typeof(b),Matrixvariate}(d, b)
end
function TransformedDistribution(d::Distribution{CholeskyVariate}, b)
return new{typeof(d),typeof(b),CholeskyVariate}(d, b)
function TransformedDistribution(d::ContinuousDistribution, b)
return new{typeof(d),typeof(b),variateform(d, b)}(d, b)
end
end

Expand Down Expand Up @@ -83,8 +82,8 @@ bijector(d::BoundedDistribution) = bijector_bounded(d)
const LowerboundedDistribution = Union{Pareto,Levy}
bijector(d::LowerboundedDistribution) = bijector_lowerbounded(d)

bijector(d::PDMatDistribution) = PDBijector()
bijector(d::MatrixBeta) = PDBijector()
bijector(d::PDMatDistribution) = PDVecBijector()
bijector(d::MatrixBeta) = PDVecBijector()

bijector(d::LKJ) = VecCorrBijector()
bijector(d::LKJCholesky) = VecCholeskyBijector(d.uplo)
Expand All @@ -101,8 +100,8 @@ end
##############################

# size
Base.length(td::Transformed) = length(td.dist)
Base.size(td::Transformed) = size(td.dist)
Base.length(td::Transformed) = output_length(td.transform, size(td.dist))
Base.size(td::Transformed) = output_size(td.transform, size(td.dist))

function logpdf(td::UnivariateTransformed, y::Real)
x, logjac = with_logabsdet_jacobian(inverse(td.transform), y)
Expand Down
18 changes: 18 additions & 0 deletions test/bijectors/corr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ using Bijectors: VecCorrBijector, VecCholeskyBijector, CorrBijector
test_bijector(bvec, x; test_not_identity=d != 1, changes_of_variables_test=false)

test_ad(x -> sum(bvec(bvecinv(x))), yvec)

# Check that output sizes are computed correctly.
tdist = transformed(dist)
@test length(tdist) == length(yvec)
@test tdist isa MultivariateDistribution

dist_unconstrained = transformed(MvNormal(zeros(length(tdist)), I), inverse(bvec))
@test size(dist_unconstrained) == size(x)
@test dist_unconstrained isa MatrixDistribution
end
end

Expand Down Expand Up @@ -60,6 +69,15 @@ end
# test_bijector is commented out for now,
# as isapprox is not defined for ::Cholesky types (the domain of LKJCholesky)
# test_bijector(b, x; test_not_identity=d != 1, changes_of_variables_test=false)

# Check that output sizes are computed correctly.
tdist = transformed(dist)
@test length(tdist) == length(y)
@test tdist isa MultivariateDistribution

dist_unconstrained = transformed(MvNormal(zeros(length(tdist)), I), inverse(b))
@test size(dist_unconstrained) == size(x)
@test dist_unconstrained isa Distribution{CholeskyVariate,Continuous}
end
end
end
42 changes: 33 additions & 9 deletions test/bijectors/pd.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
using Bijectors, DistributionsAD, LinearAlgebra, Test
using Bijectors: PDBijector
using Bijectors: PDBijector, PDVecBijector

@testset "PDBijector" begin
d = 5
b = PDBijector()
dist = Wishart(d, Matrix{Float64}(I, d, d))
x = rand(dist)
# NOTE: `PDBijector` technically isn't bijective, and so the default `getjacobian`
# used in the ChangesOfVariables.jl tests will fail as the jacobian will have determinant 0.
# Hence, we disable those tests.
test_bijector(b, x; test_not_identity=true, changes_of_variables_test=false)
for d in [2, 5]
b = PDBijector()
dist = Wishart(d, Matrix{Float64}(I, d, d))
x = rand(dist)
# NOTE: `PDBijector` technically isn't bijective, and so the default `getjacobian`
# used in the ChangesOfVariables.jl tests will fail as the jacobian will have determinant 0.
# Hence, we disable those tests.
test_bijector(b, x; test_not_identity=true, changes_of_variables_test=false)
end
end

@testset "PDVecBijector" begin
for d in [2, 5]
b = PDVecBijector()
dist = Wishart(d, Matrix{Float64}(I, d, d))
x = rand(dist)
y = b(x)

# NOTE: `PDBijector` technically isn't bijective, and so the default `getjacobian`
# used in the ChangesOfVariables.jl tests will fail as the jacobian will have determinant 0.
# Hence, we disable those tests.
test_bijector(b, x; test_not_identity=true, changes_of_variables_test=false)

# Check that output sizes are computed correctly.
tdist = transformed(dist, b)
@test length(tdist) == length(y)
@test tdist isa MultivariateDistribution

dist_unconstrained = transformed(MvNormal(zeros(length(tdist)), I), inverse(b))
harisorgn marked this conversation as resolved.
Show resolved Hide resolved
@test size(dist_unconstrained) == size(x)
@test dist_unconstrained isa MatrixDistribution
end
end
Loading