Skip to content

Commit 087a63b

Browse files
committed
Rework comparison functionalities
1 parent a579446 commit 087a63b

File tree

4 files changed

+87
-104
lines changed

4 files changed

+87
-104
lines changed

ext/IntervalArithmeticForwardDiffExt.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ Base.promote_rule(::Type{ExactReal{S}}, ::Type{Dual{T, V, N}}) where {S<:Real, T
2323
Base.promote_rule(::Type{Dual{T, V, N}}, ::Type{ExactReal{S}}) where {S<:Real, T, V, N} =
2424
Dual{T,ExactReal{IntervalArithmetic.promote_numtype(V, S)},N}
2525

26-
Base.:(==)(x::Union{BareInterval,Interval}, y::Dual) = x == value(y)
27-
Base.:(==)(x::Dual, y::Union{BareInterval,Interval}) = value(x) == y
26+
Base.:(==)(x::Interval, y::Dual) = x == value(y)
27+
Base.:(==)(x::Dual, y::Interval) = value(x) == y
2828

2929
function Base.:(^)(x::Dual{Txy,<:Interval}, y::Dual{Txy,<:Interval}) where {Txy}
3030
vx, vy = value(x), value(y)
@@ -91,10 +91,9 @@ function Base.:(^)(x::ExactReal, y::Dual{<:Ty}) where {Ty}
9191
end
9292
end
9393

94-
9594
# Piecewise functions
9695

97-
function (constant::Constant)(::Dual{T, Interval{S}}) where {T, S}
96+
function (constant::Constant)(::Dual{T,Interval{S}}) where {T, S}
9897
return Dual{T}(interval(S, constant.value), interval(S, 0.0))
9998
end
10099

src/intervals/real_interface.jl

Lines changed: 61 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -78,96 +78,77 @@ Base.hash(x::Interval, h::UInt) = hash(sup(x), hash(inf(x), hash(Interval, h)))
7878

7979
#
8080

81-
for T (:BareInterval, :Interval)
82-
@eval begin
83-
function Base.:(==)(x::$T, y::$T) # also returned when calling `≤`, `≥`, `isequal`
84-
isthin(x) && return sup(x) == y
85-
isthin(y) && return x == sup(y)
86-
return throw(ArgumentError("`==` is purposely not supported when the intervals are overlapping. See instead `isequal_interval`"))
87-
end
88-
89-
Base.:<(::$T, ::$T) = # also returned when calling `isless`, `>`
90-
throw(ArgumentError("`<` is purposely not supported for intervals. See instead `isstrictless`, `strictprecedes`"))
91-
92-
Base.isdisjoint(::$T, ::$T) =
93-
throw(ArgumentError("`isdisjoint` is purposely not supported for intervals. See instead `isdisjoint_interval`"))
94-
95-
Base.issubset(::$T, ::$T) =
96-
throw(ArgumentError("`issubset` is purposely not supported for intervals. See instead `issubset_interval`"))
97-
98-
Base.issetequal(::$T, ::$T) =
99-
throw(ArgumentError("`issetequal` is purposely not supported for intervals. See instead `isequal_interval`"))
100-
101-
Base.in(::$T, ::$T) =
102-
throw(ArgumentError("`in` is purposely not supported for intervals. See instead `in_interval`"))
103-
104-
Base.isempty(::$T) =
105-
throw(ArgumentError("`isempty` is purposely not supported for intervals. See instead `isempty_interval`"))
106-
107-
Base.isfinite(::$T) = # also returned when calling `isinf`
108-
throw(ArgumentError("`isfinite` is purposely not supported for intervals. See instead `isbounded`"))
109-
110-
Base.isnan(::$T) =
111-
throw(ArgumentError("`isnan` is purposely not supported for intervals. See instead `isnai`"))
112-
113-
Base.intersect(::$T) =
114-
throw(ArgumentError("`intersect` is purposely not supported for intervals. See instead `intersect_interval`"))
115-
116-
Base.union!(::BitSet, ::$T) = # needed to resolve ambiguity
117-
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
118-
Base.union!(::AbstractSet, ::$T) = # also returned when calling `intersect`, `symdiff` with intervals
119-
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
120-
Base.union!(::AbstractVector{S}, ::$T) where {S} =
121-
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
122-
Base.union!(::AbstractVector{S}, ::$T, ::Any, ::Any...) where {S} =
123-
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
124-
Base.union!(::AbstractVector{S}, ::$T, ::$T, ::Any...) where {S} =
125-
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
126-
Base.union!(::AbstractVector{S}, ::Any, ::$T, ::Any...) where {S} =
127-
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
128-
129-
Base.setdiff(::$T) =
130-
throw(ArgumentError("`setdiff` is purposely not supported for intervals. See instead `interiordiff`"))
131-
Base.setdiff!(::AbstractSet, ::$T) =
132-
throw(ArgumentError("`setdiff!` is purposely not supported for intervals. See instead `interiordiff`"))
133-
end
81+
function Base.:(==)(x::Interval, y::Interval) # also returned when calling `≤`, `≥`, `isequal`
82+
isthin(x) && return sup(x) == y
83+
isthin(y) && return x == sup(y)
84+
isdisjoint_interval(x, y) && return false
85+
return throw(ArgumentError("`==` is purposely not supported when the intervals are overlapping. See instead `isequal_interval`"))
86+
end
87+
88+
function Base.:<(x::Interval, y::Interval)
89+
isthin(x) && return sup(x) < y
90+
isthin(y) && return x < sup(y)
91+
strictprecedes(x, y) && return true
92+
strictprecedes(y, x) && return false
93+
return throw(ArgumentError("`<` is purposely not supported when the intervals are overlapping. See instead `strictprecedes`"))
13494
end
135-
Base.union!(::AbstractVector{S}, ::BareInterval, ::Interval, ::Any...) where {S} =
136-
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
137-
Base.union!(::AbstractVector{S}, ::Interval, ::BareInterval, ::Any...) where {S} =
138-
throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
13995

96+
# Base.isdisjoint(::Interval, ::Interval) =
97+
# throw(ArgumentError("`isdisjoint` is purposely not supported for intervals. See instead `isdisjoint_interval`"))
98+
99+
# Base.issubset(::Interval, ::Interval) =
100+
# throw(ArgumentError("`issubset` is purposely not supported for intervals. See instead `issubset_interval`"))
101+
102+
# Base.issetequal(::Interval, ::Interval) =
103+
# throw(ArgumentError("`issetequal` is purposely not supported for intervals. See instead `isequal_interval`"))
104+
105+
# Base.in(::Interval, ::Interval) =
106+
# throw(ArgumentError("`in` is purposely not supported for intervals. See instead `in_interval`"))
107+
108+
Base.isempty(::Interval) =
109+
throw(ArgumentError("`isempty` is purposely not supported for intervals. See instead `isempty_interval`"))
110+
111+
# Base.isfinite(::Interval) = # also returned when calling `isinf`
112+
# throw(ArgumentError("`isfinite` is purposely not supported for intervals. See instead `isbounded`"))
113+
114+
Base.isnan(::Interval) =
115+
throw(ArgumentError("`isnan` is purposely not supported for intervals. See instead `isnai`"))
116+
117+
# Base.intersect(::Interval) =
118+
# throw(ArgumentError("`intersect` is purposely not supported for intervals. See instead `intersect_interval`"))
119+
120+
# Base.union!(::BitSet, ::Interval) = # needed to resolve ambiguity
121+
# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
122+
# Base.union!(::AbstractSet, ::Interval) = # also returned when calling `intersect`, `symdiff` with intervals
123+
# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
124+
# Base.union!(::AbstractVector{S}, ::Interval) where {S} =
125+
# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
126+
# Base.union!(::AbstractVector{S}, ::Interval, ::Any, ::Any...) where {S} =
127+
# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
128+
# Base.union!(::AbstractVector{S}, ::Interval, ::Interval, ::Any...) where {S} =
129+
# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
130+
# Base.union!(::AbstractVector{S}, ::Any, ::Interval, ::Any...) where {S} =
131+
# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`"))
132+
133+
# Base.setdiff(::Interval) =
134+
# throw(ArgumentError("`setdiff` is purposely not supported for intervals. See instead `interiordiff`"))
135+
# Base.setdiff!(::AbstractSet, ::Interval) =
136+
# throw(ArgumentError("`setdiff!` is purposely not supported for intervals. See instead `interiordiff`"))
140137

141138
# pointwise equality
142139

143-
"""
144-
==(::BareInterval, ::Number)
145-
==(::Number, ::BareInterval)
146-
==(::Interval, ::Number)
147-
==(::Number, ::Interval)
148-
149-
Test whether an interval is the singleton of a given number. In other words, the
150-
result is true if and only if the interval contains only that number.
151-
152-
!!! note
153-
Comparison between intervals is purposely disallowed. Indeed, equality
154-
between non-singleton intervals has distinct properties, notably ``x = y``
155-
does not imply ``x - y = 0``. See instead [`isequal_interval`](@ref).
156-
"""
157-
Base.:(==)(x::Union{BareInterval,Interval}, y::Number) = isthin(x, y)
158-
Base.:(==)(x::Number, y::Union{BareInterval,Interval}) = y == x
140+
Base.:(==)(x::Interval, y::Number) = !isthin(x) & in_interval(y, x) ? throw(ArgumentError("`==` is purposely not supported when the number is contained in the interval. See instead `isthin`")) : isthin(x, y)
141+
Base.:(==)(x::Number, y::Interval) = y == x
159142
# needed to resolve ambiguity from irrationals.jl
160-
Base.:(==)(x::Interval, y::AbstractIrrational) = isthin(x, y)
143+
Base.:(==)(x::Interval, y::AbstractIrrational) = !isthin(x) & in_interval(y, x) ? throw(ArgumentError("`==` is purposely not supported when the number is contained in the interval. See instead `isthin`")) : isthin(x, y)
161144
Base.:(==)(x::AbstractIrrational, y::Interval) = y == x
162145
# needed to resolve ambiguity from complex.jl
163146
Base.:(==)(x::Interval, y::Complex) = isreal(y) & (real(y) == x)
164147
Base.:(==)(x::Complex, y::Interval) = y == x
165148

166-
# follows docstring of `Base.iszero`
167-
Base.iszero(x::Union{BareInterval,Interval}) = isthinzero(x)
168149

169-
# follows docstring of `Base.isone`
170-
Base.isone(x::Union{BareInterval,Interval}) = isthinone(x)
150+
Base.:<(x::Interval, y::Real) = (!isthin(x) & in_interval(y, x)) | isempty_interval(x) ? throw(ArgumentError("`<` is purposely not supported when the number is contained in the interval, or if the interval is empty")) : sup(x) < y
151+
Base.:<(x::Real, y::Interval) = (!isthin(y) & in_interval(x, y)) | isempty_interval(y) ? throw(ArgumentError("`<` is purposely not supported when the number is contained in the interval, or if the interval is empty")) : x < inf(y)
152+
171153

172-
# follows docstring of `Base.isinteger`
173-
Base.isinteger(x::Union{BareInterval,Interval}) = isthininteger(x)
154+
Base.isinteger(x::Interval) = !isthin(x) & !isdisjoint_interval(x, floor(x), ceil(x)) ? throw(ArgumentError("`isinteger` is purposely not supported for non-thin containing at least one integer. See instead `isthininteger`")) : isthininteger(x)

test/interval_tests/consistency.jl

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -363,17 +363,20 @@
363363
@testset "Disallowed `Real` functionalities" begin
364364
x, y = interval(1), interval(2)
365365
@test x != y
366-
@test (interval(1, 2) != y) & (y != interval(1, 2))
366+
@test_throws ArgumentError interval(1, 2) != y
367+
@test_throws ArgumentError y != interval(1, 2)
367368
@test_throws ArgumentError interval(1, 2) == interval(1, 2)
368-
@test_throws ArgumentError x < y
369-
@test_throws ArgumentError isdisjoint(x, y)
370-
@test_throws ArgumentError issubset(x, y)
371-
@test_throws ArgumentError issetequal(x, y)
372-
@test_throws ArgumentError x y
369+
@test x < y
370+
@test isdisjoint(x, y)
371+
@test !issubset(x, y)
372+
@test !issetequal(x, y)
373+
@test x y
373374
@test_throws ArgumentError isempty(x)
374-
@test_throws ArgumentError isfinite(x)
375+
@test_throws MethodError isfinite(x)
375376
@test_throws ArgumentError isnan(x)
376377
@test isinteger(x)
378+
@test !isinteger(interval(1.2, 1.9))
379+
@test_throws ArgumentError isinteger(interval(1.5, 2.5))
377380
@test x == 1
378381
@test isone(x)
379382
@test !iszero(x)

test/interval_tests/set_operations.jl

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
using IntervalArithmetic: interval_diff
22

3-
@testset "removed interval" begin
4-
@test_throws ArgumentError intersect(interval(1))
5-
@test_throws ArgumentError intersect(interval(1), 2, [1], 4., 5)
6-
@test_throws ArgumentError intersect(interval(1), interval(2.), interval(3.))
7-
@test_throws ArgumentError union(interval(1))
8-
@test_throws ArgumentError union(interval(1), 2, [1], 4., 5)
9-
@test_throws ArgumentError union(interval(1), interval(2.), interval(3.))
10-
@test_throws ArgumentError setdiff(interval(1))
11-
@test_throws ArgumentError setdiff(interval(1), 2, [1], 4., 5)
12-
@test_throws ArgumentError setdiff(interval(1), interval(2.), interval(3.))
13-
@test_throws ArgumentError symdiff(interval(1), interval(2.), interval(3.))
14-
end
3+
# @testset "removed interval" begin
4+
# @test_throws ArgumentError intersect(interval(1))
5+
# @test_throws ArgumentError intersect(interval(1), 2, [1], 4., 5)
6+
# @test_throws ArgumentError intersect(interval(1), interval(2.), interval(3.))
7+
# @test_throws ArgumentError union(interval(1))
8+
# @test_throws ArgumentError union(interval(1), 2, [1], 4., 5)
9+
# @test_throws ArgumentError union(interval(1), interval(2.), interval(3.))
10+
# @test_throws ArgumentError setdiff(interval(1))
11+
# @test_throws ArgumentError setdiff(interval(1), 2, [1], 4., 5)
12+
# @test_throws ArgumentError setdiff(interval(1), interval(2.), interval(3.))
13+
# @test_throws ArgumentError symdiff(interval(1), interval(2.), interval(3.))
14+
# end
1515

1616
@testset "interiordiff" begin
1717
x = interval(2, 4)
@@ -57,4 +57,4 @@ end
5757

5858
@test interval_diff(interval(1, 10), interval(-1, 14)) == []
5959
@test interval_diff(interval(1, 10), interval(1, 10)) == []
60-
end
60+
end

0 commit comments

Comments
 (0)