Skip to content

Commit bf104c5

Browse files
committed
Fix with_logabsdet_jacobian for mapped/broadcasted functions
1 parent 29a9543 commit bf104c5

3 files changed

Lines changed: 48 additions & 12 deletions

File tree

src/with_ladj.jl

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -109,35 +109,48 @@ function with_logabsdet_jacobian(f::Base.ComposedFunction, x)
109109
end
110110

111111

112-
function _with_ladj_on_mapped(@nospecialize(map_or_bc::F), y_with_ladj::NoLogAbsDetJacobian) where {F<:Union{typeof(map),typeof(broadcast)}}
113-
return y_with_ladj
114-
end
112+
_with_ladj_on_mapped(y_with_ladj::NoLogAbsDetJacobian) = y_with_ladj
115113

116-
function _with_ladj_on_mapped(map_or_bc::F, y_with_ladj::Tuple{Any,Real}) where {F<:Union{typeof(map),typeof(broadcast)}}
117-
return y_with_ladj
118-
end
114+
_with_ladj_on_mapped(y_with_ladj::Tuple{Any,Real}) = y_with_ladj
115+
116+
_with_ladj_on_mapped(::AbstractArray{<:NoLogAbsDetJacobian{F,T}}) where {F,T} = NoLogAbsDetJacobian{F,T}()
119117

120118
_get_all_first(x) = map(first, x)
121-
# Use x -> x[2] instead of last, using last causes horrible performance in Zygote here:
122-
_sum_over_second(x) = sum(x -> x[2], x)
119+
_get_second(x) = x[2]
120+
# Use _get_second instead of last, using last causes horrible performance in Zygote here:
121+
_sum_over_second(x) = sum(_get_second, x)
123122

124-
function _with_ladj_on_mapped(map_or_bc::F, y_with_ladj) where {F<:Union{typeof(map),typeof(broadcast)}}
123+
function _with_ladj_on_mapped(y_with_ladj)
125124
y = _get_all_first(y_with_ladj)
126125
ladj = _sum_over_second(y_with_ladj)
127126
(y, ladj)
128127
end
129128

129+
_combine_y_ladj(l::NoLogAbsDetJacobian, @nospecialize(r::NoLogAbsDetJacobian)) = l
130+
_combine_y_ladj(l::NoLogAbsDetJacobian, @nospecialize(r::Tuple{Any,Real})) = l
131+
_combine_y_ladj(@nospecialize(l::Tuple{Any,Real}), r::NoLogAbsDetJacobian) = r
132+
_combine_y_ladj(l::Tuple{Any,Real}, r::Tuple{Any,Real}) = ((l[1]..., r[1]), l[2] + r[2])
133+
134+
function _with_ladj_on_mapped(y_with_ladj::Tuple{NoLogAbsDetJacobian, Vararg{Union{NoLogAbsDetJacobian, Tuple{Any,Real}}}})
135+
return first(y_with_ladj)
136+
end
137+
138+
function _with_ladj_on_mapped(y_with_ladj::Tuple{Tuple{Any,Real}, Vararg{Union{NoLogAbsDetJacobian, Tuple{Any,Real}}}})
139+
a, bs = first(y_with_ladj), Base.tail(y_with_ladj)
140+
return foldl(_combine_y_ladj, bs, init = ((a[1],), a[2]))
141+
end
142+
130143
function with_logabsdet_jacobian(mapped_f::Base.Broadcast.BroadcastFunction, X)
131144
f = mapped_f.f
132145
y_with_ladj = broadcast(Base.Fix1(with_logabsdet_jacobian, f), X)
133-
_with_ladj_on_mapped(broadcast, y_with_ladj)
146+
_with_ladj_on_mapped(y_with_ladj)
134147
end
135148

136149
function with_logabsdet_jacobian(mapped_f::Base.Fix1{<:Union{typeof(map),typeof(broadcast)}}, X)
137150
map_or_bc = mapped_f.f
138151
f = mapped_f.x
139152
y_with_ladj = map_or_bc(Base.Fix1(with_logabsdet_jacobian, f), X)
140-
_with_ladj_on_mapped(map_or_bc, y_with_ladj)
153+
_with_ladj_on_mapped(y_with_ladj)
141154
end
142155

143156

test/getjacobian.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,12 @@ if !isdefined(Main, :foo)
4343
foo(x) = inv(exp(-x) + 1)
4444

4545
end # !isdefined(Main, :foo)
46+
47+
48+
if !isdefined(Main, :bar)
49+
50+
# with_logabsdet_jacobian for floats but not for integers
51+
bar(x) = x
52+
ChangesOfVariables.with_logabsdet_jacobian(::typeof(bar), x::AbstractFloat) = (x, zero(x))
53+
54+
end # !isdefined(Main, :bar)

test/test_with_ladj.jl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,26 @@ include("getjacobian.jl")
4949

5050
@testset "with_logabsdet_jacobian on mapped and broadcasted" begin
5151
for f in (_bc_func(foo), Base.Fix1(map, foo), Base.Fix1(broadcast, foo))
52-
for arg in (x, fill(x,), Ref(x), (x,), X)
52+
for arg in (x, fill(x,), Ref(x), (x,), (x, 2*x, 3*x), X)
5353
test_with_logabsdet_jacobian(f, arg, getjacobian, compare = isaprx)
5454
end
5555
end
5656
end
5757

58+
@testset "with_logabsdet_jacobian on mapped and broadcasted without ladj" begin
59+
for f in (_bc_func(sin), Base.Fix1(map, sin), Base.Fix1(broadcast, sin))
60+
for arg in (x, (x,), (x, x), X)
61+
@test with_logabsdet_jacobian(f, arg) isa NoLogAbsDetJacobian{typeof(sin)}
62+
end
63+
end
64+
end
65+
66+
@testset "with_logabsdet_jacobian on mapped and broadcasted with mixed ladj" begin
67+
@test with_logabsdet_jacobian(_bc_func(bar), (1.0, 2.0)) == ((1.0, 2.0), 0.0)
68+
@test with_logabsdet_jacobian(_bc_func(bar), (1.0, 2)) isa NoLogAbsDetJacobian
69+
@test with_logabsdet_jacobian(Base.Fix1(map, bar), (1, 2.0)) isa NoLogAbsDetJacobian
70+
end
71+
5872
@testset "with_logabsdet_jacobian on identity, adjoint and transpose" begin
5973
for f in (identity, adjoint, transpose)
6074
for arg in (x, A)

0 commit comments

Comments
 (0)