-
-
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
Equivalent of mapslices with views? #29146
Comments
I'd still be a major fan of bringing JuliennedArrays into Base. The major blocker for me has been that it requires some oblique syntax to get type stability for |
I'm also not entirely satisfied about the JuliennedArrays syntax. I'm not expert on the technical side, but doesn't |
No, |
I see, Do you think this needs to drop dimensions though? I don't have a strong preference either way but |
The key is that exposing a fast first class |
I don’t think it would be impossible to get ‘dims = 2’ to constant propagate. But I’ve somewhat given up on constant propagation; getting things into the type domain as soon as possible makes things SO much easier. If someone wants to give it a stab I’d welcome a PR. |
Whats the progress for this issue? I wrote a very basic mutating """
mapviews!(f, from, dest, dims)
Transform the given dimensions of array `from` and store to array `dest` using function `f`. `f` is called on each slice
of `from` resp. `dest` of the form `from[...,:,...,:,...]` resp. `dest[...,:,...,:,...]`. `dims` is an integer vector specifying where the
colons go in these expressions.
For example, if `dims` is `[1,2]`, `from` is 4-dimensional and `dest` is 4-dimensional aswell, `f` is called on `view(from,:,:,i,j)` and `view(dest,:,:,i,j)`
for all `i` and `j`.
"""
function mapviews!(f, from, dest, dims)
allDims = 1:ndims(from)
iterDims = setdiff(allDims, dims)
for x in CartesianIndices(axes(from)[iterDims])
x = [Tuple(x)...]
sliceIdx = Tuple(if n in dims; (:) else popfirst!(x) end for n in allDims)
f(view(from, sliceIdx...), view(dest, sliceIdx...))
end
end |
We now have #29749, so this can be written as |
Nice job: I think it almost closes this issue in that |
@mbauman does that also work for |
I mean, it does generate views, so yes, you with a mutating function foreach(f!, eachslice(dest, dims=d), eachslice(from, dims=d)) You can also use And of course neither |
Hi, I am not sure if this is the right place to post it, but I noticed an inconsistency in the meaning of the Let's say I want to sum rows of an array... julia> mat =[ 1 2;3 4;5 6]
3×2 Array{Int64,2}:
1 2
3 4
5 6
julia> map(sum , eachslice(mat ; dims=1))
3-element Array{Int64,1}:
3
7
11 However julia> dropdims(mapslices(sum, mat ; dims=1); dims = 1 )
2-element Array{Int64,1}:
9
12 One should use the other dimension for julia> dropdims(mapslices(sum, mat ; dims=2); dims = 2 )
3-element Array{Int64,1}:
3
7
11 The documentation explains it: in |
I think @dylanfesta points to a very important difference between
see also this discussion. EDIT: |
julia> M = rand(4,4,4);
julia> map(v -> sum(Iterators.filter(!isnan, v)), eachslice(M, dims=2))
4-element Vector{Float64}:
7.087633515941685
7.122552992022348
8.84984800208923
5.634331667457324
julia> map(v -> sum(Iterators.filter(!isnan, v)), eachslice(M, dims=(2,3)))
4×4 Matrix{Float64}:
1.80646 1.36365 1.73135 2.18617
1.86439 2.12595 2.42422 0.707997
2.54281 2.76217 2.01137 1.53349
1.42096 1.09299 0.91254 2.20785
julia> eachslice(M, dims=(2,3))[4,1]
4-element view(::Array{Float64, 3}, :, 4, 1) with eltype Float64:
0.14685562032478716
0.3136273513020742
0.39280441511008457
0.5676719922144797 |
Apologies for commenting on a completed issue but, @LilithHafner, your example second example doesn't work for me: julia> M = rand(4,4,4);
julia> map(v -> sum(Iterators.filter(!isnan, v)), eachslice(M, dims=(2,3)))
ERROR: ArgumentError: only single dimensions are supported
Stacktrace:
[1] #eachslice#244
@ ./abstractarraymath.jl:622 [inlined]
[2] top-level scope Any reason why there appears to be a regression? |
This should work on nightly; the new Mapslices is also faster on 1.9, after #40996... although some cases that inferred when that was merged seem not to now? julia> A = rand(Float32, 1000, 1000, 10);
julia> using BenchmarkTools, Statistics
julia> @btime map(mean, eachslice($A, dims=(1,3), drop=false)) |> size
15.409 ms (9 allocations: 39.47 KiB)
(1000, 1, 10)
julia> @btime mapslices(mean, $A, dims=2) |> size
13.128 ms (14915 allocations: 276.56 KiB)
(1000, 1, 10)
19.864 ms (129595 allocations: 3.09 MiB) # on Julia 1.8
julia> @btime mean($A; dims=2) |> size
1.292 ms (14 allocations: 39.77 KiB)
(1000, 1, 10)
julia> VERSION
v"1.9.0-DEV.1694" |
After some discussion on discourse it was proposed to "feature request" a version of
mapslices
in Julia Base that does not allocate slices. Naively I would think the behavior and syntax should be identical tomapslices
except that it iterates views rather than slices of the original array (mapviews
is a tentative name). I think it'd be useful for all cases where one wants to applymapslices
with a function with no side effects (or that doesn't mutate the original array) and avoid the extra allocations. A typical use case is for example summing with some filtering condition along some dimension:mapviews(v -> sum(Iterators.filter(!isnan, v)), M, dims=2)
for which I don't think there's an easy efficient solution in Base Julia right now.
It was pointed out that similar ideas have been implemented in the package JuliennedArrays and there was some discussion of moving some of that to Base, see this comment.
The text was updated successfully, but these errors were encountered: