diff --git a/src/utilities.jl b/src/utilities.jl index 16a1464..da62065 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -49,10 +49,10 @@ uppercase. macro define_singleton(name_and_supertype, constant = nothing) @capture name_and_supertype name_ <: supertype_ if constant == nothing - constant = esc(Symbol(uppercase(string(name)))) + constant = Symbol(uppercase(string(name))) end quote - Core.@__doc__ immutable $name <: $supertype end - Core.@__doc__ const $(constant) = $name() + Core.@__doc__ immutable $(esc(name)) <: $(esc(supertype)) end + Core.@__doc__ const $(esc(constant)) = $(esc(name))() end end diff --git a/test/runtests.jl b/test/runtests.jl index db6e080..88bbefa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,8 +3,9 @@ using ArgCheck using Base.Test import Compat: ∘ -include("test-utilities.jl") +include("utilities.jl") +include("test-utilities.jl") include("test-intervals.jl") include("test-transformations-basic.jl") include("test-transformations-composed.jl") diff --git a/test/test-utilities.jl b/test/test-utilities.jl index 247efb7..4c5978f 100644 --- a/test/test-utilities.jl +++ b/test/test-utilities.jl @@ -1,115 +1,11 @@ -import ForwardDiff: derivative -import Base: rand +"Test singleton type." +@define_singleton TestSingleton <: Real -""" -Return a random float in an interval (for testing). Do not use -directly when testing extrema, as these may happen with `0` -probability. -""" -rand(::RealLine, ::Type{Val{true}}) = randn() -rand(ray::PositiveRay, ::Type{Val{true}}) = ray.left + abs(randn()) -rand(ray::NegativeRay, ::Type{Val{true}}) = ray.right + abs(randn()) -rand(seg::Segment, ::Type{Val{true}}) = seg.left + width(seg) * rand() +@testset "define singleton" begin + + @test TestSingleton <: Real + @test isa(TESTSINGLETON, TestSingleton) + @test repr(@doc(TESTSINGLETON)) == repr(@doc(TestSingleton)) == + repr(doc"Test singleton type.") -function rand(x::AbstractInterval; left_prob = 0.1, right_prob = 0.1) - @argcheck left_prob + right_prob ≤ 1 - z = rand() - left, right = extrema(x) - if z < left_prob - left - elseif z > 1-right_prob - right - else - rand(x, Val{true}) - end end - - -""" -Return a function that generates random intervals in the given -interval (for testing). -""" -function random_interval(x::AbstractInterval) - a = rand(x; right_prob = 0) - b = rand(x; left_prob = 0) - if a > b - a, b = b, a - end - Interval(a, b) -end - -""" -Return a vector of values outside the interval (for testing). -""" -scalars_outside_interval(::RealLine) = [] -scalars_outside_interval(ray::PositiveRay) = ray.left - [0.1, 1.0, 2.0, Inf] -scalars_outside_interval(ray::NegativeRay) = ray.right + [0.1, 1.0, 2.0, Inf] -function scalars_outside_interval(seg::Segment) - vcat(scalars_outside_interval(PositiveRay(seg.left)), - scalars_outside_interval(NegativeRay(seg.right))) -end - -""" -Test univariate transformation `f` with `x`. Tests for: - -1. type of the transformed value, -2. whether it is in the range, -3. inverse, -4. jacobian determinant and its log using automatic differentiation. - -`forwarddiff_exceptions` is a dictionary handling exceptions that ForwardDiff -cannot cope with at the moment. See eg -## workaround for https://github.com/JuliaDiff/ForwardDiff.jl/issues/209 -""" -function test_univariate_scalar{T}(f::UnivariateTransformation, x::T; - AD_exceptions = Dict()) - y = f(x) - @test y ∈ image(f) - @test inv(f)(y) ≈ x - (y2, jac) = f(x, JAC) - @test y == y2 - expected_jac = get(AD_exceptions, x, abs(derivative(f, x))) - @test jac ≈ expected_jac - (y3, logjac) = f(x, LOGJAC) - @test y == y3 - @test logjac ≈ log(expected_jac) -end - -# some exceptions below -logit_exceptions(t=Multiply(1.0)) = Dict(t(1.0) => Inf) - -logistic_exceptions() = Dict(-Inf => 0.0) - -""" -Test that univariate transformations map an interval the correct way. -""" -function test_univariate_interval(f::UnivariateTransformation, x::AbstractInterval) - y = f(x) - left, right = extrema(x) - f_left, f_right = f(left), f(right) - if f_right < f_left - f_right, f_left = f_left, f_right - end - y_left, y_right = extrema(y) - @test y_left ≈ f_left - @test y_right ≈ f_right -end - -""" -Test univariate transformation `f`, called with random numbers and -intervals generated by `randform`, which should return numbers in the -domain. -""" -function test_univariate(f; N=500, AD_exceptions = Dict()) - dom = domain(f) - for i in 1:500 - test_univariate_scalar(f, rand(dom), AD_exceptions = AD_exceptions) - end - for i in 1:500 - test_univariate_interval(f, random_interval(dom)) - end - for x in scalars_outside_interval(dom) - @test_throws DomainError f(x) - end -end - diff --git a/test/utilities.jl b/test/utilities.jl new file mode 100644 index 0000000..78576f0 --- /dev/null +++ b/test/utilities.jl @@ -0,0 +1,114 @@ +import ForwardDiff: derivative +import Base: rand + +""" +Return a random float in an interval (for testing). Do not use +directly when testing extrema, as these may happen with `0` +probability. +""" +rand(::RealLine, ::Type{Val{true}}) = randn() +rand(ray::PositiveRay, ::Type{Val{true}}) = ray.left + abs(randn()) +rand(ray::NegativeRay, ::Type{Val{true}}) = ray.right + abs(randn()) +rand(seg::Segment, ::Type{Val{true}}) = seg.left + width(seg) * rand() + +function rand(x::AbstractInterval; left_prob = 0.1, right_prob = 0.1) + @argcheck left_prob + right_prob ≤ 1 + z = rand() + left, right = extrema(x) + if z < left_prob + left + elseif z > 1-right_prob + right + else + rand(x, Val{true}) + end +end + + +""" +Return a function that generates random intervals in the given +interval (for testing). +""" +function random_interval(x::AbstractInterval) + a = rand(x; right_prob = 0) + b = rand(x; left_prob = 0) + if a > b + a, b = b, a + end + Interval(a, b) +end + +""" +Return a vector of values outside the interval (for testing). +""" +scalars_outside_interval(::RealLine) = [] +scalars_outside_interval(ray::PositiveRay) = ray.left - [0.1, 1.0, 2.0, Inf] +scalars_outside_interval(ray::NegativeRay) = ray.right + [0.1, 1.0, 2.0, Inf] +function scalars_outside_interval(seg::Segment) + vcat(scalars_outside_interval(PositiveRay(seg.left)), + scalars_outside_interval(NegativeRay(seg.right))) +end + +""" +Test univariate transformation `f` with `x`. Tests for: + +1. type of the transformed value, +2. whether it is in the range, +3. inverse, +4. jacobian determinant and its log using automatic differentiation. + +`forwarddiff_exceptions` is a dictionary handling exceptions that ForwardDiff +cannot cope with at the moment. See eg +## workaround for https://github.com/JuliaDiff/ForwardDiff.jl/issues/209 +""" +function test_univariate_scalar{T}(f::UnivariateTransformation, x::T; + AD_exceptions = Dict()) + y = f(x) + @test y ∈ image(f) + @test inv(f)(y) ≈ x + (y2, jac) = f(x, JAC) + @test y == y2 + expected_jac = get(AD_exceptions, x, abs(derivative(f, x))) + @test jac ≈ expected_jac + (y3, logjac) = f(x, LOGJAC) + @test y == y3 + @test logjac ≈ log(expected_jac) +end + +# some exceptions below +logit_exceptions(t=Multiply(1.0)) = Dict(t(1.0) => Inf) + +logistic_exceptions() = Dict(-Inf => 0.0) + +""" +Test that univariate transformations map an interval the correct way. +""" +function test_univariate_interval(f::UnivariateTransformation, x::AbstractInterval) + y = f(x) + left, right = extrema(x) + f_left, f_right = f(left), f(right) + if f_right < f_left + f_right, f_left = f_left, f_right + end + y_left, y_right = extrema(y) + @test y_left ≈ f_left + @test y_right ≈ f_right +end + +""" +Test univariate transformation `f`, called with random numbers and +intervals generated by `randform`, which should return numbers in the +domain. +""" +function test_univariate(f; N=500, AD_exceptions = Dict()) + dom = domain(f) + for i in 1:500 + test_univariate_scalar(f, rand(dom), AD_exceptions = AD_exceptions) + end + for i in 1:500 + test_univariate_interval(f, random_interval(dom)) + end + for x in scalars_outside_interval(dom) + @test_throws DomainError f(x) + end +end