diff --git a/src/IntervalBoxes.jl b/src/IntervalBoxes.jl index 6b4c124..6c16906 100644 --- a/src/IntervalBoxes.jl +++ b/src/IntervalBoxes.jl @@ -6,7 +6,7 @@ using StaticArrays import IntervalArithmetic: emptyinterval, bisect, diam, hull, mid, mince import Base: - ∩, ∪, +, -, *, /, ==, !=, eltype, length, size, getindex, setindex, iterate, + ∩, ∪, ⊆, +, -, *, /, ==, !=, eltype, length, size, getindex, setindex, iterate, broadcasted, setdiff, big export IntervalBox diff --git a/src/intervalbox.jl b/src/intervalbox.jl index 7b56b8f..ffae9f2 100644 --- a/src/intervalbox.jl +++ b/src/intervalbox.jl @@ -80,7 +80,7 @@ big(X::IntervalBox) = big.(X) ## set operations -⊆(X::IntervalBox{N}, Y::IntervalBox{N}) where {N} = all(issubset_interval.(X.v, Y.v)) +⊆(X::IntervalBox{N}, Y::IntervalBox{N}) where {N} = all(issubset_interval.(X, Y)) ∩(X::IntervalBox{N}, Y::IntervalBox{N}) where {N} = IntervalBox(intersect_interval.(X.v, Y.v)) @@ -91,10 +91,10 @@ big(X::IntervalBox) = big.(X) ∈(X, Y::IntervalBox{N,T}) where {N,T} = throw(ArgumentError("$X ∈ $Y is not defined")) # mixing intervals with one-dimensional interval boxes -for op in (:⊆, :⊂, :⊃, :∩, :∪) - @eval $(op)(a::Interval, X::IntervalBox{1}) = $(op)(a, first(X)) - @eval $(op)(X::IntervalBox{1}, a::Interval) = $(op)(first(X), a) -end +# for op in (:⊆, :⊂, :⊃, :∩, :∪) +# @eval $(op)(a::Interval, X::IntervalBox{1}) = $(op)(a, first(X)) +# @eval $(op)(X::IntervalBox{1}, a::Interval) = $(op)(first(X), a) +# end isempty(X::IntervalBox) = any(isempty_interval, X.v) diff --git a/src/setdiff.jl b/src/setdiff.jl index a96664d..979950f 100644 --- a/src/setdiff.jl +++ b/src/setdiff.jl @@ -1,20 +1,32 @@ +_make_interval(::Type{Interval{T}}, x::T, y::T) where {T} = interval(x, y, trv) +_make_interval(::Type{BareInterval{T}}, x::T, y::T) where {T} = bareinterval(x, y) + """ _setdiff(x::Interval{T}, y::Interval{T}) -Computes the set difference x\\y and always returns a tuple of two intervals. +Computes the set difference `x \\ y` and returns a tuple of two intervals. If the set difference is only one interval or is empty, then the returned tuple contains 1 or 2 empty intervals. """ -function _setdiff(x::BareInterval{T}, y::BareInterval{T}) where T +function _setdiff(x::I, y::I) where {T, I <: IntervalType{T}} + + if x isa Interval + x = IntervalArithmetic.setdecoration(x, trv) + y = IntervalArithmetic.setdecoration(y, trv) + end + intersection = intersect_interval(x, y) isempty_interval(intersection) && return (x, emptyinterval(x)) isequal_interval(intersection, x) && return (emptyinterval(x), emptyinterval(x)) # x is subset of y; setdiff is empty - inf(x) == inf(intersection) && return (bareinterval(sup(intersection), sup(x)), emptyinterval(x)) - sup(x) == sup(intersection) && return (bareinterval(inf(x), inf(intersection)), emptyinterval(x)) - - return (bareinterval(inf(x), inf(y)), bareinterval(sup(y), sup(x))) + if inf(x) == inf(intersection) + return (_make_interval(I, sup(intersection), sup(x)), emptyinterval(x)) + elseif sup(x) == sup(intersection) + return (_make_interval(I, inf(x), inf(intersection)), emptyinterval(x)) + else + return (_make_interval(I, inf(x), inf(y)), _make_interval(I, sup(y), sup(x))) + end end @@ -33,14 +45,14 @@ function setdiff(A::IntervalBox{N,T}, B::IntervalBox{N,T}) where {N,T} intersection = A ∩ B isempty(intersection) && return [A] - result_list = fill(IntervalBox(emptyinterval.(A)), 2 * N) + result_list = fill(emptyinterval.(A), 2 * N) offset = 0 x = A.v @inbounds for i = 1:N tmp = _setdiff(A[i], B[i]) @inbounds for j = 1:2 x = setindex(x, tmp[j], i) - result_list[offset+j] = IntervalBox{N, T}(x) + result_list[offset+j] = IntervalBox(x) end offset += 2 x = setindex(x, intersection[i], i) diff --git a/test/display.jl b/test/display.jl index 54a39b1..70fcc17 100644 --- a/test/display.jl +++ b/test/display.jl @@ -1,14 +1,12 @@ using IntervalArithmetic using Test -let x, b - @testset "IntervalBox" begin setdisplay(:standard, sigfigs=6) X = IntervalBox(1..2, 3..4) - @test typeof(X) == IntervalBox{2,Float64} + @test typeof(X) == IntervalBox{2,Float64,Interval{Float64}} @test string(X) == "[1.0, 2.0] × [3.0, 4.0]" s = sprint(show, MIME("text/plain"), X) diff --git a/test/multidim.jl b/test/multidim.jl index 478124b..38e6722 100644 --- a/test/multidim.jl +++ b/test/multidim.jl @@ -1,6 +1,8 @@ -using IntervalArithmetic +using IntervalArithmetic, IntervalArithmetic.Symbols using StaticArrays +dot(x, v) = sum(x .* v) + using Test @testset "Operations on boxes" begin @@ -9,7 +11,7 @@ using Test s = @SVector [1, 2] @test 2*A == A*2 == IntervalBox(2..4, 6..8) - @test typeof(2*A) == IntervalBox{2, Float64} + @test typeof(2*A) == IntervalBox{2, Float64, Interval{Float64}} @test A + B == IntervalBox(1..4, 6..10) @test A + B.v == IntervalBox(1..4, 6..10) @test A.v + B == IntervalBox(1..4, 6..10) @@ -23,15 +25,16 @@ using Test @test -A == IntervalBox((-2)..(-1), (-4)..(-3)) @test 2 - A == IntervalBox(0..1, (-2)..(-1)) @test B - 2 == IntervalBox((-2)..0, 1..4) - @test dot(A, B) == interval(9, 28) - @test dot(A, B.v) == interval(9, 28) - @test dot(A.v, B) == interval(9, 28) + @test isequal_interval(dot(A, B), interval(9, 28)) + @test isequal_interval(dot(A, B.v), interval(9, 28)) + @test isequal_interval(dot(A.v, B), interval(9, 28)) @test A .* B == IntervalBox(0..4, 9..24) @test A ./ A == IntervalBox((0.5)..2, (0.75)..(4//3)) @test 1 ./ B == IntervalBox((0.5)..Inf, (1//6)..(1//3)) @test B ./ 1 == B @test A .^ 2 == IntervalBox(1..4, 9..16) - @test sqrt.(B) == IntervalBox(@interval(Float64, 0, sqrt(2)), @interval(Float64, sqrt(3), sqrt(6))) + @test sqrt.(B) == + IntervalBox(@interval(Float64, 0, sqrt(2)), @interval(Float64, sqrt(3), sqrt(6))) for (A, B) in ( (A, B), @@ -99,7 +102,7 @@ using Test @test isa(Y, IntervalBox) @test length(Y) == 1 @test Y == IntervalBox( (interval(1., 2.),) ) - @test typeof(Y) == IntervalBox{1, Float64} + @test typeof(Y) == IntervalBox{1, Float64, Interval{Float64}} end @testset "Functions on boxes" begin @@ -113,42 +116,47 @@ end end +set_equal(S1, S2) = all(Set(bareinterval.(S1)) .== Set(bareinterval.(S2))) + @testset "setdiff for IntervalBox" begin X = IntervalBox(2..4, 3..5) Y = IntervalBox(3..5, 4..6) - @test Set(setdiff(X, Y)) == Set([ IntervalBox(3..4, 3..4), - IntervalBox(2..3, 3..5) ]) - @test Set(setdiff(X.v, Y)) == Set([ IntervalBox(3..4, 3..4), - IntervalBox(2..3, 3..5) ]) + result = [ IntervalBox(3..4, 3..4), + IntervalBox(2..3, 3..5) ] + + @test set_equal(setdiff(X, Y), result) - @test Set(setdiff(X, Y.v)) == Set([ IntervalBox(3..4, 3..4), - IntervalBox(2..3, 3..5) ]) + @test set_equal(setdiff(X.v, Y), result) + + @test set_equal(setdiff(X, Y.v), result) X = IntervalBox(2..5, 3..6) Y = IntervalBox(-10..10, 4..5) - @test Set(setdiff(X, Y)) == Set([ IntervalBox(2..5, 3..4), - IntervalBox(2..5, 5..6) ]) + @test set_equal(setdiff(X, Y), [ IntervalBox(2..5, 3..4), + IntervalBox(2..5, 5..6) ]) X = IntervalBox(2..5, 3..6) Y = IntervalBox(4..6, 4..5) - @test Set(setdiff(X, Y)) == Set([ IntervalBox(4..5, 3..4), - IntervalBox(4..5, 5..6), - IntervalBox(2..4, 3..6) ]) + @test set_equal(setdiff(X, Y), + [ IntervalBox(4..5, 3..4), + IntervalBox(4..5, 5..6), + IntervalBox(2..4, 3..6) ]) X = IntervalBox(2..5, 3..6) Y = IntervalBox(3..4, 4..5) - @test Set(setdiff(X, Y)) == Set([ IntervalBox(3..4, 3..4), - IntervalBox(3..4, 5..6), - IntervalBox(2..3, 3..6), - IntervalBox(4..5, 3..6) ]) + @test set_equal(setdiff(X, Y), + [ IntervalBox(3..4, 3..4), + IntervalBox(3..4, 5..6), + IntervalBox(2..3, 3..6), + IntervalBox(4..5, 3..6) ]) X = IntervalBox(2..5, 3..6) Y = IntervalBox(2..4, 10..20) - @test setdiff(X, Y) == typeof(X)[X] + @test setdiff(X, Y) == [X] X = IntervalBox(2..5, 3..6) @@ -158,20 +166,22 @@ end X = IntervalBox(1..4, 3..6, 7..10) Y = IntervalBox(2..3, 4..5, 8..9) - @test Set(setdiff(X, Y)) == Set([ IntervalBox(2..3, 4..5, 7..8), - IntervalBox(2..3, 4..5, 9..10), - IntervalBox(2..3, 3..4, 7..10), - IntervalBox(2..3, 5..6, 7..10), - IntervalBox(1..2, 3..6, 7..10), - IntervalBox(3..4, 3..6, 7..10) ]) + @test set_equal(setdiff(X, Y), + [ IntervalBox(2..3, 4..5, 7..8), + IntervalBox(2..3, 4..5, 9..10), + IntervalBox(2..3, 3..4, 7..10), + IntervalBox(2..3, 5..6, 7..10), + IntervalBox(1..2, 3..6, 7..10), + IntervalBox(3..4, 3..6, 7..10) ]) X = IntervalBox(-Inf..Inf, 1..2) Y = IntervalBox(1..2, -1..1.5) - @test Set(setdiff(X, Y)) == Set([IntervalBox(-Inf..1, 1..2), - IntervalBox(2..Inf, 1..2), - IntervalBox(1..2, 1.5..2)]) + @test set_equal(setdiff(X, Y), + [IntervalBox(-Inf..1, 1..2), + IntervalBox(2..Inf, 1..2), + IntervalBox(1..2, 1.5..2)]) end @testset "mid, diam, × for IntervalBox" begin @@ -245,7 +255,7 @@ end X = IntervalBox(3..4, 5..6) Y = collect(X) @test all(isequal_interval.(Y, [bareinterval(3, 4), bareinterval(5, 6)])) - @test eltype(Y) == BareInterval{Float64} + @test eltype(Y) == Interval{Float64} end @testset "Broadcasting" begin @@ -341,4 +351,4 @@ end # @test symmetric_box(2, Float64) === IntervalBox(-1 .. 1, 2) # end -end +# end