Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Strided"
uuid = "5e0ebb24-38b0-5f93-81fe-25c709ecae67"
version = "2.6.2"
version = "2.6.3"
authors = ["Lukas Devos <lukas.devos@ugent.be>", "Maarten Van Damme <maartenvd1994@gmail.com>", "Jutho Haegeman <jutho.haegeman@ugent.be>"]

[deps]
Expand Down
17 changes: 17 additions & 0 deletions src/mapreduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ function _mapreduce(@nospecialize(f), @nospecialize(op), A::StridedView{T}, nt =
dims = size(A)
a = Base.mapreduce_first(f, op, first(A))
a2 = nt === nothing ? a : op(a, nt.init)
ndims(A) == 0 && return a2 # 0-dim scalar: single-element reduction is the result
out = similar(A, typeof(a2), (1,))
if nt === nothing
_init_reduction!(out, f, op, a)
Expand Down Expand Up @@ -162,12 +163,27 @@ function _mapreduce_order!(
@nospecialize(f), @nospecialize(op), @nospecialize(initop),
dims::Dims, arrays::Tuple{Vararg{StridedView}}
)
isempty(dims) && return _mapreduce_scalar!(f, op, initop, arrays)
dims, allstrides = order_and_fuse_dims(dims, map(strides, arrays))
offsets = map(offset, arrays)
costs = _computecosts(allstrides)
return _mapreduce_block!(f, op, initop, dims, allstrides, offsets, costs, arrays)
end

# 0-dimensional fast path: bypass @generated kernel
function _mapreduce_scalar!(@nospecialize(f), @nospecialize(op), @nospecialize(initop), arrays)
out = arrays[1]
iout = ParentIndex(offset(out) + 1)
v = f(map(a -> a[ParentIndex(offset(a) + 1)], Base.tail(arrays))...)
if op === nothing
out[iout] = v
else
o = initop === nothing ? out[iout] : initop(out[iout])
out[iout] = op(o, v)
end
return nothing
end

const MINTHREADLENGTH = 1 << 15 # minimal length before any kind of threading is applied
function _mapreduce_block!(
@nospecialize(f), @nospecialize(op), @nospecialize(initop),
Expand Down Expand Up @@ -269,6 +285,7 @@ function _mapreduce_threaded!(
end

function _mapreduce_kernel_expr(f, op, initop, N::Int, M::Int)
@assert N > 0 "Cannot generate 0-dim kernel"

# many variables
blockloopvars = Array{Symbol}(undef, N)
Expand Down
44 changes: 44 additions & 0 deletions test/othertests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,50 @@ end
end
end

@testset "0-dimensional (scalar) StridedView" begin
@testset for T in (Float32, Float64, ComplexF32, ComplexF64)
R = fill(rand(T)) # 0-dimensional Array
A = StridedView(R)
@test ndims(A) == 0

# full reductions
@test sum(A) == sum(R)
@test prod(A) == prod(R)
@test mapreduce(abs2, +, A) == mapreduce(abs2, +, R)
@test maximum(abs, A) == maximum(abs, R)
@test minimum(abs, A) == minimum(abs, R)
@test sum(abs2, A) == sum(abs2, R)
@test mapreduce(identity, +, A; init = one(T)) ==
mapreduce(identity, +, R; init = one(T))

# map / map! / copy! / fill!
@test map(x -> 2x, A)[] == 2 * R[]
B = StridedView(fill(zero(T)))
map!(x -> x + one(T), B, A)
@test B[] == R[] + one(T)
copy!(B, A)
@test B[] == R[]
fill!(B, one(T))
@test B[] == one(T)

# offset handling: 0-dim views into a larger parent
Psrc = rand(T, 5)
Pdst = rand(T, 5)
s = sreshape(StridedView(Psrc)[4:4], ())
d = sreshape(StridedView(Pdst)[3:3], ())
@test sum(s) == Psrc[4]
copy!(d, s)
@test Pdst[3] == Psrc[4]

# low-level in-place reduction with a custom initop
Pd = rand(T, 5)
d2 = sreshape(StridedView(Pd)[2:2], ())
prev = Pd[2]
Strided._mapreducedim!(sin, +, identity, (), (d2, A))
@test Pd[2] == prev + sin(R[])
end
end

@testset "@strided macro" begin
@testset for T in (Float32, Float64, ComplexF32, ComplexF64)
A1, A2, A3 = rand(T, (10,)), rand(T, (10, 10)), rand(T, (10, 10, 10))
Expand Down
Loading