Repository navigation
add softplus and Cauchy transformation #157
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
base: master
Are you sure you want to change the base?
Changes from all commits
6fc41bd
b9517a9
34bb920
99bfe01
e449839
b728208
37d33cc
94e5252
3807125
5d46d13
17d3eda
d6e8505
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| module ReactantExt | ||
| using TransformVariables: TransformVariables, ArrayTransformation, LogJacFlag, | ||
| using TransformVariables: TransformVariables, ArrayTransformation, LogJacFlag, | ||
| logjac_zero, transform_with, _ensure_float, dimension | ||
| using Reactant | ||
| using Reactant: TracedRNumber, AnyTracedRArray | ||
|
|
@@ -22,12 +22,18 @@ Base.@nospecialize function Reactant.traced_type_inner( | |
| return TransformVariables.ArrayTransformation{T_traced, M} | ||
| end | ||
|
|
||
| TransformVariables._ensure_float(x::Type{TracedRNumber{T}}) where T = TracedRNumber{_ensure_float(T)} | ||
| function TransformVariables._ensure_float(x::Type{TracedRNumber{T}}) where T | ||
| TracedRNumber{_ensure_float(T)} | ||
| end | ||
|
|
||
| function TransformVariables._cauchy_cdf(x::TracedRNumber{T}) where {T<:AbstractFloat} | ||
| ifelse(x > -1, one(x) / 2 + atan(x) / π, atan(inv(-x)) / π) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possibly the usual |
||
| end | ||
|
|
||
| @noinline function TransformVariables.transform_with( | ||
| flag::TransformVariables.LogJacFlag, | ||
| transformation::TransformVariables.ArrayTransformation, | ||
| x::AnyTracedRArray, | ||
| flag::TransformVariables.LogJacFlag, | ||
| transformation::TransformVariables.ArrayTransformation, | ||
| x::AnyTracedRArray, | ||
| index | ||
| ) | ||
| (; inner_transformation, dims) = transformation | ||
|
|
@@ -48,18 +54,18 @@ TransformVariables._ensure_float(x::Type{TracedRNumber{T}}) where T = TracedRNum | |
| throw(ArgumentError("only `Number` and `AbstractArray` transformations are supported in Reactant compilation mode")) | ||
| end | ||
|
|
||
| # Reactant can't handle arrays of non-primitive types so we have to be more explicit about | ||
| # the output and use a `@trace` for loop. | ||
| # Reactant can't handle arrays of non-primitive types so we have to be more explicit about | ||
| # the output and use a `@trace` for loop. | ||
| @trace track_numbers=false for i in eachindex(𝐼) | ||
| idx = 𝐼[i] | ||
| y, ℓ, _ = transform_with(flag, inner_transformation, x, idx) | ||
| if !isempty(y) | ||
| ℓa += ℓ | ||
| ℓa += ℓ | ||
| end | ||
| if tmp isa Number | ||
| Reactant.@allowscalar yℓ[i] = y | ||
| else | ||
| idxs = ntuple(n-> Colon(), ndims(tmp)) | ||
| idxs = ntuple(n-> Colon(), ndims(tmp)) | ||
| yℓ[idxs..., i] = y | ||
| end | ||
| end | ||
|
|
@@ -83,4 +89,4 @@ function TransformVariables.transform_with(flag::LogJacFlag, t::ArrayTransformat | |
| y, logjac_zero(flag, _ensure_float(eltype(x))), index′ | ||
| end | ||
|
|
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,5 @@ | ||||||||||||||||||||||||||||||||||||
| export TVExp, TVScale, TVShift, TVLogistic, TVNeg | ||||||||||||||||||||||||||||||||||||
| export TVExp, TVScale, TVShift, TVLogistic, TVNeg, TVSoftPlus, TVCauchy | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| export ∞, asℝ, asℝ₊, asℝ₋, as𝕀, as_real, as_positive_real, as_negative_real, | ||||||||||||||||||||||||||||||||||||
| as_unit_interval | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
@@ -157,6 +158,66 @@ inverse_eltype(::TVNeg, ::Type{T}) where T = typeof(-oneunit(T)) | |||||||||||||||||||||||||||||||||||
| inverse(::TVNeg, x::Number) = -x | ||||||||||||||||||||||||||||||||||||
| inverse_and_logjac(::TVNeg, x::Number) = -x, logjac_zero(LogJac(), typeof(x)) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||
| $(TYPEDEF) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| “Softplus” transformation ``x ↦ log(1+exp(x))``, mapping the real line to positive | ||||||||||||||||||||||||||||||||||||
| numbers. | ||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||
| struct TVSoftPlus <: ScalarTransform end | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| transform(::TVSoftPlus, x::Number) = log1pexp(x) | ||||||||||||||||||||||||||||||||||||
| transform_and_logjac(t::TVSoftPlus, x::Number) = transform(t, x), -log1pexp(-x) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| inverse_eltype(::TVSoftPlus, ::Type{T}) where T = _ensure_float(T) | ||||||||||||||||||||||||||||||||||||
| inverse(::TVSoftPlus, y::Number) = logexpm1(y) | ||||||||||||||||||||||||||||||||||||
| inverse_and_logjac(::TVSoftPlus, y::Number) = logexpm1(y), -log1mexp(-y) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||
| $(TYPEDEF) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Transformation ``x ↦ 1/2 + arctan(x)/π``, mapping the real line to `(0, 1)`, which is | ||||||||||||||||||||||||||||||||||||
| also the CDF of the Cauchy distribution. | ||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||
| struct TVCauchy <: ScalarTransform end | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| function _cauchy_cdf(x::T) where {T<:Real} | ||||||||||||||||||||||||||||||||||||
| _x = float(x) | ||||||||||||||||||||||||||||||||||||
| if _x > -1 | ||||||||||||||||||||||||||||||||||||
| one(_x) / 2 + atan(_x) / π | ||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||
| # avoid 1/2 - 1/2 cancellations | ||||||||||||||||||||||||||||||||||||
| atan(inv(-_x)) / π | ||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+184
to
+192
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| transform(::TVCauchy, x::Number) = _cauchy_cdf(float(x)) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| function transform_and_logjac(t::TVCauchy, x::Number) | ||||||||||||||||||||||||||||||||||||
| y = transform(t, x) | ||||||||||||||||||||||||||||||||||||
| y, -(log1psq(x) + IrrationalConstants.logπ) | ||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| inverse_eltype(::TVCauchy, ::Type{T}) where T = _ensure_float(T) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| function inverse(::TVCauchy, y::Number) | ||||||||||||||||||||||||||||||||||||
| @argcheck 0 <= y <= 1 DomainError | ||||||||||||||||||||||||||||||||||||
| first(_cauchy_quantile_and_sinpi(y)) | ||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| function inverse_and_logjac(::TVCauchy, y::Number) | ||||||||||||||||||||||||||||||||||||
| @argcheck 0 <= y <= 1 DomainError | ||||||||||||||||||||||||||||||||||||
| x, s = _cauchy_quantile_and_sinpi(y) | ||||||||||||||||||||||||||||||||||||
| x, IrrationalConstants.logπ - 2 * log(s) | ||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| # returns the quantile and sinpi(y) | ||||||||||||||||||||||||||||||||||||
| function _cauchy_quantile_and_sinpi(y) | ||||||||||||||||||||||||||||||||||||
| flip = y > 0.5 | ||||||||||||||||||||||||||||||||||||
| s, c = sincospi(flip ? 1 - y : y) | ||||||||||||||||||||||||||||||||||||
| (flip ? c / s : -c / s), s | ||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||
|
tpapp marked this conversation as resolved.
Resolved
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| #### | ||||||||||||||||||||||||||||||||||||
| #### composite scalar transforms | ||||||||||||||||||||||||||||||||||||
| #### | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -470,7 +470,7 @@ end | |||||||||||||||||||||||||
| @test tn[1] == tn.a == inner[1] | ||||||||||||||||||||||||||
| @test tn[2] == tn.b == inner[2] | ||||||||||||||||||||||||||
| @test tn[3] == tn.c == inner[3] | ||||||||||||||||||||||||||
| @test_throws ErrorException tn.d | ||||||||||||||||||||||||||
| @test_throws (VERSION < v"1.12" ? ErrorException : FieldError) tn.d | ||||||||||||||||||||||||||
| @test_throws BoundsError tn[4] | ||||||||||||||||||||||||||
| @test propertynames(tn) == propertynames(inner) | ||||||||||||||||||||||||||
| @test (@set tn[3] = t2) == (@set tn.c = t2) == as((a = t1, b = t2, c = t2)) | ||||||||||||||||||||||||||
|
|
@@ -1145,9 +1145,25 @@ end | |||||||||||||||||||||||||
| @test_throws InexactError inverse(t, fill(Complex(0, 1), 3)) | ||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @testset "TVSoftPlus" begin | ||||||||||||||||||||||||||
| t = TVSoftPlus() | ||||||||||||||||||||||||||
| test_transformation(t, y -> y > 0) | ||||||||||||||||||||||||||
| @test transform(t, 1000.0) == 1000.0 | ||||||||||||||||||||||||||
| @test inverse(t, 1000.0) == 1000.0 | ||||||||||||||||||||||||||
| @test transform(t, -30.0) ≈ exp(-30.0) | ||||||||||||||||||||||||||
| @test inverse(t, exp(-30.0)) ≈ -30.0 | ||||||||||||||||||||||||||
| @test @inferred(transform(t, 1f0)) isa Float32 | ||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @testset "TVCauchy" begin | ||||||||||||||||||||||||||
| test_transformation(TransformVariables.TVCauchy(), y -> 0 < y < 1) | ||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, the
Suggested change
|
||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### | ||||||||||||||||||||||||||
| ### Reactant compat tests | ||||||||||||||||||||||||||
| ### | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @testset "Reactant.jl" begin | ||||||||||||||||||||||||||
|
devmotion marked this conversation as resolved.
Resolved
|
||||||||||||||||||||||||||
| @testset "Scalar transforms" begin | ||||||||||||||||||||||||||
| a = 3.1 | ||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With |
||||||||||||||||||||||||||
|
|
@@ -1156,7 +1172,8 @@ end | |||||||||||||||||||||||||
| @test @jit(transform(asℝ₊, ar)) ≈ transform(asℝ₊, a) | ||||||||||||||||||||||||||
| @test @jit(transform(asℝ₋, ar)) ≈ transform(asℝ₋, a) | ||||||||||||||||||||||||||
| @test @jit(transform(as𝕀, ar)) ≈ transform(as𝕀, a) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @test @jit(transform(TVSoftPlus(), ar)) ≈ transform(TVSoftPlus(), a) | ||||||||||||||||||||||||||
| @test @jit(transform(TVCauchy(), ar)) ≈ transform(TVCauchy(), a) | ||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @testset "Array transforms begin" begin | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand this sentence - does it refer to
TVSoftPlusandTVCauchy? AFAICT e.g.TVScaleandTVShiftdon't have a shorthand withaseither.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Individually, they don't, but all the
as(Real ...)transforms use them as building blocks.