Skip to content

Commit 63a14a3

Browse files
authored
1.0-dev: fix interval(::Interval) and some ambiguities (#554)
* Fix `interval(::Interval)` and some ambiguities * Remove superfluous`promote_rule` * Prevent promotion between `Real` and `Interval`
1 parent 7892c35 commit 63a14a3

File tree

4 files changed

+54
-31
lines changed

4 files changed

+54
-31
lines changed

src/intervals/arithmetic/basic.jl

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,9 @@
88

99
+(a::Interval) = a # Not in the IEEE standard
1010

11-
"""
12-
-(a::Interval)
13-
14-
Implement the `neg` function of the IEEE Std 1788-2015 (Table 9.1).
15-
"""
16-
-(a::F) where {F<:Interval} = F(-sup(a), -inf(a))
17-
18-
1911
"""
2012
+(a::Interval, b::Real)
21-
+(a::Real, a::Interval)
13+
+(a::Real, b::Interval)
2214
+(a::Interval, b::Interval)
2315
2416
Implement the `add` function of the IEEE Std 1788-2015 (Table 9.1).
@@ -34,10 +26,18 @@ function +(a::F, b::F) where {F<:Interval}
3426
(isempty(a) || isempty(b)) && return emptyinterval(F)
3527
return @round(F, inf(a) + inf(b), sup(a) + sup(b))
3628
end
29+
+(a::Interval, b::Interval) = +(promote(a, b)...)
30+
31+
"""
32+
-(a::Interval)
33+
34+
Implement the `neg` function of the IEEE Std 1788-2015 (Table 9.1).
35+
"""
36+
-(a::F) where {F<:Interval} = F(-sup(a), -inf(a))
3737

3838
"""
3939
-(a::Interval, b::Real)
40-
-(a::Real, a::Interval)
40+
-(a::Real, b::Interval)
4141
-(a::Interval, b::Interval)
4242
4343
Implement the `sub` function of the IEEE Std 1788-2015 (Table 9.1).
@@ -46,19 +46,18 @@ function -(a::F, b::T) where {T<:Real, F<:Interval{T}}
4646
isempty(a) && return emptyinterval(F)
4747
return @round(F, inf(a) - b, sup(a) - b)
4848
end
49-
5049
function -(b::T, a::F) where {T, F<:Interval{T}}
5150
isempty(a) && return emptyinterval(F)
5251
return @round(F, b - sup(a), b - inf(a))
5352
end
53+
-(a::F, b::Real) where {F<:Interval} = a - F(b)
54+
-(a::Real, b::F) where {F<:Interval} = F(a) - b
5455

5556
function -(a::F, b::F) where {F<:Interval}
5657
(isempty(a) || isempty(b)) && return emptyinterval(F)
5758
return @round(F, inf(a) - sup(b), sup(a) - inf(b))
5859
end
59-
60-
-(a::F, b::Real) where {F<:Interval} = a - F(b)
61-
-(a::Real, b::F) where {F<:Interval} = F(a) - b
60+
-(a::Interval, b::Interval) = -(promote(a, b)...)
6261

6362
"""
6463
scale(α, a::Interval)
@@ -71,7 +70,7 @@ For efficiency, does not check that the constant is positive.
7170

7271
"""
7372
*(a::Interval, b::Real)
74-
*(a::Real, a::Interval)
73+
*(a::Real, b::Interval)
7574
*(a::Interval, b::Interval)
7675
7776
Implement the `mul` function of the IEEE Std 1788-2015 (Table 9.1).
@@ -88,37 +87,33 @@ function *(x::T, a::F) where {T<:Real, F<:Interval{T}}
8887
return @round(F, sup(a)*x, inf(a)*x)
8988
end
9089
end
91-
9290
*(x::T, a::F) where {T<:Real, S, F<:Interval{S}} = Interval{S}(x) * a
9391
*(a::F, x::T) where {T<:Real, S, F<:Interval{S}} = x*a
9492

9593
function *(a::F, b::F) where {F<:Interval}
9694
(isempty(a) || isempty(b)) && return emptyinterval(F)
97-
9895
(isthinzero(a) || isthinzero(b)) && return zero(F)
99-
10096
(isbounded(a) && isbounded(b)) && return mult(*, a, b)
101-
10297
return mult((x, y, r) -> unbounded_mult(F, x, y, r), a, b)
10398
end
104-
99+
*(a::Interval, b::Interval) = *(promote(a, b)...)
105100

106101
# Helper functions for multiplication
107102
function unbounded_mult(::Type{F}, x::T, y::T, r::RoundingMode) where {T, F<:Interval{T}}
108-
iszero(x) && return sign(y)*zero_times_infinity(T)
109-
iszero(y) && return sign(x)*zero_times_infinity(T)
103+
iszero(x) && return sign(y) * zero_times_infinity(T)
104+
iszero(y) && return sign(x) * zero_times_infinity(T)
110105
return *(x, y, r)
111106
end
112107

113108
function mult(op, a::F, b::F) where {T, F<:Interval{T}}
114109
if inf(b) >= zero(T)
115110
inf(a) >= zero(T) && return @round(F, op(inf(a), inf(b)), op(sup(a), sup(b)))
116111
sup(a) <= zero(T) && return @round(F, op(inf(a), sup(b)), op(sup(a), inf(b)))
117-
return @round(F, inf(a)*sup(b), sup(a)*sup(b)) # when zero(T) ∈ a
112+
return @round(F, inf(a)*sup(b), sup(a)*sup(b)) # zero(T) ∈ a
118113
elseif sup(b) <= zero(T)
119114
inf(a) >= zero(T) && return @round(F, op(sup(a), inf(b)), op(inf(a), sup(b)))
120115
sup(a) <= zero(T) && return @round(F, op(sup(a), sup(b)), op(inf(a), inf(b)))
121-
return @round(F, sup(a)*inf(b), inf(a)*inf(b)) # when zero(T) ∈ a
116+
return @round(F, sup(a)*inf(b), inf(a)*inf(b)) # zero(T) ∈ a
122117
else
123118
inf(a) > zero(T) && return @round(F, op(sup(a), inf(b)), op(sup(a), sup(b)))
124119
sup(a) < zero(T) && return @round(F, op(inf(a), sup(b)), op(inf(a), inf(b)))
@@ -129,7 +124,7 @@ end
129124

130125
"""
131126
/(a::Interval, b::Real)
132-
/(a::Real, a::Interval)
127+
/(a::Real, b::Interval)
133128
/(a::Interval, b::Interval)
134129
135130
Implement the `div` function of the IEEE Std 1788-2015 (Table 9.1).
@@ -182,6 +177,7 @@ function /(a::F, b::F) where {T, F<:Interval{T}}
182177
end
183178
end
184179
end
180+
/(a::Interval, b::Interval) = /(promote(a, b)...)
185181

186182
"""
187183
inv(a::Interval)

src/intervals/construction.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ Interval(x::Irrational) = Interval{default_bound()}(x)
109109
return :(return $res) # Set body of the function to return the precomputed result
110110
end
111111

112+
# promotion
113+
114+
Base.promote_rule(::Type{Interval{T}}, ::Type{Interval{S}}) where {T,S} =
115+
Interval{promote_type(T, S)}
116+
112117
"""
113118
interval(a, b)
114119
@@ -117,15 +122,13 @@ If so, then an `Interval(a, b)` object is returned;
117122
if not, a warning is printed and the empty interval is returned.
118123
"""
119124
function interval(a::T, b::S) where {T<:Real, S<:Real}
120-
if !is_valid_interval(a, b)
121-
@warn "Invalid input, empty interval is returned"
122-
return emptyinterval(promote_type(T, S))
123-
end
124-
125-
return Interval(a, b)
125+
is_valid_interval(a, b) && return Interval(a, b)
126+
@warn "Invalid input, empty interval is returned"
127+
return emptyinterval(promote_type(T, S))
126128
end
127129

128130
interval(a::Real) = interval(a, a)
131+
interval(a::Interval) = interval(inf(a), sup(a)) # Check the validity of the interval
129132

130133
const checked_interval = interval
131134

test/interval_tests/construction.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ using Test
4040
@test big(ℯ) in Interval{Float32}(0, ℯ)
4141
@test big(π) in Interval{Float32}(π, 4)
4242

43+
@test interval(Interval(pi)) Interval(pi)
44+
@test interval(Interval(NaN, -Inf)) emptyinterval()
45+
4346
# a < Inf and b > -Inf
4447
@test @interval("1e300") Interval(9.999999999999999e299, 1.0e300)
4548
@test @interval("-1e307") Interval(-1.0000000000000001e307, -1.0e307)
@@ -165,6 +168,16 @@ end
165168
@test convert(Interval{BigFloat}, x) === x
166169
end
167170

171+
@testset "Promotion between intervals" begin
172+
x = Interval{Float64}(π)
173+
y = Interval{BigFloat}(π)
174+
x_, y_ = promote(x, y)
175+
176+
@test promote_type(typeof(x), typeof(y)) == Interval{BigFloat}
177+
@test bounds(x_) == (BigFloat(inf(x), RoundDown), BigFloat(sup(x), RoundUp))
178+
@test y_ y
179+
end
180+
168181
@testset "Typed intervals" begin
169182
@test typeof(@interval Float64 1 2) == Interval{Float64}
170183
@test typeof(@interval 1 2) == Interval{Float64}
@@ -186,6 +199,11 @@ end
186199

187200
a = convert(Interval{Float64}, @biginterval(3, 4))
188201
@test typeof(a) == Interval{Float64}
202+
203+
pi64, pi32 = Interval{Float64}(pi), Interval{Float32}(pi)
204+
x, y = promote(pi64, pi32)
205+
@test x pi64
206+
@test y Interval{Float64}(pi32)
189207
end
190208

191209
@testset "Interval{T} constructor" begin

test/interval_tests/numeric.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ end
4040
@test a + b Interval(+(a.lo, b.lo, RoundDown), +(a.hi, b.hi, RoundUp))
4141
@test -a Interval(-a.hi, -a.lo)
4242
@test a - b Interval(-(a.lo, b.hi, RoundDown), -(a.hi, b.lo, RoundUp))
43+
for f in (:+, :-, :*, :/)
44+
@eval begin
45+
@test $f(Interval{Float64}(pi), Interval{Float32}(pi))
46+
$f(Interval{Float64}(pi), Interval{Float64}(Interval{Float32}(pi)))
47+
end
48+
end
4349
@test Interval(1//4,1//2) + Interval(2//3) Interval(11//12, 7//6)
4450
@test_broken Interval(1//4,1//2) - Interval(2//3) Interval(-5//12, -1//6)
4551

0 commit comments

Comments
 (0)