From 560c1d91e93c57cd66359d6f40275ef277552738 Mon Sep 17 00:00:00 2001 From: Tom Short Date: Thu, 28 Feb 2013 07:55:06 -0500 Subject: [PATCH 1/3] Change several methods with StridedArray args to AbstractArray (for #1276). --- base/array.jl | 62 +++++++++++++++++++++++----------------------- base/linalg.jl | 4 +-- base/statistics.jl | 8 +++--- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/base/array.jl b/base/array.jl index fd38e93d19b38..fa186ec010418 100644 --- a/base/array.jl +++ b/base/array.jl @@ -196,8 +196,8 @@ end eye(m::Int, n::Int) = eye(Float64, m, n) eye(T::Type, n::Int) = eye(T, n, n) eye(n::Int) = eye(Float64, n) -eye{T}(x::StridedMatrix{T}) = eye(T, size(x, 1), size(x, 2)) -function one{T}(x::StridedMatrix{T}) +eye{T}(x::AbstractMatrix{T}) = eye(T, size(x, 1), size(x, 2)) +function one{T}(x::AbstractMatrix{T}) m,n = size(x) if m != n; error("Multiplicative identity only defined for square matrices!"); end; eye(T, m) @@ -778,7 +778,7 @@ end ## Unary operators ## -function conj!{T<:Number}(A::StridedArray{T}) +function conj!{T<:Number}(A::AbstractArray{T}) for i=1:length(A) A[i] = conj(A[i]) end @@ -787,7 +787,7 @@ end for f in (:-, :~, :conj, :sign) @eval begin - function ($f)(A::StridedArray) + function ($f)(A::AbstractArray) F = similar(A) for i=1:length(A) F[i] = ($f)(A[i]) @@ -801,7 +801,7 @@ end for f in (:real, :imag) @eval begin - function ($f){T}(A::StridedArray{T}) + function ($f){T}(A::AbstractArray{T}) S = typeof(($f)(zero(T))) F = similar(A, S) for i=1:length(A) @@ -812,7 +812,7 @@ for f in (:real, :imag) end end -function !(A::StridedArray{Bool}) +function !(A::AbstractArray{Bool}) F = similar(A) for i=1:length(A) F[i] = !A[i] @@ -1047,7 +1047,7 @@ function flipdim{T}(A::Array{T}, d::Integer) return B end -function rotl90(A::StridedMatrix) +function rotl90(A::AbstractMatrix) m,n = size(A) B = similar(A,(n,m)) for i=1:m, j=1:n @@ -1055,7 +1055,7 @@ function rotl90(A::StridedMatrix) end return B end -function rotr90(A::StridedMatrix) +function rotr90(A::AbstractMatrix) m,n = size(A) B = similar(A,(n,m)) for i=1:m, j=1:n @@ -1063,7 +1063,7 @@ function rotr90(A::StridedMatrix) end return B end -function rot180(A::StridedMatrix) +function rot180(A::AbstractMatrix) m,n = size(A) B = similar(A) for i=1:m, j=1:n @@ -1081,7 +1081,7 @@ rotr90(A::AbstractMatrix, k::Integer) = rotl90(A,-k) rot180(A::AbstractMatrix, k::Integer) = mod(k, 2) == 1 ? rot180(A) : copy(A) reverse(v::StridedVector) = (n=length(v); [ v[n-i+1] for i=1:n ]) -function reverse!(v::StridedVector) +function reverse!(v::AbstractVector) n = length(v) r = n for i=1:div(n,2) @@ -1156,7 +1156,7 @@ function findnext(testf::Function, A, start::Integer) end findfirst(testf::Function, A) = findnext(testf, A, 1) -function find(testf::Function, A::StridedArray) +function find(testf::Function, A::AbstractArray) # use a dynamic-length array to store the indexes, then copy to a non-padded # array for the return tmpI = Array(Int, 0) @@ -1170,7 +1170,7 @@ function find(testf::Function, A::StridedArray) I end -function find(A::StridedArray) +function find(A::AbstractArray) nnzA = nnz(A) I = Array(Int, nnzA) count = 1 @@ -1186,9 +1186,9 @@ end find(x::Number) = x == 0 ? Array(Int,0) : [1] find(testf::Function, x) = find(testf(x)) -findn(A::StridedVector) = find(A) +findn(A::AbstractVector) = find(A) -function findn(A::StridedMatrix) +function findn(A::AbstractMatrix) nnzA = nnz(A) I = Array(Int, nnzA) J = Array(Int, nnzA) @@ -1216,7 +1216,7 @@ function findn_one(ivars) end global findn -function findn{T}(A::StridedArray{T}) +function findn{T}(A::AbstractArray{T}) ndimsA = ndims(A) nnzA = nnz(A) I = ntuple(ndimsA, x->Array(Int, nnzA)) @@ -1234,7 +1234,7 @@ function findn{T}(A::StridedArray{T}) end end -function findn_nzs{T}(A::StridedMatrix{T}) +function findn_nzs{T}(A::AbstractMatrix{T}) nnzA = nnz(A) I = zeros(Int, nnzA) J = zeros(Int, nnzA) @@ -1254,7 +1254,7 @@ function findn_nzs{T}(A::StridedMatrix{T}) return (I, J, NZs) end -function nonzeros{T}(A::StridedArray{T}) +function nonzeros{T}(A::AbstractArray{T}) nnzA = nnz(A) V = Array(T, nnzA) count = 1 @@ -1440,7 +1440,7 @@ prod(A::AbstractArray{Bool}) = prod(A::AbstractArray{Bool}, region) = error("use all() instead of prod() for boolean arrays") -function sum{T}(A::StridedArray{T}) +function sum{T}(A::AbstractArray{T}) if isempty(A) return zero(T) end @@ -1451,7 +1451,7 @@ function sum{T}(A::StridedArray{T}) v end -function sum_kbn{T<:FloatingPoint}(A::StridedArray{T}) +function sum_kbn{T<:FloatingPoint}(A::AbstractArray{T}) n = length(A) if (n == 0) return zero(T) @@ -1473,7 +1473,7 @@ function sum_kbn{T<:FloatingPoint}(A::StridedArray{T}) end # Uses K-B-N summation -function cumsum_kbn{T<:FloatingPoint}(v::StridedVector{T}) +function cumsum_kbn{T<:FloatingPoint}(v::AbstractVector{T}) n = length(v) r = similar(v, n) if n == 0; return r; end @@ -1495,7 +1495,7 @@ function cumsum_kbn{T<:FloatingPoint}(v::StridedVector{T}) end # Uses K-B-N summation -function cumsum_kbn{T<:FloatingPoint}(A::StridedArray{T}, axis::Integer) +function cumsum_kbn{T<:FloatingPoint}(A::AbstractArray{T}, axis::Integer) dimsA = size(A) ndimsA = ndims(A) axis_size = dimsA[axis] @@ -1530,7 +1530,7 @@ function cumsum_kbn{T<:FloatingPoint}(A::StridedArray{T}, axis::Integer) return B + C end -function prod{T}(A::StridedArray{T}) +function prod{T}(A::AbstractArray{T}) if isempty(A) return one(T) end @@ -1541,7 +1541,7 @@ function prod{T}(A::StridedArray{T}) v end -function min{T<:Integer}(A::StridedArray{T}) +function min{T<:Integer}(A::AbstractArray{T}) v = typemax(T) for i=1:length(A) x = A[i] @@ -1552,7 +1552,7 @@ function min{T<:Integer}(A::StridedArray{T}) v end -function max{T<:Integer}(A::StridedArray{T}) +function max{T<:Integer}(A::AbstractArray{T}) v = typemin(T) for i=1:length(A) x = A[i] @@ -1566,7 +1566,7 @@ end ## map over arrays ## ## along an axis -function amap(f::Function, A::StridedArray, axis::Integer) +function amap(f::Function, A::AbstractArray, axis::Integer) dimsA = size(A) ndimsA = ndims(A) axis_size = dimsA[axis] @@ -1590,7 +1590,7 @@ end ## 1 argument -function map_to2(f, first, dest::StridedArray, A::StridedArray) +function map_to2(f, first, dest::AbstractArray, A::AbstractArray) dest[1] = first for i=2:length(A) dest[i] = f(A[i]) @@ -1598,7 +1598,7 @@ function map_to2(f, first, dest::StridedArray, A::StridedArray) return dest end -function map(f, A::StridedArray) +function map(f, A::AbstractArray) if isempty(A); return A; end first = f(A[1]) dest = similar(A, typeof(first)) @@ -1606,7 +1606,7 @@ function map(f, A::StridedArray) end ## 2 argument -function map_to2(f, first, dest::StridedArray, A::StridedArray, B::StridedArray) +function map_to2(f, first, dest::AbstractArray, A::AbstractArray, B::AbstractArray) dest[1] = first for i=2:length(A) dest[i] = f(A[i], B[i]) @@ -1614,7 +1614,7 @@ function map_to2(f, first, dest::StridedArray, A::StridedArray, B::StridedArray) return dest end -function map(f, A::StridedArray, B::StridedArray) +function map(f, A::AbstractArray, B::AbstractArray) shp = promote_shape(size(A),size(B)) if isempty(A) return similar(A, eltype(A), shp) @@ -1625,7 +1625,7 @@ function map(f, A::StridedArray, B::StridedArray) end ## N argument -function map_to2(f, first, dest::StridedArray, As::StridedArray...) +function map_to2(f, first, dest::AbstractArray, As::AbstractArray...) n = length(As[1]) i = 1 ith = a->a[i] @@ -1636,7 +1636,7 @@ function map_to2(f, first, dest::StridedArray, As::StridedArray...) return dest end -function map(f, As::StridedArray...) +function map(f, As::AbstractArray...) shape = mapreduce(size, promote_shape, As) if prod(shape) == 0 return similar(As[1], eltype(As[1]), shape) diff --git a/base/linalg.jl b/base/linalg.jl index 8ab7fe45f5a9d..bcb171426d4df 100644 --- a/base/linalg.jl +++ b/base/linalg.jl @@ -1,6 +1,6 @@ ## linalg.jl: Some generic Linear Algebra definitions -function scale!{T<:Number}(X::StridedArray{T}, s::Real) +function scale!{T<:Number}(X::AbstractArray{T}, s::Real) # FIXME: could use BLAS in more cases for i in 1:length(X) X[i] *= s; @@ -8,7 +8,7 @@ function scale!{T<:Number}(X::StridedArray{T}, s::Real) return X end -cross(a::Vector, b::Vector) = +cross(a::AbstractVector, b::AbstractVector) = [a[2]*b[3]-a[3]*b[2], a[3]*b[1]-a[1]*b[3], a[1]*b[2]-a[2]*b[1]] triu(M::AbstractMatrix) = triu(M,0) diff --git a/base/statistics.jl b/base/statistics.jl index 31674c68d3795..9190cf16d665f 100644 --- a/base/statistics.jl +++ b/base/statistics.jl @@ -73,7 +73,7 @@ std(v::Ranges) = std(v, true) ## hist ## -function hist(v::StridedVector, nbins::Integer) +function hist(v::AbstractVector, nbins::Integer) h = zeros(Int, nbins) if nbins == 0 return h @@ -95,7 +95,7 @@ end hist(x) = hist(x, 10) -function hist(A::StridedMatrix, nbins::Integer) +function hist(A::AbstractMatrix, nbins::Integer) m, n = size(A) h = Array(Int, nbins, n) for j=1:n @@ -104,7 +104,7 @@ function hist(A::StridedMatrix, nbins::Integer) h end -function hist(v::StridedVector, edg::AbstractVector) +function hist(v::AbstractVector, edg::AbstractVector) n = length(edg) h = zeros(Int, n) if n == 0 @@ -121,7 +121,7 @@ function hist(v::StridedVector, edg::AbstractVector) h end -function hist(A::StridedMatrix, edg::AbstractVector) +function hist(A::AbstractMatrix, edg::AbstractVector) m, n = size(A) h = Array(Int, length(edg), n) for j=1:n From 184f372ecf5cf1af29c0337f9cd625844a3f7fe8 Mon Sep 17 00:00:00 2001 From: Tom Short Date: Sun, 3 Mar 2013 20:29:46 -0500 Subject: [PATCH 2/3] Move some methods operating on AbstractArrays from array.jl to abstractarray.jl. --- base/abstractarray.jl | 224 ++++++++++++++++++++++++++++++++++++++++++ base/array.jl | 221 ----------------------------------------- 2 files changed, 224 insertions(+), 221 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index bd16d22e94a18..7eaff2efdc32c 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1221,3 +1221,227 @@ bsxfun(f, a, b) = f(a, b) bsxfun(f, a::AbstractArray, b) = f(a, b) bsxfun(f, a, b::AbstractArray) = f(a, b) bsxfun(f, a, b, c...) = bsxfun(f, bsxfun(f, a, b), c...) + +# Basic AbstractArray functions + +max{T}(A::AbstractArray{T}, b::(), region) = reducedim(max,A,region,typemin(T)) +min{T}(A::AbstractArray{T}, b::(), region) = reducedim(min,A,region,typemax(T)) +sum{T}(A::AbstractArray{T}, region) = reducedim(+,A,region,zero(T)) +prod{T}(A::AbstractArray{T}, region) = reducedim(*,A,region,one(T)) + +all(A::AbstractArray{Bool}, region) = reducedim(all,A,region,true) +any(A::AbstractArray{Bool}, region) = reducedim(any,A,region,false) +sum(A::AbstractArray{Bool}, region) = reducedim(+,A,region,0,similar(A,Int,reduced_dims(A,region))) +sum(A::AbstractArray{Bool}) = sum(A, [1:ndims(A)])[1] +sum(A::StridedArray{Bool}) = sum(A, [1:ndims(A)])[1] +prod(A::AbstractArray{Bool}) = + error("use all() instead of prod() for boolean arrays") +prod(A::AbstractArray{Bool}, region) = + error("use all() instead of prod() for boolean arrays") + +function sum{T}(A::AbstractArray{T}) + if isempty(A) + return zero(T) + end + v = A[1] + for i=2:length(A) + v += A[i] + end + v +end + +function sum_kbn{T<:FloatingPoint}(A::AbstractArray{T}) + n = length(A) + if (n == 0) + return zero(T) + end + s = A[1] + c = zero(T) + for i in 2:n + Ai = A[i] + t = s + Ai + if abs(s) >= abs(Ai) + c += ((s-t) + Ai) + else + c += ((Ai-t) + s) + end + s = t + end + + s + c +end + +# Uses K-B-N summation +function cumsum_kbn{T<:FloatingPoint}(v::AbstractVector{T}) + n = length(v) + r = similar(v, n) + if n == 0; return r; end + + s = r[1] = v[1] + c = zero(T) + for i=2:n + vi = v[i] + t = s + vi + if abs(s) >= abs(vi) + c += ((s-t) + vi) + else + c += ((vi-t) + s) + end + s = t + r[i] = s+c + end + return r +end + +# Uses K-B-N summation +function cumsum_kbn{T<:FloatingPoint}(A::AbstractArray{T}, axis::Integer) + dimsA = size(A) + ndimsA = ndims(A) + axis_size = dimsA[axis] + axis_stride = 1 + for i = 1:(axis-1) + axis_stride *= size(A,i) + end + + if axis_size <= 1 + return A + end + + B = similar(A) + C = similar(A) + + for i = 1:length(A) + if div(i-1, axis_stride) % axis_size == 0 + B[i] = A[i] + C[i] = zero(T) + else + s = B[i-axis_stride] + Ai = A[i] + B[i] = t = s + Ai + if abs(s) >= abs(Ai) + C[i] = C[i-axis_stride] + ((s-t) + Ai) + else + C[i] = C[i-axis_stride] + ((Ai-t) + s) + end + end + end + + return B + C +end + +function prod{T}(A::AbstractArray{T}) + if isempty(A) + return one(T) + end + v = A[1] + for i=2:length(A) + v *= A[i] + end + v +end + +function min{T<:Integer}(A::AbstractArray{T}) + v = typemax(T) + for i=1:length(A) + x = A[i] + if x < v + v = x + end + end + v +end + +function max{T<:Integer}(A::AbstractArray{T}) + v = typemin(T) + for i=1:length(A) + x = A[i] + if x > v + v = x + end + end + v +end + +## map over arrays ## + +## along an axis +function amap(f::Function, A::AbstractArray, axis::Integer) + dimsA = size(A) + ndimsA = ndims(A) + axis_size = dimsA[axis] + + if axis_size == 0 + return f(A) + end + + idx = ntuple(ndimsA, j -> j == axis ? 1 : 1:dimsA[j]) + r = f(sub(A, idx)) + R = Array(typeof(r), axis_size) + R[1] = r + + for i = 2:axis_size + idx = ntuple(ndimsA, j -> j == axis ? i : 1:dimsA[j]) + R[i] = f(sub(A, idx)) + end + + return R +end + + +## 1 argument +function map_to2(f, first, dest::AbstractArray, A::AbstractArray) + dest[1] = first + for i=2:length(A) + dest[i] = f(A[i]) + end + return dest +end + +function map(f, A::AbstractArray) + if isempty(A); return A; end + first = f(A[1]) + dest = similar(A, typeof(first)) + return map_to2(f, first, dest, A) +end + +## 2 argument +function map_to2(f, first, dest::AbstractArray, A::AbstractArray, B::AbstractArray) + dest[1] = first + for i=2:length(A) + dest[i] = f(A[i], B[i]) + end + return dest +end + +function map(f, A::AbstractArray, B::AbstractArray) + shp = promote_shape(size(A),size(B)) + if isempty(A) + return similar(A, eltype(A), shp) + end + first = f(A[1], B[1]) + dest = similar(A, typeof(first), shp) + return map_to2(f, first, dest, A, B) +end + +## N argument +function map_to2(f, first, dest::AbstractArray, As::AbstractArray...) + n = length(As[1]) + i = 1 + ith = a->a[i] + dest[1] = first + for i=2:n + dest[i] = f(map(ith, As)...) + end + return dest +end + +function map(f, As::AbstractArray...) + shape = mapreduce(size, promote_shape, As) + if prod(shape) == 0 + return similar(As[1], eltype(As[1]), shape) + end + first = f(map(a->a[1], As)...) + dest = similar(As[1], typeof(first), shape) + return map_to2(f, first, dest, As...) +end + diff --git a/base/array.jl b/base/array.jl index fa186ec010418..e3e1f78b97581 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1425,227 +1425,6 @@ function reducedim(f::Function, A, region, v0, R) end end -max{T}(A::AbstractArray{T}, b::(), region) = reducedim(max,A,region,typemin(T)) -min{T}(A::AbstractArray{T}, b::(), region) = reducedim(min,A,region,typemax(T)) -sum{T}(A::AbstractArray{T}, region) = reducedim(+,A,region,zero(T)) -prod{T}(A::AbstractArray{T}, region) = reducedim(*,A,region,one(T)) - -all(A::AbstractArray{Bool}, region) = reducedim(all,A,region,true) -any(A::AbstractArray{Bool}, region) = reducedim(any,A,region,false) -sum(A::AbstractArray{Bool}, region) = reducedim(+,A,region,0,similar(A,Int,reduced_dims(A,region))) -sum(A::AbstractArray{Bool}) = sum(A, [1:ndims(A)])[1] -sum(A::StridedArray{Bool}) = sum(A, [1:ndims(A)])[1] -prod(A::AbstractArray{Bool}) = - error("use all() instead of prod() for boolean arrays") -prod(A::AbstractArray{Bool}, region) = - error("use all() instead of prod() for boolean arrays") - -function sum{T}(A::AbstractArray{T}) - if isempty(A) - return zero(T) - end - v = A[1] - for i=2:length(A) - v += A[i] - end - v -end - -function sum_kbn{T<:FloatingPoint}(A::AbstractArray{T}) - n = length(A) - if (n == 0) - return zero(T) - end - s = A[1] - c = zero(T) - for i in 2:n - Ai = A[i] - t = s + Ai - if abs(s) >= abs(Ai) - c += ((s-t) + Ai) - else - c += ((Ai-t) + s) - end - s = t - end - - s + c -end - -# Uses K-B-N summation -function cumsum_kbn{T<:FloatingPoint}(v::AbstractVector{T}) - n = length(v) - r = similar(v, n) - if n == 0; return r; end - - s = r[1] = v[1] - c = zero(T) - for i=2:n - vi = v[i] - t = s + vi - if abs(s) >= abs(vi) - c += ((s-t) + vi) - else - c += ((vi-t) + s) - end - s = t - r[i] = s+c - end - return r -end - -# Uses K-B-N summation -function cumsum_kbn{T<:FloatingPoint}(A::AbstractArray{T}, axis::Integer) - dimsA = size(A) - ndimsA = ndims(A) - axis_size = dimsA[axis] - axis_stride = 1 - for i = 1:(axis-1) - axis_stride *= size(A,i) - end - - if axis_size <= 1 - return A - end - - B = similar(A) - C = similar(A) - - for i = 1:length(A) - if div(i-1, axis_stride) % axis_size == 0 - B[i] = A[i] - C[i] = zero(T) - else - s = B[i-axis_stride] - Ai = A[i] - B[i] = t = s + Ai - if abs(s) >= abs(Ai) - C[i] = C[i-axis_stride] + ((s-t) + Ai) - else - C[i] = C[i-axis_stride] + ((Ai-t) + s) - end - end - end - - return B + C -end - -function prod{T}(A::AbstractArray{T}) - if isempty(A) - return one(T) - end - v = A[1] - for i=2:length(A) - v *= A[i] - end - v -end - -function min{T<:Integer}(A::AbstractArray{T}) - v = typemax(T) - for i=1:length(A) - x = A[i] - if x < v - v = x - end - end - v -end - -function max{T<:Integer}(A::AbstractArray{T}) - v = typemin(T) - for i=1:length(A) - x = A[i] - if x > v - v = x - end - end - v -end - -## map over arrays ## - -## along an axis -function amap(f::Function, A::AbstractArray, axis::Integer) - dimsA = size(A) - ndimsA = ndims(A) - axis_size = dimsA[axis] - - if axis_size == 0 - return f(A) - end - - idx = ntuple(ndimsA, j -> j == axis ? 1 : 1:dimsA[j]) - r = f(sub(A, idx)) - R = Array(typeof(r), axis_size) - R[1] = r - - for i = 2:axis_size - idx = ntuple(ndimsA, j -> j == axis ? i : 1:dimsA[j]) - R[i] = f(sub(A, idx)) - end - - return R -end - - -## 1 argument -function map_to2(f, first, dest::AbstractArray, A::AbstractArray) - dest[1] = first - for i=2:length(A) - dest[i] = f(A[i]) - end - return dest -end - -function map(f, A::AbstractArray) - if isempty(A); return A; end - first = f(A[1]) - dest = similar(A, typeof(first)) - return map_to2(f, first, dest, A) -end - -## 2 argument -function map_to2(f, first, dest::AbstractArray, A::AbstractArray, B::AbstractArray) - dest[1] = first - for i=2:length(A) - dest[i] = f(A[i], B[i]) - end - return dest -end - -function map(f, A::AbstractArray, B::AbstractArray) - shp = promote_shape(size(A),size(B)) - if isempty(A) - return similar(A, eltype(A), shp) - end - first = f(A[1], B[1]) - dest = similar(A, typeof(first), shp) - return map_to2(f, first, dest, A, B) -end - -## N argument -function map_to2(f, first, dest::AbstractArray, As::AbstractArray...) - n = length(As[1]) - i = 1 - ith = a->a[i] - dest[1] = first - for i=2:n - dest[i] = f(map(ith, As)...) - end - return dest -end - -function map(f, As::AbstractArray...) - shape = mapreduce(size, promote_shape, As) - if prod(shape) == 0 - return similar(As[1], eltype(As[1]), shape) - end - first = f(map(a->a[1], As)...) - dest = similar(As[1], typeof(first), shape) - return map_to2(f, first, dest, As...) -end - ## Filter ## # given a function returning a boolean and an array, return matching elements From 13c2c448c0583292b8942cbf7ceef1b71338c17c Mon Sep 17 00:00:00 2001 From: Tom Short Date: Mon, 4 Mar 2013 07:31:49 -0500 Subject: [PATCH 3/3] Remove a redundant method definition. --- base/abstractarray.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 7eaff2efdc32c..fba3c0ee863a8 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1233,7 +1233,6 @@ all(A::AbstractArray{Bool}, region) = reducedim(all,A,region,true) any(A::AbstractArray{Bool}, region) = reducedim(any,A,region,false) sum(A::AbstractArray{Bool}, region) = reducedim(+,A,region,0,similar(A,Int,reduced_dims(A,region))) sum(A::AbstractArray{Bool}) = sum(A, [1:ndims(A)])[1] -sum(A::StridedArray{Bool}) = sum(A, [1:ndims(A)])[1] prod(A::AbstractArray{Bool}) = error("use all() instead of prod() for boolean arrays") prod(A::AbstractArray{Bool}, region) =