Skip to content

Commit 4657b06

Browse files
dpsanderslbenet
authored andcommitted
Rewrite IntervalBox to contain an SVector of Intervals (#152)
* Arithmetic operations and functions on IntervalBox return IntervalBox * Add some tests of functions on IntervalBoxes * More tests... * Rewrite IntervalBox to contain an SVector * Modify arithmetic operations for new IntervalBox * Fix display of IntervalBox * Add missing functions and fix tests * Rename arithmetic_functions -> arithmetic * Fix broadcasting * Fix tests. So far no iteration for IntervalBox * Add setindex * Add propagate_inbounds * Add iteration for IntervalBox * Add tests for getindex and setindex * Typo * Fix broadcasting and add tests * Fix broadcasting, take 2
1 parent 777ad9d commit 4657b06

File tree

7 files changed

+121
-21
lines changed

7 files changed

+121
-21
lines changed

src/IntervalArithmetic.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ import Base:
2929
isinteger, setdiff,
3030
parse
3131

32+
import Base: # for IntervalBox
33+
broadcast, dot, length,
34+
getindex, setindex,
35+
start, next, done, eltype
36+
3237
export
3338
AbstractInterval, Interval,
3439
interval,

src/display.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,10 @@ function representation(X::IntervalBox, format=nothing)
245245
end
246246

247247
if display_params.format == :full
248-
return string("IntervalBox(", join(X, ", "), ")")
248+
return string("IntervalBox(", join(X.v, ", "), ")")
249249

250250
else
251-
return join(X, " × ")
251+
return join(X.v, " × ")
252252
end
253253

254254
end

src/multidim/arithmetic.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This file is part of the IntervalArithmetic.jl package; MIT licensed
2+
3+
+(a::IntervalBox, b::IntervalBox) = IntervalBox( a.v .+ b.v )
4+
+(a::IntervalBox, b::Real) = IntervalBox( a.v .+ b )
5+
+(a::Real, b::IntervalBox) = IntervalBox( a .+ b.v )
6+
7+
-(a::IntervalBox, b::IntervalBox) = IntervalBox( a.v .- b.v )
8+
-(a::IntervalBox, b::Real) = IntervalBox( a.v .- b )
9+
-(a::Real, b::IntervalBox) = IntervalBox( a .- b.v )
10+
-(a::IntervalBox) = IntervalBox( .- a.v )
11+
12+
*(a::IntervalBox, b::Real) = IntervalBox( a.v .* b )
13+
*(a::Real, b::IntervalBox) = IntervalBox( a .* b.v )
14+
15+
/(a::IntervalBox, b::Real) = IntervalBox( a.v ./ b )
16+
17+
18+
# broadcasting:
19+
20+
# wrap decides whether to wrap the result in an IntervalBox or not, based on the return type
21+
wrap(v::SVector{N,T} where {N,T<:Interval}) = IntervalBox(v)
22+
wrap(v) = v
23+
24+
Base.broadcast(f, X::IntervalBox) = wrap(f.(X.v))
25+
Base.broadcast(f, X::IntervalBox, Y::IntervalBox) = wrap(f.(X.v, Y.v))

src/multidim/intervalbox.jl

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,76 @@
11
# This file is part of the IntervalArithmetic.jl package; MIT licensed
22

33
"""An `IntervalBox` is an `N`-dimensional rectangular box, given
4-
by a Cartesian product of `N` `Interval`s.
4+
by a Cartesian product of a vector of `N` `Interval`s.
55
"""
6-
struct IntervalBox{N,T} <: StaticVector{N, Interval{T}}
7-
data::NTuple{N,Interval{T}}
6+
struct IntervalBox{N,T}
7+
v::SVector{N, Interval{T}}
88
end
99

10-
# StaticArrays.Size{N,T}(::Type{IntervalBox{N,T}}) = StaticArrays.Size(N) # @pure not needed, I think...
11-
Base.@propagate_inbounds Base.getindex(a::IntervalBox, i::Int) = a.data[i]
10+
# IntervalBox(x::Interval) = IntervalBox( SVector(x) ) # single interval treated as tuple with one element
11+
12+
IntervalBox(x::Interval...) = IntervalBox(SVector(x))
13+
IntervalBox(x::Tuple{T}) where {T<:Interval} = IntervalBox(SVector(x))
14+
15+
Base.@propagate_inbounds Base.getindex(X::IntervalBox, i) = X.v[i]
16+
17+
setindex(X::IntervalBox, y, i) = IntervalBox( setindex(X.v, y, i) )
18+
19+
# iteration:
20+
21+
22+
start(X::IntervalBox{N,T}) where {N,T} = 1
23+
24+
next(X::IntervalBox{N,T}, state) where {N,T} = (X[state], state+1)
25+
26+
done(X::IntervalBox{N,T}, state) where {N,T} = state > N
27+
28+
eltype(::Type{IntervalBox{N,T}}) where {N,T} = Interval{T} # Note that this is defined for the type
29+
30+
# length(X::IntervalBox{N,T}) where {N,T} = N
1231

1332

14-
IntervalBox(x::Interval) = IntervalBox( (x,) ) # single interval treated as tuple with one element
1533

1634

1735
## arithmetic operations
1836
# Note that standard arithmetic operations are implemented automatically by FixedSizeArrays.jl
1937

20-
mid(X::IntervalBox) = mid.(X)
38+
mid(X::IntervalBox) = mid.(X.v)
2139

2240

2341
## set operations
2442

2543
# TODO: Update to use generator
2644
(X::IntervalBox{N,T}, Y::IntervalBox{N,T}) where {N,T} =
27-
all(X .⊆ Y)
45+
all(X.v .⊆ Y.v)
2846

2947
(X::IntervalBox{N,T}, Y::IntervalBox{N,T}) where {N,T} =
30-
IntervalBox(X .∩ Y)
48+
IntervalBox(X.v .∩ Y.v)
3149
(X::IntervalBox{N,T}, Y::IntervalBox{N,T}) where {N,T} =
32-
IntervalBox(X .∪ Y)
50+
IntervalBox(X.v .∪ Y.v)
3351

3452
#=
3553
On Julia 0.6 can now write
3654
∩{N,T}(X::IntervalBox{N,T}, Y::IntervalBox{N,T}) = IntervalBox(NTuple{N, Interval{Float64}}( (X[i] ∩ Y[i]) for i in 1:N))
3755
=#
3856

3957

40-
isempty(X::IntervalBox) = any(isempty, X)
58+
isempty(X::IntervalBox) = any(isempty, X.v)
4159

42-
diam(X::IntervalBox) = maximum(diam.(X))
60+
diam(X::IntervalBox) = maximum(diam.(X.v))
4361

44-
emptyinterval(X::IntervalBox{N,T}) where {N,T} = IntervalBox(emptyinterval.(X))
62+
emptyinterval(X::IntervalBox{N,T}) where {N,T} = IntervalBox(emptyinterval.(X.v))
4563

4664

4765
import Base
4866
×(a::Interval...) = IntervalBox(a...)
49-
×(a::Interval, b::IntervalBox) = IntervalBox(a, b...)
50-
×(a::IntervalBox, b::Interval) = IntervalBox(a..., b)
51-
×(a::IntervalBox, b::IntervalBox) = IntervalBox(a..., b...)
67+
×(a::Interval, b::IntervalBox) = IntervalBox(a, b.v...)
68+
×(a::IntervalBox, b::Interval) = IntervalBox(a.v..., b)
69+
×(a::IntervalBox, b::IntervalBox) = IntervalBox(a.v..., b.v...)
5270

5371
IntervalBox(x::Interval, ::Type{Val{n}}) where {n} = IntervalBox(SVector(ntuple(i->x, Val{n})))
5472

5573
IntervalBox(x::Interval, n::Int) = IntervalBox(x, Val{n})
74+
75+
dot(x::IntervalBox, y::IntervalBox) = dot(x.v, y.v)
76+
length(x::IntervalBox) = length(x.v)

src/multidim/multidim.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
include("intervalbox.jl")
22
include("setdiff.jl")
3+
include("arithmetic.jl")

src/multidim/setdiff.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Algorithm: Start from the total overlap (in all directions);
4343
expand each direction in turn.
4444
"""
4545
function setdiff(A::IntervalBox{N,T}, B::IntervalBox{N,T}) where {N,T}
46-
X = [labelled_setdiff(a,b) for (a, b) in zip(A, B)]
46+
X = [labelled_setdiff(a, b) for (a, b) in zip(A.v, B.v)]
4747
# ordered such that the first in each is the excluded interval
4848

4949
first = [ i[1] for i in X ]
@@ -61,7 +61,7 @@ function setdiff(A::IntervalBox{N,T}, B::IntervalBox{N,T}) where {N,T}
6161
for which in X[dimension][2:end]
6262
excluded[dimension] = which[1]
6363
push!(result_list,
64-
IntervalBox(excluded[1:dimension]..., A[dimension+1:end]...))
64+
IntervalBox(excluded[1:dimension]..., A[dimension+1:N]...))
6565
end
6666
end
6767

test/multidim_tests/multidim.jl

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
using IntervalArithmetic
22
using Base.Test
3+
using StaticArrays
34

45

56
@testset "Operations on boxes" begin
67
A = IntervalBox(1..2, 3..4)
78
B = IntervalBox(0..2, 3..6)
89

9-
@test 2*A == IntervalBox(2..4, 6..8)
10+
@test 2*A == A*2 == IntervalBox(2..4, 6..8)
11+
@test typeof(2*A) == IntervalBox{2, Float64}
1012
@test A + B == IntervalBox(1..4, 6..10)
13+
@test 2 + A == IntervalBox(3..4,5..6)
14+
@test A + 2 == IntervalBox(3..4,5..6)
15+
@test -A == IntervalBox((-2)..(-1), (-4)..(-3))
16+
@test 2 - A == IntervalBox(0..1, (-2)..(-1))
17+
@test B - 2 == IntervalBox((-2)..0, 1..4)
1118
@test dot(A, B) == @interval(9, 28)
19+
@test A .* B == IntervalBox(0..4, 9..24)
20+
@test A ./ A == IntervalBox((0.5)..2, (0.75)..(4/3))
21+
@test 1 ./ B == IntervalBox((0.5)..Inf, (1/6)..(1/3))
22+
@test B ./ 1 == B
23+
@test A .^ 2 == IntervalBox(1..4, 9..16)
24+
@test B .^ 0.5 == IntervalBox(@interval(0,sqrt(2)), @interval(sqrt(3),sqrt(6)))
1225

1326
@test A B
1427
@test A B == A
@@ -32,7 +45,17 @@ using Base.Test
3245
@test isa(Y, IntervalBox)
3346
@test length(Y) == 1
3447
@test Y == IntervalBox( (Interval(1., 2.),) )
48+
@test typeof(Y) == IntervalBox{1, Float64}
49+
end
50+
51+
@testset "Functions on boxes" begin
52+
A = IntervalBox(1..2, 3..4)
3553

54+
@test exp.(A) == IntervalBox(exp(A[1]), exp(A[2]))
55+
@test typeof(exp.(A)) == IntervalBox{2,Float64}
56+
@test log.(A) == IntervalBox(log(A[1]), log(A[2]))
57+
@test sqrt.(A) == IntervalBox(sqrt(A[1]), sqrt(A[2]))
58+
@test inv.(A) == IntervalBox(inv(A[1]), inv(A[2]))
3659
end
3760

3861
# @testset "@intervalbox tests" begin
@@ -121,3 +144,28 @@ end
121144
@test IntervalBox(1..2, 3) == IntervalBox(1..2, Val{3})
122145

123146
end
147+
148+
@testset "getindex and setindex" begin
149+
X = IntervalBox(3..4, 5..6)
150+
@test X[1] == 3..4
151+
@test X[2] == 5..6
152+
@test_throws BoundsError X[3]
153+
154+
@test setindex(X, 5..5, 2) == IntervalBox(3..4, 5..5)
155+
@test_throws BoundsError setindex(X, 5..5, 3)
156+
end
157+
158+
@testset "Iteration" begin
159+
X = IntervalBox(3..4, 5..6)
160+
Y = collect(X)
161+
@test Y == [3..4, 5..6]
162+
@test eltype(Y) == Interval{Float64}
163+
end
164+
165+
@testset "Broadcasting" begin
166+
X = IntervalBox(3..4, 5..6)
167+
168+
@test sin.(X) == IntervalBox(sin(X[1]), sin(X[2]))
169+
@test mid.(X) == SVector(mid(X[1]), mid(X[2]))
170+
@test diam.(X) == SVector(diam(X[1]), diam(X[2]))
171+
end

0 commit comments

Comments
 (0)