Skip to content
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

Rewrite mul! to dispatch based on memory layout, not matrix type #25558

Closed
wants to merge 54 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e86e8bb
Added MemoryLayout, rewrote mul! to be based on memory layout
dlfivefifty Jan 14, 2018
1d80d44
MemoryLayout implemented for instances not types, improved mul! type …
dlfivefifty Jan 16, 2018
81c2f92
Added other memory layouts, updated triangular
dlfivefifty Jan 16, 2018
84fc2ee
fix ambiguity
dlfivefifty Jan 16, 2018
c65a568
fix UndefVar error
dlfivefifty Jan 17, 2018
f12129d
Merge branch 'master' of https://github.com/JuliaLang/julia into dl/a…
Jan 19, 2018
f467664
Merge branch 'master' of https://github.com/JuliaLang/julia into dl/a…
Jan 19, 2018
1387afc
Restore mapslices (for now)
Jan 19, 2018
4ff991d
order of generalized eigvals appears to be brittle, so sort before co…
Jan 19, 2018
9bbdc8f
merge
dlfivefifty Jan 19, 2018
c4d93e5
merge triangular
dlfivefifty Jan 19, 2018
9d23927
Fix mul2! usages
dlfivefifty Jan 20, 2018
cac81bc
Fix transpose/adjoint MemoryLayout, add tests, add DenseLayout
dlfivefifty Jan 20, 2018
c745821
dot, dotu dispatch, remove special * for Adjoint/Transpose
dlfivefifty Jan 21, 2018
fe55aad
Add MemoryLayout for symmetric, add docs
dlfivefifty Jan 21, 2018
807644d
Merge branch 'master' of https://github.com/JuliaLang/julia into dl/a…
dlfivefifty Jan 22, 2018
30d5ad8
Fix whitespace
dlfivefifty Jan 22, 2018
a67eebe
Fix symmetric ambiguities
dlfivefifty Jan 27, 2018
725ab0e
Merge master
dlfivefifty Jan 27, 2018
3f2528d
Override MemoryLayout for all DenseVector/Matrices (included SharedAr…
Jan 29, 2018
15238b6
Rename layouts to DenseColumnMajor, DenseColumnsStridedRows, DenseRow…
Jan 30, 2018
3e1e4c4
Add ConjLayout to replace ConjDenseColumns, and others
dlfivefifty Feb 4, 2018
64e8609
add strides for DenseRowMajor
dlfivefifty Feb 4, 2018
ce99b1b
strides for BitArray, conj of triangular layouts
dlfivefifty Feb 5, 2018
1a454fd
merge master
dlfivefifty Feb 5, 2018
33f4e48
mul1! -> rmul!, mul2! -> lmul!
dlfivefifty Feb 5, 2018
37c44d5
Redesign TriangularLayouts and Symmetric/HermitianLayout, add tests t…
dlfivefifty Feb 9, 2018
c5ddd01
Move MemoryLayout routines to Base
dlfivefifty Feb 14, 2018
8c4d4cd
merge master
dlfivefifty Feb 19, 2018
482939a
merge dense
dlfivefifty Feb 19, 2018
01047c8
Merge branch 'master' of https://github.com/JuliaLang/julia into dl/a…
dlfivefifty Feb 19, 2018
3618a39
DenseColumns -> AbstractColumnMajor
Feb 19, 2018
0b0eb44
Merge master
Feb 28, 2018
bad7814
MemoryLayout{T} -> MemoryLayout, as well as subtypes
Feb 28, 2018
6110ccb
Fix vecdot, be more conservative in dispatch for symmetriclayout, etc…
dlfivefifty Feb 28, 2018
dfcc856
Fix vecdot ambiguity
dlfivefifty Mar 1, 2018
8ad8a35
submemorylayout -> subarraylayout, MemoryLayout(::DenseArray) restore…
Mar 1, 2018
5d55e48
first attempt at arbitrary d
Mar 1, 2018
74c7f67
subarraylayout now works with arb d
dlfivefifty Mar 1, 2018
d723b1a
more ambiguities fixed
dlfivefifty Mar 2, 2018
a0cd467
add RowMajorArray tests, update memory layout docs for arbitrary dime…
Mar 2, 2018
681f73b
Add _mul(A, B, memlayA, memlayB) to simplify * overloads
Mar 2, 2018
9d0f50b
view(UpperTriangular(A), :, Base.OneTo(n)) (and similar) now conform …
Mar 2, 2018
3413fba
remove white space
dlfivefifty Mar 2, 2018
ed88786
merge master
dlfivefifty Mar 11, 2018
5535185
Add Increasing/DecreasingStrides
dlfivefifty Mar 11, 2018
53c2879
merge master
Mar 12, 2018
7b19e38
Add `Base.MemoryLayout(A)` as optional override, fix docs for MemoryL…
Mar 12, 2018
09aa094
Merge branch 'master' of https://github.com/JuliaLang/julia into dl/a…
Mar 26, 2018
f2f1b8f
Add NEWS item
Mar 26, 2018
e19f1a5
fixes for mbauman
dlfivefifty Apr 7, 2018
196b040
Merge branch 'dl/arraymemorylayout' of https://github.com/dlfivefifty…
dlfivefifty Apr 7, 2018
d386ef3
Merge branch 'master' of https://github.com/JuliaLang/julia into dl/a…
dlfivefifty Apr 7, 2018
f2bc361
Merge master
dlfivefifty May 18, 2018
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
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,11 @@ Library improvements
keyword arguments. ([#26156], [#26670])


* `Base.MemoryLayout(A::AbstractArray)` introduced to specify the layout in
memory for an array `A`, by returning `DenseColumnMajor()`, `ColumnMajor()`,
`DenseRowMajor()`, `RowMajor()` or other specialized memory layouts. The return
value is used in `mul!` to dispatch to the correct BLAS or LAPACK routines. ([#25558])

Compiler/Runtime improvements
-----------------------------

Expand Down
176 changes: 176 additions & 0 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,138 @@ size_to_strides(s, d) = (s,)
size_to_strides(s) = ()


abstract type MemoryLayout end
struct UnknownLayout <: MemoryLayout end
abstract type AbstractStridedLayout <: MemoryLayout end
abstract type AbstractIncreasingStrides <: AbstractStridedLayout end
abstract type AbstractColumnMajor <: AbstractIncreasingStrides end
struct DenseColumnMajor <: AbstractColumnMajor end
struct ColumnMajor <: AbstractColumnMajor end
struct IncreasingStrides <: AbstractIncreasingStrides end
abstract type AbstractDecreasingStrides <: AbstractStridedLayout end
abstract type AbstractRowMajor <: AbstractDecreasingStrides end
struct DenseRowMajor <: AbstractRowMajor end
struct RowMajor <: AbstractRowMajor end
struct DecreasingStrides <: AbstractIncreasingStrides end
struct StridedLayout <: AbstractStridedLayout end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still seems far too fine-grained. Yes, these are really cool and it's awesome that you can track them through some of our wrapper arrays, but you barely use them for the purposes of dispatching mul to BLAS. Really, BLAS only cares about a handful of things beyond the basic strided-ness:

  • Are the columns contiguous? (stride(A::AbstractMatrix, 1) == 1)
  • Are the rows contiguous? (stride(A::AbstractMatrix, 2) == 1)

For the wrapper arrays (reshape and view) to be able to preserve stridedness through their transformations we additionally need to know if the arrays are wholly contiguous (stride(vec(A), 1) == 1 or stride(vec(permutedims(A, reverse(ntuple(identity, ndims(A)))), 1) == 1).

You're going to hate me, but I really think this should just be:

abstract type AbstractStridedLayout <: MemoryLayout end
struct StridedLayout <: AbstractStridedLayout end
struct ColumnMajorContiguousStridedLayout <: AbstractStridedLayout end
struct RowMajorContiguousStridedLayout <: AbstractStridedLayout end

Note that gemm_wrapper! already does value-based checking on stride(A, 1) == 1, etc. I really don't see value in having these things encoded into a traitsystem. To the contrary: I think the additional complexity is just asking for trouble.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's handle renaming separately, as that's a trivial find/replace change.

So back to what it was originally? Weren't you the one to suggest adding Increasing/DecreasingStrides?

Removing ColumnMajor loses functionality: V = view(A,1:5,1,2,3) is known to be DenseColumnMajor if A is ColumnMajor, so we can do, for example, reshape(V, (2,3)) and still use BLAS.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right — I should be using your existing terms here. I was sketching out lots of possibilities and this slowly diverged as I progressed. The core idea is to eliminate all AbstractStridedLayout subtypes except the general one and DenseRowMajor and DenseColumnMajor.

Yup, I was the one to suggest the Increasing/DecreasingStrides terminology but my goal was to generalize/rename and simplify. I definitely don't want any nodes here that you don't actually use.

Yes, your exact example there is correct, but do you have any examples of ColumnMajor StridedArrays that aren't views of a Dense structure? Because if A is a ColumnMajor strided view into a DenseColumnMajor array, then SubArray "pops" the intermediate view and recomputes its indices in terms of the original parent, making that example work. Further, were I developing a ColumnMajor array type specifically, I think I'd be just fine adding specializations on view(A::MyColumnMajor, ::AbstractUnitRange, ...) to impart the additional knowledge that's available in that case. If I'm wrong, we can add this back in in the future. We can document that this type tree is experimental and that the generic StridedLayout shouldn't be used for dispatch as a more specific type might get returned in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I regard relying on overloading of view as a no go: the initial motivation for this PR (which came up in other contexts subsequently) was that if A is banded then view(A, ::UnitRange, ::UnitRange) is also banded.

Now one could override view to return a SubBandedMatrix, which is what I did initially, but it results in tons of copy-and-paste of subarray.jl. The "correct" solution was to instead link into the current SubArray infrastructure.

I think we should set aside the discussion of simplifying the type hierarchy until others weigh in, as there are a number of different needs here.


"""
UnknownLayout()

is returned by `MemoryLayout(A)` if it is unknown how the entries of an array `A`
are stored in memory.
"""
UnknownLayout

"""
AbstractStridedLayout

is an abstract type whose subtypes are returned by `MemoryLayout(A)`
if an array `A` has storage laid out at regular offsets in memory,
and which can therefore be passed to external C and Fortran functions expecting
this memory layout.

Julia's internal linear algebra machinery will automatically (and invisibly)
dispatch to BLAS and LAPACK routines if the memory layout is BLAS compatible and
the element type is a `Float32`, `Float64`, `ComplexF32`, or `ComplexF64`.
In this case, one must implement the strided array interface, which requires
overrides of `strides(A::MyMatrix)` and `unknown_convert(::Type{Ptr{T}}, A::MyMatrix)`.
"""
AbstractStridedLayout

"""
DenseColumnMajor()

is returned by `MemoryLayout(A)` if an array `A` has storage in memory
equivalent to an `Array`, so that `stride(A,1) == 1` and
`stride(A,i) ≡ size(A,i-1) * stride(A,i-1)` for `2 ≤ i ≤ ndims(A)`. In particular,
if `A` is a matrix then `strides(A) == `(1, size(A,1))`.

Arrays with `DenseColumnMajor` memory layout must conform to the `DenseArray` interface.
"""
DenseColumnMajor

"""
ColumnMajor()

is returned by `MemoryLayout(A)` if an array `A` has storage in memory
as a column major array, so that `stride(A,1) == 1` and
`stride(A,i) ≥ size(A,i-1) * stride(A,i-1)` for `2 ≤ i ≤ ndims(A)`.

Arrays with `ColumnMajor` memory layout must conform to the `DenseArray` interface.
"""
ColumnMajor

"""
IncreasingStrides()

is returned by `MemoryLayout(A)` if an array `A` has storage in memory
as a strided array with increasing strides, so that `stride(A,1) ≥ 1` and
`stride(A,i) ≥ size(A,i-1) * stride(A,i-1)` for `2 ≤ i ≤ ndims(A)`.
"""
IncreasingStrides

"""
DenseRowMajor()

is returned by `MemoryLayout(A)` if an array `A` has storage in memory
as a row major array with dense entries, so that `stride(A,ndims(A)) == 1` and
`stride(A,i) ≡ size(A,i+1) * stride(A,i+1)` for `1 ≤ i ≤ ndims(A)-1`. In particular,
if `A` is a matrix then `strides(A) == `(size(A,2), 1)`.
"""
DenseRowMajor

"""
RowMajor()

is returned by `MemoryLayout(A)` if an array `A` has storage in memory
as a row major array, so that `stride(A,ndims(A)) == 1` and
stride(A,i) ≥ size(A,i+1) * stride(A,i+1)` for `1 ≤ i ≤ ndims(A)-1`.

If `A` is a matrix with `RowMajor` memory layout, then
`transpose(A)` should return a matrix whose layout is `ColumnMajor`.
"""
RowMajor

"""
DecreasingStrides()

is returned by `MemoryLayout(A)` if an array `A` has storage in memory
as a strided array with decreasing strides, so that `stride(A,ndims(A)) ≥ 1` and
stride(A,i) ≥ size(A,i+1) * stride(A,i+1)` for `1 ≤ i ≤ ndims(A)-1`.
"""
DecreasingStrides

"""
StridedLayout()

is returned by `MemoryLayout(A)` if an array `A` has storage laid out at regular
offsets in memory. `Array`s with `StridedLayout` must conform to the `DenseArray` interface.
"""
StridedLayout

"""
MemoryLayout(A)

specifies the layout in memory for an array `A`. When
you define a new `AbstractArray` type, you can choose to override
`MemoryLayout` to indicate how an array is stored in memory.
For example, if your matrix is column major with `stride(A,2) == size(A,1)`,
then override as follows:

Base.MemoryLayout(::MyMatrix) = Base.DenseColumnMajor()

The default is `Base.UnknownLayout()` to indicate that the layout
in memory is unknown.

Julia's internal linear algebra machinery will automatically (and invisibly)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say this part in the AbstractStridedLayout section

dispatch to BLAS and LAPACK routines if the memory layout is compatible.
"""
MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout()
MemoryLayout(A::DenseArray{T}) where T = DenseColumnMajor()



function isassigned(a::AbstractArray, i::Int...)
try
a[i...]
Expand Down Expand Up @@ -379,6 +511,50 @@ function trailingsize(inds::Indices)
prod(map(unsafe_length, inds))
end

## Traits for array types ##

abstract type IndexStyle end
struct IndexLinear <: IndexStyle end
struct IndexCartesian <: IndexStyle end

"""
IndexStyle(A)
IndexStyle(typeof(A))

`IndexStyle` specifies the "native indexing style" for array `A`. When
you define a new `AbstractArray` type, you can choose to implement
either linear indexing or cartesian indexing. If you decide to
implement linear indexing, then you must set this trait for your array
type:

Base.IndexStyle(::Type{<:MyArray}) = IndexLinear()

The default is `IndexCartesian()`.

Julia's internal indexing machinery will automatically (and invisibly)
convert all indexing operations into the preferred style. This allows users
to access elements of your array using any indexing style, even when explicit
methods have not been provided.

If you define both styles of indexing for your `AbstractArray`, this
trait can be used to select the most performant indexing style. Some
methods check this trait on their inputs, and dispatch to different
algorithms depending on the most efficient access pattern. In
particular, [`eachindex`](@ref) creates an iterator whose type depends
on the setting of this trait.
"""
IndexStyle(A::AbstractArray) = IndexStyle(typeof(A))
IndexStyle(::Type{Union{}}) = IndexLinear()
IndexStyle(::Type{<:AbstractArray}) = IndexCartesian()
IndexStyle(::Type{<:Array}) = IndexLinear()
IndexStyle(::Type{<:AbstractRange}) = IndexLinear()

IndexStyle(A::AbstractArray, B::AbstractArray) = IndexStyle(IndexStyle(A), IndexStyle(B))
IndexStyle(A::AbstractArray, B::AbstractArray...) = IndexStyle(IndexStyle(A), IndexStyle(B...))
IndexStyle(::IndexLinear, ::IndexLinear) = IndexLinear()
IndexStyle(::IndexStyle, ::IndexStyle) = IndexCartesian()


## Bounds checking ##

# The overall hierarchy is
Expand Down
6 changes: 6 additions & 0 deletions base/reinterpretarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ function size(a::ReinterpretArray{T,N,S} where {N}) where {T,S}
tuple(size1, tail(psize)...)
end


MemoryLayout(A::ReinterpretArray) = reinterpretedmemorylayout(MemoryLayout(parent(A)))
reinterpretedmemorylayout(::MemoryLayout) = UnknownLayout()
reinterpretedmemorylayout(::DenseColumnMajor) = DenseColumnMajor()


elsize(::Type{<:ReinterpretArray{T}}) where {T} = sizeof(T)
unsafe_convert(::Type{Ptr{T}}, a::ReinterpretArray{T,N,S} where N) where {T,S} = Ptr{T}(unsafe_convert(Ptr{S},a.parent))

Expand Down
5 changes: 5 additions & 0 deletions base/reshapedarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -251,4 +251,9 @@ setindex!(A::ReshapedRange, val, index::ReshapedIndex) = _rs_setindex!_err()

@noinline _rs_setindex!_err() = error("indexed assignment fails for a reshaped range; consider calling collect")


MemoryLayout(A::ReshapedArray) = reshapedmemorylayout(MemoryLayout(parent(A)))
reshapedmemorylayout(::MemoryLayout) = UnknownLayout()
reshapedmemorylayout(::DenseColumnMajor) = DenseColumnMajor()

unsafe_convert(::Type{Ptr{T}}, a::ReshapedArray{T}) where {T} = unsafe_convert(Ptr{T}, parent(a))
76 changes: 76 additions & 0 deletions base/subarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,82 @@ find_extended_inds(::ScalarIndex, I...) = (@_inline_meta; find_extended_inds(I..
find_extended_inds(i1, I...) = (@_inline_meta; (i1, find_extended_inds(I...)...))
find_extended_inds() = ()

MemoryLayout(A::SubArray) = subarraylayout(MemoryLayout(parent(A)), parentindices(A))
subarraylayout(_1, _2) = UnknownLayout()
subarraylayout(_1, _2, _3)= UnknownLayout()
subarraylayout(::DenseColumnMajor, ::Tuple{I}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} =
DenseColumnMajor() # A[:] is DenseColumnMajor if A is DenseColumnMajor
subarraylayout(ml::AbstractColumnMajor, inds) = _column_subarraylayout1(ml, inds)
subarraylayout(::AbstractRowMajor, ::Tuple{I}) where I =
UnknownLayout() # A[:] does not have any structure if A is AbstractRowMajor
subarraylayout(ml::AbstractRowMajor, inds) = _row_subarraylayout1(ml, reverse(inds))
subarraylayout(ml::AbstractStridedLayout, inds) = _strided_subarraylayout(ml, inds)

_column_subarraylayout1(::DenseColumnMajor, inds::Tuple{I,Vararg{Int}}) where I<:Union{Int,AbstractCartesianIndex} =
DenseColumnMajor() # view(A,1,1,2) is a scalar, which we include in DenseColumnMajor
_column_subarraylayout1(::DenseColumnMajor, inds::Tuple{I,Vararg{Int}}) where I<:Slice =
DenseColumnMajor() # view(A,:,1,2) is a DenseColumnMajor vector
_column_subarraylayout1(::DenseColumnMajor, inds::Tuple{I,Vararg{Int}}) where I<:AbstractUnitRange{Int} =
DenseColumnMajor() # view(A,1:3,1,2) is a DenseColumnMajor vector
_column_subarraylayout1(par, inds::Tuple{I,Vararg{Int}}) where I<:Union{Int,AbstractCartesianIndex} =
DenseColumnMajor() # view(A,1,1,2) is a scalar, which we include in DenseColumnMajor
_column_subarraylayout1(par, inds::Tuple{I,Vararg{Int}}) where I<:AbstractUnitRange{Int} =
DenseColumnMajor() # view(A,1:3,1,2) is a DenseColumnMajor vector
_column_subarraylayout1(::DenseColumnMajor, inds::Tuple{I,Vararg{Any}}) where I<:Slice =
_column_subarraylayout(DenseColumnMajor(), DenseColumnMajor(), tail(inds))
_column_subarraylayout1(par::DenseColumnMajor, inds::Tuple{I,Vararg{Any}}) where I<:AbstractUnitRange{Int} =
_column_subarraylayout(par, ColumnMajor(), tail(inds))
_column_subarraylayout1(par, inds::Tuple{I,Vararg{Any}}) where I<:AbstractUnitRange{Int} =
_column_subarraylayout(par, ColumnMajor(), tail(inds))
_column_subarraylayout1(par::DenseColumnMajor, inds::Tuple{I,Vararg{Any}}) where I<:Union{RangeIndex,AbstractCartesianIndex} =
_column_subarraylayout(par, StridedLayout(), tail(inds))
_column_subarraylayout1(par, inds::Tuple{I,Vararg{Any}}) where I<:Union{RangeIndex,AbstractCartesianIndex} =
_column_subarraylayout(par, StridedLayout(), tail(inds))
_column_subarraylayout1(par, inds) = UnknownLayout()
_column_subarraylayout(par, ret, ::Tuple{}) = ret
_column_subarraylayout(par, ret, ::Tuple{I}) where I = UnknownLayout()
_column_subarraylayout(::DenseColumnMajor, ::DenseColumnMajor, inds::Tuple{I,Vararg{Int}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} =
DenseColumnMajor() # A[:,1:3,1,2] is DenseColumnMajor if A is DenseColumnMajor
_column_subarraylayout(par::DenseColumnMajor, ::DenseColumnMajor, inds::Tuple{I, Vararg{Int}}) where I<:Slice =
DenseColumnMajor()
_column_subarraylayout(par::DenseColumnMajor, ::DenseColumnMajor, inds::Tuple{I, Vararg{Any}}) where I<:Slice =
_column_subarraylayout(par, DenseColumnMajor(), tail(inds))
_column_subarraylayout(par, ::AbstractColumnMajor, inds::Tuple{I, Vararg{Any}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} =
_column_subarraylayout(par, ColumnMajor(), tail(inds))
_column_subarraylayout(par, ::AbstractStridedLayout, inds::Tuple{I, Vararg{Any}}) where I<:Union{RangeIndex,AbstractCartesianIndex} =
_column_subarraylayout(par, StridedLayout(), tail(inds))

_row_subarraylayout1(par, inds::Tuple{I,Vararg{Int}}) where I<:Union{Int,AbstractCartesianIndex} =
DenseColumnMajor() # view(A,1,1,2) is a scalar, which we include in DenseColumnMajor
_row_subarraylayout1(::DenseRowMajor, inds::Tuple{I,Vararg{Int}}) where I<:Slice =
DenseColumnMajor() # view(A,1,2,:) is a DenseColumnMajor vector
_row_subarraylayout1(par, inds::Tuple{I,Vararg{Int}}) where I<:AbstractUnitRange{Int} =
DenseColumnMajor() # view(A,1,2,1:3) is a DenseColumnMajor vector
_row_subarraylayout1(::DenseRowMajor, inds::Tuple{I,Vararg{Any}}) where I<:Slice =
_row_subarraylayout(DenseRowMajor(), DenseRowMajor(), tail(inds))
_row_subarraylayout1(par, inds::Tuple{I,Vararg{Any}}) where I<:AbstractUnitRange{Int} =
_row_subarraylayout(par, RowMajor(), tail(inds))
_row_subarraylayout1(par, inds::Tuple{I,Vararg{Any}}) where I<:Union{RangeIndex,AbstractCartesianIndex} =
_row_subarraylayout(par, StridedLayout(), tail(inds))
_row_subarraylayout1(par, inds) = UnknownLayout()
_row_subarraylayout(par, ret, ::Tuple{}) = ret
_row_subarraylayout(par, ret, ::Tuple{I}) where I = UnknownLayout()
_row_subarraylayout(::DenseRowMajor, ::DenseRowMajor, inds::Tuple{I,Vararg{Int}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} =
DenseRowMajor() # A[1,2,1:3,:] is DenseRowMajor if A is DenseRowMajor
_row_subarraylayout(par::DenseRowMajor, ::DenseRowMajor, inds::Tuple{I, Vararg{Int}}) where I<:Slice =
DenseRowMajor()
_row_subarraylayout(par::DenseRowMajor, ::DenseRowMajor, inds::Tuple{I, Vararg{Any}}) where I<:Slice =
_row_subarraylayout(par, DenseRowMajor(), tail(inds))
_row_subarraylayout(par::AbstractRowMajor, ::AbstractRowMajor, inds::Tuple{I, Vararg{Any}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} =
_row_subarraylayout(par, RowMajor(), tail(inds))
_row_subarraylayout(par::AbstractRowMajor, ::AbstractStridedLayout, inds::Tuple{I, Vararg{Any}}) where I<:Union{RangeIndex,AbstractCartesianIndex} =
_row_subarraylayout(par, StridedLayout(), tail(inds))

_strided_subarraylayout(par, inds) = UnknownLayout()
_strided_subarraylayout(par, ::Tuple{}) = StridedLayout()
_strided_subarraylayout(par, inds::Tuple{I, Vararg{Any}}) where I<:Union{RangeIndex,AbstractCartesianIndex} =
_strided_subarraylayout(par, tail(inds))

unsafe_convert(::Type{Ptr{T}}, V::SubArray{T,N,P,<:Tuple{Vararg{RangeIndex}}}) where {T,N,P} =
unsafe_convert(Ptr{T}, V.parent) + (first_index(V)-1)*sizeof(T)

Expand Down
2 changes: 2 additions & 0 deletions doc/src/manual/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ ourselves, we can officially define it as a subtype of an [`AbstractArray`](@ref
| `similar(A, ::Type{S})` | `similar(A, S, size(A))` | Return a mutable array with the same shape and the specified element type |
| `similar(A, dims::NTuple{Int})` | `similar(A, eltype(A), dims)` | Return a mutable array with the same element type and size *dims* |
| `similar(A, ::Type{S}, dims::NTuple{Int})` | `Array{S}(undef, dims)` | Return a mutable array with the specified element type and size |
| `Base.MemoryLayout(A)` | `Base.UnknownLayout()` | Return a subtype of `Base.MemoryLayout`, e.g. `Base.ColumnMajor()` |
| **Non-traditional indices** | **Default definition** | **Brief description** |
| `axes(A)` | `map(OneTo, size(A))` | Return the `AbstractUnitRange` of valid indices |
| `Base.similar(A, ::Type{S}, inds::NTuple{Ind})` | `similar(A, S, Base.to_shape(inds))` | Return a mutable array with the specified indices `inds` (see below) |
Expand Down Expand Up @@ -401,6 +402,7 @@ perhaps range-types `Ind` of your own design. For more information, see
|:----------------------------------------------- |:-------------------------------------- |:------------------------------------------------------------------------------------- |
| `strides(A)` |   | Return the distance in memory (in number of elements) between adjacent elements in each dimension as a tuple. If `A` is an `AbstractArray{T,0}`, this should return an empty tuple. |
| `Base.unsafe_convert(::Type{Ptr{T}}, A)` |   | Return the native address of an array. |
| `Base.MemoryLayout(A)` | | Return a subtype of `Base.AbstractStridedLayout`, such as `Base.DenseColumnMajor()`,`Base.DenseRowMajor()`, or `Base.StridedLayout()`.
| **Optional methods** | **Default definition** | **Brief description** |
| `stride(A, i::Int)` |   `strides(A)[i]` | Return the distance in memory (in number of elements) between adjacent elements in dimension k. |

Expand Down
2 changes: 1 addition & 1 deletion stdlib/IterativeEigensolvers/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ using Test, LinearAlgebra, SparseArrays, Random
k = 3
A = randn(n,n); A = A'A
B = randn(n,k); B = B*B'
@test sort(eigs(A, B, nev = k, sigma = 1.0)[1]) ≈ sort(eigvals(A, B)[1:k])
@test sort(eigs(A, B, nev = k, sigma = 1.0)[1]) ≈ sort(filter(isfinite, eigvals(A, B)))
end
end

Expand Down
10 changes: 7 additions & 3 deletions stdlib/LinearAlgebra/src/LinearAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ import Base: USE_BLAS64, abs, acos, acosh, acot, acoth, acsc, acsch, adjoint, as
getproperty, imag, inv, isapprox, isone, IndexStyle, kron, length, log, map, ndims,
oneunit, parent, power_by_squaring, print_matrix, promote_rule, real, round, sec, sech,
setindex!, show, similar, sin, sincos, sinh, size, size_to_strides, sqrt, StridedReinterpretArray,
StridedReshapedArray, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec
StridedReshapedArray, ReshapedArray, ReinterpretArray, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec,
MemoryLayout, UnknownLayout, AbstractStridedLayout, AbstractRowMajor, AbstractColumnMajor, DenseRowMajor, DenseColumnMajor,
ColumnMajor, RowMajor, StridedLayout
using Base: hvcat_fill, iszero, IndexLinear, _length, promote_op, promote_typeof,
@propagate_inbounds, @pure, reduce, typed_vcat
using Base.Broadcast: Broadcasted


# We use `_length` because of non-1 indices; releases after julia 0.5
# can go back to `length`. `_length(A)` is equivalent to `length(LinearIndices(A))`.

Expand Down Expand Up @@ -201,8 +204,9 @@ julia> LinearAlgebra.stride1(B)
```
"""
stride1(x) = stride(x,1)
stride1(x::Array) = 1
stride1(x::DenseArray) = stride(x, 1)::Int
stride1(x::AbstractArray) = _stride1(x, MemoryLayout(x))
_stride1(x, _) = stride(x, 1)::Int
_stride1(x, ::AbstractColumnMajor) = 1

@inline chkstride1(A...) = _chkstride1(true, A...)
@noinline _chkstride1(ok::Bool) = ok || error("matrix does not have contiguous columns")
Expand Down
Loading