-
-
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
Loosen signature for repeat() #14082
Conversation
adjust the rst signature to be consistent with your change, then run |
Pass an empty tuple as `outer` (or any other empty collection, which is equivalent | ||
to a tuple of ones of length `ndims(a)`) to use only inner repetitions. | ||
|
||
Examples: |
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.
these should probably be doctests
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.
Right.
I personally think keyword arguments are clearer than positional. Is this working around an inference limitation that will be fixed soonish? |
Thanks, but I can't get it to work. Should the signature be the one in the code or in the doc? (Either way, it doesn't work...) Regarding keyword vs. positional arguments, @simonster noted on the issue that inference would be possible, but I've not been able to get it to work for now. |
d4147f7
to
29a44ad
Compare
I managed to get the docs to work, I hadn't rebuilt Julia correctly before updating them. I've also added doctests. |
Can somebody comment about the possibility to infer the return type, now or in the future? Anybody else opposed to using positional arguments (which appeared to be the consensus on #12953 -- but I'm fine with either)? |
The key is to infer the length of the created array's size tuple: function rpt{N}(A::AbstractArray, outer::NTuple{N,Int})
sz = rptsz(A, outer)
Arpt = Array(eltype(A), sz)
...
end This is pretty easy to write using generated functions, because in a generated function you can do things like rptsz(A, ::Tuple{}) = size(A)
rptsz(A, outer::Tuple) = fill_length((), _rptsz((), A, outer), size(A))
# Build up the sz tuple so that we've consumed all elements of outer
@inline _rptsz{N}(sz::NTuple{N}, A::AbstractArray, ::Tuple{}) = sz
@inline _rptsz{N}(sz::NTuple{N}, A::AbstractArray, outer) = _rptsz((sz..., outer[1]*size(A,N+1)), A, Base.tail(outer))
# Take the preferred tuple, filling in with elements of default if it is longer
@inline fill_length(out, preferred, default) = fill_length((out..., preferred[1]), Base.tail(preferred), Base.tail(default))
@inline fill_length(out, ::Tuple{}, ::Tuple{}) = out
@inline fill_length(out, preferred, ::Tuple{}) = (out..., preferred...)
@inline fill_length(out, ::Tuple{}, default) = (out..., default...) All of those Demo: julia> using Base.Test
julia> @inferred(rptsz(zeros(2,2), ()))
(2,2)
julia> @inferred(rptsz(zeros(2,2), (5,)))
(10,2)
julia> @inferred(rptsz(zeros(2,2), (5,3)))
(10,6)
julia> @inferred(rptsz(zeros(2,2), (5,3,2)))
(10,6,2) |
In case it's not obvious from the code, the way this works is by progressively peeling off the first element of corresponding tuples. You start with |
Thanks, Tim! So it looks like moving to positional arguments is worth it. Is everybody OK with merging this? |
To make sure it's clear to everyone, this version produces a result that's still not inferrable, but it will be easier to get there. If you'd like, we could merge this and then I can polish up the code above. |
Fine with me. Will merge soon. |
That doesn't really answer the question of whether the same performance would eventually be achievable with keyword arguments, does it? This seems like a step backwards on the API. |
The broader issue about whether keyword arguments will be taken into account for type inference is indeed crucial here. All I can say is that in the past several functions were changed to use positional arguments for performance, but I would be very happy if this wasn't required anymore. |
Keyword arguments interact with performance in two distinct ways:
I think for most uses of |
|
That said, performance for |
The problem is that it's not performance for |
@JeffBezanson Any thoughts about this? |
I think we should keep the API the way we want it, and improve the compiler. |
OK, I'll update the PR to only loosen the signature. |
I've updated the PR to only loosen the signature, keeping keyword arguments. I leave type-inferrability for another PR -- let me know if you think it can be achieved (and how). |
inner::Array{Int} = ones(Int, ndims(A)), | ||
outer::Array{Int} = ones(Int, ndims(A))) | ||
""" | ||
repeat(A::AbstractArray; inner=(), outer=()) |
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 seem to accurately reflect the real default?
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, the old code used a similar "trick". The actual value ones(Int, ndims(A))
is a bit long, though not the end of the world. I've also tried another solution in which passing an empty collection is supported and is internally replaced with a vector of ones. Which one would you prefer?
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.
Not sure which implementation should be preferred. In terms of making the default in the docs match the more complicated version, how about giving the default value some temporary variable name that gets explained in more detail in the docstring body?
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 the additional complexity for the reader is worth it. ones(Int, ndims(A))
is almost as clear.
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.
Other opinions?
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, I've put the actual signature in the docs, that's the most obvious solution. Should be good to go now.
Accept any AbstractArray as first argument, and any iterable for inner and outer arguments. Use tuples by default rather than arrays, and allow passing an empty collection to mean no-op.
No objections against merging? |
Compatibility for JuliaLang/julia#14082. Use collect() since convert(Array, x) does not work for tuples.
Compatibility for JuliaLang/julia#14082. Since the new version in Julia 0.5 calls similar() internally, it is not enough to wrap it into a compatibility function to backport the fix. This is required to deprecate rep() from DataArrays.jl, which provides similar functionality for two custom array types.
Compatibility for JuliaLang/julia#14082. Since the new version in Julia 0.5 calls similar() internally, it is not enough to wrap it into a compatibility function to backport the fix. This is required to deprecate rep() from DataArrays.jl, which provides similar functionality for two custom array types.
Compatibility for JuliaLang/julia#14082. Since the new version in Julia 0.5 calls similar() internally, it is not enough to wrap it into a compatibility function to backport the fix. This is required to deprecate rep() from DataArrays.jl, which provides similar functionality for two custom array types.
Compatibility for JuliaLang/julia#14082. Since the new version in Julia 0.5 calls similar() internally, it is not enough to wrap it into a compatibility function to backport the fix. This is required to deprecate rep() from DataArrays.jl, which provides similar functionality for two custom array types.
Compatibility for JuliaLang/julia#14082. Since the new version in Julia 0.5 calls similar() internally, it is not enough to wrap it into a compatibility function to backport the fix. This is required to deprecate rep() from DataArrays.jl, which provides similar functionality for two custom array types.
Compatibility for JuliaLang/julia#14082. Since the new version in Julia 0.5 calls similar() internally, it is not enough to wrap it into a compatibility function to backport the fix. This is required to deprecate rep() from DataArrays.jl, which provides similar functionality for two custom array types.
Compatibility for JuliaLang/julia#14082. Since the new version in Julia 0.5 calls similar() internally, it is not enough to wrap it into a compatibility function to backport the fix. This is required to deprecate rep() from DataArrays.jl, which provides similar functionality for two custom array types.
Compatibility for JuliaLang/julia#14082. Since the new version in Julia 0.5 calls similar() internally, it is not enough to wrap it into a compatibility function to backport the fix. This is required to deprecate rep() from DataArrays.jl, which provides similar functionality for two custom array types.
Put 'outer' first as it is more natural to omit 'inner'. Deprecate the old version with keyword arguments.
Also change the signature to accept any AbstractArray as first argument, and any type for 'outer' and 'inner', to allow in particular passing tuples or arrays. Allow passing an empty collection to imply a no-op.
Fixes #12953.
I suspect I should update the docs after moving them out of helpdb.jl, but I don't know the command to run.