Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Stackoverflow when creating interval of intervals #185

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/IntervalArithmetic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ const Region{T} = Union{Interval{T}, IntervalBox{T}}
# These definitions has been put there because generated functions must be
# defined after all methods they use.
@generated function Interval{T}(x::Irrational) where T
res = atomic(Interval{T}, x()) # Precompute the interval
res = Interval{T}(x(), x()) # Precompute the interval
return :(return $res) # Set body of the function to return the precomputed result
end

Expand Down
2 changes: 1 addition & 1 deletion src/display.jl
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ function round_string(x::BigFloat, digits::Int, r::RoundingMode)
return repr
end

round_string(x::Real, digits::Int, r::RoundingMode) = round_string(big(x), digits, r)
round_string(x::Real, digits::Int, r::RoundingMode) = round_string(BigFloat(x), digits, r)


function basic_representation(a::Interval, format=nothing)
Expand Down
4 changes: 2 additions & 2 deletions src/intervals/arithmetic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ Return the unique interval `c` such that `b+c=a`.
See Section 12.12.5 of the IEEE-1788 Standard for
Interval Arithmetic.
"""
function cancelminus(a::Interval{T}, b::Interval{T}) where T<:Real
function cancelminus(a::Interval{T}, b::Interval{T}) where {T}
(isempty(a) && (isempty(b) || !isunbounded(b))) && return emptyinterval(T)

(isunbounded(a) || isunbounded(b) || isempty(b)) && return entireinterval(T)
Expand All @@ -547,7 +547,7 @@ function cancelminus(a::Interval{T}, b::Interval{T}) where T<:Real

return entireinterval(T)
end
cancelminus(a::Interval, b::Interval) = cancelminus(promote(a, b)...)
cancelminus(a::Interval{T}, b::Interval{S}) where {T, S} = cancelminus(promote(a, b)...)

"""
cancelplus(a, b)
Expand Down
29 changes: 17 additions & 12 deletions src/intervals/intervals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,48 @@ else
const validity_check = false
end

const IASupportedType = Union{Integer, Rational, Irrational, AbstractFloat}

abstract type AbstractInterval{T} <: Real end

struct Interval{T<:Real} <: AbstractInterval{T}
lo :: T
hi :: T

function Interval{T}(a::Real, b::Real) where T<:Real

function Interval{T}(::Val{true}, a::Real, b::Real) where {T <: Real}
if validity_check

if is_valid_interval(a, b)
new(a, b)

else
@warn "Invalid input, empty interval is returned"
return new(T(Inf), T(-Inf))
end

end

new(a, b)

end
end

eltype(::Interval{T}) where T = T

## Traits functions
can_bound_interval(::Type{T}) where {T} = false # Default case
can_bound_interval(::Type{T}) where {T <: IASupportedType} = true

## Outer constructors
function Interval{T}(::Val{false}, ::Real, ::Real) where {T <: Real}
throw(ArgumentError("Type $T is not suitable to construct an interval. If it is a custom type and should be accepted, make sure to define `can_bound_interval(::Type{$T}) = true`"))
end

Interval(a::T, b::T) where T<:Real = Interval{T}(a, b)
Interval(a::T) where T<:Real = Interval(a, a)
Interval{T}(a::Real, b::Real) where {T} = Interval{T}(Val(can_bound_interval(T)), a, b)
Interval(a::T, b::T) where {T <: Real} = Interval{T}(Val(can_bound_interval(T)), a, b)
Interval(a::T) where {T <: Real} = Interval(a, a)
Interval(a::Tuple) = Interval(a...)
Interval(a::T, b::S) where {T<:Real, S<:Real} = Interval(promote(a,b)...)
Interval(a::T, b::S) where {T, S} = Interval(promote(a,b)...)

## Concrete constructors for Interval, to effectively deal only with Float64,
# BigFloat or Rational{Integer} intervals.
Interval(a::T, b::T) where T<:Integer = Interval(float(a), float(b))
Interval(a::T, b::T) where {T <: Integer} = Interval(float(a), float(b))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these <: can now be removed.


# Constructors for Irrational
# Single argument Irrational constructor are in IntervalArithmetic.jl
Expand All @@ -63,9 +68,9 @@ Interval(a::Real, b::Irrational) = Interval{Float64}(a, b)
Interval(x::Interval) = x
Interval(x::Complex) = Interval(real(x)) + im*Interval(imag(x))

Interval{T}(x) where T = Interval(convert(T, x))
Interval{T}(x) where {T} = Interval(convert(T, x))

Interval{T}(x::Interval) where T = atomic(Interval{T}, x)
Interval{T}(x::Interval) where {T} = atomic(Interval{T}, x)

size(x::Interval) = (1,)

Expand Down
5 changes: 5 additions & 0 deletions test/interval_tests/construction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ const eeuler = Base.MathConstants.e
@test_logs (:warn,) @test isempty(interval(-Inf, -Inf))
@test_logs (:warn,) @test isempty(interval(Inf, Inf))

# Disallowed creation of interval witha a or b an interval
@test_throws ArgumentError Interval(1, 1..2)
@test_throws ArgumentError Interval(1..2, 1)
@test_throws ArgumentError Interval(1..2, 1..2)

# Conversion to Interval without type
@test convert(Interval, 1) == Interval(1.0)
@test convert(Interval, pi) == @interval(pi)
Expand Down