From e86e8bbb9eaed37d473df541a8921a8e898864ae Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sun, 14 Jan 2018 18:59:47 +0000 Subject: [PATCH 01/39] Added MemoryLayout, rewrote mul! to be based on memory layout --- base/abstractarray.jl | 3 +- base/linalg/adjtrans.jl | 14 ++++ base/linalg/dense.jl | 39 +++++---- base/linalg/linalg.jl | 41 +++++++++- base/linalg/matmul.jl | 171 ++++++++++++++-------------------------- 5 files changed, 137 insertions(+), 131 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 5a9220c2d91a4..d4b321a341f36 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -333,6 +333,7 @@ IndexStyle(A::AbstractArray, B::AbstractArray...) = IndexStyle(IndexStyle(A), In IndexStyle(::IndexLinear, ::IndexLinear) = IndexLinear() IndexStyle(::IndexStyle, ::IndexStyle) = IndexCartesian() + ## Bounds checking ## # The overall hierarchy is @@ -1790,7 +1791,7 @@ function mapslices(f, A::AbstractArray, dims::AbstractVector) # increase. The slice itself must be mutable and the result cannot contain # any mutable containers. The following errs on the side of being overly # strict (#18570 & #21123). - safe_for_reuse = isa(Aslice, StridedArray) && + safe_for_reuse = MemoryLayout(Aslice) isa StridedLayout && (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number)) # determine result size and allocate diff --git a/base/linalg/adjtrans.jl b/base/linalg/adjtrans.jl index 7f462700e5601..2b8aae682c55c 100644 --- a/base/linalg/adjtrans.jl +++ b/base/linalg/adjtrans.jl @@ -91,6 +91,8 @@ const AdjOrTransAbsMat{T} = AdjOrTrans{T,<:AbstractMatrix} wrapperop(A::Adjoint) = adjoint wrapperop(A::Transpose) = transpose + + # AbstractArray interface, basic definitions length(A::AdjOrTrans) = length(A.parent) size(v::AdjOrTransAbsVec) = (1, length(v.parent)) @@ -99,6 +101,18 @@ axes(v::AdjOrTransAbsVec) = (Base.OneTo(1), axes(v.parent)...) axes(A::AdjOrTransAbsMat) = reverse(axes(A.parent)) IndexStyle(::Type{<:AdjOrTransAbsVec}) = IndexLinear() IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() + +adjoint(::MemoryLayout{T}) where {T} = UnknownLayout{T}() +adjoint(::StridedLayout{T}) where {T<:Real} = TransposeStridedLayout{T}() +adjoint(::TransposeStridedLayout{T}) where {T<:Real} = StridedLayout{T}() +adjoint(::StridedLayout{T}) where {T<:Complex} = CTransposeStridedLayout{T}() +adjoint(::CTransposeStridedLayout{T}) where {T<:Complex} = StridedLayout{T}() +transpose(::MemoryLayout{T}) where {T} = UnknownLayout{T}() +transpose(::StridedLayout{T}) where {T} = TransposeStridedLayout{T}() +transpose(::TransposeStridedLayout{T}) where {T} = StridedLayout{T}() +MemoryLayout(::Type{A}) where A<:Adjoint{T,S} where {T,S} = adjoint(MemoryLayout(S)) +MemoryLayout(::Type{A}) where A<:Transpose{T,S} where {T,S} = transpose(MemoryLayout(S)) + @propagate_inbounds getindex(v::AdjOrTransAbsVec, i::Int) = wrapperop(v)(v.parent[i]) @propagate_inbounds getindex(A::AdjOrTransAbsMat, i::Int, j::Int) = wrapperop(A)(A.parent[j, i]) @propagate_inbounds setindex!(v::AdjOrTransAbsVec, x, i::Int) = (setindex!(v.parent, wrapperop(v)(x), i); v) diff --git a/base/linalg/dense.jl b/base/linalg/dense.jl index 74e5494781034..44c15c57b6c8f 100644 --- a/base/linalg/dense.jl +++ b/base/linalg/dense.jl @@ -35,7 +35,7 @@ function scale!(X::Array{T}, s::Real) where T<:BlasComplex end -function isone(A::StridedMatrix) +function isone(A::AbstractMatrix) m, n = size(A) m != n && return false # only square matrices can satisfy x == one(x) if sizeof(A) < ISONE_CUTOFF @@ -45,7 +45,7 @@ function isone(A::StridedMatrix) end end -@inline function _isone_triacheck(A::StridedMatrix, m::Int) +@inline function _isone_triacheck(A::AbstractMatrix, m::Int) @inbounds for i in 1:m, j in i:m if i == j isone(A[i,i]) || return false @@ -57,7 +57,7 @@ end end # Inner loop over rows to be friendly to the CPU cache -@inline function _isone_cachefriendly(A::StridedMatrix, m::Int) +@inline function _isone_cachefriendly(A::AbstractMatrix, m::Int) @inbounds for i in 1:m, j in 1:m if i == j isone(A[i,i]) || return false @@ -498,12 +498,19 @@ julia> exp(A) 0.0 2.71828 ``` """ -exp(A::StridedMatrix{<:BlasFloat}) = exp!(copy(A)) -exp(A::StridedMatrix{<:Union{Integer,Complex{<:Integer}}}) = exp!(float.(A)) +exp(A::AbstractMatrix{<:BlasFloat}) = exp!(copy(A)) +exp(A::AbstractMatrix{<:Union{Integer,Complex{<:Integer}}}) = exp!(float.(A)) ## Destructive matrix exponential using algorithm from Higham, 2008, ## "Functions of Matrices: Theory and Computation", SIAM -function exp!(A::StridedMatrix{T}) where T<:BlasFloat +exp!(A::AbstractMatrix) = _exp!(A, MemoryLayout(A)) +exp!(A::AbstractMatrix, _) = + throw(ArgumentError("exp! not implemented for non-BlasFloat types.")) +function exp!(A::AbstractMatrix{T}, _) where T<:BlasFloat + A .= exp!(Matrix{T}(A)) + A +end +function _exp!(A::AbstractMatrix{T}, ::StridedLayout{T}) where T<:BlasFloat n = checksquare(A) if ishermitian(A) return copytri!(parent(exp(Hermitian(A))), 'U', true) @@ -587,7 +594,7 @@ function exp!(A::StridedMatrix{T}) where T<:BlasFloat end ## Swap rows i and j and columns i and j in X -function rcswap!(i::Integer, j::Integer, X::StridedMatrix{<:Number}) +function rcswap!(i::Integer, j::Integer, X::AbstractMatrix{<:Number}) for k = 1:size(X,1) X[k,i], X[k,j] = X[k,j], X[k,i] end @@ -597,7 +604,7 @@ function rcswap!(i::Integer, j::Integer, X::StridedMatrix{<:Number}) end """ - log(A{T}::StridedMatrix{T}) + log(A{T}::AbstractMatrix{T}) If `A` has no negative real eigenvalue, compute the principal matrix logarithm of `A`, i.e. the unique matrix ``X`` such that ``e^X = A`` and ``-\\pi < Im(\\lambda) < \\pi`` for all @@ -627,7 +634,7 @@ julia> log(A) 0.0 1.0 ``` """ -function log(A::StridedMatrix) +function log(A::AbstractMatrix) # If possible, use diagonalization if ishermitian(A) logHermA = log(Hermitian(A)) @@ -686,7 +693,7 @@ julia> sqrt(A) 0.0 2.0 ``` """ -function sqrt(A::StridedMatrix{<:Real}) +function sqrt(A::AbstractMatrix{<:Real}) if issymmetric(A) return copytri!(parent(sqrt(Symmetric(A))), 'U') end @@ -699,7 +706,7 @@ function sqrt(A::StridedMatrix{<:Real}) return SchurF.vectors * R * SchurF.vectors' end end -function sqrt(A::StridedMatrix{<:Complex}) +function sqrt(A::AbstractMatrix{<:Complex}) if ishermitian(A) sqrtHermA = sqrt(Hermitian(A)) return isa(sqrtHermA, Hermitian) ? copytri!(parent(sqrtHermA), 'U', true) : parent(sqrtHermA) @@ -1149,7 +1156,7 @@ julia> factorize(A) # factorize will check to see that A is already factorized This returns a `5×5 Bidiagonal{Float64}`, which can now be passed to other linear algebra functions (e.g. eigensolvers) which will use specialized methods for `Bidiagonal` types. """ -function factorize(A::StridedMatrix{T}) where T +function factorize(A::AbstractMatrix{T}) where T m, n = size(A) if m == n if m == 1 return A[1] end @@ -1271,7 +1278,7 @@ julia> M * N [^KY88]: Konstantinos Konstantinides and Kung Yao, "Statistical analysis of effective singular values in matrix rank determination", IEEE Transactions on Acoustics, Speech and Signal Processing, 36(5), 1988, 757-763. [doi:10.1109/29.1585](http://dx.doi.org/10.1109/29.1585) """ -function pinv(A::StridedMatrix{T}, tol::Real) where T +function pinv(A::AbstractMatrix{T}, tol::Real) where T m, n = size(A) Tout = typeof(zero(T)/sqrt(one(T) + one(T))) if m == 0 || n == 0 @@ -1300,7 +1307,7 @@ function pinv(A::StridedMatrix{T}, tol::Real) where T Sinv[find(.!isfinite.(Sinv))] = zero(Stype) return SVD.Vt' * (Diagonal(Sinv) * SVD.U') end -function pinv(A::StridedMatrix{T}) where T +function pinv(A::AbstractMatrix{T}) where T tol = eps(real(float(one(T))))*min(size(A)...) return pinv(A, tol) end @@ -1331,7 +1338,7 @@ julia> nullspace(M) 1.0 ``` """ -function nullspace(A::StridedMatrix{T}) where T +function nullspace(A::AbstractMatrix{T}) where T m, n = size(A) (m == 0 || n == 0) && return Matrix{T}(I, n, n) SVD = svdfact(A, full = true) @@ -1398,7 +1405,7 @@ julia> A*X + X*B + C -3.77476e-15 4.44089e-16 ``` """ -function sylvester(A::StridedMatrix{T},B::StridedMatrix{T},C::StridedMatrix{T}) where T<:BlasFloat +function sylvester(A::StridedMatrix{T}, B::StridedMatrix{T}, C::StridedMatrix{T}) where T<:BlasFloat RA, QA = schur(A) RB, QB = schur(B) diff --git a/base/linalg/linalg.jl b/base/linalg/linalg.jl index 99d308b764426..a28c7ab389bd7 100644 --- a/base/linalg/linalg.jl +++ b/base/linalg/linalg.jl @@ -16,7 +16,7 @@ import Base: USE_BLAS64, abs, acos, acosh, acot, acoth, acsc, acsch, adjoint, as setindex!, show, similar, sin, sincos, sinh, size, size_to_strides, sqrt, StridedReinterpretArray, StridedReshapedArray, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec using Base: hvcat_fill, iszero, IndexLinear, _length, promote_op, promote_typeof, - @propagate_inbounds, @pure, reduce, typed_vcat + @propagate_inbounds, @pure, reduce, typed_vcat, AbstractCartesianIndex # 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))`. @@ -158,6 +158,45 @@ else const BlasInt = Int32 end +## Traits for memory layouts ## + +abstract type MemoryLayout{T} end +struct UnknownLayout{T} <: MemoryLayout{T} end +struct StridedLayout{T} <: MemoryLayout{T} end +struct TransposeStridedLayout{T} <: MemoryLayout{T} end +struct CTransposeStridedLayout{T} <: MemoryLayout{T} end + +""" + MemoryLayout(A) + MemoryLayout(typeof(A)) + +`MemoryLayout` specifies the layout in memory for an array `A`. When +you define a new `AbstractArray` type, you can choose to implement +memory layout to indicate that an array is strided in memory. If you decide to +implement memory layout, then you must set this trait for your array +type: + + Base.MemoryLayout(::Type{M}) where M <: MyArray{T,N} where {T,N} = Base.StridedLayout{T,N}() + +The default is `Base.UnknownLayout{T,N}()` to indicate that the layout +in memory is unknown. + +Julia's internal linear algebra machinery will automatically (and invisibly) +dispatch to BLAS and LAPACK routines if the memory layout is BLAS 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::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)` +""" +MemoryLayout(A::AbstractArray) = MemoryLayout(typeof(A)) +MemoryLayout(::Type{A}) where A <: AbstractArray{T,N} where {T,N} = UnknownLayout{T}() +MemoryLayout(::Type{A}) where A <: Array{T,N} where {T,N} = StridedLayout{T}() +MemoryLayout(::Type{A}) where A <: SubArray{T,N,P,I} where {T,N,P,I} = + submemorylayout(MemoryLayout(P), I) + +submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() +LinAlg.submemorylayout(::StridedLayout{T}, ::Type{NTuple{N,I}}) where {T,N,I<:Union{RangeIndex, AbstractCartesianIndex}} = + StridedLayout{T}() + # Check that stride of matrix/vector is 1 # Writing like this to avoid splatting penalty when called with multiple arguments, # see PR 16416 diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 229667b4bf451..388bbec4d79b6 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -91,10 +91,12 @@ end (b = adjb.parent; *(A, adjoint(reshape(b,length(b),1)))) (*)(a::AbstractVector, B::AbstractMatrix) = reshape(a,length(a),1)*B -mul!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasFloat} = gemv!(y, 'N', A, x) + +mul!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = _mul!(y, A, x, MemoryLayout(y), MemoryLayout(A), MemoryLayout(x)) +_mul!(y::AbstractVector{T}, A::AbstractVecOrMat{T}, x::AbstractVector{T}, ::StridedLayout, ::StridedLayout, ::StridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin - function mul!(y::StridedVector{Complex{$elty}}, A::StridedVecOrMat{Complex{$elty}}, x::StridedVector{$elty}) + function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractVecOrMat{Complex{$elty}}, x::AbstractVector{$elty}, ::StridedLayout, ::StridedLayout, ::StridedLayout) Afl = reinterpret($elty,A) yfl = reinterpret($elty,y) gemv!(yfl,'N',Afl,x) @@ -102,7 +104,7 @@ for elty in (Float32,Float64) end end end -mul!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = generic_matvecmul!(y, 'N', A, x) +_mul!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) function *(transA::Transpose{<:Any,<:StridedMatrix{T}}, x::StridedVector{S}) where {T<:BlasFloat,S} A = transA.parent @@ -114,28 +116,16 @@ function *(transA::Transpose{<:Any,<:AbstractMatrix{T}}, x::AbstractVector{S}) w TS = promote_op(matprod, T, S) mul!(similar(x,TS,size(A,2)), transpose(A), x) end -mul!(y::StridedVector{T}, transA::Transpose{<:Any,<:StridedVecOrMat{T}}, x::StridedVector{T}) where {T<:BlasFloat} = - (A = transA.parent; gemv!(y, 'T', A, x)) -mul!(y::AbstractVector, transA::Transpose{<:Any,<:AbstractVecOrMat}, x::AbstractVector) = - (A = transA.parent; generic_matvecmul!(y, 'T', A, x)) -function *(adjA::Adjoint{<:Any,<:StridedMatrix{T}}, x::StridedVector{S}) where {T<:BlasFloat,S} - A = adjA.parent - TS = promote_op(matprod, T, S) - mul!(similar(x,TS,size(A,2)), adjoint(A) ,convert(AbstractVector{TS},x)) -end -function *(adjA::Adjoint{<:Any,<:AbstractMatrix{T}}, x::AbstractVector{S}) where {T,S} - A = adjA.parent - TS = promote_op(matprod, T, S) - mul!(similar(x,TS,size(A,2)), adjoint(A), x) -end - -mul!(y::StridedVector{T}, adjA::Adjoint{<:Any,<:StridedVecOrMat{T}}, x::StridedVector{T}) where {T<:BlasReal} = - (A = adjA.parent; mul!(y, transpose(A), x)) -mul!(y::StridedVector{T}, adjA::Adjoint{<:Any,<:StridedVecOrMat{T}}, x::StridedVector{T}) where {T<:BlasComplex} = - (A = adjA.parent; gemv!(y, 'C', A, x)) -mul!(y::AbstractVector, adjA::Adjoint{<:Any,<:AbstractVecOrMat}, x::AbstractVector) = +_mul!(y::AbstractVector, transA::Transpose{<:Any,<:AbstractVecOrMat}, x::AbstractVector, _1, _2, _3) = + (A = transA.parent; generic_matvecmul!(y, 'T', A, x)) +_mul!(y::AbstractVector, adjA::Adjoint{<:Any,<:AbstractVecOrMat}, x::AbstractVector, _1, _2, _3) = (A = adjA.parent; generic_matvecmul!(y, 'C', A, x)) +_mul!(y::AbstractVector{T}, adjA::AbstractVecOrMat{T}, x::AbstractVector{T}, ::StridedLayout, ::TransposeStridedLayout, ::StridedLayout) where {T<:BlasComplex} = + gemv!(y, 'T', transpose(adjA), x) +_mul!(y::AbstractVector{T}, adjA::AbstractVecOrMat{T}, x::AbstractVector{T}, ::StridedLayout, ::CTransposeStridedLayout, ::StridedLayout) where {T<:BlasComplex} = + gemv!(y, 'C', adjoint(adjA), x) + # Matrix-matrix multiplication @@ -158,17 +148,6 @@ function (*)(A::AbstractMatrix, B::AbstractMatrix) TS = promote_op(matprod, eltype(A), eltype(B)) mul!(similar(B, TS, (size(A,1), size(B,2))), A, B) end -mul!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = gemm_wrapper!(C, 'N', 'N', A, B) -for elty in (Float32,Float64) - @eval begin - function mul!(C::StridedMatrix{Complex{$elty}}, A::StridedVecOrMat{Complex{$elty}}, B::StridedVecOrMat{$elty}) - Afl = reinterpret($elty, A) - Cfl = reinterpret($elty, C) - gemm_wrapper!(Cfl, 'N', 'N', Afl, B) - return C - end - end -end """ mul!(Y, A, B) -> Y @@ -187,7 +166,7 @@ julia> Y 7.0 7.0 ``` """ -mul!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'N', A, B) +mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) """ mul!(A, B) @@ -197,27 +176,32 @@ and return the result (the overwritten argument). """ mul!(A, B) -function *(transA::Transpose{<:Any,<:AbstractMatrix}, B::AbstractMatrix) - A = transA.parent - TS = promote_op(matprod, eltype(A), eltype(B)) - mul!(similar(B, TS, (size(A,2), size(B,2))), transpose(A), B) +_mul!(C::AbstractVecOrMat{T}, A::AbstractVecOrMat{T}, B::AbstractVecOrMat{T}, ::StridedLayout, ::StridedLayout, ::StridedLayout) where {T<:BlasFloat} = + gemm_wrapper!(C, 'N', 'N', A, B) +for elty in (Float32,Float64) + @eval begin + function _mul!(C::AbstractVecOrMat{Complex{$elty}}, A::AbstractVecOrMat{Complex{$elty}}, B::AbstractVecOrMat{$elty}, ::StridedLayout, ::StridedLayout, ::StridedLayout) + Afl = reinterpret($elty, A) + Cfl = reinterpret($elty, C) + gemm_wrapper!(Cfl, 'N', 'N', Afl, B) + return C + end + end end -mul!(C::StridedMatrix{T}, transA::Transpose{<:Any,<:StridedVecOrMat{T}}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = - (A = transA.parent; A===B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)) -mul!(C::AbstractMatrix, transA::Transpose{<:Any,<:AbstractVecOrMat}, B::AbstractVecOrMat) = - (A = transA.parent; generic_matmatmul!(C, 'T', 'N', A, B)) +_mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat, _1, _2, _3) = generic_matmatmul!(C, 'N', 'N', A, B) -function *(A::AbstractMatrix, transB::Transpose{<:Any,<:AbstractMatrix}) - B = transB.parent - TS = promote_op(matprod, eltype(A), eltype(B)) - mul!(similar(B, TS, (size(A,1), size(B,1))), A, transpose(B)) -end -mul!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, transB::Transpose{<:Any,<:StridedVecOrMat{T}}) where {T<:BlasFloat} = - (B = transB.parent; A===B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)) + +_mul!(C::AbstractVecOrMat{T}, transA::AbstractMatrix{T}, B::AbstractVecOrMat{T}, ::StridedLayout, ::TransposeStridedLayout, ::StridedLayout) where {T<:BlasFloat} = + (A = transpose(transA); A === B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)) +_mul!(C::AbstractVecOrMat, transA::AbstractVecOrMat, B::AbstractVecOrMat, _, ::TransposeStridedLayout, ::StridedLayout) = + (A = transpose(transA); generic_matmatmul!(C, 'T', 'N', A, B)) + +_mul!(C::AbstractVecOrMat{T}, A::AbstractVecOrMat{T}, transB::AbstractVecOrMat{T}, ::StridedLayout, ::StridedLayout, ::TransposeStridedLayout) where {T<:BlasFloat} = + (B = transpose(transB); A === B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)) for elty in (Float32,Float64) @eval begin - function mul!(C::StridedMatrix{Complex{$elty}}, A::StridedVecOrMat{Complex{$elty}}, transB::Transpose{<:Any,<:StridedVecOrMat{$elty}}) - B = transB.parent + function _mul!(C::AbstractVecOrMat{Complex{$elty}}, A::AbstractVecOrMat{Complex{$elty}}, transB::AbstractVecOrMat{$elty}, ::StridedLayout, ::StridedLayout, ::TransposeStridedLayout) + B = transpose(transB) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) gemm_wrapper!(Cfl, 'N', 'T', Afl, B) @@ -225,66 +209,27 @@ for elty in (Float32,Float64) end end end -# collapsing the following two defs with C::AbstractVecOrMat yields ambiguities -mul!(C::AbstractVector, A::AbstractVecOrMat, transB::Transpose{<:Any,<:AbstractVecOrMat}) = - _disambigmul!(C, A, transB) -mul!(C::AbstractMatrix, A::AbstractVecOrMat, transB::Transpose{<:Any,<:AbstractVecOrMat}) = - _disambigmul!(C, A, transB) -_disambigmul!(C::AbstractVecOrMat, A::AbstractVecOrMat, transB::Transpose{<:Any,<:AbstractVecOrMat}) = - (B = transB.parent; generic_matmatmul!(C, 'N', 'T', A, B)) - -# collapsing the following two defs with transB::Transpose{<:Any,<:AbstractVecOrMat{S}} yields ambiguities -*(transA::Transpose{<:Any,<:AbstractMatrix}, transB::Transpose{<:Any,<:AbstractMatrix}) = - _disambigmul(transA, transB) -*(transA::Transpose{<:Any,<:AbstractMatrix}, transB::Transpose{<:Any,<:AbstractVector}) = - _disambigmul(transA, transB) -function _disambigmul(transA::Transpose{<:Any,<:AbstractMatrix{T}}, transB::Transpose{<:Any,<:AbstractVecOrMat{S}}) where {T,S} - A, B = transA.parent, transB.parent - TS = promote_op(matprod, T, S) - mul!(similar(B, TS, (size(A,2), size(B,1))), transpose(A), transpose(B)) -end -mul!(C::StridedMatrix{T}, transA::Transpose{<:Any,<:StridedVecOrMat{T}}, transB::Transpose{<:Any,<:StridedVecOrMat{T}}) where {T<:BlasFloat} = - (A = transA.parent; B = transB.parent; gemm_wrapper!(C, 'T', 'T', A, B)) -mul!(C::AbstractMatrix, transA::Transpose{<:Any,<:AbstractVecOrMat}, transB::Transpose{<:Any,<:AbstractVecOrMat}) = - (A = transA.parent; B = transB.parent; generic_matmatmul!(C, 'T', 'T', A, B)) -mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractVecOrMat}, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, copy(B)) - -*(adjA::Adjoint{<:Any,<:StridedMatrix{T}}, B::StridedMatrix{T}) where {T<:BlasReal} = - (A = adjA.parent; *(transpose(A), B)) -mul!(C::StridedMatrix{T}, adjA::Adjoint{<:Any,<:StridedVecOrMat{T}}, B::StridedVecOrMat{T}) where {T<:BlasReal} = - (A = adjA.parent; mul!(C, transpose(A), B)) -function *(adjA::Adjoint{<:Any,<:AbstractMatrix}, B::AbstractMatrix) - A = adjA.parent - TS = promote_op(matprod, eltype(A), eltype(B)) - mul!(similar(B, TS, (size(A,2), size(B,2))), adjoint(A), B) -end -mul!(C::StridedMatrix{T}, adjA::Adjoint{<:Any,<:StridedVecOrMat{T}}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = - (A = adjA.parent; A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)) -mul!(C::AbstractMatrix, adjA::Adjoint{<:Any,<:AbstractVecOrMat}, B::AbstractVecOrMat) = - (A = adjA.parent; generic_matmatmul!(C, 'C', 'N', A, B)) - -*(A::StridedMatrix{<:BlasFloat}, adjB::Adjoint{<:Any,<:StridedMatrix{<:BlasReal}}) = - (B = adjB.parent; *(A, transpose(B))) -mul!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, adjB::Adjoint{<:Any,<:StridedVecOrMat{<:BlasReal}}) where {T<:BlasFloat} = - (B = adjB.parent; mul!(C, A, transpose(B))) -function *(A::AbstractMatrix, adjB::Adjoint{<:Any,<:AbstractMatrix}) - B = adjB.parent - TS = promote_op(matprod, eltype(A), eltype(B)) - mul!(similar(B,TS,(size(A,1),size(B,1))), A, adjoint(B)) -end -mul!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, adjB::Adjoint{<:Any,<:StridedVecOrMat{T}}) where {T<:BlasComplex} = - (B = adjB.parent; A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)) -mul!(C::AbstractMatrix, A::AbstractVecOrMat, adjB::Adjoint{<:Any,<:AbstractVecOrMat}) = - (B = adjB.parent; generic_matmatmul!(C, 'N', 'C', A, B)) - -*(adjA::Adjoint{<:Any,<:AbstractMatrix}, adjB::Adjoint{<:Any,<:AbstractMatrix}) = - (A = adjA.parent; B = adjB.parent; mul!(similar(B, promote_op(matprod, eltype(A), eltype(B)), (size(A,2), size(B,1))), adjoint(A), adjoint(B))) -mul!(C::StridedMatrix{T}, adjA::Adjoint{<:Any,<:StridedVecOrMat{T}}, adjB::Adjoint{<:Any,<:StridedVecOrMat{T}}) where {T<:BlasFloat} = - (A = adjA.parent; B = adjB.parent; gemm_wrapper!(C, 'C', 'C', A, B)) -mul!(C::AbstractMatrix, adjA::Adjoint{<:Any,<:AbstractVecOrMat}, adjB::Adjoint{<:Any,<:AbstractVecOrMat}) = - (A = adjA.parent; B = adjB.parent; generic_matmatmul!(C, 'C', 'C', A, B)) -mul!(C::AbstractMatrix, adjA::Adjoint{<:Any,<:AbstractVecOrMat}, transB::Transpose{<:Any,<:AbstractVecOrMat}) = - (A = adjA.parent; B = transB.parent; generic_matmatmul!(C, 'C', 'T', A, B)) +_mul!(C::AbstractVecOrMat{T}, transA::AbstractVecOrMat{T}, transB::AbstractVecOrMat{T}, ::StridedLayout, ::TransposeStridedLayout, ::TransposeStridedLayout) where {T<:BlasFloat} = + (A = transpose(transA); B = transpose(transB); gemm_wrapper!(C, 'T', 'T', A, B)) +_mul!(C::AbstractVecOrMat, transA::AbstractVecOrMat, transB::AbstractVecOrMat, _1, ::TransposeStridedLayout, ::TransposeStridedLayout) = + (A = transpose(transA); B = transpose(transB); generic_matmatmul!(C, 'T', 'T', A, B)) + +_mul!(C::AbstractVecOrMat{T}, adjA::AbstractVecOrMat{T}, B::AbstractVecOrMat{T}, ::StridedLayout, ::CTransposeStridedLayout, ::StridedLayout) where {T<:BlasComplex} = + (A = adjoint(adjA); A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)) +_mul!(C::AbstractVecOrMat, adjA::AbstractVecOrMat, B::AbstractVecOrMat, _, ::CTransposeStridedLayout, ::StridedLayout) = + (A = adjoint(adjA); generic_matmatmul!(C, 'C', 'N', A, B)) + +_mul!(C::AbstractVecOrMat{T}, A::AbstractVecOrMat{T}, adjB::AbstractVecOrMat{T}, ::StridedLayout, ::StridedLayout, ::CTransposeStridedLayout) where {T<:BlasComplex} = + (B = adjoint(adjB); A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)) +_mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, adjB::AbstractVecOrMat, _, ::StridedLayout, ::CTransposeStridedLayout) = + (B = adjoint(adjB); generic_matmatmul!(C, 'N', 'C', A, B)) + +_mul!(C::AbstractVecOrMat{T}, adjA::AbstractVecOrMat{T}, adjB::AbstractVecOrMat{T}, ::StridedLayout, ::CTransposeStridedLayout, ::CTransposeStridedLayout) where {T<:BlasFloat} = + (A = adjoint(adjA); B = adjoint(adjB); gemm_wrapper!(C, 'C', 'C', A, B)) +_mul!(C::AbstractVecOrMat, adjA::AbstractVecOrMat, adjB::AbstractVecOrMat, _, ::CTransposeStridedLayout, ::CTransposeStridedLayout) = + (A = adjoint(adjA); B = adjoint(adjB); generic_matmatmul!(C, 'C', 'C', A, B)) +_mul!(C::AbstractVecOrMat, adjA::AbstractVecOrMat, transB::AbstractVecOrMat, _, ::CTransposeStridedLayout, ::TransposeStridedLayout) = + (A = adjoint(adjA); B = transpose(transB); generic_matmatmul!(C, 'C', 'T', A, B)) # Supporting functions for matrix multiplication function copytri!(A::AbstractMatrix, uplo::Char, conjugate::Bool=false) @@ -511,7 +456,7 @@ function generic_matvecmul!(C::AbstractVector{R}, tA, A::AbstractVecOrMat, B::Ab C end -function generic_matmatmul(tA, tB, A::AbstractVecOrMat{T}, B::AbstractMatrix{S}) where {T,S} +function (tA, tB, A::AbstractVecOrMat{T}, B::AbstractMatrix{S}) where {T,S} mA, nA = lapack_size(tA, A) mB, nB = lapack_size(tB, B) C = similar(B, promote_op(matprod, T, S), mA, nB) From 1d80d44f585f6dcdb5a9aaa367423cfcf20c34ab Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Tue, 16 Jan 2018 20:26:59 +0000 Subject: [PATCH 02/39] MemoryLayout implemented for instances not types, improved mul! type definitions --- base/linalg/adjtrans.jl | 12 ++-- base/linalg/linalg.jl | 23 ++++---- base/linalg/matmul.jl | 127 +++++++++++++++++++--------------------- 3 files changed, 80 insertions(+), 82 deletions(-) diff --git a/base/linalg/adjtrans.jl b/base/linalg/adjtrans.jl index 2b8aae682c55c..c2c91afd9bc1e 100644 --- a/base/linalg/adjtrans.jl +++ b/base/linalg/adjtrans.jl @@ -103,13 +103,13 @@ IndexStyle(::Type{<:AdjOrTransAbsVec}) = IndexLinear() IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() adjoint(::MemoryLayout{T}) where {T} = UnknownLayout{T}() -adjoint(::StridedLayout{T}) where {T<:Real} = TransposeStridedLayout{T}() -adjoint(::TransposeStridedLayout{T}) where {T<:Real} = StridedLayout{T}() -adjoint(::StridedLayout{T}) where {T<:Complex} = CTransposeStridedLayout{T}() -adjoint(::CTransposeStridedLayout{T}) where {T<:Complex} = StridedLayout{T}() +adjoint(::StridedLayout{T}) where {T<:Real} = TransposeLayout{T}() +adjoint(::TransposeLayout{T}) where {T<:Real} = StridedLayout{T}() +adjoint(::StridedLayout{T}) where {T<:Complex} = CTransposeLayout{T}() +adjoint(::CTransposeLayout{T}) where {T<:Complex} = StridedLayout{T}() transpose(::MemoryLayout{T}) where {T} = UnknownLayout{T}() -transpose(::StridedLayout{T}) where {T} = TransposeStridedLayout{T}() -transpose(::TransposeStridedLayout{T}) where {T} = StridedLayout{T}() +transpose(::StridedLayout{T}) where {T} = TransposeLayout{T}() +transpose(::TransposeLayout{T}) where {T} = StridedLayout{T}() MemoryLayout(::Type{A}) where A<:Adjoint{T,S} where {T,S} = adjoint(MemoryLayout(S)) MemoryLayout(::Type{A}) where A<:Transpose{T,S} where {T,S} = transpose(MemoryLayout(S)) diff --git a/base/linalg/linalg.jl b/base/linalg/linalg.jl index a28c7ab389bd7..78fb43566505e 100644 --- a/base/linalg/linalg.jl +++ b/base/linalg/linalg.jl @@ -16,7 +16,7 @@ import Base: USE_BLAS64, abs, acos, acosh, acot, acoth, acsc, acsch, adjoint, as setindex!, show, similar, sin, sincos, sinh, size, size_to_strides, sqrt, StridedReinterpretArray, StridedReshapedArray, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec using Base: hvcat_fill, iszero, IndexLinear, _length, promote_op, promote_typeof, - @propagate_inbounds, @pure, reduce, typed_vcat, AbstractCartesianIndex + @propagate_inbounds, @pure, reduce, typed_vcat, AbstractCartesianIndex, RangeIndex # 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))`. @@ -163,8 +163,12 @@ end abstract type MemoryLayout{T} end struct UnknownLayout{T} <: MemoryLayout{T} end struct StridedLayout{T} <: MemoryLayout{T} end -struct TransposeStridedLayout{T} <: MemoryLayout{T} end -struct CTransposeStridedLayout{T} <: MemoryLayout{T} end +struct TransposeLayout{T} <: MemoryLayout{T} end +struct CTransposeLayout{T} <: MemoryLayout{T} end +struct LowerTriangularLayout{trans,T} <: MemoryLayout{T} end +struct UnitLowerTriangularLayout{trans,T} <: MemoryLayout{T} end +struct UpperTriangularLayout{trans,T} <: MemoryLayout{T} end +struct UnitUpperTriangularLayout{trans,T} <: MemoryLayout{T} end """ MemoryLayout(A) @@ -187,15 +191,14 @@ 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::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)` """ -MemoryLayout(A::AbstractArray) = MemoryLayout(typeof(A)) -MemoryLayout(::Type{A}) where A <: AbstractArray{T,N} where {T,N} = UnknownLayout{T}() -MemoryLayout(::Type{A}) where A <: Array{T,N} where {T,N} = StridedLayout{T}() -MemoryLayout(::Type{A}) where A <: SubArray{T,N,P,I} where {T,N,P,I} = - submemorylayout(MemoryLayout(P), I) +MemoryLayout(A::AbstractArray{T,N}) where {T,N} = UnknownLayout{T}() +MemoryLayout(A::Vector{T}) where {T} = StridedLayout{T}() +MemoryLayout(A::Matrix{T}) where {T} = StridedLayout{T}() +MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() -LinAlg.submemorylayout(::StridedLayout{T}, ::Type{NTuple{N,I}}) where {T,N,I<:Union{RangeIndex, AbstractCartesianIndex}} = - StridedLayout{T}() +submemorylayout(S::StridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex, AbstractCartesianIndex}} = S +submemorylayout(S::StridedLayout{T}, ::NTuple{2,I}) where {T,I<:Union{RangeIndex, AbstractCartesianIndex}} = S # Check that stride of matrix/vector is 1 # Writing like this to avoid splatting penalty when called with multiple arguments, diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 388bbec4d79b6..81bafda44abb6 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -80,23 +80,29 @@ function (*)(A::AbstractMatrix{T}, x::AbstractVector{S}) where {T,S} mul!(similar(x,TS,size(A,1)),A,x) end -# these will throw a DimensionMismatch unless B has 1 row (or 1 col for transposed case): -*(a::AbstractVector, transB::Transpose{<:Any,<:AbstractMatrix}) = - (B = transB.parent; *(reshape(a,length(a),1), transpose(B))) -*(A::AbstractMatrix, transb::Transpose{<:Any,<:AbstractVector}) = - (b = transb.parent; *(A, transpose(reshape(b,length(b),1)))) -*(a::AbstractVector, adjB::Adjoint{<:Any,<:AbstractMatrix}) = - (B = adjB.parent; *(reshape(a,length(a),1), adjoint(B))) -*(A::AbstractMatrix, adjb::Adjoint{<:Any,<:AbstractVector}) = - (b = adjb.parent; *(A, adjoint(reshape(b,length(b),1)))) -(*)(a::AbstractVector, B::AbstractMatrix) = reshape(a,length(a),1)*B +""" + mul!(Y, A, B) -> Y +Calculates the matrix-matrix or matrix-vector product ``AB`` and stores the result in `Y`, +overwriting the existing value of `Y`. Note that `Y` must not be aliased with either `A` or +`B`. -mul!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = _mul!(y, A, x, MemoryLayout(y), MemoryLayout(A), MemoryLayout(x)) -_mul!(y::AbstractVector{T}, A::AbstractVecOrMat{T}, x::AbstractVector{T}, ::StridedLayout, ::StridedLayout, ::StridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) +# Examples +```jldoctest +julia> A=[1.0 2.0; 3.0 4.0]; B=[1.0 1.0; 1.0 1.0]; Y = similar(B); mul!(Y, A, B); + +julia> Y +2×2 Array{Float64,2}: + 3.0 3.0 + 7.0 7.0 +``` +""" +mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) + +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::StridedLayout, ::StridedLayout, ::StridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin - function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractVecOrMat{Complex{$elty}}, x::AbstractVector{$elty}, ::StridedLayout, ::StridedLayout, ::StridedLayout) + function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::StridedLayout, ::StridedLayout, ::StridedLayout) Afl = reinterpret($elty,A) yfl = reinterpret($elty,y) gemv!(yfl,'N',Afl,x) @@ -104,31 +110,37 @@ for elty in (Float32,Float64) end end end -_mul!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) +_mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) -function *(transA::Transpose{<:Any,<:StridedMatrix{T}}, x::StridedVector{S}) where {T<:BlasFloat,S} - A = transA.parent - TS = promote_op(matprod, T, S) - mul!(similar(x,TS,size(A,2)), transpose(A), convert(AbstractVector{TS}, x)) -end -function *(transA::Transpose{<:Any,<:AbstractMatrix{T}}, x::AbstractVector{S}) where {T,S} - A = transA.parent - TS = promote_op(matprod, T, S) - mul!(similar(x,TS,size(A,2)), transpose(A), x) -end - -_mul!(y::AbstractVector, transA::Transpose{<:Any,<:AbstractVecOrMat}, x::AbstractVector, _1, _2, _3) = +_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::StridedLayout, ::TransposeLayout, ::StridedLayout) = (A = transA.parent; generic_matvecmul!(y, 'T', A, x)) -_mul!(y::AbstractVector, adjA::Adjoint{<:Any,<:AbstractVecOrMat}, x::AbstractVector, _1, _2, _3) = +_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::StridedLayout, ::CTransposeLayout, ::StridedLayout) = (A = adjA.parent; generic_matvecmul!(y, 'C', A, x)) -_mul!(y::AbstractVector{T}, adjA::AbstractVecOrMat{T}, x::AbstractVector{T}, ::StridedLayout, ::TransposeStridedLayout, ::StridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::StridedLayout, ::TransposeLayout, ::StridedLayout) where {T<:BlasComplex} = gemv!(y, 'T', transpose(adjA), x) -_mul!(y::AbstractVector{T}, adjA::AbstractVecOrMat{T}, x::AbstractVector{T}, ::StridedLayout, ::CTransposeStridedLayout, ::StridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::StridedLayout, ::CTransposeLayout, ::StridedLayout) where {T<:BlasComplex} = gemv!(y, 'C', adjoint(adjA), x) +# Vector-matrix multiplication -# Matrix-matrix multiplication +(*)(a::AbstractVector, B::AbstractMatrix) = reshape(a,length(a),1)*B +# these will throw a DimensionMismatch unless B has 1 row (or 1 col for transposed case): +*(a::AbstractVector, transB::Transpose{<:Any,<:AbstractMatrix}) = + (B = transB.parent; *(reshape(a,length(a),1), transpose(B))) +*(A::AbstractMatrix, transb::Transpose{<:Any,<:AbstractVector}) = + (b = transb.parent; *(A, transpose(reshape(b,length(b),1)))) +*(a::AbstractVector, adjB::Adjoint{<:Any,<:AbstractMatrix}) = + (B = adjB.parent; *(reshape(a,length(a),1), adjoint(B))) +*(A::AbstractMatrix, adjb::Adjoint{<:Any,<:AbstractVector}) = + (b = adjb.parent; *(A, adjoint(reshape(b,length(b),1)))) + +# these enable treating vectors as n x 1 matrices for important use-cases +mul!(y::AbstractMatrix, a::AbstractVector, B::AbstractMatrix) = mul!(y, reshape(a,length(a),1), B) +mul!(y::AbstractVector, a::AbstractVector, B::AbstractMatrix) = mul!(reshape(y,length(y),1), reshape(a,length(a),1), B) +mul!(y::AbstractVector, A::AbstractMatrix, B::AbstractMatrix) = mul!(reshape(y,length(b),1), A, B) + +# Matrix-matrix multiplication """ ``` *(A::AbstractMatrix, B::AbstractMatrix) @@ -149,25 +161,6 @@ function (*)(A::AbstractMatrix, B::AbstractMatrix) mul!(similar(B, TS, (size(A,1), size(B,2))), A, B) end -""" - mul!(Y, A, B) -> Y - -Calculates the matrix-matrix or matrix-vector product ``AB`` and stores the result in `Y`, -overwriting the existing value of `Y`. Note that `Y` must not be aliased with either `A` or -`B`. - -# Examples -```jldoctest -julia> A=[1.0 2.0; 3.0 4.0]; B=[1.0 1.0; 1.0 1.0]; Y = similar(B); mul!(Y, A, B); - -julia> Y -2×2 Array{Float64,2}: - 3.0 3.0 - 7.0 7.0 -``` -""" -mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) - """ mul!(A, B) @@ -176,11 +169,13 @@ and return the result (the overwritten argument). """ mul!(A, B) -_mul!(C::AbstractVecOrMat{T}, A::AbstractVecOrMat{T}, B::AbstractVecOrMat{T}, ::StridedLayout, ::StridedLayout, ::StridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix, _1, _2, _3) = generic_matmatmul!(C, 'N', 'N', A, B) + +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::StridedLayout) where {T<:BlasFloat} = gemm_wrapper!(C, 'N', 'N', A, B) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractVecOrMat{Complex{$elty}}, A::AbstractVecOrMat{Complex{$elty}}, B::AbstractVecOrMat{$elty}, ::StridedLayout, ::StridedLayout, ::StridedLayout) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::StridedLayout, ::StridedLayout, ::StridedLayout) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) gemm_wrapper!(Cfl, 'N', 'N', Afl, B) @@ -188,19 +183,17 @@ for elty in (Float32,Float64) end end end -_mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat, _1, _2, _3) = generic_matmatmul!(C, 'N', 'N', A, B) - -_mul!(C::AbstractVecOrMat{T}, transA::AbstractMatrix{T}, B::AbstractVecOrMat{T}, ::StridedLayout, ::TransposeStridedLayout, ::StridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::TransposeLayout, ::StridedLayout) where {T<:BlasFloat} = (A = transpose(transA); A === B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)) -_mul!(C::AbstractVecOrMat, transA::AbstractVecOrMat, B::AbstractVecOrMat, _, ::TransposeStridedLayout, ::StridedLayout) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, _, ::TransposeLayout, ::StridedLayout) = (A = transpose(transA); generic_matmatmul!(C, 'T', 'N', A, B)) -_mul!(C::AbstractVecOrMat{T}, A::AbstractVecOrMat{T}, transB::AbstractVecOrMat{T}, ::StridedLayout, ::StridedLayout, ::TransposeStridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::TransposeLayout) where {T<:BlasFloat} = (B = transpose(transB); A === B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractVecOrMat{Complex{$elty}}, A::AbstractVecOrMat{Complex{$elty}}, transB::AbstractVecOrMat{$elty}, ::StridedLayout, ::StridedLayout, ::TransposeStridedLayout) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::StridedLayout, ::StridedLayout, ::TransposeLayout) B = transpose(transB) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) @@ -209,27 +202,29 @@ for elty in (Float32,Float64) end end end -_mul!(C::AbstractVecOrMat{T}, transA::AbstractVecOrMat{T}, transB::AbstractVecOrMat{T}, ::StridedLayout, ::TransposeStridedLayout, ::TransposeStridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::StridedLayout, ::TransposeLayout, ::TransposeLayout) where {T<:BlasFloat} = (A = transpose(transA); B = transpose(transB); gemm_wrapper!(C, 'T', 'T', A, B)) -_mul!(C::AbstractVecOrMat, transA::AbstractVecOrMat, transB::AbstractVecOrMat, _1, ::TransposeStridedLayout, ::TransposeStridedLayout) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::StridedLayout, ::TransposeLayout, ::TransposeLayout) = (A = transpose(transA); B = transpose(transB); generic_matmatmul!(C, 'T', 'T', A, B)) -_mul!(C::AbstractVecOrMat{T}, adjA::AbstractVecOrMat{T}, B::AbstractVecOrMat{T}, ::StridedLayout, ::CTransposeStridedLayout, ::StridedLayout) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::CTransposeLayout, ::StridedLayout) where {T<:BlasComplex} = (A = adjoint(adjA); A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)) -_mul!(C::AbstractVecOrMat, adjA::AbstractVecOrMat, B::AbstractVecOrMat, _, ::CTransposeStridedLayout, ::StridedLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::StridedLayout, ::CTransposeLayout, ::StridedLayout) = (A = adjoint(adjA); generic_matmatmul!(C, 'C', 'N', A, B)) -_mul!(C::AbstractVecOrMat{T}, A::AbstractVecOrMat{T}, adjB::AbstractVecOrMat{T}, ::StridedLayout, ::StridedLayout, ::CTransposeStridedLayout) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::CTransposeLayout) where {T<:BlasComplex} = (B = adjoint(adjB); A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)) -_mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, adjB::AbstractVecOrMat, _, ::StridedLayout, ::CTransposeStridedLayout) = +_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::StridedLayout, ::StridedLayout, ::CTransposeLayout) = (B = adjoint(adjB); generic_matmatmul!(C, 'N', 'C', A, B)) -_mul!(C::AbstractVecOrMat{T}, adjA::AbstractVecOrMat{T}, adjB::AbstractVecOrMat{T}, ::StridedLayout, ::CTransposeStridedLayout, ::CTransposeStridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::StridedLayout, ::CTransposeLayout, ::CTransposeLayout) where {T<:BlasFloat} = (A = adjoint(adjA); B = adjoint(adjB); gemm_wrapper!(C, 'C', 'C', A, B)) -_mul!(C::AbstractVecOrMat, adjA::AbstractVecOrMat, adjB::AbstractVecOrMat, _, ::CTransposeStridedLayout, ::CTransposeStridedLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::StridedLayout, ::CTransposeLayout, ::CTransposeLayout) = (A = adjoint(adjA); B = adjoint(adjB); generic_matmatmul!(C, 'C', 'C', A, B)) -_mul!(C::AbstractVecOrMat, adjA::AbstractVecOrMat, transB::AbstractVecOrMat, _, ::CTransposeStridedLayout, ::TransposeStridedLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::StridedLayout, ::CTransposeLayout, ::TransposeLayout) = (A = adjoint(adjA); B = transpose(transB); generic_matmatmul!(C, 'C', 'T', A, B)) + + # Supporting functions for matrix multiplication function copytri!(A::AbstractMatrix, uplo::Char, conjugate::Bool=false) From 81c2f92d76a2a36276b8a7dcf2b309fd72375626 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Tue, 16 Jan 2018 21:53:55 +0000 Subject: [PATCH 03/39] Added other memory layouts, updated triangular --- base/linalg/adjtrans.jl | 9 ++- base/linalg/linalg.jl | 6 ++ base/linalg/matmul.jl | 2 +- base/linalg/triangular.jl | 114 +++++++++++++++++++------------------- 4 files changed, 67 insertions(+), 64 deletions(-) diff --git a/base/linalg/adjtrans.jl b/base/linalg/adjtrans.jl index c2c91afd9bc1e..d505381388a71 100644 --- a/base/linalg/adjtrans.jl +++ b/base/linalg/adjtrans.jl @@ -102,14 +102,13 @@ axes(A::AdjOrTransAbsMat) = reverse(axes(A.parent)) IndexStyle(::Type{<:AdjOrTransAbsVec}) = IndexLinear() IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() -adjoint(::MemoryLayout{T}) where {T} = UnknownLayout{T}() -adjoint(::StridedLayout{T}) where {T<:Real} = TransposeLayout{T}() -adjoint(::TransposeLayout{T}) where {T<:Real} = StridedLayout{T}() -adjoint(::StridedLayout{T}) where {T<:Complex} = CTransposeLayout{T}() -adjoint(::CTransposeLayout{T}) where {T<:Complex} = StridedLayout{T}() transpose(::MemoryLayout{T}) where {T} = UnknownLayout{T}() transpose(::StridedLayout{T}) where {T} = TransposeLayout{T}() transpose(::TransposeLayout{T}) where {T} = StridedLayout{T}() +adjoint(::MemoryLayout{T}) where {T} = UnknownLayout{T}() +adjoint(M::MemoryLayout{T}) where {T<:Real} = transpose(M) +adjoint(::StridedLayout{T}) where {T<:Complex} = CTransposeLayout{T}() +adjoint(::CTransposeLayout{T}) where {T<:Complex} = StridedLayout{T}() MemoryLayout(::Type{A}) where A<:Adjoint{T,S} where {T,S} = adjoint(MemoryLayout(S)) MemoryLayout(::Type{A}) where A<:Transpose{T,S} where {T,S} = transpose(MemoryLayout(S)) diff --git a/base/linalg/linalg.jl b/base/linalg/linalg.jl index 78fb43566505e..6a43d2c705d87 100644 --- a/base/linalg/linalg.jl +++ b/base/linalg/linalg.jl @@ -169,6 +169,12 @@ struct LowerTriangularLayout{trans,T} <: MemoryLayout{T} end struct UnitLowerTriangularLayout{trans,T} <: MemoryLayout{T} end struct UpperTriangularLayout{trans,T} <: MemoryLayout{T} end struct UnitUpperTriangularLayout{trans,T} <: MemoryLayout{T} end +struct SymmetricLayout{T} <: MemoryLayout{T} + uplo::Char +end +struct HermitianLayout{T} <: MemoryLayout{T} + uplo::Char +end """ MemoryLayout(A) diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 81bafda44abb6..272829e1e0cba 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -167,7 +167,7 @@ end Calculate the matrix-matrix product ``AB``, overwriting one of `A` or `B` (but not both), and return the result (the overwritten argument). """ -mul!(A, B) +mul!(A, B) = _mul!(A, B, MemoryLayout(A), MemoryLayout(B)) _mul!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix, _1, _2, _3) = generic_matmatmul!(C, 'N', 'N', A, B) diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index bfb25b5f14e9e..02f9920a07f17 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -362,6 +362,33 @@ diag(A::UnitLowerTriangular) = fill(one(eltype(A)), size(A,1)) diag(A::UpperTriangular) = diag(A.data) diag(A::UnitUpperTriangular) = fill(one(eltype(A)), size(A,1)) +MemoryLayout(A::UpperTriangular) = trilayout(UpperTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, MemoryLayout(parent(A))) +trilayout(::Type{TriT}, ::MemoryLayout{T}) where {TriT,T} = UnknownLayout{T}() +trilayout(::Type{TriT}, ::StridedLayout{T}) where {TriT,T} = TriT{'N',T}() +trilayout(::Type{TriT}, ::TransposeLayout{T}) where {TriT,T} = TriT{'T',T}() +trilayout(::Type{TriT}, ::CTransposeLayout{T}) where {TriT,T} = TriT{'C',T}() +transpose(::UpperTriangularLayout{'N',T}) where {T} = LowerTriangularLayout{'T',T}() +transpose(::UnitUpperTriangularLayout{'N',T}) where {T} = UnitLowerTriangularLayout{'T',T}() +transpose(::LowerTriangularLayout{'N',T}) where {T} = UpperTriangularLayout{'T',T}() +transpose(::UnitLowerTriangularLayout{'N',T}) where {T} = UnitUpperTriangularLayout{'T',T}() +transpose(::UpperTriangularLayout{'T',T}) where {T} = LowerTriangularLayout{'N',T}() +transpose(::UnitUpperTriangularLayout{'T',T}) where {T} = UnitLowerTriangularLayout{'N',T}() +transpose(::LowerTriangularLayout{'T',T}) where {T} = UpperTriangularLayout{'N',T}() +transpose(::UnitLowerTriangularLayout{'T',T}) where {T} = UnitUpperTriangularLayout{'N',T}() + + +adjoint(::UpperTriangularLayout{'N',T}) where {T<:Complex} = LowerTriangularLayout{'C',T}() +adjoint(::UnitUpperTriangularLayout{'N',T}) where {T<:Complex} = UnitLowerTriangularLayout{'C',T}() +adjoint(::LowerTriangularLayout{'N',T}) where {T<:Complex} = UpperTriangularLayout{'C',T}() +adjoint(::UnitLowerTriangularLayout{'N',T}) where {T<:Complex} = UnitUpperTriangularLayout{'C',T}() +adjoint(::UpperTriangularLayout{'C',T}) where {T<:Complex} = LowerTriangularLayout{'N',T}() +adjoint(::UnitUpperTriangularLayout{'C',T}) where {T<:Complex} = UnitLowerTriangularLayout{'N',T}() +adjoint(::LowerTriangularLayout{'C',T}) where {T<:Complex} = UpperTriangularLayout{'N',T}() +adjoint(::UnitLowerTriangularLayout{'C',T}) where {T<:Complex} = UnitUpperTriangularLayout{'N',T}() + # Unary operations -(A::LowerTriangular) = LowerTriangular(-A.data) -(A::UpperTriangular) = UpperTriangular(-A.data) @@ -460,72 +487,43 @@ fillstored!(A::UnitUpperTriangular, x) = (fillband!(A.data, x, 1, size(A,2)-1); mul!(A::Tridiagonal, B::AbstractTriangular) = A*full!(B) mul!(C::AbstractMatrix, A::AbstractTriangular, B::Tridiagonal) = mul!(C, copyto!(similar(parent(A)), A), B) mul!(C::AbstractMatrix, A::Tridiagonal, B::AbstractTriangular) = mul!(C, A, copyto!(similar(parent(B)), B)) -mul!(C::AbstractVector, A::AbstractTriangular, transB::Transpose{<:Any,<:AbstractVecOrMat}) = - (B = transB.parent; mul!(A, transpose!(C, B))) -mul!(C::AbstractMatrix, A::AbstractTriangular, transB::Transpose{<:Any,<:AbstractVecOrMat}) = - (B = transB.parent; mul!(A, transpose!(C, B))) -mul!(C::AbstractMatrix, A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractVecOrMat}) = - (B = adjB.parent; mul!(A, adjoint!(C, B))) -mul!(C::AbstractVecOrMat, A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractVecOrMat}) = - (B = adjB.parent; mul!(A, adjoint!(C, B))) -# The three methods for each op are neceesary to avoid ambiguities with definitions in matmul.jl -mul!(C::AbstractVector , A::AbstractTriangular, B::AbstractVector) = mul!(A, copyto!(C, B)) -mul!(C::AbstractMatrix , A::AbstractTriangular, B::AbstractVecOrMat) = mul!(A, copyto!(C, B)) -mul!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = mul!(A, copyto!(C, B)) -mul!(C::AbstractVector , adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractVector) = - (A = adjA.parent; mul!(adjoint(A), copyto!(C, B))) -mul!(C::AbstractMatrix , adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = - (A = adjA.parent; mul!(adjoint(A), copyto!(C, B))) -mul!(C::AbstractVecOrMat, adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = - (A = adjA.parent; mul!(adjoint(A), copyto!(C, B))) -mul!(C::AbstractVector , transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractVector) = - (A = transA.parent; mul!(transpose(A), copyto!(C, B))) -mul!(C::AbstractMatrix , transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = - (A = transA.parent; mul!(transpose(A), copyto!(C, B))) -mul!(C::AbstractVecOrMat, transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = - (A = transA.parent; mul!(transpose(A), copyto!(C, B))) -mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, copy(B)) -mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = mul!(C, A, copy(B)) -mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, copy(B)) -mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = mul!(C, A, copy(B)) -mul!(C::AbstractVector, A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = throw(MethodError(mul!, (C, A, B))) -mul!(C::AbstractVector, A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = throw(MethodError(mul!, (C, A, B))) - - -for (t, uploc, isunitc) in ((:LowerTriangular, 'L', 'N'), - (:UnitLowerTriangular, 'L', 'U'), - (:UpperTriangular, 'U', 'N'), - (:UnitUpperTriangular, 'U', 'U')) + +for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, 'L', 'N'), + (:UnitLowerTriangular, :UnitLowerTriangularLayout, 'L', 'U'), + (:UpperTriangular, :UpperTriangularLayout, 'U', 'N'), + (:UnitUpperTriangular, :UnitUpperTriangularLayout, 'U', 'U')) @eval begin # Vector multiplication - mul!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasFloat} = + _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::StridedLayout, ::$memlay, ::StridedLayout) where {T<:BlasFloat} = + mul!(A, copyto!(y, b)) + + _mul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'N'}, ::StridedLayout) where {T<:BlasFloat} = BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) - mul!(transA::Transpose{<:Any,<:$t{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasFloat} = - (A = transA.parent; BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - mul!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasReal} = - (A = adjA.parent; BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - mul!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasComplex} = - (A = adjA.parent; BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) + _mul!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'T'}, ::StridedLayout) where {T<:BlasFloat} = + (A = transpose(transA); BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) + _mul!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'C'}, ::StridedLayout) where {T<:BlasComplex} = + (A = adjoint(adjA); BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) # Matrix multiplication - mul!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = + _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::$memlay, ::StridedLayout) where {T<:BlasFloat} = + mul!(A, copyto!(C, B)) + _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::$memlay) where {T<:BlasFloat} = + mul!(A, copyto!(C, B)) + + _mul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'N'}, ::StridedLayout) where {T<:BlasFloat} = BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B) - mul!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = + _mul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::$memlay{'N'}) where {T<:BlasFloat} = BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) - mul!(transA::Transpose{<:Any,<:$t{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasFloat} = - (A = transA.parent; BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) - mul!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasComplex} = - (A = adjA.parent; BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B)) - mul!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasReal} = - (A = adjA.parent; BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) - - mul!(A::StridedMatrix{T}, transB::Transpose{<:Any,<:$t{T,<:StridedMatrix}}) where {T<:BlasFloat} = - (B = transB.parent; BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) - mul!(A::StridedMatrix{T}, adjB::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}) where {T<:BlasComplex} = - (B = adjB.parent; BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), B.data, A)) - mul!(A::StridedMatrix{T}, adjB::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}) where {T<:BlasReal} = - (B = adjB.parent; BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) + _mul!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'T'}, ::StridedLayout) where {T<:BlasFloat} = + (A = transpose(transA); BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) + _mul!(adjA::AbstractMatrix{T}, B::StridedMatrix{T}, ::$memlay{'C'}, ::StridedLayout) where {T<:BlasComplex} = + (A = adjoint(adjA); BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B)) + + _mul!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::StridedLayout, ::$memlay{'T'}) where {T<:BlasFloat} = + (B = transpose(transB); BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) + _mul!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::StridedLayout, ::$memlay{'C'}) where {T<:BlasComplex} = + (B = adjoint(adjB); BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), B.data, A)) # Left division ldiv!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = From 84fc2eebd013cb9173deb2b7988554ea6e296dd1 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Tue, 16 Jan 2018 22:08:54 +0000 Subject: [PATCH 04/39] fix ambiguity --- base/linalg/bidiag.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/base/linalg/bidiag.jl b/base/linalg/bidiag.jl index 811eec31815d0..dfc01e04cb633 100644 --- a/base/linalg/bidiag.jl +++ b/base/linalg/bidiag.jl @@ -349,8 +349,7 @@ mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractTriangular}, B::BiTriSym) = mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:AbstractVecOrMat}, B::BiTriSym) = A_mul_B_td!(C, A, B) mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractVecOrMat}, B::BiTriSym) = A_mul_B_td!(C, A, B) mul!(C::AbstractVector, A::BiTri, B::AbstractVector) = A_mul_B_td!(C, A, B) -mul!(C::AbstractMatrix, A::BiTri, B::AbstractVecOrMat) = A_mul_B_td!(C, A, B) -mul!(C::AbstractVecOrMat, A::BiTri, B::AbstractVecOrMat) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::BiTri, B::AbstractMatrix) = A_mul_B_td!(C, A, B) mul!(C::AbstractMatrix, A::BiTri, B::Transpose{<:Any,<:AbstractVecOrMat}) = A_mul_B_td!(C, A, B) # around bidiag line 330 mul!(C::AbstractMatrix, A::BiTri, B::Adjoint{<:Any,<:AbstractVecOrMat}) = A_mul_B_td!(C, A, B) mul!(C::AbstractVector, A::BiTri, B::Transpose{<:Any,<:AbstractVecOrMat}) = throw(MethodError(mul!, (C, A, B))) From c65a5683511f83549abe9fc14efafccc7f312531 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Wed, 17 Jan 2018 16:23:44 +0000 Subject: [PATCH 05/39] fix UndefVar error --- base/abstractarray.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index d4b321a341f36..659e14077d709 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1791,7 +1791,7 @@ function mapslices(f, A::AbstractArray, dims::AbstractVector) # increase. The slice itself must be mutable and the result cannot contain # any mutable containers. The following errs on the side of being overly # strict (#18570 & #21123). - safe_for_reuse = MemoryLayout(Aslice) isa StridedLayout && + safe_for_reuse = LinAlg.MemoryLayout(Aslice) isa LinAlg.StridedLayout && (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number)) # determine result size and allocate From 1387afcca42b573728f6f4141d39d45c250f01e4 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Fri, 19 Jan 2018 10:49:58 +0000 Subject: [PATCH 06/39] Restore mapslices (for now) --- base/abstractarray.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 637fb0319df04..edd298c6767b9 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1791,7 +1791,7 @@ function mapslices(f, A::AbstractArray, dims::AbstractVector) # increase. The slice itself must be mutable and the result cannot contain # any mutable containers. The following errs on the side of being overly # strict (#18570 & #21123). - safe_for_reuse = LinAlg.MemoryLayout(Aslice) isa LinAlg.StridedLayout && + safe_for_reuse = isa(Aslice, StridedArray) && (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number)) # determine result size and allocate From 4ff991d76a6c1fe299b40bb7ba7d627fec5f9f7d Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Fri, 19 Jan 2018 15:00:57 +0000 Subject: [PATCH 07/39] order of generalized eigvals appears to be brittle, so sort before comparing. --- stdlib/IterativeEigensolvers/test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/IterativeEigensolvers/test/runtests.jl b/stdlib/IterativeEigensolvers/test/runtests.jl index 6e8e550866927..53fba3b43de02 100644 --- a/stdlib/IterativeEigensolvers/test/runtests.jl +++ b/stdlib/IterativeEigensolvers/test/runtests.jl @@ -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(eigvals(A, B))[2:4] end end From c4d93e5056934ee63b65b153ffdb01277517d63a Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Fri, 19 Jan 2018 22:34:00 +0000 Subject: [PATCH 08/39] merge triangular --- stdlib/LinearAlgebra/src/triangular.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 975e7487fde67..e79f06fce2a0e 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -488,7 +488,6 @@ mul2!(A::Tridiagonal, B::AbstractTriangular) = A*full!(B) # is this necessary? mul!(C::AbstractMatrix, A::AbstractTriangular, B::Tridiagonal) = mul!(C, copyto!(similar(parent(A)), A), B) mul!(C::AbstractMatrix, A::Tridiagonal, B::AbstractTriangular) = mul!(C, A, copyto!(similar(parent(B)), B)) -<<<<<<< HEAD for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, 'L', 'N'), (:UnitLowerTriangular, :UnitLowerTriangularLayout, 'L', 'U'), From 9d239279335700cf64fde9594ad17b0b5cfaa3a3 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sat, 20 Jan 2018 08:22:27 +0000 Subject: [PATCH 09/39] Fix mul2! usages --- stdlib/LinearAlgebra/src/triangular.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index e79f06fce2a0e..b739254eb5894 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -496,7 +496,7 @@ for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, ' @eval begin # Vector multiplication _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::StridedLayout, ::$memlay, ::StridedLayout) where {T<:BlasFloat} = - mul!(A, copyto!(y, b)) + mul2!(A, copyto!(y, b)) _mul2!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'N'}, ::StridedLayout) where {T<:BlasFloat} = BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) @@ -508,7 +508,7 @@ for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, ' # Matrix multiplication _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::$memlay, ::StridedLayout) where {T<:BlasFloat} = mul2!(A, copyto!(C, B)) - _mul2!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::$memlay) where {T<:BlasFloat} = + _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::$memlay) where {T<:BlasFloat} = mul1!(copyto!(C, A), B) _mul2!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'N'}, ::StridedLayout) where {T<:BlasFloat} = From cac81bcfab7d591accb2924c328168a3dc441721 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sat, 20 Jan 2018 21:21:50 +0000 Subject: [PATCH 10/39] Fix transpose/adjoint MemoryLayout, add tests, add DenseLayout --- stdlib/IterativeEigensolvers/test/runtests.jl | 2 +- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 46 +++++++++++++++---- stdlib/LinearAlgebra/src/adjtrans.jl | 8 ++-- stdlib/LinearAlgebra/src/dense.jl | 2 +- stdlib/LinearAlgebra/src/matmul.jl | 43 +++++++++-------- stdlib/LinearAlgebra/src/triangular.jl | 19 ++++---- stdlib/LinearAlgebra/test/adjtrans.jl | 25 ++++++++++ stdlib/LinearAlgebra/test/dense.jl | 22 +++++++++ stdlib/LinearAlgebra/test/triangular.jl | 21 +++++++++ 9 files changed, 141 insertions(+), 47 deletions(-) diff --git a/stdlib/IterativeEigensolvers/test/runtests.jl b/stdlib/IterativeEigensolvers/test/runtests.jl index 53fba3b43de02..09556b7817d25 100644 --- a/stdlib/IterativeEigensolvers/test/runtests.jl +++ b/stdlib/IterativeEigensolvers/test/runtests.jl @@ -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))[2:4] + @test sort(eigs(A, B, nev = k, sigma = 1.0)[1]) ≈ sort(filter(isfinite, eigvals(A, B))) end end diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 6528bebfda46c..10721b192e214 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -16,9 +16,9 @@ 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 using Base: hvcat_fill, iszero, IndexLinear, _length, promote_op, promote_typeof, - @propagate_inbounds, @pure, reduce, typed_vcat, AbstractCartesianIndex, RangeIndex + @propagate_inbounds, @pure, reduce, typed_vcat, AbstractCartesianIndex, RangeIndex, Slice # 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))`. @@ -164,7 +164,11 @@ end abstract type MemoryLayout{T} end struct UnknownLayout{T} <: MemoryLayout{T} end -struct StridedLayout{T} <: MemoryLayout{T} end + +abstract type AbstractStridedLayout{T} <: MemoryLayout{T} end +struct DenseLayout{T} <: AbstractStridedLayout{T} end +struct StridedLayout{T} <: AbstractStridedLayout{T} end + struct TransposeLayout{T} <: MemoryLayout{T} end struct CTransposeLayout{T} <: MemoryLayout{T} end struct LowerTriangularLayout{trans,T} <: MemoryLayout{T} end @@ -199,14 +203,38 @@ 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::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)` """ -MemoryLayout(A::AbstractArray{T,N}) where {T,N} = UnknownLayout{T}() -MemoryLayout(A::Vector{T}) where {T} = StridedLayout{T}() -MemoryLayout(A::Matrix{T}) where {T} = StridedLayout{T}() -MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) +MemoryLayout(A::AbstractArray{T}) where {T} = UnknownLayout{T}() +MemoryLayout(A::Vector{T}) where {T} = DenseLayout{T}() +MemoryLayout(A::Matrix{T}) where {T} = DenseLayout{T}() + +MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() -submemorylayout(S::StridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex, AbstractCartesianIndex}} = S -submemorylayout(S::StridedLayout{T}, ::NTuple{2,I}) where {T,I<:Union{RangeIndex, AbstractCartesianIndex}} = S +submemorylayout(::DenseLayout{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseLayout{T}() +submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = + StridedLayout{T}() +submemorylayout(::DenseLayout{T}, ::Tuple{I1,Int}) where {T,I1<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseLayout{T}() +submemorylayout(::DenseLayout{T}, ::Tuple{I1,Int}) where {T,I1<:Slice} = + DenseLayout{T}() +submemorylayout(::DenseLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseLayout{T}() +submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = + StridedLayout{T}() + +MemoryLayout(A::ReshapedArray) = reshapedmemorylayout(MemoryLayout(parent(A))) +reshapedmemorylayout(::MemoryLayout{T}) where T = UnknownLayout{T}() +reshapedmemorylayout(::DenseLayout{T}) where T = DenseLayout{T}() + +MemoryLayout(A::ReinterpretArray{V}) where V = reinterpretedmemorylayout(MemoryLayout(parent(A)), V) +reinterpretedmemorylayout(::MemoryLayout{T}, ::Type{V}) where {T,V} = UnknownLayout{V}() +reinterpretedmemorylayout(::DenseLayout{T}, ::Type{V}) where {T,V} = DenseLayout{V}() + + + + +# MemoryLayout(A::ReinterpretArray{T}) where T = # Check that stride of matrix/vector is 1 # Writing like this to avoid splatting penalty when called with multiple arguments, diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index 713698aaa2646..a1a904991acaf 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -106,14 +106,14 @@ IndexStyle(::Type{<:AdjOrTransAbsVec}) = IndexLinear() IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() transpose(::MemoryLayout{T}) where {T} = UnknownLayout{T}() -transpose(::StridedLayout{T}) where {T} = TransposeLayout{T}() +transpose(::AbstractStridedLayout{T}) where {T} = TransposeLayout{T}() transpose(::TransposeLayout{T}) where {T} = StridedLayout{T}() adjoint(::MemoryLayout{T}) where {T} = UnknownLayout{T}() adjoint(M::MemoryLayout{T}) where {T<:Real} = transpose(M) -adjoint(::StridedLayout{T}) where {T<:Complex} = CTransposeLayout{T}() +adjoint(::AbstractStridedLayout{T}) where {T<:Complex} = CTransposeLayout{T}() adjoint(::CTransposeLayout{T}) where {T<:Complex} = StridedLayout{T}() -MemoryLayout(::Type{A}) where A<:Adjoint{T,S} where {T,S} = adjoint(MemoryLayout(S)) -MemoryLayout(::Type{A}) where A<:Transpose{T,S} where {T,S} = transpose(MemoryLayout(S)) +MemoryLayout(A::Adjoint) = adjoint(MemoryLayout(parent(A))) +MemoryLayout(A::Transpose) = transpose(MemoryLayout(parent(A))) @propagate_inbounds getindex(v::AdjOrTransAbsVec, i::Int) = wrapperop(v)(v.parent[i]) @propagate_inbounds getindex(A::AdjOrTransAbsMat, i::Int, j::Int) = wrapperop(A)(A.parent[j, i]) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index be4f5217388fb..f1df333762252 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -508,7 +508,7 @@ function exp!(A::AbstractMatrix{T}, _) where T<:BlasFloat A .= exp!(Matrix{T}(A)) A end -function _exp!(A::AbstractMatrix{T}, ::StridedLayout{T}) where T<:BlasFloat +function _exp!(A::AbstractMatrix{T}, ::AbstractStridedLayout{T}) where T<:BlasFloat n = checksquare(A) if ishermitian(A) return copytri!(parent(exp(Hermitian(A))), 'U', true) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index adbf4f9bd771e..dd9021d2a4dca 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -99,10 +99,10 @@ julia> Y """ mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::StridedLayout, ::StridedLayout, ::StridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin - function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::StridedLayout, ::StridedLayout, ::StridedLayout) + function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) Afl = reinterpret($elty,A) yfl = reinterpret($elty,y) gemv!(yfl,'N',Afl,x) @@ -112,13 +112,13 @@ for elty in (Float32,Float64) end _mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) -_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::StridedLayout, ::TransposeLayout, ::StridedLayout) = +_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::TransposeLayout, ::AbstractStridedLayout) = (A = transA.parent; generic_matvecmul!(y, 'T', A, x)) -_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::StridedLayout, ::CTransposeLayout, ::StridedLayout) = +_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::CTransposeLayout, ::AbstractStridedLayout) = (A = adjA.parent; generic_matvecmul!(y, 'C', A, x)) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::StridedLayout, ::TransposeLayout, ::StridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::TransposeLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = gemv!(y, 'T', transpose(adjA), x) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::StridedLayout, ::CTransposeLayout, ::StridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::CTransposeLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = gemv!(y, 'C', adjoint(adjA), x) # Vector-matrix multiplication @@ -180,11 +180,11 @@ mul2!(A, B) = _mul2!(A, B, MemoryLayout(A), MemoryLayout(B)) _mul!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix, _1, _2, _3) = generic_matmatmul!(C, 'N', 'N', A, B) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::StridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = gemm_wrapper!(C, 'N', 'N', A, B) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::StridedLayout, ::StridedLayout, ::StridedLayout) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) gemm_wrapper!(Cfl, 'N', 'N', Afl, B) @@ -193,17 +193,17 @@ for elty in (Float32,Float64) end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::TransposeLayout, ::StridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::TransposeLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = (A = transpose(transA); A === B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, _, ::TransposeLayout, ::StridedLayout) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, _, ::TransposeLayout, ::AbstractStridedLayout) = (A = transpose(transA); generic_matmatmul!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::TransposeLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::TransposeLayout) where {T<:BlasFloat} = (B = transpose(transB); A === B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::StridedLayout, ::StridedLayout, ::TransposeLayout) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::TransposeLayout) B = transpose(transB) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) @@ -212,29 +212,28 @@ for elty in (Float32,Float64) end end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::StridedLayout, ::TransposeLayout, ::TransposeLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::TransposeLayout, ::TransposeLayout) where {T<:BlasFloat} = (A = transpose(transA); B = transpose(transB); gemm_wrapper!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::StridedLayout, ::TransposeLayout, ::TransposeLayout) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::TransposeLayout, ::TransposeLayout) = (A = transpose(transA); B = transpose(transB); generic_matmatmul!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::CTransposeLayout, ::StridedLayout) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::CTransposeLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = (A = adjoint(adjA); A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::StridedLayout, ::CTransposeLayout, ::StridedLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::CTransposeLayout, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matmatmul!(C, 'C', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::CTransposeLayout) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::CTransposeLayout) where {T<:BlasComplex} = (B = adjoint(adjB); A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::StridedLayout, ::StridedLayout, ::CTransposeLayout) = +_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractStridedLayout, ::CTransposeLayout) = (B = adjoint(adjB); generic_matmatmul!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::StridedLayout, ::CTransposeLayout, ::CTransposeLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractStridedLayout, ::CTransposeLayout, ::CTransposeLayout) where {T<:BlasFloat} = (A = adjoint(adjA); B = adjoint(adjB); gemm_wrapper!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::StridedLayout, ::CTransposeLayout, ::CTransposeLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::CTransposeLayout, ::CTransposeLayout) = (A = adjoint(adjA); B = adjoint(adjB); generic_matmatmul!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::StridedLayout, ::CTransposeLayout, ::TransposeLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::CTransposeLayout, ::TransposeLayout) = (A = adjoint(adjA); B = transpose(transB); generic_matmatmul!(C, 'C', 'T', A, B)) - # Supporting functions for matrix multiplication function copytri!(A::AbstractMatrix, uplo::Char, conjugate::Bool=false) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index b739254eb5894..585be9d977b7d 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -362,14 +362,15 @@ diag(A::UnitLowerTriangular) = fill(one(eltype(A)), size(A,1)) diag(A::UpperTriangular) = diag(A.data) diag(A::UnitUpperTriangular) = fill(one(eltype(A)), size(A,1)) -MemoryLayout(A::UpperTriangular) = trilayout(UpperTriangularLayout, MemoryLayout(parent(A))) -MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, MemoryLayout(parent(A))) -MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, MemoryLayout(parent(A))) -MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, MemoryLayout(parent(A))) -trilayout(::Type{TriT}, ::MemoryLayout{T}) where {TriT,T} = UnknownLayout{T}() -trilayout(::Type{TriT}, ::StridedLayout{T}) where {TriT,T} = TriT{'N',T}() -trilayout(::Type{TriT}, ::TransposeLayout{T}) where {TriT,T} = TriT{'T',T}() -trilayout(::Type{TriT}, ::CTransposeLayout{T}) where {TriT,T} = TriT{'C',T}() +MemoryLayout(A::UpperTriangular) = trilayout(UpperTriangularLayout, LowerTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, UnitLowerTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, UpperTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, UnitUpperTriangularLayout, MemoryLayout(parent(A))) +trilayout(_1, _2, ::MemoryLayout{T}) where T = UnknownLayout{T}() +trilayout(::Type{Tri}, _, ::AbstractStridedLayout{T}) where {Tri,T} = Tri{'N',T}() +trilayout(_, ::Type{TriT}, ::TransposeLayout{T}) where {TriT,T} = TriT{'T',T}() +trilayout(_, ::Type{TriT}, ::CTransposeLayout{T}) where {TriT,T} = TriT{'C',T}() + transpose(::UpperTriangularLayout{'N',T}) where {T} = LowerTriangularLayout{'T',T}() transpose(::UnitUpperTriangularLayout{'N',T}) where {T} = UnitLowerTriangularLayout{'T',T}() transpose(::LowerTriangularLayout{'N',T}) where {T} = UpperTriangularLayout{'T',T}() @@ -378,8 +379,6 @@ transpose(::UpperTriangularLayout{'T',T}) where {T} = LowerTriangularLayout{'N', transpose(::UnitUpperTriangularLayout{'T',T}) where {T} = UnitLowerTriangularLayout{'N',T}() transpose(::LowerTriangularLayout{'T',T}) where {T} = UpperTriangularLayout{'N',T}() transpose(::UnitLowerTriangularLayout{'T',T}) where {T} = UnitUpperTriangularLayout{'N',T}() - - adjoint(::UpperTriangularLayout{'N',T}) where {T<:Complex} = LowerTriangularLayout{'C',T}() adjoint(::UnitUpperTriangularLayout{'N',T}) where {T<:Complex} = UnitLowerTriangularLayout{'C',T}() adjoint(::LowerTriangularLayout{'N',T}) where {T<:Complex} = UpperTriangularLayout{'C',T}() diff --git a/stdlib/LinearAlgebra/test/adjtrans.jl b/stdlib/LinearAlgebra/test/adjtrans.jl index 0d5f3362c4ee5..ee5366ad9c7f3 100644 --- a/stdlib/LinearAlgebra/test/adjtrans.jl +++ b/stdlib/LinearAlgebra/test/adjtrans.jl @@ -447,4 +447,29 @@ end @test adjoint!(b, a) === b end +@testset "adjoint and transpose MemoryLayout" begin + A = [1.0 2; 3 4] + @test LinearAlgebra.MemoryLayout(A') == LinearAlgebra.TransposeLayout{Float64}() + @test LinearAlgebra.MemoryLayout(transpose(A)) == LinearAlgebra.TransposeLayout{Float64}() + B = [1.0+im 2; 3 4] + @test LinearAlgebra.MemoryLayout(B') == LinearAlgebra.CTransposeLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(transpose(B)) == LinearAlgebra.TransposeLayout{ComplexF64}() + VA = view(A, 1:1, 1:1) + @test LinearAlgebra.MemoryLayout(VA') == LinearAlgebra.TransposeLayout{Float64}() + @test LinearAlgebra.MemoryLayout(transpose(VA)) == LinearAlgebra.TransposeLayout{Float64}() + VB = view(B, 1:1, 1:1) + @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.CTransposeLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(transpose(VB)) == LinearAlgebra.TransposeLayout{ComplexF64}() + VA2 = view(A, [1,2], :) + @test LinearAlgebra.MemoryLayout(VA2') == LinearAlgebra.UnknownLayout{Float64}() + @test LinearAlgebra.MemoryLayout(transpose(VA2)) == LinearAlgebra.UnknownLayout{Float64}() + VB2 = view(B, [1,2], :) + @test LinearAlgebra.MemoryLayout(VB2') == LinearAlgebra.UnknownLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(transpose(VB2)) == LinearAlgebra.UnknownLayout{ComplexF64}() + VBc = view(B', 1:1, 1:1) + @test LinearAlgebra.MemoryLayout(VBc) == LinearAlgebra.UnknownLayout{ComplexF64}() + VBt = view(transpose(B), 1:1, 1:1) + @test LinearAlgebra.MemoryLayout(VBt) == LinearAlgebra.UnknownLayout{ComplexF64}() +end + end # module TestAdjointTranspose diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index 4d9284d8d63cf..50153cdb73aa3 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -845,4 +845,26 @@ end end end +@testset "MemoryLayout for Array, SubArray, and ReinterpretArray" begin + A = [1.0 2; 3 4] + + @test LinearAlgebra.MemoryLayout(A) == LinearAlgebra.DenseLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,:,:)) == LinearAlgebra.DenseLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,:)) == LinearAlgebra.DenseLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,:,1)) == LinearAlgebra.DenseLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,:,1:1)) == LinearAlgebra.DenseLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1:1,1)) == LinearAlgebra.DenseLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1:1,1:2)) == LinearAlgebra.StridedLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1:1,:)) == LinearAlgebra.StridedLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1:2:1,1:2:1)) == LinearAlgebra.StridedLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1:2:1,:)) == LinearAlgebra.StridedLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,[1,2],:)) == LinearAlgebra.UnknownLayout{Float64}() + + @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(A,(4,),())) == LinearAlgebra.DenseLayout{Float64}() + @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == LinearAlgebra.DenseLayout{Float64}() + @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == LinearAlgebra.DenseLayout{Float64}() + + @test LinearAlgebra.MemoryLayout(reinterpret(ComplexF64,A)) == LinearAlgebra.DenseLayout{ComplexF64}() +end + end # module TestDense diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index c2e6420af3734..7d51d2f549845 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -538,4 +538,25 @@ end end end +@testset "triangular MemoryLayout" begin + A = [1.0 2; 3 4] + B = [1.0+im 2; 3 4] + for (TriType, TriLayout, TriLayoutTrans) in ((UpperTriangular, LinearAlgebra.UpperTriangularLayout, LinearAlgebra.LowerTriangularLayout), + (UnitUpperTriangular, LinearAlgebra.UnitUpperTriangularLayout, LinearAlgebra.UnitLowerTriangularLayout), + (LowerTriangular, LinearAlgebra.LowerTriangularLayout, LinearAlgebra.UpperTriangularLayout), + (UnitLowerTriangular, LinearAlgebra.UnitLowerTriangularLayout, LinearAlgebra.UnitUpperTriangularLayout)) + @test LinearAlgebra.MemoryLayout(TriType(A)) == TriLayout{'N',Float64}() + @test LinearAlgebra.MemoryLayout(TriType(transpose(A))) == TriLayoutTrans{'T',Float64}() + @test LinearAlgebra.MemoryLayout(TriType(A')) == TriLayoutTrans{'T',Float64}() + @test LinearAlgebra.MemoryLayout(transpose(TriType(A))) == TriLayoutTrans{'T',Float64}() + @test LinearAlgebra.MemoryLayout(TriType(A)') == TriLayoutTrans{'T',Float64}() + + @test LinearAlgebra.MemoryLayout(TriType(B)) == TriLayout{'N',ComplexF64}() + @test LinearAlgebra.MemoryLayout(TriType(transpose(B))) == TriLayoutTrans{'T',ComplexF64}() + @test LinearAlgebra.MemoryLayout(TriType(B')) == TriLayoutTrans{'C',ComplexF64}() + @test LinearAlgebra.MemoryLayout(transpose(TriType(B))) == TriLayoutTrans{'T',ComplexF64}() + @test LinearAlgebra.MemoryLayout(TriType(B)') == TriLayoutTrans{'C',ComplexF64}() + end +end + end # module TestTriangular From c745821a042754d70ebfe4aeb2b8ae1393072e75 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sun, 21 Jan 2018 09:19:40 +0000 Subject: [PATCH 11/39] dot, dotu dispatch, remove special * for Adjoint/Transpose --- stdlib/LinearAlgebra/src/adjtrans.jl | 5 +--- stdlib/LinearAlgebra/src/generic.jl | 10 +++++++- stdlib/LinearAlgebra/src/matmul.jl | 36 ++++++++++++++-------------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index a1a904991acaf..7476060b0ca88 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -182,10 +182,7 @@ broadcast(f, tvs::Union{Number,TransposeAbsVec}...) = transpose(broadcast((xs... # Adjoint/Transpose-vector * vector *(u::AdjointAbsVec, v::AbstractVector) = dot(u.parent, v) *(u::TransposeAbsVec{T}, v::AbstractVector{T}) where {T<:Real} = dot(u.parent, v) -function *(u::TransposeAbsVec, v::AbstractVector) - @boundscheck length(u) == length(v) || throw(DimensionMismatch()) - return sum(@inbounds(return u[k]*v[k]) for k in 1:length(u)) -end +*(u::TransposeAbsVec, v::AbstractVector) = dotu(u.parent, v) # vector * Adjoint/Transpose-vector *(u::AbstractVector, v::AdjOrTransAbsVec) = broadcast(*, u, v) # Adjoint/Transpose-vector * Adjoint/Transpose-vector diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index f1f7f7b63dd5d..763a4c2e078f9 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -624,7 +624,9 @@ norm(v::AdjointAbsVec, q::Real) = q == Inf ? norm(conj(v.parent), 1) : norm(conj norm(v::AdjointAbsVec) = norm(conj(v.parent)) norm(v::TransposeAbsVec) = norm(v.parent) -function vecdot(x::AbstractArray, y::AbstractArray) +vecdot(x::AbstractArray, y::AbstractArray) = _vecdot(x, y, MemoryLayout(x), MemoryLayout(y)) + +function _vecdot(x::AbstractArray, y::AbstractArray, _1, _2) lx = _length(x) if lx != _length(y) throw(DimensionMismatch("first array has length $(lx) which does not match the length of the second, $(_length(y)).")) @@ -731,6 +733,12 @@ end # Call optimized BLAS methods for vectors of numbers dot(x::AbstractVector{<:Number}, y::AbstractVector{<:Number}) = vecdot(x, y) +dotu(x::AbstractVector, y::AbstractVector) = _dotu(x, y, MemoryLayout(x), MemoryLayout(y)) +_dotu(x::AbstractVector{<:Real}, y::AbstractVector{<:Real}, _1, _2) = dot(x, y) +function _dotu(x::AbstractVector, y::AbstractVector, _1, _2) + @boundscheck length(x) == length(y) || throw(DimensionMismatch()) + return sum(@inbounds(return x[k]*y[k]) for k in 1:length(x)) +end ########################################################################################### diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index dd9021d2a4dca..ddf4a176ba4f1 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -38,8 +38,18 @@ end # Dot products -vecdot(x::Union{DenseArray{T},StridedVector{T}}, y::Union{DenseArray{T},StridedVector{T}}) where {T<:BlasReal} = BLAS.dot(x, y) -vecdot(x::Union{DenseArray{T},StridedVector{T}}, y::Union{DenseArray{T},StridedVector{T}}) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseLayout) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseLayout, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) + +_vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) + +_dotu(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotu(x, y) + function dot(x::Vector{T}, rx::Union{UnitRange{TI},AbstractRange{TI}}, y::Vector{T}, ry::Union{UnitRange{TI},AbstractRange{TI}}) where {T<:BlasReal,TI<:Integer} if length(rx) != length(ry) @@ -67,9 +77,6 @@ function dot(x::Vector{T}, rx::Union{UnitRange{TI},AbstractRange{TI}}, y::Vector GC.@preserve x y BLAS.dotc(length(rx), pointer(x)+(first(rx)-1)*sizeof(T), step(rx), pointer(y)+(first(ry)-1)*sizeof(T), step(ry)) end -*(transx::Transpose{<:Any,<:StridedVector{T}}, y::StridedVector{T}) where {T<:BlasComplex} = - (x = transx.parent; BLAS.dotu(x, y)) - # Matrix-vector multiplication function (*)(A::StridedMatrix{T}, x::StridedVector{S}) where {T<:BlasFloat,S} TS = promote_op(matprod, T, S) @@ -77,7 +84,7 @@ function (*)(A::StridedMatrix{T}, x::StridedVector{S}) where {T<:BlasFloat,S} end function (*)(A::AbstractMatrix{T}, x::AbstractVector{S}) where {T,S} TS = promote_op(matprod, T, S) - mul!(similar(x,TS,size(A,1)),A,x) + mul!(similar(x,TS,size(A,1)), A, x) end """ @@ -99,6 +106,10 @@ julia> Y """ mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) +_mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) + +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::AbstractStridedLayout, _) where {T<:BlasFloat} = + mul!(y, A, convert(AbstractVector{T}, x)) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin @@ -110,7 +121,6 @@ for elty in (Float32,Float64) end end end -_mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) _mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::TransposeLayout, ::AbstractStridedLayout) = (A = transA.parent; generic_matvecmul!(y, 'T', A, x)) @@ -125,16 +135,6 @@ _mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::Abs (*)(a::AbstractVector, B::AbstractMatrix) = reshape(a,length(a),1)*B -# these will throw a DimensionMismatch unless B has 1 row (or 1 col for transposed case): -*(a::AbstractVector, transB::Transpose{<:Any,<:AbstractMatrix}) = - (B = transB.parent; *(reshape(a,length(a),1), transpose(B))) -*(A::AbstractMatrix, transb::Transpose{<:Any,<:AbstractVector}) = - (b = transb.parent; *(A, transpose(reshape(b,length(b),1)))) -*(a::AbstractVector, adjB::Adjoint{<:Any,<:AbstractMatrix}) = - (B = adjB.parent; *(reshape(a,length(a),1), adjoint(B))) -*(A::AbstractMatrix, adjb::Adjoint{<:Any,<:AbstractVector}) = - (b = adjb.parent; *(A, adjoint(reshape(b,length(b),1)))) - # these enable treating vectors as n x 1 matrices for important use-cases mul!(y::AbstractMatrix, a::AbstractVector, B::AbstractMatrix) = mul!(y, reshape(a,length(a),1), B) mul!(y::AbstractVector, a::AbstractVector, B::AbstractMatrix) = mul!(reshape(y,length(y),1), reshape(a,length(a),1), B) @@ -197,7 +197,6 @@ _mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::A (A = transpose(transA); A === B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)) _mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, _, ::TransposeLayout, ::AbstractStridedLayout) = (A = transpose(transA); generic_matmatmul!(C, 'T', 'N', A, B)) - _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::TransposeLayout) where {T<:BlasFloat} = (B = transpose(transB); A === B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)) @@ -212,6 +211,7 @@ for elty in (Float32,Float64) end end end + _mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::TransposeLayout, ::TransposeLayout) where {T<:BlasFloat} = (A = transpose(transA); B = transpose(transB); gemm_wrapper!(C, 'T', 'T', A, B)) _mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::TransposeLayout, ::TransposeLayout) = From fe55aadbbd3d125f3f6438b4f688f613f40b79a4 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sun, 21 Jan 2018 20:28:35 +0000 Subject: [PATCH 12/39] Add MemoryLayout for symmetric, add docs --- doc/src/manual/interfaces.md | 1 + stdlib/LinearAlgebra/src/LinearAlgebra.jl | 37 ++++++---- stdlib/LinearAlgebra/src/adjtrans.jl | 8 ++- stdlib/LinearAlgebra/src/symmetric.jl | 85 ++++++++++++----------- stdlib/LinearAlgebra/src/triangular.jl | 5 ++ stdlib/LinearAlgebra/test/symmetric.jl | 25 +++++++ 6 files changed, 104 insertions(+), 57 deletions(-) diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 22898dbf4fcda..3795a4a3d6387 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -397,6 +397,7 @@ perhaps range-types `Ind` of your own design. For more information, see [Arrays |:----------------------------------------------- |:-------------------------------------- |:------------------------------------------------------------------------------------- | | `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. | +| `LinearAlgebra.MemoryLayout(A)` | | Return `LinearAlgebra.DenseLayout{T}()` if memory is storage is dense or `LinearAlgebra.StridedLayout{T}()` otherwise. | **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. | diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 10721b192e214..87e223a443286 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -164,23 +164,34 @@ end abstract type MemoryLayout{T} end struct UnknownLayout{T} <: MemoryLayout{T} end - abstract type AbstractStridedLayout{T} <: MemoryLayout{T} end struct DenseLayout{T} <: AbstractStridedLayout{T} end struct StridedLayout{T} <: AbstractStridedLayout{T} end -struct TransposeLayout{T} <: MemoryLayout{T} end -struct CTransposeLayout{T} <: MemoryLayout{T} end -struct LowerTriangularLayout{trans,T} <: MemoryLayout{T} end -struct UnitLowerTriangularLayout{trans,T} <: MemoryLayout{T} end -struct UpperTriangularLayout{trans,T} <: MemoryLayout{T} end -struct UnitUpperTriangularLayout{trans,T} <: MemoryLayout{T} end -struct SymmetricLayout{T} <: MemoryLayout{T} - uplo::Char -end -struct HermitianLayout{T} <: MemoryLayout{T} - uplo::Char -end +""" + UnknownLayout{T}() + +is returned by `MemoryLayout(A)` is unknown if or how the entries of an array `A` +are stored in memory. +""" +UnknownLayout + +""" + DenseLayout{T}() + +is returned by `MemoryLayout(A)` if a matrix or vector `A` have the same storage as an +`Array`. In other words, the entries are stored consecutively in memory, ordered by column. +""" +DenseLayout + +""" + StridedLayout{T}() + +is returned by `MemoryLayout(A)` if a matrix or vector `A` have the same storage as a +strided array. +""" +StridedLayout + """ MemoryLayout(A) diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index 7476060b0ca88..f0906997edf34 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -105,6 +105,11 @@ axes(A::AdjOrTransAbsMat) = reverse(axes(A.parent)) IndexStyle(::Type{<:AdjOrTransAbsVec}) = IndexLinear() IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() +# MemoryLayout of transposed and adjoint matrices +struct TransposeLayout{T} <: MemoryLayout{T} end +struct CTransposeLayout{T} <: MemoryLayout{T} end +MemoryLayout(A::Adjoint) = adjoint(MemoryLayout(parent(A))) +MemoryLayout(A::Transpose) = transpose(MemoryLayout(parent(A))) transpose(::MemoryLayout{T}) where {T} = UnknownLayout{T}() transpose(::AbstractStridedLayout{T}) where {T} = TransposeLayout{T}() transpose(::TransposeLayout{T}) where {T} = StridedLayout{T}() @@ -112,8 +117,7 @@ adjoint(::MemoryLayout{T}) where {T} = UnknownLayout{T}() adjoint(M::MemoryLayout{T}) where {T<:Real} = transpose(M) adjoint(::AbstractStridedLayout{T}) where {T<:Complex} = CTransposeLayout{T}() adjoint(::CTransposeLayout{T}) where {T<:Complex} = StridedLayout{T}() -MemoryLayout(A::Adjoint) = adjoint(MemoryLayout(parent(A))) -MemoryLayout(A::Transpose) = transpose(MemoryLayout(parent(A))) + @propagate_inbounds getindex(v::AdjOrTransAbsVec, i::Int) = wrapperop(v)(v.parent[i]) @propagate_inbounds getindex(A::AdjOrTransAbsMat, i::Int, j::Int) = wrapperop(A)(A.parent[j, i]) diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index 3d7745d16a916..17ebc735dcc33 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -180,6 +180,30 @@ Hermitian{T,S}(A::Hermitian{T,S}) where {T,S<:AbstractMatrix} = A Hermitian{T,S}(A::Hermitian) where {T,S<:AbstractMatrix} = Hermitian{T,S}(convert(S,A.data),A.uplo) AbstractMatrix{T}(A::Hermitian) where {T} = Hermitian(convert(AbstractMatrix{T}, A.data), Symbol(A.uplo)) +# MemoryLayout of Symmetric/Hermitian +struct SymmetricLayout{T} <: MemoryLayout{T} + uplo::Char +end +struct HermitianLayout{T} <: MemoryLayout{T} + uplo::Char +end +MemoryLayout(A::Hermitian) = hermitianmemorylayout(MemoryLayout(parent(A)), A.uplo) +MemoryLayout(A::Symmetric) = symmetricmemorylayout(MemoryLayout(parent(A)), A.uplo) +hermitianmemorylayout(::MemoryLayout{T}, _2) where T = UnknownLayout{T}() +hermitianmemorylayout(::AbstractStridedLayout{T}, uplo) where T<:Complex = HermitianLayout{T}(uplo) +hermitianmemorylayout(::AbstractStridedLayout{T}, uplo) where T<:Real = SymmetricLayout{T}(uplo) +hermitianmemorylayout(::TransposeLayout{T}, uplo) where T<:Complex = HermitianLayout{T}(ifelse(uplo == 'U', 'L', 'U')) +hermitianmemorylayout(::TransposeLayout{T}, uplo) where T<:Real = SymmetricLayout{T}(ifelse(uplo == 'U', 'L', 'U')) +symmetricmemorylayout(::MemoryLayout{T}, _2) where T = UnknownLayout{T}() +symmetricmemorylayout(::AbstractStridedLayout{T}, uplo) where T = SymmetricLayout{T}(uplo) +symmetricmemorylayout(::TransposeLayout{T}, uplo) where T = SymmetricLayout{T}(ifelse(uplo == 'U', 'L', 'U')) + +adjoint(H::HermitianLayout) = H +adjoint(H::SymmetricLayout{<:Real}) = H +transpose(H::SymmetricLayout) = H + + + copy(A::Symmetric{T,S}) where {T,S} = (B = copy(A.data); Symmetric{T,typeof(B)}(B,A.uplo)) copy(A::Hermitian{T,S}) where {T,S} = (B = copy(A.data); Hermitian{T,typeof(B)}(B,A.uplo)) @@ -316,52 +340,29 @@ end (-)(A::Symmetric{Tv,S}) where {Tv,S} = Symmetric{Tv,S}(-A.data, A.uplo) (-)(A::Hermitian{Tv,S}) where {Tv,S} = Hermitian{Tv,S}(-A.data, A.uplo) -## Matvec -mul!(y::StridedVector{T}, A::Symmetric{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasFloat} = - BLAS.symv!(A.uplo, one(T), A.data, x, zero(T), y) -mul!(y::StridedVector{T}, A::Hermitian{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasReal} = - BLAS.symv!(A.uplo, one(T), A.data, x, zero(T), y) -mul!(y::StridedVector{T}, A::Hermitian{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasComplex} = +## Matrix-vector product +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, + ::AbstractStridedLayout, AL::SymmetricLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = + BLAS.symv!(AL.uplo, one(T), parent(A), x, zero(T), y) +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, + ::AbstractStridedLayout, AL::HermitianLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemv!(A.uplo, one(T), A.data, x, zero(T), y) -## Matmat -mul!(C::StridedMatrix{T}, A::Symmetric{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = - BLAS.symm!('L', A.uplo, one(T), A.data, B, zero(T), C) -mul!(C::StridedMatrix{T}, A::StridedMatrix{T}, B::Symmetric{T,<:StridedMatrix}) where {T<:BlasFloat} = - BLAS.symm!('R', B.uplo, one(T), B.data, A, zero(T), C) -mul!(C::StridedMatrix{T}, A::Hermitian{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasReal} = - BLAS.symm!('L', A.uplo, one(T), A.data, B, zero(T), C) -mul!(C::StridedMatrix{T}, A::StridedMatrix{T}, B::Hermitian{T,<:StridedMatrix}) where {T<:BlasReal} = - BLAS.symm!('R', B.uplo, one(T), B.data, A, zero(T), C) -mul!(C::StridedMatrix{T}, A::Hermitian{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasComplex} = - BLAS.hemm!('L', A.uplo, one(T), A.data, B, zero(T), C) -mul!(C::StridedMatrix{T}, A::StridedMatrix{T}, B::Hermitian{T,<:StridedMatrix}) where {T<:BlasComplex} = - BLAS.hemm!('R', B.uplo, one(T), B.data, A, zero(T), C) +## Matrix-matrix product +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, + ::AbstractStridedLayout, AL::SymmetricLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = + BLAS.symm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout) where {T<:BlasFloat} = + BLAS.symm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, + ::AbstractStridedLayout, AL::HermitianLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = + BLAS.hemm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout) where {T<:BlasComplex} = + BLAS.hemm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) *(A::HermOrSym, B::HermOrSym) = A * copyto!(similar(parent(B)), B) -# Fallbacks to avoid generic_matvecmul!/generic_matmatmul! -## Symmetric{<:Number} and Hermitian{<:Real} are invariant to transpose; peel off the t -*(transA::Transpose{<:Any,<:RealHermSymComplexSym}, B::AbstractVector) = transA.parent * B -*(transA::Transpose{<:Any,<:RealHermSymComplexSym}, B::AbstractMatrix) = transA.parent * B -*(A::AbstractMatrix, transB::Transpose{<:Any,<:RealHermSymComplexSym}) = A * transB.parent -## Hermitian{<:Number} and Symmetric{<:Real} are invariant to adjoint; peel off the c -*(adjA::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::AbstractVector) = adjA.parent * B -*(adjA::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::AbstractMatrix) = adjA.parent * B -*(A::AbstractMatrix, adjB::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * adjB.parent - -# ambiguities with transposed AbstractMatrix methods in linalg/matmul.jl -*(transA::Transpose{<:Any,<:RealHermSymComplexSym}, transB::Transpose{<:Any,<:RealHermSymComplexSym}) = transA.parent * transB.parent -*(transA::Transpose{<:Any,<:RealHermSymComplexSym}, transB::Transpose{<:Any,<:RealHermSymComplexHerm}) = transA.parent * transB -*(transA::Transpose{<:Any,<:RealHermSymComplexHerm}, transB::Transpose{<:Any,<:RealHermSymComplexSym}) = transA * transB.parent -*(adjA::Adjoint{<:Any,<:RealHermSymComplexHerm}, adjB::Adjoint{<:Any,<:RealHermSymComplexHerm}) = adjA.parent * adjB.parent -*(adjA::Adjoint{<:Any,<:RealHermSymComplexSym}, adjB::Adjoint{<:Any,<:RealHermSymComplexHerm}) = adjA * adjB.parent -*(adjA::Adjoint{<:Any,<:RealHermSymComplexHerm}, adjB::Adjoint{<:Any,<:RealHermSymComplexSym}) = adjA.parent * adjB - -# ambiguities with AbstractTriangular -*(transA::Transpose{<:Any,<:RealHermSymComplexSym}, B::AbstractTriangular) = transA.parent * B -*(A::AbstractTriangular, transB::Transpose{<:Any,<:RealHermSymComplexSym}) = A * transB.parent -*(adjA::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::AbstractTriangular) = adjA.parent * B -*(A::AbstractTriangular, adjB::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * adjB.parent for T in (:Symmetric, :Hermitian), op in (:*, :/) # Deal with an ambiguous case diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 585be9d977b7d..13ca18ec0e6a4 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -362,6 +362,11 @@ diag(A::UnitLowerTriangular) = fill(one(eltype(A)), size(A,1)) diag(A::UpperTriangular) = diag(A.data) diag(A::UnitUpperTriangular) = fill(one(eltype(A)), size(A,1)) +# MemoryLayout of triangular matrices +struct LowerTriangularLayout{trans,T} <: MemoryLayout{T} end +struct UnitLowerTriangularLayout{trans,T} <: MemoryLayout{T} end +struct UpperTriangularLayout{trans,T} <: MemoryLayout{T} end +struct UnitUpperTriangularLayout{trans,T} <: MemoryLayout{T} end MemoryLayout(A::UpperTriangular) = trilayout(UpperTriangularLayout, LowerTriangularLayout, MemoryLayout(parent(A))) MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, UnitLowerTriangularLayout, MemoryLayout(parent(A))) MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, UpperTriangularLayout, MemoryLayout(parent(A))) diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index 0046e9704201a..d6627162d783b 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -487,4 +487,29 @@ end end end +@testset "Symmetric/Hermitian MemoryLayout" begin + A = [1.0 2; 3 4] + @test LinearAlgebra.MemoryLayout(Symmetric(A)) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test LinearAlgebra.MemoryLayout(Hermitian(A)) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test LinearAlgebra.MemoryLayout(Transpose(Symmetric(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test LinearAlgebra.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test LinearAlgebra.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test LinearAlgebra.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test LinearAlgebra.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout{Float64}('L') + @test LinearAlgebra.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout{Float64}('L') + @test LinearAlgebra.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout{Float64}('L') + @test LinearAlgebra.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout{Float64}('L') + B = [1.0+im 2; 3 4] + @test LinearAlgebra.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout{ComplexF64}('U') + @test LinearAlgebra.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout{ComplexF64}('U') + @test LinearAlgebra.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout{ComplexF64}('U') + @test LinearAlgebra.MemoryLayout(Transpose(Hermitian(B))) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout{ComplexF64}('U') + @test LinearAlgebra.MemoryLayout(Symmetric(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(Hermitian(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout{ComplexF64}('L') + @test LinearAlgebra.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout{ComplexF64}('L') +end + end # module TestSymmetric From 30d5ad8917bb27ad1c90e989fcb0934552c59ba6 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Mon, 22 Jan 2018 16:24:47 +0000 Subject: [PATCH 13/39] Fix whitespace --- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 87e223a443286..86f4e84bb76e8 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -188,7 +188,7 @@ DenseLayout StridedLayout{T}() is returned by `MemoryLayout(A)` if a matrix or vector `A` have the same storage as a -strided array. +strided array. """ StridedLayout @@ -212,7 +212,7 @@ Julia's internal linear algebra machinery will automatically (and invisibly) dispatch to BLAS and LAPACK routines if the memory layout is BLAS 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::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)` +overrides of `strides(A::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)`. """ MemoryLayout(A::AbstractArray{T}) where {T} = UnknownLayout{T}() MemoryLayout(A::Vector{T}) where {T} = DenseLayout{T}() From a67eebe5888f43c576d8aa54edd6f0b55485693b Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sat, 27 Jan 2018 14:00:14 +0000 Subject: [PATCH 14/39] Fix symmetric ambiguities --- stdlib/LinearAlgebra/src/matmul.jl | 3 +-- stdlib/LinearAlgebra/src/symmetric.jl | 38 +++------------------------ 2 files changed, 5 insertions(+), 36 deletions(-) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index ddf4a176ba4f1..1f730cacbd143 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -107,9 +107,8 @@ julia> Y mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) _mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) - _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::AbstractStridedLayout, _) where {T<:BlasFloat} = - mul!(y, A, convert(AbstractVector{T}, x)) + mul!(y, A, convert(Vector{T}, x)) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index 17ebc735dcc33..cff4fff784588 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -346,7 +346,7 @@ _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, BLAS.symv!(AL.uplo, one(T), parent(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, AL::HermitianLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = - BLAS.hemv!(A.uplo, one(T), A.data, x, zero(T), y) + BLAS.hemv!(A.uplo, one(T), parent(A), x, zero(T), y) ## Matrix-matrix product _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, AL::SymmetricLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = @@ -361,7 +361,9 @@ _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout) where {T<:BlasComplex} = BLAS.hemm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) -*(A::HermOrSym, B::HermOrSym) = A * copyto!(similar(parent(B)), B) +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, + ::AbstractStridedLayout, ::Union{HermitianLayout{T}, SymmetricLayout{T}}, ::Union{HermitianLayout{T}, SymmetricLayout{T}}) where {T<:BlasFloat} = + mul!(C, A, Matrix{T}(B)) for T in (:Symmetric, :Hermitian), op in (:*, :/) @@ -751,35 +753,3 @@ for func in (:log, :sqrt) end end end - -# dismabiguation methods: *(Adj of RealHermSymComplexHerm, Trans of RealHermSymComplexSym) and symmetric partner -*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Transpose{<:Any,<:RealHermSymComplexSym}) = A.parent * B.parent -*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A.parent * B.parent -# dismabiguation methods: *(Adj/Trans of AbsVec/AbsMat, Adj/Trans of RealHermSymComplex{Herm|Sym}) -*(A::Adjoint{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * B.parent -*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * B.parent -*(A::Adjoint{<:Any,<:AbstractVector}, B::Transpose{<:Any,<:RealHermSymComplexSym}) = A * B.parent -*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:RealHermSymComplexSym}) = A * B.parent -*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * B.parent -*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * B.parent -*(A::Transpose{<:Any,<:AbstractVector}, B::Transpose{<:Any,<:RealHermSymComplexSym}) = A * B.parent -*(A::Transpose{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:RealHermSymComplexSym}) = A * B.parent -# dismabiguation methods: *(Adj/Trans of RealHermSymComplex{Herm|Sym}, Adj/Trans of AbsVec/AbsMat) -*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Adjoint{<:Any,<:AbstractVector}) = A.parent * B -*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Adjoint{<:Any,<:AbstractMatrix}) = A.parent * B -*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Transpose{<:Any,<:AbstractVector}) = A.parent * B -*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Transpose{<:Any,<:AbstractMatrix}) = A.parent * B -*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Adjoint{<:Any,<:AbstractVector}) = A.parent * B -*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Adjoint{<:Any,<:AbstractMatrix}) = A.parent * B -*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Transpose{<:Any,<:AbstractVector}) = A.parent * B -*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Transpose{<:Any,<:AbstractMatrix}) = A.parent * B - -# dismabiguation methods: *(Adj/Trans of AbsTri or RealHermSymComplex{Herm|Sym}, Adj/Trans of other) -*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * B.parent -*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:RealHermSymComplexSym}) = A * B.parent -*(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * B.parent -*(A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:RealHermSymComplexSym}) = A * B.parent -*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Adjoint{<:Any,<:AbstractTriangular}) = A.parent * B -*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Transpose{<:Any,<:AbstractTriangular}) = A.parent * B -*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Adjoint{<:Any,<:AbstractTriangular}) = A.parent * B -*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Transpose{<:Any,<:AbstractTriangular}) = A.parent * B From 3f2528dd6a4d21059261e7d8e1bfff6a36a54a9b Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Mon, 29 Jan 2018 16:50:04 +0000 Subject: [PATCH 15/39] Override MemoryLayout for all DenseVector/Matrices (included SharedArrays) --- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 4 ++-- stdlib/LinearAlgebra/test/dense.jl | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index f14b6396aa211..9d7077d897dd0 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -221,8 +221,8 @@ In this case, one must implement the strided array interface, which requires overrides of `strides(A::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)`. """ MemoryLayout(A::AbstractArray{T}) where {T} = UnknownLayout{T}() -MemoryLayout(A::Vector{T}) where {T} = DenseLayout{T}() -MemoryLayout(A::Matrix{T}) where {T} = DenseLayout{T}() +MemoryLayout(A::DenseVector{T}) where {T} = DenseLayout{T}() +MemoryLayout(A::DenseMatrix{T}) where {T} = DenseLayout{T}() MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index 50153cdb73aa3..3b11509665000 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -845,6 +845,8 @@ end end end +struct MyDenseArray{T,N} <: DenseArray{T,N} end + @testset "MemoryLayout for Array, SubArray, and ReinterpretArray" begin A = [1.0 2; 3 4] @@ -865,6 +867,10 @@ end @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == LinearAlgebra.DenseLayout{Float64}() @test LinearAlgebra.MemoryLayout(reinterpret(ComplexF64,A)) == LinearAlgebra.DenseLayout{ComplexF64}() + + # this checks that SharedArray knows its layout + LinearAlgebra.MemoryLayout(MyDenseArray{Float64,1}()) == LinearAlgebra.DenseLayout{Float64}() + LinearAlgebra.MemoryLayout(MyDenseArray{Float64,2}()) == LinearAlgebra.DenseLayout{Float64}() end end # module TestDense From 15238b6a0116751daa92f07c2037407d935d7e79 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Tue, 30 Jan 2018 17:01:15 +0000 Subject: [PATCH 16/39] Rename layouts to DenseColumnMajor, DenseColumnsStridedRows, DenseRowMajor, DenseRowsStridedColumns, etc. --- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 115 ++++++++++++++++------ stdlib/LinearAlgebra/src/adjtrans.jl | 83 ++++++++++++++-- stdlib/LinearAlgebra/src/dense.jl | 9 +- stdlib/LinearAlgebra/src/matmul.jl | 79 +++++++-------- stdlib/LinearAlgebra/src/symmetric.jl | 26 ++--- stdlib/LinearAlgebra/src/triangular.jl | 30 +++--- stdlib/LinearAlgebra/test/adjtrans.jl | 30 ++++-- stdlib/LinearAlgebra/test/dense.jl | 30 +++--- 8 files changed, 266 insertions(+), 136 deletions(-) diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 9d7077d897dd0..09a77075c4940 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -167,12 +167,17 @@ else end ## Traits for memory layouts ## - abstract type MemoryLayout{T} end struct UnknownLayout{T} <: MemoryLayout{T} end -abstract type AbstractStridedLayout{T} <: MemoryLayout{T} end -struct DenseLayout{T} <: AbstractStridedLayout{T} end -struct StridedLayout{T} <: AbstractStridedLayout{T} end +abstract type DenseLayout{T} <: MemoryLayout{T} end +abstract type BlasMatrixLayout{T} <: DenseLayout{T} end +abstract type DenseColumns{T} <: BlasMatrixLayout{T} end +struct DenseColumnMajor{T} <: DenseColumns{T} end +struct DenseColumnsStridedRows{T} <: DenseColumns{T} end +abstract type DenseRows{T} <: BlasMatrixLayout{T} end +struct DenseRowMajor{T} <: DenseRows{T} end +struct DenseRowsStridedColumns{T} <: DenseRows{T} end +struct StridedLayout{T} <: DenseLayout{T} end """ UnknownLayout{T}() @@ -183,22 +188,65 @@ are stored in memory. UnknownLayout """ - DenseLayout{T}() + DenseLayout{T} -is returned by `MemoryLayout(A)` if a matrix or vector `A` have the same storage as an -`Array`. In other words, the entries are stored consecutively in memory, ordered by column. +is an abstract type whose subtypes are returned by `MemoryLayout(A)` +if a matrix or vector `A` have storage laid out at regular offsets in memory, +and which can therefore be passed to external C and Fortran functions expecting +this memory layout. """ DenseLayout +""" + DenseColumnMajor{T}() + +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory +equivalent to an `Array`, so that `stride(A,1) == 1` and `stride(A,2) == size(A,1)`. +Arrays with `DenseColumnMajor` must conform to the `DenseArray` interface. +""" +DenseColumnMajor + +""" + DenseColumnsStridedRows{T}() + +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory +as a column major matrix. In other words, the columns are stored in memory with +offsets of one, while the rows are stored with offsets given by `stride(A,2)`. +Arrays with `DenseColumnsStridedRows` must conform to the `DenseArray` interface. +""" +DenseColumnsStridedRows + +""" + DenseRowMajor{T}() + +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory +equivalent to the transpose of an `Array`, so that `stride(A,1) == size(A,1)` and +`stride(A,2) == 1`. Arrays with `DenseRowMajor` must conform to the +`DenseArray` interface. +""" +DenseRowMajor + +""" + DenseRowsStridedColumns{T}() + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +as a row major matrix. In other words, the rows are stored in memory with +offsets of one, while the columns are stored with offsets given by `stride(A,1)`. +`Array`s with `DenseRowsStridedColumns` must conform to the `DenseArray` interface, +and `transpose(A)` should return a matrix whose layout is `DenseColumnsStridedRows{T}()`. +""" +DenseRowsStridedColumns + """ StridedLayout{T}() -is returned by `MemoryLayout(A)` if a matrix or vector `A` have the same storage as a -strided array. +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage laid out at regular +offsets in memory. In other words, the columns are stored with offsets given +by `stride(A,1)` and for matrices the rows are stored in memory with offsets +of `stride(A,2)`. `Array`s with `StridedLayout` must conform to the `DenseArray` interface. """ StridedLayout - """ MemoryLayout(A) MemoryLayout(typeof(A)) @@ -220,38 +268,40 @@ 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::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)`. """ -MemoryLayout(A::AbstractArray{T}) where {T} = UnknownLayout{T}() -MemoryLayout(A::DenseVector{T}) where {T} = DenseLayout{T}() -MemoryLayout(A::DenseMatrix{T}) where {T} = DenseLayout{T}() +MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout{T}() +MemoryLayout(A::Vector{T}) where T = DenseColumnMajor{T}() +MemoryLayout(A::Matrix{T}) where T = DenseColumnMajor{T}() +MemoryLayout(A::DenseArray{T}) where T = StridedLayout{T}() MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() -submemorylayout(::DenseLayout{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseLayout{T}() -submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = +submemorylayout(::DenseColumns{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor{T}() +submemorylayout(::DenseLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = StridedLayout{T}() -submemorylayout(::DenseLayout{T}, ::Tuple{I1,Int}) where {T,I1<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseLayout{T}() -submemorylayout(::DenseLayout{T}, ::Tuple{I1,Int}) where {T,I1<:Slice} = - DenseLayout{T}() -submemorylayout(::DenseLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseLayout{T}() -submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = +submemorylayout(::DenseColumns{T}, ::Tuple{I,Int}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor{T}() +submemorylayout(::DenseColumns{T}, ::Tuple{I,Int}) where {T,I<:Slice} = + DenseColumnMajor{T}() +submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor{T}() +submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Slice} = + DenseColumnMajor{T}() +submemorylayout(::DenseColumns{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnsStridedRows{T}() +submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex},I2<:Slice} = + DenseRowsStridedColumns{T}() +submemorylayout(::DenseLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = StridedLayout{T}() MemoryLayout(A::ReshapedArray) = reshapedmemorylayout(MemoryLayout(parent(A))) reshapedmemorylayout(::MemoryLayout{T}) where T = UnknownLayout{T}() -reshapedmemorylayout(::DenseLayout{T}) where T = DenseLayout{T}() +reshapedmemorylayout(::DenseColumnMajor{T}) where T = DenseColumnMajor{T}() MemoryLayout(A::ReinterpretArray{V}) where V = reinterpretedmemorylayout(MemoryLayout(parent(A)), V) reinterpretedmemorylayout(::MemoryLayout{T}, ::Type{V}) where {T,V} = UnknownLayout{V}() -reinterpretedmemorylayout(::DenseLayout{T}, ::Type{V}) where {T,V} = DenseLayout{V}() - - - - -# MemoryLayout(A::ReinterpretArray{T}) where T = +reinterpretedmemorylayout(::DenseColumnMajor{T}, ::Type{V}) where {T,V} = DenseColumnMajor{V}() # Check that stride of matrix/vector is 1 # Writing like this to avoid splatting penalty when called with multiple arguments, @@ -284,8 +334,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, ::DenseColumns) = 1 @inline chkstride1(A...) = _chkstride1(true, A...) @noinline _chkstride1(ok::Bool) = ok || error("matrix does not have contiguous columns") diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index f0906997edf34..8754d01a3dcce 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -105,19 +105,82 @@ axes(A::AdjOrTransAbsMat) = reverse(axes(A.parent)) IndexStyle(::Type{<:AdjOrTransAbsVec}) = IndexLinear() IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() + # MemoryLayout of transposed and adjoint matrices -struct TransposeLayout{T} <: MemoryLayout{T} end -struct CTransposeLayout{T} <: MemoryLayout{T} end +abstract type ConjDenseColumns{T<:Complex} <: BlasMatrixLayout{T} end +struct ConjDenseColumnMajor{T<:Complex} <: ConjDenseColumns{T} end +struct ConjDenseColumnsStridedRows{T<:Complex} <: ConjDenseColumns{T} end +abstract type ConjDenseRows{T<:Complex} <: BlasMatrixLayout{T} end +struct ConjDenseRowMajor{T<:Complex} <: ConjDenseRows{T} end +struct ConjDenseRowsStridedColumns{T<:Complex} <: ConjDenseRows{T} end +struct ConjStridedLayout{T<:Complex} <: DenseLayout{T} end + +""" + ConjDenseColumnMajor{T}() + +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory +equivalent to the complex conjugate of an `Array`, so that `stride(A,1) == 1` +and `stride(A,2) == size(A,1)`. +`Array`s with `ConjDenseColumnMajor` must conform to the `DenseArray` interface +and `adjoint(A)` should return a matrix whose layout is `DenseRowMajor{T}()`. +""" +ConjDenseColumnMajor + +""" + ConjDenseColumnsStridedRows{T}() + +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory +as a column major matrix, where the complex conjugates of the entries of `A` +are stored. +`Array`s with `ConjDenseColumnsStridedRows` must conform to the `DenseArray` interface, +and `adjoint(A)` should return a matrix whose layout is `DenseRowsStridedColumns{T}()`. +""" +ConjDenseColumnsStridedRows + +""" + ConjDenseRowMajor{T}() + +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory +equivalent to the adjoint of an `Array`, so that `stride(A,1) == 1` and `stride(A,2) == size(A,1)`. +`Array`s with `ConjDenseRowMajor` must conform to the `DenseArray` interface +and `adjoint(A)` should return a matrix whose layout is `DenseColumnMajor{T}()`. +""" +ConjDenseRowMajor + +""" + ConjDenseRowsStridedColumns{T}() + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +as a column major matrix, where the complex conjugates of the entries of `A` +are stored. +`Array`s with `ConjDenseRowsStridedColumns` must conform to the `DenseArray` interface, +and `adjoint(A)` should return a matrix whose layout is `DenseColumnsStridedRows{T}()`. +""" +ConjDenseRowsStridedColumns + MemoryLayout(A::Adjoint) = adjoint(MemoryLayout(parent(A))) MemoryLayout(A::Transpose) = transpose(MemoryLayout(parent(A))) -transpose(::MemoryLayout{T}) where {T} = UnknownLayout{T}() -transpose(::AbstractStridedLayout{T}) where {T} = TransposeLayout{T}() -transpose(::TransposeLayout{T}) where {T} = StridedLayout{T}() -adjoint(::MemoryLayout{T}) where {T} = UnknownLayout{T}() -adjoint(M::MemoryLayout{T}) where {T<:Real} = transpose(M) -adjoint(::AbstractStridedLayout{T}) where {T<:Complex} = CTransposeLayout{T}() -adjoint(::CTransposeLayout{T}) where {T<:Complex} = StridedLayout{T}() - +transpose(::MemoryLayout{T}) where T = UnknownLayout{T}() +transpose(::StridedLayout{T}) where T = StridedLayout{T}() +transpose(::DenseColumnsStridedRows{T}) where T = DenseRowsStridedColumns{T}() +transpose(::DenseRowsStridedColumns{T}) where T = DenseColumnsStridedRows{T}() +transpose(::DenseColumnMajor{T}) where T = DenseRowMajor{T}() +transpose(::DenseRowMajor{T}) where T = DenseColumnMajor{T}() +adjoint(::MemoryLayout{T}) where T = UnknownLayout{T}() +adjoint(M::MemoryLayout{T}) where T<:Real = transpose(M) +adjoint(::StridedLayout{T}) where T<:Complex = ConjStridedLayout{T}() +adjoint(::DenseColumnsStridedRows{T}) where T<:Complex = ConjDenseRowsStridedColumns{T}() +adjoint(::DenseRowsStridedColumns{T}) where T<:Complex = ConjDenseColumnsStridedRows{T}() +adjoint(::ConjDenseColumnsStridedRows{T}) where T<:Complex = DenseRowsStridedColumns{T}() +adjoint(::ConjDenseRowsStridedColumns{T}) where T<:Complex = DenseColumnsStridedRows{T}() +adjoint(::DenseColumnMajor{T}) where T<:Complex = ConjDenseRowMajor{T}() +adjoint(::DenseRowMajor{T}) where T<:Complex = ConjDenseColumnMajor{T}() +adjoint(::ConjDenseColumnMajor{T}) where T<:Complex = DenseRowMajor{T}() +adjoint(::ConjDenseRowMajor{T}) where T<:Complex = DenseColumnMajor{T}() + +# Adjoints and transposes conform to the strided array interface if their parent does +unsafe_convert(::Ptr{T}, A::AdjOrTrans{T,S}) where {T,S} = unsafe_convert(Ptr{T}, parent(A)) +strides(A::AdjOrTrans) = reverse(strides(parent(A))) @propagate_inbounds getindex(v::AdjOrTransAbsVec, i::Int) = wrapperop(v)(v.parent[i]) @propagate_inbounds getindex(A::AdjOrTransAbsMat, i::Int, j::Int) = wrapperop(A)(A.parent[j, i]) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index 59576edcff915..f831501705872 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -116,7 +116,7 @@ isposdef(x::Number) = imag(x)==0 && real(x) > 0 # a tuple containing 1 and a cumulative product of the first N-1 sizes # this definition is also used for StridedReshapedArray and StridedReinterpretedArray # which have the same memory storage as Array -function stride(a::Union{DenseArray,StridedReshapedArray,StridedReinterpretArray}, i::Int) +function stride(a::Union{Array,StridedReshapedArray,StridedReinterpretArray}, i::Int) if i > ndims(a) return length(a) end @@ -126,7 +126,10 @@ function stride(a::Union{DenseArray,StridedReshapedArray,StridedReinterpretArray end return s end -strides(a::Union{DenseArray,StridedReshapedArray,StridedReinterpretArray}) = size_to_strides(1, size(a)...) +strides(a::Array) = size_to_strides(1, size(a)...) +strides(a::ReshapedArray) = _dense_strides(size(a), MemoryLayout(parent(a))) +strides(a::ReinterpretArray) = _dense_strides(size(a), MemoryLayout(parent(a))) +_dense_strides(sz, ::DenseColumnMajor) = size_to_strides(1, sz...) function norm(x::StridedVector{T}, rx::Union{UnitRange{TI},AbstractRange{TI}}) where {T<:BlasFloat,TI<:Integer} if minimum(rx) < 1 || maximum(rx) > length(x) @@ -508,7 +511,7 @@ function exp!(A::AbstractMatrix{T}, _) where T<:BlasFloat A .= exp!(Matrix{T}(A)) A end -function _exp!(A::AbstractMatrix{T}, ::AbstractStridedLayout{T}) where T<:BlasFloat +function _exp!(A::AbstractMatrix{T}, ::DenseColumns{T}) where T<:BlasFloat n = checksquare(A) if ishermitian(A) return copytri!(parent(exp(Hermitian(A))), 'U', true) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 356cc616adb2d..0cac3a75dccb1 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -6,17 +6,17 @@ matprod(x, y) = x*y + x*y # Dot products -_vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseLayout) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseLayout, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::DenseLayout, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::DenseLayout) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::DenseLayout, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) -_dotu(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotu(x, y) +_dotu(x::AbstractVector{T}, y::AbstractVector{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotu(x, y) function dot(x::Vector{T}, rx::Union{UnitRange{TI},AbstractRange{TI}}, y::Vector{T}, ry::Union{UnitRange{TI},AbstractRange{TI}}) where {T<:BlasReal,TI<:Integer} @@ -75,12 +75,12 @@ julia> Y mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) _mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::AbstractStridedLayout, _) where {T<:BlasFloat} = +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::DenseLayout, ::DenseLayout, _) where {T<:BlasFloat} = mul!(y, A, convert(Vector{T}, x)) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::DenseLayout, ::DenseLayout, ::DenseLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin - function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) + function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::DenseLayout, ::DenseLayout, ::DenseLayout) Afl = reinterpret($elty,A) yfl = reinterpret($elty,y) gemv!(yfl,'N',Afl,x) @@ -89,13 +89,13 @@ for elty in (Float32,Float64) end end -_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::TransposeLayout, ::AbstractStridedLayout) = - (A = transA.parent; generic_matvecmul!(y, 'T', A, x)) -_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::CTransposeLayout, ::AbstractStridedLayout) = - (A = adjA.parent; generic_matvecmul!(y, 'C', A, x)) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::TransposeLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseLayout) = + (A = transpose(transA); generic_matvecmul!(y, 'T', A, x)) +_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseLayout) = + (A = adjoint(adjA); generic_matvecmul!(y, 'C', A, x)) +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseLayout) where {T<:BlasComplex} = gemv!(y, 'T', transpose(adjA), x) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::CTransposeLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseLayout) where {T<:BlasComplex} = gemv!(y, 'C', adjoint(adjA), x) # Vector-matrix multiplication @@ -147,11 +147,11 @@ mul2!(A, B) = _mul2!(A, B, MemoryLayout(A), MemoryLayout(B)) _mul!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix, _1, _2, _3) = generic_matmatmul!(C, 'N', 'N', A, B) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout, ::DenseLayout) where {T<:BlasFloat} = gemm_wrapper!(C, 'N', 'N', A, B) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::DenseLayout, ::DenseLayout, ::DenseLayout) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) gemm_wrapper!(Cfl, 'N', 'N', Afl, B) @@ -160,16 +160,16 @@ for elty in (Float32,Float64) end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::TransposeLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseLayout) where {T<:BlasFloat} = (A = transpose(transA); A === B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, _, ::TransposeLayout, ::AbstractStridedLayout) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, _, ::DenseRowsStridedColumns, ::DenseLayout) = (A = transpose(transA); generic_matmatmul!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::TransposeLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout, ::DenseRowsStridedColumns) where {T<:BlasFloat} = (B = transpose(transB); A === B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::TransposeLayout) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::DenseLayout, ::DenseLayout, ::DenseRowsStridedColumns) B = transpose(transB) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) @@ -179,26 +179,26 @@ for elty in (Float32,Float64) end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::TransposeLayout, ::TransposeLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseRowsStridedColumns) where {T<:BlasFloat} = (A = transpose(transA); B = transpose(transB); gemm_wrapper!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::TransposeLayout, ::TransposeLayout) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseRowsStridedColumns) = (A = transpose(transA); B = transpose(transB); generic_matmatmul!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::CTransposeLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseLayout) where {T<:BlasComplex} = (A = adjoint(adjA); A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::CTransposeLayout, ::AbstractStridedLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseLayout) = (A = adjoint(adjA); generic_matmatmul!(C, 'C', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::CTransposeLayout) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout, ::ConjDenseRowsStridedColumns) where {T<:BlasComplex} = (B = adjoint(adjB); A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractStridedLayout, ::CTransposeLayout) = +_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::DenseLayout, ::DenseLayout, ::ConjDenseRowsStridedColumns) = (B = adjoint(adjB); generic_matmatmul!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractStridedLayout, ::CTransposeLayout, ::CTransposeLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::ConjDenseRowsStridedColumns) where {T<:BlasFloat} = (A = adjoint(adjA); B = adjoint(adjB); gemm_wrapper!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::CTransposeLayout, ::CTransposeLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::ConjDenseRowsStridedColumns) = (A = adjoint(adjA); B = adjoint(adjB); generic_matmatmul!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::CTransposeLayout, ::TransposeLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseRowsStridedColumns) = (A = adjoint(adjA); B = transpose(transB); generic_matmatmul!(C, 'C', 'T', A, B)) # Supporting functions for matrix multiplication @@ -219,7 +219,7 @@ function copytri!(A::AbstractMatrix, uplo::Char, conjugate::Bool=false) A end -function gemv!(y::StridedVector{T}, tA::Char, A::StridedVecOrMat{T}, x::StridedVector{T}) where T<:BlasFloat +function gemv!(y::AbstractVector{T}, tA::Char, A::AbstractVecOrMat{T}, x::AbstractVector{T}) where T<:BlasFloat mA, nA = lapack_size(tA, A) if nA != length(x) throw(DimensionMismatch("second dimension of A, $nA, does not match length of x, $(length(x))")) @@ -297,17 +297,18 @@ function herk_wrapper!(C::Union{StridedMatrix{T}, StridedMatrix{Complex{T}}}, tA end function gemm_wrapper(tA::Char, tB::Char, - A::StridedVecOrMat{T}, - B::StridedVecOrMat{T}) where T<:BlasFloat + A::AbstractVecOrMat{T}, + B::AbstractVecOrMat{T}) where T<:BlasFloat mA, nA = lapack_size(tA, A) mB, nB = lapack_size(tB, B) C = similar(B, T, mA, nB) gemm_wrapper!(C, tA, tB, A, B) end -function gemm_wrapper!(C::StridedVecOrMat{T}, tA::Char, tB::Char, - A::StridedVecOrMat{T}, - B::StridedVecOrMat{T}) where T<:BlasFloat +#gemm_wrapper! requires A, B, and C to conform to the strided array interface +function gemm_wrapper!(C::AbstractVecOrMat{T}, tA::Char, tB::Char, + A::AbstractVecOrMat{T}, + B::AbstractVecOrMat{T}) where T<:BlasFloat mA, nA = lapack_size(tA, A) mB, nB = lapack_size(tB, B) diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index cff4fff784588..bb8434049b72d 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -190,13 +190,13 @@ end MemoryLayout(A::Hermitian) = hermitianmemorylayout(MemoryLayout(parent(A)), A.uplo) MemoryLayout(A::Symmetric) = symmetricmemorylayout(MemoryLayout(parent(A)), A.uplo) hermitianmemorylayout(::MemoryLayout{T}, _2) where T = UnknownLayout{T}() -hermitianmemorylayout(::AbstractStridedLayout{T}, uplo) where T<:Complex = HermitianLayout{T}(uplo) -hermitianmemorylayout(::AbstractStridedLayout{T}, uplo) where T<:Real = SymmetricLayout{T}(uplo) -hermitianmemorylayout(::TransposeLayout{T}, uplo) where T<:Complex = HermitianLayout{T}(ifelse(uplo == 'U', 'L', 'U')) -hermitianmemorylayout(::TransposeLayout{T}, uplo) where T<:Real = SymmetricLayout{T}(ifelse(uplo == 'U', 'L', 'U')) +hermitianmemorylayout(::DenseColumns{T}, uplo) where T<:Complex = HermitianLayout{T}(uplo) +hermitianmemorylayout(::DenseColumns{T}, uplo) where T<:Real = SymmetricLayout{T}(uplo) +hermitianmemorylayout(::DenseRows{T}, uplo) where T<:Complex = HermitianLayout{T}(ifelse(uplo == 'U', 'L', 'U')) +hermitianmemorylayout(::DenseRows{T}, uplo) where T<:Real = SymmetricLayout{T}(ifelse(uplo == 'U', 'L', 'U')) symmetricmemorylayout(::MemoryLayout{T}, _2) where T = UnknownLayout{T}() -symmetricmemorylayout(::AbstractStridedLayout{T}, uplo) where T = SymmetricLayout{T}(uplo) -symmetricmemorylayout(::TransposeLayout{T}, uplo) where T = SymmetricLayout{T}(ifelse(uplo == 'U', 'L', 'U')) +symmetricmemorylayout(::DenseColumns{T}, uplo) where T = SymmetricLayout{T}(uplo) +symmetricmemorylayout(::DenseRows{T}, uplo) where T = SymmetricLayout{T}(ifelse(uplo == 'U', 'L', 'U')) adjoint(H::HermitianLayout) = H adjoint(H::SymmetricLayout{<:Real}) = H @@ -342,27 +342,27 @@ end ## Matrix-vector product _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::SymmetricLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = + ::DenseLayout, AL::SymmetricLayout, ::DenseLayout) where {T<:BlasFloat} = BLAS.symv!(AL.uplo, one(T), parent(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::HermitianLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = + ::DenseLayout, AL::HermitianLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.hemv!(A.uplo, one(T), parent(A), x, zero(T), y) ## Matrix-matrix product _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, AL::SymmetricLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = + ::DenseLayout, AL::SymmetricLayout, ::DenseLayout) where {T<:BlasFloat} = BLAS.symm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout) where {T<:BlasFloat} = + ::DenseLayout, ::DenseLayout, BL::SymmetricLayout) where {T<:BlasFloat} = BLAS.symm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, AL::HermitianLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = + ::DenseLayout, AL::HermitianLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.hemm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout) where {T<:BlasComplex} = + ::DenseLayout, ::DenseLayout, BL::HermitianLayout) where {T<:BlasComplex} = BLAS.hemm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::Union{HermitianLayout{T}, SymmetricLayout{T}}, ::Union{HermitianLayout{T}, SymmetricLayout{T}}) where {T<:BlasFloat} = + ::DenseLayout, ::Union{HermitianLayout{T}, SymmetricLayout{T}}, ::Union{HermitianLayout{T}, SymmetricLayout{T}}) where {T<:BlasFloat} = mul!(C, A, Matrix{T}(B)) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 1a00208cfc656..244f56375d5a2 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -373,9 +373,9 @@ MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, Unit MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, UpperTriangularLayout, MemoryLayout(parent(A))) MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, UnitUpperTriangularLayout, MemoryLayout(parent(A))) trilayout(_1, _2, ::MemoryLayout{T}) where T = UnknownLayout{T}() -trilayout(::Type{Tri}, _, ::AbstractStridedLayout{T}) where {Tri,T} = Tri{'N',T}() -trilayout(_, ::Type{TriT}, ::TransposeLayout{T}) where {TriT,T} = TriT{'T',T}() -trilayout(_, ::Type{TriT}, ::CTransposeLayout{T}) where {TriT,T} = TriT{'C',T}() +trilayout(::Type{Tri}, _, ::DenseColumns{T}) where {Tri,T} = Tri{'N',T}() +trilayout(_, ::Type{TriT}, ::DenseRows{T}) where {TriT,T} = TriT{'T',T}() +trilayout(_, ::Type{TriT}, ::ConjDenseRowsStridedColumns{T}) where {TriT,T} = TriT{'C',T}() transpose(::UpperTriangularLayout{'N',T}) where {T} = LowerTriangularLayout{'T',T}() transpose(::UnitUpperTriangularLayout{'N',T}) where {T} = UnitLowerTriangularLayout{'T',T}() @@ -553,35 +553,35 @@ for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, ' (:UnitUpperTriangular, :UnitUpperTriangularLayout, 'U', 'U')) @eval begin # Vector multiplication - _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::StridedLayout, ::$memlay, ::StridedLayout) where {T<:BlasFloat} = + _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::DenseLayout, ::$memlay, ::DenseLayout) where {T<:BlasFloat} = mul2!(A, copyto!(y, b)) - _mul2!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'N'}, ::StridedLayout) where {T<:BlasFloat} = + _mul2!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'N'}, ::DenseLayout) where {T<:BlasFloat} = BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) - _mul2!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'T'}, ::StridedLayout) where {T<:BlasFloat} = + _mul2!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'T'}, ::DenseLayout) where {T<:BlasFloat} = (A = transpose(transA); BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - _mul2!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'C'}, ::StridedLayout) where {T<:BlasComplex} = + _mul2!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'C'}, ::DenseLayout) where {T<:BlasComplex} = (A = adjoint(adjA); BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) # Matrix multiplication - _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::$memlay, ::StridedLayout) where {T<:BlasFloat} = + _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::$memlay, ::DenseLayout) where {T<:BlasFloat} = mul2!(A, copyto!(C, B)) - _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::StridedLayout, ::$memlay) where {T<:BlasFloat} = + _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout, ::$memlay) where {T<:BlasFloat} = mul1!(copyto!(C, A), B) - _mul2!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'N'}, ::StridedLayout) where {T<:BlasFloat} = + _mul2!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'N'}, ::DenseColumns) where {T<:BlasFloat} = BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B) - _mul1!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::StridedLayout, ::$memlay{'N'}) where {T<:BlasFloat} = + _mul1!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'N'}) where {T<:BlasFloat} = BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) - _mul2!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'T'}, ::StridedLayout) where {T<:BlasFloat} = + _mul2!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'T'}, ::DenseColumns) where {T<:BlasFloat} = (A = transpose(transA); BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) - _mul2!(adjA::AbstractMatrix{T}, B::StridedMatrix{T}, ::$memlay{'C'}, ::StridedLayout) where {T<:BlasComplex} = + _mul2!(adjA::AbstractMatrix{T}, B::StridedMatrix{T}, ::$memlay{'C'}, ::DenseColumns) where {T<:BlasComplex} = (A = adjoint(adjA); BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B)) - _mul1!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::StridedLayout, ::$memlay{'T'}) where {T<:BlasFloat} = + _mul1!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'T'}) where {T<:BlasFloat} = (B = transpose(transB); BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) - _mul1!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::StridedLayout, ::$memlay{'C'}) where {T<:BlasComplex} = + _mul1!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'C'}) where {T<:BlasComplex} = (B = adjoint(adjB); BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), B.data, A)) # Left division diff --git a/stdlib/LinearAlgebra/test/adjtrans.jl b/stdlib/LinearAlgebra/test/adjtrans.jl index ee5366ad9c7f3..a8cde50b87739 100644 --- a/stdlib/LinearAlgebra/test/adjtrans.jl +++ b/stdlib/LinearAlgebra/test/adjtrans.jl @@ -449,27 +449,37 @@ end @testset "adjoint and transpose MemoryLayout" begin A = [1.0 2; 3 4] - @test LinearAlgebra.MemoryLayout(A') == LinearAlgebra.TransposeLayout{Float64}() - @test LinearAlgebra.MemoryLayout(transpose(A)) == LinearAlgebra.TransposeLayout{Float64}() + @test LinearAlgebra.MemoryLayout(A') == LinearAlgebra.DenseRowMajor{Float64}() + @test LinearAlgebra.MemoryLayout(transpose(A)) == LinearAlgebra.DenseRowMajor{Float64}() B = [1.0+im 2; 3 4] - @test LinearAlgebra.MemoryLayout(B') == LinearAlgebra.CTransposeLayout{ComplexF64}() - @test LinearAlgebra.MemoryLayout(transpose(B)) == LinearAlgebra.TransposeLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(B') == LinearAlgebra.ConjDenseRowMajor{ComplexF64}() + @test LinearAlgebra.MemoryLayout(transpose(B)) == LinearAlgebra.DenseRowMajor{ComplexF64}() VA = view(A, 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VA') == LinearAlgebra.TransposeLayout{Float64}() - @test LinearAlgebra.MemoryLayout(transpose(VA)) == LinearAlgebra.TransposeLayout{Float64}() + @test LinearAlgebra.MemoryLayout(VA') == LinearAlgebra.DenseRowsStridedColumns{Float64}() + @test LinearAlgebra.MemoryLayout(transpose(VA)) == LinearAlgebra.DenseRowsStridedColumns{Float64}() VB = view(B, 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.CTransposeLayout{ComplexF64}() - @test LinearAlgebra.MemoryLayout(transpose(VB)) == LinearAlgebra.TransposeLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.ConjDenseRowsStridedColumns{ComplexF64}() + @test LinearAlgebra.MemoryLayout(transpose(VB)) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() + VA = view(A, 1:2:2, 1:2:2) + @test LinearAlgebra.MemoryLayout(VA') == LinearAlgebra.StridedLayout{Float64}() + @test LinearAlgebra.MemoryLayout(transpose(VA)) == LinearAlgebra.StridedLayout{Float64}() + VB = view(B, 1:2:2, 1:2:2) + @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.ConjStridedLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(transpose(VB)) == LinearAlgebra.StridedLayout{ComplexF64}() VA2 = view(A, [1,2], :) @test LinearAlgebra.MemoryLayout(VA2') == LinearAlgebra.UnknownLayout{Float64}() @test LinearAlgebra.MemoryLayout(transpose(VA2)) == LinearAlgebra.UnknownLayout{Float64}() VB2 = view(B, [1,2], :) @test LinearAlgebra.MemoryLayout(VB2') == LinearAlgebra.UnknownLayout{ComplexF64}() @test LinearAlgebra.MemoryLayout(transpose(VB2)) == LinearAlgebra.UnknownLayout{ComplexF64}() + VAc = view(A', 1:1, 1:1) + @test LinearAlgebra.MemoryLayout(VAc) == LinearAlgebra.DenseRowsStridedColumns{Float64}() + VAt = view(transpose(A), 1:1, 1:1) + @test LinearAlgebra.MemoryLayout(VAt) == LinearAlgebra.DenseRowsStridedColumns{Float64}() VBc = view(B', 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VBc) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(VBc) == LinearAlgebra.ConjDenseRowsStridedColumns{ComplexF64}() VBt = view(transpose(B), 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VBt) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(VBt) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() end end # module TestAdjointTranspose diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index 3b11509665000..23bcfc46d0d14 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -850,27 +850,29 @@ struct MyDenseArray{T,N} <: DenseArray{T,N} end @testset "MemoryLayout for Array, SubArray, and ReinterpretArray" begin A = [1.0 2; 3 4] - @test LinearAlgebra.MemoryLayout(A) == LinearAlgebra.DenseLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,:,:)) == LinearAlgebra.DenseLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,:)) == LinearAlgebra.DenseLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,:,1)) == LinearAlgebra.DenseLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,:,1:1)) == LinearAlgebra.DenseLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1:1,1)) == LinearAlgebra.DenseLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1:1,1:2)) == LinearAlgebra.StridedLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1:1,:)) == LinearAlgebra.StridedLayout{Float64}() + @test LinearAlgebra.MemoryLayout(A) == LinearAlgebra.DenseColumnMajor{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,:,:)) == LinearAlgebra.DenseColumnMajor{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,:)) == LinearAlgebra.DenseColumnMajor{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,:,1)) == LinearAlgebra.DenseColumnMajor{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,:,1:1)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1:1,1)) == LinearAlgebra.DenseColumnMajor{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1,1:1)) == LinearAlgebra.StridedLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1,:)) == LinearAlgebra.StridedLayout{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1:1,1:2)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,1:1,:)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() @test LinearAlgebra.MemoryLayout(view(A,1:2:1,1:2:1)) == LinearAlgebra.StridedLayout{Float64}() @test LinearAlgebra.MemoryLayout(view(A,1:2:1,:)) == LinearAlgebra.StridedLayout{Float64}() @test LinearAlgebra.MemoryLayout(view(A,[1,2],:)) == LinearAlgebra.UnknownLayout{Float64}() - @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(A,(4,),())) == LinearAlgebra.DenseLayout{Float64}() - @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == LinearAlgebra.DenseLayout{Float64}() - @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == LinearAlgebra.DenseLayout{Float64}() + @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(A,(4,),())) == LinearAlgebra.DenseColumnMajor{Float64}() + @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == LinearAlgebra.DenseColumnMajor{Float64}() + @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(reinterpret(ComplexF64,A)) == LinearAlgebra.DenseLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(reinterpret(ComplexF64,A)) == LinearAlgebra.DenseColumnMajor{ComplexF64}() # this checks that SharedArray knows its layout - LinearAlgebra.MemoryLayout(MyDenseArray{Float64,1}()) == LinearAlgebra.DenseLayout{Float64}() - LinearAlgebra.MemoryLayout(MyDenseArray{Float64,2}()) == LinearAlgebra.DenseLayout{Float64}() + LinearAlgebra.MemoryLayout(MyDenseArray{Float64,1}()) == LinearAlgebra.StridedLayout{Float64}() + LinearAlgebra.MemoryLayout(MyDenseArray{Float64,2}()) == LinearAlgebra.StridedLayout{Float64}() end end # module TestDense From 3e1e4c45d4bc56838ec7c325f56138560cbca323 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sun, 4 Feb 2018 21:29:02 +1100 Subject: [PATCH 17/39] Add ConjLayout to replace ConjDenseColumns, and others --- base/abstractarray.jl | 35 +++++++++++ doc/src/manual/interfaces.md | 2 +- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 63 ++++++------------- stdlib/LinearAlgebra/src/adjtrans.jl | 76 +++++------------------ stdlib/LinearAlgebra/src/matmul.jl | 58 ++++++++--------- stdlib/LinearAlgebra/src/symmetric.jl | 14 ++--- stdlib/LinearAlgebra/src/triangular.jl | 14 ++--- stdlib/LinearAlgebra/test/adjtrans.jl | 8 +-- stdlib/LinearAlgebra/test/dense.jl | 2 +- 9 files changed, 116 insertions(+), 156 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 4afa4e394fc92..836bff351cb25 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -271,6 +271,41 @@ size_to_strides(s, d) = (s,) size_to_strides(s) = () +abstract type MemoryLayout{T} end +struct UnknownLayout{T} <: MemoryLayout{T} end + +""" + UnknownLayout{T}() + +is returned by `MemoryLayout(A)` is unknown if or how the entries of an array `A` +are stored in memory. +""" +UnknownLayout + +""" + MemoryLayout(A) + MemoryLayout(typeof(A)) + +`MemoryLayout` specifies the layout in memory for an array `A`. When +you define a new `AbstractArray` type, you can choose to implement +memory layout to indicate that an array is strided in memory. If you decide to +implement memory layout, then you must set this trait for your array +type: + + Base.MemoryLayout(::Type{M}) where M <: MyArray{T,N} where {T} = LinearAlgebra.StridedLayout{T}() + +The default is `Base.UnknownLayout{T,N}()` to indicate that the layout +in memory is unknown. + +Julia's internal linear algebra machinery will automatically (and invisibly) +dispatch to BLAS and LAPACK routines if the memory layout is BLAS 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::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)`. +""" +MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout{T}() + + function isassigned(a::AbstractArray, i::Int...) try a[i...] diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 353af52380e51..44d32f0941bb9 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -399,7 +399,7 @@ perhaps range-types `Ind` of your own design. For more information, see [Arrays |:----------------------------------------------- |:-------------------------------------- |:------------------------------------------------------------------------------------- | | `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. | -| `LinearAlgebra.MemoryLayout(A)` | | Return `LinearAlgebra.DenseLayout{T}()` if memory is storage is dense or `LinearAlgebra.StridedLayout{T}()` otherwise. +| `LinearAlgebra.MemoryLayout(A)` | | Return a subtype of `LinearAlgebra.AbstractStridedLayout`, such as `LinearAlgebra.DenseColumnMajor{T}()`,`LinearAlgebra.DenseRowMajor{T}()`, or `LinearAlgebra.StridedLayout{T}()`. | **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. | diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 09a77075c4940..5f77c9d6a9f62 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -16,7 +16,8 @@ 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, ReshapedArray, ReinterpretArray, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec + StridedReshapedArray, ReshapedArray, ReinterpretArray, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec, + MemoryLayout, UnknownLayout using Base: hvcat_fill, iszero, IndexLinear, _length, promote_op, promote_typeof, @propagate_inbounds, @pure, reduce, typed_vcat, AbstractCartesianIndex, RangeIndex, Slice # We use `_length` because of non-1 indices; releases after julia 0.5 @@ -167,35 +168,24 @@ else end ## Traits for memory layouts ## -abstract type MemoryLayout{T} end -struct UnknownLayout{T} <: MemoryLayout{T} end -abstract type DenseLayout{T} <: MemoryLayout{T} end -abstract type BlasMatrixLayout{T} <: DenseLayout{T} end -abstract type DenseColumns{T} <: BlasMatrixLayout{T} end +abstract type AbstractStridedLayout{T} <: MemoryLayout{T} end +abstract type DenseColumns{T} <: AbstractStridedLayout{T} end struct DenseColumnMajor{T} <: DenseColumns{T} end struct DenseColumnsStridedRows{T} <: DenseColumns{T} end -abstract type DenseRows{T} <: BlasMatrixLayout{T} end +abstract type DenseRows{T} <: AbstractStridedLayout{T} end struct DenseRowMajor{T} <: DenseRows{T} end struct DenseRowsStridedColumns{T} <: DenseRows{T} end -struct StridedLayout{T} <: DenseLayout{T} end +struct StridedLayout{T} <: AbstractStridedLayout{T} end """ - UnknownLayout{T}() - -is returned by `MemoryLayout(A)` is unknown if or how the entries of an array `A` -are stored in memory. -""" -UnknownLayout - -""" - DenseLayout{T} + AbstractStridedLayout{T} is an abstract type whose subtypes are returned by `MemoryLayout(A)` if a matrix or vector `A` have storage laid out at regular offsets in memory, and which can therefore be passed to external C and Fortran functions expecting this memory layout. """ -DenseLayout +AbstractStridedLayout """ DenseColumnMajor{T}() @@ -247,29 +237,6 @@ of `stride(A,2)`. `Array`s with `StridedLayout` must conform to the `DenseArray` """ StridedLayout -""" - MemoryLayout(A) - MemoryLayout(typeof(A)) - -`MemoryLayout` specifies the layout in memory for an array `A`. When -you define a new `AbstractArray` type, you can choose to implement -memory layout to indicate that an array is strided in memory. If you decide to -implement memory layout, then you must set this trait for your array -type: - - Base.MemoryLayout(::Type{M}) where M <: MyArray{T,N} where {T,N} = Base.StridedLayout{T,N}() - -The default is `Base.UnknownLayout{T,N}()` to indicate that the layout -in memory is unknown. - -Julia's internal linear algebra machinery will automatically (and invisibly) -dispatch to BLAS and LAPACK routines if the memory layout is BLAS 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::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)`. -""" -MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout{T}() - MemoryLayout(A::Vector{T}) where T = DenseColumnMajor{T}() MemoryLayout(A::Matrix{T}) where T = DenseColumnMajor{T}() MemoryLayout(A::DenseArray{T}) where T = StridedLayout{T}() @@ -278,7 +245,7 @@ MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindic submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() submemorylayout(::DenseColumns{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = DenseColumnMajor{T}() -submemorylayout(::DenseLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = +submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = StridedLayout{T}() submemorylayout(::DenseColumns{T}, ::Tuple{I,Int}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = DenseColumnMajor{T}() @@ -288,11 +255,17 @@ submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Union{AbstractUnitRa DenseColumnMajor{T}() submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Slice} = DenseColumnMajor{T}() -submemorylayout(::DenseColumns{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = +submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:AbstractUnitRange{Int}} = + DenseColumnMajor{T}() +submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + DenseColumnsStridedRows{T}() +submemorylayout(::DenseColumns{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = DenseColumnsStridedRows{T}() -submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex},I2<:Slice} = +submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:Slice} = + DenseRowMajor{T}() +submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = DenseRowsStridedColumns{T}() -submemorylayout(::DenseLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = +submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = StridedLayout{T}() MemoryLayout(A::ReshapedArray) = reshapedmemorylayout(MemoryLayout(parent(A))) diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index 8754d01a3dcce..61e25c1923cbb 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -1,7 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Base: @propagate_inbounds, _return_type, _default_type, @_inline_meta -import Base: length, size, axes, IndexStyle, getindex, setindex!, parent, vec, convert, similar +import Base: length, size, axes, IndexStyle, getindex, setindex!, parent, vec, convert, similar, conj ### basic definitions (types, aliases, constructors, abstractarray interface, sundry similar) @@ -107,56 +107,14 @@ IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() # MemoryLayout of transposed and adjoint matrices -abstract type ConjDenseColumns{T<:Complex} <: BlasMatrixLayout{T} end -struct ConjDenseColumnMajor{T<:Complex} <: ConjDenseColumns{T} end -struct ConjDenseColumnsStridedRows{T<:Complex} <: ConjDenseColumns{T} end -abstract type ConjDenseRows{T<:Complex} <: BlasMatrixLayout{T} end -struct ConjDenseRowMajor{T<:Complex} <: ConjDenseRows{T} end -struct ConjDenseRowsStridedColumns{T<:Complex} <: ConjDenseRows{T} end -struct ConjStridedLayout{T<:Complex} <: DenseLayout{T} end - -""" - ConjDenseColumnMajor{T}() - -is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory -equivalent to the complex conjugate of an `Array`, so that `stride(A,1) == 1` -and `stride(A,2) == size(A,1)`. -`Array`s with `ConjDenseColumnMajor` must conform to the `DenseArray` interface -and `adjoint(A)` should return a matrix whose layout is `DenseRowMajor{T}()`. -""" -ConjDenseColumnMajor - -""" - ConjDenseColumnsStridedRows{T}() - -is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory -as a column major matrix, where the complex conjugates of the entries of `A` -are stored. -`Array`s with `ConjDenseColumnsStridedRows` must conform to the `DenseArray` interface, -and `adjoint(A)` should return a matrix whose layout is `DenseRowsStridedColumns{T}()`. -""" -ConjDenseColumnsStridedRows - -""" - ConjDenseRowMajor{T}() - -is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory -equivalent to the adjoint of an `Array`, so that `stride(A,1) == 1` and `stride(A,2) == size(A,1)`. -`Array`s with `ConjDenseRowMajor` must conform to the `DenseArray` interface -and `adjoint(A)` should return a matrix whose layout is `DenseColumnMajor{T}()`. -""" -ConjDenseRowMajor - -""" - ConjDenseRowsStridedColumns{T}() +struct ConjLayout{T<:Complex, ML<:MemoryLayout} <: MemoryLayout{T} + layout::ML +end +ConjLayout(layout::MemoryLayout{T}) where T<:Complex = ConjLayout{T, typeof(layout)}(layout) +conj(::UnknownLayout{T}) where T = UnknownLayout{T}() +conj(c::ConjLayout) = c.layout +conj(layout::MemoryLayout{T}) where T<:Complex = ConjLayout(layout) -is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory -as a column major matrix, where the complex conjugates of the entries of `A` -are stored. -`Array`s with `ConjDenseRowsStridedColumns` must conform to the `DenseArray` interface, -and `adjoint(A)` should return a matrix whose layout is `DenseColumnsStridedRows{T}()`. -""" -ConjDenseRowsStridedColumns MemoryLayout(A::Adjoint) = adjoint(MemoryLayout(parent(A))) MemoryLayout(A::Transpose) = transpose(MemoryLayout(parent(A))) @@ -168,19 +126,13 @@ transpose(::DenseColumnMajor{T}) where T = DenseRowMajor{T}() transpose(::DenseRowMajor{T}) where T = DenseColumnMajor{T}() adjoint(::MemoryLayout{T}) where T = UnknownLayout{T}() adjoint(M::MemoryLayout{T}) where T<:Real = transpose(M) -adjoint(::StridedLayout{T}) where T<:Complex = ConjStridedLayout{T}() -adjoint(::DenseColumnsStridedRows{T}) where T<:Complex = ConjDenseRowsStridedColumns{T}() -adjoint(::DenseRowsStridedColumns{T}) where T<:Complex = ConjDenseColumnsStridedRows{T}() -adjoint(::ConjDenseColumnsStridedRows{T}) where T<:Complex = DenseRowsStridedColumns{T}() -adjoint(::ConjDenseRowsStridedColumns{T}) where T<:Complex = DenseColumnsStridedRows{T}() -adjoint(::DenseColumnMajor{T}) where T<:Complex = ConjDenseRowMajor{T}() -adjoint(::DenseRowMajor{T}) where T<:Complex = ConjDenseColumnMajor{T}() -adjoint(::ConjDenseColumnMajor{T}) where T<:Complex = DenseRowMajor{T}() -adjoint(::ConjDenseRowMajor{T}) where T<:Complex = DenseColumnMajor{T}() +adjoint(M::ConjLayout{T}) where T<:Complex = transpose(conj(M)) +adjoint(M::MemoryLayout{T}) where T<:Complex = conj(transpose(M)) +submemorylayout(M::ConjLayout{T}, t::Tuple) where T<:Complex = conj(submemorylayout(conj(M), t)) # Adjoints and transposes conform to the strided array interface if their parent does -unsafe_convert(::Ptr{T}, A::AdjOrTrans{T,S}) where {T,S} = unsafe_convert(Ptr{T}, parent(A)) -strides(A::AdjOrTrans) = reverse(strides(parent(A))) +Base.unsafe_convert(::Type{Ptr{T}}, A::AdjOrTrans{T,S}) where {T,S} = Base.unsafe_convert(Ptr{T}, parent(A)) +strides(A::AdjOrTrans) = (stride(parent(A),2), stride(parent(A),1)) @propagate_inbounds getindex(v::AdjOrTransAbsVec, i::Int) = wrapperop(v)(v.parent[i]) @propagate_inbounds getindex(A::AdjOrTransAbsMat, i::Int, j::Int) = wrapperop(A)(A.parent[j, i]) @@ -280,7 +232,7 @@ pinv(v::TransposeAbsVec, tol::Real = 0) = pinv(conj(v.parent)).parent /(u::AdjointAbsVec, A::Transpose{<:Any,<:AbstractMatrix}) = adjoint(conj(A.parent) \ u.parent) # technically should be adjoint(copy(adjoint(copy(A))) \ u.parent) /(u::TransposeAbsVec, A::Adjoint{<:Any,<:AbstractMatrix}) = transpose(conj(A.parent) \ u.parent) # technically should be transpose(copy(transpose(copy(A))) \ u.parent) -# dismabiguation methods +# disambiguation methods *(A::AdjointAbsVec, B::Transpose{<:Any,<:AbstractMatrix}) = A * copy(B) *(A::TransposeAbsVec, B::Adjoint{<:Any,<:AbstractMatrix}) = A * copy(B) *(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractMatrix}) = copy(A) * B diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 0cac3a75dccb1..369026892a282 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -7,16 +7,16 @@ matprod(x, y) = x*y + x*y # Dot products _vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::DenseLayout, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::DenseLayout) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) _vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::DenseLayout, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) -_dotu(x::AbstractVector{T}, y::AbstractVector{T}, ::DenseLayout, ::DenseLayout) where {T<:BlasComplex} = BLAS.dotu(x, y) +_dotu(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotu(x, y) function dot(x::Vector{T}, rx::Union{UnitRange{TI},AbstractRange{TI}}, y::Vector{T}, ry::Union{UnitRange{TI},AbstractRange{TI}}) where {T<:BlasReal,TI<:Integer} @@ -75,12 +75,12 @@ julia> Y mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) _mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::DenseLayout, ::DenseLayout, _) where {T<:BlasFloat} = +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::AbstractStridedLayout, _) where {T<:BlasFloat} = mul!(y, A, convert(Vector{T}, x)) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::DenseLayout, ::DenseLayout, ::DenseLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin - function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::DenseLayout, ::DenseLayout, ::DenseLayout) + function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) Afl = reinterpret($elty,A) yfl = reinterpret($elty,y) gemv!(yfl,'N',Afl,x) @@ -89,13 +89,13 @@ for elty in (Float32,Float64) end end -_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseLayout) = +_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::AbstractStridedLayout) = (A = transpose(transA); generic_matvecmul!(y, 'T', A, x)) -_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseLayout) = +_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matvecmul!(y, 'C', A, x)) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::AbstractStridedLayout) where {T<:BlasComplex} = gemv!(y, 'T', transpose(adjA), x) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) where {T<:BlasComplex} = gemv!(y, 'C', adjoint(adjA), x) # Vector-matrix multiplication @@ -147,11 +147,11 @@ mul2!(A, B) = _mul2!(A, B, MemoryLayout(A), MemoryLayout(B)) _mul!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix, _1, _2, _3) = generic_matmatmul!(C, 'N', 'N', A, B) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout, ::DenseLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = gemm_wrapper!(C, 'N', 'N', A, B) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::DenseLayout, ::DenseLayout, ::DenseLayout) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) gemm_wrapper!(Cfl, 'N', 'N', Afl, B) @@ -160,16 +160,16 @@ for elty in (Float32,Float64) end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::AbstractStridedLayout) where {T<:BlasFloat} = (A = transpose(transA); A === B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, _, ::DenseRowsStridedColumns, ::DenseLayout) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, _, ::DenseRowsStridedColumns, ::AbstractStridedLayout) = (A = transpose(transA); generic_matmatmul!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout, ::DenseRowsStridedColumns) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::DenseRowsStridedColumns) where {T<:BlasFloat} = (B = transpose(transB); A === B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::DenseLayout, ::DenseLayout, ::DenseRowsStridedColumns) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::DenseRowsStridedColumns) B = transpose(transB) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) @@ -179,26 +179,26 @@ for elty in (Float32,Float64) end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseRowsStridedColumns) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::DenseRowsStridedColumns) where {T<:BlasFloat} = (A = transpose(transA); B = transpose(transB); gemm_wrapper!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::DenseLayout, ::DenseRowsStridedColumns, ::DenseRowsStridedColumns) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::DenseRowsStridedColumns) = (A = transpose(transA); B = transpose(transB); generic_matmatmul!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseLayout) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) where {T<:BlasComplex} = (A = adjoint(adjA); A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matmatmul!(C, 'C', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout, ::ConjDenseRowsStridedColumns) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}) where {T<:BlasComplex} = (B = adjoint(adjB); A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::DenseLayout, ::DenseLayout, ::ConjDenseRowsStridedColumns) = +_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}) = (B = adjoint(adjB); generic_matmatmul!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::ConjDenseRowsStridedColumns) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}) where {T<:BlasFloat} = (A = adjoint(adjA); B = adjoint(adjB); gemm_wrapper!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::ConjDenseRowsStridedColumns) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}) = (A = adjoint(adjA); B = adjoint(adjB); generic_matmatmul!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::DenseLayout, ::ConjDenseRowsStridedColumns, ::DenseRowsStridedColumns) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::DenseRowsStridedColumns) = (A = adjoint(adjA); B = transpose(transB); generic_matmatmul!(C, 'C', 'T', A, B)) # Supporting functions for matrix multiplication diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index bb8434049b72d..286d770580eb7 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -342,27 +342,27 @@ end ## Matrix-vector product _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::DenseLayout, AL::SymmetricLayout, ::DenseLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, AL::SymmetricLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symv!(AL.uplo, one(T), parent(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::DenseLayout, AL::HermitianLayout, ::DenseLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, AL::HermitianLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemv!(A.uplo, one(T), parent(A), x, zero(T), y) ## Matrix-matrix product _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::DenseLayout, AL::SymmetricLayout, ::DenseLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, AL::SymmetricLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::DenseLayout, ::DenseLayout, BL::SymmetricLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout) where {T<:BlasFloat} = BLAS.symm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::DenseLayout, AL::HermitianLayout, ::DenseLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, AL::HermitianLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::DenseLayout, ::DenseLayout, BL::HermitianLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout) where {T<:BlasComplex} = BLAS.hemm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::DenseLayout, ::Union{HermitianLayout{T}, SymmetricLayout{T}}, ::Union{HermitianLayout{T}, SymmetricLayout{T}}) where {T<:BlasFloat} = + ::AbstractStridedLayout, ::Union{HermitianLayout{T}, SymmetricLayout{T}}, ::Union{HermitianLayout{T}, SymmetricLayout{T}}) where {T<:BlasFloat} = mul!(C, A, Matrix{T}(B)) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 244f56375d5a2..d6d463a98a58c 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -375,7 +375,7 @@ MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, Unit trilayout(_1, _2, ::MemoryLayout{T}) where T = UnknownLayout{T}() trilayout(::Type{Tri}, _, ::DenseColumns{T}) where {Tri,T} = Tri{'N',T}() trilayout(_, ::Type{TriT}, ::DenseRows{T}) where {TriT,T} = TriT{'T',T}() -trilayout(_, ::Type{TriT}, ::ConjDenseRowsStridedColumns{T}) where {TriT,T} = TriT{'C',T}() +trilayout(_, ::Type{TriT}, ::ConjLayout{T,DenseRowsStridedColumns{T}}) where {TriT,T} = TriT{'C',T}() transpose(::UpperTriangularLayout{'N',T}) where {T} = LowerTriangularLayout{'T',T}() transpose(::UnitUpperTriangularLayout{'N',T}) where {T} = UnitLowerTriangularLayout{'T',T}() @@ -553,20 +553,20 @@ for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, ' (:UnitUpperTriangular, :UnitUpperTriangularLayout, 'U', 'U')) @eval begin # Vector multiplication - _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::DenseLayout, ::$memlay, ::DenseLayout) where {T<:BlasFloat} = + _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::AbstractStridedLayout, ::$memlay, ::AbstractStridedLayout) where {T<:BlasFloat} = mul2!(A, copyto!(y, b)) - _mul2!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'N'}, ::DenseLayout) where {T<:BlasFloat} = + _mul2!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'N'}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) - _mul2!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'T'}, ::DenseLayout) where {T<:BlasFloat} = + _mul2!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'T'}, ::AbstractStridedLayout) where {T<:BlasFloat} = (A = transpose(transA); BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - _mul2!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'C'}, ::DenseLayout) where {T<:BlasComplex} = + _mul2!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'C'}, ::AbstractStridedLayout) where {T<:BlasComplex} = (A = adjoint(adjA); BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) # Matrix multiplication - _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::$memlay, ::DenseLayout) where {T<:BlasFloat} = + _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::$memlay, ::AbstractStridedLayout) where {T<:BlasFloat} = mul2!(A, copyto!(C, B)) - _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseLayout, ::DenseLayout, ::$memlay) where {T<:BlasFloat} = + _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::$memlay) where {T<:BlasFloat} = mul1!(copyto!(C, A), B) _mul2!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'N'}, ::DenseColumns) where {T<:BlasFloat} = diff --git a/stdlib/LinearAlgebra/test/adjtrans.jl b/stdlib/LinearAlgebra/test/adjtrans.jl index a8cde50b87739..a43b0b8194fb6 100644 --- a/stdlib/LinearAlgebra/test/adjtrans.jl +++ b/stdlib/LinearAlgebra/test/adjtrans.jl @@ -452,19 +452,19 @@ end @test LinearAlgebra.MemoryLayout(A') == LinearAlgebra.DenseRowMajor{Float64}() @test LinearAlgebra.MemoryLayout(transpose(A)) == LinearAlgebra.DenseRowMajor{Float64}() B = [1.0+im 2; 3 4] - @test LinearAlgebra.MemoryLayout(B') == LinearAlgebra.ConjDenseRowMajor{ComplexF64}() + @test LinearAlgebra.MemoryLayout(B') == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowMajor{ComplexF64}()) @test LinearAlgebra.MemoryLayout(transpose(B)) == LinearAlgebra.DenseRowMajor{ComplexF64}() VA = view(A, 1:1, 1:1) @test LinearAlgebra.MemoryLayout(VA') == LinearAlgebra.DenseRowsStridedColumns{Float64}() @test LinearAlgebra.MemoryLayout(transpose(VA)) == LinearAlgebra.DenseRowsStridedColumns{Float64}() VB = view(B, 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.ConjDenseRowsStridedColumns{ComplexF64}() + @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowsStridedColumns{ComplexF64}()) @test LinearAlgebra.MemoryLayout(transpose(VB)) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() VA = view(A, 1:2:2, 1:2:2) @test LinearAlgebra.MemoryLayout(VA') == LinearAlgebra.StridedLayout{Float64}() @test LinearAlgebra.MemoryLayout(transpose(VA)) == LinearAlgebra.StridedLayout{Float64}() VB = view(B, 1:2:2, 1:2:2) - @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.ConjStridedLayout{ComplexF64}() + @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.ConjLayout(LinearAlgebra.StridedLayout{ComplexF64}()) @test LinearAlgebra.MemoryLayout(transpose(VB)) == LinearAlgebra.StridedLayout{ComplexF64}() VA2 = view(A, [1,2], :) @test LinearAlgebra.MemoryLayout(VA2') == LinearAlgebra.UnknownLayout{Float64}() @@ -477,7 +477,7 @@ end VAt = view(transpose(A), 1:1, 1:1) @test LinearAlgebra.MemoryLayout(VAt) == LinearAlgebra.DenseRowsStridedColumns{Float64}() VBc = view(B', 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VBc) == LinearAlgebra.ConjDenseRowsStridedColumns{ComplexF64}() + @test LinearAlgebra.MemoryLayout(VBc) == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowsStridedColumns{ComplexF64}()) VBt = view(transpose(B), 1:1, 1:1) @test LinearAlgebra.MemoryLayout(VBt) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() end diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index 23bcfc46d0d14..f976747fa39bb 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -854,7 +854,7 @@ struct MyDenseArray{T,N} <: DenseArray{T,N} end @test LinearAlgebra.MemoryLayout(view(A,:,:)) == LinearAlgebra.DenseColumnMajor{Float64}() @test LinearAlgebra.MemoryLayout(view(A,:)) == LinearAlgebra.DenseColumnMajor{Float64}() @test LinearAlgebra.MemoryLayout(view(A,:,1)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,:,1:1)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() + @test LinearAlgebra.MemoryLayout(view(A,:,1:1)) == LinearAlgebra.DenseColumnMajor{Float64}() @test LinearAlgebra.MemoryLayout(view(A,1:1,1)) == LinearAlgebra.DenseColumnMajor{Float64}() @test LinearAlgebra.MemoryLayout(view(A,1,1:1)) == LinearAlgebra.StridedLayout{Float64}() @test LinearAlgebra.MemoryLayout(view(A,1,:)) == LinearAlgebra.StridedLayout{Float64}() From 64e860927abc40d6ea648b19f4d1cb4c60e18bb0 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Mon, 5 Feb 2018 05:24:26 +1100 Subject: [PATCH 18/39] add strides for DenseRowMajor --- stdlib/LinearAlgebra/src/adjtrans.jl | 2 +- stdlib/LinearAlgebra/src/dense.jl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index 61e25c1923cbb..82dc259b9e8d0 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -110,7 +110,7 @@ IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() struct ConjLayout{T<:Complex, ML<:MemoryLayout} <: MemoryLayout{T} layout::ML end -ConjLayout(layout::MemoryLayout{T}) where T<:Complex = ConjLayout{T, typeof(layout)}(layout) +ConjLayout(layout::ML) where ML<:MemoryLayout{T} where T<:Complex = ConjLayout{T,ML}(layout) conj(::UnknownLayout{T}) where T = UnknownLayout{T}() conj(c::ConjLayout) = c.layout conj(layout::MemoryLayout{T}) where T<:Complex = ConjLayout(layout) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index f831501705872..baf231478d7bc 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -130,6 +130,7 @@ strides(a::Array) = size_to_strides(1, size(a)...) strides(a::ReshapedArray) = _dense_strides(size(a), MemoryLayout(parent(a))) strides(a::ReinterpretArray) = _dense_strides(size(a), MemoryLayout(parent(a))) _dense_strides(sz, ::DenseColumnMajor) = size_to_strides(1, sz...) +_dense_strides(sz, ::DenseRowMajor) = reverse(size_to_strides(1, sz...)) function norm(x::StridedVector{T}, rx::Union{UnitRange{TI},AbstractRange{TI}}) where {T<:BlasFloat,TI<:Integer} if minimum(rx) < 1 || maximum(rx) > length(x) From ce99b1b990782ae545607a305ee48668a285d880 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Tue, 6 Feb 2018 08:07:15 +1100 Subject: [PATCH 19/39] strides for BitArray, conj of triangular layouts --- doc/src/manual/interfaces.md | 2 +- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 1 - stdlib/LinearAlgebra/src/dense.jl | 1 + stdlib/LinearAlgebra/src/matmul.jl | 6 +-- stdlib/LinearAlgebra/src/triangular.jl | 33 ++++++++-------- stdlib/LinearAlgebra/test/adjtrans.jl | 40 ++++++++++---------- stdlib/LinearAlgebra/test/dense.jl | 46 +++++++++++------------ stdlib/LinearAlgebra/test/symmetric.jl | 40 ++++++++++---------- stdlib/LinearAlgebra/test/triangular.jl | 22 +++++------ stdlib/SharedArrays/src/SharedArrays.jl | 7 +++- 10 files changed, 98 insertions(+), 100 deletions(-) diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 44d32f0941bb9..9f45c17e5891d 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -399,7 +399,7 @@ perhaps range-types `Ind` of your own design. For more information, see [Arrays |:----------------------------------------------- |:-------------------------------------- |:------------------------------------------------------------------------------------- | | `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. | -| `LinearAlgebra.MemoryLayout(A)` | | Return a subtype of `LinearAlgebra.AbstractStridedLayout`, such as `LinearAlgebra.DenseColumnMajor{T}()`,`LinearAlgebra.DenseRowMajor{T}()`, or `LinearAlgebra.StridedLayout{T}()`. +| `Base.MemoryLayout(A)` | | Return a subtype of `LinearAlgebra.AbstractStridedLayout`, such as `LinearAlgebra.DenseColumnMajor{T}()`,`LinearAlgebra.DenseRowMajor{T}()`, or `LinearAlgebra.StridedLayout{T}()`. | **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. | diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 5f77c9d6a9f62..fc4e6378d3f61 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -239,7 +239,6 @@ StridedLayout MemoryLayout(A::Vector{T}) where T = DenseColumnMajor{T}() MemoryLayout(A::Matrix{T}) where T = DenseColumnMajor{T}() -MemoryLayout(A::DenseArray{T}) where T = StridedLayout{T}() MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index baf231478d7bc..965d9625f099d 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -127,6 +127,7 @@ function stride(a::Union{Array,StridedReshapedArray,StridedReinterpretArray}, i: return s end strides(a::Array) = size_to_strides(1, size(a)...) +strides(a::BitArray) = size_to_strides(1, size(a)...) #TODO: This is needed for permutedims!, but its not clear what stride means here strides(a::ReshapedArray) = _dense_strides(size(a), MemoryLayout(parent(a))) strides(a::ReinterpretArray) = _dense_strides(size(a), MemoryLayout(parent(a))) _dense_strides(sz, ::DenseColumnMajor) = size_to_strides(1, sz...) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 369026892a282..9b8f7762ea097 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -75,9 +75,9 @@ julia> Y mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) _mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::AbstractStridedLayout, _) where {T<:BlasFloat} = +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::DenseColumnsStridedRows, _) where {T<:BlasFloat} = mul!(y, A, convert(Vector{T}, x)) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseColumnsStridedRows, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) @@ -93,7 +93,7 @@ _mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractSt (A = transpose(transA); generic_matvecmul!(y, 'T', A, x)) _mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matvecmul!(y, 'C', A, x)) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::AbstractStridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'T', transpose(adjA), x) _mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) where {T<:BlasComplex} = gemv!(y, 'C', adjoint(adjA), x) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index d6d463a98a58c..a68d6aa566c79 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -375,24 +375,21 @@ MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, Unit trilayout(_1, _2, ::MemoryLayout{T}) where T = UnknownLayout{T}() trilayout(::Type{Tri}, _, ::DenseColumns{T}) where {Tri,T} = Tri{'N',T}() trilayout(_, ::Type{TriT}, ::DenseRows{T}) where {TriT,T} = TriT{'T',T}() -trilayout(_, ::Type{TriT}, ::ConjLayout{T,DenseRowsStridedColumns{T}}) where {TriT,T} = TriT{'C',T}() - -transpose(::UpperTriangularLayout{'N',T}) where {T} = LowerTriangularLayout{'T',T}() -transpose(::UnitUpperTriangularLayout{'N',T}) where {T} = UnitLowerTriangularLayout{'T',T}() -transpose(::LowerTriangularLayout{'N',T}) where {T} = UpperTriangularLayout{'T',T}() -transpose(::UnitLowerTriangularLayout{'N',T}) where {T} = UnitUpperTriangularLayout{'T',T}() -transpose(::UpperTriangularLayout{'T',T}) where {T} = LowerTriangularLayout{'N',T}() -transpose(::UnitUpperTriangularLayout{'T',T}) where {T} = UnitLowerTriangularLayout{'N',T}() -transpose(::LowerTriangularLayout{'T',T}) where {T} = UpperTriangularLayout{'N',T}() -transpose(::UnitLowerTriangularLayout{'T',T}) where {T} = UnitUpperTriangularLayout{'N',T}() -adjoint(::UpperTriangularLayout{'N',T}) where {T<:Complex} = LowerTriangularLayout{'C',T}() -adjoint(::UnitUpperTriangularLayout{'N',T}) where {T<:Complex} = UnitLowerTriangularLayout{'C',T}() -adjoint(::LowerTriangularLayout{'N',T}) where {T<:Complex} = UpperTriangularLayout{'C',T}() -adjoint(::UnitLowerTriangularLayout{'N',T}) where {T<:Complex} = UnitUpperTriangularLayout{'C',T}() -adjoint(::UpperTriangularLayout{'C',T}) where {T<:Complex} = LowerTriangularLayout{'N',T}() -adjoint(::UnitUpperTriangularLayout{'C',T}) where {T<:Complex} = UnitLowerTriangularLayout{'N',T}() -adjoint(::LowerTriangularLayout{'C',T}) where {T<:Complex} = UpperTriangularLayout{'N',T}() -adjoint(::UnitLowerTriangularLayout{'C',T}) where {T<:Complex} = UnitUpperTriangularLayout{'N',T}() +trilayout(_, ::Type{TriT}, ::ConjLayout{T,<:DenseRows}) where {TriT,T} = TriT{'C',T}() + +for (TriLayout, TriLayoutTrans) in ((UpperTriangularLayout, LowerTriangularLayout), + (UnitUpperTriangularLayout, UnitLowerTriangularLayout), + (LowerTriangularLayout, UpperTriangularLayout), + (UnitLowerTriangularLayout, UnitUpperTriangularLayout)) + @eval begin + transpose(::$TriLayout{'N',T}) where T = $TriLayoutTrans{'T',T}() + transpose(::$TriLayout{'T',T}) where T = $TriLayoutTrans{'N',T}() + adjoint(::$TriLayout{'N',T}) where T<:Complex = $TriLayoutTrans{'C',T}() + adjoint(::$TriLayout{'C',T}) where T<:Complex = $TriLayoutTrans{'N',T}() + conj(::$TriLayout{'T',T}) where T<:Complex = $TriLayout{'C',T}() + conj(::$TriLayout{'C',T}) where T<:Complex = $TriLayout{'T',T}() + end +end # Unary operations -(A::LowerTriangular) = LowerTriangular(-A.data) diff --git a/stdlib/LinearAlgebra/test/adjtrans.jl b/stdlib/LinearAlgebra/test/adjtrans.jl index a43b0b8194fb6..7ef5025647097 100644 --- a/stdlib/LinearAlgebra/test/adjtrans.jl +++ b/stdlib/LinearAlgebra/test/adjtrans.jl @@ -449,37 +449,37 @@ end @testset "adjoint and transpose MemoryLayout" begin A = [1.0 2; 3 4] - @test LinearAlgebra.MemoryLayout(A') == LinearAlgebra.DenseRowMajor{Float64}() - @test LinearAlgebra.MemoryLayout(transpose(A)) == LinearAlgebra.DenseRowMajor{Float64}() + @test Base.MemoryLayout(A') == LinearAlgebra.DenseRowMajor{Float64}() + @test Base.MemoryLayout(transpose(A)) == LinearAlgebra.DenseRowMajor{Float64}() B = [1.0+im 2; 3 4] - @test LinearAlgebra.MemoryLayout(B') == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowMajor{ComplexF64}()) - @test LinearAlgebra.MemoryLayout(transpose(B)) == LinearAlgebra.DenseRowMajor{ComplexF64}() + @test Base.MemoryLayout(B') == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowMajor{ComplexF64}()) + @test Base.MemoryLayout(transpose(B)) == LinearAlgebra.DenseRowMajor{ComplexF64}() VA = view(A, 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VA') == LinearAlgebra.DenseRowsStridedColumns{Float64}() - @test LinearAlgebra.MemoryLayout(transpose(VA)) == LinearAlgebra.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(VA') == LinearAlgebra.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(transpose(VA)) == LinearAlgebra.DenseRowsStridedColumns{Float64}() VB = view(B, 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowsStridedColumns{ComplexF64}()) - @test LinearAlgebra.MemoryLayout(transpose(VB)) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() + @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowsStridedColumns{ComplexF64}()) + @test Base.MemoryLayout(transpose(VB)) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() VA = view(A, 1:2:2, 1:2:2) - @test LinearAlgebra.MemoryLayout(VA') == LinearAlgebra.StridedLayout{Float64}() - @test LinearAlgebra.MemoryLayout(transpose(VA)) == LinearAlgebra.StridedLayout{Float64}() + @test Base.MemoryLayout(VA') == LinearAlgebra.StridedLayout{Float64}() + @test Base.MemoryLayout(transpose(VA)) == LinearAlgebra.StridedLayout{Float64}() VB = view(B, 1:2:2, 1:2:2) - @test LinearAlgebra.MemoryLayout(VB') == LinearAlgebra.ConjLayout(LinearAlgebra.StridedLayout{ComplexF64}()) - @test LinearAlgebra.MemoryLayout(transpose(VB)) == LinearAlgebra.StridedLayout{ComplexF64}() + @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(LinearAlgebra.StridedLayout{ComplexF64}()) + @test Base.MemoryLayout(transpose(VB)) == LinearAlgebra.StridedLayout{ComplexF64}() VA2 = view(A, [1,2], :) - @test LinearAlgebra.MemoryLayout(VA2') == LinearAlgebra.UnknownLayout{Float64}() - @test LinearAlgebra.MemoryLayout(transpose(VA2)) == LinearAlgebra.UnknownLayout{Float64}() + @test Base.MemoryLayout(VA2') == LinearAlgebra.UnknownLayout{Float64}() + @test Base.MemoryLayout(transpose(VA2)) == LinearAlgebra.UnknownLayout{Float64}() VB2 = view(B, [1,2], :) - @test LinearAlgebra.MemoryLayout(VB2') == LinearAlgebra.UnknownLayout{ComplexF64}() - @test LinearAlgebra.MemoryLayout(transpose(VB2)) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(VB2') == LinearAlgebra.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(transpose(VB2)) == LinearAlgebra.UnknownLayout{ComplexF64}() VAc = view(A', 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VAc) == LinearAlgebra.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(VAc) == LinearAlgebra.DenseRowsStridedColumns{Float64}() VAt = view(transpose(A), 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VAt) == LinearAlgebra.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(VAt) == LinearAlgebra.DenseRowsStridedColumns{Float64}() VBc = view(B', 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VBc) == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowsStridedColumns{ComplexF64}()) + @test Base.MemoryLayout(VBc) == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowsStridedColumns{ComplexF64}()) VBt = view(transpose(B), 1:1, 1:1) - @test LinearAlgebra.MemoryLayout(VBt) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() + @test Base.MemoryLayout(VBt) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() end end # module TestAdjointTranspose diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index f976747fa39bb..7ff64b3c3b1da 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -845,34 +845,30 @@ end end end -struct MyDenseArray{T,N} <: DenseArray{T,N} end - @testset "MemoryLayout for Array, SubArray, and ReinterpretArray" begin A = [1.0 2; 3 4] - @test LinearAlgebra.MemoryLayout(A) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,:,:)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,:)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,:,1)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,:,1:1)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1:1,1)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1,1:1)) == LinearAlgebra.StridedLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1,:)) == LinearAlgebra.StridedLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1:1,1:2)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1:1,:)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1:2:1,1:2:1)) == LinearAlgebra.StridedLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,1:2:1,:)) == LinearAlgebra.StridedLayout{Float64}() - @test LinearAlgebra.MemoryLayout(view(A,[1,2],:)) == LinearAlgebra.UnknownLayout{Float64}() - - @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(A,(4,),())) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == LinearAlgebra.DenseColumnMajor{Float64}() - @test LinearAlgebra.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == LinearAlgebra.DenseColumnMajor{Float64}() - - @test LinearAlgebra.MemoryLayout(reinterpret(ComplexF64,A)) == LinearAlgebra.DenseColumnMajor{ComplexF64}() - - # this checks that SharedArray knows its layout - LinearAlgebra.MemoryLayout(MyDenseArray{Float64,1}()) == LinearAlgebra.StridedLayout{Float64}() - LinearAlgebra.MemoryLayout(MyDenseArray{Float64,2}()) == LinearAlgebra.StridedLayout{Float64}() + @test Base.MemoryLayout(A) == LinearAlgebra.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,:,:)) == LinearAlgebra.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,:)) == LinearAlgebra.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,:,1)) == LinearAlgebra.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,:,1:1)) == LinearAlgebra.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,1:1,1)) == LinearAlgebra.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,1,1:1)) == LinearAlgebra.StridedLayout{Float64}() + @test Base.MemoryLayout(view(A,1,:)) == LinearAlgebra.StridedLayout{Float64}() + @test Base.MemoryLayout(view(A,1:1,1:2)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() + @test Base.MemoryLayout(view(A,1:1,:)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() + @test Base.MemoryLayout(view(A,1:2:1,1:2:1)) == LinearAlgebra.StridedLayout{Float64}() + @test Base.MemoryLayout(view(A,1:2:1,:)) == LinearAlgebra.StridedLayout{Float64}() + @test Base.MemoryLayout(view(A,[1,2],:)) == LinearAlgebra.UnknownLayout{Float64}() + + @test Base.MemoryLayout(Base.ReshapedArray(A,(4,),())) == LinearAlgebra.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == LinearAlgebra.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == LinearAlgebra.DenseColumnMajor{Float64}() + + @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == LinearAlgebra.DenseColumnMajor{ComplexF64}() + + Base.MemoryLayout(BitArray([true,true,false])) == LinearAlgebra.UnknownLayout{Bool}() end end # module TestDense diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index d6627162d783b..5ce084eb0ecd6 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -489,27 +489,27 @@ end @testset "Symmetric/Hermitian MemoryLayout" begin A = [1.0 2; 3 4] - @test LinearAlgebra.MemoryLayout(Symmetric(A)) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test LinearAlgebra.MemoryLayout(Hermitian(A)) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test LinearAlgebra.MemoryLayout(Transpose(Symmetric(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test LinearAlgebra.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test LinearAlgebra.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test LinearAlgebra.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test LinearAlgebra.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout{Float64}('L') - @test LinearAlgebra.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout{Float64}('L') - @test LinearAlgebra.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout{Float64}('L') - @test LinearAlgebra.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout{Float64}('L') + @test Base.MemoryLayout(Symmetric(A)) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test Base.MemoryLayout(Hermitian(A)) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test Base.MemoryLayout(Transpose(Symmetric(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test Base.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test Base.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test Base.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') + @test Base.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout{Float64}('L') + @test Base.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout{Float64}('L') + @test Base.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout{Float64}('L') + @test Base.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout{Float64}('L') B = [1.0+im 2; 3 4] - @test LinearAlgebra.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout{ComplexF64}('U') - @test LinearAlgebra.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout{ComplexF64}('U') - @test LinearAlgebra.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout{ComplexF64}('U') - @test LinearAlgebra.MemoryLayout(Transpose(Hermitian(B))) == LinearAlgebra.UnknownLayout{ComplexF64}() - @test LinearAlgebra.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.UnknownLayout{ComplexF64}() - @test LinearAlgebra.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout{ComplexF64}('U') - @test LinearAlgebra.MemoryLayout(Symmetric(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() - @test LinearAlgebra.MemoryLayout(Hermitian(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() - @test LinearAlgebra.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout{ComplexF64}('L') - @test LinearAlgebra.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout{ComplexF64}('L') + @test Base.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout{ComplexF64}('U') + @test Base.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout{ComplexF64}('U') + @test Base.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout{ComplexF64}('U') + @test Base.MemoryLayout(Transpose(Hermitian(B))) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.ConjLayout(LinearAlgebra.SymmetricLayout{ComplexF64}('U')) + @test Base.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout{ComplexF64}('U') + @test Base.MemoryLayout(Symmetric(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(Hermitian(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout{ComplexF64}('L') + @test Base.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout{ComplexF64}('L') end end # module TestSymmetric diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index 9266b9dcb1f53..6828367b175fe 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -556,17 +556,17 @@ end (UnitUpperTriangular, LinearAlgebra.UnitUpperTriangularLayout, LinearAlgebra.UnitLowerTriangularLayout), (LowerTriangular, LinearAlgebra.LowerTriangularLayout, LinearAlgebra.UpperTriangularLayout), (UnitLowerTriangular, LinearAlgebra.UnitLowerTriangularLayout, LinearAlgebra.UnitUpperTriangularLayout)) - @test LinearAlgebra.MemoryLayout(TriType(A)) == TriLayout{'N',Float64}() - @test LinearAlgebra.MemoryLayout(TriType(transpose(A))) == TriLayoutTrans{'T',Float64}() - @test LinearAlgebra.MemoryLayout(TriType(A')) == TriLayoutTrans{'T',Float64}() - @test LinearAlgebra.MemoryLayout(transpose(TriType(A))) == TriLayoutTrans{'T',Float64}() - @test LinearAlgebra.MemoryLayout(TriType(A)') == TriLayoutTrans{'T',Float64}() - - @test LinearAlgebra.MemoryLayout(TriType(B)) == TriLayout{'N',ComplexF64}() - @test LinearAlgebra.MemoryLayout(TriType(transpose(B))) == TriLayoutTrans{'T',ComplexF64}() - @test LinearAlgebra.MemoryLayout(TriType(B')) == TriLayoutTrans{'C',ComplexF64}() - @test LinearAlgebra.MemoryLayout(transpose(TriType(B))) == TriLayoutTrans{'T',ComplexF64}() - @test LinearAlgebra.MemoryLayout(TriType(B)') == TriLayoutTrans{'C',ComplexF64}() + @test Base.MemoryLayout(TriType(A)) == TriLayout{'N',Float64}() + @test Base.MemoryLayout(TriType(transpose(A))) == TriLayoutTrans{'T',Float64}() + @test Base.MemoryLayout(TriType(A')) == TriLayoutTrans{'T',Float64}() + @test Base.MemoryLayout(transpose(TriType(A))) == TriLayoutTrans{'T',Float64}() + @test Base.MemoryLayout(TriType(A)') == TriLayoutTrans{'T',Float64}() + + @test Base.MemoryLayout(TriType(B)) == TriLayout{'N',ComplexF64}() + @test Base.MemoryLayout(TriType(transpose(B))) == TriLayoutTrans{'T',ComplexF64}() + @test Base.MemoryLayout(TriType(B')) == TriLayoutTrans{'C',ComplexF64}() + @test Base.MemoryLayout(transpose(TriType(B))) == TriLayoutTrans{'T',ComplexF64}() + @test Base.MemoryLayout(TriType(B)') == TriLayoutTrans{'C',ComplexF64}() end end end # module TestTriangular diff --git a/stdlib/SharedArrays/src/SharedArrays.jl b/stdlib/SharedArrays/src/SharedArrays.jl index 44c681c153995..444c39dc8e11e 100644 --- a/stdlib/SharedArrays/src/SharedArrays.jl +++ b/stdlib/SharedArrays/src/SharedArrays.jl @@ -10,7 +10,8 @@ module SharedArrays using Mmap, Distributed, Random import Base: length, size, ndims, IndexStyle, reshape, convert, deepcopy_internal, - show, getindex, setindex!, fill!, similar, reduce, map!, copyto!, unsafe_convert + show, getindex, setindex!, fill!, similar, reduce, map!, copyto!, unsafe_convert, + strides, stride import Random using Serialization using Serialization: serialize_cycle_header, serialize_type, writetag, UNDEFREF_TAG, serialize, deserialize @@ -343,6 +344,10 @@ for each worker process. """ localindices(S::SharedArray) = S.pidx > 0 ? range_1dim(S, S.pidx) : 1:0 +Base.MemoryLayout(S::SharedArray) = Base.MemoryLayout(sdata(S)) +strides(S::SharedArray) = strides(sdata(S)) +stride(S::SharedArray, i::Int) = stride(sdata(S), i) + unsafe_convert(::Type{Ptr{T}}, S::SharedArray{T}) where {T} = unsafe_convert(Ptr{T}, sdata(S)) unsafe_convert(::Type{Ptr{T}}, S::SharedArray ) where {T} = unsafe_convert(Ptr{T}, sdata(S)) From 33f4e481cb8339ef390dd537a86e05016a81948b Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Tue, 6 Feb 2018 08:27:59 +1100 Subject: [PATCH 20/39] mul1! -> rmul!, mul2! -> lmul! --- stdlib/LinearAlgebra/src/matmul.jl | 13 +--- stdlib/LinearAlgebra/src/triangular.jl | 93 ++++---------------------- 2 files changed, 14 insertions(+), 92 deletions(-) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index e46db5da0e819..a7ad11dbb66e2 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -134,23 +134,14 @@ end Calculate the matrix-matrix product ``AB``, overwriting `A`, and return the result. """ -<<<<<<< HEAD -mul1!(A, B) = _mul1!(A, B, MemoryLayout(A), MemoryLayout(B)) - -======= -rmul!(A, B) ->>>>>>> 4b90831838f84f1c5fb8ec1ed6ed98da7b9fc04d +rmul!(A, B) = _rmul!(A, B, MemoryLayout(A), MemoryLayout(B)) """ lmul!(A, B) Calculate the matrix-matrix product ``AB``, overwriting `B`, and return the result. """ -<<<<<<< HEAD -mul2!(A, B) = _mul2!(A, B, MemoryLayout(A), MemoryLayout(B)) -======= -lmul!(A, B) ->>>>>>> 4b90831838f84f1c5fb8ec1ed6ed98da7b9fc04d +lmul!(A, B) = _lmul!(A, B, MemoryLayout(A), MemoryLayout(B)) _mul!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix, _1, _2, _3) = generic_matmatmul!(C, 'N', 'N', A, B) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 9c1879427985c..c5f3e0cfa77c5 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -543,7 +543,6 @@ lmul!(A::Tridiagonal, B::AbstractTriangular) = A*full!(B) # is this necessary? mul!(C::AbstractMatrix, A::AbstractTriangular, B::Tridiagonal) = mul!(C, copyto!(similar(parent(A)), A), B) mul!(C::AbstractMatrix, A::Tridiagonal, B::AbstractTriangular) = mul!(C, A, copyto!(similar(parent(B)), B)) -<<<<<<< HEAD for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, 'L', 'N'), (:UnitLowerTriangular, :UnitLowerTriangularLayout, 'L', 'U'), @@ -552,103 +551,35 @@ for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, ' @eval begin # Vector multiplication _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::AbstractStridedLayout, ::$memlay, ::AbstractStridedLayout) where {T<:BlasFloat} = - mul2!(A, copyto!(y, b)) + lmul!(A, copyto!(y, b)) - _mul2!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'N'}, ::AbstractStridedLayout) where {T<:BlasFloat} = + _lmul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'N'}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) - _mul2!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'T'}, ::AbstractStridedLayout) where {T<:BlasFloat} = + _lmul!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'T'}, ::AbstractStridedLayout) where {T<:BlasFloat} = (A = transpose(transA); BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - _mul2!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'C'}, ::AbstractStridedLayout) where {T<:BlasComplex} = + _lmul!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'C'}, ::AbstractStridedLayout) where {T<:BlasComplex} = (A = adjoint(adjA); BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) # Matrix multiplication _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::$memlay, ::AbstractStridedLayout) where {T<:BlasFloat} = - mul2!(A, copyto!(C, B)) + lmul!(A, copyto!(C, B)) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::$memlay) where {T<:BlasFloat} = - mul1!(copyto!(C, A), B) + rmul!(copyto!(C, A), B) - _mul2!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'N'}, ::DenseColumns) where {T<:BlasFloat} = + _lmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'N'}, ::DenseColumns) where {T<:BlasFloat} = BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B) - _mul1!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'N'}) where {T<:BlasFloat} = + _rmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'N'}) where {T<:BlasFloat} = BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) - _mul2!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'T'}, ::DenseColumns) where {T<:BlasFloat} = + _lmul!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'T'}, ::DenseColumns) where {T<:BlasFloat} = (A = transpose(transA); BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) - _mul2!(adjA::AbstractMatrix{T}, B::StridedMatrix{T}, ::$memlay{'C'}, ::DenseColumns) where {T<:BlasComplex} = + _lmul!(adjA::AbstractMatrix{T}, B::StridedMatrix{T}, ::$memlay{'C'}, ::DenseColumns) where {T<:BlasComplex} = (A = adjoint(adjA); BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B)) - _mul1!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'T'}) where {T<:BlasFloat} = + _rmul!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'T'}) where {T<:BlasFloat} = (B = transpose(transB); BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) - _mul1!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'C'}) where {T<:BlasComplex} = + _rmul!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'C'}) where {T<:BlasComplex} = (B = adjoint(adjB); BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), B.data, A)) -======= -mul!(C::AbstractVector, A::AbstractTriangular, transB::Transpose{<:Any,<:AbstractVecOrMat}) = - (B = transB.parent; lmul!(A, transpose!(C, B))) -mul!(C::AbstractMatrix, A::AbstractTriangular, transB::Transpose{<:Any,<:AbstractVecOrMat}) = - (B = transB.parent; lmul!(A, transpose!(C, B))) -mul!(C::AbstractMatrix, A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractVecOrMat}) = - (B = adjB.parent; lmul!(A, adjoint!(C, B))) -mul!(C::AbstractVecOrMat, A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractVecOrMat}) = - (B = adjB.parent; lmul!(A, adjoint!(C, B))) - -# The three methods for each op are neceesary to avoid ambiguities with definitions in matmul.jl -mul!(C::AbstractVector , A::AbstractTriangular, B::AbstractVector) = lmul!(A, copyto!(C, B)) -mul!(C::AbstractMatrix , A::AbstractTriangular, B::AbstractVecOrMat) = lmul!(A, copyto!(C, B)) -mul!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = lmul!(A, copyto!(C, B)) -mul!(C::AbstractVector , adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractVector) = - (A = adjA.parent; lmul!(adjoint(A), copyto!(C, B))) -mul!(C::AbstractMatrix , adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = - (A = adjA.parent; lmul!(adjoint(A), copyto!(C, B))) -mul!(C::AbstractVecOrMat, adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = - (A = adjA.parent; lmul!(adjoint(A), copyto!(C, B))) -mul!(C::AbstractVector , transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractVector) = - (A = transA.parent; lmul!(transpose(A), copyto!(C, B))) -mul!(C::AbstractMatrix , transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = - (A = transA.parent; lmul!(transpose(A), copyto!(C, B))) -mul!(C::AbstractVecOrMat, transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = - (A = transA.parent; lmul!(transpose(A), copyto!(C, B))) -mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, copy(B)) -mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = mul!(C, A, copy(B)) -mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, copy(B)) -mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = mul!(C, A, copy(B)) -mul!(C::AbstractVector, A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = throw(MethodError(mul!, (C, A, B))) -mul!(C::AbstractVector, A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = throw(MethodError(mul!, (C, A, B))) - -for (t, uploc, isunitc) in ((:LowerTriangular, 'L', 'N'), - (:UnitLowerTriangular, 'L', 'U'), - (:UpperTriangular, 'U', 'N'), - (:UnitUpperTriangular, 'U', 'U')) - @eval begin - # Vector multiplication - lmul!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasFloat} = - BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) - lmul!(transA::Transpose{<:Any,<:$t{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasFloat} = - (A = transA.parent; BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - lmul!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasReal} = - (A = adjA.parent; BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - lmul!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasComplex} = - (A = adjA.parent; BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) - - # Matrix multiplication - lmul!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = - BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B) - rmul!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = - BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) - - lmul!(transA::Transpose{<:Any,<:$t{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasFloat} = - (A = transA.parent; BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) - lmul!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasComplex} = - (A = adjA.parent; BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B)) - lmul!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasReal} = - (A = adjA.parent; BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) - - rmul!(A::StridedMatrix{T}, transB::Transpose{<:Any,<:$t{T,<:StridedMatrix}}) where {T<:BlasFloat} = - (B = transB.parent; BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) - rmul!(A::StridedMatrix{T}, adjB::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}) where {T<:BlasComplex} = - (B = adjB.parent; BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), B.data, A)) - rmul!(A::StridedMatrix{T}, adjB::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}) where {T<:BlasReal} = - (B = adjB.parent; BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) ->>>>>>> 4b90831838f84f1c5fb8ec1ed6ed98da7b9fc04d # Left division ldiv!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = From 37c44d5d8f29742368292a4bdcb5c2317a693fd8 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sat, 10 Feb 2018 09:55:37 +1100 Subject: [PATCH 21/39] Redesign TriangularLayouts and Symmetric/HermitianLayout, add tests that BLAS routines are called correctly --- stdlib/LinearAlgebra/src/matmul.jl | 45 +++--- stdlib/LinearAlgebra/src/symmetric.jl | 48 ++++--- stdlib/LinearAlgebra/src/triangular.jl | 176 ++++++++++++++++-------- stdlib/LinearAlgebra/test/dense.jl | 16 +++ stdlib/LinearAlgebra/test/symmetric.jl | 47 ++++--- stdlib/LinearAlgebra/test/triangular.jl | 68 +++++++-- 6 files changed, 270 insertions(+), 130 deletions(-) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index a7ad11dbb66e2..7f11a71aac4f7 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -75,12 +75,12 @@ julia> Y mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) _mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::DenseColumnsStridedRows, _) where {T<:BlasFloat} = +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::DenseColumns, _) where {T<:BlasFloat} = mul!(y, A, convert(Vector{T}, x)) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseColumnsStridedRows, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseColumns, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin - function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) + function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::AbstractStridedLayout, ::DenseColumns, ::AbstractStridedLayout) Afl = reinterpret($elty,A) yfl = reinterpret($elty,y) gemv!(yfl,'N',Afl,x) @@ -89,13 +89,13 @@ for elty in (Float32,Float64) end end -_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::AbstractStridedLayout) = +_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::DenseRows, ::AbstractStridedLayout) = (A = transpose(transA); generic_matvecmul!(y, 'T', A, x)) -_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) = +_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matvecmul!(y, 'C', A, x)) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::AbstractStridedLayout) where {T<:BlasFloat} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseRows, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'T', transpose(adjA), x) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::AbstractStridedLayout) where {T<:BlasComplex} = gemv!(y, 'C', adjoint(adjA), x) # Vector-matrix multiplication @@ -135,6 +135,7 @@ end Calculate the matrix-matrix product ``AB``, overwriting `A`, and return the result. """ rmul!(A, B) = _rmul!(A, B, MemoryLayout(A), MemoryLayout(B)) +_rmul!(A, B, _1, _2) = copyto!(A, mul!(similar(A), A, B)) """ lmul!(A, B) @@ -142,7 +143,7 @@ rmul!(A, B) = _rmul!(A, B, MemoryLayout(A), MemoryLayout(B)) Calculate the matrix-matrix product ``AB``, overwriting `B`, and return the result. """ lmul!(A, B) = _lmul!(A, B, MemoryLayout(A), MemoryLayout(B)) - +_lmul!(A, B, _1, _2) = copyto!(B, mul!(similar(B), A, B)) _mul!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix, _1, _2, _3) = generic_matmatmul!(C, 'N', 'N', A, B) @@ -150,7 +151,7 @@ _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::Abstra gemm_wrapper!(C, 'N', 'N', A, B) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::AbstractStridedLayout) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::DenseColumns, ::DenseColumns, ::DenseColumns) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) gemm_wrapper!(Cfl, 'N', 'N', Afl, B) @@ -159,16 +160,16 @@ for elty in (Float32,Float64) end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::AbstractStridedLayout) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::DenseRows, ::DenseColumns) where {T<:BlasFloat} = (A = transpose(transA); A === B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, _, ::DenseRowsStridedColumns, ::AbstractStridedLayout) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::DenseRows, ::AbstractStridedLayout) = (A = transpose(transA); generic_matmatmul!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::DenseRowsStridedColumns) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::DenseColumns, ::DenseRows) where {T<:BlasFloat} = (B = transpose(transB); A === B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::DenseRowsStridedColumns) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::DenseColumns, ::DenseColumns, ::DenseRows) B = transpose(transB) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) @@ -178,26 +179,26 @@ for elty in (Float32,Float64) end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::DenseRowsStridedColumns) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::DenseRows, ::DenseRows) where {T<:BlasFloat} = (A = transpose(transA); B = transpose(transB); gemm_wrapper!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::DenseRowsStridedColumns, ::DenseRowsStridedColumns) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::DenseRows, ::DenseRows) = (A = transpose(transA); B = transpose(transB); generic_matmatmul!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::ConjLayout{<:Complex,<:DenseRows}, ::DenseColumns) where {T<:BlasComplex} = (A = adjoint(adjA); A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::AbstractStridedLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matmatmul!(C, 'C', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::DenseColumns, ::ConjLayout{<:Complex,<:DenseRows}) where {T<:BlasComplex} = (B = adjoint(adjB); A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}) = +_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}) = (B = adjoint(adjB); generic_matmatmul!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::ConjLayout{<:Complex,<:DenseRows}, ::ConjLayout{<:Complex,<:DenseRows}) where {T<:BlasFloat} = (A = adjoint(adjA); B = adjoint(adjB); gemm_wrapper!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::ConjLayout{<:Complex,<:DenseRows}) = (A = adjoint(adjA); B = adjoint(adjB); generic_matmatmul!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRowsStridedColumns}, ::DenseRowsStridedColumns) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::DenseRows) = (A = adjoint(adjA); B = transpose(transB); generic_matmatmul!(C, 'C', 'T', A, B)) # Supporting functions for matrix multiplication diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index 9623bc2c47143..a01869971648b 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -245,22 +245,27 @@ Hermitian{T,S}(A::Hermitian) where {T,S<:AbstractMatrix} = Hermitian{T,S}(conver AbstractMatrix{T}(A::Hermitian) where {T} = Hermitian(convert(AbstractMatrix{T}, A.data), Symbol(A.uplo)) # MemoryLayout of Symmetric/Hermitian -struct SymmetricLayout{T} <: MemoryLayout{T} +struct SymmetricLayout{T,ML<:MemoryLayout} <: MemoryLayout{T} + layout::ML uplo::Char end -struct HermitianLayout{T} <: MemoryLayout{T} +SymmetricLayout(layout::ML, uplo) where ML<:MemoryLayout{T} where T = SymmetricLayout{T,ML}(layout, uplo) +struct HermitianLayout{T,ML<:MemoryLayout} <: MemoryLayout{T} + layout::ML uplo::Char end +HermitianLayout(layout::ML, uplo) where ML<:MemoryLayout{T} where T = HermitianLayout{T,ML}(layout, uplo) + MemoryLayout(A::Hermitian) = hermitianmemorylayout(MemoryLayout(parent(A)), A.uplo) MemoryLayout(A::Symmetric) = symmetricmemorylayout(MemoryLayout(parent(A)), A.uplo) -hermitianmemorylayout(::MemoryLayout{T}, _2) where T = UnknownLayout{T}() -hermitianmemorylayout(::DenseColumns{T}, uplo) where T<:Complex = HermitianLayout{T}(uplo) -hermitianmemorylayout(::DenseColumns{T}, uplo) where T<:Real = SymmetricLayout{T}(uplo) -hermitianmemorylayout(::DenseRows{T}, uplo) where T<:Complex = HermitianLayout{T}(ifelse(uplo == 'U', 'L', 'U')) -hermitianmemorylayout(::DenseRows{T}, uplo) where T<:Real = SymmetricLayout{T}(ifelse(uplo == 'U', 'L', 'U')) -symmetricmemorylayout(::MemoryLayout{T}, _2) where T = UnknownLayout{T}() -symmetricmemorylayout(::DenseColumns{T}, uplo) where T = SymmetricLayout{T}(uplo) -symmetricmemorylayout(::DenseRows{T}, uplo) where T = SymmetricLayout{T}(ifelse(uplo == 'U', 'L', 'U')) +hermitianmemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() +hermitianmemorylayout(layout::DenseColumns{<:Complex}, uplo) = HermitianLayout(layout,uplo) +hermitianmemorylayout(layout::DenseColumns{<:Real}, uplo) = SymmetricLayout(layout,uplo) +hermitianmemorylayout(layout::DenseRows{<:Complex}, uplo) = HermitianLayout(layout,uplo) +hermitianmemorylayout(layout::DenseRows{<:Real}, uplo) = SymmetricLayout(layout,uplo) +symmetricmemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() +symmetricmemorylayout(layout::DenseColumns, uplo) = SymmetricLayout(layout,uplo) +symmetricmemorylayout(layout::DenseRows, uplo) = SymmetricLayout(layout,uplo) adjoint(H::HermitianLayout) = H adjoint(H::SymmetricLayout{<:Real}) = H @@ -405,24 +410,31 @@ end (-)(A::Hermitian{Tv,S}) where {Tv,S} = Hermitian{Tv,S}(-A.data, A.uplo) ## Matrix-vector product -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::SymmetricLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, + ::AbstractStridedLayout, AL::SymmetricLayout{T,<:DenseColumns}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symv!(AL.uplo, one(T), parent(A), x, zero(T), y) +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, + ::AbstractStridedLayout, AL::SymmetricLayout{T,<:DenseRows}, ::AbstractStridedLayout) where {T<:BlasFloat} = + BLAS.symv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(parent(A)), x, zero(T), y) +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, + ::AbstractStridedLayout, AL::HermitianLayout{T,<:DenseColumns}, ::AbstractStridedLayout) where {T<:BlasComplex} = + BLAS.hemv!(AL.uplo, one(T), parent(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::HermitianLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = - BLAS.hemv!(A.uplo, one(T), parent(A), x, zero(T), y) + ::AbstractStridedLayout, AL::HermitianLayout{T,<:DenseRows}, ::AbstractStridedLayout) where {T<:BlasComplex} = + BLAS.hemv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(parent(A)), x, zero(T), y) + ## Matrix-matrix product _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, AL::SymmetricLayout, ::AbstractStridedLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, AL::SymmetricLayout{T,<:DenseColumns}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout{T,<:DenseColumns}) where {T<:BlasFloat} = BLAS.symm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, AL::HermitianLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, AL::HermitianLayout{T,<:DenseColumns}, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout{T,<:DenseColumns}) where {T<:BlasComplex} = BLAS.hemm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index c5f3e0cfa77c5..9a4ec616e08bb 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -364,30 +364,84 @@ diag(A::UpperTriangular) = diag(A.data) diag(A::UnitUpperTriangular) = fill(one(eltype(A)), size(A,1)) # MemoryLayout of triangular matrices -struct LowerTriangularLayout{trans,T} <: MemoryLayout{T} end -struct UnitLowerTriangularLayout{trans,T} <: MemoryLayout{T} end -struct UpperTriangularLayout{trans,T} <: MemoryLayout{T} end -struct UnitUpperTriangularLayout{trans,T} <: MemoryLayout{T} end -MemoryLayout(A::UpperTriangular) = trilayout(UpperTriangularLayout, LowerTriangularLayout, MemoryLayout(parent(A))) -MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, UnitLowerTriangularLayout, MemoryLayout(parent(A))) -MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, UpperTriangularLayout, MemoryLayout(parent(A))) -MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, UnitUpperTriangularLayout, MemoryLayout(parent(A))) -trilayout(_1, _2, ::MemoryLayout{T}) where T = UnknownLayout{T}() -trilayout(::Type{Tri}, _, ::DenseColumns{T}) where {Tri,T} = Tri{'N',T}() -trilayout(_, ::Type{TriT}, ::DenseRows{T}) where {TriT,T} = TriT{'T',T}() -trilayout(_, ::Type{TriT}, ::ConjLayout{T,<:DenseRows}) where {TriT,T} = TriT{'C',T}() +for memlay in (:LowerTriangularLayout, :UnitLowerTriangularLayout, + :UpperTriangularLayout, :UnitUpperTriangularLayout) + @eval begin + struct $memlay{T, ML<:MemoryLayout} <: MemoryLayout{T} + layout::ML + end + $memlay(layout::ML) where ML<:MemoryLayout{T} where T = $memlay{T,ML}(layout) + end +end + +""" + LowerTriangularLayout{trans,T} + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +equivalent to a `LowerTriangular{T,Matrix{T}}` (`trans == 'N'`), +`Adjoint{T,UpperTriangular{T,Matrix{T}}` (`trans == 'C'`), or +`Transpose{T,UpperTriangular{T,Matrix{T}}` (`trans == 'T'`). + +`A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and +`transpose(A).data` must exist if `trans == 'T'`. +""" +LowerTriangularLayout + +""" + UnitLowerTriangularLayout{trans,T} + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +equivalent to a `UnitLowerTriangular{T,Matrix{T}}` (`trans = 'N'`), +`Adjoint{T,UnitUpperTriangular{T,Matrix{T}}` (`trans = 'C'`), or +`Transpose{T,UnitUpperTriangular{T,Matrix{T}}` (`trans = 'T'`). + +`A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and +`transpose(A).data` must exist if `trans == 'T'`. +""" +UnitLowerTriangularLayout + +""" + UpperTriangularLayout{trans,T} + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +equivalent to a `UpperTriangular{T,Matrix{T}}` (`trans = 'N'`), +`Adjoint{T,LowerTriangular{T,Matrix{T}}` (`trans = 'C'`), or +`Transpose{T,LowerTriangular{T,Matrix{T}}` (`trans = 'T'`). + +`A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and +`transpose(A).data` must exist if `trans == 'T'`. +""" +UpperTriangularLayout + +""" + UnitUpperTriangularLayout{trans,T} + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +equivalent to a `UnitUpperTriangular{T,Matrix{T}}` (`trans = 'N'`), +`Adjoint{T,UnitLowerTriangular{T,Matrix{T}}` (`trans = 'C'`), or +`Transpose{T,UnitLowerTriangular{T,Matrix{T}}` (`trans = 'T'`). + +`A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and +`transpose(A).data` must exist if `trans == 'T'`. +""" +UnitUpperTriangularLayout + + +MemoryLayout(A::UpperTriangular) = trilayout(UpperTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, MemoryLayout(parent(A))) +trilayout(_, ::MemoryLayout{T}) where T = UnknownLayout{T}() +trilayout(::Type{Tri}, ML::DenseColumns{T}) where {Tri,T} = Tri(ML) for (TriLayout, TriLayoutTrans) in ((UpperTriangularLayout, LowerTriangularLayout), (UnitUpperTriangularLayout, UnitLowerTriangularLayout), (LowerTriangularLayout, UpperTriangularLayout), (UnitLowerTriangularLayout, UnitUpperTriangularLayout)) @eval begin - transpose(::$TriLayout{'N',T}) where T = $TriLayoutTrans{'T',T}() - transpose(::$TriLayout{'T',T}) where T = $TriLayoutTrans{'N',T}() - adjoint(::$TriLayout{'N',T}) where T<:Complex = $TriLayoutTrans{'C',T}() - adjoint(::$TriLayout{'C',T}) where T<:Complex = $TriLayoutTrans{'N',T}() - conj(::$TriLayout{'T',T}) where T<:Complex = $TriLayout{'C',T}() - conj(::$TriLayout{'C',T}) where T<:Complex = $TriLayout{'T',T}() + transpose(ml::$TriLayout) = $TriLayoutTrans(transpose(ml.layout)) + adjoint(ml::$TriLayout) = $TriLayoutTrans(adjoint(ml.layout)) + conj(ml::$TriLayout) = $TriLayoutTrans(conj(ml.layout)) end end @@ -544,20 +598,20 @@ lmul!(A::Tridiagonal, B::AbstractTriangular) = A*full!(B) # is this necessary? mul!(C::AbstractMatrix, A::AbstractTriangular, B::Tridiagonal) = mul!(C, copyto!(similar(parent(A)), A), B) mul!(C::AbstractMatrix, A::Tridiagonal, B::AbstractTriangular) = mul!(C, A, copyto!(similar(parent(B)), B)) -for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, 'L', 'N'), - (:UnitLowerTriangular, :UnitLowerTriangularLayout, 'L', 'U'), - (:UpperTriangular, :UpperTriangularLayout, 'U', 'N'), - (:UnitUpperTriangular, :UnitUpperTriangularLayout, 'U', 'U')) +for (t, memlay, memlaytrans, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, :UpperTriangularLayout, 'L', 'N'), + (:UnitLowerTriangular, :UnitLowerTriangularLayout, :UnitUpperTriangularLayout, 'L', 'U'), + (:UpperTriangular, :UpperTriangularLayout, :LowerTriangularLayout, 'U', 'N'), + (:UnitUpperTriangular, :UnitUpperTriangularLayout, :UnitLowerTriangularLayout, 'U', 'U')) @eval begin # Vector multiplication _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::AbstractStridedLayout, ::$memlay, ::AbstractStridedLayout) where {T<:BlasFloat} = lmul!(A, copyto!(y, b)) - _lmul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'N'}, ::AbstractStridedLayout) where {T<:BlasFloat} = + _lmul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{T,DC}, ::AbstractStridedLayout) where {T<:BlasFloat,DC<:DenseColumns} = BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) - _lmul!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'T'}, ::AbstractStridedLayout) where {T<:BlasFloat} = + _lmul!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{T,DR}, ::AbstractStridedLayout) where {T<:BlasFloat,DR<:DenseRows} = (A = transpose(transA); BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - _lmul!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{'C'}, ::AbstractStridedLayout) where {T<:BlasComplex} = + _lmul!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{T,ConjLayout{T,DR}}, ::AbstractStridedLayout) where {T<:BlasComplex,DR<:DenseRows} = (A = adjoint(adjA); BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) # Matrix multiplication @@ -566,19 +620,19 @@ for (t, memlay, uploc, isunitc) in ((:LowerTriangular, :LowerTriangularLayout, ' _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::$memlay) where {T<:BlasFloat} = rmul!(copyto!(C, A), B) - _lmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'N'}, ::DenseColumns) where {T<:BlasFloat} = + _lmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{T,DC}, ::DenseColumns) where {T<:BlasFloat,DC<:DenseColumns} = BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B) - _rmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'N'}) where {T<:BlasFloat} = + _rmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::$memlay{T,DC}) where {T<:BlasFloat,DC<:DenseColumns} = BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) - _lmul!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{'T'}, ::DenseColumns) where {T<:BlasFloat} = + _lmul!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{T,DR}, ::DenseColumns) where {T<:BlasFloat,DR<:DenseRows} = (A = transpose(transA); BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) - _lmul!(adjA::AbstractMatrix{T}, B::StridedMatrix{T}, ::$memlay{'C'}, ::DenseColumns) where {T<:BlasComplex} = + _lmul!(adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{T,ConjLayout{T,DR}}, ::DenseColumns) where {T<:BlasComplex,DR<:DenseRows} = (A = adjoint(adjA); BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B)) - _rmul!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'T'}) where {T<:BlasFloat} = + _rmul!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::$memlaytrans{T,DR}) where {T<:BlasFloat,DR<:DenseRows} = (B = transpose(transB); BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) - _rmul!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::$memlay{'C'}) where {T<:BlasComplex} = + _rmul!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::$memlaytrans{T,ConjLayout{T,DR}}) where {T<:BlasComplex,DR<:DenseRows} = (B = adjoint(adjB); BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), B.data, A)) # Left division @@ -714,7 +768,7 @@ for (t, unitt) in ((UpperTriangular, UnitUpperTriangular), end ## Generic triangular multiplication -function lmul!(A::UpperTriangular, B::StridedVecOrMat) +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,<:DenseColumns}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -731,7 +785,7 @@ function lmul!(A::UpperTriangular, B::StridedVecOrMat) B end -function lmul!(A::UnitUpperTriangular, B::StridedVecOrMat) +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,<:DenseColumns}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -748,7 +802,7 @@ function lmul!(A::UnitUpperTriangular, B::StridedVecOrMat) B end -function lmul!(A::LowerTriangular, B::StridedVecOrMat) +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,<:DenseColumns}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -764,7 +818,7 @@ function lmul!(A::LowerTriangular, B::StridedVecOrMat) end B end -function lmul!(A::UnitLowerTriangular, B::StridedVecOrMat) +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,<:DenseColumns}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -781,8 +835,8 @@ function lmul!(A::UnitLowerTriangular, B::StridedVecOrMat) B end -function lmul!(adjA::Adjoint{<:Any,<:UpperTriangular}, B::StridedVecOrMat) - A = adjA.parent +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:DenseRows} + A = adjoint(adjA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -799,7 +853,7 @@ function lmul!(adjA::Adjoint{<:Any,<:UpperTriangular}, B::StridedVecOrMat) B end -function lmul!(adjA::Adjoint{<:Any,<:UnitUpperTriangular}, B::StridedVecOrMat) +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:DenseRows} A = adjA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -817,7 +871,7 @@ function lmul!(adjA::Adjoint{<:Any,<:UnitUpperTriangular}, B::StridedVecOrMat) B end -function lmul!(adjA::Adjoint{<:Any,<:LowerTriangular}, B::StridedVecOrMat) +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:DenseRows} A = adjA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -834,7 +888,7 @@ function lmul!(adjA::Adjoint{<:Any,<:LowerTriangular}, B::StridedVecOrMat) end B end -function lmul!(adjA::Adjoint{<:Any,<:UnitLowerTriangular}, B::StridedVecOrMat) +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:DenseRows} A = adjA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -852,7 +906,7 @@ function lmul!(adjA::Adjoint{<:Any,<:UnitLowerTriangular}, B::StridedVecOrMat) B end -function lmul!(transA::Transpose{<:Any,<:UpperTriangular}, B::StridedVecOrMat) +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,DR}, _) where {T,DR<:DenseRows} A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -869,7 +923,7 @@ function lmul!(transA::Transpose{<:Any,<:UpperTriangular}, B::StridedVecOrMat) end B end -function lmul!(transA::Transpose{<:Any,<:UnitUpperTriangular}, B::StridedVecOrMat) +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,DR}, _) where {T,DR<:DenseRows} A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -887,7 +941,7 @@ function lmul!(transA::Transpose{<:Any,<:UnitUpperTriangular}, B::StridedVecOrMa B end -function lmul!(transA::Transpose{<:Any,<:LowerTriangular}, B::StridedVecOrMat) +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,DR}, _) where {T,DR<:DenseRows} A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -904,7 +958,7 @@ function lmul!(transA::Transpose{<:Any,<:LowerTriangular}, B::StridedVecOrMat) end B end -function lmul!(transA::Transpose{<:Any,<:UnitLowerTriangular}, B::StridedVecOrMat) +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,DR}, _) where {T,DR<:DenseRows} A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -922,7 +976,7 @@ function lmul!(transA::Transpose{<:Any,<:UnitLowerTriangular}, B::StridedVecOrMa B end -function rmul!(A::StridedMatrix, B::UpperTriangular) +function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) @@ -938,7 +992,7 @@ function rmul!(A::StridedMatrix, B::UpperTriangular) end A end -function rmul!(A::StridedMatrix, B::UnitUpperTriangular) +function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) @@ -955,7 +1009,7 @@ function rmul!(A::StridedMatrix, B::UnitUpperTriangular) A end -function rmul!(A::StridedMatrix, B::LowerTriangular) +function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) @@ -971,7 +1025,7 @@ function rmul!(A::StridedMatrix, B::LowerTriangular) end A end -function rmul!(A::StridedMatrix, B::UnitLowerTriangular) +function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) @@ -988,8 +1042,8 @@ function rmul!(A::StridedMatrix, B::UnitLowerTriangular) A end -function rmul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UpperTriangular}) - B = adjB.parent +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:DenseRows} + B = adjoint(adjB) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) @@ -1006,8 +1060,8 @@ function rmul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UpperTriangular}) A end -function rmul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UnitUpperTriangular}) - B = adjB.parent +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:DenseRows} + B = adjoint(adjB) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) @@ -1024,8 +1078,8 @@ function rmul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UnitUpperTriangular}) A end -function rmul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:LowerTriangular}) - B = adjB.parent +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:DenseRows} + B = adjoint(adjB) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) @@ -1042,8 +1096,8 @@ function rmul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:LowerTriangular}) A end -function rmul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UnitLowerTriangular}) - B = adjB.parent +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:DenseRows} + B = adjoint(adjB) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) @@ -1060,8 +1114,8 @@ function rmul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UnitLowerTriangular}) A end -function rmul!(A::StridedMatrix, transB::Transpose{<:Any,<:UpperTriangular}) - B = transB.parent +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{T,DR}) where {T,DR<:DenseRows} + B = transpose(transB) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) @@ -1077,7 +1131,7 @@ function rmul!(A::StridedMatrix, transB::Transpose{<:Any,<:UpperTriangular}) end A end -function rmul!(A::StridedMatrix, transB::Transpose{<:Any,<:UnitUpperTriangular}) +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{T,DR}) where {T,DR<:DenseRows} B = transB.parent m, n = size(A) if size(B, 1) != n @@ -1095,7 +1149,7 @@ function rmul!(A::StridedMatrix, transB::Transpose{<:Any,<:UnitUpperTriangular}) A end -function rmul!(A::StridedMatrix, transB::Transpose{<:Any,<:LowerTriangular}) +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{T,DR}) where {T,DR<:DenseRows} B = transB.parent m, n = size(A) if size(B, 1) != n @@ -1113,7 +1167,7 @@ function rmul!(A::StridedMatrix, transB::Transpose{<:Any,<:LowerTriangular}) A end -function rmul!(A::StridedMatrix, transB::Transpose{<:Any,<:UnitLowerTriangular}) +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{T,DR}) where {T,DR<:DenseRows} B = transB.parent m, n = size(A) if size(B, 1) != n diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index 7ff64b3c3b1da..7dd2d30bc3e8b 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -869,6 +869,22 @@ end @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == LinearAlgebra.DenseColumnMajor{ComplexF64}() Base.MemoryLayout(BitArray([true,true,false])) == LinearAlgebra.UnknownLayout{Bool}() + + A = rand(100,100) + x = rand(100) + @test all(A*x .=== view(A,:,:)*x .=== view(A',:,:)'*x .=== + BLAS.gemv!('N', 1.0, A, x, 0.0, similar(x))) + @test all(A'*x .=== view(A',:,:)*x .=== view(A,:,:)'*x .=== + BLAS.gemv!('T', 1.0, A, x, 0.0, similar(x))) + + B = rand(ComplexF64,100,100) + y = rand(ComplexF64,100) + @test all(B*y .=== view(B,:,:)*y .=== view(B',:,:)'*y .=== transpose(view(transpose(B),:,:))*y .=== + BLAS.gemv!('N', one(ComplexF64), B, y, zero(ComplexF64), similar(y))) + @test all(B'*y .=== view(B',:,:)*y .=== view(B,:,:)'*y .=== + BLAS.gemv!('C', one(ComplexF64), B, y, zero(ComplexF64), similar(y))) + @test all(transpose(B)*y .=== view(transpose(B),:,:)*y .=== transpose(view(B,:,:))*y .=== + BLAS.gemv!('T', one(ComplexF64), B, y, zero(ComplexF64), similar(y))) end end # module TestDense diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index 5c974aca35afe..e296f40b4925e 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -489,27 +489,38 @@ end @testset "Symmetric/Hermitian MemoryLayout" begin A = [1.0 2; 3 4] - @test Base.MemoryLayout(Symmetric(A)) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test Base.MemoryLayout(Hermitian(A)) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test Base.MemoryLayout(Transpose(Symmetric(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test Base.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test Base.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test Base.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout{Float64}('U') - @test Base.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout{Float64}('L') - @test Base.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout{Float64}('L') - @test Base.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout{Float64}('L') - @test Base.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout{Float64}('L') + @test Base.MemoryLayout(Symmetric(A)) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Hermitian(A)) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Transpose(Symmetric(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{Float64}(),'U') + @test Base.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{Float64}(),'U') + @test Base.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{Float64}(),'U') + @test Base.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{Float64}(),'U') B = [1.0+im 2; 3 4] - @test Base.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout{ComplexF64}('U') - @test Base.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout{ComplexF64}('U') - @test Base.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout{ComplexF64}('U') + @test Base.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U') @test Base.MemoryLayout(Transpose(Hermitian(B))) == LinearAlgebra.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.ConjLayout(LinearAlgebra.SymmetricLayout{ComplexF64}('U')) - @test Base.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout{ComplexF64}('U') + @test Base.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.ConjLayout(LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U')) + @test Base.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U') @test Base.MemoryLayout(Symmetric(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() @test Base.MemoryLayout(Hermitian(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout{ComplexF64}('L') - @test Base.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout{ComplexF64}('L') + @test Base.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout(LinearAlgebra.DenseRowMajor{ComplexF64}(),'U') + + A = randn(100,100) + x = randn(100) + @test all(Symmetric(A)*x .=== Hermitian(A)*x .=== Symmetric(A)'*x .=== Symmetric(view(A,:,:)',:L)*x .=== BLAS.symv!('U', 1.0, A, x, 0.0, similar(x))) + @test all(Symmetric(A,:L)*x .=== Hermitian(A,:L)*x .=== Symmetric(A,:L)'*x .=== Symmetric(view(A,:,:)',:U)*x .=== BLAS.symv!('L', 1.0, A, x, 0.0, similar(x))) + A = randn(ComplexF64,100,100) + x = randn(ComplexF64,100) + @test all(Symmetric(A)*x .=== transpose(Symmetric(A))*x .=== Symmetric(transpose(view(A,:,:)),:L)*x .=== BLAS.symv!('U', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) + @test all(Symmetric(A,:L)*x .=== transpose(Symmetric(A,:L))*x .=== Symmetric(transpose(view(A,:,:)),:U)*x .=== BLAS.symv!('L', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) + @test all(Hermitian(A)*x .=== Hermitian(A)'*x .=== BLAS.hemv!('U', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) + @test all(Hermitian(A,:L)*x .=== Hermitian(A,:L)'*x .=== BLAS.hemv!('L', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) end @testset "#25625 recursive transposition" begin @@ -534,4 +545,4 @@ end @test H == adjoint(H) == Matrix(H) == Matrix(adjoint(H)) == adjoint(Matrix(H)) end -end # module TestSymmetric +end # module TestSymmetricx diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index 36f42382aebca..2f6501305bd0a 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -556,17 +556,63 @@ end (UnitUpperTriangular, LinearAlgebra.UnitUpperTriangularLayout, LinearAlgebra.UnitLowerTriangularLayout), (LowerTriangular, LinearAlgebra.LowerTriangularLayout, LinearAlgebra.UpperTriangularLayout), (UnitLowerTriangular, LinearAlgebra.UnitLowerTriangularLayout, LinearAlgebra.UnitUpperTriangularLayout)) - @test Base.MemoryLayout(TriType(A)) == TriLayout{'N',Float64}() - @test Base.MemoryLayout(TriType(transpose(A))) == TriLayoutTrans{'T',Float64}() - @test Base.MemoryLayout(TriType(A')) == TriLayoutTrans{'T',Float64}() - @test Base.MemoryLayout(transpose(TriType(A))) == TriLayoutTrans{'T',Float64}() - @test Base.MemoryLayout(TriType(A)') == TriLayoutTrans{'T',Float64}() - - @test Base.MemoryLayout(TriType(B)) == TriLayout{'N',ComplexF64}() - @test Base.MemoryLayout(TriType(transpose(B))) == TriLayoutTrans{'T',ComplexF64}() - @test Base.MemoryLayout(TriType(B')) == TriLayoutTrans{'C',ComplexF64}() - @test Base.MemoryLayout(transpose(TriType(B))) == TriLayoutTrans{'T',ComplexF64}() - @test Base.MemoryLayout(TriType(B)') == TriLayoutTrans{'C',ComplexF64}() + @test Base.MemoryLayout(TriType(A)) == TriLayout(LinearAlgebra.DenseColumnMajor{Float64}()) + @test Base.MemoryLayout(TriType(transpose(A))) == Base.UnknownLayout{Float64}() + @test Base.MemoryLayout(TriType(A')) == Base.UnknownLayout{Float64}() + @test Base.MemoryLayout(transpose(TriType(A))) == TriLayoutTrans(LinearAlgebra.DenseRowMajor{Float64}()) + @test Base.MemoryLayout(TriType(A)') == TriLayoutTrans(LinearAlgebra.DenseRowMajor{Float64}()) + + @test Base.MemoryLayout(TriType(B)) == TriLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}()) + @test Base.MemoryLayout(TriType(transpose(B))) == Base.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(TriType(B')) == Base.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(transpose(TriType(B))) == TriLayoutTrans(LinearAlgebra.DenseRowMajor{ComplexF64}()) + @test Base.MemoryLayout(TriType(B)') == TriLayoutTrans(conj(LinearAlgebra.DenseRowMajor{ComplexF64}())) end + + A = randn(Float64, 100, 100) + x = randn(Float64, 100) + @test all(UpperTriangular(A)*x .=== UpperTriangular(view(A',:,:)')*x .=== + BLAS.trmv!('U', 'N', 'N', A, copy(x))) + @test all(UnitUpperTriangular(A)*x .=== UnitUpperTriangular(view(A',:,:)')*x .=== + BLAS.trmv!('U', 'N', 'U', A, copy(x))) + @test all(LowerTriangular(A)*x .=== LowerTriangular(view(A',:,:)')*x .=== + BLAS.trmv!('L', 'N', 'N', A, copy(x))) + @test all(UnitLowerTriangular(A)*x .=== UnitLowerTriangular(view(A',:,:)')*x .=== + BLAS.trmv!('L', 'N', 'U', A, copy(x))) + @test all(UpperTriangular(A)'*x .=== UpperTriangular(view(A',:,:)')'*x .=== + BLAS.trmv!('U', 'T', 'N', A, copy(x))) + @test all(UnitUpperTriangular(A)'*x .=== UnitUpperTriangular(view(A',:,:)')'*x .=== + BLAS.trmv!('U', 'T', 'U', A, copy(x))) + @test all(LowerTriangular(A)'*x .=== LowerTriangular(view(A',:,:)')'*x .=== + BLAS.trmv!('L', 'T', 'N', A, copy(x))) + @test all(UnitLowerTriangular(A)'*x .=== UnitLowerTriangular(view(A',:,:)')'*x .=== + BLAS.trmv!('L', 'T', 'U', A, copy(x))) + + A = randn(ComplexF64, 100, 100) + x = randn(ComplexF64, 100) + @test all(UpperTriangular(A)*x .=== UpperTriangular(view(A',:,:)')*x .=== + BLAS.trmv!('U', 'N', 'N', A, copy(x))) + @test all(UnitUpperTriangular(A)*x .=== UnitUpperTriangular(view(A',:,:)')*x .=== + BLAS.trmv!('U', 'N', 'U', A, copy(x))) + @test all(LowerTriangular(A)*x .=== LowerTriangular(view(A',:,:)')*x .=== + BLAS.trmv!('L', 'N', 'N', A, copy(x))) + @test all(UnitLowerTriangular(A)*x .=== UnitLowerTriangular(view(A',:,:)')*x .=== + BLAS.trmv!('L', 'N', 'U', A, copy(x))) + @test all(transpose(UpperTriangular(A))*x .=== transpose(UpperTriangular(view(A',:,:)'))*x .=== + BLAS.trmv!('U', 'T', 'N', A, copy(x))) + @test all(transpose(UnitUpperTriangular(A))*x .=== transpose(UnitUpperTriangular(view(A',:,:)'))*x .=== + BLAS.trmv!('U', 'T', 'U', A, copy(x))) + @test all(transpose(LowerTriangular(A))*x .=== transpose(LowerTriangular(view(A',:,:)'))*x .=== + BLAS.trmv!('L', 'T', 'N', A, copy(x))) + @test all(transpose(UnitLowerTriangular(A))*x .=== transpose(UnitLowerTriangular(view(A',:,:)'))*x .=== + BLAS.trmv!('L', 'T', 'U', A, copy(x))) + @test all(UpperTriangular(A)'*x .=== UpperTriangular(view(A',:,:)')'*x .=== + BLAS.trmv!('U', 'C', 'N', A, copy(x))) + @test all(UnitUpperTriangular(A)'*x .=== UnitUpperTriangular(view(A',:,:)')'*x .=== + BLAS.trmv!('U', 'C', 'U', A, copy(x))) + @test all(LowerTriangular(A)'*x .=== LowerTriangular(view(A',:,:)')'*x .=== + BLAS.trmv!('L', 'C', 'N', A, copy(x))) + @test all(UnitLowerTriangular(A)'*x .=== UnitLowerTriangular(view(A',:,:)')'*x .=== + BLAS.trmv!('L', 'C', 'U', A, copy(x))) end end # module TestTriangular From c5ddd013251335b11fdc6bf83ac92c5689829661 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Wed, 14 Feb 2018 19:14:07 +1100 Subject: [PATCH 22/39] Move MemoryLayout routines to Base --- base/abstractarray.jl | 83 +++++++++++++++- base/reinterpretarray.jl | 4 + base/reshapedarray.jl | 5 + base/subarray.jl | 27 ++++++ doc/src/manual/interfaces.md | 2 +- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 111 +--------------------- stdlib/LinearAlgebra/src/adjtrans.jl | 2 +- stdlib/LinearAlgebra/test/adjtrans.jl | 40 ++++---- stdlib/LinearAlgebra/test/dense.jl | 26 +---- stdlib/LinearAlgebra/test/symmetric.jl | 40 ++++---- stdlib/LinearAlgebra/test/triangular.jl | 12 +-- test/abstractarray.jl | 26 +++++ 12 files changed, 191 insertions(+), 187 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 89952bb1cb659..745f6cb10535b 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -273,15 +273,83 @@ size_to_strides(s) = () abstract type MemoryLayout{T} end struct UnknownLayout{T} <: MemoryLayout{T} end +abstract type AbstractStridedLayout{T} <: MemoryLayout{T} end +abstract type DenseColumns{T} <: AbstractStridedLayout{T} end +struct DenseColumnMajor{T} <: DenseColumns{T} end +struct DenseColumnsStridedRows{T} <: DenseColumns{T} end +abstract type DenseRows{T} <: AbstractStridedLayout{T} end +struct DenseRowMajor{T} <: DenseRows{T} end +struct DenseRowsStridedColumns{T} <: DenseRows{T} end +struct StridedLayout{T} <: AbstractStridedLayout{T} end """ UnknownLayout{T}() -is returned by `MemoryLayout(A)` is unknown if or how the entries of an array `A` +is returned by `MemoryLayout(A)` if it is unknown how the entries of an array `A` are stored in memory. """ UnknownLayout +""" + AbstractStridedLayout{T} + +is an abstract type whose subtypes are returned by `MemoryLayout(A)` +if a matrix or vector `A` have storage laid out at regular offsets in memory, +and which can therefore be passed to external C and Fortran functions expecting +this memory layout. +""" +AbstractStridedLayout + +""" + DenseColumnMajor{T}() + +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory +equivalent to an `Array`, so that `stride(A,1) == 1` and `stride(A,2) == size(A,1)`. +Arrays with `DenseColumnMajor` must conform to the `DenseArray` interface. +""" +DenseColumnMajor + +""" + DenseColumnsStridedRows{T}() + +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory +as a column major matrix. In other words, the columns are stored in memory with +offsets of one, while the rows are stored with offsets given by `stride(A,2)`. +Arrays with `DenseColumnsStridedRows` must conform to the `DenseArray` interface. +""" +DenseColumnsStridedRows + +""" + DenseRowMajor{T}() + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +equivalent to the transpose of an `Array`, so that `stride(A,1) == size(A,1)` and +`stride(A,2) == 1`. Arrays with `DenseRowMajor` must conform to the +`DenseArray` interface. +""" +DenseRowMajor + +""" + DenseRowsStridedColumns{T}() + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +as a row major matrix. In other words, the rows are stored in memory with +offsets of one, while the columns are stored with offsets given by `stride(A,1)`. +Arrays with `DenseRowsStridedColumns` must conform to the `DenseArray` interface, +and `transpose(A)` should return a matrix whose layout is `DenseColumnsStridedRows{T}()`. +""" +DenseRowsStridedColumns + +""" + StridedLayout{T}() + +is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage laid out at regular +offsets in memory. In other words, the columns are stored with offsets given +by `stride(A,1)` and for matrices the rows are stored in memory with offsets +of `stride(A,2)`. `Array`s with `StridedLayout` must conform to the `DenseArray` interface. +""" +StridedLayout + """ MemoryLayout(A) MemoryLayout(typeof(A)) @@ -290,21 +358,26 @@ UnknownLayout you define a new `AbstractArray` type, you can choose to implement memory layout to indicate that an array is strided in memory. If you decide to implement memory layout, then you must set this trait for your array -type: +type: for example, if your matrix is column major with `stride(A,2) == size(A,1)`, +then override as follows: - Base.MemoryLayout(::Type{M}) where M <: MyArray{T,N} where {T} = LinearAlgebra.StridedLayout{T}() + Base.MemoryLayout(::Type{M}) where M <: MyMatrix{T} where {T} = Base.DenseColumnMajor{T}() -The default is `Base.UnknownLayout{T,N}()` to indicate that the layout +The default is `Base.UnknownLayout{T}()` to indicate that the layout in memory is unknown. Julia's internal linear algebra machinery will automatically (and invisibly) dispatch to BLAS and LAPACK routines if the memory layout is BLAS 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::MyArray)` and `unknown_convert(::Type{Ptr{T}}, A::MyArray)`. +overrides of `strides(A::MyMatrix)` and `unknown_convert(::Type{Ptr{T}}, A::MyMatrix)`. """ MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout{T}() +MemoryLayout(A::Vector{T}) where T = DenseColumnMajor{T}() +MemoryLayout(A::Matrix{T}) where T = DenseColumnMajor{T}() + + function isassigned(a::AbstractArray, i::Int...) try diff --git a/base/reinterpretarray.jl b/base/reinterpretarray.jl index 5e79d13dd2b65..cca152affe8a8 100644 --- a/base/reinterpretarray.jl +++ b/base/reinterpretarray.jl @@ -41,6 +41,10 @@ function size(a::ReinterpretArray{T,N,S} where {N}) where {T,S} tuple(size1, tail(psize)...) end +MemoryLayout(A::ReinterpretArray{V}) where V = reinterpretedmemorylayout(MemoryLayout(parent(A)), V) +reinterpretedmemorylayout(::MemoryLayout{T}, ::Type{V}) where {T,V} = UnknownLayout{V}() +reinterpretedmemorylayout(::DenseColumnMajor{T}, ::Type{V}) where {T,V} = DenseColumnMajor{V}() + unsafe_convert(::Type{Ptr{T}}, a::ReinterpretArray{T,N,S} where N) where {T,S} = Ptr{T}(unsafe_convert(Ptr{S},a.parent)) @inline @propagate_inbounds getindex(a::ReinterpretArray{T,0}) where {T} = reinterpret(T, a.parent[]) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index e7749b9a97960..bb559ad022d7a 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -239,4 +239,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{T}) where T = UnknownLayout{T}() +reshapedmemorylayout(::DenseColumnMajor{T}) where T = DenseColumnMajor{T}() + unsafe_convert(::Type{Ptr{T}}, a::ReshapedArray{T}) where {T} = unsafe_convert(Ptr{T}, parent(a)) diff --git a/base/subarray.jl b/base/subarray.jl index e9e184648028b..6c89076e86f8b 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -324,6 +324,33 @@ 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) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) +submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() +submemorylayout(::DenseColumns{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor{T}() +submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = + StridedLayout{T}() +submemorylayout(::DenseColumns{T}, ::Tuple{I,Int}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor{T}() +submemorylayout(::DenseColumns{T}, ::Tuple{I,Int}) where {T,I<:Slice} = + DenseColumnMajor{T}() +submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor{T}() +submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Slice} = + DenseColumnMajor{T}() +submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:AbstractUnitRange{Int}} = + DenseColumnMajor{T}() +submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + DenseColumnsStridedRows{T}() +submemorylayout(::DenseColumns{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + DenseColumnsStridedRows{T}() +submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:Slice} = + DenseRowMajor{T}() +submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + DenseRowsStridedColumns{T}() +submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = + StridedLayout{T}() + 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) diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 35629da10697a..44b744922ac13 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -408,7 +408,7 @@ perhaps range-types `Ind` of your own design. For more information, see [Arrays |:----------------------------------------------- |:-------------------------------------- |:------------------------------------------------------------------------------------- | | `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 `LinearAlgebra.AbstractStridedLayout`, such as `LinearAlgebra.DenseColumnMajor{T}()`,`LinearAlgebra.DenseRowMajor{T}()`, or `LinearAlgebra.StridedLayout{T}()`. +| `Base.MemoryLayout(A)` | | Return a subtype of `Base.AbstractStridedLayout`, such as `Base.DenseColumnMajor{T}()`,`Base.DenseRowMajor{T}()`, or `Base.StridedLayout{T}()`. | **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. | diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 1c21de4bed1de..ed1e98991909b 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -17,7 +17,8 @@ import Base: USE_BLAS64, abs, acos, acosh, acot, acoth, acsc, acsch, adjoint, as 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, ReshapedArray, ReinterpretArray, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec, - MemoryLayout, UnknownLayout + MemoryLayout, UnknownLayout, AbstractStridedLayout, DenseRows, DenseColumns, DenseRowMajor, DenseColumnMajor, + DenseColumnsStridedRows, DenseRowsStridedColumns, StridedLayout using Base: hvcat_fill, iszero, IndexLinear, _length, promote_op, promote_typeof, @propagate_inbounds, @pure, reduce, typed_vcat, AbstractCartesianIndex, RangeIndex, Slice # We use `_length` because of non-1 indices; releases after julia 0.5 @@ -171,114 +172,6 @@ else const BlasInt = Int32 end -## Traits for memory layouts ## -abstract type AbstractStridedLayout{T} <: MemoryLayout{T} end -abstract type DenseColumns{T} <: AbstractStridedLayout{T} end -struct DenseColumnMajor{T} <: DenseColumns{T} end -struct DenseColumnsStridedRows{T} <: DenseColumns{T} end -abstract type DenseRows{T} <: AbstractStridedLayout{T} end -struct DenseRowMajor{T} <: DenseRows{T} end -struct DenseRowsStridedColumns{T} <: DenseRows{T} end -struct StridedLayout{T} <: AbstractStridedLayout{T} end - -""" - AbstractStridedLayout{T} - -is an abstract type whose subtypes are returned by `MemoryLayout(A)` -if a matrix or vector `A` have storage laid out at regular offsets in memory, -and which can therefore be passed to external C and Fortran functions expecting -this memory layout. -""" -AbstractStridedLayout - -""" - DenseColumnMajor{T}() - -is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory -equivalent to an `Array`, so that `stride(A,1) == 1` and `stride(A,2) == size(A,1)`. -Arrays with `DenseColumnMajor` must conform to the `DenseArray` interface. -""" -DenseColumnMajor - -""" - DenseColumnsStridedRows{T}() - -is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory -as a column major matrix. In other words, the columns are stored in memory with -offsets of one, while the rows are stored with offsets given by `stride(A,2)`. -Arrays with `DenseColumnsStridedRows` must conform to the `DenseArray` interface. -""" -DenseColumnsStridedRows - -""" - DenseRowMajor{T}() - -is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory -equivalent to the transpose of an `Array`, so that `stride(A,1) == size(A,1)` and -`stride(A,2) == 1`. Arrays with `DenseRowMajor` must conform to the -`DenseArray` interface. -""" -DenseRowMajor - -""" - DenseRowsStridedColumns{T}() - -is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory -as a row major matrix. In other words, the rows are stored in memory with -offsets of one, while the columns are stored with offsets given by `stride(A,1)`. -`Array`s with `DenseRowsStridedColumns` must conform to the `DenseArray` interface, -and `transpose(A)` should return a matrix whose layout is `DenseColumnsStridedRows{T}()`. -""" -DenseRowsStridedColumns - -""" - StridedLayout{T}() - -is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage laid out at regular -offsets in memory. In other words, the columns are stored with offsets given -by `stride(A,1)` and for matrices the rows are stored in memory with offsets -of `stride(A,2)`. `Array`s with `StridedLayout` must conform to the `DenseArray` interface. -""" -StridedLayout - -MemoryLayout(A::Vector{T}) where T = DenseColumnMajor{T}() -MemoryLayout(A::Matrix{T}) where T = DenseColumnMajor{T}() - -MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) -submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() -submemorylayout(::DenseColumns{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseColumnMajor{T}() -submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = - StridedLayout{T}() -submemorylayout(::DenseColumns{T}, ::Tuple{I,Int}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseColumnMajor{T}() -submemorylayout(::DenseColumns{T}, ::Tuple{I,Int}) where {T,I<:Slice} = - DenseColumnMajor{T}() -submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseColumnMajor{T}() -submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Slice} = - DenseColumnMajor{T}() -submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:AbstractUnitRange{Int}} = - DenseColumnMajor{T}() -submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - DenseColumnsStridedRows{T}() -submemorylayout(::DenseColumns{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - DenseColumnsStridedRows{T}() -submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:Slice} = - DenseRowMajor{T}() -submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - DenseRowsStridedColumns{T}() -submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = - StridedLayout{T}() - -MemoryLayout(A::ReshapedArray) = reshapedmemorylayout(MemoryLayout(parent(A))) -reshapedmemorylayout(::MemoryLayout{T}) where T = UnknownLayout{T}() -reshapedmemorylayout(::DenseColumnMajor{T}) where T = DenseColumnMajor{T}() - -MemoryLayout(A::ReinterpretArray{V}) where V = reinterpretedmemorylayout(MemoryLayout(parent(A)), V) -reinterpretedmemorylayout(::MemoryLayout{T}, ::Type{V}) where {T,V} = UnknownLayout{V}() -reinterpretedmemorylayout(::DenseColumnMajor{T}, ::Type{V}) where {T,V} = DenseColumnMajor{V}() - # Check that stride of matrix/vector is 1 # Writing like this to avoid splatting penalty when called with multiple arguments, # see PR 16416 diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index e539f8688bf60..c90aed07aeec4 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -149,7 +149,7 @@ adjoint(::MemoryLayout{T}) where T = UnknownLayout{T}() adjoint(M::MemoryLayout{T}) where T<:Real = transpose(M) adjoint(M::ConjLayout{T}) where T<:Complex = transpose(conj(M)) adjoint(M::MemoryLayout{T}) where T<:Complex = conj(transpose(M)) -submemorylayout(M::ConjLayout{T}, t::Tuple) where T<:Complex = conj(submemorylayout(conj(M), t)) +Base.submemorylayout(M::ConjLayout{T}, t::Tuple) where T<:Complex = conj(Base.submemorylayout(conj(M), t)) # Adjoints and transposes conform to the strided array interface if their parent does Base.unsafe_convert(::Type{Ptr{T}}, A::AdjOrTrans{T,S}) where {T,S} = Base.unsafe_convert(Ptr{T}, parent(A)) diff --git a/stdlib/LinearAlgebra/test/adjtrans.jl b/stdlib/LinearAlgebra/test/adjtrans.jl index 7ef5025647097..cd80f4711ae5e 100644 --- a/stdlib/LinearAlgebra/test/adjtrans.jl +++ b/stdlib/LinearAlgebra/test/adjtrans.jl @@ -449,37 +449,37 @@ end @testset "adjoint and transpose MemoryLayout" begin A = [1.0 2; 3 4] - @test Base.MemoryLayout(A') == LinearAlgebra.DenseRowMajor{Float64}() - @test Base.MemoryLayout(transpose(A)) == LinearAlgebra.DenseRowMajor{Float64}() + @test Base.MemoryLayout(A') == Base.DenseRowMajor{Float64}() + @test Base.MemoryLayout(transpose(A)) == Base.DenseRowMajor{Float64}() B = [1.0+im 2; 3 4] - @test Base.MemoryLayout(B') == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowMajor{ComplexF64}()) - @test Base.MemoryLayout(transpose(B)) == LinearAlgebra.DenseRowMajor{ComplexF64}() + @test Base.MemoryLayout(B') == LinearAlgebra.ConjLayout(Base.DenseRowMajor{ComplexF64}()) + @test Base.MemoryLayout(transpose(B)) == Base.DenseRowMajor{ComplexF64}() VA = view(A, 1:1, 1:1) - @test Base.MemoryLayout(VA') == LinearAlgebra.DenseRowsStridedColumns{Float64}() - @test Base.MemoryLayout(transpose(VA)) == LinearAlgebra.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(VA') == Base.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(transpose(VA)) == Base.DenseRowsStridedColumns{Float64}() VB = view(B, 1:1, 1:1) - @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowsStridedColumns{ComplexF64}()) - @test Base.MemoryLayout(transpose(VB)) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() + @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(Base.DenseRowsStridedColumns{ComplexF64}()) + @test Base.MemoryLayout(transpose(VB)) == Base.DenseRowsStridedColumns{ComplexF64}() VA = view(A, 1:2:2, 1:2:2) - @test Base.MemoryLayout(VA') == LinearAlgebra.StridedLayout{Float64}() - @test Base.MemoryLayout(transpose(VA)) == LinearAlgebra.StridedLayout{Float64}() + @test Base.MemoryLayout(VA') == Base.StridedLayout{Float64}() + @test Base.MemoryLayout(transpose(VA)) == Base.StridedLayout{Float64}() VB = view(B, 1:2:2, 1:2:2) - @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(LinearAlgebra.StridedLayout{ComplexF64}()) - @test Base.MemoryLayout(transpose(VB)) == LinearAlgebra.StridedLayout{ComplexF64}() + @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(Base.StridedLayout{ComplexF64}()) + @test Base.MemoryLayout(transpose(VB)) == Base.StridedLayout{ComplexF64}() VA2 = view(A, [1,2], :) - @test Base.MemoryLayout(VA2') == LinearAlgebra.UnknownLayout{Float64}() - @test Base.MemoryLayout(transpose(VA2)) == LinearAlgebra.UnknownLayout{Float64}() + @test Base.MemoryLayout(VA2') == Base.UnknownLayout{Float64}() + @test Base.MemoryLayout(transpose(VA2)) == Base.UnknownLayout{Float64}() VB2 = view(B, [1,2], :) - @test Base.MemoryLayout(VB2') == LinearAlgebra.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(transpose(VB2)) == LinearAlgebra.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(VB2') == Base.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(transpose(VB2)) == Base.UnknownLayout{ComplexF64}() VAc = view(A', 1:1, 1:1) - @test Base.MemoryLayout(VAc) == LinearAlgebra.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(VAc) == Base.DenseRowsStridedColumns{Float64}() VAt = view(transpose(A), 1:1, 1:1) - @test Base.MemoryLayout(VAt) == LinearAlgebra.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(VAt) == Base.DenseRowsStridedColumns{Float64}() VBc = view(B', 1:1, 1:1) - @test Base.MemoryLayout(VBc) == LinearAlgebra.ConjLayout(LinearAlgebra.DenseRowsStridedColumns{ComplexF64}()) + @test Base.MemoryLayout(VBc) == LinearAlgebra.ConjLayout(Base.DenseRowsStridedColumns{ComplexF64}()) VBt = view(transpose(B), 1:1, 1:1) - @test Base.MemoryLayout(VBt) == LinearAlgebra.DenseRowsStridedColumns{ComplexF64}() + @test Base.MemoryLayout(VBt) == Base.DenseRowsStridedColumns{ComplexF64}() end end # module TestAdjointTranspose diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index 7dd2d30bc3e8b..2e4a3f45b040d 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -845,31 +845,7 @@ end end end -@testset "MemoryLayout for Array, SubArray, and ReinterpretArray" begin - A = [1.0 2; 3 4] - - @test Base.MemoryLayout(A) == LinearAlgebra.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,:,:)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,:)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,:,1)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,:,1:1)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,1:1,1)) == LinearAlgebra.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,1,1:1)) == LinearAlgebra.StridedLayout{Float64}() - @test Base.MemoryLayout(view(A,1,:)) == LinearAlgebra.StridedLayout{Float64}() - @test Base.MemoryLayout(view(A,1:1,1:2)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() - @test Base.MemoryLayout(view(A,1:1,:)) == LinearAlgebra.DenseColumnsStridedRows{Float64}() - @test Base.MemoryLayout(view(A,1:2:1,1:2:1)) == LinearAlgebra.StridedLayout{Float64}() - @test Base.MemoryLayout(view(A,1:2:1,:)) == LinearAlgebra.StridedLayout{Float64}() - @test Base.MemoryLayout(view(A,[1,2],:)) == LinearAlgebra.UnknownLayout{Float64}() - - @test Base.MemoryLayout(Base.ReshapedArray(A,(4,),())) == LinearAlgebra.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == LinearAlgebra.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == LinearAlgebra.DenseColumnMajor{Float64}() - - @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == LinearAlgebra.DenseColumnMajor{ComplexF64}() - - Base.MemoryLayout(BitArray([true,true,false])) == LinearAlgebra.UnknownLayout{Bool}() - +@testset "Dispatch to BLAS routines" begin A = rand(100,100) x = rand(100) @test all(A*x .=== view(A,:,:)*x .=== view(A',:,:)'*x .=== diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index e296f40b4925e..4fd1f662d4980 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -489,27 +489,27 @@ end @testset "Symmetric/Hermitian MemoryLayout" begin A = [1.0 2; 3 4] - @test Base.MemoryLayout(Symmetric(A)) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Hermitian(A)) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Transpose(Symmetric(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{Float64}(),'U') - @test Base.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{Float64}(),'U') - @test Base.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{Float64}(),'U') - @test Base.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{Float64}(),'U') + @test Base.MemoryLayout(Symmetric(A)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Hermitian(A)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Transpose(Symmetric(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') + @test Base.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{Float64}(),'U') + @test Base.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{Float64}(),'U') + @test Base.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{Float64}(),'U') + @test Base.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{Float64}(),'U') B = [1.0+im 2; 3 4] - @test Base.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Transpose(Hermitian(B))) == LinearAlgebra.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.ConjLayout(LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U')) - @test Base.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Symmetric(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(Hermitian(B')) == LinearAlgebra.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.DenseRowMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout(LinearAlgebra.DenseRowMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Transpose(Hermitian(B))) == Base.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.ConjLayout(LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{ComplexF64}(),'U')) + @test Base.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Symmetric(B')) == Base.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(Hermitian(B')) == Base.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout(Base.DenseRowMajor{ComplexF64}(),'U') A = randn(100,100) x = randn(100) diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index 2f6501305bd0a..574b020490297 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -556,17 +556,17 @@ end (UnitUpperTriangular, LinearAlgebra.UnitUpperTriangularLayout, LinearAlgebra.UnitLowerTriangularLayout), (LowerTriangular, LinearAlgebra.LowerTriangularLayout, LinearAlgebra.UpperTriangularLayout), (UnitLowerTriangular, LinearAlgebra.UnitLowerTriangularLayout, LinearAlgebra.UnitUpperTriangularLayout)) - @test Base.MemoryLayout(TriType(A)) == TriLayout(LinearAlgebra.DenseColumnMajor{Float64}()) + @test Base.MemoryLayout(TriType(A)) == TriLayout(Base.DenseColumnMajor{Float64}()) @test Base.MemoryLayout(TriType(transpose(A))) == Base.UnknownLayout{Float64}() @test Base.MemoryLayout(TriType(A')) == Base.UnknownLayout{Float64}() - @test Base.MemoryLayout(transpose(TriType(A))) == TriLayoutTrans(LinearAlgebra.DenseRowMajor{Float64}()) - @test Base.MemoryLayout(TriType(A)') == TriLayoutTrans(LinearAlgebra.DenseRowMajor{Float64}()) + @test Base.MemoryLayout(transpose(TriType(A))) == TriLayoutTrans(Base.DenseRowMajor{Float64}()) + @test Base.MemoryLayout(TriType(A)') == TriLayoutTrans(Base.DenseRowMajor{Float64}()) - @test Base.MemoryLayout(TriType(B)) == TriLayout(LinearAlgebra.DenseColumnMajor{ComplexF64}()) + @test Base.MemoryLayout(TriType(B)) == TriLayout(Base.DenseColumnMajor{ComplexF64}()) @test Base.MemoryLayout(TriType(transpose(B))) == Base.UnknownLayout{ComplexF64}() @test Base.MemoryLayout(TriType(B')) == Base.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(transpose(TriType(B))) == TriLayoutTrans(LinearAlgebra.DenseRowMajor{ComplexF64}()) - @test Base.MemoryLayout(TriType(B)') == TriLayoutTrans(conj(LinearAlgebra.DenseRowMajor{ComplexF64}())) + @test Base.MemoryLayout(transpose(TriType(B))) == TriLayoutTrans(Base.DenseRowMajor{ComplexF64}()) + @test Base.MemoryLayout(TriType(B)') == TriLayoutTrans(conj(Base.DenseRowMajor{ComplexF64}())) end A = randn(Float64, 100, 100) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index b52fe31768d0d..802783e49a679 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -882,3 +882,29 @@ end @test hcat(1:2, fill(1, (2,1))) == hcat([1:2;], fill(1, (2,1))) == reshape([1,2,1,1],2,2) @test [(1:3) (4:6); fill(1, (3,2))] == reshape([1,2,3,1,1,1,4,5,6,1,1,1], 6,2) end + +@testset "MemoryLayout for Array, SubArray, and ReinterpretArray" begin + let A = [1.0 2; 3 4] + @test Base.MemoryLayout(A) == Base.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,:,:)) == Base.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,:)) == Base.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,:,1)) == Base.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,:,1:1)) == Base.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,1:1,1)) == Base.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,1,1:1)) == Base.StridedLayout{Float64}() + @test Base.MemoryLayout(view(A,1,:)) == Base.StridedLayout{Float64}() + @test Base.MemoryLayout(view(A,1:1,1:2)) == Base.DenseColumnsStridedRows{Float64}() + @test Base.MemoryLayout(view(A,1:1,:)) == Base.DenseColumnsStridedRows{Float64}() + @test Base.MemoryLayout(view(A,1:2:1,1:2:1)) == Base.StridedLayout{Float64}() + @test Base.MemoryLayout(view(A,1:2:1,:)) == Base.StridedLayout{Float64}() + @test Base.MemoryLayout(view(A,[1,2],:)) == Base.UnknownLayout{Float64}() + + @test Base.MemoryLayout(Base.ReshapedArray(A,(4,),())) == Base.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == Base.DenseColumnMajor{Float64}() + @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == Base.DenseColumnMajor{Float64}() + + @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == Base.DenseColumnMajor{ComplexF64}() + + Base.MemoryLayout(BitArray([true,true,false])) == Base.UnknownLayout{Bool}() + end +end From 482939aa033891cfe313bd3bac1a51293e5b3816 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Mon, 19 Feb 2018 08:00:47 +0000 Subject: [PATCH 23/39] merge dense --- stdlib/LinearAlgebra/src/dense.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index 3b96cfa3a7bb8..fc992e635d4a5 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -1351,11 +1351,7 @@ julia> nullspace(M, 2) 0.0 0.0 1.0 ``` """ -<<<<<<< HEAD -function nullspace(A::AbstractMatrix{T}) where T -======= function nullspace(A::StridedMatrix, tol::Real = min(size(A)...)*eps(real(float(one(eltype(A)))))) ->>>>>>> 15a345bf74a27429bc4bb0c33b99a9151d65a735 m, n = size(A) (m == 0 || n == 0) && return Matrix{T}(I, n, n) SVD = svdfact(A, full=true) From 3618a39f1158accac5eaf53169cb3a327ca8f16a Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Mon, 19 Feb 2018 10:10:32 +0000 Subject: [PATCH 24/39] DenseColumns -> AbstractColumnMajor DenseColumnsStridedRows -> ColumnMajor DenseRows -> AbstractRowMajor DenseRowsStridedColumns -> RowMajor --- base/abstractarray.jl | 26 +++++----- base/subarray.jl | 22 ++++----- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 6 +-- stdlib/LinearAlgebra/src/adjtrans.jl | 4 +- stdlib/LinearAlgebra/src/dense.jl | 2 +- stdlib/LinearAlgebra/src/matmul.jl | 42 ++++++++-------- stdlib/LinearAlgebra/src/symmetric.jl | 28 +++++------ stdlib/LinearAlgebra/src/triangular.jl | 60 +++++++++++------------ stdlib/LinearAlgebra/test/adjtrans.jl | 16 +++--- test/abstractarray.jl | 4 +- 10 files changed, 105 insertions(+), 105 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index bc320c6e1adb6..bbdcdb3f4185e 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -274,12 +274,12 @@ size_to_strides(s) = () abstract type MemoryLayout{T} end struct UnknownLayout{T} <: MemoryLayout{T} end abstract type AbstractStridedLayout{T} <: MemoryLayout{T} end -abstract type DenseColumns{T} <: AbstractStridedLayout{T} end -struct DenseColumnMajor{T} <: DenseColumns{T} end -struct DenseColumnsStridedRows{T} <: DenseColumns{T} end -abstract type DenseRows{T} <: AbstractStridedLayout{T} end -struct DenseRowMajor{T} <: DenseRows{T} end -struct DenseRowsStridedColumns{T} <: DenseRows{T} end +abstract type AbstractColumnMajor{T} <: AbstractStridedLayout{T} end +struct DenseColumnMajor{T} <: AbstractColumnMajor{T} end +struct ColumnMajor{T} <: AbstractColumnMajor{T} end +abstract type AbstractRowMajor{T} <: AbstractStridedLayout{T} end +struct DenseRowMajor{T} <: AbstractRowMajor{T} end +struct RowMajor{T} <: AbstractRowMajor{T} end struct StridedLayout{T} <: AbstractStridedLayout{T} end """ @@ -310,14 +310,14 @@ Arrays with `DenseColumnMajor` must conform to the `DenseArray` interface. DenseColumnMajor """ - DenseColumnsStridedRows{T}() + ColumnMajor{T}() is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory as a column major matrix. In other words, the columns are stored in memory with offsets of one, while the rows are stored with offsets given by `stride(A,2)`. -Arrays with `DenseColumnsStridedRows` must conform to the `DenseArray` interface. +Arrays with `ColumnMajor` must conform to the `DenseArray` interface. """ -DenseColumnsStridedRows +ColumnMajor """ DenseRowMajor{T}() @@ -330,15 +330,15 @@ equivalent to the transpose of an `Array`, so that `stride(A,1) == size(A,1)` an DenseRowMajor """ - DenseRowsStridedColumns{T}() + RowMajor{T}() is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory as a row major matrix. In other words, the rows are stored in memory with offsets of one, while the columns are stored with offsets given by `stride(A,1)`. -Arrays with `DenseRowsStridedColumns` must conform to the `DenseArray` interface, -and `transpose(A)` should return a matrix whose layout is `DenseColumnsStridedRows{T}()`. +Arrays with `RowMajor` must conform to the `DenseArray` interface, +and `transpose(A)` should return a matrix whose layout is `ColumnMajor{T}()`. """ -DenseRowsStridedColumns +RowMajor """ StridedLayout{T}() diff --git a/base/subarray.jl b/base/subarray.jl index ec1e70503d9a6..cd3e0bb143a71 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -326,28 +326,28 @@ find_extended_inds() = () MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() -submemorylayout(::DenseColumns{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = +submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = DenseColumnMajor{T}() submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = StridedLayout{T}() -submemorylayout(::DenseColumns{T}, ::Tuple{I,Int}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = +submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I,Int}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = DenseColumnMajor{T}() -submemorylayout(::DenseColumns{T}, ::Tuple{I,Int}) where {T,I<:Slice} = +submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I,Int}) where {T,I<:Slice} = DenseColumnMajor{T}() -submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = +submemorylayout(::AbstractRowMajor{T}, ::Tuple{Int,I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = DenseColumnMajor{T}() -submemorylayout(::DenseRows{T}, ::Tuple{Int,I}) where {T,I<:Slice} = +submemorylayout(::AbstractRowMajor{T}, ::Tuple{Int,I}) where {T,I<:Slice} = DenseColumnMajor{T}() submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:AbstractUnitRange{Int}} = DenseColumnMajor{T}() submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - DenseColumnsStridedRows{T}() -submemorylayout(::DenseColumns{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - DenseColumnsStridedRows{T}() -submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:Slice} = + ColumnMajor{T}() +submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + ColumnMajor{T}() +submemorylayout(::AbstractRowMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:Slice} = DenseRowMajor{T}() -submemorylayout(::DenseRows{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - DenseRowsStridedColumns{T}() +submemorylayout(::AbstractRowMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + RowMajor{T}() submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = StridedLayout{T}() diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 0d8229c7a237c..b12f688a3ea45 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -17,8 +17,8 @@ import Base: USE_BLAS64, abs, acos, acosh, acot, acoth, acsc, acsch, adjoint, as 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, ReshapedArray, ReinterpretArray, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec, - MemoryLayout, UnknownLayout, AbstractStridedLayout, DenseRows, DenseColumns, DenseRowMajor, DenseColumnMajor, - DenseColumnsStridedRows, DenseRowsStridedColumns, StridedLayout + 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, AbstractCartesianIndex, RangeIndex, Slice # We use `_length` because of non-1 indices; releases after julia 0.5 @@ -204,7 +204,7 @@ julia> LinearAlgebra.stride1(B) stride1(x) = stride(x,1) stride1(x::AbstractArray) = _stride1(x, MemoryLayout(x)) _stride1(x, _) = stride(x, 1)::Int -_stride1(x, ::DenseColumns) = 1 +_stride1(x, ::AbstractColumnMajor) = 1 @inline chkstride1(A...) = _chkstride1(true, A...) @noinline _chkstride1(ok::Bool) = ok || error("matrix does not have contiguous columns") diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index c90aed07aeec4..ba0f4b54238f3 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -141,8 +141,8 @@ MemoryLayout(A::Adjoint) = adjoint(MemoryLayout(parent(A))) MemoryLayout(A::Transpose) = transpose(MemoryLayout(parent(A))) transpose(::MemoryLayout{T}) where T = UnknownLayout{T}() transpose(::StridedLayout{T}) where T = StridedLayout{T}() -transpose(::DenseColumnsStridedRows{T}) where T = DenseRowsStridedColumns{T}() -transpose(::DenseRowsStridedColumns{T}) where T = DenseColumnsStridedRows{T}() +transpose(::ColumnMajor{T}) where T = RowMajor{T}() +transpose(::RowMajor{T}) where T = ColumnMajor{T}() transpose(::DenseColumnMajor{T}) where T = DenseRowMajor{T}() transpose(::DenseRowMajor{T}) where T = DenseColumnMajor{T}() adjoint(::MemoryLayout{T}) where T = UnknownLayout{T}() diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index fc992e635d4a5..340d278affe38 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -513,7 +513,7 @@ function exp!(A::AbstractMatrix{T}, _) where T<:BlasFloat A .= exp!(Matrix{T}(A)) A end -function _exp!(A::AbstractMatrix{T}, ::DenseColumns{T}) where T<:BlasFloat +function _exp!(A::AbstractMatrix{T}, ::AbstractColumnMajor{T}) where T<:BlasFloat n = checksquare(A) if ishermitian(A) return copytri!(parent(exp(Hermitian(A))), 'U', true) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 7f11a71aac4f7..72f18ef84b74c 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -75,12 +75,12 @@ julia> Y mul!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul!(C, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) _mul!(y::AbstractVector, A::AbstractMatrix, x::AbstractVector, _1, _2, _3) = generic_matvecmul!(y, 'N', A, x) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::DenseColumns, _) where {T<:BlasFloat} = +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector, ::AbstractStridedLayout, ::AbstractColumnMajor, _) where {T<:BlasFloat} = mul!(y, A, convert(Vector{T}, x)) -_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseColumns, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) +_mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractColumnMajor, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin - function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::AbstractStridedLayout, ::DenseColumns, ::AbstractStridedLayout) + function _mul!(y::AbstractVector{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, x::AbstractVector{$elty}, ::AbstractStridedLayout, ::AbstractColumnMajor, ::AbstractStridedLayout) Afl = reinterpret($elty,A) yfl = reinterpret($elty,y) gemv!(yfl,'N',Afl,x) @@ -89,13 +89,13 @@ for elty in (Float32,Float64) end end -_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::DenseRows, ::AbstractStridedLayout) = +_mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::AbstractRowMajor, ::AbstractStridedLayout) = (A = transpose(transA); generic_matvecmul!(y, 'T', A, x)) -_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::AbstractStridedLayout) = +_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matvecmul!(y, 'C', A, x)) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::DenseRows, ::AbstractStridedLayout) where {T<:BlasFloat} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractRowMajor, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'T', transpose(adjA), x) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::AbstractStridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = gemv!(y, 'C', adjoint(adjA), x) # Vector-matrix multiplication @@ -151,7 +151,7 @@ _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::Abstra gemm_wrapper!(C, 'N', 'N', A, B) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::DenseColumns, ::DenseColumns, ::DenseColumns) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, B::AbstractMatrix{$elty}, ::AbstractColumnMajor, ::AbstractColumnMajor, ::AbstractColumnMajor) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) gemm_wrapper!(Cfl, 'N', 'N', Afl, B) @@ -160,16 +160,16 @@ for elty in (Float32,Float64) end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::DenseRows, ::DenseColumns) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractColumnMajor, ::AbstractRowMajor, ::AbstractColumnMajor) where {T<:BlasFloat} = (A = transpose(transA); A === B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::DenseRows, ::AbstractStridedLayout) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::AbstractRowMajor, ::AbstractStridedLayout) = (A = transpose(transA); generic_matmatmul!(C, 'T', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::DenseColumns, ::DenseRows) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractColumnMajor, ::AbstractColumnMajor, ::AbstractRowMajor) where {T<:BlasFloat} = (B = transpose(transB); A === B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)) for elty in (Float32,Float64) @eval begin - function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::DenseColumns, ::DenseColumns, ::DenseRows) + function _mul!(C::AbstractMatrix{Complex{$elty}}, A::AbstractMatrix{Complex{$elty}}, transB::AbstractMatrix{$elty}, ::AbstractColumnMajor, ::AbstractColumnMajor, ::AbstractRowMajor) B = transpose(transB) Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) @@ -179,26 +179,26 @@ for elty in (Float32,Float64) end end -_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::DenseRows, ::DenseRows) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractColumnMajor, ::AbstractRowMajor, ::AbstractRowMajor) where {T<:BlasFloat} = (A = transpose(transA); B = transpose(transB); gemm_wrapper!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::DenseRows, ::DenseRows) = +_mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractRowMajor, ::AbstractRowMajor) = (A = transpose(transA); B = transpose(transB); generic_matmatmul!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::ConjLayout{<:Complex,<:DenseRows}, ::DenseColumns) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractColumnMajor, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractColumnMajor) where {T<:BlasComplex} = (A = adjoint(adjA); A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::AbstractStridedLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matmatmul!(C, 'C', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::DenseColumns, ::ConjLayout{<:Complex,<:DenseRows}) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractColumnMajor, ::AbstractColumnMajor, ::ConjLayout{<:Complex,<:AbstractRowMajor}) where {T<:BlasComplex} = (B = adjoint(adjB); A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}) = +_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}) = (B = adjoint(adjB); generic_matmatmul!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::ConjLayout{<:Complex,<:DenseRows}, ::ConjLayout{<:Complex,<:DenseRows}) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractColumnMajor, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::ConjLayout{<:Complex,<:AbstractRowMajor}) where {T<:BlasFloat} = (A = adjoint(adjA); B = adjoint(adjB); gemm_wrapper!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::ConjLayout{<:Complex,<:DenseRows}) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::ConjLayout{<:Complex,<:AbstractRowMajor}) = (A = adjoint(adjA); B = adjoint(adjB); generic_matmatmul!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:DenseRows}, ::DenseRows) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractRowMajor) = (A = adjoint(adjA); B = transpose(transB); generic_matmatmul!(C, 'C', 'T', A, B)) # Supporting functions for matrix multiplication diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index a2d86e0212940..b5fe450bae04a 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -259,13 +259,13 @@ HermitianLayout(layout::ML, uplo) where ML<:MemoryLayout{T} where T = HermitianL MemoryLayout(A::Hermitian) = hermitianmemorylayout(MemoryLayout(parent(A)), A.uplo) MemoryLayout(A::Symmetric) = symmetricmemorylayout(MemoryLayout(parent(A)), A.uplo) hermitianmemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() -hermitianmemorylayout(layout::DenseColumns{<:Complex}, uplo) = HermitianLayout(layout,uplo) -hermitianmemorylayout(layout::DenseColumns{<:Real}, uplo) = SymmetricLayout(layout,uplo) -hermitianmemorylayout(layout::DenseRows{<:Complex}, uplo) = HermitianLayout(layout,uplo) -hermitianmemorylayout(layout::DenseRows{<:Real}, uplo) = SymmetricLayout(layout,uplo) +hermitianmemorylayout(layout::AbstractColumnMajor{<:Complex}, uplo) = HermitianLayout(layout,uplo) +hermitianmemorylayout(layout::AbstractColumnMajor{<:Real}, uplo) = SymmetricLayout(layout,uplo) +hermitianmemorylayout(layout::AbstractRowMajor{<:Complex}, uplo) = HermitianLayout(layout,uplo) +hermitianmemorylayout(layout::AbstractRowMajor{<:Real}, uplo) = SymmetricLayout(layout,uplo) symmetricmemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() -symmetricmemorylayout(layout::DenseColumns, uplo) = SymmetricLayout(layout,uplo) -symmetricmemorylayout(layout::DenseRows, uplo) = SymmetricLayout(layout,uplo) +symmetricmemorylayout(layout::AbstractColumnMajor, uplo) = SymmetricLayout(layout,uplo) +symmetricmemorylayout(layout::AbstractRowMajor, uplo) = SymmetricLayout(layout,uplo) adjoint(H::HermitianLayout) = H adjoint(H::SymmetricLayout{<:Real}) = H @@ -411,30 +411,30 @@ end ## Matrix-vector product _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::SymmetricLayout{T,<:DenseColumns}, ::AbstractStridedLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, AL::SymmetricLayout{T,<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symv!(AL.uplo, one(T), parent(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::SymmetricLayout{T,<:DenseRows}, ::AbstractStridedLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, AL::SymmetricLayout{T,<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(parent(A)), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::HermitianLayout{T,<:DenseColumns}, ::AbstractStridedLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, AL::HermitianLayout{T,<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemv!(AL.uplo, one(T), parent(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::HermitianLayout{T,<:DenseRows}, ::AbstractStridedLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, AL::HermitianLayout{T,<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(parent(A)), x, zero(T), y) ## Matrix-matrix product _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, AL::SymmetricLayout{T,<:DenseColumns}, ::AbstractStridedLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, AL::SymmetricLayout{T,<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout{T,<:DenseColumns}) where {T<:BlasFloat} = + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout{T,<:AbstractColumnMajor}) where {T<:BlasFloat} = BLAS.symm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, AL::HermitianLayout{T,<:DenseColumns}, ::AbstractStridedLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, AL::HermitianLayout{T,<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout{T,<:DenseColumns}) where {T<:BlasComplex} = + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout{T,<:AbstractColumnMajor}) where {T<:BlasComplex} = BLAS.hemm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 9a4ec616e08bb..1be6eb0293437 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -432,7 +432,7 @@ MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, Memo MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, MemoryLayout(parent(A))) MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, MemoryLayout(parent(A))) trilayout(_, ::MemoryLayout{T}) where T = UnknownLayout{T}() -trilayout(::Type{Tri}, ML::DenseColumns{T}) where {Tri,T} = Tri(ML) +trilayout(::Type{Tri}, ML::AbstractColumnMajor{T}) where {Tri,T} = Tri(ML) for (TriLayout, TriLayoutTrans) in ((UpperTriangularLayout, LowerTriangularLayout), (UnitUpperTriangularLayout, UnitLowerTriangularLayout), @@ -607,11 +607,11 @@ for (t, memlay, memlaytrans, uploc, isunitc) in ((:LowerTriangular, :LowerTriang _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::AbstractStridedLayout, ::$memlay, ::AbstractStridedLayout) where {T<:BlasFloat} = lmul!(A, copyto!(y, b)) - _lmul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{T,DC}, ::AbstractStridedLayout) where {T<:BlasFloat,DC<:DenseColumns} = + _lmul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{T,DC}, ::AbstractStridedLayout) where {T<:BlasFloat,DC<:AbstractColumnMajor} = BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) - _lmul!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{T,DR}, ::AbstractStridedLayout) where {T<:BlasFloat,DR<:DenseRows} = + _lmul!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{T,DR}, ::AbstractStridedLayout) where {T<:BlasFloat,DR<:AbstractRowMajor} = (A = transpose(transA); BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - _lmul!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{T,ConjLayout{T,DR}}, ::AbstractStridedLayout) where {T<:BlasComplex,DR<:DenseRows} = + _lmul!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{T,ConjLayout{T,DR}}, ::AbstractStridedLayout) where {T<:BlasComplex,DR<:AbstractRowMajor} = (A = adjoint(adjA); BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) # Matrix multiplication @@ -620,19 +620,19 @@ for (t, memlay, memlaytrans, uploc, isunitc) in ((:LowerTriangular, :LowerTriang _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::$memlay) where {T<:BlasFloat} = rmul!(copyto!(C, A), B) - _lmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{T,DC}, ::DenseColumns) where {T<:BlasFloat,DC<:DenseColumns} = + _lmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{T,DC}, ::AbstractColumnMajor) where {T<:BlasFloat,DC<:AbstractColumnMajor} = BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B) - _rmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::DenseColumns, ::$memlay{T,DC}) where {T<:BlasFloat,DC<:DenseColumns} = + _rmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlay{T,DC}) where {T<:BlasFloat,DC<:AbstractColumnMajor} = BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) - _lmul!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{T,DR}, ::DenseColumns) where {T<:BlasFloat,DR<:DenseRows} = + _lmul!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{T,DR}, ::AbstractColumnMajor) where {T<:BlasFloat,DR<:AbstractRowMajor} = (A = transpose(transA); BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) - _lmul!(adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{T,ConjLayout{T,DR}}, ::DenseColumns) where {T<:BlasComplex,DR<:DenseRows} = + _lmul!(adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{T,ConjLayout{T,DR}}, ::AbstractColumnMajor) where {T<:BlasComplex,DR<:AbstractRowMajor} = (A = adjoint(adjA); BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B)) - _rmul!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::DenseColumns, ::$memlaytrans{T,DR}) where {T<:BlasFloat,DR<:DenseRows} = + _rmul!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlaytrans{T,DR}) where {T<:BlasFloat,DR<:AbstractRowMajor} = (B = transpose(transB); BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) - _rmul!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::DenseColumns, ::$memlaytrans{T,ConjLayout{T,DR}}) where {T<:BlasComplex,DR<:DenseRows} = + _rmul!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlaytrans{T,ConjLayout{T,DR}}) where {T<:BlasComplex,DR<:AbstractRowMajor} = (B = adjoint(adjB); BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), B.data, A)) # Left division @@ -768,7 +768,7 @@ for (t, unitt) in ((UpperTriangular, UnitUpperTriangular), end ## Generic triangular multiplication -function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,<:DenseColumns}, _) where T +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,<:AbstractColumnMajor}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -785,7 +785,7 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{ B end -function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,<:DenseColumns}, _) where T +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,<:AbstractColumnMajor}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -802,7 +802,7 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLay B end -function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,<:DenseColumns}, _) where T +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,<:AbstractColumnMajor}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -818,7 +818,7 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{ end B end -function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,<:DenseColumns}, _) where T +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,<:AbstractColumnMajor}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -835,7 +835,7 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLay B end -function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:DenseRows} +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:AbstractRowMajor} A = adjoint(adjA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -853,7 +853,7 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayo B end -function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:DenseRows} +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:AbstractRowMajor} A = adjA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -871,7 +871,7 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangular B end -function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:DenseRows} +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:AbstractRowMajor} A = adjA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -888,7 +888,7 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayo end B end -function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:DenseRows} +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:AbstractRowMajor} A = adjA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -906,7 +906,7 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangular B end -function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,DR}, _) where {T,DR<:DenseRows} +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,DR}, _) where {T,DR<:AbstractRowMajor} A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -923,7 +923,7 @@ function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLa end B end -function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,DR}, _) where {T,DR<:DenseRows} +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,DR}, _) where {T,DR<:AbstractRowMajor} A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -941,7 +941,7 @@ function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangul B end -function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,DR}, _) where {T,DR<:DenseRows} +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,DR}, _) where {T,DR<:AbstractRowMajor} A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -958,7 +958,7 @@ function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLa end B end -function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,DR}, _) where {T,DR<:DenseRows} +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,DR}, _) where {T,DR<:AbstractRowMajor} A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -1042,7 +1042,7 @@ function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, : A end -function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:DenseRows} +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:AbstractRowMajor} B = adjoint(adjB) m, n = size(A) if size(B, 1) != n @@ -1060,7 +1060,7 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout A end -function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:DenseRows} +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:AbstractRowMajor} B = adjoint(adjB) m, n = size(A) if size(B, 1) != n @@ -1078,7 +1078,7 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout A end -function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:DenseRows} +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:AbstractRowMajor} B = adjoint(adjB) m, n = size(A) if size(B, 1) != n @@ -1096,7 +1096,7 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout A end -function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:DenseRows} +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:AbstractRowMajor} B = adjoint(adjB) m, n = size(A) if size(B, 1) != n @@ -1114,7 +1114,7 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout A end -function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{T,DR}) where {T,DR<:DenseRows} +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{T,DR}) where {T,DR<:AbstractRowMajor} B = transpose(transB) m, n = size(A) if size(B, 1) != n @@ -1131,7 +1131,7 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo end A end -function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{T,DR}) where {T,DR<:DenseRows} +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{T,DR}) where {T,DR<:AbstractRowMajor} B = transB.parent m, n = size(A) if size(B, 1) != n @@ -1149,7 +1149,7 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo A end -function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{T,DR}) where {T,DR<:DenseRows} +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{T,DR}) where {T,DR<:AbstractRowMajor} B = transB.parent m, n = size(A) if size(B, 1) != n @@ -1167,7 +1167,7 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo A end -function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{T,DR}) where {T,DR<:DenseRows} +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{T,DR}) where {T,DR<:AbstractRowMajor} B = transB.parent m, n = size(A) if size(B, 1) != n diff --git a/stdlib/LinearAlgebra/test/adjtrans.jl b/stdlib/LinearAlgebra/test/adjtrans.jl index cd80f4711ae5e..d8316054c172f 100644 --- a/stdlib/LinearAlgebra/test/adjtrans.jl +++ b/stdlib/LinearAlgebra/test/adjtrans.jl @@ -455,11 +455,11 @@ end @test Base.MemoryLayout(B') == LinearAlgebra.ConjLayout(Base.DenseRowMajor{ComplexF64}()) @test Base.MemoryLayout(transpose(B)) == Base.DenseRowMajor{ComplexF64}() VA = view(A, 1:1, 1:1) - @test Base.MemoryLayout(VA') == Base.DenseRowsStridedColumns{Float64}() - @test Base.MemoryLayout(transpose(VA)) == Base.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(VA') == Base.RowMajor{Float64}() + @test Base.MemoryLayout(transpose(VA)) == Base.RowMajor{Float64}() VB = view(B, 1:1, 1:1) - @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(Base.DenseRowsStridedColumns{ComplexF64}()) - @test Base.MemoryLayout(transpose(VB)) == Base.DenseRowsStridedColumns{ComplexF64}() + @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(Base.RowMajor{ComplexF64}()) + @test Base.MemoryLayout(transpose(VB)) == Base.RowMajor{ComplexF64}() VA = view(A, 1:2:2, 1:2:2) @test Base.MemoryLayout(VA') == Base.StridedLayout{Float64}() @test Base.MemoryLayout(transpose(VA)) == Base.StridedLayout{Float64}() @@ -473,13 +473,13 @@ end @test Base.MemoryLayout(VB2') == Base.UnknownLayout{ComplexF64}() @test Base.MemoryLayout(transpose(VB2)) == Base.UnknownLayout{ComplexF64}() VAc = view(A', 1:1, 1:1) - @test Base.MemoryLayout(VAc) == Base.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(VAc) == Base.RowMajor{Float64}() VAt = view(transpose(A), 1:1, 1:1) - @test Base.MemoryLayout(VAt) == Base.DenseRowsStridedColumns{Float64}() + @test Base.MemoryLayout(VAt) == Base.RowMajor{Float64}() VBc = view(B', 1:1, 1:1) - @test Base.MemoryLayout(VBc) == LinearAlgebra.ConjLayout(Base.DenseRowsStridedColumns{ComplexF64}()) + @test Base.MemoryLayout(VBc) == LinearAlgebra.ConjLayout(Base.RowMajor{ComplexF64}()) VBt = view(transpose(B), 1:1, 1:1) - @test Base.MemoryLayout(VBt) == Base.DenseRowsStridedColumns{ComplexF64}() + @test Base.MemoryLayout(VBt) == Base.RowMajor{ComplexF64}() end end # module TestAdjointTranspose diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 802783e49a679..f6cee4c80975a 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -893,8 +893,8 @@ end @test Base.MemoryLayout(view(A,1:1,1)) == Base.DenseColumnMajor{Float64}() @test Base.MemoryLayout(view(A,1,1:1)) == Base.StridedLayout{Float64}() @test Base.MemoryLayout(view(A,1,:)) == Base.StridedLayout{Float64}() - @test Base.MemoryLayout(view(A,1:1,1:2)) == Base.DenseColumnsStridedRows{Float64}() - @test Base.MemoryLayout(view(A,1:1,:)) == Base.DenseColumnsStridedRows{Float64}() + @test Base.MemoryLayout(view(A,1:1,1:2)) == Base.ColumnMajor{Float64}() + @test Base.MemoryLayout(view(A,1:1,:)) == Base.ColumnMajor{Float64}() @test Base.MemoryLayout(view(A,1:2:1,1:2:1)) == Base.StridedLayout{Float64}() @test Base.MemoryLayout(view(A,1:2:1,:)) == Base.StridedLayout{Float64}() @test Base.MemoryLayout(view(A,[1,2],:)) == Base.UnknownLayout{Float64}() From bad7814afc2e28139846d15523c98afa0b93e4ae Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Wed, 28 Feb 2018 15:49:30 +0000 Subject: [PATCH 25/39] MemoryLayout{T} -> MemoryLayout, as well as subtypes --- base/abstractarray.jl | 46 ++++++------ base/reinterpretarray.jl | 6 +- base/reshapedarray.jl | 4 +- base/subarray.jl | 50 ++++++------- doc/src/manual/interfaces.md | 2 +- stdlib/LinearAlgebra/src/adjtrans.jl | 39 +++++----- stdlib/LinearAlgebra/src/dense.jl | 2 +- stdlib/LinearAlgebra/src/matmul.jl | 18 ++--- stdlib/LinearAlgebra/src/symmetric.jl | 50 +++++++------ stdlib/LinearAlgebra/src/triangular.jl | 94 +++++++++++-------------- stdlib/LinearAlgebra/test/adjtrans.jl | 40 +++++------ stdlib/LinearAlgebra/test/symmetric.jl | 40 +++++------ stdlib/LinearAlgebra/test/triangular.jl | 22 +++--- test/abstractarray.jl | 42 +++++------ 14 files changed, 221 insertions(+), 234 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index ff0cc05be1bde..1b9bb5a54176a 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -275,19 +275,19 @@ size_to_strides(s, d) = (s,) size_to_strides(s) = () -abstract type MemoryLayout{T} end -struct UnknownLayout{T} <: MemoryLayout{T} end -abstract type AbstractStridedLayout{T} <: MemoryLayout{T} end -abstract type AbstractColumnMajor{T} <: AbstractStridedLayout{T} end -struct DenseColumnMajor{T} <: AbstractColumnMajor{T} end -struct ColumnMajor{T} <: AbstractColumnMajor{T} end -abstract type AbstractRowMajor{T} <: AbstractStridedLayout{T} end -struct DenseRowMajor{T} <: AbstractRowMajor{T} end -struct RowMajor{T} <: AbstractRowMajor{T} end -struct StridedLayout{T} <: AbstractStridedLayout{T} end +abstract type MemoryLayout end +struct UnknownLayout <: MemoryLayout end +abstract type AbstractStridedLayout <: MemoryLayout end +abstract type AbstractColumnMajor <: AbstractStridedLayout end +struct DenseColumnMajor <: AbstractColumnMajor end +struct ColumnMajor <: AbstractColumnMajor end +abstract type AbstractRowMajor <: AbstractStridedLayout end +struct DenseRowMajor <: AbstractRowMajor end +struct RowMajor <: AbstractRowMajor end +struct StridedLayout <: AbstractStridedLayout end """ - UnknownLayout{T}() + UnknownLayout() is returned by `MemoryLayout(A)` if it is unknown how the entries of an array `A` are stored in memory. @@ -295,7 +295,7 @@ are stored in memory. UnknownLayout """ - AbstractStridedLayout{T} + AbstractStridedLayout is an abstract type whose subtypes are returned by `MemoryLayout(A)` if a matrix or vector `A` have storage laid out at regular offsets in memory, @@ -305,7 +305,7 @@ this memory layout. AbstractStridedLayout """ - DenseColumnMajor{T}() + DenseColumnMajor() is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory equivalent to an `Array`, so that `stride(A,1) == 1` and `stride(A,2) == size(A,1)`. @@ -314,7 +314,7 @@ Arrays with `DenseColumnMajor` must conform to the `DenseArray` interface. DenseColumnMajor """ - ColumnMajor{T}() + ColumnMajor() is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage in memory as a column major matrix. In other words, the columns are stored in memory with @@ -324,7 +324,7 @@ Arrays with `ColumnMajor` must conform to the `DenseArray` interface. ColumnMajor """ - DenseRowMajor{T}() + DenseRowMajor() is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory equivalent to the transpose of an `Array`, so that `stride(A,1) == size(A,1)` and @@ -334,18 +334,18 @@ equivalent to the transpose of an `Array`, so that `stride(A,1) == size(A,1)` an DenseRowMajor """ - RowMajor{T}() + RowMajor() is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory as a row major matrix. In other words, the rows are stored in memory with offsets of one, while the columns are stored with offsets given by `stride(A,1)`. Arrays with `RowMajor` must conform to the `DenseArray` interface, -and `transpose(A)` should return a matrix whose layout is `ColumnMajor{T}()`. +and `transpose(A)` should return a matrix whose layout is `ColumnMajor()`. """ RowMajor """ - StridedLayout{T}() + StridedLayout() is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage laid out at regular offsets in memory. In other words, the columns are stored with offsets given @@ -365,9 +365,9 @@ implement memory layout, then you must set this trait for your array type: for example, if your matrix is column major with `stride(A,2) == size(A,1)`, then override as follows: - Base.MemoryLayout(::Type{M}) where M <: MyMatrix{T} where {T} = Base.DenseColumnMajor{T}() + Base.MemoryLayout(::Type{M}) where M <: MyMatrix = Base.DenseColumnMajor() -The default is `Base.UnknownLayout{T}()` to indicate that the layout +The default is `Base.UnknownLayout()` to indicate that the layout in memory is unknown. Julia's internal linear algebra machinery will automatically (and invisibly) @@ -376,10 +376,10 @@ 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)`. """ -MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout{T}() +MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout() -MemoryLayout(A::Vector{T}) where T = DenseColumnMajor{T}() -MemoryLayout(A::Matrix{T}) where T = DenseColumnMajor{T}() +MemoryLayout(A::Vector{T}) where T = DenseColumnMajor() +MemoryLayout(A::Matrix{T}) where T = DenseColumnMajor() diff --git a/base/reinterpretarray.jl b/base/reinterpretarray.jl index 6599bf0d1bcc4..72b3f8d00b24e 100644 --- a/base/reinterpretarray.jl +++ b/base/reinterpretarray.jl @@ -44,9 +44,9 @@ function size(a::ReinterpretArray{T,N,S} where {N}) where {T,S} tuple(size1, tail(psize)...) end -MemoryLayout(A::ReinterpretArray{V}) where V = reinterpretedmemorylayout(MemoryLayout(parent(A)), V) -reinterpretedmemorylayout(::MemoryLayout{T}, ::Type{V}) where {T,V} = UnknownLayout{V}() -reinterpretedmemorylayout(::DenseColumnMajor{T}, ::Type{V}) where {T,V} = DenseColumnMajor{V}() +MemoryLayout(A::ReinterpretArray) where V = reinterpretedmemorylayout(MemoryLayout(parent(A))) +reinterpretedmemorylayout(::MemoryLayout) = UnknownLayout() +reinterpretedmemorylayout(::DenseColumnMajor) = DenseColumnMajor() unsafe_convert(::Type{Ptr{T}}, a::ReinterpretArray{T,N,S} where N) where {T,S} = Ptr{T}(unsafe_convert(Ptr{S},a.parent)) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index 0354fdaa2c33d..83d3f752e62eb 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -244,7 +244,7 @@ setindex!(A::ReshapedRange, val, index::ReshapedIndex) = _rs_setindex!_err() MemoryLayout(A::ReshapedArray) = reshapedmemorylayout(MemoryLayout(parent(A))) -reshapedmemorylayout(::MemoryLayout{T}) where T = UnknownLayout{T}() -reshapedmemorylayout(::DenseColumnMajor{T}) where T = DenseColumnMajor{T}() +reshapedmemorylayout(::MemoryLayout) = UnknownLayout() +reshapedmemorylayout(::DenseColumnMajor) = DenseColumnMajor() unsafe_convert(::Type{Ptr{T}}, a::ReshapedArray{T}) where {T} = unsafe_convert(Ptr{T}, parent(a)) diff --git a/base/subarray.jl b/base/subarray.jl index 86d552ed7e900..c71e3003da5c2 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -318,31 +318,31 @@ find_extended_inds(i1, I...) = (@_inline_meta; (i1, find_extended_inds(I...)...) find_extended_inds() = () MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) -submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() -submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseColumnMajor{T}() -submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = - StridedLayout{T}() -submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I,Int}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseColumnMajor{T}() -submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I,Int}) where {T,I<:Slice} = - DenseColumnMajor{T}() -submemorylayout(::AbstractRowMajor{T}, ::Tuple{Int,I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseColumnMajor{T}() -submemorylayout(::AbstractRowMajor{T}, ::Tuple{Int,I}) where {T,I<:Slice} = - DenseColumnMajor{T}() -submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:AbstractUnitRange{Int}} = - DenseColumnMajor{T}() -submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - ColumnMajor{T}() -submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - ColumnMajor{T}() -submemorylayout(::AbstractRowMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:Slice} = - DenseRowMajor{T}() -submemorylayout(::AbstractRowMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - RowMajor{T}() -submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = - StridedLayout{T}() +submemorylayout(::MemoryLayout, _)= UnknownLayout() +submemorylayout(::AbstractColumnMajor, ::Tuple{I}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor() +submemorylayout(::AbstractStridedLayout, ::Tuple{I}) where {I<:Union{RangeIndex,AbstractCartesianIndex}} = + StridedLayout() +submemorylayout(::AbstractColumnMajor, ::Tuple{I,Int}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor() +submemorylayout(::AbstractColumnMajor, ::Tuple{I,Int}) where {I<:Slice} = + DenseColumnMajor() +submemorylayout(::AbstractRowMajor, ::Tuple{Int,I}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor() +submemorylayout(::AbstractRowMajor, ::Tuple{Int,I}) where {I<:Slice} = + DenseColumnMajor() +submemorylayout(::DenseColumnMajor, ::Tuple{I1,I2}) where {I1<:Slice,I2<:AbstractUnitRange{Int}} = + DenseColumnMajor() +submemorylayout(::DenseColumnMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + ColumnMajor() +submemorylayout(::AbstractColumnMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + ColumnMajor() +submemorylayout(::AbstractRowMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:Slice} = + DenseRowMajor() +submemorylayout(::AbstractRowMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + RowMajor() +submemorylayout(::AbstractStridedLayout, ::Tuple{I1,I2}) where {I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = + StridedLayout() 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) diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 44b744922ac13..d73d9b7cd07cd 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -408,7 +408,7 @@ perhaps range-types `Ind` of your own design. For more information, see [Arrays |:----------------------------------------------- |:-------------------------------------- |:------------------------------------------------------------------------------------- | | `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{T}()`,`Base.DenseRowMajor{T}()`, or `Base.StridedLayout{T}()`. +| `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. | diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index 58bb8cd201cf4..8488eca22f032 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -131,28 +131,27 @@ IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() # MemoryLayout of transposed and adjoint matrices -struct ConjLayout{T<:Complex, ML<:MemoryLayout} <: MemoryLayout{T} +struct ConjLayout{ML<:MemoryLayout} <: MemoryLayout layout::ML end -ConjLayout(layout::ML) where ML<:MemoryLayout{T} where T<:Complex = ConjLayout{T,ML}(layout) -conj(::UnknownLayout{T}) where T = UnknownLayout{T}() -conj(c::ConjLayout) = c.layout -conj(layout::MemoryLayout{T}) where T<:Complex = ConjLayout(layout) - - -MemoryLayout(A::Adjoint) = adjoint(MemoryLayout(parent(A))) -MemoryLayout(A::Transpose) = transpose(MemoryLayout(parent(A))) -transpose(::MemoryLayout{T}) where T = UnknownLayout{T}() -transpose(::StridedLayout{T}) where T = StridedLayout{T}() -transpose(::ColumnMajor{T}) where T = RowMajor{T}() -transpose(::RowMajor{T}) where T = ColumnMajor{T}() -transpose(::DenseColumnMajor{T}) where T = DenseRowMajor{T}() -transpose(::DenseRowMajor{T}) where T = DenseColumnMajor{T}() -adjoint(::MemoryLayout{T}) where T = UnknownLayout{T}() -adjoint(M::MemoryLayout{T}) where T<:Real = transpose(M) -adjoint(M::ConjLayout{T}) where T<:Complex = transpose(conj(M)) -adjoint(M::MemoryLayout{T}) where T<:Complex = conj(transpose(M)) -Base.submemorylayout(M::ConjLayout{T}, t::Tuple) where T<:Complex = conj(Base.submemorylayout(conj(M), t)) +conjlayout(::Type{<:Complex}, M::ConjLayout) = M.layout +conjlayout(::Type{<:Complex}, M::MemoryLayout) = ConjLayout(M) +conjlayout(::Type{<:Real}, M::MemoryLayout) = M +conjlayout(::Type{<:Complex}, M::UnknownLayout) = M + +Base.submemorylayout(M::ConjLayout, t::Tuple) = ConjLayout(Base.submemorylayout(M.layout, t)) + +MemoryLayout(A::Transpose) = transposelayout(MemoryLayout(parent(A))) +MemoryLayout(A::Adjoint) = adjointlayout(eltype(A), MemoryLayout(parent(A))) +transposelayout(_) = UnknownLayout() +transposelayout(::StridedLayout) = StridedLayout() +transposelayout(::ColumnMajor) = RowMajor() +transposelayout(::RowMajor) = ColumnMajor() +transposelayout(::DenseColumnMajor) = DenseRowMajor() +transposelayout(::DenseRowMajor) = DenseColumnMajor() +transposelayout(M::ConjLayout) = ConjLayout(transposelayout(M.layout)) +adjointlayout(::Type{T}, M::MemoryLayout) where T = transposelayout(conjlayout(T, M)) + # Adjoints and transposes conform to the strided array interface if their parent does Base.unsafe_convert(::Type{Ptr{T}}, A::AdjOrTrans{T,S}) where {T,S} = Base.unsafe_convert(Ptr{T}, parent(A)) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index 474bd5d44a2c7..9fd1d24bd8351 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -513,7 +513,7 @@ function exp!(A::AbstractMatrix{T}, _) where T<:BlasFloat A .= exp!(Matrix{T}(A)) A end -function _exp!(A::AbstractMatrix{T}, ::AbstractColumnMajor{T}) where T<:BlasFloat +function _exp!(A::AbstractMatrix{T}, ::AbstractColumnMajor) where T<:BlasFloat n = checksquare(A) if ishermitian(A) return copytri!(parent(exp(Hermitian(A))), 'U', true) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index d546efa54e78a..7eeae11d161a6 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -91,11 +91,11 @@ end _mul!(y::AbstractVector, transA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::AbstractRowMajor, ::AbstractStridedLayout) = (A = transpose(transA); generic_matvecmul!(y, 'T', A, x)) -_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractStridedLayout) = +_mul!(y::AbstractVector, adjA::AbstractMatrix, x::AbstractVector, ::AbstractStridedLayout, ::ConjLayout{<:AbstractRowMajor}, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matvecmul!(y, 'C', A, x)) _mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractRowMajor, ::AbstractStridedLayout) where {T<:BlasFloat} = gemv!(y, 'T', transpose(adjA), x) -_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = +_mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, ::ConjLayout{<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = gemv!(y, 'C', adjoint(adjA), x) # Vector-matrix multiplication @@ -182,21 +182,21 @@ _mul!(C::AbstractMatrix{T}, transA::AbstractMatrix{T}, transB::AbstractMatrix{T} _mul!(C::AbstractMatrix, transA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractRowMajor, ::AbstractRowMajor) = (A = transpose(transA); B = transpose(transB); generic_matmatmul!(C, 'T', 'T', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractColumnMajor, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractColumnMajor) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractColumnMajor, ::ConjLayout{<:AbstractRowMajor}, ::AbstractColumnMajor) where {T<:BlasComplex} = (A = adjoint(adjA); A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractStridedLayout) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:AbstractRowMajor}, ::AbstractStridedLayout) = (A = adjoint(adjA); generic_matmatmul!(C, 'C', 'N', A, B)) -_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractColumnMajor, ::AbstractColumnMajor, ::ConjLayout{<:Complex,<:AbstractRowMajor}) where {T<:BlasComplex} = +_mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractColumnMajor, ::AbstractColumnMajor, ::ConjLayout{<:AbstractRowMajor}) where {T<:BlasComplex} = (B = adjoint(adjB); A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}) = +_mul!(C::AbstractMatrix, A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::AbstractStridedLayout, ::ConjLayout{<:AbstractRowMajor}) = (B = adjoint(adjB); generic_matmatmul!(C, 'N', 'C', A, B)) -_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractColumnMajor, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::ConjLayout{<:Complex,<:AbstractRowMajor}) where {T<:BlasFloat} = +_mul!(C::AbstractMatrix{T}, adjA::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractColumnMajor, ::ConjLayout{<:AbstractRowMajor}, ::ConjLayout{<:AbstractRowMajor}) where {T<:BlasFloat} = (A = adjoint(adjA); B = adjoint(adjB); gemm_wrapper!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::ConjLayout{<:Complex,<:AbstractRowMajor}) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:AbstractRowMajor}, ::ConjLayout{<:AbstractRowMajor}) = (A = adjoint(adjA); B = adjoint(adjB); generic_matmatmul!(C, 'C', 'C', A, B)) -_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:Complex,<:AbstractRowMajor}, ::AbstractRowMajor) = +_mul!(C::AbstractMatrix, adjA::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::ConjLayout{<:AbstractRowMajor}, ::AbstractRowMajor) = (A = adjoint(adjA); B = transpose(transB); generic_matmatmul!(C, 'C', 'T', A, B)) # Supporting functions for matrix multiplication diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index b5fe450bae04a..59e53a9124dac 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -245,33 +245,31 @@ Hermitian{T,S}(A::Hermitian) where {T,S<:AbstractMatrix} = Hermitian{T,S}(conver AbstractMatrix{T}(A::Hermitian) where {T} = Hermitian(convert(AbstractMatrix{T}, A.data), Symbol(A.uplo)) # MemoryLayout of Symmetric/Hermitian -struct SymmetricLayout{T,ML<:MemoryLayout} <: MemoryLayout{T} +struct SymmetricLayout{ML<:MemoryLayout} <: MemoryLayout layout::ML uplo::Char end -SymmetricLayout(layout::ML, uplo) where ML<:MemoryLayout{T} where T = SymmetricLayout{T,ML}(layout, uplo) -struct HermitianLayout{T,ML<:MemoryLayout} <: MemoryLayout{T} +SymmetricLayout(layout::ML, uplo) where ML<:MemoryLayout = SymmetricLayout{ML}(layout, uplo) +struct HermitianLayout{ML<:MemoryLayout} <: MemoryLayout layout::ML uplo::Char end -HermitianLayout(layout::ML, uplo) where ML<:MemoryLayout{T} where T = HermitianLayout{T,ML}(layout, uplo) +HermitianLayout(layout::ML, uplo) where ML<:MemoryLayout = HermitianLayout{ML}(layout, uplo) -MemoryLayout(A::Hermitian) = hermitianmemorylayout(MemoryLayout(parent(A)), A.uplo) +MemoryLayout(A::Hermitian) = hermitianmemorylayout(eltype(A), MemoryLayout(parent(A)), A.uplo) MemoryLayout(A::Symmetric) = symmetricmemorylayout(MemoryLayout(parent(A)), A.uplo) -hermitianmemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() -hermitianmemorylayout(layout::AbstractColumnMajor{<:Complex}, uplo) = HermitianLayout(layout,uplo) -hermitianmemorylayout(layout::AbstractColumnMajor{<:Real}, uplo) = SymmetricLayout(layout,uplo) -hermitianmemorylayout(layout::AbstractRowMajor{<:Complex}, uplo) = HermitianLayout(layout,uplo) -hermitianmemorylayout(layout::AbstractRowMajor{<:Real}, uplo) = SymmetricLayout(layout,uplo) -symmetricmemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() +hermitianmemorylayout(_1, _2, _3) = UnknownLayout() +hermitianmemorylayout(::Type{<:Complex}, layout::AbstractColumnMajor, uplo) = HermitianLayout(layout,uplo) +hermitianmemorylayout(::Type{<:Real}, layout::AbstractColumnMajor, uplo) = SymmetricLayout(layout,uplo) +hermitianmemorylayout(::Type{<:Complex}, layout::AbstractRowMajor, uplo) = HermitianLayout(layout,uplo) +hermitianmemorylayout(::Type{<:Real}, layout::AbstractRowMajor, uplo) = SymmetricLayout(layout,uplo) +symmetricmemorylayout(_1, _2) = UnknownLayout() symmetricmemorylayout(layout::AbstractColumnMajor, uplo) = SymmetricLayout(layout,uplo) symmetricmemorylayout(layout::AbstractRowMajor, uplo) = SymmetricLayout(layout,uplo) - -adjoint(H::HermitianLayout) = H -adjoint(H::SymmetricLayout{<:Real}) = H -transpose(H::SymmetricLayout) = H - - +symmetricmemorylayout(layout::ConjLayout{<:AbstractColumnMajor}, uplo) = SymmetricLayout(layout,uplo) +symmetricmemorylayout(layout::ConjLayout{<:AbstractRowMajor}, uplo) = SymmetricLayout(layout,uplo) +transposelayout(S::SymmetricLayout) = S +adjointlayout(::Type{T}, S::HermitianLayout) where T = S copy(A::Symmetric{T,S}) where {T,S} = (B = copy(A.data); Symmetric{T,typeof(B)}(B,A.uplo)) copy(A::Hermitian{T,S}) where {T,S} = (B = copy(A.data); Hermitian{T,typeof(B)}(B,A.uplo)) @@ -411,34 +409,34 @@ end ## Matrix-vector product _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::SymmetricLayout{T,<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, AL::SymmetricLayout{<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symv!(AL.uplo, one(T), parent(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::SymmetricLayout{T,<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, AL::SymmetricLayout{<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(parent(A)), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::HermitianLayout{T,<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, AL::HermitianLayout{<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemv!(AL.uplo, one(T), parent(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, - ::AbstractStridedLayout, AL::HermitianLayout{T,<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, AL::HermitianLayout{<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(parent(A)), x, zero(T), y) ## Matrix-matrix product _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, AL::SymmetricLayout{T,<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = + ::AbstractStridedLayout, AL::SymmetricLayout{<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = BLAS.symm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout{T,<:AbstractColumnMajor}) where {T<:BlasFloat} = + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout{<:AbstractColumnMajor}) where {T<:BlasFloat} = BLAS.symm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, AL::HermitianLayout{T,<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = + ::AbstractStridedLayout, AL::HermitianLayout{<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.hemm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout{T,<:AbstractColumnMajor}) where {T<:BlasComplex} = + ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout{<:AbstractColumnMajor}) where {T<:BlasComplex} = BLAS.hemm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, - ::AbstractStridedLayout, ::Union{HermitianLayout{T}, SymmetricLayout{T}}, ::Union{HermitianLayout{T}, SymmetricLayout{T}}) where {T<:BlasFloat} = + ::AbstractStridedLayout, ::Union{HermitianLayout, SymmetricLayout}, ::Union{HermitianLayout, SymmetricLayout}) where {T<:BlasFloat} = mul!(C, A, Matrix{T}(B)) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 1be6eb0293437..7eee65939a14d 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -367,20 +367,17 @@ diag(A::UnitUpperTriangular) = fill(one(eltype(A)), size(A,1)) for memlay in (:LowerTriangularLayout, :UnitLowerTriangularLayout, :UpperTriangularLayout, :UnitUpperTriangularLayout) @eval begin - struct $memlay{T, ML<:MemoryLayout} <: MemoryLayout{T} + struct $memlay{ML<:MemoryLayout} <: MemoryLayout layout::ML end - $memlay(layout::ML) where ML<:MemoryLayout{T} where T = $memlay{T,ML}(layout) end end """ - LowerTriangularLayout{trans,T} + LowerTriangularLayout(ML::MemoryLayout) is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory -equivalent to a `LowerTriangular{T,Matrix{T}}` (`trans == 'N'`), -`Adjoint{T,UpperTriangular{T,Matrix{T}}` (`trans == 'C'`), or -`Transpose{T,UpperTriangular{T,Matrix{T}}` (`trans == 'T'`). +equivalent to a `LowerTriangular(B)` where `B` satisfies `MemoryLayout(B) == ML`. `A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and `transpose(A).data` must exist if `trans == 'T'`. @@ -388,12 +385,10 @@ equivalent to a `LowerTriangular{T,Matrix{T}}` (`trans == 'N'`), LowerTriangularLayout """ - UnitLowerTriangularLayout{trans,T} + UnitLowerTriangularLayout(ML::MemoryLayout) is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory -equivalent to a `UnitLowerTriangular{T,Matrix{T}}` (`trans = 'N'`), -`Adjoint{T,UnitUpperTriangular{T,Matrix{T}}` (`trans = 'C'`), or -`Transpose{T,UnitUpperTriangular{T,Matrix{T}}` (`trans = 'T'`). +equivalent to a `UnitLowerTriangular(B)` where `B` satisfies `MemoryLayout(B) == ML`. `A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and `transpose(A).data` must exist if `trans == 'T'`. @@ -401,12 +396,10 @@ equivalent to a `UnitLowerTriangular{T,Matrix{T}}` (`trans = 'N'`), UnitLowerTriangularLayout """ - UpperTriangularLayout{trans,T} + UpperTriangularLayout(ML::MemoryLayout) is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory -equivalent to a `UpperTriangular{T,Matrix{T}}` (`trans = 'N'`), -`Adjoint{T,LowerTriangular{T,Matrix{T}}` (`trans = 'C'`), or -`Transpose{T,LowerTriangular{T,Matrix{T}}` (`trans = 'T'`). +equivalent to a `UpperTriangularLayout(B)` where `B` satisfies `MemoryLayout(B) == ML`. `A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and `transpose(A).data` must exist if `trans == 'T'`. @@ -414,12 +407,10 @@ equivalent to a `UpperTriangular{T,Matrix{T}}` (`trans = 'N'`), UpperTriangularLayout """ - UnitUpperTriangularLayout{trans,T} + UnitUpperTriangularLayout(ML::MemoryLayout) is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory -equivalent to a `UnitUpperTriangular{T,Matrix{T}}` (`trans = 'N'`), -`Adjoint{T,UnitLowerTriangular{T,Matrix{T}}` (`trans = 'C'`), or -`Transpose{T,UnitLowerTriangular{T,Matrix{T}}` (`trans = 'T'`). +equivalent to a `UpperTriangularLayout(B)` where `B` satisfies `MemoryLayout(B) == ML`. `A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and `transpose(A).data` must exist if `trans == 'T'`. @@ -431,17 +422,16 @@ MemoryLayout(A::UpperTriangular) = trilayout(UpperTriangularLayout, MemoryLayout MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, MemoryLayout(parent(A))) MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, MemoryLayout(parent(A))) MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, MemoryLayout(parent(A))) -trilayout(_, ::MemoryLayout{T}) where T = UnknownLayout{T}() -trilayout(::Type{Tri}, ML::AbstractColumnMajor{T}) where {Tri,T} = Tri(ML) +trilayout(_, ::MemoryLayout) = UnknownLayout() +trilayout(::Type{Tri}, ML::AbstractColumnMajor) where {Tri} = Tri(ML) for (TriLayout, TriLayoutTrans) in ((UpperTriangularLayout, LowerTriangularLayout), (UnitUpperTriangularLayout, UnitLowerTriangularLayout), (LowerTriangularLayout, UpperTriangularLayout), (UnitLowerTriangularLayout, UnitUpperTriangularLayout)) @eval begin - transpose(ml::$TriLayout) = $TriLayoutTrans(transpose(ml.layout)) - adjoint(ml::$TriLayout) = $TriLayoutTrans(adjoint(ml.layout)) - conj(ml::$TriLayout) = $TriLayoutTrans(conj(ml.layout)) + transposelayout(ml::$TriLayout) = $TriLayoutTrans(transposelayout(ml.layout)) + conjlayout(::Type{<:Complex}, ml::$TriLayout) = $TriLayout(ConjLayout(ml.layout)) end end @@ -607,11 +597,11 @@ for (t, memlay, memlaytrans, uploc, isunitc) in ((:LowerTriangular, :LowerTriang _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::AbstractStridedLayout, ::$memlay, ::AbstractStridedLayout) where {T<:BlasFloat} = lmul!(A, copyto!(y, b)) - _lmul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{T,DC}, ::AbstractStridedLayout) where {T<:BlasFloat,DC<:AbstractColumnMajor} = + _lmul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{DC}, ::AbstractStridedLayout) where {T<:BlasFloat,DC<:AbstractColumnMajor} = BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) - _lmul!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{T,DR}, ::AbstractStridedLayout) where {T<:BlasFloat,DR<:AbstractRowMajor} = + _lmul!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{DR}, ::AbstractStridedLayout) where {T<:BlasFloat,DR<:AbstractRowMajor} = (A = transpose(transA); BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) - _lmul!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{T,ConjLayout{T,DR}}, ::AbstractStridedLayout) where {T<:BlasComplex,DR<:AbstractRowMajor} = + _lmul!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{ConjLayout{DR}}, ::AbstractStridedLayout) where {T<:BlasComplex,DR<:AbstractRowMajor} = (A = adjoint(adjA); BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) # Matrix multiplication @@ -620,19 +610,19 @@ for (t, memlay, memlaytrans, uploc, isunitc) in ((:LowerTriangular, :LowerTriang _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, ::$memlay) where {T<:BlasFloat} = rmul!(copyto!(C, A), B) - _lmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{T,DC}, ::AbstractColumnMajor) where {T<:BlasFloat,DC<:AbstractColumnMajor} = + _lmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{DC}, ::AbstractColumnMajor) where {T<:BlasFloat,DC<:AbstractColumnMajor} = BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B) - _rmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlay{T,DC}) where {T<:BlasFloat,DC<:AbstractColumnMajor} = + _rmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlay{DC}) where {T<:BlasFloat,DC<:AbstractColumnMajor} = BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) - _lmul!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{T,DR}, ::AbstractColumnMajor) where {T<:BlasFloat,DR<:AbstractRowMajor} = + _lmul!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{DR}, ::AbstractColumnMajor) where {T<:BlasFloat,DR<:AbstractRowMajor} = (A = transpose(transA); BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) - _lmul!(adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{T,ConjLayout{T,DR}}, ::AbstractColumnMajor) where {T<:BlasComplex,DR<:AbstractRowMajor} = + _lmul!(adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{ConjLayout{DR}}, ::AbstractColumnMajor) where {T<:BlasComplex,DR<:AbstractRowMajor} = (A = adjoint(adjA); BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B)) - _rmul!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlaytrans{T,DR}) where {T<:BlasFloat,DR<:AbstractRowMajor} = + _rmul!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlaytrans{DR}) where {T<:BlasFloat,DR<:AbstractRowMajor} = (B = transpose(transB); BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) - _rmul!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlaytrans{T,ConjLayout{T,DR}}) where {T<:BlasComplex,DR<:AbstractRowMajor} = + _rmul!(A::AbstractMatrix{T}, adjB::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlaytrans{ConjLayout{DR}}) where {T<:BlasComplex,DR<:AbstractRowMajor} = (B = adjoint(adjB); BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), B.data, A)) # Left division @@ -768,7 +758,7 @@ for (t, unitt) in ((UpperTriangular, UnitUpperTriangular), end ## Generic triangular multiplication -function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,<:AbstractColumnMajor}, _) where T +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{<:AbstractColumnMajor}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -785,7 +775,7 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{ B end -function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,<:AbstractColumnMajor}, _) where T +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{<:AbstractColumnMajor}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -802,7 +792,7 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLay B end -function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,<:AbstractColumnMajor}, _) where T +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{<:AbstractColumnMajor}, _) where T m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -818,7 +808,7 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{ end B end -function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,<:AbstractColumnMajor}, _) where T +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{<:AbstractColumnMajor}, _) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) @@ -835,7 +825,7 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLay B end -function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:AbstractRowMajor} +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}, _) A = adjoint(adjA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -853,7 +843,7 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayo B end -function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:AbstractRowMajor} +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}, _) A = adjA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -871,7 +861,7 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangular B end -function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:AbstractRowMajor} +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}, _) A = adjA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -888,7 +878,7 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayo end B end -function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,ConjLayout{T,DR}}, _) where {T,DR<:AbstractRowMajor} +function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}, _) A = adjA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -906,7 +896,7 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangular B end -function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{T,DR}, _) where {T,DR<:AbstractRowMajor} +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{<:AbstractRowMajor}, _) A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -923,7 +913,7 @@ function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLa end B end -function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{T,DR}, _) where {T,DR<:AbstractRowMajor} +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{<:AbstractRowMajor}, _) A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -941,7 +931,7 @@ function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangul B end -function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{T,DR}, _) where {T,DR<:AbstractRowMajor} +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{<:AbstractRowMajor}, _) A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -958,7 +948,7 @@ function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLa end B end -function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{T,DR}, _) where {T,DR<:AbstractRowMajor} +function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{<:AbstractRowMajor}, _) A = transA.parent m, n = size(B, 1), size(B, 2) if m != size(A, 1) @@ -1042,7 +1032,7 @@ function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, : A end -function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:AbstractRowMajor} +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}) B = adjoint(adjB) m, n = size(A) if size(B, 1) != n @@ -1060,7 +1050,7 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout A end -function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:AbstractRowMajor} +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}) B = adjoint(adjB) m, n = size(A) if size(B, 1) != n @@ -1078,7 +1068,7 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout A end -function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:AbstractRowMajor} +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}) B = adjoint(adjB) m, n = size(A) if size(B, 1) != n @@ -1096,7 +1086,7 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout A end -function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{T,ConjLayout{T,DR}}) where {T,DR<:AbstractRowMajor} +function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}) B = adjoint(adjB) m, n = size(A) if size(B, 1) != n @@ -1114,7 +1104,7 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout A end -function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{T,DR}) where {T,DR<:AbstractRowMajor} +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::LowerTriangularLayout{<:AbstractRowMajor}) B = transpose(transB) m, n = size(A) if size(B, 1) != n @@ -1131,7 +1121,7 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo end A end -function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{T,DR}) where {T,DR<:AbstractRowMajor} +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{<:AbstractRowMajor}) B = transB.parent m, n = size(A) if size(B, 1) != n @@ -1149,7 +1139,7 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo A end -function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{T,DR}) where {T,DR<:AbstractRowMajor} +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{<:AbstractRowMajor}) B = transB.parent m, n = size(A) if size(B, 1) != n @@ -1167,7 +1157,7 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo A end -function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{T,DR}) where {T,DR<:AbstractRowMajor} +function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{<:AbstractRowMajor}) B = transB.parent m, n = size(A) if size(B, 1) != n diff --git a/stdlib/LinearAlgebra/test/adjtrans.jl b/stdlib/LinearAlgebra/test/adjtrans.jl index 32b164704a77e..7e7cb60f312ee 100644 --- a/stdlib/LinearAlgebra/test/adjtrans.jl +++ b/stdlib/LinearAlgebra/test/adjtrans.jl @@ -449,37 +449,37 @@ end @testset "adjoint and transpose MemoryLayout" begin A = [1.0 2; 3 4] - @test Base.MemoryLayout(A') == Base.DenseRowMajor{Float64}() - @test Base.MemoryLayout(transpose(A)) == Base.DenseRowMajor{Float64}() + @test Base.MemoryLayout(A') == Base.DenseRowMajor() + @test Base.MemoryLayout(transpose(A)) == Base.DenseRowMajor() B = [1.0+im 2; 3 4] - @test Base.MemoryLayout(B') == LinearAlgebra.ConjLayout(Base.DenseRowMajor{ComplexF64}()) - @test Base.MemoryLayout(transpose(B)) == Base.DenseRowMajor{ComplexF64}() + @test Base.MemoryLayout(B') == LinearAlgebra.ConjLayout(Base.DenseRowMajor()) + @test Base.MemoryLayout(transpose(B)) == Base.DenseRowMajor() VA = view(A, 1:1, 1:1) - @test Base.MemoryLayout(VA') == Base.RowMajor{Float64}() - @test Base.MemoryLayout(transpose(VA)) == Base.RowMajor{Float64}() + @test Base.MemoryLayout(VA') == Base.RowMajor() + @test Base.MemoryLayout(transpose(VA)) == Base.RowMajor() VB = view(B, 1:1, 1:1) - @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(Base.RowMajor{ComplexF64}()) - @test Base.MemoryLayout(transpose(VB)) == Base.RowMajor{ComplexF64}() + @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(Base.RowMajor()) + @test Base.MemoryLayout(transpose(VB)) == Base.RowMajor() VA = view(A, 1:2:2, 1:2:2) - @test Base.MemoryLayout(VA') == Base.StridedLayout{Float64}() - @test Base.MemoryLayout(transpose(VA)) == Base.StridedLayout{Float64}() + @test Base.MemoryLayout(VA') == Base.StridedLayout() + @test Base.MemoryLayout(transpose(VA)) == Base.StridedLayout() VB = view(B, 1:2:2, 1:2:2) - @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(Base.StridedLayout{ComplexF64}()) - @test Base.MemoryLayout(transpose(VB)) == Base.StridedLayout{ComplexF64}() + @test Base.MemoryLayout(VB') == LinearAlgebra.ConjLayout(Base.StridedLayout()) + @test Base.MemoryLayout(transpose(VB)) == Base.StridedLayout() VA2 = view(A, [1,2], :) - @test Base.MemoryLayout(VA2') == Base.UnknownLayout{Float64}() - @test Base.MemoryLayout(transpose(VA2)) == Base.UnknownLayout{Float64}() + @test Base.MemoryLayout(VA2') == Base.UnknownLayout() + @test Base.MemoryLayout(transpose(VA2)) == Base.UnknownLayout() VB2 = view(B, [1,2], :) - @test Base.MemoryLayout(VB2') == Base.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(transpose(VB2)) == Base.UnknownLayout{ComplexF64}() + @test Base.MemoryLayout(VB2') == Base.UnknownLayout() + @test Base.MemoryLayout(transpose(VB2)) == Base.UnknownLayout() VAc = view(A', 1:1, 1:1) - @test Base.MemoryLayout(VAc) == Base.RowMajor{Float64}() + @test Base.MemoryLayout(VAc) == Base.RowMajor() VAt = view(transpose(A), 1:1, 1:1) - @test Base.MemoryLayout(VAt) == Base.RowMajor{Float64}() + @test Base.MemoryLayout(VAt) == Base.RowMajor() VBc = view(B', 1:1, 1:1) - @test Base.MemoryLayout(VBc) == LinearAlgebra.ConjLayout(Base.RowMajor{ComplexF64}()) + @test Base.MemoryLayout(VBc) == LinearAlgebra.ConjLayout(Base.RowMajor()) VBt = view(transpose(B), 1:1, 1:1) - @test Base.MemoryLayout(VBt) == Base.RowMajor{ComplexF64}() + @test Base.MemoryLayout(VBt) == Base.RowMajor() end diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index d5554496f06ff..19bd8014dc6be 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -489,27 +489,27 @@ end @testset "Symmetric/Hermitian MemoryLayout" begin A = [1.0 2; 3 4] - @test Base.MemoryLayout(Symmetric(A)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Hermitian(A)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Transpose(Symmetric(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{Float64}(),'U') - @test Base.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{Float64}(),'U') - @test Base.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{Float64}(),'U') - @test Base.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{Float64}(),'U') - @test Base.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{Float64}(),'U') + @test Base.MemoryLayout(Symmetric(A)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Hermitian(A)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Transpose(Symmetric(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') + @test Base.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') + @test Base.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') + @test Base.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') B = [1.0+im 2; 3 4] - @test Base.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Transpose(Hermitian(B))) == Base.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.ConjLayout(LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor{ComplexF64}(),'U')) - @test Base.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Symmetric(B')) == Base.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(Hermitian(B')) == Base.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor{ComplexF64}(),'U') - @test Base.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout(Base.DenseRowMajor{ComplexF64}(),'U') + @test Base.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Transpose(Hermitian(B))) == Base.UnknownLayout() + @test Base.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.ConjLayout(Base.DenseColumnMajor()),'U') + @test Base.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(Symmetric(B')) == Base.UnknownLayout() + @test Base.MemoryLayout(Hermitian(B')) == Base.UnknownLayout() + @test Base.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') + @test Base.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout(Base.DenseRowMajor(),'U') A = randn(100,100) x = randn(100) diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index 574b020490297..a590fab104b00 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -556,17 +556,17 @@ end (UnitUpperTriangular, LinearAlgebra.UnitUpperTriangularLayout, LinearAlgebra.UnitLowerTriangularLayout), (LowerTriangular, LinearAlgebra.LowerTriangularLayout, LinearAlgebra.UpperTriangularLayout), (UnitLowerTriangular, LinearAlgebra.UnitLowerTriangularLayout, LinearAlgebra.UnitUpperTriangularLayout)) - @test Base.MemoryLayout(TriType(A)) == TriLayout(Base.DenseColumnMajor{Float64}()) - @test Base.MemoryLayout(TriType(transpose(A))) == Base.UnknownLayout{Float64}() - @test Base.MemoryLayout(TriType(A')) == Base.UnknownLayout{Float64}() - @test Base.MemoryLayout(transpose(TriType(A))) == TriLayoutTrans(Base.DenseRowMajor{Float64}()) - @test Base.MemoryLayout(TriType(A)') == TriLayoutTrans(Base.DenseRowMajor{Float64}()) - - @test Base.MemoryLayout(TriType(B)) == TriLayout(Base.DenseColumnMajor{ComplexF64}()) - @test Base.MemoryLayout(TriType(transpose(B))) == Base.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(TriType(B')) == Base.UnknownLayout{ComplexF64}() - @test Base.MemoryLayout(transpose(TriType(B))) == TriLayoutTrans(Base.DenseRowMajor{ComplexF64}()) - @test Base.MemoryLayout(TriType(B)') == TriLayoutTrans(conj(Base.DenseRowMajor{ComplexF64}())) + @test Base.MemoryLayout(TriType(A)) == TriLayout(Base.DenseColumnMajor()) + @test Base.MemoryLayout(TriType(transpose(A))) == Base.UnknownLayout() + @test Base.MemoryLayout(TriType(A')) == Base.UnknownLayout() + @test Base.MemoryLayout(transpose(TriType(A))) == TriLayoutTrans(Base.DenseRowMajor()) + @test Base.MemoryLayout(TriType(A)') == TriLayoutTrans(Base.DenseRowMajor()) + + @test Base.MemoryLayout(TriType(B)) == TriLayout(Base.DenseColumnMajor()) + @test Base.MemoryLayout(TriType(transpose(B))) == Base.UnknownLayout() + @test Base.MemoryLayout(TriType(B')) == Base.UnknownLayout() + @test Base.MemoryLayout(transpose(TriType(B))) == TriLayoutTrans(Base.DenseRowMajor()) + @test Base.MemoryLayout(TriType(B)') == TriLayoutTrans(LinearAlgebra.ConjLayout(Base.DenseRowMajor())) end A = randn(Float64, 100, 100) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index f6cee4c80975a..fbd7e6eb6ebcb 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -885,26 +885,26 @@ end @testset "MemoryLayout for Array, SubArray, and ReinterpretArray" begin let A = [1.0 2; 3 4] - @test Base.MemoryLayout(A) == Base.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,:,:)) == Base.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,:)) == Base.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,:,1)) == Base.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,:,1:1)) == Base.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,1:1,1)) == Base.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,1,1:1)) == Base.StridedLayout{Float64}() - @test Base.MemoryLayout(view(A,1,:)) == Base.StridedLayout{Float64}() - @test Base.MemoryLayout(view(A,1:1,1:2)) == Base.ColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,1:1,:)) == Base.ColumnMajor{Float64}() - @test Base.MemoryLayout(view(A,1:2:1,1:2:1)) == Base.StridedLayout{Float64}() - @test Base.MemoryLayout(view(A,1:2:1,:)) == Base.StridedLayout{Float64}() - @test Base.MemoryLayout(view(A,[1,2],:)) == Base.UnknownLayout{Float64}() - - @test Base.MemoryLayout(Base.ReshapedArray(A,(4,),())) == Base.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == Base.DenseColumnMajor{Float64}() - @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == Base.DenseColumnMajor{Float64}() - - @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == Base.DenseColumnMajor{ComplexF64}() - - Base.MemoryLayout(BitArray([true,true,false])) == Base.UnknownLayout{Bool}() + @test Base.MemoryLayout(A) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,:,:)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,:)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,:,1)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,:,1:1)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1:1,1)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1,1:1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1,:)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1:1,1:2)) == Base.ColumnMajor() + @test Base.MemoryLayout(view(A,1:1,:)) == Base.ColumnMajor() + @test Base.MemoryLayout(view(A,1:2:1,1:2:1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1:2:1,:)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,[1,2],:)) == Base.UnknownLayout() + + @test Base.MemoryLayout(Base.ReshapedArray(A,(4,),())) == Base.DenseColumnMajor() + @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == Base.DenseColumnMajor() + @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == Base.DenseColumnMajor() + + @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == Base.DenseColumnMajor() + + Base.MemoryLayout(BitArray([true,true,false])) == Base.UnknownLayout() end end From 6110ccbeb15871bfc12b7472e72d6452a8962442 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Wed, 28 Feb 2018 21:57:48 +0000 Subject: [PATCH 26/39] Fix vecdot, be more conservative in dispatch for symmetriclayout, etc., make naming convention consistent --- base/reinterpretarray.jl | 2 +- stdlib/LinearAlgebra/src/adjtrans.jl | 6 ++++-- stdlib/LinearAlgebra/src/matmul.jl | 12 ++++++------ stdlib/LinearAlgebra/src/symmetric.jl | 22 ++++++++++------------ stdlib/LinearAlgebra/src/triangular.jl | 12 ++++++------ stdlib/LinearAlgebra/test/matmul.jl | 5 +++++ stdlib/LinearAlgebra/test/symmetric.jl | 2 +- 7 files changed, 33 insertions(+), 28 deletions(-) diff --git a/base/reinterpretarray.jl b/base/reinterpretarray.jl index 72b3f8d00b24e..43e5f24b67f92 100644 --- a/base/reinterpretarray.jl +++ b/base/reinterpretarray.jl @@ -44,7 +44,7 @@ function size(a::ReinterpretArray{T,N,S} where {N}) where {T,S} tuple(size1, tail(psize)...) end -MemoryLayout(A::ReinterpretArray) where V = reinterpretedmemorylayout(MemoryLayout(parent(A))) +MemoryLayout(A::ReinterpretArray) = reinterpretedmemorylayout(MemoryLayout(parent(A))) reinterpretedmemorylayout(::MemoryLayout) = UnknownLayout() reinterpretedmemorylayout(::DenseColumnMajor) = DenseColumnMajor() diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index 8488eca22f032..ac37fcce4f401 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -134,10 +134,12 @@ IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() struct ConjLayout{ML<:MemoryLayout} <: MemoryLayout layout::ML end + +conjlayout(_1, _2) = UnknownLayout() conjlayout(::Type{<:Complex}, M::ConjLayout) = M.layout -conjlayout(::Type{<:Complex}, M::MemoryLayout) = ConjLayout(M) +conjlayout(::Type{<:Complex}, M::AbstractStridedLayout) = ConjLayout(M) conjlayout(::Type{<:Real}, M::MemoryLayout) = M -conjlayout(::Type{<:Complex}, M::UnknownLayout) = M + Base.submemorylayout(M::ConjLayout, t::Tuple) = ConjLayout(Base.submemorylayout(M.layout, t)) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 7eeae11d161a6..9c6a587757d0a 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -6,14 +6,14 @@ matprod(x, y) = x*y + x*y # Dot products -_vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractArray{T}, y::AbstractArray{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractArray{T}, ::AbstractStridedLayout, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) +_vecdot(x::AbstractArray{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) _vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractMatrix{T}, y::AbstractMatrix{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractMatrix{T}, ::AbstractStridedLayout, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractMatrix{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractArray{T}, y::AbstractArray{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractVector{T}, y::AbstractArray{T}, ::AbstractStridedLayout, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) +_vecdot(x::AbstractArray{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) _vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) _dotu(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotu(x, y) diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index 59e53a9124dac..2594f174fabbc 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -256,18 +256,16 @@ struct HermitianLayout{ML<:MemoryLayout} <: MemoryLayout end HermitianLayout(layout::ML, uplo) where ML<:MemoryLayout = HermitianLayout{ML}(layout, uplo) -MemoryLayout(A::Hermitian) = hermitianmemorylayout(eltype(A), MemoryLayout(parent(A)), A.uplo) -MemoryLayout(A::Symmetric) = symmetricmemorylayout(MemoryLayout(parent(A)), A.uplo) -hermitianmemorylayout(_1, _2, _3) = UnknownLayout() -hermitianmemorylayout(::Type{<:Complex}, layout::AbstractColumnMajor, uplo) = HermitianLayout(layout,uplo) -hermitianmemorylayout(::Type{<:Real}, layout::AbstractColumnMajor, uplo) = SymmetricLayout(layout,uplo) -hermitianmemorylayout(::Type{<:Complex}, layout::AbstractRowMajor, uplo) = HermitianLayout(layout,uplo) -hermitianmemorylayout(::Type{<:Real}, layout::AbstractRowMajor, uplo) = SymmetricLayout(layout,uplo) -symmetricmemorylayout(_1, _2) = UnknownLayout() -symmetricmemorylayout(layout::AbstractColumnMajor, uplo) = SymmetricLayout(layout,uplo) -symmetricmemorylayout(layout::AbstractRowMajor, uplo) = SymmetricLayout(layout,uplo) -symmetricmemorylayout(layout::ConjLayout{<:AbstractColumnMajor}, uplo) = SymmetricLayout(layout,uplo) -symmetricmemorylayout(layout::ConjLayout{<:AbstractRowMajor}, uplo) = SymmetricLayout(layout,uplo) +MemoryLayout(A::Hermitian) = hermitianlayout(eltype(A), MemoryLayout(parent(A)), A.uplo) +MemoryLayout(A::Symmetric) = symmetriclayout(MemoryLayout(parent(A)), A.uplo) +hermitianlayout(_1, _2, _3) = UnknownLayout() +hermitianlayout(::Type{<:Complex}, layout::AbstractColumnMajor, uplo) = HermitianLayout(layout,uplo) +hermitianlayout(::Type{<:Real}, layout::AbstractColumnMajor, uplo) = SymmetricLayout(layout,uplo) +hermitianlayout(::Type{<:Complex}, layout::AbstractRowMajor, uplo) = HermitianLayout(layout,uplo) +hermitianlayout(::Type{<:Real}, layout::AbstractRowMajor, uplo) = SymmetricLayout(layout,uplo) +symmetriclayout(_1, _2) = UnknownLayout() +symmetriclayout(layout::AbstractColumnMajor, uplo) = SymmetricLayout(layout,uplo) +symmetriclayout(layout::AbstractRowMajor, uplo) = SymmetricLayout(layout,uplo) transposelayout(S::SymmetricLayout) = S adjointlayout(::Type{T}, S::HermitianLayout) where T = S diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 7eee65939a14d..8dad4c2908265 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -418,12 +418,12 @@ equivalent to a `UpperTriangularLayout(B)` where `B` satisfies `MemoryLayout(B) UnitUpperTriangularLayout -MemoryLayout(A::UpperTriangular) = trilayout(UpperTriangularLayout, MemoryLayout(parent(A))) -MemoryLayout(A::UnitUpperTriangular) = trilayout(UnitUpperTriangularLayout, MemoryLayout(parent(A))) -MemoryLayout(A::LowerTriangular) = trilayout(LowerTriangularLayout, MemoryLayout(parent(A))) -MemoryLayout(A::UnitLowerTriangular) = trilayout(UnitLowerTriangularLayout, MemoryLayout(parent(A))) -trilayout(_, ::MemoryLayout) = UnknownLayout() -trilayout(::Type{Tri}, ML::AbstractColumnMajor) where {Tri} = Tri(ML) +MemoryLayout(A::UpperTriangular) = triangularlayout(UpperTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::UnitUpperTriangular) = triangularlayout(UnitUpperTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::LowerTriangular) = triangularlayout(LowerTriangularLayout, MemoryLayout(parent(A))) +MemoryLayout(A::UnitLowerTriangular) = triangularlayout(UnitLowerTriangularLayout, MemoryLayout(parent(A))) +triangularlayout(_, ::MemoryLayout) = UnknownLayout() +triangularlayout(::Type{Tri}, ML::AbstractColumnMajor) where {Tri} = Tri(ML) for (TriLayout, TriLayoutTrans) in ((UpperTriangularLayout, LowerTriangularLayout), (UnitUpperTriangularLayout, UnitLowerTriangularLayout), diff --git a/stdlib/LinearAlgebra/test/matmul.jl b/stdlib/LinearAlgebra/test/matmul.jl index ce3dc20c2bcae..1e76ee56a6854 100644 --- a/stdlib/LinearAlgebra/test/matmul.jl +++ b/stdlib/LinearAlgebra/test/matmul.jl @@ -250,6 +250,11 @@ vecdot_(x,y) = invoke(vecdot, Tuple{Any,Any}, x,y) end end +@testset "array vecdot" begin + a = rand(3,3,3) + @test vecdot(a,a) === vecdot(vec(a), a) === vecdot(a, vec(a)) === dot(vec(a), vec(a)) === BLAS.dot(a,a) +end + @testset "Issue 11978" begin A = Matrix{Matrix{Float64}}(uninitialized, 2, 2) A[1,1] = Matrix(1.0I, 3, 3) diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index 19bd8014dc6be..e188a856a40fd 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -504,7 +504,7 @@ end @test Base.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor(),'U') @test Base.MemoryLayout(Transpose(Symmetric(B))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') @test Base.MemoryLayout(Transpose(Hermitian(B))) == Base.UnknownLayout() - @test Base.MemoryLayout(Adjoint(Symmetric(B))) == LinearAlgebra.SymmetricLayout(LinearAlgebra.ConjLayout(Base.DenseColumnMajor()),'U') + @test Base.MemoryLayout(Adjoint(Symmetric(B))) == Base.UnknownLayout() @test Base.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor(),'U') @test Base.MemoryLayout(Symmetric(B')) == Base.UnknownLayout() @test Base.MemoryLayout(Hermitian(B')) == Base.UnknownLayout() From dfcc856a4d837013c3974f9af61d2445b61d4674 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Thu, 1 Mar 2018 09:10:28 +0000 Subject: [PATCH 27/39] Fix vecdot ambiguity --- stdlib/LinearAlgebra/src/matmul.jl | 32 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 9c6a587757d0a..d75496bac29a4 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -6,17 +6,27 @@ matprod(x, y) = x*y + x*y # Dot products -_vecdot(x::AbstractArray{T}, y::AbstractArray{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractArray{T}, ::AbstractStridedLayout, ::DenseColumnMajor) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractArray{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasReal} = BLAS.dot(x, y) - -_vecdot(x::AbstractArray{T}, y::AbstractArray{T}, ::DenseColumnMajor, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractArray{T}, ::AbstractStridedLayout, ::DenseColumnMajor) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractArray{T}, y::AbstractVector{T}, ::DenseColumnMajor, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) -_vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotc(x, y) - -_dotu(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotu(x, y) +for (typ, bdot) in ((:BlasReal, :(BLAS.dot)), (:BlasComplex, :(BLAS.dotc))) + @eval begin + _vecdot(x::AbstractArray{T}, y::AbstractArray{T}, + ::DenseColumnMajor, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) + _vecdot(x::AbstractVector{T}, y::AbstractVector{T}, + ::DenseColumnMajor, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) + _vecdot(x::AbstractVector{T}, y::AbstractArray{T}, + ::DenseColumnMajor, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) + _vecdot(x::AbstractArray{T}, y::AbstractVector{T}, + ::DenseColumnMajor, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) + _vecdot(x::AbstractVector{T}, y::AbstractArray{T}, + ::AbstractStridedLayout, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) + _vecdot(x::AbstractArray{T}, y::AbstractVector{T}, + ::DenseColumnMajor, ::AbstractStridedLayout) where T<:$typ = $bdot(x, y) + _vecdot(x::AbstractVector{T}, y::AbstractVector{T}, + ::AbstractStridedLayout, ::AbstractStridedLayout) where T<:$typ = $bdot(x, y) + end + end + +_dotu(x::AbstractVector{T}, y::AbstractVector{T}, + ::AbstractStridedLayout, ::AbstractStridedLayout) where {T<:BlasComplex} = BLAS.dotu(x, y) function dot(x::Vector{T}, rx::Union{UnitRange{TI},AbstractRange{TI}}, y::Vector{T}, ry::Union{UnitRange{TI},AbstractRange{TI}}) where {T<:BlasReal,TI<:Integer} From 8ad8a357167c884dd2325a7818fd3606ece1fb8a Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Thu, 1 Mar 2018 13:42:03 +0000 Subject: [PATCH 28/39] submemorylayout -> subarraylayout, MemoryLayout(::DenseArray) restored based on new definition. --- base/abstractarray.jl | 3 +-- base/subarray.jl | 28 +++++++++++------------ stdlib/LinearAlgebra/src/adjtrans.jl | 2 +- stdlib/SharedArrays/src/SharedArrays.jl | 1 - test/abstractarray.jl | 30 ++++++++++++++++++++++++- 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 1b9bb5a54176a..d92baa5b49f2e 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -378,8 +378,7 @@ overrides of `strides(A::MyMatrix)` and `unknown_convert(::Type{Ptr{T}}, A::MyMa """ MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout() -MemoryLayout(A::Vector{T}) where T = DenseColumnMajor() -MemoryLayout(A::Matrix{T}) where T = DenseColumnMajor() +MemoryLayout(A::DenseArray{T}) where T = DenseColumnMajor() diff --git a/base/subarray.jl b/base/subarray.jl index c71e3003da5c2..c58b1a7186eaf 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -317,31 +317,31 @@ 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) = submemorylayout(MemoryLayout(parent(A)), parentindices(A)) -submemorylayout(::MemoryLayout, _)= UnknownLayout() -submemorylayout(::AbstractColumnMajor, ::Tuple{I}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = +MemoryLayout(A::SubArray) = subarraylayout(MemoryLayout(parent(A)), parentindices(A)) +subarraylayout(::MemoryLayout, _)= UnknownLayout() +subarraylayout(::AbstractColumnMajor, ::Tuple{I}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = DenseColumnMajor() -submemorylayout(::AbstractStridedLayout, ::Tuple{I}) where {I<:Union{RangeIndex,AbstractCartesianIndex}} = +subarraylayout(::AbstractStridedLayout, ::Tuple{I}) where {I<:Union{RangeIndex,AbstractCartesianIndex}} = StridedLayout() -submemorylayout(::AbstractColumnMajor, ::Tuple{I,Int}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = +subarraylayout(::AbstractColumnMajor, ::Tuple{I,Int}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = DenseColumnMajor() -submemorylayout(::AbstractColumnMajor, ::Tuple{I,Int}) where {I<:Slice} = +subarraylayout(::AbstractColumnMajor, ::Tuple{I,Int}) where {I<:Slice} = DenseColumnMajor() -submemorylayout(::AbstractRowMajor, ::Tuple{Int,I}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = +subarraylayout(::AbstractRowMajor, ::Tuple{Int,I}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = DenseColumnMajor() -submemorylayout(::AbstractRowMajor, ::Tuple{Int,I}) where {I<:Slice} = +subarraylayout(::AbstractRowMajor, ::Tuple{Int,I}) where {I<:Slice} = DenseColumnMajor() -submemorylayout(::DenseColumnMajor, ::Tuple{I1,I2}) where {I1<:Slice,I2<:AbstractUnitRange{Int}} = +subarraylayout(::DenseColumnMajor, ::Tuple{I1,I2}) where {I1<:Slice,I2<:AbstractUnitRange{Int}} = DenseColumnMajor() -submemorylayout(::DenseColumnMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = +subarraylayout(::DenseColumnMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = ColumnMajor() -submemorylayout(::AbstractColumnMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = +subarraylayout(::AbstractColumnMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = ColumnMajor() -submemorylayout(::AbstractRowMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:Slice} = +subarraylayout(::AbstractRowMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:Slice} = DenseRowMajor() -submemorylayout(::AbstractRowMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = +subarraylayout(::AbstractRowMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = RowMajor() -submemorylayout(::AbstractStridedLayout, ::Tuple{I1,I2}) where {I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = +subarraylayout(::AbstractStridedLayout, ::Tuple{I1,I2}) where {I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = StridedLayout() unsafe_convert(::Type{Ptr{T}}, V::SubArray{T,N,P,<:Tuple{Vararg{RangeIndex}}}) where {T,N,P} = diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index ac37fcce4f401..ee35c090adaa1 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -141,7 +141,7 @@ conjlayout(::Type{<:Complex}, M::AbstractStridedLayout) = ConjLayout(M) conjlayout(::Type{<:Real}, M::MemoryLayout) = M -Base.submemorylayout(M::ConjLayout, t::Tuple) = ConjLayout(Base.submemorylayout(M.layout, t)) +Base.subarraylayout(M::ConjLayout, t::Tuple) = ConjLayout(Base.subarraylayout(M.layout, t)) MemoryLayout(A::Transpose) = transposelayout(MemoryLayout(parent(A))) MemoryLayout(A::Adjoint) = adjointlayout(eltype(A), MemoryLayout(parent(A))) diff --git a/stdlib/SharedArrays/src/SharedArrays.jl b/stdlib/SharedArrays/src/SharedArrays.jl index 3baac67a6845f..23cd3e7804030 100644 --- a/stdlib/SharedArrays/src/SharedArrays.jl +++ b/stdlib/SharedArrays/src/SharedArrays.jl @@ -343,7 +343,6 @@ for each worker process. """ localindices(S::SharedArray) = S.pidx > 0 ? range_1dim(S, S.pidx) : 1:0 -Base.MemoryLayout(S::SharedArray) = Base.MemoryLayout(sdata(S)) strides(S::SharedArray) = strides(sdata(S)) stride(S::SharedArray, i::Int) = stride(sdata(S), i) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index fbd7e6eb6ebcb..5947ba8597740 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -883,6 +883,8 @@ end @test [(1:3) (4:6); fill(1, (3,2))] == reshape([1,2,3,1,1,1,4,5,6,1,1,1], 6,2) end +struct MyDenseArray{T,N} <: DenseArray{T,N} end + @testset "MemoryLayout for Array, SubArray, and ReinterpretArray" begin let A = [1.0 2; 3 4] @test Base.MemoryLayout(A) == Base.DenseColumnMajor() @@ -904,7 +906,33 @@ end @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,1),(1,2),())) == Base.DenseColumnMajor() @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == Base.DenseColumnMajor() + end - Base.MemoryLayout(BitArray([true,true,false])) == Base.UnknownLayout() + # TODO: implement subarraylayout for arbitrary dimensions + let A = randn(3,3,3) + @test Base.MemoryLayout(A) == Base.DenseColumnMajor() + # @test Base.MemoryLayout(view(A,:,:,:)) == Base.DenseColumnMajor() + # @test Base.MemoryLayout(view(A,:)) == Base.DenseColumnMajor() + # @test Base.MemoryLayout(view(A,:,:,1)) == Base.DenseColumnMajor() + # @test Base.MemoryLayout(view(A,:,:,1:1)) == Base.DenseColumnMajor() + # @test Base.MemoryLayout(view(A,1:1,1,1)) == Base.DenseColumnMajor() + # @test Base.MemoryLayout(view(A,1,1:1,1:1)) == Base.StridedLayout() + # @test Base.MemoryLayout(view(A,1,:,:)) == Base.StridedLayout() + # @test Base.MemoryLayout(view(A,1:1,1:2,1:2)) == Base.ColumnMajor() + # @test Base.MemoryLayout(view(A,1:1,:,:)) == Base.ColumnMajor() + # @test Base.MemoryLayout(view(A,1:2:1,1:2:1,1:2:1)) == Base.StridedLayout() + # @test Base.MemoryLayout(view(A,1:2:1,:,:)) == Base.StridedLayout() + # @test Base.MemoryLayout(view(A,[1,2],:,:)) == Base.UnknownLayout() + # + # @test Base.MemoryLayout(Base.ReshapedArray(A,(3^3,),())) == Base.DenseColumnMajor() + # @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,:,:),(3^3,),())) == Base.DenseColumnMajor() + # @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,1,1),(1,3),())) == Base.DenseColumnMajor() + # + # @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == Base.DenseColumnMajor() end + + @test Base.MemoryLayout(MyDenseArray{Float64,1}()) == Base.DenseColumnMajor() + @test Base.MemoryLayout(MyDenseArray{Float64,3}()) == Base.DenseColumnMajor() + + @test Base.MemoryLayout(BitArray([true,true,false])) == Base.UnknownLayout() end From 5d55e482b910a5768df9f8c9cc26905629118668 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Thu, 1 Mar 2018 15:52:20 +0000 Subject: [PATCH 29/39] first attempt at arbitrary d --- base/subarray.jl | 61 +++++++++++++++++++++++++++---------------- test/abstractarray.jl | 36 ++++++++++++------------- 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/base/subarray.jl b/base/subarray.jl index c58b1a7186eaf..03738e41e4ec9 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -318,30 +318,47 @@ 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(::MemoryLayout, _)= UnknownLayout() -subarraylayout(::AbstractColumnMajor, ::Tuple{I}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = +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(::AbstractColumnMajor, inds::Tuple{I,Vararg{Int}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} = + DenseColumnMajor() # A[1,2,:] is a DenseColumnMajor vector +_column_subarraylayout1(par, inds) = _column_subarraylayout(par, DenseColumnMajor(), inds) +_column_subarraylayout(_, ret, ::Tuple{}) = ret +_column_subarraylayout(_, 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() -subarraylayout(::AbstractStridedLayout, ::Tuple{I}) where {I<:Union{RangeIndex,AbstractCartesianIndex}} = - StridedLayout() -subarraylayout(::AbstractColumnMajor, ::Tuple{I,Int}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseColumnMajor() -subarraylayout(::AbstractColumnMajor, ::Tuple{I,Int}) where {I<:Slice} = - DenseColumnMajor() -subarraylayout(::AbstractRowMajor, ::Tuple{Int,I}) where {I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = - DenseColumnMajor() -subarraylayout(::AbstractRowMajor, ::Tuple{Int,I}) where {I<:Slice} = - DenseColumnMajor() -subarraylayout(::DenseColumnMajor, ::Tuple{I1,I2}) where {I1<:Slice,I2<:AbstractUnitRange{Int}} = - DenseColumnMajor() -subarraylayout(::DenseColumnMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - ColumnMajor() -subarraylayout(::AbstractColumnMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - ColumnMajor() -subarraylayout(::AbstractRowMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:Slice} = +_column_subarraylayout(par::DenseColumnMajor, ::DenseColumnMajor, inds::Tuple{I, Vararg{Any}}) where I<:Slice = + _column_subarraylayout(par, DenseColumnMajor(), tail(inds)) +_column_subarraylayout(par::AbstractColumnMajor, ::AbstractColumnMajor, inds::Tuple{I, Vararg{Any}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} = + _column_subarraylayout(par, ColumnMajor(), tail(inds)) +_column_subarraylayout(par::AbstractColumnMajor, ::AbstractStridedLayout, inds::Tuple{I, Vararg{Any}}) where I<:Union{RangeIndex,AbstractCartesianIndex} = + _column_subarraylayout(par, StridedLayout(), tail(inds)) +_row_subarraylayout1(::AbstractRowMajor, inds::Tuple{I,Vararg{Int}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} = + DenseColumnMajor() # A[1,2,:] is a DenseColumnMajor vector +_row_subarraylayout1(par, inds) = _row_subarraylayout(par, DenseRowMajor(), inds) +_row_subarraylayout(_, ret, ::Tuple{}) = ret +_row_subarraylayout(_, ret, ::Tuple{I}) where I = UnknownLayout() +_row_subarraylayout(::AbstractRowMajor, ::DenseRowMajor, inds::Tuple{I,Vararg{Int}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} = + DenseRowMajor() +_row_subarraylayout(par::DenseRowMajor, ::DenseRowMajor, inds::Tuple{I, Vararg{Int}}) where I<:Slice = DenseRowMajor() -subarraylayout(::AbstractRowMajor, ::Tuple{I1,I2}) where {I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = - RowMajor() -subarraylayout(::AbstractStridedLayout, ::Tuple{I1,I2}) where {I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = +_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(_1, _2) = UnknownLayout() +_strided_subarraylayout(ml::AbstractStridedLayout, inds::Tuple{Vararg{I}}) where I<:Union{RangeIndex,AbstractCartesianIndex} = StridedLayout() unsafe_convert(::Type{Ptr{T}}, V::SubArray{T,N,P,<:Tuple{Vararg{RangeIndex}}}) where {T,N,P} = diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 5947ba8597740..53b635ad23418 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -911,24 +911,24 @@ struct MyDenseArray{T,N} <: DenseArray{T,N} end # TODO: implement subarraylayout for arbitrary dimensions let A = randn(3,3,3) @test Base.MemoryLayout(A) == Base.DenseColumnMajor() - # @test Base.MemoryLayout(view(A,:,:,:)) == Base.DenseColumnMajor() - # @test Base.MemoryLayout(view(A,:)) == Base.DenseColumnMajor() - # @test Base.MemoryLayout(view(A,:,:,1)) == Base.DenseColumnMajor() - # @test Base.MemoryLayout(view(A,:,:,1:1)) == Base.DenseColumnMajor() - # @test Base.MemoryLayout(view(A,1:1,1,1)) == Base.DenseColumnMajor() - # @test Base.MemoryLayout(view(A,1,1:1,1:1)) == Base.StridedLayout() - # @test Base.MemoryLayout(view(A,1,:,:)) == Base.StridedLayout() - # @test Base.MemoryLayout(view(A,1:1,1:2,1:2)) == Base.ColumnMajor() - # @test Base.MemoryLayout(view(A,1:1,:,:)) == Base.ColumnMajor() - # @test Base.MemoryLayout(view(A,1:2:1,1:2:1,1:2:1)) == Base.StridedLayout() - # @test Base.MemoryLayout(view(A,1:2:1,:,:)) == Base.StridedLayout() - # @test Base.MemoryLayout(view(A,[1,2],:,:)) == Base.UnknownLayout() - # - # @test Base.MemoryLayout(Base.ReshapedArray(A,(3^3,),())) == Base.DenseColumnMajor() - # @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,:,:),(3^3,),())) == Base.DenseColumnMajor() - # @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,1,1),(1,3),())) == Base.DenseColumnMajor() - # - # @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,:,:,:)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,:)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,:,:,1)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,:,:,1:1)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1:1,1,1)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1,1:1,1:1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1,:,:)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1:1,1:2,1:2)) == Base.ColumnMajor() + @test Base.MemoryLayout(view(A,1:1,:,:)) == Base.ColumnMajor() + @test Base.MemoryLayout(view(A,1:2:1,1:2:1,1:2:1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1:2:1,:,:)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,[1,2],:,:)) == Base.UnknownLayout() + + @test Base.MemoryLayout(Base.ReshapedArray(A,(3^3,),())) == Base.DenseColumnMajor() + @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,:,:),(3^3,),())) == Base.DenseColumnMajor() + @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,1,1),(1,3),())) == Base.DenseColumnMajor() + + @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == Base.DenseColumnMajor() end @test Base.MemoryLayout(MyDenseArray{Float64,1}()) == Base.DenseColumnMajor() From 74c7f673a2100d32b615eea92f5f2d43e926788d Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Thu, 1 Mar 2018 22:43:16 +0000 Subject: [PATCH 30/39] subarraylayout now works with arb d --- base/subarray.jl | 62 +++++++++++++++++++++++++++++++------------ test/abstractarray.jl | 5 ++-- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/base/subarray.jl b/base/subarray.jl index 03738e41e4ec9..de4000b90f693 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -327,28 +327,54 @@ 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(::AbstractColumnMajor, inds::Tuple{I,Vararg{Int}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} = - DenseColumnMajor() # A[1,2,:] is a DenseColumnMajor vector -_column_subarraylayout1(par, inds) = _column_subarraylayout(par, DenseColumnMajor(), inds) -_column_subarraylayout(_, ret, ::Tuple{}) = ret -_column_subarraylayout(_, ret, ::Tuple{I}) where I = UnknownLayout() + +_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, 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<: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, ::AbstractColumnMajor, inds::Tuple{I, Vararg{Any}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} = +_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::AbstractColumnMajor, ::AbstractStridedLayout, inds::Tuple{I, Vararg{Any}}) where I<:Union{RangeIndex,AbstractCartesianIndex} = +_column_subarraylayout(par, ::AbstractStridedLayout, inds::Tuple{I, Vararg{Any}}) where I<:Union{RangeIndex,AbstractCartesianIndex} = _column_subarraylayout(par, StridedLayout(), tail(inds)) -_row_subarraylayout1(::AbstractRowMajor, inds::Tuple{I,Vararg{Int}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} = - DenseColumnMajor() # A[1,2,:] is a DenseColumnMajor vector -_row_subarraylayout1(par, inds) = _row_subarraylayout(par, DenseRowMajor(), inds) -_row_subarraylayout(_, ret, ::Tuple{}) = ret -_row_subarraylayout(_, ret, ::Tuple{I}) where I = UnknownLayout() -_row_subarraylayout(::AbstractRowMajor, ::DenseRowMajor, inds::Tuple{I,Vararg{Int}}) where I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex} = - DenseRowMajor() + +_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 = @@ -357,9 +383,11 @@ _row_subarraylayout(par::AbstractRowMajor, ::AbstractRowMajor, inds::Tuple{I, Va _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(_1, _2) = UnknownLayout() -_strided_subarraylayout(ml::AbstractStridedLayout, inds::Tuple{Vararg{I}}) where I<:Union{RangeIndex,AbstractCartesianIndex} = - StridedLayout() + +_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) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 53b635ad23418..3833ff7fc5984 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -893,6 +893,7 @@ struct MyDenseArray{T,N} <: DenseArray{T,N} end @test Base.MemoryLayout(view(A,:,1)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,:,1:1)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,1:1,1)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1,2)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,1,1:1)) == Base.StridedLayout() @test Base.MemoryLayout(view(A,1,:)) == Base.StridedLayout() @test Base.MemoryLayout(view(A,1:1,1:2)) == Base.ColumnMajor() @@ -908,14 +909,14 @@ struct MyDenseArray{T,N} <: DenseArray{T,N} end @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == Base.DenseColumnMajor() end - # TODO: implement subarraylayout for arbitrary dimensions - let A = randn(3,3,3) + let A = randn(2,2,2) @test Base.MemoryLayout(A) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,:,:,:)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,:)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,:,:,1)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,:,:,1:1)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,1:1,1,1)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1,2,2)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,1,1:1,1:1)) == Base.StridedLayout() @test Base.MemoryLayout(view(A,1,:,:)) == Base.StridedLayout() @test Base.MemoryLayout(view(A,1:1,1:2,1:2)) == Base.ColumnMajor() From d723b1a53a30f5b7c405ee0701df11e13f54398b Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Fri, 2 Mar 2018 07:07:42 +0000 Subject: [PATCH 31/39] more ambiguities fixed --- base/subarray.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/base/subarray.jl b/base/subarray.jl index de4000b90f693..5ebac23c4dbae 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -340,8 +340,12 @@ _column_subarraylayout1(par, inds::Tuple{I,Vararg{Int}}) where I<:AbstractUnitRa 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() From a0cd4675ebb659e86ee59f87aa4dc4513cf832b8 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Fri, 2 Mar 2018 11:14:41 +0000 Subject: [PATCH 32/39] add RowMajorArray tests, update memory layout docs for arbitrary dimensional arrays --- base/abstractarray.jl | 58 ++++++++++++++++++++++++------------------- base/subarray.jl | 2 +- test/abstractarray.jl | 50 ++++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 28 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index d92baa5b49f2e..e218d8f425d93 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -298,59 +298,68 @@ UnknownLayout AbstractStridedLayout is an abstract type whose subtypes are returned by `MemoryLayout(A)` -if a matrix or vector `A` have storage laid out at regular offsets in memory, +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 a vector or matrix `A` has storage in memory -equivalent to an `Array`, so that `stride(A,1) == 1` and `stride(A,2) == size(A,1)`. -Arrays with `DenseColumnMajor` must conform to the `DenseArray` interface. +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 a vector or matrix `A` has storage in memory -as a column major matrix. In other words, the columns are stored in memory with -offsets of one, while the rows are stored with offsets given by `stride(A,2)`. -Arrays with `ColumnMajor` must conform to the `DenseArray` interface. +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 """ DenseRowMajor() -is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory -equivalent to the transpose of an `Array`, so that `stride(A,1) == size(A,1)` and -`stride(A,2) == 1`. Arrays with `DenseRowMajor` must conform to the -`DenseArray` interface. +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 a matrix `A` has storage in memory -as a row major matrix. In other words, the rows are stored in memory with -offsets of one, while the columns are stored with offsets given by `stride(A,1)`. -Arrays with `RowMajor` must conform to the `DenseArray` interface, -and `transpose(A)` should return a matrix whose layout is `ColumnMajor()`. +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 """ StridedLayout() -is returned by `MemoryLayout(A)` if a vector or matrix `A` has storage laid out at regular -offsets in memory. In other words, the columns are stored with offsets given -by `stride(A,1)` and for matrices the rows are stored in memory with offsets -of `stride(A,2)`. `Array`s with `StridedLayout` must conform to the `DenseArray` interface. +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 @@ -362,7 +371,7 @@ StridedLayout you define a new `AbstractArray` type, you can choose to implement memory layout to indicate that an array is strided in memory. If you decide to implement memory layout, then you must set this trait for your array -type: for example, if your matrix is column major with `stride(A,2) == size(A,1)`, +type. For example, if your matrix is column major with `stride(A,2) == size(A,1)`, then override as follows: Base.MemoryLayout(::Type{M}) where M <: MyMatrix = Base.DenseColumnMajor() @@ -371,10 +380,7 @@ The default is `Base.UnknownLayout()` to indicate that the layout in memory is unknown. Julia's internal linear algebra machinery will automatically (and invisibly) -dispatch to BLAS and LAPACK routines if the memory layout is BLAS 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)`. +dispatch to BLAS and LAPACK routines if the memory layout is compatible. """ MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout() diff --git a/base/subarray.jl b/base/subarray.jl index 5ebac23c4dbae..f4c7b2f1fd513 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -386,7 +386,7 @@ _row_subarraylayout(par::DenseRowMajor, ::DenseRowMajor, inds::Tuple{I, Vararg{A _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)) + _row_subarraylayout(par, StridedLayout(), tail(inds)) _strided_subarraylayout(par, inds) = UnknownLayout() _strided_subarraylayout(par, ::Tuple{}) = StridedLayout() diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 3833ff7fc5984..a957bd124c678 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -884,9 +884,17 @@ end end struct MyDenseArray{T,N} <: DenseArray{T,N} end +struct RowMajorArray{T,N} <: AbstractArray{T,N} + A::Array{T,N} +end + +Base.getindex(A::RowMajorArray{T,N}, inds::Vararg{Int,N}) where {T,N} = A.A[reverse(inds)...] +Base.setindex!(A::RowMajorArray, v, inds::Vararg{Int,N}) where {T,N} = (A.A[reverse(inds)...] = v) +Base.MemoryLayout(::RowMajorArray) = Base.DenseRowMajor() +Base.size(A::RowMajorArray) = reverse(size(A.A)) @testset "MemoryLayout for Array, SubArray, and ReinterpretArray" begin - let A = [1.0 2; 3 4] + let A = randn(2,2) @test Base.MemoryLayout(A) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,:,:)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,:)) == Base.DenseColumnMajor() @@ -896,11 +904,15 @@ struct MyDenseArray{T,N} <: DenseArray{T,N} end @test Base.MemoryLayout(view(A,1,2)) == Base.DenseColumnMajor() @test Base.MemoryLayout(view(A,1,1:1)) == Base.StridedLayout() @test Base.MemoryLayout(view(A,1,:)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,:,1:-2:1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1:1,1:-2:1)) == Base.StridedLayout() @test Base.MemoryLayout(view(A,1:1,1:2)) == Base.ColumnMajor() @test Base.MemoryLayout(view(A,1:1,:)) == Base.ColumnMajor() @test Base.MemoryLayout(view(A,1:2:1,1:2:1)) == Base.StridedLayout() @test Base.MemoryLayout(view(A,1:2:1,:)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1:2:1,1:2)) == Base.StridedLayout() @test Base.MemoryLayout(view(A,[1,2],:)) == Base.UnknownLayout() + @test Base.MemoryLayout(view(A,:,[1,2])) == Base.UnknownLayout() @test Base.MemoryLayout(Base.ReshapedArray(A,(4,),())) == Base.DenseColumnMajor() @test Base.MemoryLayout(Base.ReshapedArray(view(A,:,:),(4,),())) == Base.DenseColumnMajor() @@ -932,6 +944,42 @@ struct MyDenseArray{T,N} <: DenseArray{T,N} end @test Base.MemoryLayout(reinterpret(ComplexF64,A)) == Base.DenseColumnMajor() end + let A = RowMajorArray(randn(2,2)) + @test Base.MemoryLayout(A) == Base.DenseRowMajor() + @test Base.MemoryLayout(view(A,:,:)) == Base.DenseRowMajor() + @test Base.MemoryLayout(view(A,:)) == Base.UnknownLayout() + @test Base.MemoryLayout(view(A,:,1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,:,1:1)) == Base.RowMajor() + @test Base.MemoryLayout(view(A,1:1,1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1,2)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1,1:1)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1,:)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1:1,1:2)) == Base.RowMajor() + @test Base.MemoryLayout(view(A,1:1,:)) == Base.DenseRowMajor() + @test Base.MemoryLayout(view(A,1:2:1,1:2:1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1:-2:1,:)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1:-2:1,1:2)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,[1,2],:)) == Base.UnknownLayout() + @test Base.MemoryLayout(view(A,:,[1,2])) == Base.UnknownLayout() + end + + let A = RowMajorArray(randn(2,2,2)) + @test Base.MemoryLayout(A) == Base.DenseRowMajor() + @test Base.MemoryLayout(view(A,:,:,:)) == Base.DenseRowMajor() + @test Base.MemoryLayout(view(A,:)) == Base.UnknownLayout() + @test Base.MemoryLayout(view(A,:,:,1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,:,:,1:1)) == Base.RowMajor() + @test Base.MemoryLayout(view(A,1:1,1,1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1,2,2)) == Base.DenseColumnMajor() + @test Base.MemoryLayout(view(A,1,1:1,1:1)) == Base.RowMajor() + @test Base.MemoryLayout(view(A,1,:,:)) == Base.DenseRowMajor() + @test Base.MemoryLayout(view(A,1:1,1:2,1:2)) == Base.RowMajor() + @test Base.MemoryLayout(view(A,1:1,:,:)) == Base.DenseRowMajor() + @test Base.MemoryLayout(view(A,1:2:1,1:2:1,1:2:1)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,1:2:1,:,:)) == Base.StridedLayout() + @test Base.MemoryLayout(view(A,[1,2],:,:)) == Base.UnknownLayout() + end + @test Base.MemoryLayout(MyDenseArray{Float64,1}()) == Base.DenseColumnMajor() @test Base.MemoryLayout(MyDenseArray{Float64,3}()) == Base.DenseColumnMajor() From 681f73b272af5bece1c69991bc2eb572a17a2a50 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Fri, 2 Mar 2018 17:50:59 +0000 Subject: [PATCH 33/39] Add _mul(A, B, memlayA, memlayB) to simplify * overloads convert(AbstractArray{T}, ::Adjoint) now returns an Adjoint (and also Transpose) SymmetricLayout expanded on, supports view(Symmetric(A), :, :) *TriangularLayout expanded on --- stdlib/LinearAlgebra/src/adjtrans.jl | 9 + stdlib/LinearAlgebra/src/matmul.jl | 12 +- stdlib/LinearAlgebra/src/symmetric.jl | 55 ++++- stdlib/LinearAlgebra/src/triangular.jl | 317 +++++++++++-------------- stdlib/LinearAlgebra/test/symmetric.jl | 51 +++- 5 files changed, 252 insertions(+), 192 deletions(-) diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index ee35c090adaa1..cd3945db12f5c 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -170,6 +170,15 @@ strides(A::AdjOrTrans) = (stride(parent(A),2), stride(parent(A),1)) # conversion of underlying storage convert(::Type{Adjoint{T,S}}, A::Adjoint) where {T,S} = Adjoint{T,S}(convert(S, A.parent)) convert(::Type{Transpose{T,S}}, A::Transpose) where {T,S} = Transpose{T,S}(convert(S, A.parent)) +convert(::Type{AbstractArray{T}}, A::Transpose{T}) where {T} = A +convert(::Type{AbstractArray{T}}, A::Adjoint{T}) where {T} = A +convert(::Type{AbstractMatrix{T}}, A::Transpose{T}) where {T} = A +convert(::Type{AbstractMatrix{T}}, A::Adjoint{T}) where {T} = A +convert(::Type{AbstractArray{T}}, A::Adjoint) where {T} = Adjoint(convert(AbstractArray{T}, A.parent)) +convert(::Type{AbstractArray{T}}, A::Transpose) where {T} = Transpose(convert(AbstractArray{T}, A.parent)) +convert(::Type{AbstractMatrix{T}}, A::Adjoint) where {T} = Adjoint(convert(AbstractArray{T}, A.parent)) +convert(::Type{AbstractMatrix{T}}, A::Transpose) where {T} = Transpose(convert(AbstractArray{T}, A.parent)) + # for vectors, the semantics of the wrapped and unwrapped types differ # so attempt to maintain both the parent and wrapper type insofar as possible diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index d75496bac29a4..5ec6527771c46 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -56,11 +56,13 @@ function dot(x::Vector{T}, rx::Union{UnitRange{TI},AbstractRange{TI}}, y::Vector end # Matrix-vector multiplication -function (*)(A::StridedMatrix{T}, x::StridedVector{S}) where {T<:BlasFloat,S} +(*)(A::AbstractVecOrMat, B::AbstractVecOrMat) = _mul(A, B, MemoryLayout(A), MemoryLayout(B)) + +function _mul(A::AbstractMatrix{T}, x::AbstractVector{S}, ::StridedLayout, ::StridedLayout) where {T<:BlasFloat,S} TS = promote_op(matprod, T, S) mul!(similar(x, TS, size(A,1)), A, convert(AbstractVector{TS}, x)) end -function (*)(A::AbstractMatrix{T}, x::AbstractVector{S}) where {T,S} +function _mul(A::AbstractMatrix{T}, x::AbstractVector{S}, _1, _2) where {T,S} TS = promote_op(matprod, T, S) mul!(similar(x,TS,size(A,1)), A, x) end @@ -110,7 +112,7 @@ _mul!(y::AbstractVector{T}, adjA::AbstractMatrix{T}, x::AbstractVector{T}, ::Abs # Vector-matrix multiplication -(*)(a::AbstractVector, B::AbstractMatrix) = reshape(a,length(a),1)*B +_mul(a::AbstractVector, B::AbstractMatrix, _1, _2) = reshape(a,length(a),1)*B # these enable treating vectors as n x 1 matrices for important use-cases mul!(y::AbstractMatrix, a::AbstractVector, B::AbstractMatrix) = mul!(y, reshape(a,length(a),1), B) @@ -131,7 +133,9 @@ julia> [1 1; 0 1] * [1 0; 1 1] 1 1 ``` """ -function (*)(A::AbstractMatrix, B::AbstractMatrix) +*(::AbstractMatrix, ::AbstractMatrix) + +function _mul(A::AbstractMatrix, B::AbstractMatrix, _1, _2) TS = promote_op(matprod, eltype(A), eltype(B)) mul!(similar(B, TS, (size(A,1), size(B,2))), A, B) end diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index 2594f174fabbc..3f88db4250cc2 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -237,6 +237,9 @@ end Array(A::Union{Symmetric,Hermitian}) = convert(Matrix, A) parent(A::HermOrSym) = A.data +symmetricdata(A::Symmetric) = A.data +symmetricdata(A::Hermitian{<:Real}) = A.data +hermitiandata(A::Hermitian) = A.data Symmetric{T,S}(A::Symmetric{T,S}) where {T,S<:AbstractMatrix} = A Symmetric{T,S}(A::Symmetric) where {T,S<:AbstractMatrix} = Symmetric{T,S}(convert(S,A.data),A.uplo) AbstractMatrix{T}(A::Symmetric) where {T} = Symmetric(convert(AbstractMatrix{T}, A.data), Symbol(A.uplo)) @@ -245,11 +248,38 @@ Hermitian{T,S}(A::Hermitian) where {T,S<:AbstractMatrix} = Hermitian{T,S}(conver AbstractMatrix{T}(A::Hermitian) where {T} = Hermitian(convert(AbstractMatrix{T}, A.data), Symbol(A.uplo)) # MemoryLayout of Symmetric/Hermitian +""" + SymmetricLayout(layout, uplo) + + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +as a symmetrized version of `layout`, where the entries used are dictated by the +`uplo`, which can be `'U'` or `L'`. + +A matrix that has memory layout `SymmetricLayout(layout, uplo)` must overrided +`symmetricdata(A)` to return a matrix `B` such that `MemoryLayout(B) == layout` and +`A[k,j] == B[k,j]` for `j ≥ k` if `uplo == 'U'` (`j ≤ k` if `uplo == 'L'`) and +`A[k,j] == B[j,k]` for `j < k` if `uplo == 'U'` (`j > k` if `uplo == 'L'`). +""" struct SymmetricLayout{ML<:MemoryLayout} <: MemoryLayout layout::ML uplo::Char end SymmetricLayout(layout::ML, uplo) where ML<:MemoryLayout = SymmetricLayout{ML}(layout, uplo) + +""" + HermitianLayout(layout, uplo) + + +is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory +as a hermitianized version of `layout`, where the entries used are dictated by the +`uplo`, which can be `'U'` or `L'`. + +A matrix that has memory layout `HermitianLayout(layout, uplo)` must overrided +`hermitiandata(A)` to return a matrix `B` such that `MemoryLayout(B) == layout` and +`A[k,j] == B[k,j]` for `j ≥ k` if `uplo == 'U'` (`j ≤ k` if `uplo == 'L'`) and +`A[k,j] == conj(B[j,k])` for `j < k` if `uplo == 'U'` (`j > k` if `uplo == 'L'`). +""" struct HermitianLayout{ML<:MemoryLayout} <: MemoryLayout layout::ML uplo::Char @@ -267,7 +297,16 @@ symmetriclayout(_1, _2) = UnknownLayout() symmetriclayout(layout::AbstractColumnMajor, uplo) = SymmetricLayout(layout,uplo) symmetriclayout(layout::AbstractRowMajor, uplo) = SymmetricLayout(layout,uplo) transposelayout(S::SymmetricLayout) = S +adjointlayout(::Type{T}, S::SymmetricLayout) where T<:Real = S adjointlayout(::Type{T}, S::HermitianLayout) where T = S +Base.subarraylayout(S::SymmetricLayout, ::Tuple{<:Slice,<:Slice}) = S +Base.subarraylayout(S::HermitianLayout, ::Tuple{<:Slice,<:Slice}) = S +symmetricdata(V::SubArray{<:Any, 2, <:Any, <:Tuple{<:Slice,<:Slice}}) = symmetricdata(parent(V)) +symmetricdata(V::Adjoint{<:Real}) = symmetricdata(parent(V)) +symmetricdata(V::Transpose) = symmetricdata(parent(V)) +hermitiandata(V::SubArray{<:Any, 2, <:Any, <:Tuple{<:Slice,<:Slice}}) = hermitiandata(parent(V)) +hermitiandata(V::Adjoint) = hermitiandata(parent(V)) +hermitiandata(V::Transpose{<:Real}) = hermitiandata(parent(V)) copy(A::Symmetric{T,S}) where {T,S} = (B = copy(A.data); Symmetric{T,typeof(B)}(B,A.uplo)) copy(A::Hermitian{T,S}) where {T,S} = (B = copy(A.data); Hermitian{T,typeof(B)}(B,A.uplo)) @@ -408,30 +447,30 @@ end ## Matrix-vector product _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, AL::SymmetricLayout{<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = - BLAS.symv!(AL.uplo, one(T), parent(A), x, zero(T), y) + BLAS.symv!(AL.uplo, one(T), symmetricdata(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, AL::SymmetricLayout{<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = - BLAS.symv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(parent(A)), x, zero(T), y) + BLAS.symv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(symmetricdata(A)), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, AL::HermitianLayout{<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = - BLAS.hemv!(AL.uplo, one(T), parent(A), x, zero(T), y) + BLAS.hemv!(AL.uplo, one(T), hermitiandata(A), x, zero(T), y) _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, x::AbstractVector{T}, ::AbstractStridedLayout, AL::HermitianLayout{<:AbstractRowMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = - BLAS.hemv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(parent(A)), x, zero(T), y) + BLAS.hemv!(ifelse(AL.uplo == 'L', 'U', 'L'), one(T), transpose(hermitiandata(A)), x, zero(T), y) ## Matrix-matrix product _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, AL::SymmetricLayout{<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasFloat} = - BLAS.symm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) + BLAS.symm!('L', AL.uplo, one(T), symmetricdata(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, BL::SymmetricLayout{<:AbstractColumnMajor}) where {T<:BlasFloat} = - BLAS.symm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) + BLAS.symm!('R', BL.uplo, one(T), symmetricdata(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, AL::HermitianLayout{<:AbstractColumnMajor}, ::AbstractStridedLayout) where {T<:BlasComplex} = - BLAS.hemm!('L', AL.uplo, one(T), parent(A), B, zero(T), C) + BLAS.hemm!('L', AL.uplo, one(T), hermitiandata(A), B, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::AbstractStridedLayout, BL::HermitianLayout{<:AbstractColumnMajor}) where {T<:BlasComplex} = - BLAS.hemm!('R', BL.uplo, one(T), parent(B), A, zero(T), C) + BLAS.hemm!('R', BL.uplo, one(T), hermitiandata(B), A, zero(T), C) _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::Union{HermitianLayout, SymmetricLayout}, ::Union{HermitianLayout, SymmetricLayout}) where {T<:BlasFloat} = diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 8dad4c2908265..80a41a4aa1a0c 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -100,6 +100,7 @@ imag(A::UnitUpperTriangular) = UpperTriangular(triu!(imag(A.data),1)) Array(A::AbstractTriangular) = Matrix(A) parent(A::AbstractTriangular) = A.data +triangulardata(A::AbstractTriangular) = A.data # then handle all methods that requires specific handling of upper/lower and unit diagonal @@ -364,23 +365,30 @@ diag(A::UpperTriangular) = diag(A.data) diag(A::UnitUpperTriangular) = fill(one(eltype(A)), size(A,1)) # MemoryLayout of triangular matrices +abstract type AbstractTriangularLayout{ML} <: MemoryLayout end + for memlay in (:LowerTriangularLayout, :UnitLowerTriangularLayout, :UpperTriangularLayout, :UnitUpperTriangularLayout) @eval begin - struct $memlay{ML<:MemoryLayout} <: MemoryLayout + struct $memlay{ML<:MemoryLayout} <: AbstractTriangularLayout{ML} layout::ML end end end """ - LowerTriangularLayout(ML::MemoryLayout) + LowerTriangularLayout(layout) is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory -equivalent to a `LowerTriangular(B)` where `B` satisfies `MemoryLayout(B) == ML`. +equivalent to a `LowerTriangular(B)` where `B` satisfies `MemoryLayout(B) == layout`. + +A matrix that has memory layout `LowerTriangularLayout(layout)` must overrided +`triangulardata(A)` to return a matrix `B` such that `MemoryLayout(B) == layout` and +`A[k,j] ≡ zero(eltype(A))` for `j > k` and +`A[k,j] ≡ B[k,j]` for `j ≤ k`. -`A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and -`transpose(A).data` must exist if `trans == 'T'`. +Moreover, `transpose(A)` and `adjoint(A)` must return a matrix that has memory +layout `UpperTriangularLayout`. """ LowerTriangularLayout @@ -388,10 +396,16 @@ LowerTriangularLayout UnitLowerTriangularLayout(ML::MemoryLayout) is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory -equivalent to a `UnitLowerTriangular(B)` where `B` satisfies `MemoryLayout(B) == ML`. +equivalent to a `UnitLowerTriangular(B)` where `B` satisfies `MemoryLayout(B) == layout`. + +A matrix that has memory layout `UnitLowerTriangularLayout(layout)` must overrided +`triangulardata(A)` to return a matrix `B` such that `MemoryLayout(B) == layout` and +`A[k,j] ≡ zero(eltype(A))` for `j > k`, +`A[k,j] ≡ one(eltype(A))` for `j == k`, +`A[k,j] ≡ B[k,j]` for `j < k`. -`A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and -`transpose(A).data` must exist if `trans == 'T'`. +Moreover, `transpose(A)` and `adjoint(A)` must return a matrix that has memory +layout `UnitUpperTriangularLayout`. """ UnitLowerTriangularLayout @@ -401,8 +415,13 @@ UnitLowerTriangularLayout is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory equivalent to a `UpperTriangularLayout(B)` where `B` satisfies `MemoryLayout(B) == ML`. -`A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and -`transpose(A).data` must exist if `trans == 'T'`. +A matrix that has memory layout `UpperTriangularLayout(layout)` must overrided +`triangulardata(A)` to return a matrix `B` such that `MemoryLayout(B) == layout` and +`A[k,j] ≡ B[k,j]` for `j ≥ k` and +`A[k,j] ≡ zero(eltype(A))` for `j < k`. + +Moreover, `transpose(A)` and `adjoint(A)` must return a matrix that has memory +layout `LowerTriangularLayout`. """ UpperTriangularLayout @@ -412,8 +431,14 @@ UpperTriangularLayout is returned by `MemoryLayout(A)` if a matrix `A` has storage in memory equivalent to a `UpperTriangularLayout(B)` where `B` satisfies `MemoryLayout(B) == ML`. -`A.data` must exist if `trans == 'N'`, `adjoint(A).data` must exist if `trans == 'C'`, and -`transpose(A).data` must exist if `trans == 'T'`. +A matrix that has memory layout `UnitUpperTriangularLayout(layout)` must overrided +`triangulardata(A)` to return a matrix `B` such that `MemoryLayout(B) == layout` and +`A[k,j] ≡ B[k,j]` for `j > k`, +`A[k,j] ≡ one(eltype(A))` for `j == k`, +`A[k,j] ≡ zero(eltype(A))` for `j < k`. + +Moreover, `transpose(A)` and `adjoint(A)` must return a matrix that has memory +layout `UnitLowerTriangularLayout`. """ UnitUpperTriangularLayout @@ -435,6 +460,9 @@ for (TriLayout, TriLayoutTrans) in ((UpperTriangularLayout, LowerTriangularL end end +triangulardata(A::Adjoint) = Adjoint(triangulardata(parent(A))) +triangulardata(A::Transpose) = Transpose(triangulardata(parent(A))) + # Unary operations -(A::LowerTriangular) = LowerTriangular(-A.data) -(A::UpperTriangular) = UpperTriangular(-A.data) @@ -598,11 +626,11 @@ for (t, memlay, memlaytrans, uploc, isunitc) in ((:LowerTriangular, :LowerTriang lmul!(A, copyto!(y, b)) _lmul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{DC}, ::AbstractStridedLayout) where {T<:BlasFloat,DC<:AbstractColumnMajor} = - BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) + BLAS.trmv!($uploc, 'N', $isunitc, triangulardata(A), b) _lmul!(transA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{DR}, ::AbstractStridedLayout) where {T<:BlasFloat,DR<:AbstractRowMajor} = - (A = transpose(transA); BLAS.trmv!($uploc, 'T', $isunitc, A.data, b)) + (A = transpose(transA); BLAS.trmv!($uploc, 'T', $isunitc, triangulardata(A), b)) _lmul!(adjA::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlaytrans{ConjLayout{DR}}, ::AbstractStridedLayout) where {T<:BlasComplex,DR<:AbstractRowMajor} = - (A = adjoint(adjA); BLAS.trmv!($uploc, 'C', $isunitc, A.data, b)) + (A = adjoint(adjA); BLAS.trmv!($uploc, 'C', $isunitc, triangulardata(A), b)) # Matrix multiplication _mul!(C::AbstractMatrix{T}, A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractStridedLayout, ::$memlay, ::AbstractStridedLayout) where {T<:BlasFloat} = @@ -611,14 +639,14 @@ for (t, memlay, memlaytrans, uploc, isunitc) in ((:LowerTriangular, :LowerTriang rmul!(copyto!(C, A), B) _lmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlay{DC}, ::AbstractColumnMajor) where {T<:BlasFloat,DC<:AbstractColumnMajor} = - BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B) + BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), triangulardata(A), B) _rmul!(A::AbstractMatrix{T}, B::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlay{DC}) where {T<:BlasFloat,DC<:AbstractColumnMajor} = BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) _lmul!(transA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{DR}, ::AbstractColumnMajor) where {T<:BlasFloat,DR<:AbstractRowMajor} = - (A = transpose(transA); BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B)) + (A = transpose(transA); BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), triangulardata(A), B)) _lmul!(adjA::AbstractMatrix{T}, B::AbstractMatrix{T}, ::$memlaytrans{ConjLayout{DR}}, ::AbstractColumnMajor) where {T<:BlasComplex,DR<:AbstractRowMajor} = - (A = adjoint(adjA); BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B)) + (A = adjoint(adjA); BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), triangulardata(A), B)) _rmul!(A::AbstractMatrix{T}, transB::AbstractMatrix{T}, ::AbstractColumnMajor, ::$memlaytrans{DR}) where {T<:BlasFloat,DR<:AbstractRowMajor} = (B = transpose(transB); BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) @@ -763,11 +791,12 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{ if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = 1:m - Bij = A.data[i,i]*B[i,j] + Bij = Adata[i,i]*B[i,j] for k = i + 1:m - Bij += A.data[i,k]*B[k,j] + Bij += Adata[i,k]*B[k,j] end B[i,j] = Bij end @@ -780,11 +809,12 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLay if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = 1:m Bij = B[i,j] for k = i + 1:m - Bij += A.data[i,k]*B[k,j] + Bij += Adata[i,k]*B[k,j] end B[i,j] = Bij end @@ -797,11 +827,12 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{ if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = m:-1:1 - Bij = A.data[i,i]*B[i,j] + Bij = Adata[i,i]*B[i,j] for k = 1:i - 1 - Bij += A.data[i,k]*B[k,j] + Bij += Adata[i,k]*B[k,j] end B[i,j] = Bij end @@ -813,11 +844,12 @@ function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLay if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = m:-1:1 Bij = B[i,j] for k = 1:i - 1 - Bij += A.data[i,k]*B[k,j] + Bij += Adata[i,k]*B[k,j] end B[i,j] = Bij end @@ -831,11 +863,12 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayo if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = m:-1:1 - Bij = A.data[i,i]'B[i,j] + Bij = Adata[i,i]'B[i,j] for k = 1:i - 1 - Bij += A.data[k,i]'B[k,j] + Bij += Adata[k,i]'B[k,j] end B[i,j] = Bij end @@ -844,16 +877,17 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayo end function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}, _) - A = adjA.parent + A = adjoint(adjA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = m:-1:1 Bij = B[i,j] for k = 1:i - 1 - Bij += A.data[k,i]'B[k,j] + Bij += Adata[k,i]'B[k,j] end B[i,j] = Bij end @@ -862,16 +896,17 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangular end function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}, _) - A = adjA.parent + A = adjoint(adjA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = 1:m - Bij = A.data[i,i]'B[i,j] + Bij = Adata[i,i]'B[i,j] for k = i + 1:m - Bij += A.data[k,i]'B[k,j] + Bij += Adata[k,i]'B[k,j] end B[i,j] = Bij end @@ -879,16 +914,17 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayo B end function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{<:ConjLayout{<:AbstractRowMajor}}, _) - A = adjA.parent + A = adjoint(adjA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = 1:m Bij = B[i,j] for k = i + 1:m - Bij += A.data[k,i]'B[k,j] + Bij += Adata[k,i]'B[k,j] end B[i,j] = Bij end @@ -897,16 +933,17 @@ function _lmul!(adjA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangular end function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLayout{<:AbstractRowMajor}, _) - A = transA.parent + A = transpose(transA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = m:-1:1 - Bij = transpose(A.data[i,i]) * B[i,j] + Bij = transpose(Adata[i,i]) * B[i,j] for k = 1:i - 1 - Bij += transpose(A.data[k,i]) * B[k,j] + Bij += transpose(Adata[k,i]) * B[k,j] end B[i,j] = Bij end @@ -914,16 +951,17 @@ function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::LowerTriangularLa B end function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangularLayout{<:AbstractRowMajor}, _) - A = transA.parent + A = transpose(transA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = m:-1:1 Bij = B[i,j] for k = 1:i - 1 - Bij += transpose(A.data[k,i]) * B[k,j] + Bij += transpose(Adata[k,i]) * B[k,j] end B[i,j] = Bij end @@ -932,16 +970,17 @@ function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitLowerTriangul end function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{<:AbstractRowMajor}, _) - A = transA.parent + A = transpose(transA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = 1:m - Bij = transpose(A.data[i,i]) * B[i,j] + Bij = transpose(Adata[i,i]) * B[i,j] for k = i + 1:m - Bij += transpose(A.data[k,i]) * B[k,j] + Bij += transpose(Adata[k,i]) * B[k,j] end B[i,j] = Bij end @@ -949,16 +988,17 @@ function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLa B end function _lmul!(transA::AbstractMatrix, B::AbstractVecOrMat, ::UnitUpperTriangularLayout{<:AbstractRowMajor}, _) - A = transA.parent + A = transpose(transA) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) end + Adata = triangulardata(A) for j = 1:n for i = 1:m Bij = B[i,j] for k = i + 1:m - Bij += transpose(A.data[k,i]) * B[k,j] + Bij += transpose(Adata[k,i]) * B[k,j] end B[i,j] = Bij end @@ -971,11 +1011,12 @@ function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, : if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = n:-1:1 Aij = A[i,j]*B[j,j] for k = 1:j - 1 - Aij += A[i,k]*B.data[k,j] + Aij += A[i,k]*Bdata[k,j] end A[i,j] = Aij end @@ -987,11 +1028,12 @@ function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, : if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = n:-1:1 Aij = A[i,j] for k = 1:j - 1 - Aij += A[i,k]*B.data[k,j] + Aij += A[i,k]*Bdata[k,j] end A[i,j] = Aij end @@ -1004,11 +1046,12 @@ function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, : if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = 1:n Aij = A[i,j]*B[j,j] for k = j + 1:n - Aij += A[i,k]*B.data[k,j] + Aij += A[i,k]*Bdata[k,j] end A[i,j] = Aij end @@ -1020,11 +1063,12 @@ function _rmul!(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, : if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = 1:n Aij = A[i,j] for k = j + 1:n - Aij += A[i,k]*B.data[k,j] + Aij += A[i,k]*Bdata[k,j] end A[i,j] = Aij end @@ -1038,11 +1082,12 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = 1:n - Aij = A[i,j]*B.data[j,j]' + Aij = A[i,j]*Bdata[j,j]' for k = j + 1:n - Aij += A[i,k]*B.data[j,k]' + Aij += A[i,k]*Bdata[j,k]' end A[i,j] = Aij end @@ -1056,11 +1101,12 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = 1:n Aij = A[i,j] for k = j + 1:n - Aij += A[i,k]*B.data[j,k]' + Aij += A[i,k]*Bdata[j,k]' end A[i,j] = Aij end @@ -1074,11 +1120,12 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = n:-1:1 - Aij = A[i,j]*B.data[j,j]' + Aij = A[i,j]*Bdata[j,j]' for k = 1:j - 1 - Aij += A[i,k]*B.data[j,k]' + Aij += A[i,k]*Bdata[j,k]' end A[i,j] = Aij end @@ -1092,11 +1139,12 @@ function _rmul!(A::AbstractMatrix, adjB::AbstractMatrix, ::AbstractStridedLayout if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = n:-1:1 Aij = A[i,j] for k = 1:j - 1 - Aij += A[i,k]*B.data[j,k]' + Aij += A[i,k]*Bdata[j,k]' end A[i,j] = Aij end @@ -1110,11 +1158,12 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = 1:n - Aij = A[i,j] * transpose(B.data[j,j]) + Aij = A[i,j] * transpose(Bdata[j,j]) for k = j + 1:n - Aij += A[i,k] * transpose(B.data[j,k]) + Aij += A[i,k] * transpose(Bdata[j,k]) end A[i,j] = Aij end @@ -1122,16 +1171,17 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo A end function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitLowerTriangularLayout{<:AbstractRowMajor}) - B = transB.parent + B = transpose(transB) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = 1:n Aij = A[i,j] for k = j + 1:n - Aij += A[i,k] * transpose(B.data[j,k]) + Aij += A[i,k] * transpose(Bdata[j,k]) end A[i,j] = Aij end @@ -1140,16 +1190,17 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo end function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UpperTriangularLayout{<:AbstractRowMajor}) - B = transB.parent + B = transpose(transB) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = n:-1:1 - Aij = A[i,j] * transpose(B.data[j,j]) + Aij = A[i,j] * transpose(Bdata[j,j]) for k = 1:j - 1 - Aij += A[i,k] * transpose(B.data[j,k]) + Aij += A[i,k] * transpose(Bdata[j,k]) end A[i,j] = Aij end @@ -1158,16 +1209,17 @@ function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayo end function _rmul!(A::AbstractMatrix, transB::AbstractMatrix, ::AbstractStridedLayout, ::UnitUpperTriangularLayout{<:AbstractRowMajor}) - B = transB.parent + B = transpose(transB) m, n = size(A) if size(B, 1) != n throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) end + Bdata = triangulardata(B) for i = 1:m for j = n:-1:1 Aij = A[i,j] for k = 1:j - 1 - Aij += A[i,k] * transpose(B.data[j,k]) + Aij += A[i,k] * transpose(Bdata[j,k]) end A[i,j] = Aij end @@ -1635,7 +1687,27 @@ rdiv!(A::LowerTriangular, transB::Transpose{<:Any,<:Union{UpperTriangular,UnitUp ## for these cases, but I'm not sure it is worth it. (*)(A::Union{Tridiagonal,SymTridiagonal}, B::AbstractTriangular) = rmul!(Matrix(A), B) -for (f, f2!) in ((:*, :lmul!), (:\, :ldiv!)) + +function _mul(A::AbstractMatrix, B::AbstractMatrix, ::Union{LowerTriangularLayout,UnitLowerTriangularLayout}, ::LowerTriangularLayout) + TAB = typeof(*(zero(eltype(A)), zero(eltype(B))) + + *(zero(eltype(A)), zero(eltype(B)))) + BB = similar(B, TAB, size(B)) + copyto!(BB, B) + return LowerTriangular(lmul!(convert(AbstractMatrix{TAB}, A), BB)) +end + + +function _mul(A::AbstractMatrix, B::AbstractMatrix, ::Union{UpperTriangularLayout,UnitUpperTriangularLayout}, ::UpperTriangularLayout) + TAB = typeof(*(zero(eltype(A)), zero(eltype(B))) + + *(zero(eltype(A)), zero(eltype(B)))) + BB = similar(B, TAB, size(B)) + copyto!(BB, B) + return UpperTriangular(lmul!(convert(AbstractMatrix{TAB}, A), BB)) +end + + + +for (f, f2!) in ((:\, :ldiv!),) @eval begin function ($f)(A::LowerTriangular, B::LowerTriangular) TAB = typeof(($f)(zero(eltype(A)), zero(eltype(B))) + @@ -1672,8 +1744,6 @@ for (f, f2!) in ((:*, :lmul!), (:\, :ldiv!)) end for (ipop, op, xformtype, xformop) in ( - (:lmul!, :*, :Adjoint, :adjoint), - (:lmul!, :*, :Transpose, :transpose), (:ldiv!, :\, :Adjoint, :adjoint), (:ldiv!, :\, :Transpose, :transpose)) @eval begin @@ -1745,8 +1815,6 @@ function (/)(A::UpperTriangular, B::UnitUpperTriangular) end for (ipop, op, xformtype, xformop) in ( - (:rmul!, :*, :Adjoint, :adjoint), - (:rmul!, :*, :Transpose, :transpose), (:rdiv!, :/, :Adjoint, :adjoint), (:rdiv!, :/, :Transpose, :transpose)) @eval begin @@ -1789,66 +1857,22 @@ for (ipop, op, xformtype, xformop) in ( end ## The general promotion methods -function *(A::AbstractTriangular, B::AbstractTriangular) +function _mul(A::AbstractMatrix, B::AbstractMatrix, ::AbstractTriangularLayout, ::AbstractTriangularLayout) TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) BB = similar(B, TAB, size(B)) copyto!(BB, B) lmul!(convert(AbstractArray{TAB}, A), BB) end -function *(adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractTriangular) - A = adjA.parent - TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - BB = similar(B, TAB, size(B)) - copyto!(BB, B) - lmul!(adjoint(convert(AbstractArray{TAB}, A)), BB) -end -function *(transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractTriangular) - A = transA.parent - TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - BB = similar(B, TAB, size(B)) - copyto!(BB, B) - lmul!(transpose(convert(AbstractArray{TAB}, A)), BB) -end - -function *(A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractTriangular}) - B = adjB.parent - TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - AA = similar(A, TAB, size(A)) - copyto!(AA, A) - rmul!(AA, adjoint(convert(AbstractArray{TAB}, B))) -end -function *(A::AbstractTriangular, transB::Transpose{<:Any,<:AbstractTriangular}) - B = transB.parent - TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - AA = similar(A, TAB, size(A)) - copyto!(AA, A) - rmul!(AA, transpose(convert(AbstractArray{TAB}, B))) -end for mat in (:AbstractVector, :AbstractMatrix) ### Multiplication with triangle to the left and hence rhs cannot be transposed. - @eval begin - function *(A::AbstractTriangular, B::$mat) - TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - BB = similar(B, TAB, size(B)) - copyto!(BB, B) - lmul!(convert(AbstractArray{TAB}, A), BB) - end - function *(adjA::Adjoint{<:Any,<:AbstractTriangular}, B::$mat) - A = adjA.parent - TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - BB = similar(B, TAB, size(B)) - copyto!(BB, B) - lmul!(adjoint(convert(AbstractArray{TAB}, A)), BB) - end - function *(transA::Transpose{<:Any,<:AbstractTriangular}, B::$mat) - A = transA.parent - TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - BB = similar(B, TAB, size(B)) - copyto!(BB, B) - lmul!(transpose(convert(AbstractArray{TAB}, A)), BB) - end + @eval function _mul(A::AbstractMatrix, B::$mat, ::AbstractTriangularLayout, ::AbstractStridedLayout) + TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) + BB = similar(B, TAB, size(B)) + copyto!(BB, B) + lmul!(convert(AbstractArray{TAB}, A), BB) end + ### Left division with triangle to the left hence rhs cannot be transposed. No quotients. @eval begin function \(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::$mat) @@ -1944,48 +1968,12 @@ for mat in (:AbstractVector, :AbstractMatrix) end ### Multiplication with triangle to the right and hence lhs cannot be transposed. # Only for AbstractMatrix, hence outside the above loop. -function *(A::AbstractMatrix, B::AbstractTriangular) +function _mul(A::AbstractMatrix, B::AbstractMatrix, ::AbstractStridedLayout, ::AbstractTriangularLayout) TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) AA = similar(A, TAB, size(A)) copyto!(AA, A) rmul!(AA, convert(AbstractArray{TAB}, B)) end -function *(A::AbstractMatrix, adjB::Adjoint{<:Any,<:AbstractTriangular}) - B = adjB.parent - TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - AA = similar(A, TAB, size(A)) - copyto!(AA, A) - rmul!(AA, adjoint(convert(AbstractArray{TAB}, B))) -end -function *(A::AbstractMatrix, transB::Transpose{<:Any,<:AbstractTriangular}) - B = transB.parent - TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - AA = similar(A, TAB, size(A)) - copyto!(AA, A) - rmul!(AA, transpose(convert(AbstractArray{TAB}, B))) -end -# ambiguity resolution with definitions in linalg/rowvector.jl -*(v::AdjointAbsVec, A::AbstractTriangular) = adjoint(adjoint(A) * v.parent) -*(v::TransposeAbsVec, A::AbstractTriangular) = transpose(transpose(A) * v.parent) -*(v::AdjointAbsVec, A::Adjoint{<:Any,<:AbstractTriangular}) = adjoint(A.parent * v.parent) -*(v::TransposeAbsVec, A::Transpose{<:Any,<:AbstractTriangular}) = transpose(A.parent * v.parent) - - -# If these are not defined, they will fallback to the versions in matmul.jl -# and dispatch to generic_matmatmul! which is very costly to compile. The methods -# below might compute an unnecessary copy. Eliminating the copy requires adding -# all the promotion logic here once again. Since these methods are probably relatively -# rare, we chose not to bother for now. -*(A::Adjoint{<:Any,<:AbstractMatrix}, B::AbstractTriangular) = copy(A) * B -*(A::Transpose{<:Any,<:AbstractMatrix}, B::AbstractTriangular) = copy(A) * B -*(A::AbstractTriangular, B::Adjoint{<:Any,<:AbstractMatrix}) = A * copy(B) -*(A::AbstractTriangular, B::Transpose{<:Any,<:AbstractMatrix}) = A * copy(B) -*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractTriangular}) = A * copy(B) -*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractMatrix}) = A * copy(B) -*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractTriangular}) = copy(A) * B -*(A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractTriangular}) = A * copy(B) -*(A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractMatrix}) = A * copy(B) -*(A::Transpose{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:AbstractTriangular}) = copy(A) * B # Complex matrix power for upper triangular factor, see: # Higham and Lin, "A Schur-Padé algorithm for fractional powers of a Matrix", @@ -2489,25 +2477,6 @@ end factorize(A::AbstractTriangular) = A -# dismabiguation methods: *(AbstractTriangular, Adj/Trans of AbstractVector) -*(A::AbstractTriangular, B::Adjoint{<:Any,<:AbstractVector}) = A * copy(B) -*(A::AbstractTriangular, B::Transpose{<:Any,<:AbstractVector}) = A * copy(B) -# dismabiguation methods: *(Adj/Trans of AbstractTriangular, Trans/Ajd of AbstractTriangular) -*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractTriangular}) = copy(A) * B -*(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractTriangular}) = copy(A) * B -# dismabiguation methods: *(Adj/Trans of AbstractTriangular, Adj/Trans of AbsVec or AbsMat) -*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVector}) = A * copy(B) -*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractMatrix}) = A * copy(B) -*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVector}) = A * copy(B) -*(A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVector}) = A * copy(B) -*(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVector}) = A * copy(B) -*(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractMatrix}) = A * copy(B) -# dismabiguation methods: *(Adj/Trans of AbsVec or AbsMat, Adj/Trans of AbstractTriangular) -*(A::Adjoint{<:Any,<:AbstractVector}, B::Transpose{<:Any,<:AbstractTriangular}) = copy(A) * B -*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:AbstractTriangular}) = copy(A) * B -*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractTriangular}) = copy(A) * B -*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractTriangular}) = copy(A) * B - # disambiguation methods: /(Adjoint of AbsVec, <:AbstractTriangular) /(u::AdjointAbsVec, A::Union{LowerTriangular,UpperTriangular}) = adjoint(adjoint(A) \ u.parent) /(u::AdjointAbsVec, A::Union{UnitLowerTriangular,UnitUpperTriangular}) = adjoint(adjoint(A) \ u.parent) diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index e188a856a40fd..731b117176308 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -495,10 +495,26 @@ end @test Base.MemoryLayout(Transpose(Hermitian(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') @test Base.MemoryLayout(Adjoint(Symmetric(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') @test Base.MemoryLayout(Adjoint(Hermitian(A))) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(view(Symmetric(A),:,:)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(view(Hermitian(A),:,:)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') @test Base.MemoryLayout(Symmetric(A')) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') @test Base.MemoryLayout(Hermitian(A')) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') @test Base.MemoryLayout(Symmetric(transpose(A))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') @test Base.MemoryLayout(Hermitian(transpose(A))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') + + @test LinearAlgebra.symmetricdata(Symmetric(A)) ≡ A + @test LinearAlgebra.symmetricdata(Hermitian(A)) ≡ A + @test LinearAlgebra.symmetricdata(Transpose(Symmetric(A))) ≡ A + @test LinearAlgebra.symmetricdata(Transpose(Hermitian(A))) ≡ A + @test LinearAlgebra.symmetricdata(Adjoint(Symmetric(A))) ≡ A + @test LinearAlgebra.symmetricdata(Adjoint(Hermitian(A))) ≡ A + @test LinearAlgebra.symmetricdata(view(Symmetric(A),:,:)) ≡ A + @test LinearAlgebra.symmetricdata(view(Hermitian(A),:,:)) ≡ A + @test LinearAlgebra.symmetricdata(Symmetric(A')) ≡ A' + @test LinearAlgebra.symmetricdata(Hermitian(A')) ≡ A' + @test LinearAlgebra.symmetricdata(Symmetric(transpose(A))) ≡ transpose(A) + @test LinearAlgebra.symmetricdata(Hermitian(transpose(A))) ≡ transpose(A) + B = [1.0+im 2; 3 4] @test Base.MemoryLayout(Symmetric(B)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') @test Base.MemoryLayout(Hermitian(B)) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor(),'U') @@ -506,21 +522,44 @@ end @test Base.MemoryLayout(Transpose(Hermitian(B))) == Base.UnknownLayout() @test Base.MemoryLayout(Adjoint(Symmetric(B))) == Base.UnknownLayout() @test Base.MemoryLayout(Adjoint(Hermitian(B))) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(view(Symmetric(B),:,:)) == LinearAlgebra.SymmetricLayout(Base.DenseColumnMajor(),'U') + @test Base.MemoryLayout(view(Hermitian(B),:,:)) == LinearAlgebra.HermitianLayout(Base.DenseColumnMajor(),'U') @test Base.MemoryLayout(Symmetric(B')) == Base.UnknownLayout() @test Base.MemoryLayout(Hermitian(B')) == Base.UnknownLayout() @test Base.MemoryLayout(Symmetric(transpose(B))) == LinearAlgebra.SymmetricLayout(Base.DenseRowMajor(),'U') @test Base.MemoryLayout(Hermitian(transpose(B))) == LinearAlgebra.HermitianLayout(Base.DenseRowMajor(),'U') + @test LinearAlgebra.symmetricdata(Symmetric(B)) ≡ B + @test LinearAlgebra.hermitiandata(Hermitian(B)) ≡ B + @test LinearAlgebra.symmetricdata(Transpose(Symmetric(B))) ≡ B + @test LinearAlgebra.hermitiandata(Adjoint(Hermitian(B))) ≡ B + @test LinearAlgebra.symmetricdata(view(Symmetric(B),:,:)) ≡ B + @test LinearAlgebra.hermitiandata(view(Hermitian(B),:,:)) ≡ B + @test LinearAlgebra.symmetricdata(Symmetric(B')) ≡ B' + @test LinearAlgebra.hermitiandata(Hermitian(B')) ≡ B' + @test LinearAlgebra.symmetricdata(Symmetric(transpose(B))) ≡ transpose(B) + @test LinearAlgebra.hermitiandata(Hermitian(transpose(B))) ≡ transpose(B) + A = randn(100,100) x = randn(100) - @test all(Symmetric(A)*x .=== Hermitian(A)*x .=== Symmetric(A)'*x .=== Symmetric(view(A,:,:)',:L)*x .=== BLAS.symv!('U', 1.0, A, x, 0.0, similar(x))) - @test all(Symmetric(A,:L)*x .=== Hermitian(A,:L)*x .=== Symmetric(A,:L)'*x .=== Symmetric(view(A,:,:)',:U)*x .=== BLAS.symv!('L', 1.0, A, x, 0.0, similar(x))) + @test all(Symmetric(A)*x .=== Hermitian(A)*x .=== Symmetric(A)'*x .=== + Symmetric(view(A,:,:)',:L)*x .=== view(Symmetric(A),:,:)*x .=== + BLAS.symv!('U', 1.0, A, x, 0.0, similar(x))) + @test all(Symmetric(A,:L)*x .=== Hermitian(A,:L)*x .=== Symmetric(A,:L)'*x .=== + Symmetric(view(A,:,:)',:U)*x .=== view(Hermitian(A,:L),:,:)*x .=== + BLAS.symv!('L', 1.0, A, x, 0.0, similar(x))) A = randn(ComplexF64,100,100) x = randn(ComplexF64,100) - @test all(Symmetric(A)*x .=== transpose(Symmetric(A))*x .=== Symmetric(transpose(view(A,:,:)),:L)*x .=== BLAS.symv!('U', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) - @test all(Symmetric(A,:L)*x .=== transpose(Symmetric(A,:L))*x .=== Symmetric(transpose(view(A,:,:)),:U)*x .=== BLAS.symv!('L', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) - @test all(Hermitian(A)*x .=== Hermitian(A)'*x .=== BLAS.hemv!('U', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) - @test all(Hermitian(A,:L)*x .=== Hermitian(A,:L)'*x .=== BLAS.hemv!('L', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) + @test all(Symmetric(A)*x .=== transpose(Symmetric(A))*x .=== + Symmetric(transpose(view(A,:,:)),:L)*x .=== view(Symmetric(A),:,:)*x .=== + BLAS.symv!('U', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) + @test all(Symmetric(A,:L)*x .=== transpose(Symmetric(A,:L))*x .=== + Symmetric(transpose(view(A,:,:)),:U)*x .=== view(Symmetric(A,:L),:,:)*x .=== + BLAS.symv!('L', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) + @test all(Hermitian(A)*x .=== Hermitian(A)'*x .=== view(Hermitian(A),:,:)*x .=== + BLAS.hemv!('U', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) + @test all(Hermitian(A,:L)*x .=== Hermitian(A,:L)'*x .=== view(Hermitian(A,:L),:,:)*x .=== + BLAS.hemv!('L', one(ComplexF64), A, x, zero(ComplexF64), similar(x))) end @testset "#25625 recursive transposition" begin From 9d0f50b5640715ee5c8507e0ceecd5da6fcc31fa Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Fri, 2 Mar 2018 18:15:15 +0000 Subject: [PATCH 34/39] view(UpperTriangular(A), :, Base.OneTo(n)) (and similar) now conform to triangular matrix interface --- stdlib/LinearAlgebra/src/triangular.jl | 3 ++ stdlib/LinearAlgebra/test/triangular.jl | 60 ++++++++++++++++--------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 80a41a4aa1a0c..32d58aab41606 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -449,6 +449,7 @@ MemoryLayout(A::LowerTriangular) = triangularlayout(LowerTriangularLayout, Memor MemoryLayout(A::UnitLowerTriangular) = triangularlayout(UnitLowerTriangularLayout, MemoryLayout(parent(A))) triangularlayout(_, ::MemoryLayout) = UnknownLayout() triangularlayout(::Type{Tri}, ML::AbstractColumnMajor) where {Tri} = Tri(ML) +Base.subarraylayout(layout::AbstractTriangularLayout, ::Tuple{<:Union{Slice,Base.OneTo},<:Union{Slice,Base.OneTo}}) = layout for (TriLayout, TriLayoutTrans) in ((UpperTriangularLayout, LowerTriangularLayout), (UnitUpperTriangularLayout, UnitLowerTriangularLayout), @@ -462,6 +463,8 @@ end triangulardata(A::Adjoint) = Adjoint(triangulardata(parent(A))) triangulardata(A::Transpose) = Transpose(triangulardata(parent(A))) +triangulardata(A::SubArray{<:Any,2,<:Any,<:Tuple{<:Union{Slice,Base.OneTo},<:Union{Slice,Base.OneTo}}}) = + view(triangulardata(parent(A)), parentindices(A)...) # Unary operations -(A::LowerTriangular) = LowerTriangular(-A.data) diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index a590fab104b00..209392cf88528 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -572,47 +572,67 @@ end A = randn(Float64, 100, 100) x = randn(Float64, 100) @test all(UpperTriangular(A)*x .=== UpperTriangular(view(A',:,:)')*x .=== - BLAS.trmv!('U', 'N', 'N', A, copy(x))) + view(UpperTriangular(A), Base.OneTo(100), :)*x .=== + BLAS.trmv!('U', 'N', 'N', A, copy(x))) @test all(UnitUpperTriangular(A)*x .=== UnitUpperTriangular(view(A',:,:)')*x .=== - BLAS.trmv!('U', 'N', 'U', A, copy(x))) + view(UnitUpperTriangular(A), Base.OneTo(100), :)*x .=== + BLAS.trmv!('U', 'N', 'U', A, copy(x))) @test all(LowerTriangular(A)*x .=== LowerTriangular(view(A',:,:)')*x .=== - BLAS.trmv!('L', 'N', 'N', A, copy(x))) + view(LowerTriangular(A), Base.OneTo(100), :)*x .=== + BLAS.trmv!('L', 'N', 'N', A, copy(x))) @test all(UnitLowerTriangular(A)*x .=== UnitLowerTriangular(view(A',:,:)')*x .=== - BLAS.trmv!('L', 'N', 'U', A, copy(x))) + view(UnitLowerTriangular(A), Base.OneTo(100), :)*x .=== + BLAS.trmv!('L', 'N', 'U', A, copy(x))) @test all(UpperTriangular(A)'*x .=== UpperTriangular(view(A',:,:)')'*x .=== - BLAS.trmv!('U', 'T', 'N', A, copy(x))) + view(UpperTriangular(A)', Base.OneTo(100), :)*x .=== + BLAS.trmv!('U', 'T', 'N', A, copy(x))) @test all(UnitUpperTriangular(A)'*x .=== UnitUpperTriangular(view(A',:,:)')'*x .=== - BLAS.trmv!('U', 'T', 'U', A, copy(x))) + view(UnitUpperTriangular(A)', Base.OneTo(100), :)*x .=== + BLAS.trmv!('U', 'T', 'U', A, copy(x))) @test all(LowerTriangular(A)'*x .=== LowerTriangular(view(A',:,:)')'*x .=== - BLAS.trmv!('L', 'T', 'N', A, copy(x))) + view(LowerTriangular(A)', Base.OneTo(100), :)*x .=== + BLAS.trmv!('L', 'T', 'N', A, copy(x))) @test all(UnitLowerTriangular(A)'*x .=== UnitLowerTriangular(view(A',:,:)')'*x .=== - BLAS.trmv!('L', 'T', 'U', A, copy(x))) + view(UnitLowerTriangular(A)', Base.OneTo(100), :)*x .=== + BLAS.trmv!('L', 'T', 'U', A, copy(x))) A = randn(ComplexF64, 100, 100) x = randn(ComplexF64, 100) @test all(UpperTriangular(A)*x .=== UpperTriangular(view(A',:,:)')*x .=== - BLAS.trmv!('U', 'N', 'N', A, copy(x))) + view(UpperTriangular(A), :, Base.OneTo(100))*x .=== + BLAS.trmv!('U', 'N', 'N', A, copy(x))) @test all(UnitUpperTriangular(A)*x .=== UnitUpperTriangular(view(A',:,:)')*x .=== - BLAS.trmv!('U', 'N', 'U', A, copy(x))) + view(UnitUpperTriangular(A), :, Base.OneTo(100))*x .=== + BLAS.trmv!('U', 'N', 'U', A, copy(x))) @test all(LowerTriangular(A)*x .=== LowerTriangular(view(A',:,:)')*x .=== - BLAS.trmv!('L', 'N', 'N', A, copy(x))) + view(LowerTriangular(A), :, Base.OneTo(100))*x .=== + BLAS.trmv!('L', 'N', 'N', A, copy(x))) @test all(UnitLowerTriangular(A)*x .=== UnitLowerTriangular(view(A',:,:)')*x .=== - BLAS.trmv!('L', 'N', 'U', A, copy(x))) + view(UnitLowerTriangular(A), :, Base.OneTo(100))*x .=== + BLAS.trmv!('L', 'N', 'U', A, copy(x))) @test all(transpose(UpperTriangular(A))*x .=== transpose(UpperTriangular(view(A',:,:)'))*x .=== - BLAS.trmv!('U', 'T', 'N', A, copy(x))) + view(transpose(UpperTriangular(A)), :, Base.OneTo(100))*x .=== + BLAS.trmv!('U', 'T', 'N', A, copy(x))) @test all(transpose(UnitUpperTriangular(A))*x .=== transpose(UnitUpperTriangular(view(A',:,:)'))*x .=== - BLAS.trmv!('U', 'T', 'U', A, copy(x))) + view(transpose(UnitUpperTriangular(A)), :, Base.OneTo(100))*x .=== + BLAS.trmv!('U', 'T', 'U', A, copy(x))) @test all(transpose(LowerTriangular(A))*x .=== transpose(LowerTriangular(view(A',:,:)'))*x .=== - BLAS.trmv!('L', 'T', 'N', A, copy(x))) + view(transpose(LowerTriangular(A)), :, Base.OneTo(100))*x .=== + BLAS.trmv!('L', 'T', 'N', A, copy(x))) @test all(transpose(UnitLowerTriangular(A))*x .=== transpose(UnitLowerTriangular(view(A',:,:)'))*x .=== - BLAS.trmv!('L', 'T', 'U', A, copy(x))) + view(transpose(UnitLowerTriangular(A)), :, Base.OneTo(100))*x .=== + BLAS.trmv!('L', 'T', 'U', A, copy(x))) @test all(UpperTriangular(A)'*x .=== UpperTriangular(view(A',:,:)')'*x .=== - BLAS.trmv!('U', 'C', 'N', A, copy(x))) + view(UpperTriangular(A)', :, Base.OneTo(100))*x .=== + BLAS.trmv!('U', 'C', 'N', A, copy(x))) @test all(UnitUpperTriangular(A)'*x .=== UnitUpperTriangular(view(A',:,:)')'*x .=== - BLAS.trmv!('U', 'C', 'U', A, copy(x))) + view(UnitUpperTriangular(A)', :, Base.OneTo(100))*x .=== + BLAS.trmv!('U', 'C', 'U', A, copy(x))) @test all(LowerTriangular(A)'*x .=== LowerTriangular(view(A',:,:)')'*x .=== - BLAS.trmv!('L', 'C', 'N', A, copy(x))) + view(LowerTriangular(A)', :, Base.OneTo(100))*x .=== + BLAS.trmv!('L', 'C', 'N', A, copy(x))) @test all(UnitLowerTriangular(A)'*x .=== UnitLowerTriangular(view(A',:,:)')'*x .=== - BLAS.trmv!('L', 'C', 'U', A, copy(x))) + view(UnitLowerTriangular(A)', :, Base.OneTo(100))*x .=== + BLAS.trmv!('L', 'C', 'U', A, copy(x))) end end # module TestTriangular From 3413fbae069aaba4f43d3be26c0a63132006fe14 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Fri, 2 Mar 2018 20:22:04 +0000 Subject: [PATCH 35/39] remove white space --- base/subarray.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/subarray.jl b/base/subarray.jl index f4c7b2f1fd513..5ebac23c4dbae 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -386,7 +386,7 @@ _row_subarraylayout(par::DenseRowMajor, ::DenseRowMajor, inds::Tuple{I, Vararg{A _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)) + _row_subarraylayout(par, StridedLayout(), tail(inds)) _strided_subarraylayout(par, inds) = UnknownLayout() _strided_subarraylayout(par, ::Tuple{}) = StridedLayout() From 5535185c9cfe910d6dc5c605ad0d8bc40736e684 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sun, 11 Mar 2018 18:15:46 +0000 Subject: [PATCH 36/39] Add Increasing/DecreasingStrides Fix stack overflow caused by mul!/lmul! loop in Triangular --- base/abstractarray.jl | 26 ++++++++++++++++++++++++-- stdlib/LinearAlgebra/src/adjtrans.jl | 13 ------------- stdlib/LinearAlgebra/src/triangular.jl | 9 ++++++++- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index e21779f076e3b..c8a476552a10a 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -290,12 +290,16 @@ size_to_strides(s) = () abstract type MemoryLayout end struct UnknownLayout <: MemoryLayout end abstract type AbstractStridedLayout <: MemoryLayout end -abstract type AbstractColumnMajor <: AbstractStridedLayout end +abstract type AbstractIncreasingStrides <: AbstractStridedLayout end +abstract type AbstractColumnMajor <: AbstractIncreasingStrides end struct DenseColumnMajor <: AbstractColumnMajor end struct ColumnMajor <: AbstractColumnMajor end -abstract type AbstractRowMajor <: AbstractStridedLayout 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 """ @@ -345,6 +349,15 @@ Arrays with `ColumnMajor` memory layout must conform to the `DenseArray` interfa """ 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() @@ -367,6 +380,15 @@ If `A` is a matrix with `RowMajor` memory layout, then """ 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() diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index cd3945db12f5c..c196221051ecc 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -265,16 +265,3 @@ pinv(v::TransposeAbsVec, tol::Real = 0) = pinv(conj(v.parent)).parent /(u::TransposeAbsVec, A::AbstractMatrix) = transpose(transpose(A) \ u.parent) /(u::AdjointAbsVec, A::Transpose{<:Any,<:AbstractMatrix}) = adjoint(conj(A.parent) \ u.parent) # technically should be adjoint(copy(adjoint(copy(A))) \ u.parent) /(u::TransposeAbsVec, A::Adjoint{<:Any,<:AbstractMatrix}) = transpose(conj(A.parent) \ u.parent) # technically should be transpose(copy(transpose(copy(A))) \ u.parent) - -# disambiguation methods -*(A::AdjointAbsVec, B::Transpose{<:Any,<:AbstractMatrix}) = A * copy(B) -*(A::TransposeAbsVec, B::Adjoint{<:Any,<:AbstractMatrix}) = A * copy(B) -*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractMatrix}) = copy(A) * B -*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:AbstractMatrix}) = A * copy(B) -# Adj/Trans-vector * Trans/Adj-vector, shouldn't exist, here for ambiguity resolution? TODO: test removal -*(A::Adjoint{<:Any,<:AbstractVector}, B::Transpose{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) -*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) -# Adj/Trans-matrix * Trans/Adj-vector, shouldn't exist, here for ambiguity resolution? TODO: test removal -*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) -*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) -*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 56e9e4460938e..2cb98c9c3259f 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -625,7 +625,14 @@ for (t, memlay, memlaytrans, uploc, isunitc) in ((:LowerTriangular, :LowerTriang (:UnitUpperTriangular, :UnitUpperTriangularLayout, :UnitLowerTriangularLayout, 'U', 'U')) @eval begin # Vector multiplication - _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, ::AbstractStridedLayout, ::$memlay, ::AbstractStridedLayout) where {T<:BlasFloat} = + _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, + ::AbstractStridedLayout, ::$memlay{<:AbstractColumnMajor}, ::AbstractStridedLayout) where T = + lmul!(A, copyto!(y, b)) + _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, + ::AbstractStridedLayout, ::$memlay{<:AbstractRowMajor}, ::AbstractStridedLayout) where T = + lmul!(A, copyto!(y, b)) + _mul!(y::AbstractVector{T}, A::AbstractMatrix{T}, b::AbstractVector{T}, + ::AbstractStridedLayout, ::$memlay{<:ConjLayout{<:AbstractRowMajor}}, ::AbstractStridedLayout) where T = lmul!(A, copyto!(y, b)) _lmul!(A::AbstractMatrix{T}, b::AbstractVector{T}, ::$memlay{DC}, ::AbstractStridedLayout) where {T<:BlasFloat,DC<:AbstractColumnMajor} = From 7b19e3846ad2c111d4587b14a0926ddb4ac8d6b9 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Mon, 12 Mar 2018 09:36:10 +0000 Subject: [PATCH 37/39] Add `Base.MemoryLayout(A)` as optional override, fix docs for MemoryLayout --- base/abstractarray.jl | 13 +++++-------- doc/src/manual/interfaces.md | 1 + 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index cd4f86568bbfd..d83e8a6c8dbcd 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -399,16 +399,14 @@ StridedLayout """ MemoryLayout(A) - MemoryLayout(typeof(A)) -`MemoryLayout` specifies the layout in memory for an array `A`. When -you define a new `AbstractArray` type, you can choose to implement -memory layout to indicate that an array is strided in memory. If you decide to -implement memory layout, then you must set this trait for your array -type. For example, if your matrix is column major with `stride(A,2) == size(A,1)`, +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(::Type{M}) where M <: MyMatrix = Base.DenseColumnMajor() + Base.MemoryLayout(::MyMatrix) = Base.DenseColumnMajor() The default is `Base.UnknownLayout()` to indicate that the layout in memory is unknown. @@ -417,7 +415,6 @@ Julia's internal linear algebra machinery will automatically (and invisibly) 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() diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 9cd4026b1aea6..caccee078c1bd 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -236,6 +236,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) | From f2f1b8f3c15afc206f5cdbe4ec4057c7b788c916 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Mon, 26 Mar 2018 09:54:15 +0100 Subject: [PATCH 38/39] Add NEWS item --- NEWS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS.md b/NEWS.md index 2df1ea68b030a..c4196e7161631 100644 --- a/NEWS.md +++ b/NEWS.md @@ -634,6 +634,11 @@ Library improvements * `trunc`, `floor`, `ceil`, `round`, and `signif` specify `base` using a keyword argument. ([#26156]) + * `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 ----------------------------- From e19f1a5c73d91f63948bdf5b9b4365ede3da57f2 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Sat, 7 Apr 2018 15:10:36 +0100 Subject: [PATCH 39/39] fixes for mbauman --- stdlib/LinearAlgebra/src/dense.jl | 5 ++--- stdlib/LinearAlgebra/src/generic.jl | 5 +++-- stdlib/LinearAlgebra/src/matmul.jl | 12 ------------ stdlib/LinearAlgebra/src/triangular.jl | 2 +- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index dc8d9ad191c8c..3224f18c2a10f 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -116,7 +116,7 @@ isposdef(x::Number) = imag(x)==0 && real(x) > 0 # a tuple containing 1 and a cumulative product of the first N-1 sizes # this definition is also used for StridedReshapedArray and StridedReinterpretedArray # which have the same memory storage as Array -function stride(a::Union{Array,StridedReshapedArray,StridedReinterpretArray}, i::Int) +function stride(a::Union{DenseArray,StridedReshapedArray,StridedReinterpretArray}, i::Int) if i > ndims(a) return length(a) end @@ -126,8 +126,7 @@ function stride(a::Union{Array,StridedReshapedArray,StridedReinterpretArray}, i: end return s end -strides(a::Array) = size_to_strides(1, size(a)...) -strides(a::BitArray) = size_to_strides(1, size(a)...) #TODO: This is needed for permutedims!, but its not clear what stride means here +strides(a::DenseArray) = size_to_strides(1, size(a)...) strides(a::ReshapedArray) = _dense_strides(size(a), MemoryLayout(parent(a))) strides(a::ReinterpretArray) = _dense_strides(size(a), MemoryLayout(parent(a))) _dense_strides(sz, ::DenseColumnMajor) = size_to_strides(1, sz...) diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index 6fcd892b9c0ca..3b9a58782e516 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -590,9 +590,10 @@ norm(v::AdjointAbsVec, q::Real) = q == Inf ? norm(conj(v.parent), 1) : norm(conj norm(v::AdjointAbsVec) = norm(conj(v.parent)) norm(v::TransposeAbsVec) = norm(v.parent) -vecdot(x::AbstractArray, y::AbstractArray) = _vecdot(x, y, MemoryLayout(x), MemoryLayout(y)) +vecdot(x::AbstractArray, y::AbstractArray) = vecdot(vec(x), vec(y)) +vecdot(x::AbstractVector, y::AbstractVector) = _vecdot(x, y, MemoryLayout(x), MemoryLayout(y)) -function _vecdot(x::AbstractArray, y::AbstractArray, _1, _2) +function _vecdot(x::AbstractVector, y::AbstractVector, _1, _2) lx = _length(x) if lx != _length(y) throw(DimensionMismatch("first array has length $(lx) which does not match the length of the second, $(_length(y)).")) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 1bfa11c693e5e..4e90be9c34b7a 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -8,18 +8,6 @@ matprod(x, y) = x*y + x*y for (typ, bdot) in ((:BlasReal, :(BLAS.dot)), (:BlasComplex, :(BLAS.dotc))) @eval begin - _vecdot(x::AbstractArray{T}, y::AbstractArray{T}, - ::DenseColumnMajor, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) - _vecdot(x::AbstractVector{T}, y::AbstractVector{T}, - ::DenseColumnMajor, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) - _vecdot(x::AbstractVector{T}, y::AbstractArray{T}, - ::DenseColumnMajor, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) - _vecdot(x::AbstractArray{T}, y::AbstractVector{T}, - ::DenseColumnMajor, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) - _vecdot(x::AbstractVector{T}, y::AbstractArray{T}, - ::AbstractStridedLayout, ::DenseColumnMajor) where T<:$typ = $bdot(x, y) - _vecdot(x::AbstractArray{T}, y::AbstractVector{T}, - ::DenseColumnMajor, ::AbstractStridedLayout) where T<:$typ = $bdot(x, y) _vecdot(x::AbstractVector{T}, y::AbstractVector{T}, ::AbstractStridedLayout, ::AbstractStridedLayout) where T<:$typ = $bdot(x, y) end diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 2cb98c9c3259f..42cc4c894a617 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -796,7 +796,7 @@ for (t, unitt) in ((UpperTriangular, UnitUpperTriangular), end ## Generic triangular multiplication -function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{<:AbstractColumnMajor}, _) where T +function _lmul!(A::AbstractMatrix, B::AbstractVecOrMat, ::UpperTriangularLayout{<:AbstractColumnMajor}, _) m, n = size(B, 1), size(B, 2) if m != size(A, 1) throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m"))