diff --git a/base/abstractarray.jl b/base/abstractarray.jl index cbbae8e852b2e..3816ee926dead 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -559,7 +559,9 @@ end """ strides(A) -Return a tuple of the memory strides in each dimension. +Return a tuple of the memory strides in each dimension, for an `AbstractArray` with a +strided memory layout. For arrays with a non-strided layout (such as sparse arrays), return +`nothing`. See also: [`stride`](@ref). @@ -571,7 +573,7 @@ julia> strides(A) (1, 3, 12) ``` """ -function strides end +strides(::AbstractArray) = nothing """ stride(A, k::Integer) @@ -592,15 +594,14 @@ julia> stride(A,3) ``` """ function stride(A::AbstractArray, k::Integer) - st = strides(A) - k ≤ ndims(A) && return st[k] - ndims(A) == 0 && return 1 - sz = size(A) - s = st[1] * sz[1] - for i in 2:ndims(A) - s += st[i] * sz[i] + str = strides(A) + if str === nothing + return nothing + else + k ≤ ndims(A) && return st[k] + ndims(A) == 0 && return 1 + return sum(st .* size(A)) end - return s end @inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...) diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index cf9748168aac2..acf1c364fb7fb 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -61,7 +61,11 @@ Base.pointer(A::PermutedDimsArray, i::Integer) = throw(ArgumentError("pointer(A, function Base.strides(A::PermutedDimsArray{T,N,perm}) where {T,N,perm} s = strides(parent(A)) - ntuple(d->s[perm[d]], Val(N)) + if s === nothing + return nothing + else + return ntuple(d->s[perm[d]], Val(N)) + end end Base.elsize(::Type{<:PermutedDimsArray{<:Any, <:Any, <:Any, <:Any, P}}) where {P} = Base.elsize(P) diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index b722e49bb2c3d..5281dba7e6e8f 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -382,6 +382,25 @@ parent(A::AdjOrTrans) = A.parent vec(v::TransposeAbsVec{<:Number}) = parent(v) vec(v::AdjointAbsVec{<:Real}) = parent(v) +# provide strides, but only for eltypes that are directly stored in memory (i.e. unaffected +# by recursive `adjoint` and `transpose`, being `Real` and `Number` respectively) +function Base.strides(a::Union{Adjoint{<:Real, <:AbstractVector}, Transpose{<:Number, <:AbstractVector}}) + str = strides(a.parent) + if str === nothing + return nothing + else + return (1, str[1]) + end +end +function Base.strides(a::Union{Adjoint{<:Real, <:AbstractMatrix}, Transpose{<:Number, <:AbstractMatrix}}) + str = strides(a.parent) + if str === nothing + return nothing + else + return (str[2], str[1]) + end +end + ### concatenation # preserve Adjoint/Transpose wrapper around vectors # to retain the associated semantics post-concatenation