Skip to content

Commit

Permalink
Add tests provided by Aqua.jl (JuliaIntervals#687)
Browse files Browse the repository at this point in the history
* Add tests provided by Aqua.jl

* Additions to Project.toml and test/Project.toml

* Fix _interval_infsup ambiguities

* Add ambiguity solutions proposed by @OlivierHnt, and revert 47605eb

47605eb solved some ambiguities, but induced (construction) errors

Co-authored-by: Olivier Hénot <[email protected]>

* Solve Base.union! ambiguities

* Remove LinearAlgebra from [deps]

* Try to solve some ambiguities related to ForwardDiff

* Return Dual's for promote_rule

* Add convert method to ForwardDiff extension

* Add Dual(x::ExactReal)

* More methods Dual(::ExactReal)

* Fix Project.toml

* Define similar to avoid many ambiguities

* Fix rebase issues

* Fix tests

* Fix compat

* Fix similar breaking Documenter

---------

Co-authored-by: Olivier Hénot <[email protected]>
Co-authored-by: Benoît Richard <[email protected]>
  • Loading branch information
3 people authored Dec 9, 2024
1 parent a2ef716 commit da867a2
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 40 deletions.
5 changes: 3 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,21 @@ RoundingEmulator = "5eaf0fd0-dfba-4ccb-bf02-d820a40db705"
[weakdeps]
DiffRules = "b552c78f-8df3-52c6-915a-8e097449b14b"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"

[extensions]
IntervalArithmeticDiffRulesExt = "DiffRules"
IntervalArithmeticForwardDiffExt = "ForwardDiff"
IntervalArithmeticRecipesBaseExt = "RecipesBase"
IntervalArithmeticIntervalSetsExt = "IntervalSets"
IntervalArithmeticRecipesBaseExt = "RecipesBase"

[compat]
CRlibm_jll = "1"
DiffRules = "1"
ForwardDiff = "0.10"
IntervalSets = "0.7"
LinearAlgebra = "1.9"
MacroTools = "0.5"
RecipesBase = "1"
RoundingEmulator = "0.2"
Expand Down
26 changes: 21 additions & 5 deletions ext/IntervalArithmeticForwardDiffExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,27 @@ module IntervalArithmeticForwardDiffExt
using IntervalArithmetic, ForwardDiff
using ForwardDiff: Dual, Partials, , value, partials

#
# Needed to avoid method ambiguities:
ForwardDiff.can_dual(::Type{ExactReal}) = true
Dual(x::ExactReal) = Dual{Nothing, typeof(x), 0}(x.value)
Dual{T}(x::ExactReal) where {T} = Dual{T, typeof(x), 0}(x.value)
Dual{T, V}(x::ExactReal) where {T, V<:Real} = convert(Dual{T, V, 0}, x)
Dual{T, V, N}(x::ExactReal) where {T, V<:Real, N} = convert(Dual{T, V, N}, x)

Base.convert(::Type{Dual{T,V,N}}, x::ExactReal) where {T,V,N} = Dual{T}(V(x), zero(Partials{N,V}))

Base.promote_rule(::Type{Dual{T, V, N}}, ::Type{Interval{S}}) where {T, V, N, S<:Union{AbstractFloat, Rational}} =
Dual{T,Interval{IntervalArithmetic.promote_numtype(V, S)},N}
Base.promote_rule(::Type{Interval{S}}, ::Type{Dual{T, V, N}}) where {S<:Union{AbstractFloat, Rational}, T, V, N} =
Dual{T,Interval{IntervalArithmetic.promote_numtype(V, S)},N}
Base.promote_rule(::Type{ExactReal{S}}, ::Type{Dual{T, V, N}}) where {S<:Real, T, V, N} =
Dual{T,ExactReal{IntervalArithmetic.promote_numtype(V, S)},N}
Base.promote_rule(::Type{Dual{T, V, N}}, ::Type{ExactReal{S}}) where {S<:Real, T, V, N} =
Dual{T,ExactReal{IntervalArithmetic.promote_numtype(V, S)},N}

Base.:(==)(x::Union{BareInterval,Interval}, y::Dual) = isthin(x, y)
Base.:(==)(x::Dual, y::Union{BareInterval,Interval}) = y == x


function Base.:(^)(x::Dual{Txy,<:Interval}, y::Dual{Txy,<:Interval}) where {Txy}
vx, vy = value(x), value(y)
Expand Down Expand Up @@ -70,8 +90,4 @@ function Base.:(^)(x::ExactReal, y::Dual{<:Ty}) where {Ty}
end
end

# resolve ambiguity

Base.convert(::Type{Dual{T,V,N}}, x::ExactReal) where {T,V,N} = Dual{T}(V(x), zero(Partials{N,V}))

end
6 changes: 6 additions & 0 deletions src/intervals/construction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ interval(::Type{T}, A::AbstractArray, d::AbstractArray{Decoration}; format::Symb
interval(A::AbstractArray, d::AbstractArray{Decoration}; format::Symbol = :infsup) = interval.(A, d; format = format)
interval(::Type{T}, A::AbstractArray, B::AbstractArray, d::AbstractArray{Decoration}; format::Symbol = :infsup) where {T} = interval.(T, A, B, d; format = format)
interval(A::AbstractArray, B::AbstractArray, d::AbstractArray{Decoration}; format::Symbol = :infsup) = interval.(A, B, d; format = format)
interval(T::Type, d::Decoration; format::Symbol = :infsup) = throw(MethodError(interval, (T, d)))

# standard format

Expand Down Expand Up @@ -488,6 +489,11 @@ function _interval_infsup(::Type{T}, x, y::Union{BareInterval,Interval}, d::Deco
end
end

_interval_infsup(::Type{T}, a::Complex, b::Union{BareInterval,Interval}, d::Decoration = com) where {T<:NumTypes} =
complex(_interval_infsup(T, real(a), real(b), d), _interval_infsup(T, imag(a), imag(b), d))
_interval_infsup(::Type{T}, a::Union{BareInterval,Interval}, b::Complex, d::Decoration = com) where {T<:NumTypes} =
complex(_interval_infsup(T, real(a), real(b), d), _interval_infsup(T, imag(a), imag(b), d))

_interval_infsup(::Type{T}, a::Complex, b::Complex, d::Decoration = com) where {T<:NumTypes} =
complex(_interval_infsup(T, real(a), real(b), d), _interval_infsup(T, imag(a), imag(b), d))
_interval_infsup(::Type{T}, a::Complex, b, d::Decoration = com) where {T<:NumTypes} =
Expand Down
2 changes: 2 additions & 0 deletions src/intervals/exact_literals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ struct ExactReal{T<:Real} <: Real
ExactReal(value::T) where {T<:Real} = new{T}(value)
end

ExactReal(x::ExactReal) = x

_value(x::ExactReal) = x.value # hook for interval constructor

# utilities
Expand Down
5 changes: 5 additions & 0 deletions src/intervals/real_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ for T ∈ (:BareInterval, :Interval)
throw(ArgumentError("`setdiff!` is purposely not supported for intervals. See instead `interiordiff`"))
end
end
Base.union!(::AbstractVector{S}, ::BareInterval, ::Interval, ::Any...) where {S} =
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
Base.union!(::AbstractVector{S}, ::Interval, ::BareInterval, ::Any...) where {S} =
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))


# allow pointwise equality

Expand Down
41 changes: 8 additions & 33 deletions src/matmul.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,39 +86,14 @@ struct MatMulMode{T} end

matmul_mode() = MatMulMode{:slow}()

#

function Base.:*(A::AbstractMatrix{<:RealOrComplexI}, B::AbstractMatrix{<:RealOrComplexI})
T = promote_type(eltype(A), eltype(B))
C = zeros(T, size(A, 1), size(B, 2))
return LinearAlgebra.mul!(C, A, B, one(T), zero(T))
end
function Base.:*(A::AbstractMatrix{<:RealOrComplexI}, B::AbstractVector{<:RealOrComplexI})
T = promote_type(eltype(A), eltype(B))
C = zeros(T, size(A, 1))
return LinearAlgebra.mul!(C, A, B, one(T), zero(T))
end

function Base.:*(A::AbstractMatrix{<:RealOrComplexI}, B::AbstractMatrix)
T = promote_type(eltype(A), eltype(B))
C = zeros(T, size(A, 1), size(B, 2))
return LinearAlgebra.mul!(C, A, B, one(T), zero(T))
end
function Base.:*(A::AbstractMatrix{<:RealOrComplexI}, B::AbstractVector)
T = promote_type(eltype(A), eltype(B))
C = zeros(T, size(A, 1))
return LinearAlgebra.mul!(C, A, B, one(T), zero(T))
end

function Base.:*(A::AbstractMatrix, B::AbstractMatrix{<:RealOrComplexI})
T = promote_type(eltype(A), eltype(B))
C = zeros(T, size(A, 1), size(B, 2))
return LinearAlgebra.mul!(C, A, B, one(T), zero(T))
end
function Base.:*(A::AbstractMatrix, B::AbstractVector{<:RealOrComplexI})
T = promote_type(eltype(A), eltype(B))
C = zeros(T, size(A, 1))
return LinearAlgebra.mul!(C, A, B, one(T), zero(T))
Base.similar(a::Array{T}) where {T <: RealOrComplexI} = zeros(T, size(a))
Base.similar(a::Array{T}, S::Type) where {T <: RealOrComplexI} = zeros(S, size(a))
Base.similar(::Array{T}, m::Int) where {T <: RealOrComplexI} = zeros(T, m)
Base.similar(::Array{T}, S::Type, dims::Dims{N}) where {N, T <: RealOrComplexI} = zeros(S, dims)
Base.similar(::Array{T}, dims::Dims{N}) where {T <: RealOrComplexI, N} = zeros(T, dims)

function LinearAlgebra.mul!(C::AbstractVecOrMat{<:RealOrComplexI}, A::AbstractMatrix{<:RealOrComplexI}, B::AbstractVecOrMat{<:RealOrComplexI})
return LinearAlgebra.mul!(C, A, B, interval(true), interval(false))
end

function LinearAlgebra.mul!(C::AbstractVecOrMat{<:RealOrComplexI}, A::AbstractMatrix{<:RealOrComplexI}, B::AbstractVecOrMat{<:RealOrComplexI}, α::Number, β::Number)
Expand Down
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[deps]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
Expand Down
29 changes: 29 additions & 0 deletions test/aqua.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Test
using IntervalArithmetic
using Aqua

@testset "Aqua tests (performance)" begin
# This tests that we don't accidentally run into
# https://github.com/JuliaLang/julia/issues/29393
# Aqua.test_unbound_args(IntervalArithmetic)
ua = Aqua.detect_unbound_args_recursively(IntervalArithmetic)
@test length(ua) == 0

# See: https://github.com/SciML/OrdinaryDiffEq.jl/issues/1750
# Test that we're not introducing method ambiguities across deps
ambs = Aqua.detect_ambiguities(IntervalArithmetic; recursive = true)
pkg_match(pkgname, pkdir::Nothing) = false
pkg_match(pkgname, pkdir::AbstractString) = occursin(pkgname, pkdir)
filter!(x -> pkg_match("IntervalArithmetic", pkgdir(last(x).module)), ambs)
@test_broken length(ambs) == 0
end

@testset "Aqua tests (additional)" begin
Aqua.test_undefined_exports(IntervalArithmetic)
# Aqua.test_deps_compat(IntervalArithmetic)
Aqua.test_stale_deps(IntervalArithmetic)
Aqua.test_piracies(IntervalArithmetic)
Aqua.test_unbound_args(IntervalArithmetic)
Aqua.test_project_extras(IntervalArithmetic)
Aqua.test_persistent_tasks(IntervalArithmetic)
end
3 changes: 3 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ for f ∈ readdir("ITF1788_tests"; join = true)
include(f)
end
end

# Aqua tests
include("aqua.jl")

0 comments on commit da867a2

Please sign in to comment.