Simplified version of mod(x::Interval, y::Real)#525
Conversation
|
Btw, I've also found that julia> using IntervalArithmetic
julia> function mod178(X::Interval, a::Interval)
division = X / a
fl = floor(division)
if fl.lo < fl.hi
return 0..(a.hi)
end
return (division - fl) * a
end
mod178 (generic function with 1 method)
julia> mod178(1..1, 0.9..1.1)
[0, 1.10001]
julia> maximum(mod(1, x) for x in 0.9:0.01:1.1)
1.0 |
Codecov ReportPatch coverage:
❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more. Additional details and impacted files@@ Coverage Diff @@
## master #525 +/- ##
==========================================
+ Coverage 90.36% 90.96% +0.59%
==========================================
Files 25 25
Lines 1796 1837 +41
==========================================
+ Hits 1623 1671 +48
+ Misses 173 166 -7
☔ View full report in Codecov by Sentry. |
Co-authored-by: lucaferranti <49938764+lucaferranti@users.noreply.github.com>
| Calculate `x mod y` where `x` is an interval and `y` is a positive divisor. | ||
| """ | ||
| function mod(x::Interval, y::Real) | ||
| @assert y > zero(y) "modulo is currently implemented only for a positive divisor." |
There was a problem hiding this comment.
Is it possible to extend this to have strictly negative y? I understand that having 0 ∈ y complicates things....
There was a problem hiding this comment.
Updated for strictly negative divisor. Hope its correct.
There was a problem hiding this comment.
The implementation seems to me correct if we have y::AbstractFloat (perhaps also including Rationals, but let me forget about them now), which corresponds to the tests.
However, if y::Interval (and we have Interval <: Real) then there this function throws errors: e.g., try mod(1..2, 1..2), which I think should return Interval(0.0, 2.0). In this case things are subtle, because y != zero(y) is true for [-1, 1], but that interval is not strictly positive or negative. Also, Interval(zero(y), y) causes the error mentioned above. I guess this is the reason that mod has two methods in #178.
My suggestion is either restrict y::AbstractFloat, or include a new method where y::Interval.
There was a problem hiding this comment.
This is my mistake. My intention was to constrain y NOT to be Interval. I've not realized 1..3 isa Real -> true. However, If I constraint it to y::AbstractFloat it does not accept integers for example because 1 isa AbstractFloat -> false, right?
There was a problem hiding this comment.
you could do Union{AbstractFloat, Integer} to accept both integers and floats but no intervals (similar to add rationals and irrationals).
Can the method be generalized to the case of y interval?
There was a problem hiding this comment.
actually forget about the union, a better suggestion would be to define
mod(x::Real, y::Interval) = throw(ArgumentError("mod not defined for second argument interval"))
mod(x::Interval, y::Interval) = throw(ArgumentError("mod not defined for second argument interval"))There was a problem hiding this comment.
mod can indeed be generalized for y::Interval. It's tricky with respect of having zero within the interval, which is part of the reason I was suggesting to have either a strictly positive or negative y. Actually, a motivating example would be to have y::Irrational, or actually any (mathematical) real number which is not exactly representable as a Float64. Note that #178 includes such an implementation, though it does not include the restriction of strictly positive/negative intervals. The subtleties related to zero at the end are related to the division: y appears in the denominator.
There was a problem hiding this comment.
I unresolved this conversation, so it is easy to track the discussion...
There was a problem hiding this comment.
fwiw in octave
>> mod(infsup(-3, 2), infsup(-1, 0.5))
ans = [-1, +0.5]
>> mod(infsup(-3, 2), infsup(0, 0))
ans = [Empty]
>> mod(infsup(-3, 2), infsup(0, 3))
ans = [0, 3]
>> mod(infsup(-3, 2), infsup(1, 3))
ans = [0, 3]
>> mod(infsup(-3, 2), infsup(-3, 2))
ans = [-3, +2]
| Calculate `x::Interval mod y::Real`, limited by `y != 0`. | ||
| """ | ||
| function mod(x::Interval, y::Real) | ||
| @assert y != zero(y) """mod(x::Interval, y::Real) |
There was a problem hiding this comment.
an alternative would be to return an empty interval, I think this would be more conformant with the IEEE standard behavior, e.g.
julia> sqrt(-1.. -1)
∅
julia> log(-2.. -1)
∅There was a problem hiding this comment.
Or we can define mod(a..b, 0) == 0..0 ⊇ ∅ as Wolfram says
https://www.wolframalpha.com/input?i=limit+x-%3E0%2B+mod%281%2C+x%29
Consequently, for 0 ∈ y, we can define smth like mod(x,y) = union(mod(x,(y.lo..y.lo/3)), mod(x, (y.hi/3)..(y.hi))) because the maximum value needs to by in (y.hi/2)..(y.hi)
There was a problem hiding this comment.
I propose to solve this in some future PR, and move the discussion to #129, to keep track once this PR merged.
There was a problem hiding this comment.
Or we can define
mod(a..b, 0) == 0..0 ⊇ ∅as Wolfram says https://www.wolframalpha.com/input?i=limit+x-%3E0%2B+mod%281%2C+x%29
Julia (and Wolfram) return NaN (undefined) for mod(3.2, 0.0), which makes sense due to the division in the algorithm.
Consequently, for
0 ∈ y, we can define smth likemod(x,y) = union(mod(x,(y.lo..y.lo/3)), mod(x, (y.hi/3)..(y.hi)))because the maximum value needs to by in(y.hi/2)..(y.hi)
This idea is interesting, and reminds me a little bit what we have for extended_div. That certainly should be addressed in another PR. Yet, I think for (mathematical) reals, mod(x,y) is a number in the interval [0,y] for y>0, or [y, 0] if y<0, isn't it?
From the range of mod(x,y) for real y, then for a strictly positive interval y, we should return [0, sup(y)], or if it is strictly negative [inf(y), 0]. If 0 ∈ y, we should return the hull of these intervals.
There was a problem hiding this comment.
I think my last comment corresponds to these results... Or not?
|
Sorry for the extended delay. Since all tests are passing and all discussions are passing, I am merging. Thanks a lot for your contribution ! |
commit 1c0522f Merge: 4c239d5 ee93bd4 Author: Benoît Richard <kolaru@hotmail.com> Date: Sun Jul 23 23:13:48 2023 +0200 Merge pull request #569 from vaerksted/master fix typos commit ee93bd4 Author: spaette <spaette@gmx.com> Date: Sat Jul 22 12:11:01 2023 -0500 typos commit 4c239d5 Author: Benoît Richard <kolaru@hotmail.com> Date: Tue Jul 4 00:35:20 2023 +0200 Bump version commit 249040d Merge: 4404658 7bef23e Author: Benoît Richard <kolaru@hotmail.com> Date: Tue Jul 4 00:34:13 2023 +0200 Merge pull request #525 from petvana/simplified-mod Simplified version of mod(x::Interval, y::Real) commit 4404658 Author: Benoît Richard <kolaru@hotmail.com> Date: Wed Jun 14 14:03:14 2023 +0200 Bump version for release commit 7bef23e Author: Petr Vana <petvana@centrum.cz> Date: Fri May 27 11:11:53 2022 +0200 Cleanup commit f9f4733 Author: Petr Vana <petvana@centrum.cz> Date: Fri May 27 11:10:05 2022 +0200 Throw ArgumentError for Interval divisor for mod commit 6fdc809 Merge: 439723f d2603d6 Author: Petr Vana <petvana@centrum.cz> Date: Fri May 27 11:01:43 2022 +0200 Merge branch 'simplified-mod' of github.com:petvana/IntervalArithmetic.jl into simplified-mod commit 439723f Author: Petr Vana <petvana@centrum.cz> Date: Fri May 27 11:01:27 2022 +0200 Disable divisor for mod to be an interval commit d2603d6 Author: Petr Vana <vanapet1@fel.cvut.cz> Date: Thu May 26 11:34:04 2022 +0200 Update docs commit 45abc46 Author: Petr Vana <vanapet1@fel.cvut.cz> Date: Thu May 26 11:30:14 2022 +0200 Implementation for strictly negative divisors for mod commit ff47910 Author: Petr Vana <vanapet1@fel.cvut.cz> Date: Thu May 26 11:11:35 2022 +0200 Add todo for mod with between two intervals commit ea00b23 Author: Petr Vana <petvana@centrum.cz> Date: Wed May 25 19:59:30 2022 +0200 Imrpove test coverage + use zero() commit b56f4be Author: Petr Vana <vanapet1@fel.cvut.cz> Date: Wed May 25 13:44:24 2022 +0200 Use ⊇ operator commit d23df89 Author: Petr Vana <petvana@centrum.cz> Date: Tue May 24 21:13:53 2022 +0200 Update src/intervals/functions.jl Co-authored-by: lucaferranti <49938764+lucaferranti@users.noreply.github.com> commit 153d749 Author: Petr Vana <petvana@centrum.cz> Date: Tue May 24 20:27:51 2022 +0200 Improve testing commit fea1b34 Author: Petr Vana <petvana@centrum.cz> Date: Tue May 24 20:10:05 2022 +0200 Introduce simplified version of mod
commit 1c0522f Merge: 4c239d5 ee93bd4 Author: Benoît Richard <kolaru@hotmail.com> Date: Sun Jul 23 23:13:48 2023 +0200 Merge pull request #569 from vaerksted/master fix typos commit ee93bd4 Author: spaette <spaette@gmx.com> Date: Sat Jul 22 12:11:01 2023 -0500 typos commit 4c239d5 Author: Benoît Richard <kolaru@hotmail.com> Date: Tue Jul 4 00:35:20 2023 +0200 Bump version commit 249040d Merge: 4404658 7bef23e Author: Benoît Richard <kolaru@hotmail.com> Date: Tue Jul 4 00:34:13 2023 +0200 Merge pull request #525 from petvana/simplified-mod Simplified version of mod(x::Interval, y::Real) commit 4404658 Author: Benoît Richard <kolaru@hotmail.com> Date: Wed Jun 14 14:03:14 2023 +0200 Bump version for release commit 7bef23e Author: Petr Vana <petvana@centrum.cz> Date: Fri May 27 11:11:53 2022 +0200 Cleanup commit f9f4733 Author: Petr Vana <petvana@centrum.cz> Date: Fri May 27 11:10:05 2022 +0200 Throw ArgumentError for Interval divisor for mod commit 6fdc809 Merge: 439723f d2603d6 Author: Petr Vana <petvana@centrum.cz> Date: Fri May 27 11:01:43 2022 +0200 Merge branch 'simplified-mod' of github.com:petvana/IntervalArithmetic.jl into simplified-mod commit 439723f Author: Petr Vana <petvana@centrum.cz> Date: Fri May 27 11:01:27 2022 +0200 Disable divisor for mod to be an interval commit d2603d6 Author: Petr Vana <vanapet1@fel.cvut.cz> Date: Thu May 26 11:34:04 2022 +0200 Update docs commit 45abc46 Author: Petr Vana <vanapet1@fel.cvut.cz> Date: Thu May 26 11:30:14 2022 +0200 Implementation for strictly negative divisors for mod commit ff47910 Author: Petr Vana <vanapet1@fel.cvut.cz> Date: Thu May 26 11:11:35 2022 +0200 Add todo for mod with between two intervals commit ea00b23 Author: Petr Vana <petvana@centrum.cz> Date: Wed May 25 19:59:30 2022 +0200 Imrpove test coverage + use zero() commit b56f4be Author: Petr Vana <vanapet1@fel.cvut.cz> Date: Wed May 25 13:44:24 2022 +0200 Use ⊇ operator commit d23df89 Author: Petr Vana <petvana@centrum.cz> Date: Tue May 24 21:13:53 2022 +0200 Update src/intervals/functions.jl Co-authored-by: lucaferranti <49938764+lucaferranti@users.noreply.github.com> commit 153d749 Author: Petr Vana <petvana@centrum.cz> Date: Tue May 24 20:27:51 2022 +0200 Improve testing commit fea1b34 Author: Petr Vana <petvana@centrum.cz> Date: Tue May 24 20:10:05 2022 +0200 Introduce simplified version of mod
This PR cherry-picks
mod(x::Interval, y::Real)from #178 because it seems to be the most useful case (at least for me), and also easiest to implement.Cc: @dpsanders @lbenet
fixes #129