-
Notifications
You must be signed in to change notification settings - Fork 71
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
Conversation
Codecov Report
@@ Coverage Diff @@
## master #185 +/- ##
=========================================
Coverage ? 82.31%
=========================================
Files ? 25
Lines ? 1227
Branches ? 0
=========================================
Hits ? 1010
Misses ? 217
Partials ? 0
Continue to review full report at Codecov.
|
Thanks @Kolaru for looking into this. I just checked in Julia 1.0 and the problem reported in #182 persists. I like your idea of introducing I think the following would allow for such an enlargement, but I haven't being able to test it in Julia 1.0. using InteractiveUtils: subtypes
const IASupportedType = Union{setdiff(subtypes(Real), [AbstractInterval])...} This would result on Another option, as @dpsanders suggested, is that |
What about a trait-like solution ? Something like struct Interval{T} where {T <: Real}
a::T
b::T
Interval{T}(::Type{Val{true}}, a::T, b::T) = new(a, b)
Interval{T}(::Type{Val{false}}, ::T, ::T) = error("Type $T not good for interval arithmetic.")
end
Interval(a::T, b::T) where {T <: Real} = Interval(Val{isGoodForIA(T)}, a, b) So to make a custom type isGoodForIA(A) = true Like that absurd intervals are never passed silently, but it can still easily be extended with arbitrary type. Also I don't think this would justifiy adding |
43a1073
to
09aa126
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the far too long delay in getting to this. I think this is very nice.
I've added some suggestions for simplifying the code.
Basically, the only place where type restrictions should be required is when actually creating an Interval
object.
src/intervals/arithmetic.jl
Outdated
@@ -447,7 +447,7 @@ function radius(a::Interval) | |||
return max(m - a.lo, a.hi - m) | |||
end | |||
|
|||
function radius(a::Interval{Rational{T}}) where T | |||
function radius(a::Interval{Rational{T}}) where {T <: Integer} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's necessary to specify T <: Integer
since that is imposed when a Rational
is created.
src/intervals/arithmetic.jl
Outdated
@@ -461,7 +461,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 <: IASupportedType} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can just leave this as where {T}
. I don't see the need to restrict the type here; the type should be restricted already when an Interval
is initially created.
src/intervals/intervals.jl
Outdated
@@ -11,52 +11,56 @@ else | |||
const validity_check = false | |||
end | |||
|
|||
const IASupportedType = Union{Integer, Rational, Irrational, Float16, Float32, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's a good idea to make a restrictive list like this. I like the trait idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept it in the latest update, for the definition of the default cases for can_bound_interval
.
src/intervals/intervals.jl
Outdated
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}(::Type{Val{true}}, a::Real, b::Real) where {T <: Real} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change to ::Val{true}
src/intervals/intervals.jl
Outdated
|
||
## Traits functions | ||
canBeIntervalBound(::Type{T}) where {T <: IASupportedType} = true | ||
canBeIntervalBound(T) = false # Default case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe canBeIntervalBound(::Type{T}) where {T} = false
src/intervals/intervals.jl
Outdated
|
||
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 <: Real} = Interval{T}(Val{canBeIntervalBound(T)}, a, b) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you can now remove the <: Real
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace by Val(can_bound_interval(T))
src/intervals/intervals.jl
Outdated
end | ||
end | ||
|
||
|
||
## Traits functions | ||
canBeIntervalBound(::Type{T}) where {T <: IASupportedType} = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to can_bound_interval
src/intervals/intervals.jl
Outdated
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 <: Real, S <: Real} = Interval(promote(a,b)...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove <: Real
|
||
## 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<:Irrational = Interval(float(a), float(b)) | ||
Interval(a::T, b::T) where {T <: Integer} = Interval(float(a), float(b)) |
There was a problem hiding this comment.
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.
src/intervals/intervals.jl
Outdated
|
||
eltype(x::Interval{T}) where T<:Real = T | ||
eltype(x::Interval{T}) where {T <: Real} = T |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove <: Real
I closed the wrong PR, sorry for this. |
What's the status here? Should we merge this? |
I need to go back to it to address your last review. I don't remember why I didn't do it earlier, but I'll do it shortly. |
09aa126
to
b4fbd97
Compare
The coverage decrease comes from the fact that |
b4fbd97
to
337ce67
Compare
This is ready (and may also help avoid some amiguity error I get in #271 when trying to have generic constructors). |
Codecov Report
@@ Coverage Diff @@
## master #185 +/- ##
==========================================
- Coverage 91.55% 91.52% -0.03%
==========================================
Files 25 25
Lines 1752 1758 +6
==========================================
+ Hits 1604 1609 +5
- Misses 148 149 +1
Continue to review full report at Codecov.
|
Fix #182. I have define a new type alias of all supported type (basically all built-in number type). Therefore this make the implementation the less generic possible, which is also the safest.
The change also somehow confuse Julia when it comes to finding the most specific method in some cases, for unknown reason.
Finally a small change in the display function to be sure to avoid an infinite recursion by using specifically the
BigFloat
constructor.