-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
cumsum fixes (fixes #18363 and #18336) #18364
Conversation
Also fixes #13244. |
(I thought about using |
As @andreasnoack pointed out, this does not produce the expected result for I'm conflicted on whether we should widen a sum of, say |
Okay, updated it to use the same type as |
@@ -472,12 +469,16 @@ for (f, f!, fp, op) = ((:cumsum, :cumsum!, :cumsum_pairwise!, :+), | |||
@eval function ($f!)(result::AbstractVector, v::AbstractVector) | |||
n = length(v) | |||
if n == 0; return result; end | |||
($fp)(v, result, $(op==:+ ? :(zero(first(v))) : :(one(first(v)))), first(indices(v,1)), n) | |||
li = linearindices(v) |
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.
Best would be to have n = length(li)
since that's guaranteed to work even if v
has non-1 indices.
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.
Doesn't length(v)
return the number of elements in the array regardless? Or is length(v)
equivalent to last(linearindices(v))
? The latter would seem odd to me.
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.
Ah, I see that the length
documentation says it returns "For ordered, indexable collections, the maximum index i for which getindex(collection, i) is valid."
Okay, changed it to length(li)
as you suggest. It still seems strange to me.
(Note also that this cumsum
method is only for AbstractVector
, and the length
documentation says that it "Returns the number of elements in A." for any AbstractArray
.)
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.
http://docs.julialang.org/en/latest/devdocs/offset-arrays/#background
Though if this isn't to be backported, then perhaps you could just stick with the original, since the situation with length
is just for 0.5. However, packages probably haven't started preparing for 0.6 yet, so they may not support length
yet for unconventional arrays.
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 the definition/documentation for length
should be revisited. It makes more sense to me for it to always return an element count, and have nothing to do with indices. The docs should say "returns the number of elements generated by an iterator".
…onsistent with non-empty case for size mismatches
Slightly tangential but I really think we should probably make Bool On Monday, September 5, 2016, Steven G. Johnson notifications@github.com
|
I agree with @StefanKarpinski. There really ought to be a I opened #18367 for that discussion. |
Seems like a random Travis timeout on OSX. I'll try restarting CI. (Is there a way to just restart Travis?) |
Darn it, now Travis is succeeding but one of the AppVeyor builds is timing out. These random CI failures are really frustrating. |
You can restart specific CI services through their UI. I also request that you please make a backup of travis failure logs to a gist before restarting, as restarted builds there overwrite previous logs. |
I'd much rather not widen |
@tkelman, okay, so it should just use |
I think that sounds sane. I'm not sure which corner cases the current |
|
@tkelman, the main current corner case seems to be @andreasnoack, |
Hmm, no, it looks like |
Hmm, also need to handle |
Okay, the new behavior should be more consistent with the old |
Better? |
@@ -470,14 +476,18 @@ for (f, f!, fp, op) = ((:cumsum, :cumsum!, :cumsum_pairwise!, :+), | |||
end | |||
|
|||
@eval function ($f!)(result::AbstractVector, v::AbstractVector) | |||
n = length(v) | |||
li = linearindices(v) | |||
li != linearindices(result) && throw(BoundsError()) |
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.
Should this be an DimensionMismatch
and include a helpful message about the nature of the problem?
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.
ok
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.
Great. Test needs to change too.
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.
whoops, right.
Aside from one small comment, LGTM. |
|
||
# handle sums of Vector{Bool} and similar. it would be nice to handle | ||
# any AbstractArray here, but it's not clear how that would be possible | ||
rcum_promote_type{T,N}(op, ::Type{Array{T,N}}) = Array{rcum_promote_type(op,T), N} |
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 you can do
rcum_promote_type{T}(op, ::Type{T}) = promote_eltype_op(op, T)
rcum_promote_type{T}(op, ::Type{Array{T,N}) = Array{rcum_promote_type(op, T), N}
without specializing for <:Number
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.
promote_eltype_op
gives the wrong answers for non-Number
arguments too. e.g. it gives Base.promote_eltype_op(+, Range{Int}) --> Int
when I want Range{Int}
.
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.
Yeah, that's why I left the second definition. Maybe some day, if we get triangular dispatch or something like it, that will be easier.
EDIT: I see that for Range
that won't work unless we also have something like triangular dispatch.
This is a (minor) breaking change, but the previous behavior could be argued to be buggy. Should we consider backporting this fix? |
I would say the odds of this breaking someone's code is pretty low. About the only cases that should actually break would be |
This fixes #18336 and #18363 — there were an embarrassing number of problems with
cumsum
andcumprod
for corner cases. (My fault, I think, since I wrote this routine back in #4039.)The breaking change is that
cumsum(v)
now usessimilar(v, rcum_promote_type(+, eltype(v)))
rather than the broken_cumsum_type(v)
function, wherercum_promote_type
is a new function that callspromote_op
for numbers but which leaves most other types alone. I don't think this should change any working cases forcumsum
of numeric types, but it might break some unusual user-defined types in which+
produces a different type.(The user can still control the result type manually by passing an array to
cumsum!
, however.)