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

Unbounded interval support #104

Merged
merged 24 commits into from
Jun 23, 2020
Merged

Unbounded interval support #104

merged 24 commits into from
Jun 23, 2020

Conversation

omus
Copy link
Collaborator

@omus omus commented Jun 10, 2020

Using the parametric bounds interface in #102 this PR adds the fundamentals for constructing and interacting with unbounded intervals.

Intervals with unbounded endpoints can be constructed by using nothing as a placeholder (e.g. Interval(nothing, 2) creates the interval (,2]). Explicitly stating the bound type requires that when supplying nothing that the respectively stated bound type is Unbounded (e.g. Interval{Unbounded,Open}(nothing, 3) creates (,3) but Interval{Open,Open}(nothing, 3) and Interval{Unbounded,Unbounded}(nothing, 3) both raise MethodErrors).

As for the actual implementation for Interval{T} where T is the element type we always store values of type T and never store Nothing. Doing this avoids using a union type which would result in Interval no longer being a bits type. However, using the first or last function on an unbounded endpoint does now return nothing.

The current implementation has span throw an exception on unbounded intervals as discussed in #89 (comment).

@omus omus changed the title Core unbounded interval support WIP: Core unbounded interval support Jun 10, 2020
@codecov
Copy link

codecov bot commented Jun 10, 2020

Codecov Report

Merging #104 into master will increase coverage by 2.34%.
The diff coverage is 94.02%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #104      +/-   ##
==========================================
+ Coverage   69.94%   72.28%   +2.34%     
==========================================
  Files           8        8              
  Lines         376      415      +39     
==========================================
+ Hits          263      300      +37     
- Misses        113      115       +2     
Impacted Files Coverage Δ
src/Intervals.jl 100.00% <ø> (ø)
src/plotting.jl 94.11% <0.00%> (ø)
src/interval.jl 96.00% <93.54%> (-1.20%) ⬇️
src/endpoint.jl 94.73% <95.00%> (+1.18%) ⬆️
src/anchoredinterval.jl 98.57% <100.00%> (+0.35%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 78b125a...b055421. Read the comment docs.

src/anchoredinterval.jl Outdated Show resolved Hide resolved
@@ -246,6 +266,8 @@ function Base.isempty(interval::AnchoredInterval{P,T}) where {P,T}
return P == zero(P) && !isclosed(interval)
end

# TODO: Not required but should be addressed
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Optimized intersect for AnchoredIntervals. This function may need to be dropped as it it may no longer possible to return an AnchoredInterval for unbounded results here. I need to think about this more.

@omus omus force-pushed the cv/parametric-bounds branch 2 times, most recently from 88f26f6 to 70443cb Compare June 11, 2020 18:53
@omus omus force-pushed the cv/parametric-bounds branch 2 times, most recently from a59deb6 to f24a406 Compare June 12, 2020 05:16
Base automatically changed from cv/parametric-bounds to master June 12, 2020 12:33
@omus omus changed the title WIP: Core unbounded interval support Unbounded interval support Jun 12, 2020
@omus
Copy link
Collaborator Author

omus commented Jun 12, 2020

Rebased now that #102 has been merged.

src/anchoredinterval.jl Outdated Show resolved Hide resolved
src/endpoint.jl Outdated Show resolved Hide resolved
@@ -60,6 +60,17 @@ See also: [`Interval`](@ref), [`HE`](@ref), [`HB`](@ref)
"""
struct AnchoredInterval{P, T, L <: Bound, R <: Bound} <: AbstractInterval{T,L,R}
anchor::T

function AnchoredInterval{P,T,L,R}(anchor::T) where {P, T, L <: Bound, R <: Bound}
if P < zero(P) && R === Unbounded || P > zero(P) && L === Unbounded
Copy link
Member

Choose a reason for hiding this comment

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

Should we really include support for unbounded AnchoredIntervals? Do you expect people to pass infinite periods? I think it makes sense to restrict AnchoredIntervals to finite P.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A very valid question. Just because we can support it doesn't mean we should. I'll give that some thought

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

One argument for keeping this is that removing Unbounded support doesn't stop people from using infinite periods. We'd have to add checks to disable that as well

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thinking about this more I think support for unbounded and infinity should be consistent. If we do want to remove unbounded support entirely from AnchoredInterval we should also remove support for infinity.

My rational in why these go together is that I was planning on defining equality between infinite and unbounded intervals such that [∞,x] == (,x]. Not having unbounded support but having infinity support seems wrong to me considering this.

Copy link
Member

Choose a reason for hiding this comment

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

Thinking about this more I think support for unbounded and infinity should be consistent.

Yeah I do agree.

Okay, I can imagine wanting this rather than just using Interval I guess. But it's hard to imagine why you'd want an AnchoredInterval with infinity as part of the type.

Copy link
Member

Choose a reason for hiding this comment

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

Okay, I'm okay with keeping this functionality. But a MethodError hurts readability for the error, since the user cannot see from the type signature why this is wrong. I think this should be a different type of error.

One way to keep it a MethodError would be to add yet another type parameter that's just the sign of the period, then all the relevant information would be available for dispatch.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll make it an argument error. Not entirely accurate but better

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

More thoughts on this: #104 (comment)

src/anchoredinterval.jl Outdated Show resolved Hide resolved
@omus
Copy link
Collaborator Author

omus commented Jun 12, 2020

In reviewing the code again and taking this conversation into consideration. I've noticed that there are some cases with AnchoredIntervalwhere non-finite values are allowed as the value for the anchor endpoint. The reason this is problematic is for the same reason we don't allow the anchor endpoint to be unbounded: it makes it impossible to calculate the other endpoint.

I've unfortunately run out of time to work on this and ensure the problem is solved correctly so I'll be holding off on merging this PR. I do believe the unbounded support for the Interval type is fully functional at this time.

end

_isfinite(x) = iszero(x - x)
_isfinite(x::Real) = Base.isfinite(x)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm attempting to get this functionality added to base: JuliaLang/julia#36380

src/docstrings.jl Outdated Show resolved Hide resolved
src/docstrings.jl Outdated Show resolved Hide resolved
@@ -3,7 +3,8 @@ interval_markers(L::Type{<:Bound}, R::Type{<:Bound}) = interval_marker.([L, R])
interval_marker(x::Type{Closed}) = :vline
interval_marker(x::Type{Open}) = :none

@recipe function f(xs::AbstractVector{<:AbstractInterval{T}}, ys) where T
# TODO: Add support for plotting unbounded intervals
Copy link
Contributor

Choose a reason for hiding this comment

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

Open an issue and add to this comment?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, thanks. I did look into this and it got complicated quickly

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@nicoleepp nicoleepp left a comment

Choose a reason for hiding this comment

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

LGTM

@omus
Copy link
Collaborator Author

omus commented Jun 23, 2020

Rebased to apply documentation fixups and fixed typo in commit message. Just waiting on CI then will merge.

@omus omus merged commit 153ce03 into master Jun 23, 2020
@omus omus deleted the cv/unbounded-parametric branch June 23, 2020 19:39
@omus omus mentioned this pull request Aug 14, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants