From 7442802dce509a59cc33214966c7c7e25e6c36c0 Mon Sep 17 00:00:00 2001 From: David Widmann Date: Tue, 20 Aug 2024 20:15:05 +0200 Subject: [PATCH] Make Test a weak dependency (#30) * Make Test a weak dependency * Fix typo * Import `logabsdet` --- Project.toml | 8 ++++-- README.md | 4 +-- ext/ChangesOfVariablesTestExt.jl | 31 +++++++++++++++++++++ src/ChangesOfVariables.jl | 41 +++++++++++++++++++++++++-- src/test.jl | 48 -------------------------------- 5 files changed, 78 insertions(+), 54 deletions(-) create mode 100644 ext/ChangesOfVariablesTestExt.jl delete mode 100644 src/test.jl diff --git a/Project.toml b/Project.toml index 5cacfb5..390d81b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ChangesOfVariables" uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" -version = "0.1.8" +version = "0.1.9" [deps] InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" @@ -9,19 +9,23 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [weakdeps] InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [extensions] ChangesOfVariablesInverseFunctionsExt = "InverseFunctions" +ChangesOfVariablesTestExt = "Test" [compat] InverseFunctions = "0.1" LinearAlgebra = "<0.0.1, 1" +Test = "<0.0.1, 1" julia = "1" [extras] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Documenter", "InverseFunctions", "ForwardDiff"] +test = ["Documenter", "InverseFunctions", "ForwardDiff", "Test"] diff --git a/README.md b/README.md index 2c5bca0..61289d4 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ changes for functions that perform a change of variables (like coordinate transformations). `ChangesOfVariables` is a very lightweight package and has no dependencies -beyond `Base`, `LinearAlgebra` and `Test` (plus a weak depdendency on -`InverseFunctions`). +beyond `Base` and `LinearAlgebra` (plus a weak dependency on `InverseFunctions` +and `Test`). ## Documentation diff --git a/ext/ChangesOfVariablesTestExt.jl b/ext/ChangesOfVariablesTestExt.jl new file mode 100644 index 0000000..4d681a8 --- /dev/null +++ b/ext/ChangesOfVariablesTestExt.jl @@ -0,0 +1,31 @@ +module ChangesOfVariablesTestExt + +using Test: @inferred, @test, @testset +using ChangesOfVariables: ChangesOfVariables, logabsdet, with_logabsdet_jacobian + +function ChangesOfVariables.test_with_logabsdet_jacobian(f, x, getjacobian; compare = isapprox, kwargs...) + @testset "test_with_logabsdet_jacobian: $f with input $x" begin + ref_y, test_type_inference = try + @inferred(f(x)), true + catch err + f(x), false + end + + y, ladj = if test_type_inference + @inferred with_logabsdet_jacobian(f, x) + else + with_logabsdet_jacobian(f, x) + end + + ref_ladj = _generalized_logabsdet(getjacobian(f, x))[1] + + @test compare(y, ref_y; kwargs...) + @test compare(ladj, ref_ladj; kwargs...) + end + return nothing +end + +_generalized_logabsdet(A) = logabsdet(A) +_generalized_logabsdet(x::Real) = log(abs(x)) + +end # module diff --git a/src/ChangesOfVariables.jl b/src/ChangesOfVariables.jl index daa3e0a..db62a89 100644 --- a/src/ChangesOfVariables.jl +++ b/src/ChangesOfVariables.jl @@ -10,14 +10,51 @@ transformations). module ChangesOfVariables using LinearAlgebra -using Test include("with_ladj.jl") include("setladj.jl") -include("test.jl") + +""" + ChangesOfVariables.test_with_logabsdet_jacobian(f, x, getjacobian; compare = isapprox, kwargs...) + +Test if [`with_logabsdet_jacobian(f, x)`](@ref) is implemented correctly. + +Checks if the result of `with_logabsdet_jacobian(f, x)` is approximately +equal to `(f(x), logabsdet(getjacobian(f, x)))` + +So the test uses `getjacobian(f, x)` to calculate a reference Jacobian for +`f` at `x`. Passing `ForwardDiff.jabobian`, `Zygote.jacobian` or similar as +the `getjacobian` function will do fine in most cases. If input and output +of `f` are real scalar values, use `ForwardDiff.derivative`. + +Note that the result of `getjacobian(f, x)` must be a real-valued matrix +or a real scalar, so you may need to use a custom `getjacobian` function +that transforms the shape of `x` and `f(x)` internally, in conjunction +with automatic differentiation. + +`kwargs...` are forwarded to `compare`. + +!!! Note + On Julia >= 1.9, you have to load the `Test` standard library to be able to use + this function. +""" +function test_with_logabsdet_jacobian end @static if !isdefined(Base, :get_extension) include("../ext/ChangesOfVariablesInverseFunctionsExt.jl") + include("../ext/ChangesOfVariablesTestExt.jl") +end + +# Better error message if users forget to load Test +if isdefined(Base, :get_extension) && isdefined(Base.Experimental, :register_error_hint) + function __init__() + Base.Experimental.register_error_hint(MethodError) do io, exc, _, _ + if exc.f === test_with_logabsdet_jacobian && + (Base.get_extension(ChangesOfVariables, :ChangesOfVariablesTest) === nothing) + print(io, "\nDid you forget to load Test?") + end + end + end end end # module diff --git a/src/test.jl b/src/test.jl deleted file mode 100644 index e68183f..0000000 --- a/src/test.jl +++ /dev/null @@ -1,48 +0,0 @@ -# This file is a part of ChangesOfVariables.jl, licensed under the MIT License (MIT). - - -""" - ChangesOfVariables.test_with_logabsdet_jacobian(f, x, getjacobian; compare = isapprox, kwargs...) - -Test if [`with_logabsdet_jacobian(f, x)`](@ref) is implemented correctly. - -Checks if the result of `with_logabsdet_jacobian(f, x)` is approximately -equal to `(f(x), logabsdet(getjacobian(f, x)))` - -So the test uses `getjacobian(f, x)` to calculate a reference Jacobian for -`f` at `x`. Passing `ForwardDiff.jabobian`, `Zygote.jacobian` or similar as -the `getjacobian` function will do fine in most cases. If input and output -of `f` are real scalar values, use `ForwardDiff.derivative`. - -Note that the result of `getjacobian(f, x)` must be a real-valued matrix -or a real scalar, so you may need to use a custom `getjacobian` function -that transforms the shape of `x` and `f(x)` internally, in conjunction -with automatic differentiation. - -`kwargs...` are forwarded to `compare`. -""" -function test_with_logabsdet_jacobian(f, x, getjacobian; compare = isapprox, kwargs...) - @testset "test_with_logabsdet_jacobian: $f with input $x" begin - ref_y, test_type_inference = try - @inferred(f(x)), true - catch err - f(x), false - end - - y, ladj = if test_type_inference - @inferred with_logabsdet_jacobian(f, x) - else - with_logabsdet_jacobian(f, x) - end - - ref_ladj = _generalized_logabsdet(getjacobian(f, x))[1] - - @test compare(y, ref_y; kwargs...) - @test compare(ladj, ref_ladj; kwargs...) - end - return nothing -end - - -_generalized_logabsdet(A) = logabsdet(A) -_generalized_logabsdet(x::Real) = log(abs(x))