diff --git a/base/deprecated.jl b/base/deprecated.jl index 44e83e07e72c7..7b3f7c427750d 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1956,8 +1956,8 @@ function full(Q::LinAlg.LQPackedQ; thin::Bool = true) "`full(Q::LQPackedQ; thin::Bool = true)` (and `full` in general) ", "has been deprecated. To replace `full(Q::LQPackedQ, true)`, ", "consider `Matrix(Q)` or `Array(Q)`. To replace `full(Q::LQPackedQ, false)`, ", - "consider `Base.LinAlg.A_mul_B!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 2), size(Q.factors, 2)))`."), :full) - return thin ? Array(Q) : A_mul_B!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 2), size(Q.factors, 2))) + "consider `Base.LinAlg.mul!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 2), size(Q.factors, 2)))`."), :full) + return thin ? Array(Q) : Base.LinAlg.mul!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 2), size(Q.factors, 2))) end function full(Q::Union{LinAlg.QRPackedQ,LinAlg.QRCompactWYQ}; thin::Bool = true) qtypestr = isa(Q, LinAlg.QRPackedQ) ? "QRPackedQ" : @@ -1967,8 +1967,8 @@ function full(Q::Union{LinAlg.QRPackedQ,LinAlg.QRCompactWYQ}; thin::Bool = true) "`full(Q::$(qtypestr); thin::Bool = true)` (and `full` in general) ", "has been deprecated. To replace `full(Q::$(qtypestr), true)`, ", "consider `Matrix(Q)` or `Array(Q)`. To replace `full(Q::$(qtypestr), false)`, ", - "consider `Base.LinAlg.A_mul_B!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 1), size(Q.factors, 1)))`."), :full) - return thin ? Array(Q) : A_mul_B!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 1), size(Q.factors, 1))) + "consider `Base.LinAlg.mul!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 1), size(Q.factors, 1)))`."), :full) + return thin ? Array(Q) : Base.LinAlg.mul!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 1), size(Q.factors, 1))) end # full for symmetric / hermitian / triangular wrappers @@ -2159,6 +2159,792 @@ finalizer(f::Ptr{Void}, o::Function) = invoke(finalizer, Tuple{Ptr{Void}, Any}, Base.@deprecate_binding broadcast_t broadcast false ", broadcast_t(f, ::Type{ElType}, shape, iter, As...)` should become `broadcast(f, Broadcast.DefaultArrayStyle{N}(), ElType, shape, As...))` (see the manual chapter Interfaces)" end +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/bidiag.jl, to deprecate +@eval Base.LinAlg begin + A_mul_B!(C::AbstractMatrix, A::SymTridiagonal, B::BiTriSym) = mul!(C, A, B) + A_mul_B!(C::AbstractMatrix, A::BiTri, B::BiTriSym) = mul!(C, A, B) + A_mul_B!(C::AbstractMatrix, A::BiTriSym, B::BiTriSym) = mul!(C, A, B) + A_mul_B!(C::AbstractMatrix, A::AbstractTriangular, B::BiTriSym) = mul!(C, A, B) + A_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::BiTriSym) = mul!(C, A, B) + A_mul_B!(C::AbstractMatrix, A::Diagonal, B::BiTriSym) = mul!(C, A, B) + A_mul_B!(C::AbstractVector, A::BiTri, B::AbstractVector) = mul!(C, A, B) + A_mul_B!(C::AbstractMatrix, A::BiTri, B::AbstractVecOrMat) = mul!(C, A, B) + A_mul_B!(C::AbstractVecOrMat, A::BiTri, B::AbstractVecOrMat) = mul!(C, A, B) + Ac_ldiv_B(A::Bidiagonal, v::RowVector) = \(Adjoint(A), v) + At_ldiv_B(A::Bidiagonal, v::RowVector) = \(Transpose(A), v) + Ac_ldiv_B(A::Bidiagonal{<:Number}, v::RowVector{<:Number}) = \(Adjoint(A), v) + At_ldiv_B(A::Bidiagonal{<:Number}, v::RowVector{<:Number}) = \(Transpose(A), v) + Ac_mul_B(A::Bidiagonal{T}, B::AbstractVector{T}) where {T} = *(Adjoint(A), B) + A_mul_Bc(A::Bidiagonal{T}, B::AbstractVector{T}) where {T} = *(A, Adjoint(B)) + A_rdiv_Bc(A::Bidiagonal{T}, B::AbstractVector{T}) where {T} = /(A, Adjoint(B)) + A_ldiv_B!(A::Union{Bidiagonal, AbstractTriangular}, b::AbstractVector) = ldiv!(A, b) + At_ldiv_B!(A::Bidiagonal, b::AbstractVector) = ldiv!(Transpose(A), b) + Ac_ldiv_B!(A::Bidiagonal, b::AbstractVector) = ldiv!(Adjoint(A), b) + A_ldiv_B!(A::Union{Bidiagonal,AbstractTriangular}, B::AbstractMatrix) = ldiv!(A, B) + Ac_ldiv_B!(A::Union{Bidiagonal,AbstractTriangular}, B::AbstractMatrix) = ldiv!(Adjoint(A), B) + At_ldiv_B!(A::Union{Bidiagonal,AbstractTriangular}, B::AbstractMatrix) = ldiv!(Transpose(A), B) + At_ldiv_B(A::Bidiagonal{TA}, B::AbstractVecOrMat{TB}) where {TA<:Number,TB<:Number} = \(Transpose(A), B) + At_ldiv_B(A::Bidiagonal, B::AbstractVecOrMat) = \(Transpose(A), B) + Ac_ldiv_B(A::Bidiagonal{TA}, B::AbstractVecOrMat{TB}) where {TA<:Number,TB<:Number} = \(Adjoint(A), B) + Ac_ldiv_B(A::Bidiagonal, B::AbstractVecOrMat) = ldiv!(Adjoint(A), B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/tridiag.jl, to deprecate +@eval Base.LinAlg begin + A_mul_B!(C::StridedVecOrMat, S::SymTridiagonal, B::StridedVecOrMat) = mul!(C, S, B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/diagonal.jl, to deprecate +@eval Base.LinAlg begin + A_mul_B!(A::Union{LowerTriangular,UpperTriangular}, D::Diagonal) = mul!(A, D) + A_mul_B!(A::UnitLowerTriangular, D::Diagonal) = mul!(A, D) + A_mul_B!(A::UnitUpperTriangular, D::Diagonal) = mul!(A, D) + A_mul_B!(D::Diagonal, B::UnitLowerTriangular) = mul!(D, B) + A_mul_B!(D::Diagonal, B::UnitUpperTriangular) = mul!(D, B) + Ac_mul_B(D::Diagonal, B::Diagonal) = *(Adjoint(D), B) + Ac_mul_B(A::AbstractTriangular, D::Diagonal) = *(Adjoint(A), D) + Ac_mul_B(A::AbstractMatrix, D::Diagonal) = *(Adjoint(A), D) + At_mul_B(D::Diagonal, B::Diagonal) = *(Transpose(D), B) + At_mul_B(A::AbstractTriangular, D::Diagonal) = *(Transpose(A), D) + At_mul_B(A::AbstractMatrix, D::Diagonal) = *(Transpose(A), D) + A_mul_Bc(D::Diagonal, B::Diagonal) = *(D, Adjoint(B)) + A_mul_Bc(D::Diagonal, B::AbstractTriangular) = *(D, Adjoint(B)) + A_mul_Bc(D::Diagonal, Q::Union{QRCompactWYQ,QRPackedQ}) = *(D, Adjoint(Q)) + A_mul_Bc(D::Diagonal, A::AbstractMatrix) = *(D, Adjoint(A)) + A_mul_Bt(D::Diagonal, B::Diagonal) = *(D, Transpose(B)) + A_mul_Bt(D::Diagonal, B::AbstractTriangular) = *(D, Transpose(B)) + A_mul_Bt(D::Diagonal, A::AbstractMatrix) = *(D, Transpose(A)) + Ac_mul_Bc(D::Diagonal, B::Diagonal) = *(Adjoint(D), Adjoint(B)) + At_mul_Bt(D::Diagonal, B::Diagonal) = *(Transpose(D), Transpose(B)) + A_mul_B!(A::Diagonal,B::Diagonal) = mul!(A, B) + At_mul_B!(A::Diagonal,B::Diagonal) = mul!(Transpose(A), B) + Ac_mul_B!(A::Diagonal,B::Diagonal) = mul!(Adjoint(A), B) + A_mul_B!(A::QRPackedQ, D::Diagonal) = mul!(A, D) + A_mul_B!(A::Diagonal,B::AbstractMatrix) = mul!(A, B) + At_mul_B!(A::Diagonal,B::AbstractMatrix) = mul!(Transpose(A), B) + Ac_mul_B!(A::Diagonal,B::AbstractMatrix) = mul!(Adjoint(A), B) + A_mul_B!(A::AbstractMatrix,B::Diagonal) = mul!(A, B) + A_mul_Bt!(A::AbstractMatrix,B::Diagonal) = mul!(A, Transpose(B)) + A_mul_Bc!(A::AbstractMatrix,B::Diagonal) = mul!(A, Adjoint(B)) + A_mul_B!(out::AbstractVector, A::Diagonal, in::AbstractVector) = mul!(out, A, in) + Ac_mul_B!(out::AbstractVector, A::Diagonal, in::AbstractVector) = mul!(out, Adjoint(A), in) + At_mul_B!(out::AbstractVector, A::Diagonal, in::AbstractVector) = mul!(out, Transpose(A), in) + A_mul_B!(out::AbstractMatrix, A::Diagonal, in::AbstractMatrix) = mul!(out, A, in) + Ac_mul_B!(out::AbstractMatrix, A::Diagonal, in::AbstractMatrix) = mul!(out, Adjoint(A), in) + At_mul_B!(out::AbstractMatrix, A::Diagonal, in::AbstractMatrix) = mul!(out, Transpose(A), in) + A_mul_Bt(A::Diagonal, B::RealHermSymComplexSym) = *(A, Transpose(B)) + At_mul_B(A::RealHermSymComplexSym, B::Diagonal) = *(Transpose(A), B) + A_mul_Bc(A::Diagonal, B::RealHermSymComplexHerm) = *(A, Adjoint(B)) + Ac_mul_B(A::RealHermSymComplexHerm, B::Diagonal) = *(Adjoint(A), B) + A_ldiv_B!(D::Diagonal{T}, v::AbstractVector{T}) where {T} = ldiv!(D, v) + A_ldiv_B!(D::Diagonal{T}, V::AbstractMatrix{T}) where {T} = ldiv!(D, V) + Ac_ldiv_B!(D::Diagonal{T}, B::AbstractVecOrMat{T}) where {T} = ldiv!(Adjoint(D), B) + At_ldiv_B!(D::Diagonal{T}, B::AbstractVecOrMat{T}) where {T} = ldiv!(Transpose(D), B) + A_rdiv_B!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} = rdiv!(A, D) + A_rdiv_Bc!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} = rdiv!(A, Adjoint(D)) + A_rdiv_Bt!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} = rdiv!(A, Transpose(D)) + Ac_ldiv_B(F::Factorization, D::Diagonal) = \(Adjoint(F), D) + A_mul_Bt(D::Diagonal, rowvec::RowVector) = *(D, Transpose(rowvec)) + A_mul_Bc(D::Diagonal, rowvec::RowVector) = *(D, Adjoint(rowvec)) + A_ldiv_B!(D::Diagonal, B::StridedVecOrMat) = ldiv!(D, B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/special.jl, to deprecate +@eval Base.LinAlg begin + A_mul_Bc!(A::AbstractTriangular, B::Union{QRCompactWYQ,QRPackedQ}) = mul!(A, Adjoint(B)) + A_mul_Bc(A::AbstractTriangular, B::Union{QRCompactWYQ,QRPackedQ}) = *(A, Adjoint(B)) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/bunchkaufman.jl, to deprecate +@eval Base.LinAlg begin + A_ldiv_B!(B::BunchKaufman{T}, R::StridedVecOrMat{T}) where {T<:BlasReal} = ldiv!(B, R) + A_ldiv_B!(B::BunchKaufman{T}, R::StridedVecOrMat{T}) where {T<:BlasComplex} = ldiv!(B, R) + A_ldiv_B!(B::BunchKaufman{T}, R::StridedVecOrMat{S}) where {T,S} = ldiv!(B, R) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/cholesky.jl, to deprecate +@eval Base.LinAlg begin + A_ldiv_B!(C::Cholesky{T,<:AbstractMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = ldiv!(C, B) + A_ldiv_B!(C::Cholesky{<:Any,<:AbstractMatrix}, B::StridedVecOrMat) = ldiv!(C, B) + A_ldiv_B!(C::CholeskyPivoted{T}, B::StridedVector{T}) where {T<:BlasFloat} = ldiv!(C, B) + A_ldiv_B!(C::CholeskyPivoted{T}, B::StridedMatrix{T}) where {T<:BlasFloat} = ldiv!(C, B) + A_ldiv_B!(C::CholeskyPivoted, B::StridedVector) = ldiv!(C, B) + A_ldiv_B!(C::CholeskyPivoted, B::StridedMatrix) = ldiv!(C, B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/factorization.jl, to deprecate +@eval Base.LinAlg begin + Ac_ldiv_B(F::Factorization, B::AbstractVecOrMat) = \(Adjoint(F), B) + A_ldiv_B!(Y::AbstractVecOrMat, A::Factorization, B::AbstractVecOrMat) = ldiv!(Y, A, B) + Ac_ldiv_B!(Y::AbstractVecOrMat, A::Factorization, B::AbstractVecOrMat) = ldiv!(Y, Adjoint(A), B) + At_ldiv_B!(Y::AbstractVecOrMat, A::Factorization, B::AbstractVecOrMat) = ldiv!(Y, Transpose(A), B) + At_ldiv_B(F::Factorization{<:Real}, B::AbstractVecOrMat) = \(Transpose(F), B) + At_ldiv_B(F::Factorization, B) = \(Transpose(F), B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/hessenberg.jl, to deprecate +@eval Base.LinAlg begin + A_mul_B!(Q::HessenbergQ{T}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = mul!(Q, X) + A_mul_B!(X::StridedMatrix{T}, Q::HessenbergQ{T}) where {T<:BlasFloat} = mul!(X, Q) + Ac_mul_B!(Q::HessenbergQ{T}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = mul!(Adjoint(Q), X) + A_mul_Bc!(X::StridedMatrix{T}, Q::HessenbergQ{T}) where {T<:BlasFloat} = mul!(X, Adjoint(Q)) + Ac_mul_B(Q::HessenbergQ{T}, X::StridedVecOrMat{S}) where {T,S} = *(Adjoint(Q), X) + A_mul_Bc(X::StridedVecOrMat{S}, Q::HessenbergQ{T}) where {T,S} = *(X, Adjoint(Q)) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/ldlt.jl, to deprecate +@eval Base.LinAlg begin + A_ldiv_B!(S::LDLt{T,M}, B::AbstractVecOrMat{T}) where {T,M<:SymTridiagonal{T}} = ldiv!(S, B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/svd.jl, to deprecate +@eval Base.LinAlg begin + A_ldiv_B!(A::SVD{T}, B::StridedVecOrMat) where {T} = ldiv!(A, B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/symmetric.jl, to deprecate +@eval Base.LinAlg begin + A_mul_B!(y::StridedVector{T}, A::Symmetric{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasFloat} = mul!(y, A, x) + A_mul_B!(y::StridedVector{T}, A::Hermitian{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasReal} = mul!(y, A, x) + A_mul_B!(y::StridedVector{T}, A::Hermitian{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasComplex} = mul!(y, A, x) + A_mul_B!(C::StridedMatrix{T}, A::Symmetric{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = mul!(C, A, B) + A_mul_B!(C::StridedMatrix{T}, A::StridedMatrix{T}, B::Symmetric{T,<:StridedMatrix}) where {T<:BlasFloat} = mul!(C, A, B) + A_mul_B!(C::StridedMatrix{T}, A::Hermitian{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasReal} = mul!(C, A, B) + A_mul_B!(C::StridedMatrix{T}, A::StridedMatrix{T}, B::Hermitian{T,<:StridedMatrix}) where {T<:BlasReal} = mul!(C, A, B) + A_mul_B!(C::StridedMatrix{T}, A::Hermitian{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasComplex} = mul!(C, A, B) + A_mul_B!(C::StridedMatrix{T}, A::StridedMatrix{T}, B::Hermitian{T,<:StridedMatrix}) where {T<:BlasComplex} = mul!(C, A, B) + At_mul_B(A::RealHermSymComplexSym, B::AbstractVector) = *(Transpose(A), B) + At_mul_B(A::RealHermSymComplexSym, B::AbstractMatrix) = *(Transpose(A), B) + A_mul_Bt(A::AbstractMatrix, B::RealHermSymComplexSym) = *(A, Transpose(B)) + Ac_mul_B(A::RealHermSymComplexHerm, B::AbstractVector) = *(Adjoint(A), B) + Ac_mul_B(A::RealHermSymComplexHerm, B::AbstractMatrix) = *(Adjoint(A), B) + A_mul_Bc(A::AbstractMatrix, B::RealHermSymComplexHerm) = *(A, Adjoint(B)) + A_mul_Bt(A::RowVector, B::RealHermSymComplexSym) = *(A, Transpose(B)) + A_mul_Bc(A::RowVector, B::RealHermSymComplexHerm) = *(A, Adjoint(B)) + At_mul_B(A::RealHermSymComplexSym, B::AbstractTriangular) = *(Transpose(A), B) + A_mul_Bt(A::AbstractTriangular, B::RealHermSymComplexSym) = *(A, Transpose(B)) + Ac_mul_B(A::RealHermSymComplexHerm, B::AbstractTriangular) = *(Adjoint(A), B) + A_mul_Bc(A::AbstractTriangular, B::RealHermSymComplexHerm) = *(A, Adjoint(B)) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/lu.jl, to deprecate +@eval Base.LinAlg begin + A_ldiv_B!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = ldiv!(A, B) + A_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, B::StridedVecOrMat) = ldiv!(A, B) + At_ldiv_B!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = ldiv!(Transpose(A), B) + At_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, B::StridedVecOrMat) = ldiv!(Transpose(A), B) + Ac_ldiv_B!(F::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:Real} = ldiv!(Adjoint(F), B) + Ac_ldiv_B!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = ldiv!(Adjoint(A), B) + Ac_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, B::StridedVecOrMat) = ldiv!(Adjoint(A), B) + At_ldiv_Bt(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = \(Transpose(A), Transpose(B)) + At_ldiv_Bt(A::LU, B::StridedVecOrMat) = \(Transpose(A), Transpose(B)) + Ac_ldiv_Bc(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = \(Adjoint(A), Adjoint(B)) + Ac_ldiv_Bc(A::LU, B::StridedVecOrMat) = \(Adjoint(A), Adjoint(B)) + A_ldiv_B!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} = ldiv!(A, B) + At_ldiv_B!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} = \(Transpose(A), B) + Ac_ldiv_B!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} = ldiv!(Adjoint(A), B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/lq.jl, to deprecate +@eval Base.LinAlg begin + A_mul_B!(A::LQ{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = mul!(A, B) + A_mul_B!(A::LQ{T}, B::QR{T}) where {T<:BlasFloat} = mul!(A, B) + A_mul_B!(A::QR{T}, B::LQ{T}) where {T<:BlasFloat} = mul!(A, B) + A_mul_B!(A::LQPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = mul!(A, B) + Ac_mul_B!(A::LQPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasReal} = mul!(Adjoint(A), B) + Ac_mul_B!(A::LQPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = mul!(Adjoint(A), B) + Ac_mul_B(A::LQPackedQ, B::StridedVecOrMat) = *(Adjoint(A), B) + A_mul_Bc(A::LQPackedQ, B::StridedVecOrMat) = *(A, Adjoint(B)) + Ac_mul_Bc(A::LQPackedQ, B::StridedVecOrMat) = *(Adjoint(A), Adjoint(B)) + A_mul_B!(A::StridedMatrix{T}, B::LQPackedQ{T}) where {T<:BlasFloat} = mul!(A, B) + A_mul_Bc!(A::StridedMatrix{T}, B::LQPackedQ{T}) where {T<:BlasReal} = mul!(A, Adjoint(B)) + A_mul_Bc!(A::StridedMatrix{T}, B::LQPackedQ{T}) where {T<:BlasComplex} = mul!(A, Adjoint(B)) + A_mul_Bc(A::StridedVecOrMat, Q::LQPackedQ) = *(A, Adjoint(Q)) + Ac_mul_Bc(A::StridedMatrix, Q::LQPackedQ) = *(Adjoint(A), Adjoint(Q)) + Ac_mul_B(A::StridedMatrix, Q::LQPackedQ) = *(Adjoint(A), Q) + A_ldiv_B!(A::LQ{T}, B::StridedVecOrMat{T}) where {T} = ldiv!(A, B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/qr.jl, to deprecate +@eval Base.LinAlg begin + A_mul_B!(A::QRCompactWYQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasFloat, S<:StridedMatrix} = mul!(A, B) + A_mul_B!(A::QRPackedQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasFloat, S<:StridedMatrix} = mul!(A, B) + A_mul_B!(A::QRPackedQ, B::AbstractVecOrMat) = mul!(A, B) + Ac_mul_B!(A::QRCompactWYQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasReal,S<:StridedMatrix} = mul!(Adjoint(A), B) + Ac_mul_B!(A::QRCompactWYQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasComplex,S<:StridedMatrix} = mul!(Adjoint(A), B) + Ac_mul_B!(A::QRPackedQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasReal,S<:StridedMatrix} = mul!(Adjoint(A), B) + Ac_mul_B!(A::QRPackedQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasComplex,S<:StridedMatrix} = mul!(Adjoint(A), B) + Ac_mul_B!(A::QRPackedQ, B::AbstractVecOrMat) = mul!(Adjoint(A), B) + Ac_mul_B(Q::AbstractQ, B::StridedVecOrMat) = *(Adjoint(Q), B) + A_mul_Bc(Q::AbstractQ, B::StridedVecOrMat) = *(Q, Adjoint(B)) + Ac_mul_Bc(Q::AbstractQ, B::StridedVecOrMat) = *(Adjoint(Q), Adjoint(B)) + A_mul_B!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = mul!(A, B) + A_mul_B!(A::StridedVecOrMat{T}, B::QRPackedQ{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = mul!(A, B) + A_mul_B!(A::StridedMatrix,Q::QRPackedQ) = mul!(A, Q) + A_mul_Bc!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T}) where {T<:BlasReal} = mul!(A, Adjoint(B)) + A_mul_Bc!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T}) where {T<:BlasComplex} = mul!(A, Adjoint(B)) + A_mul_Bc!(A::StridedVecOrMat{T}, B::QRPackedQ{T}) where {T<:BlasReal} = mul!(A, Adjoint(B)) + A_mul_Bc!(A::StridedVecOrMat{T}, B::QRPackedQ{T}) where {T<:BlasComplex} = mul!(A, Adjoint(B)) + A_mul_Bc!(A::StridedMatrix,Q::QRPackedQ) = mul!(A, Adjoint(Q)) + A_mul_Bc(A::StridedMatrix, B::AbstractQ) = *(A, Adjoint(B)) + A_mul_Bc(rowvec::RowVector, B::AbstractQ) = *(rowvec, Adjoint(B)) + Ac_mul_B(A::StridedVecOrMat, Q::AbstractQ) = *(Adjoint(A), Q) + Ac_mul_Bc(A::StridedVecOrMat, Q::AbstractQ) = *(Adjoint(A), Adjoint(Q)) + A_ldiv_B!(A::QRCompactWY{T}, b::StridedVector{T}) where {T<:BlasFloat} = ldiv!(A, b) + A_ldiv_B!(A::QRCompactWY{T}, B::StridedMatrix{T}) where {T<:BlasFloat} = ldiv!(A, B) + A_ldiv_B!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where {T<:BlasFloat} = ldiv!(A, B, rcond) + A_ldiv_B!(A::QRPivoted{T}, B::StridedVector{T}) where {T<:BlasFloat} = ldiv!(A, B) + A_ldiv_B!(A::QRPivoted{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = ldiv!(A, B) + A_ldiv_B!(A::QR{T}, B::StridedMatrix{T}) where {T} = ldiv!(A, B) + A_ldiv_B!(A::QR, B::StridedVector) = ldiv!(A, B) + A_ldiv_B!(A::QRPivoted, b::StridedVector) = ldiv!(A, b) + A_ldiv_B!(A::QRPivoted, B::StridedMatrix) = ldiv!(A, B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/matmul.jl, to deprecate +@eval Base.LinAlg begin + Ac_mul_Bc(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} = *(Adjoint(A), Adjoint(B)) + Ac_mul_Bc!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = mul!(C, Adjoint(A), Adjoint(B)) + Ac_mul_Bc!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = mul!(C, Adjoint(A), Adjoint(B)) + Ac_mul_Bt!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = mul!(C, Adjoint(A), Transpose(B)) + A_mul_Bc!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = mul!(C, A, Adjoint(B)) + A_mul_Bc!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = mul!(C, A, Adjoint(B)) + A_mul_Bc(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} = *(A, Adjoint(B)) + A_mul_Bc(A::StridedMatrix{<:BlasFloat}, B::StridedMatrix{<:BlasReal}) = *(A, Adjoint(B)) + A_mul_Bc!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{<:BlasReal}) where {T<:BlasFloat} = mul!(C, A, Adjoint(B)) + Ac_mul_B!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = mul!(C, Adjoint(A), B) + Ac_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = mul!(C, Adjoint(A), B) + Ac_mul_B(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} = *(Adjoint(A), B) + Ac_mul_B(A::StridedMatrix{T}, B::StridedMatrix{T}) where {T<:BlasReal} = *(Adjoint(A), B) + Ac_mul_B!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasReal} = mul!(C, Adjoint(A), B) + At_mul_Bt!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = mul!(C, Transpose(A), Transpose(B)) + At_mul_Bt!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = mul!(C, Transpose(A), Transpose(B)) + At_mul_Bt(A::AbstractMatrix{T}, B::AbstractVecOrMat{S}) where {T,S} = *(Transpose(A), Transpose(B)) + A_mul_Bt!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = mul!(C, A, Transpose(B)) + A_mul_Bt!(C::StridedMatrix{Complex{Float32}}, A::StridedVecOrMat{Complex{Float32}}, B::StridedVecOrMat{Float32}) = mul!(C, A, Transpose(B)) + A_mul_Bt!(C::StridedMatrix{Complex{Float64}}, A::StridedVecOrMat{Complex{Float64}}, B::StridedVecOrMat{Float64}) = mul!(C, A, Transpose(B)) + A_mul_Bt!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = mul!(C, A, Transpose(B)) + A_mul_Bt(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} = *(A, Transpose(B)) + At_mul_B!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = mul!(C, Transpose(A), B) + At_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = mul!(C, Transpose(A), B) + At_mul_B(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} = *(Transpose(A), B) + """ + A_mul_B!(A, B) + + Calculate the matrix-matrix product ``AB``, overwriting one of `A` or `B` (but not both), + and return the result (the overwritten argument). + """ + A_mul_B!(A, B) + """ + A_mul_B!(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); A_mul_B!(Y, A, B); + + julia> Y + 2×2 Array{Float64,2}: + 3.0 3.0 + 7.0 7.0 + ``` + """ + A_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = mul!(C, A, B) + A_mul_B!(C::StridedMatrix{Complex{Float32}}, A::StridedVecOrMat{Complex{Float32}}, B::StridedVecOrMat{Float32}) = mul!(C, A, B) + A_mul_B!(C::StridedMatrix{Complex{Float64}}, A::StridedVecOrMat{Complex{Float64}}, B::StridedVecOrMat{Float64}) = mul!(C, A, B) + A_mul_B!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = mul!(C, A, B) + Ac_mul_B!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasReal} = mul!(y, Adjoint(A), x) + Ac_mul_B!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasComplex} = mul!(y, Adjoint(A), x) + Ac_mul_B!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = mul!(y, Adjoint(A), x) + Ac_mul_B(A::StridedMatrix{T}, x::StridedVector{S}) where {T<:BlasFloat,S} = *(Adjoint(A), x) + Ac_mul_B(A::AbstractMatrix{T}, x::AbstractVector{S}) where {T,S} = *(Adjoint(A), x) + At_mul_B(A::StridedMatrix{T}, x::StridedVector{S}) where {T<:BlasFloat,S} = *(Transpose(A), x) + At_mul_B(A::AbstractMatrix{T}, x::AbstractVector{S}) where {T,S} = *(Transpose(A), x) + At_mul_B!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasFloat} = mul!(y, Transpose(A), x) + At_mul_B!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = mul!(y, Transpose(A), x) + A_mul_B!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = mul!(y, A, x) + A_mul_B!(y::StridedVector{Complex{Float32}}, A::StridedVecOrMat{Complex{Float32}}, x::StridedVector{Float32}) = mul!(y, A, x) + A_mul_B!(y::StridedVector{Complex{Float64}}, A::StridedVecOrMat{Complex{Float64}}, x::StridedVector{Float64}) = mul!(y, A, x) + A_mul_B!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasFloat} = mul!(y, A, x) + A_mul_Bt(a::AbstractVector, B::AbstractMatrix) = *(a, Transpose(B)) + A_mul_Bt(A::AbstractMatrix, b::AbstractVector) = *(A, Transpose(b)) + A_mul_Bc(a::AbstractVector, B::AbstractMatrix) = *(a, Adjoint(B)) + A_mul_Bc(A::AbstractMatrix, b::AbstractVector) = *(A, Adjoint(b)) + At_mul_B(x::StridedVector{T}, y::StridedVector{T}) where {T<:BlasComplex} = *(Transpose(x), y) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/triangular.jl, to deprecate +@eval Base.LinAlg begin + A_mul_Bc(A::AbstractTriangular, B::AbstractTriangular) = *(A, Adjoint(B)) + A_mul_Bt(A::AbstractTriangular, B::AbstractTriangular) = *(A, Transpose(B)) + Ac_mul_B(A::AbstractTriangular, B::AbstractTriangular) = *(Adjoint(A), B) + At_mul_B(A::AbstractTriangular, B::AbstractTriangular) = *(Transpose(A), B) + Ac_ldiv_B(A::Union{UpperTriangular,LowerTriangular}, B::RowVector) = \(Adjoint(A), B) + Ac_ldiv_B(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::RowVector) = \(Adjoint(A), B) + At_ldiv_B(A::Union{UpperTriangular,LowerTriangular}, B::RowVector) = \(Transpose(A), B) + At_ldiv_B(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::RowVector) = \(Transpose(A), B) + A_rdiv_Bc(rowvec::RowVector, A::Union{UpperTriangular,LowerTriangular}) = /(rowvec, Adjoint(A)) + A_rdiv_Bc(rowvec::RowVector, A::Union{UnitUpperTriangular,UnitLowerTriangular}) = /(rowvec, Adjoint(A)) + A_rdiv_Bt(rowvec::RowVector, A::Union{UpperTriangular,LowerTriangular}) = /(rowvec, Transpose(A)) + A_rdiv_Bt(rowvec::RowVector, A::Union{UnitUpperTriangular,UnitLowerTriangular}) = /(rowvec, Transpose(A)) + A_mul_Bt(rowvec::RowVector, A::AbstractTriangular) = *(rowvec, Transpose(A)) + A_mul_Bt(A::AbstractTriangular, rowvec::RowVector) = *(A, Transpose(rowvec)) + At_mul_Bt(A::AbstractTriangular, rowvec::RowVector) = *(Transpose(A), Transpose(rowvec)) + A_mul_Bc(rowvec::RowVector, A::AbstractTriangular) = *(rowvec, Adjoint(A)) + A_mul_Bc(A::AbstractTriangular, rowvec::RowVector) = *(A, Adjoint(rowvec)) + Ac_mul_Bc(A::AbstractTriangular, rowvec::RowVector) = *(Adjoint(A), Adjoint(rowvec)) + Ac_mul_B(A::AbstractMatrix, B::AbstractTriangular) = *(Adjoint(A), B) + At_mul_B(A::AbstractMatrix, B::AbstractTriangular) = *(Transpose(A), B) + A_mul_Bc(A::AbstractTriangular, B::AbstractMatrix) = *(A, Adjoint(B)) + A_mul_Bt(A::AbstractTriangular, B::AbstractMatrix) = *(A, Transpose(B)) + Ac_mul_Bc(A::AbstractTriangular, B::AbstractTriangular) = *(Adjoint(A), Adjoint(B)) + Ac_mul_Bc(A::AbstractTriangular, B::AbstractMatrix) = *(Adjoint(A), Adjoint(B)) + Ac_mul_Bc(A::AbstractMatrix, B::AbstractTriangular) = *(Adjoint(A), Adjoint(B)) + At_mul_Bt(A::AbstractTriangular, B::AbstractTriangular) = *(Transpose(A), Transpose(B)) + At_mul_Bt(A::AbstractTriangular, B::AbstractMatrix) = *(Transpose(A), Transpose(B)) + At_mul_Bt(A::AbstractMatrix, B::AbstractTriangular) = *(Transpose(A), Transpose(B)) + A_mul_Bc!(A::UpperTriangular, B::Union{LowerTriangular,UnitLowerTriangular}) = mul!(A, Adjoint(B)) + A_mul_Bc!(A::LowerTriangular, B::Union{UpperTriangular,UnitUpperTriangular}) = mul!(A, Adjoint(B)) + A_mul_Bt!(A::UpperTriangular, B::Union{LowerTriangular,UnitLowerTriangular}) = mul!(A, Transpose(B)) + A_mul_Bt!(A::LowerTriangular, B::Union{UpperTriangular,UnitUpperTriangular}) = mul!(A, Transpose(B)) + A_rdiv_Bc!(A::UpperTriangular, B::Union{LowerTriangular,UnitLowerTriangular}) = rdiv!(A, Adjoint(B)) + A_rdiv_Bc!(A::LowerTriangular, B::Union{UpperTriangular,UnitUpperTriangular}) = rdiv!(A, Adjoint(B)) + A_rdiv_Bt!(A::UpperTriangular, B::Union{LowerTriangular,UnitLowerTriangular}) = rdiv!(A, Transpose(B)) + A_rdiv_Bt!(A::LowerTriangular, B::Union{UpperTriangular,UnitUpperTriangular}) = rdiv!(A, Transpose(B)) + A_rdiv_B!(A::UpperTriangular, B::Union{UpperTriangular,UnitUpperTriangular}) = rdiv!(A, B) + A_rdiv_B!(A::LowerTriangular, B::Union{LowerTriangular,UnitLowerTriangular}) = rdiv!(A, B) + Ac_mul_B!(A::Union{LowerTriangular,UnitLowerTriangular}, B::UpperTriangular) = mul!(Adjoint(A), B) + Ac_mul_B!(A::Union{UpperTriangular,UnitUpperTriangular}, B::LowerTriangular) = mul!(Adjoint(A), B) + At_mul_B!(A::Union{LowerTriangular,UnitLowerTriangular}, B::UpperTriangular) = mul!(Transpose(A), B) + At_mul_B!(A::Union{UpperTriangular,UnitUpperTriangular}, B::LowerTriangular) = mul!(Transpose(A), B) + Ac_ldiv_B!(A::Union{LowerTriangular,UnitLowerTriangular}, B::UpperTriangular) = ldiv!(Adjoint(A), B) + Ac_ldiv_B!(A::Union{UpperTriangular,UnitUpperTriangular}, B::LowerTriangular) = ldiv!(Adjoint(A), B) + At_ldiv_B!(A::Union{LowerTriangular,UnitLowerTriangular}, B::UpperTriangular) = ldiv!(Transpose(A), B) + At_ldiv_B!(A::Union{UpperTriangular,UnitUpperTriangular}, B::LowerTriangular) = ldiv!(Transpose(A), B) + A_rdiv_Bt!(A::StridedMatrix, B::UnitLowerTriangular) = rdiv!(A, Transpose(B)) + A_rdiv_Bt!(A::StridedMatrix, B::LowerTriangular) = rdiv!(A, Transpose(B)) + A_rdiv_Bt!(A::StridedMatrix, B::UnitUpperTriangular) = rdiv!(A, Transpose(B)) + A_rdiv_Bt!(A::StridedMatrix, B::UpperTriangular) = rdiv!(A, Transpose(B)) + A_rdiv_Bc!(A::StridedMatrix, B::UnitLowerTriangular) = rdiv!(A, Adjoint(B)) + A_rdiv_Bc!(A::StridedMatrix, B::LowerTriangular) = rdiv!(A, Adjoint(B)) + A_rdiv_Bc!(A::StridedMatrix, B::UnitUpperTriangular) = rdiv!(A, Adjoint(B)) + A_rdiv_Bc!(A::StridedMatrix, B::UpperTriangular) = rdiv!(A, Adjoint(B)) + A_rdiv_B!(A::StridedMatrix, B::UnitLowerTriangular) = rdiv!(A, B) + A_rdiv_B!(A::StridedMatrix, B::LowerTriangular) = rdiv!(A, B) + A_rdiv_B!(A::StridedMatrix, B::UnitUpperTriangular) = rdiv!(A, B) + A_rdiv_B!(A::StridedMatrix, B::UpperTriangular) = rdiv!(A, B) + Ac_ldiv_B!(A::UnitUpperTriangular, b::AbstractVector, x::AbstractVector = b) = ldiv!(Adjoint(A), b, x) + Ac_ldiv_B!(A::UpperTriangular, b::AbstractVector, x::AbstractVector = b) = ldiv!(Adjoint(A), b, x) + Ac_ldiv_B!(A::UnitLowerTriangular, b::AbstractVector, x::AbstractVector = b) = ldiv!(Adjoint(A), b, x) + Ac_ldiv_B!(A::LowerTriangular, b::AbstractVector, x::AbstractVector = b) = ldiv!(Adjoint(A), b, x) + At_ldiv_B!(A::UnitUpperTriangular, b::AbstractVector, x::AbstractVector = b) = ldiv!(Transpose(A), b, x) + At_ldiv_B!(A::UpperTriangular, b::AbstractVector, x::AbstractVector = b) = ldiv!(Transpose(A), b, x) + At_ldiv_B!(A::UnitLowerTriangular, b::AbstractVector, x::AbstractVector = b) = ldiv!(Transpose(A), b, x) + At_ldiv_B!(A::LowerTriangular, b::AbstractVector, x::AbstractVector = b) = ldiv!(Transpose(A), b, x) + A_mul_Bt!(A::StridedMatrix, B::UnitLowerTriangular) = mul!(A, Transpose(B)) + A_mul_Bt!(A::StridedMatrix, B::LowerTriangular) = mul!(A, Transpose(B)) + A_mul_Bt!(A::StridedMatrix, B::UnitUpperTriangular) = mul!(A, Transpose(B)) + A_mul_Bt!(A::StridedMatrix, B::UpperTriangular) = mul!(A, Transpose(B)) + A_mul_Bc!(A::StridedMatrix, B::UnitLowerTriangular) = mul!(A, Adjoint(B)) + A_mul_Bc!(A::StridedMatrix, B::LowerTriangular) = mul!(A, Adjoint(B)) + A_mul_Bc!(A::StridedMatrix, B::UnitUpperTriangular) = mul!(A, Adjoint(B)) + A_mul_Bc!(A::StridedMatrix, B::UpperTriangular) = mul!(A, Adjoint(B)) + A_mul_B!(A::StridedMatrix, B::UnitLowerTriangular) = mul!(A, B) + A_mul_B!(A::StridedMatrix, B::LowerTriangular) = mul!(A, B) + A_mul_B!(A::StridedMatrix, B::UnitUpperTriangular) = mul!(A, B) + A_mul_B!(A::StridedMatrix, B::UpperTriangular) = mul!(A, B) + At_mul_B!(A::UnitLowerTriangular, B::StridedVecOrMat) = mul!(Transpose(A), B) + At_mul_B!(A::LowerTriangular, B::StridedVecOrMat) = mul!(Transpose(A), B) + At_mul_B!(A::UnitUpperTriangular, B::StridedVecOrMat) = mul!(Transpose(A), B) + At_mul_B!(A::UpperTriangular, B::StridedVecOrMat) = mul!(Transpose(A), B) + Ac_mul_B!(A::UnitLowerTriangular, B::StridedVecOrMat) = mul!(Adjoint(A), B) + Ac_mul_B!(A::LowerTriangular, B::StridedVecOrMat) = mul!(Adjoint(A), B) + Ac_mul_B!(A::UnitUpperTriangular, B::StridedVecOrMat) = mul!(Adjoint(A), B) + Ac_mul_B!(A::UpperTriangular, B::StridedVecOrMat) = mul!(Adjoint(A), B) + A_mul_B!(A::UnitLowerTriangular, B::StridedVecOrMat) = mul!(A, B) + A_mul_B!(A::LowerTriangular, B::StridedVecOrMat) = mul!(A, B) + A_mul_B!(A::UnitUpperTriangular, B::StridedVecOrMat) = mul!(A, B) + A_mul_B!(A::UpperTriangular, B::StridedVecOrMat) = mul!(A, B) + A_mul_B!(C::AbstractVector , A::AbstractTriangular, B::AbstractVector) = mul!(C, A, B) + A_mul_B!(C::AbstractMatrix , A::AbstractTriangular, B::AbstractVecOrMat) = mul!(C, A, B) + A_mul_B!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = mul!(C, A, B) + Ac_mul_B!(C::AbstractVector , A::AbstractTriangular, B::AbstractVector) = mul!(C, Adjoint(A), B) + Ac_mul_B!(C::AbstractMatrix , A::AbstractTriangular, B::AbstractVecOrMat) = mul!(C, Adjoint(A), B) + Ac_mul_B!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = mul!(C, Adjoint(A), B) + At_mul_B!(C::AbstractVector , A::AbstractTriangular, B::AbstractVector) = mul!(C, Transpose(A), B) + At_mul_B!(C::AbstractMatrix , A::AbstractTriangular, B::AbstractVecOrMat) = mul!(C, Transpose(A), B) + At_mul_B!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = mul!(C, Transpose(A), B) + A_mul_B!(A::Tridiagonal, B::AbstractTriangular) = mul!(A, B) + A_mul_B!(C::AbstractMatrix, A::AbstractTriangular, B::Tridiagonal) = mul!(C, A, B) + A_mul_B!(C::AbstractMatrix, A::Tridiagonal, B::AbstractTriangular) = mul!(C, A, B) + A_mul_Bt!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = mul!(C, A, Transpose(B)) + A_mul_Bc!(C::AbstractMatrix, A::AbstractTriangular, B::AbstractVecOrMat) = mul!(C, A, Adjoint(B)) + A_mul_Bc!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = mul!(C, A, Adjoint(B)) +end +for mat in (:AbstractVector, :AbstractMatrix) + @eval Base.LinAlg begin + Ac_mul_B(A::AbstractTriangular, B::$mat) = *(Adjoint(A), B) + At_mul_B(A::AbstractTriangular, B::$mat) = *(Transpose(A), B) + Ac_ldiv_B(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::$mat) = \(Adjoint(A), B) + At_ldiv_B(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::$mat) = \(Transpose(A), B) + Ac_ldiv_B(A::Union{UpperTriangular,LowerTriangular}, B::$mat) = \(Adjoint(A), B) + At_ldiv_B(A::Union{UpperTriangular,LowerTriangular}, B::$mat) = \(Transpose(A), B) + A_rdiv_Bc(A::$mat, B::Union{UnitUpperTriangular, UnitLowerTriangular}) = /(A, Adjoint(B)) + A_rdiv_Bt(A::$mat, B::Union{UnitUpperTriangular, UnitLowerTriangular}) = /(A, Transpose(B)) + A_rdiv_Bc(A::$mat, B::Union{UpperTriangular,LowerTriangular}) = /(A, Adjoint(B)) + A_rdiv_Bt(A::$mat, B::Union{UpperTriangular,LowerTriangular}) = /(A, Transpose(B)) + end +end +@eval Base.LinAlg begin + A_mul_Bc(A::AbstractMatrix, B::AbstractTriangular) = *(A, Adjoint(B)) + A_mul_Bt(A::AbstractMatrix, B::AbstractTriangular) = *(A, Transpose(B)) +end +for (f, op, transform) in ( + (:A_mul_Bc, :*, :Adjoint), + (:A_mul_Bt, :*, :Transpose), + (:A_rdiv_Bc, :/, :Adjoint), + (:A_rdiv_Bt, :/, :Transpose)) + @eval Base.LinAlg begin + $f(A::LowerTriangular, B::UpperTriangular) = ($op)(A, ($transform)(B)) + $f(A::LowerTriangular, B::UnitUpperTriangular) = ($op)(A, ($transform)(B)) + $f(A::UpperTriangular, B::LowerTriangular) = ($op)(A, ($transform)(B)) + $f(A::UpperTriangular, B::UnitLowerTriangular) = ($op)(A, ($transform)(B)) + end +end +for (f, op, transform) in ( + (:Ac_mul_B, :*, :Adjoint), + (:At_mul_B, :*, :Transpose), + (:Ac_ldiv_B, :\, :Adjoint), + (:At_ldiv_B, :\, :Transpose)) + @eval Base.LinAlg begin + ($f)(A::UpperTriangular, B::LowerTriangular) = ($op)(($transform)(A), B) + ($f)(A::UnitUpperTriangular, B::LowerTriangular) = ($op)(($transform)(A), B) + ($f)(A::LowerTriangular, B::UpperTriangular) = ($op)(($transform)(A), B) + ($f)(A::UnitLowerTriangular, B::UpperTriangular) = ($op)(($transform)(A), B) + end +end +for (t, uploc, isunitc) in ((:LowerTriangular, 'L', 'N'), + (:UnitLowerTriangular, 'L', 'U'), + (:UpperTriangular, 'U', 'N'), + (:UnitUpperTriangular, 'U', 'U')) + @eval Base.LinAlg begin + # Vector multiplication + A_mul_B!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasFloat} = mul!(A, b) + At_mul_B!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasFloat} = mul!(Transpose(A), b) + Ac_mul_B!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasReal} = mul!(Adjoint(A), b) + Ac_mul_B!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasComplex} = mul!(Adjoint(A), b) + + # Matrix multiplication + A_mul_B!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = mul!(A, B) + A_mul_B!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = mul!(A, B) + + At_mul_B!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = mul!(Transpose(A), B) + Ac_mul_B!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasComplex} = mul!(Adjoint(A), B) + Ac_mul_B!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasReal} = mul!(Adjoint(A), B) + + A_mul_Bt!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = mul!(A, Transpose(B)) + A_mul_Bc!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasComplex} = mul!(A, Adjoint(B)) + A_mul_Bc!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasReal} = mul!(A, Adjoint(B)) + + # Left division + A_ldiv_B!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = ldiv!(A, B) + At_ldiv_B!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = ldiv!(Transpose(A), B) + Ac_ldiv_B!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasReal} = ldiv!(Adjoint(A), B) + Ac_ldiv_B!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = ldiv!(Adjoint(A), B) + + # Right division + A_rdiv_B!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = rdiv!(A, B) + A_rdiv_Bt!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = rdiv!(A, Transpose(B)) + A_rdiv_Bc!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasReal} = rdiv!(A, Adjoint(B)) + A_rdiv_Bc!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasComplex} = rdiv!(A, Adjoint(B)) + end +end +@eval Base.LinAlg begin + """ + A_ldiv_B!([Y,] A, B) -> Y + + Compute `A \\ B` in-place and store the result in `Y`, returning the result. + If only two arguments are passed, then `A_ldiv_B!(A, B)` overwrites `B` with + the result. + + The argument `A` should *not* be a matrix. Rather, instead of matrices it should be a + factorization object (e.g. produced by [`factorize`](@ref) or [`cholfact`](@ref)). + The reason for this is that factorization itself is both expensive and typically allocates memory + (although it can also be done in-place via, e.g., [`lufact!`](@ref)), + and performance-critical situations requiring `A_ldiv_B!` usually also require fine-grained + control over the factorization of `A`. + """ + A_ldiv_B! + + """ + Ac_ldiv_B!([Y,] A, B) -> Y + + Similar to [`A_ldiv_B!`](@ref), but return ``Aᴴ`` \\ ``B``, + computing the result in-place in `Y` (or overwriting `B` if `Y` is not supplied). + """ + Ac_ldiv_B! + + """ + At_ldiv_B!([Y,] A, B) -> Y + + Similar to [`A_ldiv_B!`](@ref), but return ``Aᵀ`` \\ ``B``, + computing the result in-place in `Y` (or overwriting `B` if `Y` is not supplied). + """ + At_ldiv_B! +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/sparse/linalg.jl, to deprecate +@eval Base.SparseArrays begin + using Base.LinAlg: Adjoint, Transpose + Ac_ldiv_B(A::SparseMatrixCSC, B::RowVector) = \(Adjoint(A), B) + At_ldiv_B(A::SparseMatrixCSC, B::RowVector) = \(Transpose(A), B) + Ac_ldiv_B(A::SparseMatrixCSC, B::AbstractVecOrMat) = \(Adjoint(A), B) + At_ldiv_B(A::SparseMatrixCSC, B::AbstractVecOrMat) = \(Transpose(A), B) + A_rdiv_Bc!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where {T} = rdiv!(A, Adjoint(D)) + A_rdiv_Bt!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where {T} = rdiv!(A, Transpose(D)) + A_rdiv_B!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where {T} = rdiv!(A, D) + A_ldiv_B!(L::LowerTriangular{T,<:SparseMatrixCSCUnion{T}}, B::StridedVecOrMat) where {T} = ldiv!(L, B) + A_ldiv_B!(U::UpperTriangular{T,<:SparseMatrixCSCUnion{T}}, B::StridedVecOrMat) where {T} = ldiv!(U, B) + A_mul_Bt(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = *(A, Transpose(B)) + A_mul_Bc(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = *(A, Adjoint(B)) + At_mul_B(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = *(Transpose(A), B) + Ac_mul_B(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = *(Adjoint(A), B) + At_mul_Bt(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = *(Transpose(A), Transpose(B)) + Ac_mul_Bc(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = *(Adjoint(A), Adjoint(B)) + A_mul_B!(C::StridedVecOrMat, A::SparseMatrixCSC, B::StridedVecOrMat) = mul!(C, A, B) + Ac_mul_B!(C::StridedVecOrMat, A::SparseMatrixCSC, B::StridedVecOrMat) = mul!(C, Adjoint(A), B) + At_mul_B!(C::StridedVecOrMat, A::SparseMatrixCSC, B::StridedVecOrMat) = mul!(C, Transpose(A), B) + A_mul_B!(α::Number, A::SparseMatrixCSC, B::StridedVecOrMat, β::Number, C::StridedVecOrMat) = mul!(α, A, B, β, C) + A_mul_B(A::SparseMatrixCSC{TA,S}, x::StridedVector{Tx}) where {TA,S,Tx} = *(A, x) + A_mul_B(A::SparseMatrixCSC{TA,S}, B::StridedMatrix{Tx}) where {TA,S,Tx} = *(A, B) + Ac_mul_B!(α::Number, A::SparseMatrixCSC, B::StridedVecOrMat, β::Number, C::StridedVecOrMat) = mul!(α, Adjoint(A), B, β, C) + Ac_mul_B(A::SparseMatrixCSC{TA,S}, x::StridedVector{Tx}) where {TA,S,Tx} = *(Adjoint(A), x) + Ac_mul_B(A::SparseMatrixCSC{TA,S}, B::StridedMatrix{Tx}) where {TA,S,Tx} = *(Adjoint(A), B) + At_mul_B!(α::Number, A::SparseMatrixCSC, B::StridedVecOrMat, β::Number, C::StridedVecOrMat) = mul!(α, Transpose(A), B, β, C) + At_mul_B(A::SparseMatrixCSC{TA,S}, x::StridedVector{Tx}) where {TA,S,Tx} = *(Transpose(A), x) + At_mul_B(A::SparseMatrixCSC{TA,S}, B::StridedMatrix{Tx}) where {TA,S,Tx} = *(Transpose(A), B) + A_mul_Bt(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} = *(A, Transpose(B)) + A_mul_Bc(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} = *(A, Adjoint(B)) + At_mul_B(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} = *(Transpose(A), B) + Ac_mul_B(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} = *(Adjoint(A),B) + At_mul_Bt(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} = *(Transpose(A), Transpose(B)) + Ac_mul_Bc(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} = *(Adjoint(A), Adjoint(B)) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/sparse/sparsevector.jl, to deprecate +for isunittri in (true, false), islowertri in (true, false) + unitstr = isunittri ? "Unit" : "" + halfstr = islowertri ? "Lower" : "Upper" + tritype = :(Base.LinAlg.$(Symbol(unitstr, halfstr, "Triangular"))) + @eval Base.SparseArrays begin + using Base.LinAlg: Adjoint, Transpose + At_ldiv_B(A::$tritype{TA,<:AbstractMatrix}, b::SparseVector{Tb}) where {TA<:Number,Tb<:Number} = \(Transpose(A), b) + At_ldiv_B(A::$tritype{TA,<:StridedMatrix}, b::SparseVector{Tb}) where {TA<:Number,Tb<:Number} = \(Transpose(A), b) + At_ldiv_B(A::$tritype, b::SparseVector) = \(Transpose(A), b) + Ac_ldiv_B(A::$tritype{TA,<:AbstractMatrix}, b::SparseVector{Tb}) where {TA<:Number,Tb<:Number} = \(Adjoint(A), b) + Ac_ldiv_B(A::$tritype{TA,<:StridedMatrix}, b::SparseVector{Tb}) where {TA<:Number,Tb<:Number} = \(Adjoint(A), b) + Ac_ldiv_B(A::$tritype, b::SparseVector) = \(Adjoint(A), b) + A_ldiv_B!(A::$tritype{<:Any,<:StridedMatrix}, b::SparseVector) = ldiv!(A, b) + At_ldiv_B!(A::$tritype{<:Any,<:StridedMatrix}, b::SparseVector) = ldiv!(Transpose(A), b) + Ac_ldiv_B!(A::$tritype{<:Any,<:StridedMatrix}, b::SparseVector) = ldiv!(Adjoint(A), b) + end +end +@eval Base.SparseArrays begin + using Base.LinAlg: Adjoint, Transpose + Ac_mul_B(A::SparseMatrixCSC, x::AbstractSparseVector) = *(Adjoint(A), x) + At_mul_B(A::SparseMatrixCSC, x::AbstractSparseVector) = *(Transpose(A), x) + Ac_mul_B!(α::Number, A::SparseMatrixCSC, x::AbstractSparseVector, β::Number, y::StridedVector) = mul!(α, Adjoint(A), x, β, y) + Ac_mul_B!(y::StridedVector{Ty}, A::SparseMatrixCSC, x::AbstractSparseVector{Tx}) where {Tx,Ty} = mul!(y, Adjoint(A), x) + At_mul_B!(α::Number, A::SparseMatrixCSC, x::AbstractSparseVector, β::Number, y::StridedVector) = mul!(α, Transpose(A), x, β, y) + At_mul_B!(y::StridedVector{Ty}, A::SparseMatrixCSC, x::AbstractSparseVector{Tx}) where {Tx,Ty} = mul!(y, Transpose(A), x) + A_mul_B!(α::Number, A::SparseMatrixCSC, x::AbstractSparseVector, β::Number, y::StridedVector) = mul!(α, A, x, β, y) + A_mul_B!(y::StridedVector{Ty}, A::SparseMatrixCSC, x::AbstractSparseVector{Tx}) where {Tx,Ty} = mul!(y, A, x) + At_mul_B!(α::Number, A::StridedMatrix, x::AbstractSparseVector, β::Number, y::StridedVector) = mul!(α, Transpose(A), x, β, y) + At_mul_B!(y::StridedVector{Ty}, A::StridedMatrix, x::AbstractSparseVector{Tx}) where {Tx,Ty} = mul!(y, Transpose(A), x) + At_mul_B(A::StridedMatrix{Ta}, x::AbstractSparseVector{Tx}) where {Ta,Tx} = *(Transpose(A), x) + A_mul_B!(α::Number, A::StridedMatrix, x::AbstractSparseVector, β::Number, y::StridedVector) = mul!(α, A, x, β, y) + A_mul_B!(y::StridedVector{Ty}, A::StridedMatrix, x::AbstractSparseVector{Tx}) where {Tx,Ty} = mul!(y, A, x) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/rowvector.jl, to deprecate +@eval Base.LinAlg begin + A_rdiv_Bt(rowvec::RowVector, mat::AbstractMatrix) = /(rowvec, Transpose(mat)) + A_rdiv_Bc(rowvec::RowVector, mat::AbstractMatrix) = /(rowvec, Adjoint(mat)) + At_ldiv_B(mat::AbstractMatrix, rowvec::RowVector) = \(Transpose(mat), rowvec) + Ac_ldiv_B(mat::AbstractMatrix, rowvec::RowVector) = \(Adjoint(mat), rowvec) + Ac_mul_B(u::RowVector, v::AbstractVector) = *(Adjoint(u), v) + Ac_mul_B(vec::AbstractVector, mat::AbstractMatrix) = *(Adjoint(vec), mat) + Ac_mul_B(rowvec1::RowVector, rowvec2::RowVector) = *(Adjoint(rowvec1), rowvec2) + Ac_mul_B(vec::AbstractVector, rowvec::RowVector) = *(Adjoint(vec), rowvec) + Ac_mul_B(vec1::AbstractVector, vec2::AbstractVector) = *(Adjoint(vec1), vec2) + Ac_mul_Bc(rowvec::RowVector, vec::AbstractVector) = *(Adjoint(rowvec), Adjoint(vec)) + Ac_mul_Bc(vec::AbstractVector, mat::AbstractMatrix) = *(Adjoint(vec), Adjoint(mat)) + Ac_mul_Bc(rowvec1::RowVector, rowvec2::RowVector) = *(Adjoint(rowvec1), Adjoint(rowvec2)) + Ac_mul_Bc(vec::AbstractVector, rowvec::RowVector) = *(Adjoint(vec), Adjoint(rowvec)) + Ac_mul_Bc(vec::AbstractVector, rowvec::AbstractVector) = *(Adjoint(vec), Adjoint(rowvec)) + Ac_mul_Bc(mat::AbstractMatrix, rowvec::RowVector) = *(Adjoint(mat), Adjoint(rowvec)) + A_mul_Bc(u::RowVector, v::AbstractVector) = *(u, Adjoint(v)) + A_mul_Bc(rowvec::RowVector, mat::AbstractMatrix) = *(rowvec, Adjoint(mat)) + A_mul_Bc(rowvec1::RowVector, rowvec2::RowVector) = *(rowvec1, Adjoint(rowvec2)) + A_mul_Bc(vec::AbstractVector, rowvec::RowVector) = *(vec, Adjoint(rowvec)) + A_mul_Bc(vec1::AbstractVector, vec2::AbstractVector) = *(vec1, Adjoint(vec2)) + A_mul_Bc(mat::AbstractMatrix, rowvec::RowVector) = *(mat, Adjoint(rowvec)) + At_mul_B(v::RowVector, u::AbstractVector) = *(Transpose(v), u) + At_mul_B(vec::AbstractVector, mat::AbstractMatrix) = *(Transpose(vec), mat) + At_mul_B(rowvec1::RowVector, rowvec2::RowVector) = *(Transpose(rowvec1), rowvec2) + At_mul_B(vec::AbstractVector, rowvec::RowVector) = *(Transpose(vec), rowvec) + At_mul_B(vec1::AbstractVector{T}, vec2::AbstractVector{T}) where {T<:Real} = *(Transpose(vec1), vec2) + At_mul_B(vec1::AbstractVector, vec2::AbstractVector) = *(Transpose(vec1), vec2) + At_mul_Bt(rowvec::RowVector, vec::AbstractVector) = *(Transpose(rowvec), Transpose(vec)) + At_mul_Bt(vec::AbstractVector, mat::AbstractMatrix) = *(Transpose(vec), Transpose(mat)) + At_mul_Bt(rowvec1::RowVector, rowvec2::RowVector) = *(Transpose(rowvec1), Transpose(rowvec2)) + At_mul_Bt(vec::AbstractVector, rowvec::RowVector) = *(Transpose(vec), Transpose(rowvec)) + At_mul_Bt(vec::AbstractVector, rowvec::AbstractVector) = *(Transpose(vec), Transpose(rowvec)) + At_mul_Bt(mat::AbstractMatrix, rowvec::RowVector) = *(Transpose(mat), Transpose(rowvec)) + A_mul_Bt(v::RowVector, A::AbstractVector) = *(v, Transpose(A)) + A_mul_Bt(rowvec::RowVector, mat::AbstractMatrix) = *(rowvec, Transpose(mat)) + A_mul_Bt(rowvec1::RowVector, rowvec2::RowVector) = *(rowvec1, Transpose(rowvec2)) + A_mul_Bt(vec::AbstractVector, rowvec::RowVector) = *(vec, Transpose(rowvec)) + A_mul_Bt(vec1::AbstractVector, vec2::AbstractVector) = *(vec1, Transpose(vec2)) + A_mul_Bt(mat::AbstractMatrix, rowvec::RowVector) = *(mat, Transpose(rowvec)) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/linalg/givens.jl, to deprecate +@eval Base.LinAlg begin + A_mul_Bc!(A::AbstractMatrix, R::Rotation) = mul!(A, Adjoint(R)) + A_mul_B!(R::Rotation, A::AbstractMatrix) = mul!(R, A) + A_mul_B!(G::Givens, R::Rotation) = mul!(G, R) + A_mul_Bc!(A::AbstractMatrix, G::Givens) = mul!(A, Adjoint(G)) + A_mul_B!(G::Givens, A::AbstractVecOrMat) = mul!(G, A) + A_mul_B!(G1::Givens, G2::Givens) = mul!(G1, G2) + A_mul_Bc(A::AbstractVecOrMat{T}, R::AbstractRotation{S}) where {T,S} = *(A, Adjoint(R)) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from base/operators.jl, to deprecate +@eval Base begin + using Base.LinAlg: Adjoint, Transpose + """ + Ac_ldiv_Bt(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ`` \\ ``Bᵀ``. + """ + Ac_ldiv_Bt(a,b) = \(Adjoint(a), Transpose(b)) + """ + At_ldiv_Bt(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ`` \\ ``Bᵀ``. + """ + At_ldiv_Bt(a,b) = \(Transpose(a), Transpose(b)) + """ + A_ldiv_Bt(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``A`` \\ ``Bᵀ``. + """ + A_ldiv_Bt(a,b) = \(a, Transpose(b)) + """ + At_ldiv_B(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ`` \\ ``B``. + """ + At_ldiv_B(a,b) = \(Transpose(a), b) + """ + Ac_ldiv_Bc(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ`` \\ ``Bᴴ``. + """ + Ac_ldiv_Bc(a,b) = \(Adjoint(a), Adjoint(b)) + """ + A_ldiv_Bc(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``A`` \\ ``Bᴴ``. + """ + A_ldiv_Bc(a,b) = \(a, Adjoint(b)) + """ + Ac_ldiv_B(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ`` \\ ``B``. + """ + Ac_ldiv_B(a,b) = \(Adjoint(a), b) + """ + At_rdiv_Bt(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ / Bᵀ``. + """ + At_rdiv_Bt(a,b) = /(Transpose(a), Transpose(b)) + """ + A_rdiv_Bt(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``A / Bᵀ``. + """ + A_rdiv_Bt(a,b) = /(a, Transpose(b)) + """ + At_rdiv_B(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ / B``. + """ + At_rdiv_B(a,b) = /(Transpose(a), b) + """ + Ac_rdiv_Bc(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ / Bᴴ``. + """ + Ac_rdiv_Bc(a,b) = /(Adjoint(a), Adjoint(b)) + """ + A_rdiv_Bc(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``A / Bᴴ``. + """ + A_rdiv_Bc(a,b) = /(a, Adjoint(b)) + """ + Ac_rdiv_B(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ / B``. + """ + Ac_rdiv_B(a,b) = /(Adjoint(a), b) + """ + At_mul_Bt(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ⋅Bᵀ``. + """ + At_mul_Bt(a,b) = *(Transpose(a), Transpose(b)) + """ + A_mul_Bt(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``A⋅Bᵀ``. + """ + A_mul_Bt(a,b) = *(a, Transpose(b)) + """ + At_mul_B(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ⋅B``. + """ + At_mul_B(a,b) = *(Transpose(a), b) + """ + Ac_mul_Bc(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ Bᴴ``. + """ + Ac_mul_Bc(a,b) = *(Adjoint(a), Adjoint(b)) + """ + A_mul_Bc(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``A⋅Bᴴ``. + """ + A_mul_Bc(a,b) = *(a, Adjoint(b)) + """ + Ac_mul_B(A, B) + + For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ⋅B``. + """ + Ac_mul_B(a,b) = *(Adjoint(a), b) +end + +# re. A_mul_B deprecation, don't forget to: +# 1) delete function shims in base/linalg/linalg.jl + # issue #24822 @deprecate_binding Display AbstractDisplay diff --git a/base/linalg/adjtrans.jl b/base/linalg/adjtrans.jl new file mode 100644 index 0000000000000..d9e931d278fa6 --- /dev/null +++ b/base/linalg/adjtrans.jl @@ -0,0 +1,120 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +using Base: @pure, @propagate_inbounds, _return_type, _default_type, _isleaftype, @_inline_meta +import Base: length, size, indices, IndexStyle, getindex, setindex!, parent, vec, convert, similar + +### basic definitions (types, aliases, constructors, abstractarray interface, sundry similar) + +# note that Adjoint and Transpose must be able to wrap not only vectors and matrices +# but also factorizations, rotations, and other linear algebra objects, including +# user-defined such objects. so do not restrict the wrapped type. +struct Adjoint{T,S} <: AbstractMatrix{T} + parent::S + function Adjoint{T,S}(A::S) where {T,S} + checkeltype(Adjoint, T, eltype(A)) + new(A) + end +end +struct Transpose{T,S} <: AbstractMatrix{T} + parent::S + function Transpose{T,S}(A::S) where {T,S} + checkeltype(Transpose, T, eltype(A)) + new(A) + end +end + +@pure function checkeltype(::Type{Transform}, ::Type{ResultEltype}, ::Type{ParentEltype}) where {Transform, ResultEltype, ParentEltype} + if ResultEltype !== transformtype(Transform, ParentEltype) + error(string("Element type mismatch. Tried to create an `$Transform{$ResultEltype}` ", + "from an object with eltype `$ParentEltype`, but the element type of the ", + "`$Transform` of an object with eltype `$ParentEltype` must be ", + "`$(transformtype(Transform, ParentEltype))`")) + end + return nothing +end +function transformtype(::Type{O}, ::Type{S}) where {O,S} + # similar to promote_op(::Any, ::Type) + @_inline_meta + T = _return_type(O, Tuple{_default_type(S)}) + _isleaftype(S) && return _isleaftype(T) ? T : Any + return typejoin(S, T) +end + +# basic outer constructors +Adjoint(A) = Adjoint{transformtype(Adjoint,eltype(A)),typeof(A)}(A) +Transpose(A) = Transpose{transformtype(Transpose,eltype(A)),typeof(A)}(A) + +# numbers are the end of the line +Adjoint(x::Number) = adjoint(x) +Transpose(x::Number) = transpose(x) + +# unwrapping constructors +# perhaps slightly odd, but necessary (at least till adjoint and transpose names are free) +Adjoint(A::Adjoint) = A.parent +Transpose(A::Transpose) = A.parent + +# some aliases for internal convenience use +const AdjOrTrans{T,S} = Union{Adjoint{T,S},Transpose{T,S}} where {T,S} +const AdjOrTransAbsVec{T} = AdjOrTrans{T,<:AbstractVector} +const AdjOrTransAbsMat{T} = AdjOrTrans{T,<:AbstractMatrix} + +# for internal use below +wrappertype(A::Adjoint) = Adjoint +wrappertype(A::Transpose) = Transpose +wrappertype(::Type{<:Adjoint}) = Adjoint +wrappertype(::Type{<:Transpose}) = Transpose + +# AbstractArray interface, basic definitions +length(A::AdjOrTrans) = length(A.parent) +size(v::AdjOrTransAbsVec) = (1, length(v.parent)) +size(A::AdjOrTransAbsMat) = reverse(size(A.parent)) +indices(v::AdjOrTransAbsVec) = (Base.OneTo(1), indices(v.parent)...) +indices(A::AdjOrTransAbsMat) = reverse(indices(A.parent)) +IndexStyle(::Type{<:AdjOrTransAbsVec}) = IndexLinear() +IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() +@propagate_inbounds getindex(v::AdjOrTransAbsVec, i::Int) = wrappertype(v)(v.parent[i]) +@propagate_inbounds getindex(A::AdjOrTransAbsMat, i::Int, j::Int) = wrappertype(A)(A.parent[j, i]) +@propagate_inbounds setindex!(v::AdjOrTransAbsVec, x, i::Int) = (setindex!(v.parent, wrappertype(v)(x), i); v) +@propagate_inbounds setindex!(A::AdjOrTransAbsMat, x, i::Int, j::Int) = (setindex!(A.parent, wrappertype(A)(x), j, i); A) +# AbstractArray interface, additional definitions to retain wrapper over vectors where appropriate +@propagate_inbounds getindex(v::AdjOrTransAbsVec, ::Colon, is::AbstractArray{Int}) = wrappertype(v)(v.parent[is]) +@propagate_inbounds getindex(v::AdjOrTransAbsVec, ::Colon, ::Colon) = wrappertype(v)(v.parent[:]) + +# 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)) + +# for vectors, the semantics of the wrapped and unwrapped types differ +# so attempt to maintain both the parent and wrapper type insofar as possible +similar(A::AdjOrTransAbsVec) = wrappertype(A)(similar(A.parent)) +similar(A::AdjOrTransAbsVec, ::Type{T}) where {T} = wrappertype(A)(similar(A.parent, transformtype(wrappertype(A), T))) +# for matrices, the semantics of the wrapped and unwrapped types are generally the same +# and as you are allocating with similar anyway, you might as well get something unwrapped +similar(A::AdjOrTrans) = similar(A.parent, eltype(A), size(A)) +similar(A::AdjOrTrans, ::Type{T}) where {T} = similar(A.parent, T, size(A)) +similar(A::AdjOrTrans, ::Type{T}, dims::Dims{N}) where {T,N} = similar(A.parent, T, dims) + +# sundry basic definitions +parent(A::AdjOrTrans) = A.parent +vec(v::AdjOrTransAbsVec) = v.parent + + +### linear algebra + +# definitions necessary for test/linalg/rowvector.jl to pass +# should be cleaned up / revised as necessary in the future +/(A::Transpose{<:Any,<:Vector}, B::Matrix) = /(transpose(A.parent), B) +/(A::Transpose{<:Any,<:Vector}, B::Transpose{<:Any,<:Matrix}) = /(transpose(A.parent), B) +*(A::Adjoint{<:Any,<:Matrix}, B::Adjoint{<:Any,<:Vector}) = *(adjoint(A.parent), adjoint(B.parent)) + + +# dismabiguation methods +*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractVector}) = transpose(A.parent) * B +*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractMatrix}) = transpose(A.parent) * B +*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractVector}) = A * adjoint(B.parent) +*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractMatrix}) = transpose(A.parent) * B +*(A::Adjoint{<:Any,<:AbstractVector}, B::Transpose{<:Any,<:AbstractVector}) = adjoint(A.parent) * B +*(A::Adjoint{<:Any,<:AbstractVector}, B::Transpose{<:Any,<:AbstractMatrix}) = adjoint(A.parent) * B +*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractVector}) = A * adjoint(B.parent) +*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:AbstractVector}) = A * transpose(B.parent) +*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:AbstractMatrix}) = adjoint(A.parent) * B \ No newline at end of file diff --git a/base/linalg/bidiag.jl b/base/linalg/bidiag.jl index 305d914cc057e..f9f173c7e4ac0 100644 --- a/base/linalg/bidiag.jl +++ b/base/linalg/bidiag.jl @@ -325,25 +325,33 @@ end const BiTriSym = Union{Bidiagonal,Tridiagonal,SymTridiagonal} const BiTri = Union{Bidiagonal,Tridiagonal} -A_mul_B!(C::AbstractMatrix, A::SymTridiagonal, B::BiTriSym) = A_mul_B_td!(C, A, B) -A_mul_B!(C::AbstractMatrix, A::BiTri, B::BiTriSym) = A_mul_B_td!(C, A, B) -A_mul_B!(C::AbstractMatrix, A::BiTriSym, B::BiTriSym) = A_mul_B_td!(C, A, B) -A_mul_B!(C::AbstractMatrix, A::AbstractTriangular, B::BiTriSym) = A_mul_B_td!(C, A, B) -A_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::BiTriSym) = A_mul_B_td!(C, A, B) -A_mul_B!(C::AbstractMatrix, A::Diagonal, B::BiTriSym) = A_mul_B_td!(C, A, B) -A_mul_B!(C::AbstractVector, A::BiTri, B::AbstractVector) = A_mul_B_td!(C, A, B) -A_mul_B!(C::AbstractMatrix, A::BiTri, B::AbstractVecOrMat) = A_mul_B_td!(C, A, B) -A_mul_B!(C::AbstractVecOrMat, A::BiTri, B::AbstractVecOrMat) = A_mul_B_td!(C, A, B) - -\(::Diagonal, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) -\(::Bidiagonal, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) -\(::Bidiagonal{<:Number}, ::RowVector{<:Number}) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) - -At_ldiv_B(::Bidiagonal, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) -At_ldiv_B(::Bidiagonal{<:Number}, ::RowVector{<:Number}) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) - -Ac_ldiv_B(::Bidiagonal, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) -Ac_ldiv_B(::Bidiagonal{<:Number}, ::RowVector{<:Number}) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) +mul!(C::AbstractMatrix, A::SymTridiagonal, B::BiTriSym) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::BiTri, B::BiTriSym) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::BiTriSym, B::BiTriSym) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::AbstractTriangular, B::BiTriSym) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::AbstractMatrix, B::BiTriSym) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::Diagonal, B::BiTriSym) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:Diagonal}, B::BiTriSym) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::Transpose{<:Any,<:Diagonal}, B::BiTriSym) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:AbstractTriangular}, B::BiTriSym) = A_mul_B_td!(C, A, B) +mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractTriangular}, B::BiTriSym) = A_mul_B_td!(C, A, B) +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::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))) + +\(::Diagonal, ::RowVector) = _mat_ldiv_rowvec_error() +\(::Bidiagonal, ::RowVector) = _mat_ldiv_rowvec_error() +\(::Bidiagonal{<:Number}, ::RowVector{<:Number}) = _mat_ldiv_rowvec_error() +\(::Adjoint{<:Any,<:Bidiagonal}, ::RowVector) = _mat_ldiv_rowvec_error() +\(::Transpose{<:Any,<:Bidiagonal}, ::RowVector) = _mat_ldiv_rowvec_error() +\(::Adjoint{<:Number,<:Bidiagonal{<:Number}}, ::RowVector{<:Number}) = _mat_ldiv_rowvec_error() +\(::Transpose{<:Number,<:Bidiagonal{<:Number}}, ::RowVector{<:Number}) = _mat_ldiv_rowvec_error() +_mat_ldiv_rowvec_error() = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) function check_A_mul_B!_sizes(C, A, B) nA, mA = size(A) @@ -375,7 +383,7 @@ end function A_mul_B_td!(C::AbstractMatrix, A::BiTriSym, B::BiTriSym) check_A_mul_B!_sizes(C, A, B) n = size(A,1) - n <= 3 && return A_mul_B!(C, Array(A), Array(B)) + n <= 3 && return mul!(C, Array(A), Array(B)) fill!(C, zero(eltype(C))) Al = _diag(A, -1) Ad = _diag(A, 0) @@ -434,7 +442,7 @@ function A_mul_B_td!(C::AbstractVecOrMat, A::BiTriSym, B::AbstractVecOrMat) if size(C,2) != nB throw(DimensionMismatch("A has second dimension $nA, B has $(size(B,2)), C has $(size(C,2)) but all must match")) end - nA <= 3 && return A_mul_B!(C, Array(A), Array(B)) + nA <= 3 && return mul!(C, Array(A), Array(B)) l = _diag(A, -1) d = _diag(A, 0) u = _diag(A, 1) @@ -455,7 +463,7 @@ end function A_mul_B_td!(C::AbstractMatrix, A::AbstractMatrix, B::BiTriSym) check_A_mul_B!_sizes(C, A, B) n = size(A,1) - n <= 3 && return A_mul_B!(C, Array(A), Array(B)) + n <= 3 && return mul!(C, Array(A), Array(B)) m = size(B,2) Bl = _diag(B, -1) Bd = _diag(B, 0) @@ -489,15 +497,17 @@ const SpecialMatrix = Union{Bidiagonal,SymTridiagonal,Tridiagonal} *(A::SpecialMatrix, B::SpecialMatrix) = Array(A) * Array(B) #Generic multiplication -for func in (:*, :Ac_mul_B, :A_mul_Bc, :/, :A_rdiv_Bc) - @eval ($func)(A::Bidiagonal{T}, B::AbstractVector{T}) where {T} = ($func)(Array(A), B) -end +*(A::Bidiagonal{T}, B::AbstractVector{T}) where {T} = *(Array(A), B) +*(adjA::Adjoint{<:Any,<:Bidiagonal{T}}, B::AbstractVector{T}) where {T} = *(Adjoint(Array(adjA.parent)), B) +*(A::Bidiagonal{T}, adjB::Adjoint{<:Any,<:AbstractVector{T}}) where {T} = *(Array(A), Adjoint(adjB.parent)) +/(A::Bidiagonal{T}, B::AbstractVector{T}) where {T} = /(Array(A), B) +/(A::Bidiagonal{T}, adjB::Adjoint{<:Any,<:AbstractVector{T}}) where {T} = /(Array(A), Adjoint(adjB.parent)) #Linear solvers -A_ldiv_B!(A::Union{Bidiagonal, AbstractTriangular}, b::AbstractVector) = naivesub!(A, b) -At_ldiv_B!(A::Bidiagonal, b::AbstractVector) = A_ldiv_B!(transpose(A), b) -Ac_ldiv_B!(A::Bidiagonal, b::AbstractVector) = A_ldiv_B!(adjoint(A), b) -function A_ldiv_B!(A::Union{Bidiagonal,AbstractTriangular}, B::AbstractMatrix) +ldiv!(A::Union{Bidiagonal, AbstractTriangular}, b::AbstractVector) = naivesub!(A, b) +ldiv!(transA::Transpose{<:Any,<:Bidiagonal}, b::AbstractVector) = ldiv!(transpose(transA.parent), b) +ldiv!(adjA::Adjoint{<:Any,<:Bidiagonal}, b::AbstractVector) = ldiv!(adjoint(adjA.parent), b) +function ldiv!(A::Union{Bidiagonal,AbstractTriangular}, B::AbstractMatrix) nA,mA = size(A) tmp = similar(B,size(B,1)) n = size(B, 1) @@ -506,26 +516,40 @@ function A_ldiv_B!(A::Union{Bidiagonal,AbstractTriangular}, B::AbstractMatrix) end for i = 1:size(B,2) copy!(tmp, 1, B, (i - 1)*n + 1, n) - A_ldiv_B!(A, tmp) + ldiv!(A, tmp) copy!(B, (i - 1)*n + 1, tmp, 1, n) # Modify this when array view are implemented. end B end -for func in (:Ac_ldiv_B!, :At_ldiv_B!) - @eval function ($func)(A::Union{Bidiagonal,AbstractTriangular}, B::AbstractMatrix) - nA,mA = size(A) - tmp = similar(B,size(B,1)) - n = size(B, 1) - if mA != n - throw(DimensionMismatch("size of A' is ($mA,$nA), corresponding dimension of B is $n")) - end - for i = 1:size(B,2) - copy!(tmp, 1, B, (i - 1)*n + 1, n) - ($func)(A, tmp) - copy!(B, (i - 1)*n + 1, tmp, 1, n) # Modify this when array view are implemented. - end - B +function ldiv!(adjA::Adjoint{<:Any,<:Union{Bidiagonal,AbstractTriangular}}, B::AbstractMatrix) + A = adjA.parent + nA,mA = size(A) + tmp = similar(B,size(B,1)) + n = size(B, 1) + if mA != n + throw(DimensionMismatch("size of A' is ($mA,$nA), corresponding dimension of B is $n")) end + for i = 1:size(B,2) + copy!(tmp, 1, B, (i - 1)*n + 1, n) + ldiv!(Adjoint(A), tmp) + copy!(B, (i - 1)*n + 1, tmp, 1, n) # Modify this when array view are implemented. + end + B +end +function ldiv!(transA::Transpose{<:Any,<:Union{Bidiagonal,AbstractTriangular}}, B::AbstractMatrix) + A = transA.parent + nA,mA = size(A) + tmp = similar(B,size(B,1)) + n = size(B, 1) + if mA != n + throw(DimensionMismatch("size of A' is ($mA,$nA), corresponding dimension of B is $n")) + end + for i = 1:size(B,2) + copy!(tmp, 1, B, (i - 1)*n + 1, n) + ldiv!(Transpose(A), tmp) + copy!(B, (i - 1)*n + 1, tmp, 1, n) # Modify this when array view are implemented. + end + B end #Generic solver using naive substitution function naivesub!(A::Bidiagonal{T}, b::AbstractVector, x::AbstractVector = b) where T @@ -550,15 +574,26 @@ function naivesub!(A::Bidiagonal{T}, b::AbstractVector, x::AbstractVector = b) w end ### Generic promotion methods and fallbacks -for (f,g) in ((:\, :A_ldiv_B!), (:At_ldiv_B, :At_ldiv_B!), (:Ac_ldiv_B, :Ac_ldiv_B!)) - @eval begin - function ($f)(A::Bidiagonal{TA}, B::AbstractVecOrMat{TB}) where {TA<:Number,TB<:Number} - TAB = typeof((zero(TA)*zero(TB) + zero(TA)*zero(TB))/one(TA)) - ($g)(convert(AbstractArray{TAB}, A), copy_oftype(B, TAB)) - end - ($f)(A::Bidiagonal, B::AbstractVecOrMat) = ($g)(A, copy(B)) - end +function \(A::Bidiagonal{<:Number}, B::AbstractVecOrMat{<:Number}) + TA, TB = eltype(A), eltype(B) + TAB = typeof((zero(TA)*zero(TB) + zero(TA)*zero(TB))/one(TA)) + ldiv!(convert(AbstractArray{TAB}, A), copy_oftype(B, TAB)) +end +\(A::Bidiagonal, B::AbstractVecOrMat) = ldiv!(A, copy(B)) +function \(transA::Transpose{<:Number,<:Bidiagonal{<:Number}}, B::AbstractVecOrMat{<:Number}) + A = transA.parent + TA, TB = eltype(A), eltype(B) + TAB = typeof((zero(TA)*zero(TB) + zero(TA)*zero(TB))/one(TA)) + ldiv!(Transpose(convert(AbstractArray{TAB}, A)), copy_oftype(B, TAB)) +end +\(transA::Transpose{<:Any,<:Bidiagonal}, B::AbstractVecOrMat) = ldiv!(Transpose(transA.parent), copy(B)) +function \(adjA::Adjoint{<:Number,<:Bidiagonal{<:Number}}, B::AbstractVecOrMat{<:Number}) + A = adjA.parent + TA, TB = eltype(A), eltype(B) + TAB = typeof((zero(TA)*zero(TB) + zero(TA)*zero(TB))/one(TA)) + ldiv!(Adjoint(convert(AbstractArray{TAB}, A)), copy_oftype(B, TAB)) end +\(adjA::Adjoint{<:Any,<:Bidiagonal}, B::AbstractVecOrMat) = ldiv!(Adjoint(adjA.parent), copy(B)) factorize(A::Bidiagonal) = A diff --git a/base/linalg/bunchkaufman.jl b/base/linalg/bunchkaufman.jl index cc1d4f32011d3..e856d6b742e06 100644 --- a/base/linalg/bunchkaufman.jl +++ b/base/linalg/bunchkaufman.jl @@ -254,7 +254,7 @@ function inv(B::BunchKaufman{<:BlasComplex}) end end -function A_ldiv_B!(B::BunchKaufman{T}, R::StridedVecOrMat{T}) where T<:BlasReal +function ldiv!(B::BunchKaufman{T}, R::StridedVecOrMat{T}) where T<:BlasReal if !issuccess(B) throw(SingularException(B.info)) end @@ -265,7 +265,7 @@ function A_ldiv_B!(B::BunchKaufman{T}, R::StridedVecOrMat{T}) where T<:BlasReal LAPACK.sytrs!(B.uplo, B.LD, B.ipiv, R) end end -function A_ldiv_B!(B::BunchKaufman{T}, R::StridedVecOrMat{T}) where T<:BlasComplex +function ldiv!(B::BunchKaufman{T}, R::StridedVecOrMat{T}) where T<:BlasComplex if !issuccess(B) throw(SingularException(B.info)) end @@ -285,9 +285,9 @@ function A_ldiv_B!(B::BunchKaufman{T}, R::StridedVecOrMat{T}) where T<:BlasCompl end end # There is no fallback solver for Bunch-Kaufman so we'll have to promote to same element type -function A_ldiv_B!(B::BunchKaufman{T}, R::StridedVecOrMat{S}) where {T,S} +function ldiv!(B::BunchKaufman{T}, R::StridedVecOrMat{S}) where {T,S} TS = promote_type(T,S) - return A_ldiv_B!(convert(BunchKaufman{TS}, B), convert(AbstractArray{TS}, R)) + return ldiv!(convert(BunchKaufman{TS}, B), convert(AbstractArray{TS}, R)) end function logabsdet(F::BunchKaufman) diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index 938a066027c13..bfaec7a83476b 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -419,22 +419,22 @@ function show(io::IO, mime::MIME{Symbol("text/plain")}, C::CholeskyPivoted{<:Any show(io, mime, C[:p]) end -A_ldiv_B!(C::Cholesky{T,<:AbstractMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = +ldiv!(C::Cholesky{T,<:AbstractMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = @assertposdef LAPACK.potrs!(C.uplo, C.factors, B) C.info -function A_ldiv_B!(C::Cholesky{<:Any,<:AbstractMatrix}, B::StridedVecOrMat) +function ldiv!(C::Cholesky{<:Any,<:AbstractMatrix}, B::StridedVecOrMat) if C.uplo == 'L' - return Ac_ldiv_B!(LowerTriangular(C.factors), A_ldiv_B!(LowerTriangular(C.factors), B)) + return ldiv!(Adjoint(LowerTriangular(C.factors)), ldiv!(LowerTriangular(C.factors), B)) else - return A_ldiv_B!(UpperTriangular(C.factors), Ac_ldiv_B!(UpperTriangular(C.factors), B)) + return ldiv!(UpperTriangular(C.factors), ldiv!(Adjoint(UpperTriangular(C.factors)), B)) end end -function A_ldiv_B!(C::CholeskyPivoted{T}, B::StridedVector{T}) where T<:BlasFloat +function ldiv!(C::CholeskyPivoted{T}, B::StridedVector{T}) where T<:BlasFloat chkfullrank(C) ipermute!(LAPACK.potrs!(C.uplo, C.factors, permute!(B, C.piv)), C.piv) end -function A_ldiv_B!(C::CholeskyPivoted{T}, B::StridedMatrix{T}) where T<:BlasFloat +function ldiv!(C::CholeskyPivoted{T}, B::StridedMatrix{T}) where T<:BlasFloat chkfullrank(C) n = size(C, 1) for i=1:size(B, 2) @@ -447,23 +447,23 @@ function A_ldiv_B!(C::CholeskyPivoted{T}, B::StridedMatrix{T}) where T<:BlasFloa B end -function A_ldiv_B!(C::CholeskyPivoted, B::StridedVector) +function ldiv!(C::CholeskyPivoted, B::StridedVector) if C.uplo == 'L' - Ac_ldiv_B!(LowerTriangular(C.factors), - A_ldiv_B!(LowerTriangular(C.factors), B[C.piv]))[invperm(C.piv)] + ldiv!(Adjoint(LowerTriangular(C.factors)), + ldiv!(LowerTriangular(C.factors), B[C.piv]))[invperm(C.piv)] else - A_ldiv_B!(UpperTriangular(C.factors), - Ac_ldiv_B!(UpperTriangular(C.factors), B[C.piv]))[invperm(C.piv)] + ldiv!(UpperTriangular(C.factors), + ldiv!(Adjoint(UpperTriangular(C.factors)), B[C.piv]))[invperm(C.piv)] end end -function A_ldiv_B!(C::CholeskyPivoted, B::StridedMatrix) +function ldiv!(C::CholeskyPivoted, B::StridedMatrix) if C.uplo == 'L' - Ac_ldiv_B!(LowerTriangular(C.factors), - A_ldiv_B!(LowerTriangular(C.factors), B[C.piv,:]))[invperm(C.piv),:] + ldiv!(Adjoint(LowerTriangular(C.factors)), + ldiv!(LowerTriangular(C.factors), B[C.piv,:]))[invperm(C.piv),:] else - A_ldiv_B!(UpperTriangular(C.factors), - Ac_ldiv_B!(UpperTriangular(C.factors), B[C.piv,:]))[invperm(C.piv),:] + ldiv!(UpperTriangular(C.factors), + ldiv!(Adjoint(UpperTriangular(C.factors)), B[C.piv,:]))[invperm(C.piv),:] end end diff --git a/base/linalg/dense.jl b/base/linalg/dense.jl index aafe437d80a20..1adbfc683ce78 100644 --- a/base/linalg/dense.jl +++ b/base/linalg/dense.jl @@ -1400,9 +1400,9 @@ function sylvester(A::StridedMatrix{T},B::StridedMatrix{T},C::StridedMatrix{T}) RA, QA = schur(A) RB, QB = schur(B) - D = -Ac_mul_B(QA,C*QB) + D = -(Adjoint(QA) * (C*QB)) Y, scale = LAPACK.trsyl!('N','N', RA, RB, D) - scale!(QA*A_mul_Bc(Y,QB), inv(scale)) + scale!(QA*(Y * Adjoint(QB)), inv(scale)) end sylvester(A::StridedMatrix{T}, B::StridedMatrix{T}, C::StridedMatrix{T}) where {T<:Integer} = sylvester(float(A), float(B), float(C)) @@ -1443,9 +1443,9 @@ julia> A*X + X*A' + B function lyap(A::StridedMatrix{T}, C::StridedMatrix{T}) where {T<:BlasFloat} R, Q = schur(A) - D = -Ac_mul_B(Q,C*Q) + D = -(Adjoint(Q) * (C*Q)) Y, scale = LAPACK.trsyl!('N', T <: Complex ? 'C' : 'T', R, R, D) - scale!(Q*A_mul_Bc(Y,Q), inv(scale)) + scale!(Q*(Y * Adjoint(Q)), inv(scale)) end lyap(A::StridedMatrix{T}, C::StridedMatrix{T}) where {T<:Integer} = lyap(float(A), float(C)) lyap(a::T, c::T) where {T<:Number} = -c/(2a) diff --git a/base/linalg/diagonal.jl b/base/linalg/diagonal.jl index 31032e5b59c61..a6f70e68dc252 100644 --- a/base/linalg/diagonal.jl +++ b/base/linalg/diagonal.jl @@ -150,110 +150,153 @@ end (*)(Da::Diagonal, Db::Diagonal) = Diagonal(Da.diag .* Db.diag) (*)(D::Diagonal, V::AbstractVector) = D.diag .* V -(*)(A::AbstractTriangular, D::Diagonal) = A_mul_B!(copy(A), D) -(*)(D::Diagonal, B::AbstractTriangular) = A_mul_B!(D, copy(B)) +(*)(A::AbstractTriangular, D::Diagonal) = mul!(copy(A), D) +(*)(D::Diagonal, B::AbstractTriangular) = mul!(D, copy(B)) (*)(A::AbstractMatrix, D::Diagonal) = scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag)), size(A)), A, D.diag) (*)(D::Diagonal, A::AbstractMatrix) = scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag)), size(A)), D.diag, A) -A_mul_B!(A::Union{LowerTriangular,UpperTriangular}, D::Diagonal) = - typeof(A)(A_mul_B!(A.data, D)) -function A_mul_B!(A::UnitLowerTriangular, D::Diagonal) - A_mul_B!(A.data, D) +mul!(A::Union{LowerTriangular,UpperTriangular}, D::Diagonal) = typeof(A)(mul!(A.data, D)) +function mul!(A::UnitLowerTriangular, D::Diagonal) + mul!(A.data, D) for i = 1:size(A, 1) A.data[i,i] = D.diag[i] end LowerTriangular(A.data) end -function A_mul_B!(A::UnitUpperTriangular, D::Diagonal) - A_mul_B!(A.data, D) +function mul!(A::UnitUpperTriangular, D::Diagonal) + mul!(A.data, D) for i = 1:size(A, 1) A.data[i,i] = D.diag[i] end UpperTriangular(A.data) end -function A_mul_B!(D::Diagonal, B::UnitLowerTriangular) - A_mul_B!(D, B.data) +function mul!(D::Diagonal, B::UnitLowerTriangular) + mul!(D, B.data) for i = 1:size(B, 1) B.data[i,i] = D.diag[i] end LowerTriangular(B.data) end -function A_mul_B!(D::Diagonal, B::UnitUpperTriangular) - A_mul_B!(D, B.data) +function mul!(D::Diagonal, B::UnitUpperTriangular) + mul!(D, B.data) for i = 1:size(B, 1) B.data[i,i] = D.diag[i] end UpperTriangular(B.data) end -Ac_mul_B(D::Diagonal, B::Diagonal) = Diagonal(adjoint.(D.diag) .* B.diag) -Ac_mul_B(A::AbstractTriangular, D::Diagonal) = A_mul_B!(adjoint(A), D) -function Ac_mul_B(A::AbstractMatrix, D::Diagonal) +*(adjD::Adjoint{<:Any,<:Diagonal}, B::Diagonal) = (D = adjD.parent; Diagonal(adjoint.(D.diag) .* B.diag)) +*(adjA::Adjoint{<:Any,<:AbstractTriangular}, D::Diagonal) = (A = adjA.parent; mul!(adjoint(A), D)) +function *(adjA::Adjoint{<:Any,<:AbstractMatrix}, D::Diagonal) + A = adjA.parent Ac = similar(A, promote_op(*, eltype(A), eltype(D.diag)), (size(A, 2), size(A, 1))) adjoint!(Ac, A) - A_mul_B!(Ac, D) + mul!(Ac, D) end -At_mul_B(D::Diagonal, B::Diagonal) = Diagonal(transpose.(D.diag) .* B.diag) -At_mul_B(A::AbstractTriangular, D::Diagonal) = A_mul_B!(transpose(A), D) -function At_mul_B(A::AbstractMatrix, D::Diagonal) +*(transD::Transpose{<:Any,<:Diagonal}, B::Diagonal) = (D = transD.parent; Diagonal(transpose.(D.diag) .* B.diag)) +*(transA::Transpose{<:Any,<:AbstractTriangular}, D::Diagonal) = (A = transA.parent; mul!(transpose(A), D)) +function *(transA::Transpose{<:Any,<:AbstractMatrix}, D::Diagonal) + A = transA.parent At = similar(A, promote_op(*, eltype(A), eltype(D.diag)), (size(A, 2), size(A, 1))) transpose!(At, A) - A_mul_B!(At, D) + mul!(At, D) end -A_mul_Bc(D::Diagonal, B::Diagonal) = Diagonal(D.diag .* adjoint.(B.diag)) -A_mul_Bc(D::Diagonal, B::AbstractTriangular) = A_mul_B!(D, adjoint(B)) -A_mul_Bc(D::Diagonal, Q::Union{Base.LinAlg.QRCompactWYQ,Base.LinAlg.QRPackedQ}) = A_mul_Bc!(Array(D), Q) -function A_mul_Bc(D::Diagonal, A::AbstractMatrix) +*(D::Diagonal, adjB::Adjoint{<:Any,<:Diagonal}) = (B = adjB.parent; Diagonal(D.diag .* adjoint.(B.diag))) +*(D::Diagonal, adjB::Adjoint{<:Any,<:AbstractTriangular}) = (B = adjB.parent; mul!(D, adjoint(B))) +*(D::Diagonal, adjQ::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) = (Q = adjQ.parent; mul!(Array(D), Adjoint(Q))) +function *(D::Diagonal, adjA::Adjoint{<:Any,<:AbstractMatrix}) + A = adjA.parent Ac = similar(A, promote_op(*, eltype(A), eltype(D.diag)), (size(A, 2), size(A, 1))) adjoint!(Ac, A) - A_mul_B!(D, Ac) + mul!(D, Ac) end -A_mul_Bt(D::Diagonal, B::Diagonal) = Diagonal(D.diag .* transpose.(B.diag)) -A_mul_Bt(D::Diagonal, B::AbstractTriangular) = A_mul_B!(D, transpose(B)) -function A_mul_Bt(D::Diagonal, A::AbstractMatrix) +*(D::Diagonal, transB::Transpose{<:Any,<:Diagonal}) = (B = transB.parent; Diagonal(D.diag .* transpose.(B.diag))) +*(D::Diagonal, transB::Transpose{<:Any,<:AbstractTriangular}) = (B = transB.parent; mul!(D, transpose(B))) +function *(D::Diagonal, transA::Transpose{<:Any,<:AbstractMatrix}) + A = transA.parent At = similar(A, promote_op(*, eltype(A), eltype(D.diag)), (size(A, 2), size(A, 1))) transpose!(At, A) - A_mul_B!(D, At) + mul!(D, At) end -Ac_mul_Bc(D::Diagonal, B::Diagonal) = Diagonal(adjoint.(D.diag) .* adjoint.(B.diag)) -At_mul_Bt(D::Diagonal, B::Diagonal) = Diagonal(transpose.(D.diag) .* transpose.(B.diag)) - -A_mul_B!(A::Diagonal,B::Diagonal) = throw(MethodError(A_mul_B!, Tuple{Diagonal,Diagonal})) -At_mul_B!(A::Diagonal,B::Diagonal) = throw(MethodError(At_mul_B!, Tuple{Diagonal,Diagonal})) -Ac_mul_B!(A::Diagonal,B::Diagonal) = throw(MethodError(Ac_mul_B!, Tuple{Diagonal,Diagonal})) -A_mul_B!(A::Base.LinAlg.QRPackedQ, D::Diagonal) = throw(MethodError(A_mul_B!, Tuple{Diagonal,Diagonal})) -A_mul_B!(A::Diagonal,B::AbstractMatrix) = scale!(A.diag,B) -At_mul_B!(A::Diagonal,B::AbstractMatrix) = scale!(A.diag,B) -Ac_mul_B!(A::Diagonal,B::AbstractMatrix) = scale!(conj(A.diag),B) -A_mul_B!(A::AbstractMatrix,B::Diagonal) = scale!(A,B.diag) -A_mul_Bt!(A::AbstractMatrix,B::Diagonal) = scale!(A,B.diag) -A_mul_Bc!(A::AbstractMatrix,B::Diagonal) = scale!(A,conj(B.diag)) +*(adjD::Adjoint{<:Any,<:Diagonal}, adjB::Adjoint{<:Any,<:Diagonal}) = + (D = adjD.parent; B = adjB.parent; Diagonal(adjoint.(D.diag) .* adjoint.(B.diag))) +*(transD::Transpose{<:Any,<:Diagonal}, transB::Transpose{<:Any,<:Diagonal}) = + (D = transD.parent; B = transB.parent; Diagonal(transpose.(D.diag) .* transpose.(B.diag))) + +mul!(A::Diagonal, B::Diagonal) = throw(MethodError(mul!, Tuple{Diagonal,Diagonal})) +mul!(A::QRPackedQ, D::Diagonal) = throw(MethodError(mul!, Tuple{Diagonal,Diagonal})) +mul!(A::QRPackedQ, B::Adjoint{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(A::QRPackedQ, B::Transpose{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(A::Adjoint{<:Any,<:QRPackedQ}, B::Diagonal) = throw(MethodError(mul!, (A, B))) +mul!(A::Adjoint{<:Any,<:QRPackedQ}, B::Adjoint{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(A::Adjoint{<:Any,<:QRPackedQ}, B::Transpose{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(A::Diagonal, B::Adjoint{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(A::Diagonal, B::Transpose{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(A::Adjoint{<:Any,<:Diagonal}, B::Adjoint{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(A::Adjoint{<:Any,<:Diagonal}, B::Transpose{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(A::Transpose{<:Any,<:Diagonal}, B::Adjoint{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(A::Transpose{<:Any,<:Diagonal}, B::Transpose{<:Any,<:Diagonal}) = throw(MethodError(mul!, (A, B))) +mul!(transA::Transpose{<:Any,<:Diagonal}, B::Diagonal) = + throw(MethodError(mul!, Tuple{Transpose{<:Any,<:Diagonal},Diagonal})) +mul!(adjA::Adjoint{<:Any,<:Diagonal}, B::Diagonal) = + throw(MethodError(mul!, Tuple{Adjoint{<:Any,<:Diagonal},Diagonal})) +mul!(A::Diagonal, B::AbstractMatrix) = scale!(A.diag, B) +mul!(adjA::Adjoint{<:Any,<:Diagonal}, B::AbstractMatrix) = (A = adjA.parent; scale!(conj(A.diag),B)) +mul!(transA::Transpose{<:Any,<:Diagonal}, B::AbstractMatrix) = (A = transA.parent; scale!(A.diag,B)) +mul!(A::AbstractMatrix, B::Diagonal) = scale!(A,B.diag) +mul!(A::AbstractMatrix, adjB::Adjoint{<:Any,<:Diagonal}) = (B = adjB.parent; scale!(A,conj(B.diag))) +mul!(A::AbstractMatrix, transB::Transpose{<:Any,<:Diagonal}) = (B = transB.parent; scale!(A,B.diag)) # Get ambiguous method if try to unify AbstractVector/AbstractMatrix here using AbstractVecOrMat -A_mul_B!(out::AbstractVector, A::Diagonal, in::AbstractVector) = out .= A.diag .* in -Ac_mul_B!(out::AbstractVector, A::Diagonal, in::AbstractVector) = out .= adjoint.(A.diag) .* in -At_mul_B!(out::AbstractVector, A::Diagonal, in::AbstractVector) = out .= transpose.(A.diag) .* in +mul!(out::AbstractVector, A::Diagonal, in::AbstractVector) = out .= A.diag .* in +mul!(out::AbstractVector, adjA::Adjoint{<:Any,<:Diagonal}, in::AbstractVector) = + (A = adjA.parent; out .= adjoint.(A.diag) .* in) +mul!(out::AbstractVector, transA::Transpose{<:Any,<:Diagonal}, in::AbstractVector) = + (A = transA.parent; out .= transpose.(A.diag) .* in) + +mul!(out::AbstractMatrix, A::Diagonal, in::AbstractMatrix) = out .= A.diag .* in +mul!(out::AbstractMatrix, adjA::Adjoint{<:Any,<:Diagonal}, in::AbstractMatrix) = + (A = adjA.parent; out .= adjoint.(A.diag) .* in) +mul!(out::AbstractMatrix, transA::Transpose{<:Any,<:Diagonal}, in::AbstractMatrix) = + (A = transA.parent; out .= transpose.(A.diag) .* in) + +mul!(C::AbstractMatrix, A::Diagonal, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, adjoint(B.parent)) +mul!(C::AbstractMatrix, A::Diagonal, B::Transpose{<:Any,<:AbstractVecOrMat}) = mul!(C, A, transpose(B.parent)) +mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:Diagonal}, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, adjoint(B.parent)) +mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:Diagonal}, B::Transpose{<:Any,<:AbstractVecOrMat}) = mul!(C, A, transpose(B.parent)) +mul!(C::AbstractMatrix, A::Transpose{<:Any,<:Diagonal}, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, adjoint(B.parent)) +mul!(C::AbstractMatrix, A::Transpose{<:Any,<:Diagonal}, B::Transpose{<:Any,<:AbstractVecOrMat}) = mul!(C, A, transpose(B.parent)) -A_mul_B!(out::AbstractMatrix, A::Diagonal, in::AbstractMatrix) = out .= A.diag .* in -Ac_mul_B!(out::AbstractMatrix, A::Diagonal, in::AbstractMatrix) = out .= adjoint.(A.diag) .* in -At_mul_B!(out::AbstractMatrix, A::Diagonal, in::AbstractMatrix) = out .= transpose.(A.diag) .* in # ambiguities with Symmetric/Hermitian # RealHermSymComplex[Sym]/[Herm] only include Number; invariant to [c]transpose -A_mul_Bt(A::Diagonal, B::RealHermSymComplexSym) = A*B -At_mul_B(A::RealHermSymComplexSym, B::Diagonal) = A*B -A_mul_Bc(A::Diagonal, B::RealHermSymComplexHerm) = A*B -Ac_mul_B(A::RealHermSymComplexHerm, B::Diagonal) = A*B +*(A::Diagonal, transB::Transpose{<:Any,<:RealHermSymComplexSym}) = A * transB.parent +*(transA::Transpose{<:Any,<:RealHermSymComplexSym}, B::Diagonal) = transA.parent * B +*(A::Diagonal, adjB::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * adjB.parent +*(adjA::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Diagonal) = adjA.parent * B +*(transA::Transpose{<:Any,<:RealHermSymComplexSym}, transD::Transpose{<:Any,<:Diagonal}) = transA.parent * transD +*(transD::Transpose{<:Any,<:Diagonal}, transA::Transpose{<:Any,<:RealHermSymComplexSym}) = transD * transA.parent +*(adjA::Adjoint{<:Any,<:RealHermSymComplexHerm}, adjD::Adjoint{<:Any,<:Diagonal}) = adjA.parent * adjD +*(adjD::Adjoint{<:Any,<:Diagonal}, adjA::Adjoint{<:Any,<:RealHermSymComplexHerm}) = adjD * adjA.parent +mul!(C::AbstractMatrix, adjA::Adjoint{<:Any,<:Diagonal}, adjB::Adjoint{<:Any,<:RealHermSymComplexHerm}) = + mul!(C, adjA, adjB.parent) +mul!(C::AbstractMatrix, transA::Transpose{<:Any,<:Diagonal}, transB::Transpose{<:Any,<:RealHermSymComplexSym}) = + mul!(C, transA, transB.parent) +mul!(C::AbstractMatrix, adjA::Adjoint{<:Any,<:Diagonal}, adjB::Adjoint{<:Any,<:RealHermSymComplexSym}) = + (A = adjA.parent; C .= adjoint.(A.diag) .* adjB) +mul!(C::AbstractMatrix, transA::Transpose{<:Any,<:Diagonal}, transB::Transpose{<:Any,<:RealHermSymComplexHerm}) = + (A = transA.parent; C .= transpose.(A.diag) .* transB) + (/)(Da::Diagonal, Db::Diagonal) = Diagonal(Da.diag ./ Db.diag) -function A_ldiv_B!(D::Diagonal{T}, v::AbstractVector{T}) where {T} +function ldiv!(D::Diagonal{T}, v::AbstractVector{T}) where {T} if length(v) != length(D.diag) throw(DimensionMismatch("diagonal matrix is $(length(D.diag)) by $(length(D.diag)) but right hand side has $(length(v)) rows")) end @@ -266,7 +309,7 @@ function A_ldiv_B!(D::Diagonal{T}, v::AbstractVector{T}) where {T} end v end -function A_ldiv_B!(D::Diagonal{T}, V::AbstractMatrix{T}) where {T} +function ldiv!(D::Diagonal{T}, V::AbstractMatrix{T}) where {T} if size(V,1) != length(D.diag) throw(DimensionMismatch("diagonal matrix is $(length(D.diag)) by $(length(D.diag)) but right hand side has $(size(V,1)) rows")) end @@ -282,10 +325,12 @@ function A_ldiv_B!(D::Diagonal{T}, V::AbstractMatrix{T}) where {T} V end -Ac_ldiv_B!(D::Diagonal{T}, B::AbstractVecOrMat{T}) where {T} = A_ldiv_B!(conj(D), B) -At_ldiv_B!(D::Diagonal{T}, B::AbstractVecOrMat{T}) where {T} = A_ldiv_B!(D, B) +ldiv!(adjD::Adjoint{<:Any,<:Diagonal{T}}, B::AbstractVecOrMat{T}) where {T} = + (D = adjD.parent; ldiv!(conj(D), B)) +ldiv!(transD::Transpose{<:Any,<:Diagonal{T}}, B::AbstractVecOrMat{T}) where {T} = + (D = transD.parent; ldiv!(D, B)) -function A_rdiv_B!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} +function rdiv!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} dd = D.diag m, n = size(A) if (k = length(dd)) ≠ n @@ -303,18 +348,20 @@ function A_rdiv_B!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} A end -A_rdiv_Bc!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} = A_rdiv_B!(A, conj(D)) -A_rdiv_Bt!(A::AbstractMatrix{T}, D::Diagonal{T}) where {T} = A_rdiv_B!(A, D) +rdiv!(A::AbstractMatrix{T}, adjD::Adjoint{<:Any,<:Diagonal{T}}) where {T} = + (D = adjD.parent; rdiv!(A, conj(D))) +rdiv!(A::AbstractMatrix{T}, transD::Transpose{<:Any,<:Diagonal{T}}) where {T} = + (D = transD.parent; rdiv!(A, D)) (\)(F::Factorization, D::Diagonal) = - A_ldiv_B!(F, Matrix{typeof(oneunit(eltype(D))/oneunit(eltype(F)))}(D)) -Ac_ldiv_B(F::Factorization, D::Diagonal) = - Ac_ldiv_B!(F, Matrix{typeof(oneunit(eltype(D))/oneunit(eltype(F)))}(D)) + ldiv!(F, Matrix{typeof(oneunit(eltype(D))/oneunit(eltype(F)))}(D)) +\(adjF::Adjoint{<:Any,<:Factorization}, D::Diagonal) = + (F = adjF.parent; ldiv!(Adjoint(F), Matrix{typeof(oneunit(eltype(D))/oneunit(eltype(F)))}(D))) # Methods to resolve ambiguities with `Diagonal` @inline *(rowvec::RowVector, D::Diagonal) = transpose(D * transpose(rowvec)) -@inline A_mul_Bt(D::Diagonal, rowvec::RowVector) = D*transpose(rowvec) -@inline A_mul_Bc(D::Diagonal, rowvec::RowVector) = D*adjoint(rowvec) +*(D::Diagonal, transrowvec::Transpose{<:Any,<:RowVector}) = (rowvec = transrowvec.parent; D*transpose(rowvec)) +*(D::Diagonal, adjrowvec::Adjoint{<:Any,<:RowVector}) = (rowvec = adjrowvec.parent; D*adjoint(rowvec)) conj(D::Diagonal) = Diagonal(conj(D.diag)) transpose(D::Diagonal{<:Number}) = D @@ -352,7 +399,7 @@ for f in (:exp, :log, :sqrt, end #Linear solver -function A_ldiv_B!(D::Diagonal, B::StridedVecOrMat) +function ldiv!(D::Diagonal, B::StridedVecOrMat) m, n = size(B, 1), size(B, 2) if m != length(D.diag) throw(DimensionMismatch("diagonal matrix is $(length(D.diag)) by $(length(D.diag)) but right hand side has $m rows")) @@ -431,3 +478,9 @@ function svdfact(D::Diagonal) U, s, V = svd(D) SVD(U, s, V') end + +# dismabiguation methods: * of Diagonal and Adj/Trans AbsVec +*(A::Diagonal, B::Adjoint{<:Any,<:AbstractVector}) = A * adjoint(B.parent) +*(A::Diagonal, B::Transpose{<:Any,<:AbstractVector}) = A * transpose(B.parent) +*(A::Adjoint{<:Any,<:AbstractVector}, B::Diagonal) = adjoint(A.parent) * B +*(A::Transpose{<:Any,<:AbstractVector}, B::Diagonal) = transpose(A.parent) * B diff --git a/base/linalg/factorization.jl b/base/linalg/factorization.jl index 487221a20acac..d99c071799244 100644 --- a/base/linalg/factorization.jl +++ b/base/linalg/factorization.jl @@ -47,7 +47,7 @@ end ### General promotion rules convert(::Type{Factorization{T}}, F::Factorization{T}) where {T} = F -inv(F::Factorization{T}) where {T} = (n = size(F, 1); A_ldiv_B!(F, Matrix{T}(I, n, n))) +inv(F::Factorization{T}) where {T} = (n = size(F, 1); ldiv!(F, Matrix{T}(I, n, n))) Base.hash(F::Factorization, h::UInt) = mapreduce(f -> hash(getfield(F, f)), hash, h, 1:nfields(F)) Base.:(==)( F::T, G::T) where {T<:Factorization} = all(f -> getfield(F, f) == getfield(G, f), 1:nfields(F)) @@ -57,60 +57,36 @@ Base.isequal(F::T, G::T) where {T<:Factorization} = all(f -> isequal(getfield(F, # the complex rhs as a real rhs with twice the number of columns function (\)(F::Factorization{T}, B::VecOrMat{Complex{T}}) where T<:BlasReal c2r = reshape(transpose(reinterpret(T, reshape(B, (1, length(B))))), size(B, 1), 2*size(B, 2)) - x = A_ldiv_B!(F, c2r) + x = ldiv!(F, c2r) return reshape(collect(reinterpret(Complex{T}, transpose(reshape(x, div(length(x), 2), 2)))), _ret_size(F, B)) end -for (f1, f2) in ((:\, :A_ldiv_B!), - (:Ac_ldiv_B, :Ac_ldiv_B!)) - @eval begin - function $f1(F::Factorization, B::AbstractVecOrMat) - TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F))) - BB = similar(B, TFB, size(B)) - copy!(BB, B) - $f2(F, BB) - end - end +function \(F::Factorization, B::AbstractVecOrMat) + TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F))) + BB = similar(B, TFB, size(B)) + copy!(BB, B) + ldiv!(F, BB) +end +function \(adjF::Adjoint{<:Any,<:Factorization}, B::AbstractVecOrMat) + F = adjF.parent + TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F))) + BB = similar(B, TFB, size(B)) + copy!(BB, B) + ldiv!(Adjoint(F), BB) end # support the same 3-arg idiom as in our other in-place A_*_B functions: -for f in (:A_ldiv_B!, :Ac_ldiv_B!, :At_ldiv_B!) - @eval $f(Y::AbstractVecOrMat, A::Factorization, B::AbstractVecOrMat) = - $f(A, copy!(Y, B)) -end +ldiv!(Y::AbstractVecOrMat, A::Factorization, B::AbstractVecOrMat) = ldiv!(A, copy!(Y, B)) +ldiv!(Y::AbstractVecOrMat, adjA::Adjoint{<:Any,<:Factorization}, B::AbstractVecOrMat) = + (A = adjA.parent; ldiv!(Adjoint(A), copy!(Y, B))) +ldiv!(Y::AbstractVecOrMat, transA::Transpose{<:Any,<:Factorization}, B::AbstractVecOrMat) = + (A = transA.parent; ldiv!(Transpose(A), copy!(Y, B))) # fallback methods for transposed solves -At_ldiv_B(F::Factorization{<:Real}, B::AbstractVecOrMat) = Ac_ldiv_B(F, B) -At_ldiv_B(F::Factorization, B) = conj.(Ac_ldiv_B(F, conj.(B))) - -""" - A_ldiv_B!([Y,] A, B) -> Y - -Compute `A \\ B` in-place and store the result in `Y`, returning the result. -If only two arguments are passed, then `A_ldiv_B!(A, B)` overwrites `B` with -the result. - -The argument `A` should *not* be a matrix. Rather, instead of matrices it should be a -factorization object (e.g. produced by [`factorize`](@ref) or [`cholfact`](@ref)). -The reason for this is that factorization itself is both expensive and typically allocates memory -(although it can also be done in-place via, e.g., [`lufact!`](@ref)), -and performance-critical situations requiring `A_ldiv_B!` usually also require fine-grained -control over the factorization of `A`. -""" -A_ldiv_B! - -""" - Ac_ldiv_B!([Y,] A, B) -> Y - -Similar to [`A_ldiv_B!`](@ref), but return ``Aᴴ`` \\ ``B``, -computing the result in-place in `Y` (or overwriting `B` if `Y` is not supplied). -""" -Ac_ldiv_B! +\(transF::Transpose{<:Any,<:Factorization{<:Real}}, B::AbstractVecOrMat) = (F = transF.parent; \(Adjoint(F), B)) +\(transF::Transpose{<:Any,<:Factorization}, B::AbstractVecOrMat) = (F = transF.parent; conj.(\(Adjoint(F), conj.(B)))) -""" - At_ldiv_B!([Y,] A, B) -> Y - -Similar to [`A_ldiv_B!`](@ref), but return ``Aᵀ`` \\ ``B``, -computing the result in-place in `Y` (or overwriting `B` if `Y` is not supplied). -""" -At_ldiv_B! +# dismabiguation methods +\(A::Adjoint{<:Any,<:Factorization}, B::RowVector) = adjoint(A.parent) \ B +\(A::Transpose{<:Any,<:Factorization}, B::RowVector) = transpose(A.parent) \ B +\(A::Transpose{<:Any,<:Factorization{<:Real}}, B::RowVector) = transpose(A.parent) \ B diff --git a/base/linalg/generic.jl b/base/linalg/generic.jl index a88d7e886201a..8ec784332a418 100644 --- a/base/linalg/generic.jl +++ b/base/linalg/generic.jl @@ -811,7 +811,7 @@ function inv(A::AbstractMatrix{T}) where T S = typeof(zero(T)/one(T)) # dimensionful S0 = typeof(zero(T)/oneunit(T)) # dimensionless dest = Matrix{S0}(I, n, n) - A_ldiv_B!(factorize(convert(AbstractMatrix{S}, A)), dest) + ldiv!(factorize(convert(AbstractMatrix{S}, A)), dest) end function pinv(v::AbstractVector{T}, tol::Real=real(zero(T))) where T diff --git a/base/linalg/givens.jl b/base/linalg/givens.jl index de621983494d4..27dc2a9979029 100644 --- a/base/linalg/givens.jl +++ b/base/linalg/givens.jl @@ -7,11 +7,14 @@ transpose(R::AbstractRotation) = error("transpose not implemented for $(typeof(R function *(R::AbstractRotation{T}, A::AbstractVecOrMat{S}) where {T,S} TS = typeof(zero(T)*zero(S) + zero(T)*zero(S)) - A_mul_B!(convert(AbstractRotation{TS}, R), TS == S ? copy(A) : convert(AbstractArray{TS}, A)) + mul!(convert(AbstractRotation{TS}, R), TS == S ? copy(A) : convert(AbstractArray{TS}, A)) end -function A_mul_Bc(A::AbstractVecOrMat{T}, R::AbstractRotation{S}) where {T,S} +*(A::AbstractVector, adjR::Adjoint{<:Any,<:AbstractRotation}) = _absvecormat_mul_adjrot(A, adjR) +*(A::AbstractMatrix, adjR::Adjoint{<:Any,<:AbstractRotation}) = _absvecormat_mul_adjrot(A, adjR) +function _absvecormat_mul_adjrot(A::AbstractVecOrMat{T}, adjR::Adjoint{<:Any,<:AbstractRotation{S}}) where {T,S} + R = adjR.parent TS = typeof(zero(T)*zero(S) + zero(T)*zero(S)) - A_mul_Bc!(TS == T ? copy(A) : convert(AbstractArray{TS}, A), convert(AbstractRotation{TS}, R)) + mul!(TS == T ? copy(A) : convert(AbstractArray{TS}, A), Adjoint(convert(AbstractRotation{TS}, R))) end """ LinAlg.Givens(i1,i2,c,s) -> G @@ -318,9 +321,9 @@ function getindex(G::Givens, i::Integer, j::Integer) end -A_mul_B!(G1::Givens, G2::Givens) = error("Operation not supported. Consider *") +mul!(G1::Givens, G2::Givens) = error("Operation not supported. Consider *") -function A_mul_B!(G::Givens, A::AbstractVecOrMat) +function mul!(G::Givens, A::AbstractVecOrMat) m, n = size(A, 1), size(A, 2) if G.i2 > m throw(DimensionMismatch("column indices for rotation are outside the matrix")) @@ -332,7 +335,8 @@ function A_mul_B!(G::Givens, A::AbstractVecOrMat) end return A end -function A_mul_Bc!(A::AbstractMatrix, G::Givens) +function mul!(A::AbstractMatrix, adjG::Adjoint{<:Any,<:Givens}) + G = adjG.parent m, n = size(A, 1), size(A, 2) if G.i2 > n throw(DimensionMismatch("column indices for rotation are outside the matrix")) @@ -344,20 +348,47 @@ function A_mul_Bc!(A::AbstractMatrix, G::Givens) end return A end -function A_mul_B!(G::Givens, R::Rotation) +function mul!(G::Givens, R::Rotation) push!(R.rotations, G) return R end -function A_mul_B!(R::Rotation, A::AbstractMatrix) +function mul!(R::Rotation, A::AbstractMatrix) @inbounds for i = 1:length(R.rotations) - A_mul_B!(R.rotations[i], A) + mul!(R.rotations[i], A) end return A end -function A_mul_Bc!(A::AbstractMatrix, R::Rotation) +function mul!(A::AbstractMatrix, adjR::Adjoint{<:Any,<:Rotation}) + R = adjR.parent @inbounds for i = 1:length(R.rotations) - A_mul_Bc!(A, R.rotations[i]) + mul!(A, Adjoint(R.rotations[i])) end return A end *(G1::Givens{T}, G2::Givens{T}) where {T} = Rotation(push!(push!(Givens{T}[], G2), G1)) + +# dismabiguation methods: *(Adj/Trans of AbsVec or AbsMat, Adj of AbstractRotation) +*(A::Adjoint{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractRotation}) = adjoint(A.parent) * B +*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractRotation}) = adjoint(A.parent) * B +*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractRotation}) = transpose(A.parent) * B +*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractRotation}) = transpose(A.parent) * B +# dismabiguation methods: *(Adj/Trans of AbsTri or RealHermSymComplex{Herm|Sym}, Adj of AbstractRotation) +*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractRotation}) = adjoint(A.parent) * B +*(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractRotation}) = transpose(A.parent) * B +*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Adjoint{<:Any,<:AbstractRotation}) = A.parent * B +*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Adjoint{<:Any,<:AbstractRotation}) = A.parent * B +# dismabiguation methods: *(Diag/RowVec/AbsTri, Adj of AbstractRotation) +*(A::Diagonal, B::Adjoint{<:Any,<:AbstractRotation}) = A * adjoint(B.parent) +*(A::RowVector, B::Adjoint{<:Any,<:AbstractRotation}) = A * adjoint(B.parent) +*(A::AbstractTriangular, B::Adjoint{<:Any,<:AbstractRotation}) = A * adjoint(B.parent) +# moar disambiguation +mul!(A::QRPackedQ, B::Adjoint{<:Any,<:Givens}) = throw(MethodError(mul!, (A, B))) +mul!(A::QRPackedQ, B::Adjoint{<:Any,<:Rotation}) = throw(MethodError(mul!, (A, B))) +mul!(A::Adjoint{<:Any,<:QRPackedQ}, B::Adjoint{<:Any,<:Givens}) = throw(MethodError(mul!, (A, B))) +mul!(A::Adjoint{<:Any,<:QRPackedQ}, B::Adjoint{<:Any,<:Rotation}) = throw(MethodError(mul!, (A, B))) +mul!(A::Diagonal, B::Adjoint{<:Any,<:Givens}) = throw(MethodError(mul!, (A, B))) +mul!(A::Diagonal, B::Adjoint{<:Any,<:Rotation}) = throw(MethodError(mul!, (A, B))) +mul!(A::Adjoint{<:Any,<:Diagonal}, B::Adjoint{<:Any,<:Givens}) = throw(MethodError(mul!, (A, B))) +mul!(A::Adjoint{<:Any,<:Diagonal}, B::Adjoint{<:Any,<:Rotation}) = throw(MethodError(mul!, (A, B))) +mul!(A::Transpose{<:Any,<:Diagonal}, B::Adjoint{<:Any,<:Rotation}) = throw(MethodError(mul!, (A, B))) +mul!(A::Transpose{<:Any,<:Diagonal}, B::Adjoint{<:Any,<:Givens}) = throw(MethodError(mul!, (A, B))) diff --git a/base/linalg/hessenberg.jl b/base/linalg/hessenberg.jl index fc4d44ddd9c3e..ca64cb8259b4e 100644 --- a/base/linalg/hessenberg.jl +++ b/base/linalg/hessenberg.jl @@ -73,7 +73,7 @@ function getindex(A::HessenbergQ, i::Integer, j::Integer) x[i] = 1 y = zeros(eltype(A), size(A, 2)) y[j] = 1 - return dot(x, A_mul_B!(A, y)) + return dot(x, mul!(A, y)) end ## reconstruct the original matrix @@ -84,29 +84,31 @@ convert(::Type{AbstractArray}, F::Hessenberg) = convert(AbstractMatrix, F) convert(::Type{Matrix}, F::Hessenberg) = convert(Array, convert(AbstractArray, F)) convert(::Type{Array}, F::Hessenberg) = convert(Matrix, F) -A_mul_B!(Q::HessenbergQ{T}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = +mul!(Q::HessenbergQ{T}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = LAPACK.ormhr!('L', 'N', 1, size(Q.factors, 1), Q.factors, Q.τ, X) -A_mul_B!(X::StridedMatrix{T}, Q::HessenbergQ{T}) where {T<:BlasFloat} = +mul!(X::StridedMatrix{T}, Q::HessenbergQ{T}) where {T<:BlasFloat} = LAPACK.ormhr!('R', 'N', 1, size(Q.factors, 1), Q.factors, Q.τ, X) -Ac_mul_B!(Q::HessenbergQ{T}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = - LAPACK.ormhr!('L', ifelse(T<:Real, 'T', 'C'), 1, size(Q.factors, 1), Q.factors, Q.τ, X) -A_mul_Bc!(X::StridedMatrix{T}, Q::HessenbergQ{T}) where {T<:BlasFloat} = - LAPACK.ormhr!('R', ifelse(T<:Real, 'T', 'C'), 1, size(Q.factors, 1), Q.factors, Q.τ, X) +mul!(adjQ::Adjoint{<:Any,<:HessenbergQ{T}}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = + (Q = adjQ.parent; LAPACK.ormhr!('L', ifelse(T<:Real, 'T', 'C'), 1, size(Q.factors, 1), Q.factors, Q.τ, X)) +mul!(X::StridedMatrix{T}, adjQ::Adjoint{<:Any,<:HessenbergQ{T}}) where {T<:BlasFloat} = + (Q = adjQ.parent; LAPACK.ormhr!('R', ifelse(T<:Real, 'T', 'C'), 1, size(Q.factors, 1), Q.factors, Q.τ, X)) function (*)(Q::HessenbergQ{T}, X::StridedVecOrMat{S}) where {T,S} TT = typeof(zero(T)*zero(S) + zero(T)*zero(S)) - return A_mul_B!(Q, copy_oftype(X, TT)) + return mul!(Q, copy_oftype(X, TT)) end function (*)(X::StridedVecOrMat{S}, Q::HessenbergQ{T}) where {T,S} TT = typeof(zero(T)*zero(S) + zero(T)*zero(S)) - return A_mul_B!(copy_oftype(X, TT), Q) + return mul!(copy_oftype(X, TT), Q) end -function Ac_mul_B(Q::HessenbergQ{T}, X::StridedVecOrMat{S}) where {T,S} +function *(adjQ::Adjoint{<:Any,<:HessenbergQ{T}}, X::StridedVecOrMat{S}) where {T,S} + Q = adjQ.parent TT = typeof(zero(T)*zero(S) + zero(T)*zero(S)) - return Ac_mul_B!(Q, copy_oftype(X, TT)) + return mul!(Adjoint(Q), copy_oftype(X, TT)) end -function A_mul_Bc(X::StridedVecOrMat{S}, Q::HessenbergQ{T}) where {T,S} +function *(X::StridedVecOrMat{S}, adjQ::Adjoint{<:Any,<:HessenbergQ{T}}) where {T,S} + Q = adjQ.parent TT = typeof(zero(T)*zero(S) + zero(T)*zero(S)) - return A_mul_Bc!(copy_oftype(X, TT), Q) + return mul!(copy_oftype(X, TT), Adjoint(Q)) end diff --git a/base/linalg/ldlt.jl b/base/linalg/ldlt.jl index a2d65971ce78d..d8bc1f38c979a 100644 --- a/base/linalg/ldlt.jl +++ b/base/linalg/ldlt.jl @@ -91,7 +91,7 @@ end factorize(S::SymTridiagonal) = ldltfact(S) -function A_ldiv_B!(S::LDLt{T,M}, B::AbstractVecOrMat{T}) where {T,M<:SymTridiagonal{T}} +function ldiv!(S::LDLt{T,M}, B::AbstractVecOrMat{T}) where {T,M<:SymTridiagonal{T}} n, nrhs = size(B, 1), size(B, 2) if size(S,1) != n throw(DimensionMismatch("Matrix has dimensions $(size(S)) but right hand side has first dimension $n")) diff --git a/base/linalg/linalg.jl b/base/linalg/linalg.jl index ce75dd49c4fc7..8c21dd2076191 100644 --- a/base/linalg/linalg.jl +++ b/base/linalg/linalg.jl @@ -1,5 +1,26 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# shims to maintain existence of names in Base module in A_mul_B deprecation process +function Ac_ldiv_Bt end +function At_ldiv_Bt end +function A_ldiv_Bt end +function At_ldiv_B end +function Ac_ldiv_Bc end +function A_ldiv_Bc end +function Ac_ldiv_B end +function At_rdiv_Bt end +function A_rdiv_Bt end +function At_rdiv_B end +function Ac_rdiv_Bc end +function A_rdiv_Bc end +function Ac_rdiv_B end +function At_mul_Bt end +function A_mul_Bt end +function At_mul_B end +function Ac_mul_Bc end +function A_mul_Bc end +function Ac_mul_B end + """ Linear algebra module. Provides array arithmetic, matrix factorizations and other linear algebra related @@ -237,9 +258,21 @@ function char_uplo(uplo::Symbol) end end +# shims to maintain existence of names in LinAlg module in A_mul_B deprecation process +function A_mul_B! end +function Ac_mul_B! end +function Ac_mul_B! end +function At_mul_B! end +function A_ldiv_B! end +function At_ldiv_B! end +function Ac_ldiv_B! end +function A_rdiv_B! end +function A_rdiv_Bc! end + copy_oftype(A::AbstractArray{T}, ::Type{T}) where {T} = copy(A) copy_oftype(A::AbstractArray{T,N}, ::Type{S}) where {T,N,S} = convert(AbstractArray{S,N}, A) +include("adjtrans.jl") include("conjarray.jl") include("transpose.jl") include("rowvector.jl") diff --git a/base/linalg/lq.jl b/base/linalg/lq.jl index 01966e41dd069..005a676087285 100644 --- a/base/linalg/lq.jl +++ b/base/linalg/lq.jl @@ -57,7 +57,7 @@ function lq(A::Union{Number,AbstractMatrix}; full::Bool = false, thin::Union{Boo end F = lqfact(A) L, Q = F[:L], F[:Q] - return L, !full ? Array(Q) : A_mul_B!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 2), size(Q.factors, 2))) + return L, !full ? Array(Q) : mul!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 2), size(Q.factors, 2))) end copy(A::LQ) = LQ(copy(A.factors), copy(A.τ)) @@ -84,7 +84,7 @@ function getindex(A::LQ, d::Symbol) end getindex(A::LQPackedQ, i::Integer, j::Integer) = - A_mul_B!(A, setindex!(zeros(eltype(A), size(A, 2)), 1, j))[i] + mul!(A, setindex!(zeros(eltype(A), size(A, 2)), 1, j))[i] getq(A::LQ) = LQPackedQ(A.factors, A.τ) @@ -120,58 +120,66 @@ end ## Multiplication by LQ -A_mul_B!(A::LQ{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = +mul!(A::LQ{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = A[:L] * LAPACK.ormlq!('L', 'N', A.factors, A.τ, B) -A_mul_B!(A::LQ{T}, B::QR{T}) where {T<:BlasFloat} = +mul!(A::LQ{T}, B::QR{T}) where {T<:BlasFloat} = A[:L] * LAPACK.ormlq!('L', 'N', A.factors, A.τ, Matrix(B)) -A_mul_B!(A::QR{T}, B::LQ{T}) where {T<:BlasFloat} = - A_mul_B!(zeros(eltype(A), size(A)), Matrix(A), Matrix(B)) +mul!(A::QR{T}, B::LQ{T}) where {T<:BlasFloat} = + mul!(zeros(eltype(A), size(A)), Matrix(A), Matrix(B)) function *(A::LQ{TA}, B::StridedVecOrMat{TB}) where {TA,TB} TAB = promote_type(TA, TB) - A_mul_B!(convert(Factorization{TAB},A), copy_oftype(B, TAB)) + mul!(convert(Factorization{TAB},A), copy_oftype(B, TAB)) end function *(A::LQ{TA},B::QR{TB}) where {TA,TB} TAB = promote_type(TA, TB) - A_mul_B!(convert(Factorization{TAB},A), convert(Factorization{TAB},B)) + mul!(convert(Factorization{TAB},A), convert(Factorization{TAB},B)) end function *(A::QR{TA},B::LQ{TB}) where {TA,TB} TAB = promote_type(TA, TB) - A_mul_B!(convert(Factorization{TAB},A), convert(Factorization{TAB},B)) + mul!(convert(Factorization{TAB},A), convert(Factorization{TAB},B)) end +*(A::Adjoint{<:Any,<:LQ}, B::LQ) = adjoint(A.parent) * B +*(A::LQ, B::Adjoint{<:Any,<:LQ}) = A * adjoint(B.parent) ## Multiplication by Q ### QB -A_mul_B!(A::LQPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = LAPACK.ormlq!('L','N',A.factors,A.τ,B) +mul!(A::LQPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = LAPACK.ormlq!('L','N',A.factors,A.τ,B) function (*)(A::LQPackedQ, B::StridedVecOrMat) TAB = promote_type(eltype(A), eltype(B)) - A_mul_B!(convert(AbstractMatrix{TAB}, A), copy_oftype(B, TAB)) + mul!(convert(AbstractMatrix{TAB}, A), copy_oftype(B, TAB)) end ### QcB -Ac_mul_B!(A::LQPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasReal} = LAPACK.ormlq!('L','T',A.factors,A.τ,B) -Ac_mul_B!(A::LQPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = LAPACK.ormlq!('L','C',A.factors,A.τ,B) -function Ac_mul_B(A::LQPackedQ, B::StridedVecOrMat) +mul!(adjA::Adjoint{<:Any,<:LQPackedQ{T}}, B::StridedVecOrMat{T}) where {T<:BlasReal} = + (A = adjA.parent; LAPACK.ormlq!('L','T',A.factors,A.τ,B)) +mul!(adjA::Adjoint{<:Any,<:LQPackedQ{T}}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = + (A = adjA.parent; LAPACK.ormlq!('L','C',A.factors,A.τ,B)) +function *(adjA::Adjoint{<:Any,<:LQPackedQ}, B::StridedVecOrMat) + A = adjA.parent TAB = promote_type(eltype(A), eltype(B)) if size(B,1) == size(A.factors,2) - Ac_mul_B!(convert(AbstractMatrix{TAB}, A), copy_oftype(B, TAB)) + mul!(Adjoint(convert(AbstractMatrix{TAB}, A)), copy_oftype(B, TAB)) elseif size(B,1) == size(A.factors,1) - Ac_mul_B!(convert(AbstractMatrix{TAB}, A), [B; zeros(TAB, size(A.factors, 2) - size(A.factors, 1), size(B, 2))]) + mul!(Adjoint(convert(AbstractMatrix{TAB}, A)), [B; zeros(TAB, size(A.factors, 2) - size(A.factors, 1), size(B, 2))]) else throw(DimensionMismatch("first dimension of B, $(size(B,1)), must equal one of the dimensions of A, $(size(A))")) end end ### QBc/QcBc -for (f1, f2) in ((:A_mul_Bc, :A_mul_B!), - (:Ac_mul_Bc, :Ac_mul_B!)) - @eval begin - function ($f1)(A::LQPackedQ, B::StridedVecOrMat) - TAB = promote_type(eltype(A), eltype(B)) - BB = similar(B, TAB, (size(B, 2), size(B, 1))) - adjoint!(BB, B) - return ($f2)(A, BB) - end - end +function *(A::LQPackedQ, adjB::Adjoint{<:Any,<:StridedVecOrMat}) + B = adjB.parent + TAB = promote_type(eltype(A), eltype(B)) + BB = similar(B, TAB, (size(B, 2), size(B, 1))) + adjoint!(BB, B) + return mul!(A, BB) +end +function *(adjA::Adjoint{<:Any,<:LQPackedQ}, adjB::Adjoint{<:Any,<:StridedVecOrMat}) + A, B = adjA.parent, adjB.parent + TAB = promote_type(eltype(A), eltype(B)) + BB = similar(B, TAB, (size(B, 2), size(B, 1))) + adjoint!(BB, B) + return mul!(Adjoint(A), BB) end # in-place right-application of LQPackedQs @@ -179,12 +187,12 @@ end # match the number of columns (nQ) of the LQPackedQ (Q) (necessary for in-place # operation, and the underlying LAPACK routine (ormlq) treats the implicit Q # as its (nQ-by-nQ) square form) -A_mul_B!(A::StridedMatrix{T}, B::LQPackedQ{T}) where {T<:BlasFloat} = +mul!(A::StridedMatrix{T}, B::LQPackedQ{T}) where {T<:BlasFloat} = LAPACK.ormlq!('R', 'N', B.factors, B.τ, A) -A_mul_Bc!(A::StridedMatrix{T}, B::LQPackedQ{T}) where {T<:BlasReal} = - LAPACK.ormlq!('R', 'T', B.factors, B.τ, A) -A_mul_Bc!(A::StridedMatrix{T}, B::LQPackedQ{T}) where {T<:BlasComplex} = - LAPACK.ormlq!('R', 'C', B.factors, B.τ, A) +mul!(A::StridedMatrix{T}, adjB::Adjoint{<:Any,<:LQPackedQ{T}}) where {T<:BlasReal} = + (B = adjB.parent; LAPACK.ormlq!('R', 'T', B.factors, B.τ, A)) +mul!(A::StridedMatrix{T}, adjB::Adjoint{<:Any,<:LQPackedQ{T}}) where {T<:BlasComplex} = + (B = adjB.parent; LAPACK.ormlq!('R', 'C', B.factors, B.τ, A)) # out-of-place right application of LQPackedQs # @@ -198,14 +206,16 @@ A_mul_Bc!(A::StridedMatrix{T}, B::LQPackedQ{T}) where {T<:BlasComplex} = # (1) the inner dimension in the multiplication is the LQPackedQ's second dimension. # in this case, the LQPackedQ behaves like its square form. # -function A_mul_Bc(A::StridedVecOrMat, Q::LQPackedQ) +function *(A::StridedVecOrMat, adjQ::Adjoint{<:Any,<:LQPackedQ}) + Q = adjQ.parent TR = promote_type(eltype(A), eltype(Q)) - return A_mul_Bc!(copy_oftype(A, TR), convert(AbstractMatrix{TR}, Q)) + return mul!(copy_oftype(A, TR), Adjoint(convert(AbstractMatrix{TR}, Q))) end -function Ac_mul_Bc(A::StridedMatrix, Q::LQPackedQ) +function *(adjA::Adjoint{<:Any,<:StridedMatrix}, adjQ::Adjoint{<:Any,<:LQPackedQ}) + A, Q = adjA.parent, adjQ.parent TR = promote_type(eltype(A), eltype(Q)) C = adjoint!(similar(A, TR, reverse(size(A))), A) - return A_mul_Bc!(C, convert(AbstractMatrix{TR}, Q)) + return mul!(C, Adjoint(convert(AbstractMatrix{TR}, Q))) end # # (2) the inner dimension in the multiplication is the LQPackedQ's first dimension. @@ -230,9 +240,10 @@ function *(A::StridedVecOrMat, Q::LQPackedQ) else _rightappdimmismatch("columns") end - return A_mul_B!(C, convert(AbstractMatrix{TR}, Q)) + return mul!(C, convert(AbstractMatrix{TR}, Q)) end -function Ac_mul_B(A::StridedMatrix, Q::LQPackedQ) +function *(adjA::Adjoint{<:Any,<:StridedMatrix}, Q::LQPackedQ) + A = adjA.parent TR = promote_type(eltype(A), eltype(Q)) if size(A, 1) == size(Q.factors, 2) C = adjoint!(similar(A, TR, reverse(size(A))), A) @@ -242,7 +253,7 @@ function Ac_mul_B(A::StridedMatrix, Q::LQPackedQ) else _rightappdimmismatch("rows") end - return A_mul_B!(C, convert(AbstractMatrix{TR}, Q)) + return mul!(C, convert(AbstractMatrix{TR}, Q)) end _rightappdimmismatch(rowsorcols) = throw(DimensionMismatch(string("the number of $(rowsorcols) of the matrix on the left ", @@ -256,7 +267,7 @@ function (\)(A::LQ{TA}, b::StridedVector{Tb}) where {TA,Tb} m = checksquare(A) m == length(b) || throw(DimensionMismatch("left hand side has $m rows, but right hand side has length $(length(b))")) AA = convert(Factorization{S}, A) - x = A_ldiv_B!(AA, copy_oftype(b, S)) + x = ldiv!(AA, copy_oftype(b, S)) return x end function (\)(A::LQ{TA},B::StridedMatrix{TB}) where {TA,TB} @@ -264,20 +275,20 @@ function (\)(A::LQ{TA},B::StridedMatrix{TB}) where {TA,TB} m = checksquare(A) m == size(B,1) || throw(DimensionMismatch("left hand side has $m rows, but right hand side has $(size(B,1)) rows")) AA = convert(Factorization{S}, A) - X = A_ldiv_B!(AA, copy_oftype(B, S)) + X = ldiv!(AA, copy_oftype(B, S)) return X end # With a real lhs and complex rhs with the same precision, we can reinterpret # the complex rhs as a real rhs with twice the number of columns function (\)(F::LQ{T}, B::VecOrMat{Complex{T}}) where T<:BlasReal c2r = reshape(transpose(reinterpret(T, reshape(B, (1, length(B))))), size(B, 1), 2*size(B, 2)) - x = A_ldiv_B!(F, c2r) + x = ldiv!(F, c2r) return reshape(collect(reinterpret(Complex{T}, transpose(reshape(x, div(length(x), 2), 2)))), isa(B, AbstractVector) ? (size(F,2),) : (size(F,2), size(B,2))) end -function A_ldiv_B!(A::LQ{T}, B::StridedVecOrMat{T}) where T - Ac_mul_B!(A[:Q], A_ldiv_B!(LowerTriangular(A[:L]),B)) +function ldiv!(A::LQ{T}, B::StridedVecOrMat{T}) where T + mul!(Adjoint(A[:Q]), ldiv!(LowerTriangular(A[:L]),B)) return B end diff --git a/base/linalg/lu.jl b/base/linalg/lu.jl index 873a889f91f35..b25a8aee89c0f 100644 --- a/base/linalg/lu.jl +++ b/base/linalg/lu.jl @@ -302,39 +302,49 @@ function _swap_rows!(B::StridedMatrix, i::Integer, j::Integer) B end -A_ldiv_B!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = +ldiv!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = @assertnonsingular LAPACK.getrs!('N', A.factors, A.ipiv, B) A.info -function A_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, B::StridedVecOrMat) +function ldiv!(A::LU{<:Any,<:StridedMatrix}, B::StridedVecOrMat) _apply_ipiv!(A, B) - A_ldiv_B!(UpperTriangular(A.factors), A_ldiv_B!(UnitLowerTriangular(A.factors), B)) + ldiv!(UpperTriangular(A.factors), ldiv!(UnitLowerTriangular(A.factors), B)) end -At_ldiv_B!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = - @assertnonsingular LAPACK.getrs!('T', A.factors, A.ipiv, B) A.info +ldiv!(transA::Transpose{T,<:LU{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = + (A = transA.parent; @assertnonsingular(LAPACK.getrs!('T', A.factors, A.ipiv, B), A.info)) -function At_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, B::StridedVecOrMat) - At_ldiv_B!(UnitLowerTriangular(A.factors), At_ldiv_B!(UpperTriangular(A.factors), B)) +function ldiv!(transA::Transpose{<:Any,<:LU{<:Any,<:StridedMatrix}}, B::StridedVecOrMat) + A = transA.parent + ldiv!(Transpose(UnitLowerTriangular(A.factors)), ldiv!(Transpose(UpperTriangular(A.factors)), B)) _apply_inverse_ipiv!(A, B) end -Ac_ldiv_B!(F::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:Real} = - At_ldiv_B!(F, B) -Ac_ldiv_B!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = - @assertnonsingular LAPACK.getrs!('C', A.factors, A.ipiv, B) A.info +ldiv!(adjF::Adjoint{T,<:LU{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:Real} = + (F = adjF.parent; ldiv!(Transpose(F), B)) +ldiv!(adjA::Adjoint{T,<:LU{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = + (A = adjA.parent; @assertnonsingular(LAPACK.getrs!('C', A.factors, A.ipiv, B), A.info)) -function Ac_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, B::StridedVecOrMat) - Ac_ldiv_B!(UnitLowerTriangular(A.factors), Ac_ldiv_B!(UpperTriangular(A.factors), B)) +function ldiv!(adjA::Adjoint{<:Any,<:LU{<:Any,<:StridedMatrix}}, B::StridedVecOrMat) + A = adjA.parent + ldiv!(Adjoint(UnitLowerTriangular(A.factors)), ldiv!(Adjoint(UpperTriangular(A.factors)), B)) _apply_inverse_ipiv!(A, B) end -At_ldiv_Bt(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = +function \(transA::Transpose{T,<:LU{T,<:StridedMatrix}}, + transB::Transpose{T,<:StridedVecOrMat{T}}) where {T<:BlasFloat} + A, B = transA.parent, transB.parent @assertnonsingular LAPACK.getrs!('T', A.factors, A.ipiv, transpose(B)) A.info -At_ldiv_Bt(A::LU, B::StridedVecOrMat) = At_ldiv_B(A, transpose(B)) +end +\(transA::Transpose{<:Any,<:LU}, transB::Transpose{<:Any,<:StridedVecOrMat}) = + (A = transA.parent; B = transB.parent; \(Transpose(A), transpose(B))) -Ac_ldiv_Bc(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = +function \(adjA::Adjoint{T,<:LU{T,<:StridedMatrix}}, + adjB::Adjoint{T,<:StridedVecOrMat{T}}) where {T<:BlasComplex} + A, B = adjA.parent, adjB.parent @assertnonsingular LAPACK.getrs!('C', A.factors, A.ipiv, adjoint(B)) A.info -Ac_ldiv_Bc(A::LU, B::StridedVecOrMat) = Ac_ldiv_B(A, adjoint(B)) +end +\(adjA::Adjoint{<:Any,<:LU}, adjB::Adjoint{<:Any,<:StridedVecOrMat}) = + (A = adjA.parent; B = adjB.parent; \(Adjoint(A), adjoint(B))) function det(F::LU{T}) where T n = checksquare(F) @@ -372,7 +382,7 @@ end inv!(A::LU{<:BlasFloat,<:StridedMatrix}) = @assertnonsingular LAPACK.getri!(A.factors, A.ipiv) A.info inv!(A::LU{T,<:StridedMatrix}) where {T} = - @assertnonsingular A_ldiv_B!(A.factors, copy(A), Matrix{T}(I, size(A, 1), size(A, 1))) A.info + @assertnonsingular ldiv!(A.factors, copy(A), Matrix{T}(I, size(A, 1), size(A, 1))) A.info inv(A::LU{<:BlasFloat,<:StridedMatrix}) = inv!(copy(A)) function _cond1Inf(A::LU{<:BlasFloat,<:StridedMatrix}, p::Number, normA::Real) @@ -478,7 +488,7 @@ function getindex(F::LU{T,Tridiagonal{T,V}}, d::Symbol) where {T,V} end # See dgtts2.f -function A_ldiv_B!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} +function ldiv!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} n = size(A,1) if n != size(B,1) throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) @@ -509,7 +519,8 @@ function A_ldiv_B!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} return B end -function At_ldiv_B!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} +function ldiv!(transA::Transpose{<:Any,<:LU{T,Tridiagonal{T,V}}}, B::AbstractVecOrMat) where {T,V} + A = transA.parent n = size(A,1) if n != size(B,1) throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) @@ -544,7 +555,8 @@ function At_ldiv_B!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} end # Ac_ldiv_B!(A::LU{T,Tridiagonal{T}}, B::AbstractVecOrMat) where {T<:Real} = At_ldiv_B!(A,B) -function Ac_ldiv_B!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} +function ldiv!(adjA::Adjoint{<:Any,LU{T,Tridiagonal{T,V}}}, B::AbstractVecOrMat) where {T,V} + A = adjA.parent n = size(A,1) if n != size(B,1) throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) @@ -578,7 +590,7 @@ function Ac_ldiv_B!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} return B end -/(B::AbstractMatrix,A::LU) = At_ldiv_Bt(A,B).' +/(B::AbstractMatrix,A::LU) = \(Transpose(A),Transpose(B)).' # Conversions convert(::Type{AbstractMatrix}, F::LU) = (F[:L] * F[:U])[invperm(F[:p]),:] diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index bf0fbd8283d18..abcc734a70bf3 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -67,29 +67,34 @@ function dot(x::Vector{T}, rx::Union{UnitRange{TI},AbstractRange{TI}}, y::Vector Base.@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 -At_mul_B(x::StridedVector{T}, y::StridedVector{T}) where {T<:BlasComplex} = BLAS.dotu(x, y) +*(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) - A_mul_B!(similar(x, TS, size(A,1)), A, convert(AbstractVector{TS}, x)) + mul!(similar(x, TS, size(A,1)), A, convert(AbstractVector{TS}, x)) end function (*)(A::AbstractMatrix{T}, x::AbstractVector{S}) where {T,S} TS = promote_op(matprod, T, S) - A_mul_B!(similar(x,TS,size(A,1)),A,x) + 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_mul_Bt(a::AbstractVector, B::AbstractMatrix) = A_mul_Bt(reshape(a,length(a),1),B) -A_mul_Bt(A::AbstractMatrix, b::AbstractVector) = A_mul_Bt(A,reshape(b,length(b),1)) -A_mul_Bc(a::AbstractVector, B::AbstractMatrix) = A_mul_Bc(reshape(a,length(a),1),B) -A_mul_Bc(A::AbstractMatrix, b::AbstractVector) = A_mul_Bc(A,reshape(b,length(b),1)) +*(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 -A_mul_B!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasFloat} = gemv!(y, 'N', A, x) +mul!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasFloat} = gemv!(y, 'N', A, x) for elty in (Float32,Float64) @eval begin - function A_mul_B!(y::StridedVector{Complex{$elty}}, A::StridedVecOrMat{Complex{$elty}}, x::StridedVector{$elty}) + function mul!(y::StridedVector{Complex{$elty}}, A::StridedVecOrMat{Complex{$elty}}, x::StridedVector{$elty}) Afl = reinterpret($elty,A) yfl = reinterpret($elty,y) gemv!(yfl,'N',Afl,x) @@ -97,31 +102,40 @@ for elty in (Float32,Float64) end end end -A_mul_B!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = generic_matvecmul!(y, 'N', A, x) +mul!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = generic_matvecmul!(y, 'N', A, x) -function At_mul_B(A::StridedMatrix{T}, x::StridedVector{S}) where {T<:BlasFloat,S} +function *(transA::Transpose{<:Any,<:StridedMatrix{T}}, x::StridedVector{S}) where {T<:BlasFloat,S} + A = transA.parent TS = promote_op(matprod, T, S) - At_mul_B!(similar(x,TS,size(A,2)), A, convert(AbstractVector{TS}, x)) + mul!(similar(x,TS,size(A,2)), Transpose(A), convert(AbstractVector{TS}, x)) end -function At_mul_B(A::AbstractMatrix{T}, x::AbstractVector{S}) where {T,S} +function *(transA::Transpose{<:Any,<:AbstractMatrix{T}}, x::AbstractVector{S}) where {T,S} + A = transA.parent TS = promote_op(matprod, T, S) - At_mul_B!(similar(x,TS,size(A,2)), A, x) + mul!(similar(x,TS,size(A,2)), Transpose(A), x) end -At_mul_B!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasFloat} = gemv!(y, 'T', A, x) -At_mul_B!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = generic_matvecmul!(y, 'T', A, x) +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 Ac_mul_B(A::StridedMatrix{T}, x::StridedVector{S}) where {T<:BlasFloat,S} +function *(adjA::Adjoint{<:Any,<:StridedMatrix{T}}, x::StridedVector{S}) where {T<:BlasFloat,S} + A = adjA.parent TS = promote_op(matprod, T, S) - Ac_mul_B!(similar(x,TS,size(A,2)),A,convert(AbstractVector{TS},x)) + mul!(similar(x,TS,size(A,2)), Adjoint(A) ,convert(AbstractVector{TS},x)) end -function Ac_mul_B(A::AbstractMatrix{T}, x::AbstractVector{S}) where {T,S} +function *(adjA::Adjoint{<:Any,<:AbstractMatrix{T}}, x::AbstractVector{S}) where {T,S} + A = adjA.parent TS = promote_op(matprod, T, S) - Ac_mul_B!(similar(x,TS,size(A,2)), A, x) + mul!(similar(x,TS,size(A,2)), Adjoint(A), x) end -Ac_mul_B!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasReal} = At_mul_B!(y, A, x) -Ac_mul_B!(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) where {T<:BlasComplex} = gemv!(y, 'C', A, x) -Ac_mul_B!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = generic_matvecmul!(y, 'C', A, x) +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) = + (A = adjA.parent; generic_matvecmul!(y, 'C', A, x)) # Matrix-matrix multiplication @@ -140,14 +154,14 @@ julia> [1 1; 0 1] * [1 0; 1 1] 1 1 ``` """ -function (*)(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} - TS = promote_op(matprod, T, S) - A_mul_B!(similar(B, TS, (size(A,1), size(B,2))), A, B) +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 -A_mul_B!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = gemm_wrapper!(C, 'N', 'N', A, B) +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 A_mul_B!(C::StridedMatrix{Complex{$elty}}, A::StridedVecOrMat{Complex{$elty}}, B::StridedVecOrMat{$elty}) + 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) @@ -157,7 +171,7 @@ for elty in (Float32,Float64) end """ - A_mul_B!(Y, A, B) -> Y + 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 @@ -165,7 +179,7 @@ overwriting the existing value of `Y`. Note that `Y` must not be aliased with ei # Examples ```jldoctest -julia> A=[1.0 2.0; 3.0 4.0]; B=[1.0 1.0; 1.0 1.0]; Y = similar(B); A_mul_B!(Y, A, B); +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}: @@ -173,31 +187,37 @@ julia> Y 7.0 7.0 ``` """ -A_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'N', A, B) +mul!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'N', A, B) """ - A_mul_B!(A, B) + mul!(A, B) Calculate the matrix-matrix product ``AB``, overwriting one of `A` or `B` (but not both), and return the result (the overwritten argument). """ -A_mul_B!(A, B) +mul!(A, B) -function At_mul_B(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} - TS = promote_op(matprod, T, S) - At_mul_B!(similar(B, TS, (size(A,2), size(B,2))), 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) end -At_mul_B!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = A===B ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B) -At_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'T', 'N', A, B) +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)) -function A_mul_Bt(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} - TS = promote_op(matprod, T, S) - A_mul_Bt!(similar(B, TS, (size(A,1), size(B,1))), 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 -A_mul_Bt!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = A===B ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B) +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)) for elty in (Float32,Float64) @eval begin - function A_mul_Bt!(C::StridedMatrix{Complex{$elty}}, A::StridedVecOrMat{Complex{$elty}}, B::StridedVecOrMat{$elty}) + function mul!(C::StridedMatrix{Complex{$elty}}, A::StridedVecOrMat{Complex{$elty}}, transB::Transpose{<:Any,<:StridedVecOrMat{$elty}}) + B = transB.parent Afl = reinterpret($elty, A) Cfl = reinterpret($elty, C) gemm_wrapper!(Cfl, 'N', 'T', Afl, B) @@ -205,38 +225,66 @@ for elty in (Float32,Float64) end end end -A_mul_Bt!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'T', A, B) - -function At_mul_Bt(A::AbstractMatrix{T}, B::AbstractVecOrMat{S}) where {T,S} - TS = promote_op(matprod, T, S) - At_mul_Bt!(similar(B, TS, (size(A,2), size(B,1))), A, B) -end -At_mul_Bt!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = gemm_wrapper!(C, 'T', 'T', A, B) -At_mul_Bt!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'T', 'T', A, B) - -Ac_mul_B(A::StridedMatrix{T}, B::StridedMatrix{T}) where {T<:BlasReal} = At_mul_B(A, B) -Ac_mul_B!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasReal} = At_mul_B!(C, A, B) -function Ac_mul_B(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} - TS = promote_op(matprod, T, S) - Ac_mul_B!(similar(B, TS, (size(A,2), size(B,2))), A, B) -end -Ac_mul_B!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = A===B ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B) -Ac_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'C', 'N', A, B) - -A_mul_Bc(A::StridedMatrix{<:BlasFloat}, B::StridedMatrix{<:BlasReal}) = A_mul_Bt(A, B) -A_mul_Bc!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{<:BlasReal}) where {T<:BlasFloat} = A_mul_Bt!(C, A, B) -function A_mul_Bc(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} +# 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) - A_mul_Bc!(similar(B,TS,(size(A,1),size(B,1))),A,B) -end -A_mul_Bc!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = A===B ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B) -A_mul_Bc!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'C', A, B) - -Ac_mul_Bc(A::AbstractMatrix{T}, B::AbstractMatrix{S}) where {T,S} = - Ac_mul_Bc!(similar(B, promote_op(matprod, T, S), (size(A,2), size(B,1))), A, B) -Ac_mul_Bc!(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = gemm_wrapper!(C, 'C', 'C', A, B) -Ac_mul_Bc!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'C', 'C', A, B) -Ac_mul_Bt!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'C', 'T', A, B) + 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, adjoint(B.parent)) + +*(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)) # Supporting functions for matrix multiplication function copytri!(A::AbstractMatrix, uplo::Char, conjugate::Bool=false) diff --git a/base/linalg/qr.jl b/base/linalg/qr.jl index dcdbc64e8c996..db28f03980f52 100644 --- a/base/linalg/qr.jl +++ b/base/linalg/qr.jl @@ -329,13 +329,13 @@ function _qr(A::Union{Number,AbstractMatrix}, ::Val{false}; full::Bool = false) F = qrfact(A, Val(false)) Q, R = getq(F), F[:R]::Matrix{eltype(F)} sQf1 = size(Q.factors, 1) - return (!full ? Array(Q) : A_mul_B!(Q, Matrix{eltype(Q)}(I, sQf1, sQf1))), R + return (!full ? Array(Q) : mul!(Q, Matrix{eltype(Q)}(I, sQf1, sQf1))), R end function _qr(A::Union{Number, AbstractMatrix}, ::Val{true}; full::Bool = false) F = qrfact(A, Val(true)) Q, R, p = getq(F), F[:R]::Matrix{eltype(F)}, F[:p]::Vector{BlasInt} sQf1 = size(Q.factors, 1) - return (!full ? Array(Q) : A_mul_B!(Q, Matrix{eltype(Q)}(I, sQf1, sQf1))), R, p + return (!full ? Array(Q) : mul!(Q, Matrix{eltype(Q)}(I, sQf1, sQf1))), R, p end """ @@ -508,7 +508,7 @@ convert(::Type{AbstractMatrix{T}}, Q::QRPackedQ) where {T} = convert(QRPackedQ{T convert(::Type{QRCompactWYQ{S}}, Q::QRCompactWYQ) where {S} = QRCompactWYQ(convert(AbstractMatrix{S}, Q.factors), convert(AbstractMatrix{S}, Q.T)) convert(::Type{AbstractMatrix{S}}, Q::QRCompactWYQ{S}) where {S} = Q convert(::Type{AbstractMatrix{S}}, Q::QRCompactWYQ) where {S} = convert(QRCompactWYQ{S}, Q) -convert(::Type{Matrix}, A::AbstractQ{T}) where {T} = A_mul_B!(A, Matrix{T}(I, size(A.factors, 1), min(size(A.factors)...))) +convert(::Type{Matrix}, A::AbstractQ{T}) where {T} = mul!(A, Matrix{T}(I, size(A.factors, 1), min(size(A.factors)...))) convert(::Type{Array}, A::AbstractQ) = convert(Matrix, A) size(A::Union{QR,QRCompactWY,QRPivoted}, dim::Integer) = size(A.factors, dim) @@ -522,16 +522,16 @@ function getindex(A::AbstractQ, i::Integer, j::Integer) x[i] = 1 y = zeros(eltype(A), size(A, 2)) y[j] = 1 - return dot(x, A_mul_B!(A, y)) + return dot(x, mul!(A, y)) end ## Multiplication by Q ### QB -A_mul_B!(A::QRCompactWYQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasFloat, S<:StridedMatrix} = +mul!(A::QRCompactWYQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasFloat, S<:StridedMatrix} = LAPACK.gemqrt!('L','N',A.factors,A.T,B) -A_mul_B!(A::QRPackedQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasFloat, S<:StridedMatrix} = +mul!(A::QRPackedQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasFloat, S<:StridedMatrix} = LAPACK.ormqr!('L','N',A.factors,A.τ,B) -function A_mul_B!(A::QRPackedQ, B::AbstractVecOrMat) +function mul!(A::QRPackedQ, B::AbstractVecOrMat) mA, nA = size(A.factors) mB, nB = size(B,1), size(B,2) if mA != mB @@ -566,7 +566,7 @@ function (*)(A::AbstractQ, b::StridedVector) else throw(DimensionMismatch("vector must have length either $(size(A.factors, 1)) or $(size(A.factors, 2))")) end - A_mul_B!(Anew, bnew) + mul!(Anew, bnew) end function (*)(A::AbstractQ, B::StridedMatrix) TAB = promote_type(eltype(A), eltype(B)) @@ -578,19 +578,20 @@ function (*)(A::AbstractQ, B::StridedMatrix) else throw(DimensionMismatch("first dimension of matrix must have size either $(size(A.factors, 1)) or $(size(A.factors, 2))")) end - A_mul_B!(Anew, Bnew) + mul!(Anew, Bnew) end ### QcB -Ac_mul_B!(A::QRCompactWYQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasReal,S<:StridedMatrix} = - LAPACK.gemqrt!('L','T',A.factors,A.T,B) -Ac_mul_B!(A::QRCompactWYQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasComplex,S<:StridedMatrix} = - LAPACK.gemqrt!('L','C',A.factors,A.T,B) -Ac_mul_B!(A::QRPackedQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasReal,S<:StridedMatrix} = - LAPACK.ormqr!('L','T',A.factors,A.τ,B) -Ac_mul_B!(A::QRPackedQ{T,S}, B::StridedVecOrMat{T}) where {T<:BlasComplex,S<:StridedMatrix} = - LAPACK.ormqr!('L','C',A.factors,A.τ,B) -function Ac_mul_B!(A::QRPackedQ, B::AbstractVecOrMat) +mul!(adjA::Adjoint{<:Any,<:QRCompactWYQ{T,S}}, B::StridedVecOrMat{T}) where {T<:BlasReal,S<:StridedMatrix} = + (A = adjA.parent; LAPACK.gemqrt!('L','T',A.factors,A.T,B)) +mul!(adjA::Adjoint{<:Any,<:QRCompactWYQ{T,S}}, B::StridedVecOrMat{T}) where {T<:BlasComplex,S<:StridedMatrix} = + (A = adjA.parent; LAPACK.gemqrt!('L','C',A.factors,A.T,B)) +mul!(adjA::Adjoint{<:Any,<:QRPackedQ{T,S}}, B::StridedVecOrMat{T}) where {T<:BlasReal,S<:StridedMatrix} = + (A = adjA.parent; LAPACK.ormqr!('L','T',A.factors,A.τ,B)) +mul!(adjA::Adjoint{<:Any,<:QRPackedQ{T,S}}, B::StridedVecOrMat{T}) where {T<:BlasComplex,S<:StridedMatrix} = + (A = adjA.parent; LAPACK.ormqr!('L','C',A.factors,A.τ,B)) +function mul!(adjA::Adjoint{<:Any,<:QRPackedQ}, B::AbstractVecOrMat) + A = adjA.parent mA, nA = size(A.factors) mB, nB = size(B,1), size(B,2) if mA != mB @@ -614,30 +615,34 @@ function Ac_mul_B!(A::QRPackedQ, B::AbstractVecOrMat) end B end -function Ac_mul_B(Q::AbstractQ, B::StridedVecOrMat) +function *(adjQ::Adjoint{<:Any,<:AbstractQ}, B::StridedVecOrMat) + Q = adjQ.parent TQB = promote_type(eltype(Q), eltype(B)) - return Ac_mul_B!(convert(AbstractMatrix{TQB}, Q), copy_oftype(B, TQB)) + return mul!(Adjoint(convert(AbstractMatrix{TQB}, Q)), copy_oftype(B, TQB)) end ### QBc/QcBc -for (f1, f2) in ((:A_mul_Bc, :A_mul_B!), - (:Ac_mul_Bc, :Ac_mul_B!)) - @eval begin - function ($f1)(Q::AbstractQ, B::StridedVecOrMat) - TQB = promote_type(eltype(Q), eltype(B)) - Bc = similar(B, TQB, (size(B, 2), size(B, 1))) - adjoint!(Bc, B) - return ($f2)(convert(AbstractMatrix{TQB}, Q), Bc) - end - end +function *(Q::AbstractQ, adjB::Adjoint{<:Any,<:StridedVecOrMat}) + B = adjB.parent + TQB = promote_type(eltype(Q), eltype(B)) + Bc = similar(B, TQB, (size(B, 2), size(B, 1))) + adjoint!(Bc, B) + return mul!(convert(AbstractMatrix{TQB}, Q), Bc) +end +function *(adjQ::Adjoint{<:Any,<:AbstractQ}, adjB::Adjoint{<:Any,<:StridedVecOrMat}) + Q, B = adjQ.parent, adjB.parent + TQB = promote_type(eltype(Q), eltype(B)) + Bc = similar(B, TQB, (size(B, 2), size(B, 1))) + adjoint!(Bc, B) + return mul!(Adjoint(convert(AbstractMatrix{TQB}, Q)), Bc) end ### AQ -A_mul_B!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = +mul!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = LAPACK.gemqrt!('R','N', B.factors, B.T, A) -A_mul_B!(A::StridedVecOrMat{T}, B::QRPackedQ{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = +mul!(A::StridedVecOrMat{T}, B::QRPackedQ{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = LAPACK.ormqr!('R', 'N', B.factors, B.τ, A) -function A_mul_B!(A::StridedMatrix,Q::QRPackedQ) +function mul!(A::StridedMatrix,Q::QRPackedQ) mQ, nQ = size(Q.factors) mA, nA = size(A,1), size(A,2) if nA != mQ @@ -664,15 +669,20 @@ end function (*)(A::StridedMatrix, Q::AbstractQ) TAQ = promote_type(eltype(A), eltype(Q)) - return A_mul_B!(copy_oftype(A, TAQ), convert(AbstractMatrix{TAQ}, Q)) + return mul!(copy_oftype(A, TAQ), convert(AbstractMatrix{TAQ}, Q)) end ### AQc -A_mul_Bc!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T}) where {T<:BlasReal} = LAPACK.gemqrt!('R','T',B.factors,B.T,A) -A_mul_Bc!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T}) where {T<:BlasComplex} = LAPACK.gemqrt!('R','C',B.factors,B.T,A) -A_mul_Bc!(A::StridedVecOrMat{T}, B::QRPackedQ{T}) where {T<:BlasReal} = LAPACK.ormqr!('R','T',B.factors,B.τ,A) -A_mul_Bc!(A::StridedVecOrMat{T}, B::QRPackedQ{T}) where {T<:BlasComplex} = LAPACK.ormqr!('R','C',B.factors,B.τ,A) -function A_mul_Bc!(A::StridedMatrix,Q::QRPackedQ) +mul!(A::StridedVecOrMat{T}, adjB::Adjoint{<:Any,<:QRCompactWYQ{T}}) where {T<:BlasReal} = + (B = adjB.parent; LAPACK.gemqrt!('R','T',B.factors,B.T,A)) +mul!(A::StridedVecOrMat{T}, adjB::Adjoint{<:Any,<:QRCompactWYQ{T}}) where {T<:BlasComplex} = + (B = adjB.parent; LAPACK.gemqrt!('R','C',B.factors,B.T,A)) +mul!(A::StridedVecOrMat{T}, adjB::Adjoint{<:Any,<:QRPackedQ{T}}) where {T<:BlasReal} = + (B = adjB.parent; LAPACK.ormqr!('R','T',B.factors,B.τ,A)) +mul!(A::StridedVecOrMat{T}, adjB::Adjoint{<:Any,<:QRPackedQ{T}}) where {T<:BlasComplex} = + (B = adjB.parent; LAPACK.ormqr!('R','C',B.factors,B.τ,A)) +function mul!(A::StridedMatrix, adjQ::Adjoint{<:Any,<:QRPackedQ}) + Q = adjQ.parent mQ, nQ = size(Q.factors) mA, nA = size(A,1), size(A,2) if nA != mQ @@ -696,40 +706,46 @@ function A_mul_Bc!(A::StridedMatrix,Q::QRPackedQ) end A end -function A_mul_Bc(A::StridedMatrix, B::AbstractQ) +function *(A::StridedMatrix, adjB::Adjoint{<:Any,<:AbstractQ}) + B = adjB.parent TAB = promote_type(eltype(A),eltype(B)) BB = convert(AbstractMatrix{TAB}, B) if size(A,2) == size(B.factors, 1) AA = similar(A, TAB, size(A)) copy!(AA, A) - return A_mul_Bc!(AA, BB) + return mul!(AA, Adjoint(BB)) elseif size(A,2) == size(B.factors,2) - return A_mul_Bc!([A zeros(TAB, size(A, 1), size(B.factors, 1) - size(B.factors, 2))], BB) + return mul!([A zeros(TAB, size(A, 1), size(B.factors, 1) - size(B.factors, 2))], Adjoint(BB)) else throw(DimensionMismatch("matrix A has dimensions $(size(A)) but matrix B has dimensions $(size(B))")) end end -@inline A_mul_Bc(rowvec::RowVector, B::AbstractQ) = adjoint(B*adjoint(rowvec)) +@inline *(rowvec::RowVector, adjB::Adjoint{<:Any,<:AbstractQ}) = (B = adjB.parent; adjoint(B*adjoint(rowvec))) ### AcQ/AcQc -for (f1, f2) in ((:Ac_mul_B, :A_mul_B!), - (:Ac_mul_Bc, :A_mul_Bc!)) - @eval begin - function ($f1)(A::StridedVecOrMat, Q::AbstractQ) - TAQ = promote_type(eltype(A), eltype(Q)) - Ac = similar(A, TAQ, (size(A, 2), size(A, 1))) - adjoint!(Ac, A) - return ($f2)(Ac, convert(AbstractMatrix{TAQ}, Q)) - end - end +function *(adjA::Adjoint{<:Any,<:StridedVecOrMat}, Q::AbstractQ) + A = adjA.parent + TAQ = promote_type(eltype(A), eltype(Q)) + Ac = similar(A, TAQ, (size(A, 2), size(A, 1))) + adjoint!(Ac, A) + return mul!(Ac, convert(AbstractMatrix{TAQ}, Q)) +end +function *(adjA::Adjoint{<:Any,<:StridedVecOrMat}, adjQ::Adjoint{<:Any,<:AbstractQ}) + A, Q = adjA.parent, adjQ.parent + TAQ = promote_type(eltype(A), eltype(Q)) + Ac = similar(A, TAQ, (size(A, 2), size(A, 1))) + adjoint!(Ac, A) + return mul!(Ac, Adjoint(convert(AbstractMatrix{TAQ}, Q))) end -A_ldiv_B!(A::QRCompactWY{T}, b::StridedVector{T}) where {T<:BlasFloat} = (A_ldiv_B!(UpperTriangular(A[:R]), view(Ac_mul_B!(A[:Q], b), 1:size(A, 2))); b) -A_ldiv_B!(A::QRCompactWY{T}, B::StridedMatrix{T}) where {T<:BlasFloat} = (A_ldiv_B!(UpperTriangular(A[:R]), view(Ac_mul_B!(A[:Q], B), 1:size(A, 2), 1:size(B, 2))); B) +ldiv!(A::QRCompactWY{T}, b::StridedVector{T}) where {T<:BlasFloat} = + (ldiv!(UpperTriangular(A[:R]), view(mul!(Adjoint(A[:Q]), b), 1:size(A, 2))); b) +ldiv!(A::QRCompactWY{T}, B::StridedMatrix{T}) where {T<:BlasFloat} = + (ldiv!(UpperTriangular(A[:R]), view(mul!(Adjoint(A[:Q]), B), 1:size(A, 2), 1:size(B, 2))); B) # Julia implementation similar to xgelsy -function A_ldiv_B!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:BlasFloat +function ldiv!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:BlasFloat mA, nA = size(A.factors) nr = min(mA,nA) nrhs = size(B, 2) @@ -758,21 +774,21 @@ function A_ldiv_B!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:B rnk += 1 end C, τ = LAPACK.tzrzf!(A.factors[1:rnk,:]) - A_ldiv_B!(UpperTriangular(C[1:rnk,1:rnk]),view(Ac_mul_B!(getq(A),view(B, 1:mA, 1:nrhs)),1:rnk,1:nrhs)) + ldiv!(UpperTriangular(C[1:rnk,1:rnk]),view(mul!(Adjoint(getq(A)), view(B, 1:mA, 1:nrhs)), 1:rnk, 1:nrhs)) B[rnk+1:end,:] = zero(T) LAPACK.ormrz!('L', eltype(B)<:Complex ? 'C' : 'T', C, τ, view(B,1:nA,1:nrhs)) B[1:nA,:] = view(B, 1:nA, :)[invperm(A[:p]::Vector{BlasInt}),:] return B, rnk end -A_ldiv_B!(A::QRPivoted{T}, B::StridedVector{T}) where {T<:BlasFloat} = - vec(A_ldiv_B!(A,reshape(B,length(B),1))) -A_ldiv_B!(A::QRPivoted{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = - A_ldiv_B!(A, B, min(size(A)...)*eps(real(float(one(eltype(B))))))[1] -function A_ldiv_B!(A::QR{T}, B::StridedMatrix{T}) where T +ldiv!(A::QRPivoted{T}, B::StridedVector{T}) where {T<:BlasFloat} = + vec(ldiv!(A,reshape(B,length(B),1))) +ldiv!(A::QRPivoted{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = + ldiv!(A, B, min(size(A)...)*eps(real(float(one(eltype(B))))))[1] +function ldiv!(A::QR{T}, B::StridedMatrix{T}) where T m, n = size(A) minmn = min(m,n) mB, nB = size(B) - Ac_mul_B!(A[:Q], view(B, 1:m, :)) + mul!(Adjoint(A[:Q]), view(B, 1:m, :)) R = A[:R] @inbounds begin if n > m # minimum norm solution @@ -794,7 +810,7 @@ function A_ldiv_B!(A::QR{T}, B::StridedMatrix{T}) where T end end end - Base.A_ldiv_B!(UpperTriangular(view(R, :, 1:minmn)), view(B, 1:minmn, :)) + Base.LinAlg.ldiv!(UpperTriangular(view(R, :, 1:minmn)), view(B, 1:minmn, :)) if n > m # Apply elementary transformation to solution B[m + 1:mB,1:nB] = zero(T) for j = 1:nB @@ -814,14 +830,14 @@ function A_ldiv_B!(A::QR{T}, B::StridedMatrix{T}) where T end return B end -A_ldiv_B!(A::QR, B::StridedVector) = A_ldiv_B!(A, reshape(B, length(B), 1))[:] -function A_ldiv_B!(A::QRPivoted, b::StridedVector) - A_ldiv_B!(QR(A.factors,A.τ), b) +ldiv!(A::QR, B::StridedVector) = ldiv!(A, reshape(B, length(B), 1))[:] +function ldiv!(A::QRPivoted, b::StridedVector) + ldiv!(QR(A.factors,A.τ), b) b[1:size(A.factors, 2)] = view(b, 1:size(A.factors, 2))[invperm(A.jpvt)] b end -function A_ldiv_B!(A::QRPivoted, B::StridedMatrix) - A_ldiv_B!(QR(A.factors, A.τ), B) +function ldiv!(A::QRPivoted, B::StridedMatrix) + ldiv!(QR(A.factors, A.τ), B) B[1:size(A.factors, 2),:] = view(B, 1:size(A.factors, 2), :)[invperm(A.jpvt),:] B end @@ -846,7 +862,7 @@ function (\)(A::Union{QR{TA},QRCompactWY{TA},QRPivoted{TA}}, B::AbstractVecOrMat X = _zeros(S, B, n) X[1:size(B, 1), :] = B - A_ldiv_B!(AA, X) + ldiv!(AA, X) return _cut_B(X, 1:n) end @@ -871,7 +887,7 @@ function (\)(A::Union{QR{T},QRCompactWY{T},QRPivoted{T}}, BIn::VecOrMat{Complex{ X = _zeros(T, B, n) X[1:size(B, 1), :] = B - A_ldiv_B!(A, X) + ldiv!(A, X) # |z1|z3| reinterpret |x1|x2|x3|x4| transpose |x1|y1| reshape |x1|y1|x3|y3| # |z2|z4| <- |y1|y2|y3|y4| <- |x2|y2| <- |x2|y2|x4|y4| diff --git a/base/linalg/rowvector.jl b/base/linalg/rowvector.jl index 8f7084f9cf650..0044114277e46 100644 --- a/base/linalg/rowvector.jl +++ b/base/linalg/rowvector.jl @@ -208,50 +208,77 @@ end *(vec::AbstractVector, rowvec::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) # Transposed forms -A_mul_Bt(::RowVector, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) -@inline A_mul_Bt(rowvec::RowVector, mat::AbstractMatrix) = transpose(mat * transpose(rowvec)) -@inline A_mul_Bt(rowvec1::RowVector, rowvec2::RowVector) = rowvec1*transpose(rowvec2) -A_mul_Bt(vec::AbstractVector, rowvec::RowVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -@inline A_mul_Bt(vec1::AbstractVector, vec2::AbstractVector) = vec1 * transpose(vec2) -@inline A_mul_Bt(mat::AbstractMatrix, rowvec::RowVector) = mat * transpose(rowvec) - -@inline At_mul_Bt(rowvec::RowVector, vec::AbstractVector) = transpose(rowvec) * transpose(vec) -@inline At_mul_Bt(vec::AbstractVector, mat::AbstractMatrix) = transpose(mat * vec) -At_mul_Bt(rowvec1::RowVector, rowvec2::RowVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -@inline At_mul_Bt(vec::AbstractVector, rowvec::RowVector) = transpose(vec)*transpose(rowvec) -At_mul_Bt(vec::AbstractVector, rowvec::AbstractVector) = throw(DimensionMismatch( - "Cannot multiply two transposed vectors")) -@inline At_mul_Bt(mat::AbstractMatrix, rowvec::RowVector) = mat.' * transpose(rowvec) - -At_mul_B(::RowVector, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -@inline At_mul_B(vec::AbstractVector, mat::AbstractMatrix) = transpose(At_mul_B(mat,vec)) -@inline At_mul_B(rowvec1::RowVector, rowvec2::RowVector) = transpose(rowvec1) * rowvec2 -At_mul_B(vec::AbstractVector, rowvec::RowVector) = throw(DimensionMismatch( - "Cannot multiply two transposed vectors")) -@inline At_mul_B(vec1::AbstractVector{T}, vec2::AbstractVector{T}) where {T<:Real} = - reduce(+, map(At_mul_B, vec1, vec2)) # Seems to be overloaded... -@inline At_mul_B(vec1::AbstractVector, vec2::AbstractVector) = transpose(vec1) * vec2 +*(::RowVector, ::Transpose{<:Any,<:AbstractVector}) = + throw(DimensionMismatch("Cannot multiply two transposed vectors")) +*(rowvec::RowVector, transmat::Transpose{<:Any,<:AbstractMatrix}) = + (mat = transmat.parent; transpose(mat * transpose(rowvec))) +*(rowvec1::RowVector, transrowvec2::Transpose{<:Any,<:RowVector}) = + (rowvec2 = transrowvec2.parent; rowvec1*transpose(rowvec2)) +*(::AbstractVector, ::Transpose{<:Any,<:RowVector}) = + throw(DimensionMismatch("Cannot multiply two vectors")) +*(vec1::AbstractVector, transvec2::Transpose{<:Any,<:AbstractVector}) = + (vec2 = transvec2.parent; vec1 * transpose(vec2)) +*(mat::AbstractMatrix, transrowvec::Transpose{<:Any,<:RowVector}) = + (rowvec = transrowvec.parent; mat * transpose(rowvec)) + +*(transrowvec::Transpose{<:Any,<:RowVector}, transvec::Transpose{<:Any,<:AbstractVector}) = + transpose(transrowvec.parent) * transpose(transvec.parent) +*(transvec::Transpose{<:Any,<:AbstractVector}, transmat::Transpose{<:Any,<:AbstractMatrix}) = + transpose(transmat.parent * transvec.parent) +*(transrowvec1::Transpose{<:Any,<:RowVector}, transrowvec2::Transpose{<:Any,<:RowVector}) = + throw(DimensionMismatch("Cannot multiply two vectors")) +*(transvec::Transpose{<:Any,<:AbstractVector}, transrowvec::Transpose{<:Any,<:RowVector}) = + transpose(transvec.parent)*transpose(transrowvec.parent) +*(transvec::Transpose{<:Any,<:AbstractVector}, transrowvec::Transpose{<:Any,<:AbstractVector}) = + throw(DimensionMismatch("Cannot multiply two transposed vectors")) +*(transmat::Transpose{<:Any,<:AbstractMatrix}, transrowvec::Transpose{<:Any,<:RowVector}) = + (transmat.parent).' * transpose(transrowvec.parent) + +*(::Transpose{<:Any,<:RowVector}, ::AbstractVector) = + throw(DimensionMismatch("Cannot multiply two vectors")) +*(transvec::Transpose{<:Any,<:AbstractVector}, mat::AbstractMatrix) = + transpose(*(Transpose(mat), transvec.parent)) +*(transrowvec1::Transpose{<:Any,<:RowVector}, rowvec2::RowVector) = + transpose(transrowvec1.parent) * rowvec2 +*(transvec::Transpose{<:Any,<:AbstractVector}, rowvec::RowVector) = + throw(DimensionMismatch("Cannot multiply two transposed vectors")) +*(transvec1::Transpose{<:Any,<:AbstractVector{T}}, vec2::AbstractVector{T}) where {T<:Real} = + reduce(+, map(*, transvec1.parent, vec2)) # Seems to be overloaded... +*(transvec1::Transpose{<:Any,<:AbstractVector}, vec2::AbstractVector) = + transpose(transvec1.parent) * vec2 # Conjugated forms -A_mul_Bc(::RowVector, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) -@inline A_mul_Bc(rowvec::RowVector, mat::AbstractMatrix) = adjoint(mat * adjoint(rowvec)) -@inline A_mul_Bc(rowvec1::RowVector, rowvec2::RowVector) = rowvec1 * adjoint(rowvec2) -A_mul_Bc(vec::AbstractVector, rowvec::RowVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -@inline A_mul_Bc(vec1::AbstractVector, vec2::AbstractVector) = vec1 * adjoint(vec2) -@inline A_mul_Bc(mat::AbstractMatrix, rowvec::RowVector) = mat * adjoint(rowvec) - -@inline Ac_mul_Bc(rowvec::RowVector, vec::AbstractVector) = adjoint(rowvec) * adjoint(vec) -@inline Ac_mul_Bc(vec::AbstractVector, mat::AbstractMatrix) = adjoint(mat * vec) -Ac_mul_Bc(rowvec1::RowVector, rowvec2::RowVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -@inline Ac_mul_Bc(vec::AbstractVector, rowvec::RowVector) = adjoint(vec)*adjoint(rowvec) -Ac_mul_Bc(vec::AbstractVector, rowvec::AbstractVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) -@inline Ac_mul_Bc(mat::AbstractMatrix, rowvec::RowVector) = mat' * adjoint(rowvec) - -Ac_mul_B(::RowVector, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -@inline Ac_mul_B(vec::AbstractVector, mat::AbstractMatrix) = adjoint(Ac_mul_B(mat,vec)) -@inline Ac_mul_B(rowvec1::RowVector, rowvec2::RowVector) = adjoint(rowvec1) * rowvec2 -Ac_mul_B(vec::AbstractVector, rowvec::RowVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) -@inline Ac_mul_B(vec1::AbstractVector, vec2::AbstractVector) = adjoint(vec1)*vec2 +*(::RowVector, ::Adjoint{<:Any,<:AbstractVector}) = + throw(DimensionMismatch("Cannot multiply two transposed vectors")) +*(rowvec::RowVector, adjmat::Adjoint{<:Any,<:AbstractMatrix}) = + adjoint(adjmat.parent * adjoint(rowvec)) +*(rowvec1::RowVector, adjrowvec2::Adjoint{<:Any,<:RowVector}) = + rowvec1 * adjoint(adjrowvec2.parent) +*(vec::AbstractVector, adjrowvec::Adjoint{<:Any,<:RowVector}) = + throw(DimensionMismatch("Cannot multiply two vectors")) +*(vec1::AbstractVector, adjvec2::Adjoint{<:Any,<:AbstractVector}) = + vec1 * adjoint(adjvec2.parent) +*(mat::AbstractMatrix, adjrowvec::Adjoint{<:Any,<:RowVector}) = + mat * adjoint(adjrowvec.parent) + +*(adjrowvec::Adjoint{<:Any,<:RowVector}, adjvec::Adjoint{<:Any,<:AbstractVector}) = + adjoint(adjrowvec.parent) * adjoint(adjvec.parent) +*(adjvec::Adjoint{<:Any,<:AbstractVector}, adjmat::Adjoint{<:Any,<:AbstractMatrix}) = + adjoint(adjmat.parent * adjvec.parent) +*(adjrowvec1::Adjoint{<:Any,<:RowVector}, adjrowvec2::Adjoint{<:Any,<:RowVector}) = + throw(DimensionMismatch("Cannot multiply two vectors")) +*(adjvec::Adjoint{<:Any,<:AbstractVector}, adjrowvec::Adjoint{<:Any,<:RowVector}) = + adjoint(adjvec.parent)*adjoint(adjrowvec.parent) +*(adjvec::Adjoint{<:Any,<:AbstractVector}, adjrowvec::Adjoint{<:Any,<:AbstractVector}) = + throw(DimensionMismatch("Cannot multiply two transposed vectors")) +*(adjmat::Adjoint{<:Any,<:AbstractMatrix}, adjrowvec::Adjoint{<:Any,<:RowVector}) = + (adjmat.parent)' * adjoint(adjrowvec.parent) + +*(::Adjoint{<:Any,<:RowVector}, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) +*(adjvec::Adjoint{<:Any,<:AbstractVector}, mat::AbstractMatrix) = adjoint(*(Adjoint(mat), adjvec.parent)) +*(adjrowvec1::Adjoint{<:Any,<:RowVector}, rowvec2::RowVector) = adjoint(adjrowvec1.parent) * rowvec2 +*(adjvec::Adjoint{<:Any,<:AbstractVector}, rowvec::RowVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) +*(adjvec1::Adjoint{<:Any,<:AbstractVector}, vec2::AbstractVector) = adjoint(adjvec1.parent)*vec2 # Pseudo-inverse pinv(v::RowVector, tol::Real=0) = pinv(v', tol)' @@ -260,11 +287,26 @@ pinv(v::RowVector, tol::Real=0) = pinv(v', tol)' \(rowvec1::RowVector, rowvec2::RowVector) = pinv(rowvec1) * rowvec2 \(mat::AbstractMatrix, rowvec::RowVector) = throw(DimensionMismatch("Cannot left-divide transposed vector by matrix")) -At_ldiv_B(mat::AbstractMatrix, rowvec::RowVector) = throw(DimensionMismatch("Cannot left-divide transposed vector by matrix")) -Ac_ldiv_B(mat::AbstractMatrix, rowvec::RowVector) = throw(DimensionMismatch("Cannot left-divide transposed vector by matrix")) +\(transmat::Transpose{<:Any,<:AbstractMatrix}, rowvec::RowVector) = + throw(DimensionMismatch("Cannot left-divide transposed vector by matrix")) +\(adjmat::Adjoint{<:Any,<:AbstractMatrix}, rowvec::RowVector) = + throw(DimensionMismatch("Cannot left-divide transposed vector by matrix")) # Right Division # @inline /(rowvec::RowVector, mat::AbstractMatrix) = transpose(transpose(mat) \ transpose(rowvec)) -@inline A_rdiv_Bt(rowvec::RowVector, mat::AbstractMatrix) = transpose(mat \ transpose(rowvec)) -@inline A_rdiv_Bc(rowvec::RowVector, mat::AbstractMatrix) = adjoint(mat \ adjoint(rowvec)) +/(rowvec::RowVector, transmat::Transpose{<:Any,<:AbstractMatrix}) = transpose(transmat.parent \ transpose(rowvec)) +/(rowvec::RowVector, adjmat::Adjoint{<:Any,<:AbstractMatrix}) = adjoint(adjmat.parent \ adjoint(rowvec)) + + +# definitions necessary for test/linalg/dense.jl to pass +# should be cleaned up / revised as necessary in the future +/(A::Number, B::Adjoint{<:Any,<:RowVector}) = /(A, adjoint(B.parent)) +/(A::Matrix, B::RowVector) = adjoint(adjoint(B) \ adjoint(A)) + + +# dismabiguation methods +*(A::Adjoint{<:Any,<:AbstractVector}, B::Transpose{<:Any,<:RowVector}) = adjoint(A.parent) * B +*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:RowVector}) = A * transpose(B.parent) +*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:RowVector}) = transpose(A.parent) * B +*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:RowVector}) = A * adjoint(B.parent) diff --git a/base/linalg/special.jl b/base/linalg/special.jl index 48a8053653d3d..2a751008e1869 100644 --- a/base/linalg/special.jl +++ b/base/linalg/special.jl @@ -122,5 +122,7 @@ for op in (:+, :-) end end -A_mul_Bc!(A::AbstractTriangular, B::Union{QRCompactWYQ,QRPackedQ}) = A_mul_Bc!(full!(A), B) -A_mul_Bc(A::AbstractTriangular, B::Union{QRCompactWYQ,QRPackedQ}) = A_mul_Bc(copy!(similar(parent(A)), A), B) +mul!(A::AbstractTriangular, adjB::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) = + (B = adjB.parent; mul!(full!(A), Adjoint(B))) +*(A::AbstractTriangular, adjB::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) = + (B = adjB.parent; *(copy!(similar(parent(A)), A), Adjoint(B))) diff --git a/base/linalg/svd.jl b/base/linalg/svd.jl index 2672a432bd27c..e25b921fc2141 100644 --- a/base/linalg/svd.jl +++ b/base/linalg/svd.jl @@ -256,7 +256,7 @@ svdvals(x::Number) = abs(x) svdvals(S::SVD{<:Any,T}) where {T} = (S[:S])::Vector{T} # SVD least squares -function A_ldiv_B!(A::SVD{T}, B::StridedVecOrMat) where T +function ldiv!(A::SVD{T}, B::StridedVecOrMat) where T k = searchsortedlast(A.S, eps(real(T))*A.S[1], rev=true) view(A.Vt,1:k,:)' * (view(A.S,1:k) .\ (view(A.U,:,1:k)' * B)) end diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index 20d587a6a1bc8..503781d046a08 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -299,46 +299,54 @@ end (-)(A::Hermitian{Tv,S}) where {Tv,S} = Hermitian{Tv,S}(-A.data, A.uplo) ## Matvec -A_mul_B!(y::StridedVector{T}, A::Symmetric{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasFloat} = +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) -A_mul_B!(y::StridedVector{T}, A::Hermitian{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasReal} = +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) -A_mul_B!(y::StridedVector{T}, A::Hermitian{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasComplex} = +mul!(y::StridedVector{T}, A::Hermitian{T,<:StridedMatrix}, x::StridedVector{T}) where {T<:BlasComplex} = BLAS.hemv!(A.uplo, one(T), A.data, x, zero(T), y) ## Matmat -A_mul_B!(C::StridedMatrix{T}, A::Symmetric{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = +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) -A_mul_B!(C::StridedMatrix{T}, A::StridedMatrix{T}, B::Symmetric{T,<:StridedMatrix}) where {T<:BlasFloat} = +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) -A_mul_B!(C::StridedMatrix{T}, A::Hermitian{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasReal} = +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) -A_mul_B!(C::StridedMatrix{T}, A::StridedMatrix{T}, B::Hermitian{T,<:StridedMatrix}) where {T<:BlasReal} = +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) -A_mul_B!(C::StridedMatrix{T}, A::Hermitian{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasComplex} = +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) -A_mul_B!(C::StridedMatrix{T}, A::StridedMatrix{T}, B::Hermitian{T,<:StridedMatrix}) where {T<:BlasComplex} = +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) *(A::HermOrSym, B::HermOrSym) = A * copy!(similar(parent(B)), B) # Fallbacks to avoid generic_matvecmul!/generic_matmatmul! ## Symmetric{<:Number} and Hermitian{<:Real} are invariant to transpose; peel off the t -At_mul_B(A::RealHermSymComplexSym, B::AbstractVector) = A*B -At_mul_B(A::RealHermSymComplexSym, B::AbstractMatrix) = A*B -A_mul_Bt(A::AbstractMatrix, B::RealHermSymComplexSym) = A*B +*(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 -Ac_mul_B(A::RealHermSymComplexHerm, B::AbstractVector) = A*B -Ac_mul_B(A::RealHermSymComplexHerm, B::AbstractMatrix) = A*B -A_mul_Bc(A::AbstractMatrix, B::RealHermSymComplexHerm) = A*B +*(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 RowVector -A_mul_Bt(A::RowVector, B::RealHermSymComplexSym) = A*B -A_mul_Bc(A::RowVector, B::RealHermSymComplexHerm) = A*B +*(A::RowVector, transB::Transpose{<:Any,<:RealHermSymComplexSym}) = A * transB.parent +*(A::RowVector, adjB::Adjoint{<:Any,<:RealHermSymComplexHerm}) = A * adjB.parent # ambiguities with AbstractTriangular -At_mul_B(A::RealHermSymComplexSym, B::AbstractTriangular) = A*B -A_mul_Bt(A::AbstractTriangular, B::RealHermSymComplexSym) = A*B -Ac_mul_B(A::RealHermSymComplexHerm, B::AbstractTriangular) = A*B -A_mul_Bc(A::AbstractTriangular, B::RealHermSymComplexHerm) = A*B +*(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 @@ -729,3 +737,40 @@ 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 RealHermSymComplex{Herm|Sym}, Adj/Trans of RowVector) +*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Adjoint{<:Any,<:RowVector}) = A.parent * B +*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Transpose{<:Any,<:RowVector}) = A.parent * B +*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Adjoint{<:Any,<:RowVector}) = A.parent * B +*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Transpose{<:Any,<:RowVector}) = 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 diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index e1b62b6e61c1c..30807f2011664 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -443,20 +443,40 @@ scale!(c::Number, A::Union{UpperTriangular,LowerTriangular}) = scale!(A,c) # BlasFloat routines # ###################### -A_mul_B!(A::Tridiagonal, B::AbstractTriangular) = A*full!(B) -A_mul_B!(C::AbstractMatrix, A::AbstractTriangular, B::Tridiagonal) = A_mul_B!(C, copy!(similar(parent(A)), A), B) -A_mul_B!(C::AbstractMatrix, A::Tridiagonal, B::AbstractTriangular) = A_mul_B!(C, A, copy!(similar(parent(B)), B)) -A_mul_Bt!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = A_mul_B!(A, transpose!(C, B)) -A_mul_Bc!(C::AbstractMatrix, A::AbstractTriangular, B::AbstractVecOrMat) = A_mul_B!(A, adjoint!(C, B)) -A_mul_Bc!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = A_mul_B!(A, adjoint!(C, B)) -# The three methods are neceesary to avoid ambiguities with definitions in matmul.jl -for f in (:A_mul_B!, :Ac_mul_B!, :At_mul_B!) - @eval begin - ($f)(C::AbstractVector , A::AbstractTriangular, B::AbstractVector) = ($f)(A, copy!(C, B)) - ($f)(C::AbstractMatrix , A::AbstractTriangular, B::AbstractVecOrMat) = ($f)(A, copy!(C, B)) - ($f)(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = ($f)(A, copy!(C, B)) - end -end +mul!(A::Tridiagonal, B::AbstractTriangular) = A*full!(B) +mul!(C::AbstractMatrix, A::AbstractTriangular, B::Tridiagonal) = mul!(C, copy!(similar(parent(A)), A), B) +mul!(C::AbstractMatrix, A::Tridiagonal, B::AbstractTriangular) = mul!(C, A, copy!(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, copy!(C, B)) +mul!(C::AbstractMatrix , A::AbstractTriangular, B::AbstractVecOrMat) = mul!(A, copy!(C, B)) +mul!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = mul!(A, copy!(C, B)) +mul!(C::AbstractVector , adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractVector) = + (A = adjA.parent; mul!(Adjoint(A), copy!(C, B))) +mul!(C::AbstractMatrix , adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = + (A = adjA.parent; mul!(Adjoint(A), copy!(C, B))) +mul!(C::AbstractVecOrMat, adjA::Adjoint{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = + (A = adjA.parent; mul!(Adjoint(A), copy!(C, B))) +mul!(C::AbstractVector , transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractVector) = + (A = transA.parent; mul!(Transpose(A), copy!(C, B))) +mul!(C::AbstractMatrix , transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = + (A = transA.parent; mul!(Transpose(A), copy!(C, B))) +mul!(C::AbstractVecOrMat, transA::Transpose{<:Any,<:AbstractTriangular}, B::AbstractVecOrMat) = + (A = transA.parent; mul!(Transpose(A), copy!(C, B))) +mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, adjoint(B.parent)) +mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = mul!(C, A, adjoint(B.parent)) +mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVecOrMat}) = mul!(C, A, adjoint(B.parent)) +mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVecOrMat}) = mul!(C, A, transpose(B.parent)) +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'), @@ -464,54 +484,54 @@ for (t, uploc, isunitc) in ((:LowerTriangular, 'L', 'N'), (:UnitUpperTriangular, 'U', 'U')) @eval begin # Vector multiplication - A_mul_B!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasFloat} = + mul!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasFloat} = BLAS.trmv!($uploc, 'N', $isunitc, A.data, b) - At_mul_B!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasFloat} = - BLAS.trmv!($uploc, 'T', $isunitc, A.data, b) - Ac_mul_B!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasReal} = - BLAS.trmv!($uploc, 'T', $isunitc, A.data, b) - Ac_mul_B!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasComplex} = - BLAS.trmv!($uploc, 'C', $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)) # Matrix multiplication - A_mul_B!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = + mul!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B) - A_mul_B!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = + mul!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) - At_mul_B!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} = - BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B) - Ac_mul_B!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasComplex} = - BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), A.data, B) - Ac_mul_B!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasReal} = - BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), A.data, B) + 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)) - A_mul_Bt!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = - BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A) - A_mul_Bc!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasComplex} = - BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), B.data, A) - A_mul_Bc!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasReal} = - BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), B.data, A) + 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)) # Left division - A_ldiv_B!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = + ldiv!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = LAPACK.trtrs!($uploc, 'N', $isunitc, A.data, B) - At_ldiv_B!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = - LAPACK.trtrs!($uploc, 'T', $isunitc, A.data, B) - Ac_ldiv_B!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasReal} = - LAPACK.trtrs!($uploc, 'T', $isunitc, A.data, B) - Ac_ldiv_B!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = - LAPACK.trtrs!($uploc, 'C', $isunitc, A.data, B) + ldiv!(transA::Transpose{<:Any,<:$t{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = + (A = transA.parent; LAPACK.trtrs!($uploc, 'T', $isunitc, A.data, B)) + ldiv!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasReal} = + (A = adjA.parent; LAPACK.trtrs!($uploc, 'T', $isunitc, A.data, B)) + ldiv!(adjA::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = + (A = adjA.parent; LAPACK.trtrs!($uploc, 'C', $isunitc, A.data, B)) # Right division - A_rdiv_B!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = + rdiv!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = BLAS.trsm!('R', $uploc, 'N', $isunitc, one(T), B.data, A) - A_rdiv_Bt!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} = - BLAS.trsm!('R', $uploc, 'T', $isunitc, one(T), B.data, A) - A_rdiv_Bc!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasReal} = - BLAS.trsm!('R', $uploc, 'T', $isunitc, one(T), B.data, A) - A_rdiv_Bc!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasComplex} = - BLAS.trsm!('R', $uploc, 'C', $isunitc, one(T), B.data, A) + rdiv!(A::StridedMatrix{T}, transB::Transpose{<:Any,<:$t{T,<:StridedMatrix}}) where {T<:BlasFloat} = + (B = transB.parent; BLAS.trsm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) + rdiv!(A::StridedMatrix{T}, adjB::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}) where {T<:BlasReal} = + (B = adjB.parent; BLAS.trsm!('R', $uploc, 'T', $isunitc, one(T), B.data, A)) + rdiv!(A::StridedMatrix{T}, adjB::Adjoint{<:Any,<:$t{T,<:StridedMatrix}}) where {T<:BlasComplex} = + (B = adjB.parent; BLAS.trsm!('R', $uploc, 'C', $isunitc, one(T), B.data, A)) # Matrix inverse inv!(A::$t{T,S}) where {T<:BlasFloat,S<:StridedMatrix} = @@ -537,14 +557,14 @@ end function inv(A::LowerTriangular{T}) where T S = typeof((zero(T)*one(T) + zero(T))/one(T)) - LowerTriangular(A_ldiv_B!(convert(AbstractArray{S}, A), Matrix{S}(I, size(A, 1), size(A, 1)))) + LowerTriangular(ldiv!(convert(AbstractArray{S}, A), Matrix{S}(I, size(A, 1), size(A, 1)))) end function inv(A::UpperTriangular{T}) where T S = typeof((zero(T)*one(T) + zero(T))/one(T)) - UpperTriangular(A_ldiv_B!(convert(AbstractArray{S}, A), Matrix{S}(I, size(A, 1), size(A, 1)))) + UpperTriangular(ldiv!(convert(AbstractArray{S}, A), Matrix{S}(I, size(A, 1), size(A, 1)))) end -inv(A::UnitUpperTriangular{T}) where {T} = UnitUpperTriangular(A_ldiv_B!(A, Matrix{T}(I, size(A, 1), size(A, 1)))) -inv(A::UnitLowerTriangular{T}) where {T} = UnitLowerTriangular(A_ldiv_B!(A, Matrix{T}(I, size(A, 1), size(A, 1)))) +inv(A::UnitUpperTriangular{T}) where {T} = UnitUpperTriangular(ldiv!(A, Matrix{T}(I, size(A, 1), size(A, 1)))) +inv(A::UnitLowerTriangular{T}) where {T} = UnitLowerTriangular(ldiv!(A, Matrix{T}(I, size(A, 1), size(A, 1)))) errorbounds(A::AbstractTriangular{T,<:StridedMatrix}, X::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:Union{BigFloat,Complex{BigFloat}}} = error("not implemented yet! Please submit a pull request.") @@ -626,7 +646,7 @@ for (t, unitt) in ((UpperTriangular, UnitUpperTriangular), end ## Generic triangular multiplication -function A_mul_B!(A::UpperTriangular, B::StridedVecOrMat) +function mul!(A::UpperTriangular, B::StridedVecOrMat) 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")) @@ -642,7 +662,7 @@ function A_mul_B!(A::UpperTriangular, B::StridedVecOrMat) end B end -function A_mul_B!(A::UnitUpperTriangular, B::StridedVecOrMat) +function mul!(A::UnitUpperTriangular, B::StridedVecOrMat) 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")) @@ -659,7 +679,7 @@ function A_mul_B!(A::UnitUpperTriangular, B::StridedVecOrMat) B end -function A_mul_B!(A::LowerTriangular, B::StridedVecOrMat) +function mul!(A::LowerTriangular, B::StridedVecOrMat) 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")) @@ -675,7 +695,7 @@ function A_mul_B!(A::LowerTriangular, B::StridedVecOrMat) end B end -function A_mul_B!(A::UnitLowerTriangular, B::StridedVecOrMat) +function mul!(A::UnitLowerTriangular, B::StridedVecOrMat) 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")) @@ -692,7 +712,8 @@ function A_mul_B!(A::UnitLowerTriangular, B::StridedVecOrMat) B end -function Ac_mul_B!(A::UpperTriangular, B::StridedVecOrMat) +function mul!(adjA::Adjoint{<:Any,<:UpperTriangular}, B::StridedVecOrMat) + A = adjA.parent 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")) @@ -708,7 +729,8 @@ function Ac_mul_B!(A::UpperTriangular, B::StridedVecOrMat) end B end -function Ac_mul_B!(A::UnitUpperTriangular, B::StridedVecOrMat) +function mul!(adjA::Adjoint{<:Any,<:UnitUpperTriangular}, B::StridedVecOrMat) + A = adjA.parent 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")) @@ -725,7 +747,8 @@ function Ac_mul_B!(A::UnitUpperTriangular, B::StridedVecOrMat) B end -function Ac_mul_B!(A::LowerTriangular, B::StridedVecOrMat) +function mul!(adjA::Adjoint{<:Any,<:LowerTriangular}, B::StridedVecOrMat) + A = adjA.parent 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")) @@ -741,7 +764,8 @@ function Ac_mul_B!(A::LowerTriangular, B::StridedVecOrMat) end B end -function Ac_mul_B!(A::UnitLowerTriangular, B::StridedVecOrMat) +function mul!(adjA::Adjoint{<:Any,<:UnitLowerTriangular}, B::StridedVecOrMat) + A = adjA.parent 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")) @@ -758,7 +782,8 @@ function Ac_mul_B!(A::UnitLowerTriangular, B::StridedVecOrMat) B end -function At_mul_B!(A::UpperTriangular, B::StridedVecOrMat) +function mul!(transA::Transpose{<:Any,<:UpperTriangular}, B::StridedVecOrMat) + A = transA.parent 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")) @@ -774,7 +799,8 @@ function At_mul_B!(A::UpperTriangular, B::StridedVecOrMat) end B end -function At_mul_B!(A::UnitUpperTriangular, B::StridedVecOrMat) +function mul!(transA::Transpose{<:Any,<:UnitUpperTriangular}, B::StridedVecOrMat) + A = transA.parent 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")) @@ -791,7 +817,8 @@ function At_mul_B!(A::UnitUpperTriangular, B::StridedVecOrMat) B end -function At_mul_B!(A::LowerTriangular, B::StridedVecOrMat) +function mul!(transA::Transpose{<:Any,<:LowerTriangular}, B::StridedVecOrMat) + A = transA.parent 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")) @@ -807,7 +834,8 @@ function At_mul_B!(A::LowerTriangular, B::StridedVecOrMat) end B end -function At_mul_B!(A::UnitLowerTriangular, B::StridedVecOrMat) +function mul!(transA::Transpose{<:Any,<:UnitLowerTriangular}, B::StridedVecOrMat) + A = transA.parent 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")) @@ -824,7 +852,7 @@ function At_mul_B!(A::UnitLowerTriangular, B::StridedVecOrMat) B end -function A_mul_B!(A::StridedMatrix, B::UpperTriangular) +function mul!(A::StridedMatrix, B::UpperTriangular) 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))")) @@ -840,7 +868,7 @@ function A_mul_B!(A::StridedMatrix, B::UpperTriangular) end A end -function A_mul_B!(A::StridedMatrix, B::UnitUpperTriangular) +function mul!(A::StridedMatrix, B::UnitUpperTriangular) 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))")) @@ -857,7 +885,7 @@ function A_mul_B!(A::StridedMatrix, B::UnitUpperTriangular) A end -function A_mul_B!(A::StridedMatrix, B::LowerTriangular) +function mul!(A::StridedMatrix, B::LowerTriangular) 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))")) @@ -873,7 +901,7 @@ function A_mul_B!(A::StridedMatrix, B::LowerTriangular) end A end -function A_mul_B!(A::StridedMatrix, B::UnitLowerTriangular) +function mul!(A::StridedMatrix, B::UnitLowerTriangular) 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))")) @@ -890,7 +918,8 @@ function A_mul_B!(A::StridedMatrix, B::UnitLowerTriangular) A end -function A_mul_Bc!(A::StridedMatrix, B::UpperTriangular) +function mul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UpperTriangular}) + B = adjB.parent 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))")) @@ -906,7 +935,8 @@ function A_mul_Bc!(A::StridedMatrix, B::UpperTriangular) end A end -function A_mul_Bc!(A::StridedMatrix, B::UnitUpperTriangular) +function mul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UnitUpperTriangular}) + B = adjB.parent 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))")) @@ -923,7 +953,8 @@ function A_mul_Bc!(A::StridedMatrix, B::UnitUpperTriangular) A end -function A_mul_Bc!(A::StridedMatrix, B::LowerTriangular) +function mul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:LowerTriangular}) + B = adjB.parent 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))")) @@ -939,7 +970,8 @@ function A_mul_Bc!(A::StridedMatrix, B::LowerTriangular) end A end -function A_mul_Bc!(A::StridedMatrix, B::UnitLowerTriangular) +function mul!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UnitLowerTriangular}) + B = adjB.parent 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))")) @@ -956,7 +988,8 @@ function A_mul_Bc!(A::StridedMatrix, B::UnitLowerTriangular) A end -function A_mul_Bt!(A::StridedMatrix, B::UpperTriangular) +function mul!(A::StridedMatrix, transB::Transpose{<:Any,<:UpperTriangular}) + B = transB.parent 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))")) @@ -972,7 +1005,8 @@ function A_mul_Bt!(A::StridedMatrix, B::UpperTriangular) end A end -function A_mul_Bt!(A::StridedMatrix, B::UnitUpperTriangular) +function mul!(A::StridedMatrix, transB::Transpose{<:Any,<:UnitUpperTriangular}) + B = transB.parent 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))")) @@ -989,7 +1023,8 @@ function A_mul_Bt!(A::StridedMatrix, B::UnitUpperTriangular) A end -function A_mul_Bt!(A::StridedMatrix, B::LowerTriangular) +function mul!(A::StridedMatrix, transB::Transpose{<:Any,<:LowerTriangular}) + B = transB.parent 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))")) @@ -1005,7 +1040,8 @@ function A_mul_Bt!(A::StridedMatrix, B::LowerTriangular) end A end -function A_mul_Bt!(A::StridedMatrix, B::UnitLowerTriangular) +function mul!(A::StridedMatrix, transB::Transpose{<:Any,<:UnitLowerTriangular}) + B = transB.parent 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))")) @@ -1086,7 +1122,8 @@ function naivesub!(A::UnitLowerTriangular, b::AbstractVector, x::AbstractVector end # in the following transpose and conjugate transpose naive substitution variants, # accumulating in z rather than b[j] significantly improves performance as of Dec 2015 -function At_ldiv_B!(A::LowerTriangular, b::AbstractVector, x::AbstractVector = b) +function ldiv!(transA::Transpose{<:Any,<:LowerTriangular}, b::AbstractVector, x::AbstractVector = b) + A = transA.parent n = size(A, 1) if !(n == length(b) == length(x)) throw(DimensionMismatch("first dimension of left hand side A, $n, length of output x, $(length(x)), and length of right hand side b, $(length(b)), must be equal")) @@ -1101,7 +1138,8 @@ function At_ldiv_B!(A::LowerTriangular, b::AbstractVector, x::AbstractVector = b end x end -function At_ldiv_B!(A::UnitLowerTriangular, b::AbstractVector, x::AbstractVector = b) +function ldiv!(transA::Transpose{<:Any,<:UnitLowerTriangular}, b::AbstractVector, x::AbstractVector = b) + A = transA.parent n = size(A, 1) if !(n == length(b) == length(x)) throw(DimensionMismatch("first dimension of left hand side A, $n, length of output x, $(length(x)), and length of right hand side b, $(length(b)), must be equal")) @@ -1115,7 +1153,8 @@ function At_ldiv_B!(A::UnitLowerTriangular, b::AbstractVector, x::AbstractVector end x end -function At_ldiv_B!(A::UpperTriangular, b::AbstractVector, x::AbstractVector = b) +function ldiv!(transA::Transpose{<:Any,<:UpperTriangular}, b::AbstractVector, x::AbstractVector = b) + A = transA.parent n = size(A, 1) if !(n == length(b) == length(x)) throw(DimensionMismatch("first dimension of left hand side A, $n, length of output x, $(length(x)), and length of right hand side b, $(length(b)), must be equal")) @@ -1130,7 +1169,8 @@ function At_ldiv_B!(A::UpperTriangular, b::AbstractVector, x::AbstractVector = b end x end -function At_ldiv_B!(A::UnitUpperTriangular, b::AbstractVector, x::AbstractVector = b) +function ldiv!(transA::Transpose{<:Any,<:UnitUpperTriangular}, b::AbstractVector, x::AbstractVector = b) + A = transA.parent n = size(A, 1) if !(n == length(b) == length(x)) throw(DimensionMismatch("first dimension of left hand side A, $n, length of output x, $(length(x)), and length of right hand side b, $(length(b)), must be equal")) @@ -1144,7 +1184,8 @@ function At_ldiv_B!(A::UnitUpperTriangular, b::AbstractVector, x::AbstractVector end x end -function Ac_ldiv_B!(A::LowerTriangular, b::AbstractVector, x::AbstractVector = b) +function ldiv!(adjA::Adjoint{<:Any,<:LowerTriangular}, b::AbstractVector, x::AbstractVector = b) + A = adjA.parent n = size(A, 1) if !(n == length(b) == length(x)) throw(DimensionMismatch("first dimension of left hand side A, $n, length of output x, $(length(x)), and length of right hand side b, $(length(b)), must be equal")) @@ -1159,7 +1200,8 @@ function Ac_ldiv_B!(A::LowerTriangular, b::AbstractVector, x::AbstractVector = b end x end -function Ac_ldiv_B!(A::UnitLowerTriangular, b::AbstractVector, x::AbstractVector = b) +function ldiv!(adjA::Adjoint{<:Any,<:UnitLowerTriangular}, b::AbstractVector, x::AbstractVector = b) + A = adjA.parent n = size(A, 1) if !(n == length(b) == length(x)) throw(DimensionMismatch("first dimension of left hand side A, $n, length of output x, $(length(x)), and length of right hand side b, $(length(b)), must be equal")) @@ -1173,7 +1215,8 @@ function Ac_ldiv_B!(A::UnitLowerTriangular, b::AbstractVector, x::AbstractVector end x end -function Ac_ldiv_B!(A::UpperTriangular, b::AbstractVector, x::AbstractVector = b) +function ldiv!(adjA::Adjoint{<:Any,<:UpperTriangular}, b::AbstractVector, x::AbstractVector = b) + A = adjA.parent n = size(A, 1) if !(n == length(b) == length(x)) throw(DimensionMismatch("first dimension of left hand side A, $n, length of output x, $(length(x)), and length of right hand side b, $(length(b)), must be equal")) @@ -1188,7 +1231,8 @@ function Ac_ldiv_B!(A::UpperTriangular, b::AbstractVector, x::AbstractVector = b end x end -function Ac_ldiv_B!(A::UnitUpperTriangular, b::AbstractVector, x::AbstractVector = b) +function ldiv!(adjA::Adjoint{<:Any,<:UnitUpperTriangular}, b::AbstractVector, x::AbstractVector = b) + A = adjA.parent n = size(A, 1) if !(n == length(b) == length(x)) throw(DimensionMismatch("first dimension of left hand side A, $n, length of output x, $(length(x)), and length of right hand side b, $(length(b)), must be equal")) @@ -1203,7 +1247,7 @@ function Ac_ldiv_B!(A::UnitUpperTriangular, b::AbstractVector, x::AbstractVector x end -function A_rdiv_B!(A::StridedMatrix, B::UpperTriangular) +function rdiv!(A::StridedMatrix, B::UpperTriangular) 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))")) @@ -1219,7 +1263,7 @@ function A_rdiv_B!(A::StridedMatrix, B::UpperTriangular) end A end -function A_rdiv_B!(A::StridedMatrix, B::UnitUpperTriangular) +function rdiv!(A::StridedMatrix, B::UnitUpperTriangular) 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))")) @@ -1236,7 +1280,7 @@ function A_rdiv_B!(A::StridedMatrix, B::UnitUpperTriangular) A end -function A_rdiv_B!(A::StridedMatrix, B::LowerTriangular) +function rdiv!(A::StridedMatrix, B::LowerTriangular) 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))")) @@ -1252,7 +1296,7 @@ function A_rdiv_B!(A::StridedMatrix, B::LowerTriangular) end A end -function A_rdiv_B!(A::StridedMatrix, B::UnitLowerTriangular) +function rdiv!(A::StridedMatrix, B::UnitLowerTriangular) 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))")) @@ -1269,7 +1313,8 @@ function A_rdiv_B!(A::StridedMatrix, B::UnitLowerTriangular) A end -function A_rdiv_Bc!(A::StridedMatrix, B::UpperTriangular) +function rdiv!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UpperTriangular}) + B = adjB.parent 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))")) @@ -1285,7 +1330,8 @@ function A_rdiv_Bc!(A::StridedMatrix, B::UpperTriangular) end A end -function A_rdiv_Bc!(A::StridedMatrix, B::UnitUpperTriangular) +function rdiv!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UnitUpperTriangular}) + B = adjB.parent 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))")) @@ -1302,7 +1348,8 @@ function A_rdiv_Bc!(A::StridedMatrix, B::UnitUpperTriangular) A end -function A_rdiv_Bc!(A::StridedMatrix, B::LowerTriangular) +function rdiv!(A::StridedMatrix, adjB::Adjoint{<:Any,<:LowerTriangular}) + B = adjB.parent 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))")) @@ -1318,7 +1365,8 @@ function A_rdiv_Bc!(A::StridedMatrix, B::LowerTriangular) end A end -function A_rdiv_Bc!(A::StridedMatrix, B::UnitLowerTriangular) +function rdiv!(A::StridedMatrix, adjB::Adjoint{<:Any,<:UnitLowerTriangular}) + B = adjB.parent 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))")) @@ -1335,7 +1383,8 @@ function A_rdiv_Bc!(A::StridedMatrix, B::UnitLowerTriangular) A end -function A_rdiv_Bt!(A::StridedMatrix, B::UpperTriangular) +function rdiv!(A::StridedMatrix, transB::Transpose{<:Any,<:UpperTriangular}) + B = transB.parent 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))")) @@ -1351,7 +1400,8 @@ function A_rdiv_Bt!(A::StridedMatrix, B::UpperTriangular) end A end -function A_rdiv_Bt!(A::StridedMatrix, B::UnitUpperTriangular) +function rdiv!(A::StridedMatrix, transB::Transpose{<:Any,<:UnitUpperTriangular}) + B = transB.parent 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))")) @@ -1368,7 +1418,8 @@ function A_rdiv_Bt!(A::StridedMatrix, B::UnitUpperTriangular) A end -function A_rdiv_Bt!(A::StridedMatrix, B::LowerTriangular) +function rdiv!(A::StridedMatrix, transB::Transpose{<:Any,<:LowerTriangular}) + B = transB.parent 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))")) @@ -1384,7 +1435,8 @@ function A_rdiv_Bt!(A::StridedMatrix, B::LowerTriangular) end A end -function A_rdiv_Bt!(A::StridedMatrix, B::UnitLowerTriangular) +function rdiv!(A::StridedMatrix, transB::Transpose{<:Any,<:UnitLowerTriangular}) + B = transB.parent 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))")) @@ -1401,28 +1453,44 @@ function A_rdiv_Bt!(A::StridedMatrix, B::UnitLowerTriangular) A end -for f in (:Ac_mul_B!, :At_mul_B!, :Ac_ldiv_B!, :At_ldiv_B!) - @eval begin - $f(A::Union{LowerTriangular,UnitLowerTriangular}, B::UpperTriangular) = - UpperTriangular($f(A, triu!(B.data))) - $f(A::Union{UpperTriangular,UnitUpperTriangular}, B::LowerTriangular) = - LowerTriangular($f(A, tril!(B.data))) - end -end - -A_rdiv_B!(A::UpperTriangular, B::Union{UpperTriangular,UnitUpperTriangular}) = - UpperTriangular(A_rdiv_B!(triu!(A.data), B)) -A_rdiv_B!(A::LowerTriangular, B::Union{LowerTriangular,UnitLowerTriangular}) = - LowerTriangular(A_rdiv_B!(tril!(A.data), B)) - -for f in (:A_mul_Bc!, :A_mul_Bt!, :A_rdiv_Bc!, :A_rdiv_Bt!) - @eval begin - $f(A::UpperTriangular, B::Union{LowerTriangular,UnitLowerTriangular}) = - UpperTriangular($f(triu!(A.data), B)) - $f(A::LowerTriangular, B::Union{UpperTriangular,UnitUpperTriangular}) = - LowerTriangular($f(tril!(A.data), B)) - end -end +mul!(adjA::Adjoint{<:Any,<:Union{LowerTriangular,UnitLowerTriangular}}, B::UpperTriangular) = + (A = adjA.parent; UpperTriangular(mul!(Adjoint(A), triu!(B.data)))) +mul!(adjA::Adjoint{<:Any,<:Union{UpperTriangular,UnitUpperTriangular}}, B::LowerTriangular) = + (A = adjA.parent; LowerTriangular(mul!(Adjoint(A), tril!(B.data)))) +mul!(transA::Transpose{<:Any,<:Union{LowerTriangular,UnitLowerTriangular}}, B::UpperTriangular) = + (A = transA.parent; UpperTriangular(mul!(Transpose(A), triu!(B.data)))) +mul!(transA::Transpose{<:Any,<:Union{UpperTriangular,UnitUpperTriangular}}, B::LowerTriangular) = + (A = transA.parent; LowerTriangular(mul!(Transpose(A), tril!(B.data)))) +ldiv!(adjA::Adjoint{<:Any,<:Union{LowerTriangular,UnitLowerTriangular}}, B::UpperTriangular) = + (A = adjA.parent; UpperTriangular(ldiv!(Adjoint(A), triu!(B.data)))) +ldiv!(adjA::Adjoint{<:Any,<:Union{UpperTriangular,UnitUpperTriangular}}, B::LowerTriangular) = + (A = adjA.parent; LowerTriangular(ldiv!(Adjoint(A), tril!(B.data)))) +ldiv!(transA::Transpose{<:Any,<:Union{LowerTriangular,UnitLowerTriangular}}, B::UpperTriangular) = + (A = transA.parent; UpperTriangular(ldiv!(Transpose(A), triu!(B.data)))) +ldiv!(transA::Transpose{<:Any,<:Union{UpperTriangular,UnitUpperTriangular}}, B::LowerTriangular) = + (A = transA.parent; LowerTriangular(ldiv!(Transpose(A), tril!(B.data)))) + +rdiv!(A::UpperTriangular, B::Union{UpperTriangular,UnitUpperTriangular}) = + UpperTriangular(rdiv!(triu!(A.data), B)) +rdiv!(A::LowerTriangular, B::Union{LowerTriangular,UnitLowerTriangular}) = + LowerTriangular(rdiv!(tril!(A.data), B)) + +mul!(A::UpperTriangular, adjB::Adjoint{<:Any,<:Union{LowerTriangular,UnitLowerTriangular}}) = + (B = adjB.parent; UpperTriangular(mul!(triu!(A.data), Adjoint(B)))) +mul!(A::LowerTriangular, adjB::Adjoint{<:Any,<:Union{UpperTriangular,UnitUpperTriangular}}) = + (B = adjB.parent; LowerTriangular(mul!(tril!(A.data), Adjoint(B)))) +mul!(A::UpperTriangular, transB::Transpose{<:Any,<:Union{LowerTriangular,UnitLowerTriangular}}) = + (B = transB.parent; UpperTriangular(mul!(triu!(A.data), Transpose(B)))) +mul!(A::LowerTriangular, transB::Transpose{<:Any,<:Union{UpperTriangular,UnitUpperTriangular}}) = + (B = transB.parent; LowerTriangular(mul!(tril!(A.data), Transpose(B)))) +rdiv!(A::UpperTriangular, adjB::Adjoint{<:Any,<:Union{LowerTriangular,UnitLowerTriangular}}) = + (B = adjB.parent; UpperTriangular(rdiv!(triu!(A.data), Adjoint(B)))) +rdiv!(A::LowerTriangular, adjB::Adjoint{<:Any,<:Union{UpperTriangular,UnitUpperTriangular}}) = + (B = adjB.parent; LowerTriangular(rdiv!(tril!(A.data), Adjoint(B)))) +rdiv!(A::UpperTriangular, transB::Transpose{<:Any,<:Union{LowerTriangular,UnitLowerTriangular}}) = + (B = transB.parent; UpperTriangular(rdiv!(triu!(A.data), Transpose(B)))) +rdiv!(A::LowerTriangular, transB::Transpose{<:Any,<:Union{UpperTriangular,UnitUpperTriangular}}) = + (B = transB.parent; LowerTriangular(rdiv!(tril!(A.data), Transpose(B)))) # Promotion ## Promotion methods in matmul don't apply to triangular multiplication since @@ -1433,9 +1501,9 @@ end ## Some Triangular-Triangular cases. We might want to write taylored methods ## for these cases, but I'm not sure it is worth it. -(*)(A::Union{Tridiagonal,SymTridiagonal}, B::AbstractTriangular) = A_mul_B!(Matrix(A), B) +(*)(A::Union{Tridiagonal,SymTridiagonal}, B::AbstractTriangular) = mul!(Matrix(A), B) -for (f1, f2) in ((:*, :A_mul_B!), (:\, :A_ldiv_B!)) +for (f1, f2) in ((:*, :mul!), (:\, :ldiv!)) @eval begin function ($f1)(A::LowerTriangular, B::LowerTriangular) TAB = typeof(($f1)(zero(eltype(A)), zero(eltype(B))) + @@ -1471,39 +1539,46 @@ for (f1, f2) in ((:*, :A_mul_B!), (:\, :A_ldiv_B!)) end end -for (f1, f2) in ((:Ac_mul_B, :Ac_mul_B!), (:At_mul_B, :At_mul_B!), - (:Ac_ldiv_B, Ac_ldiv_B!), (:At_ldiv_B, :At_ldiv_B!)) +for (ipop, op, xform) in ( + (:mul!, :*, :Adjoint), + (:mul!, :*, :Transpose), + (:ldiv!, :\, :Adjoint), + (:ldiv!, :\, :Transpose)) @eval begin - function ($f1)(A::UpperTriangular, B::LowerTriangular) - TAB = typeof(($f1)(zero(eltype(A)), zero(eltype(B))) + - ($f1)(zero(eltype(A)), zero(eltype(B)))) + function ($op)(xformA::($xform){<:Any,<:UpperTriangular}, B::LowerTriangular) + A = xformA.parent + TAB = typeof(($op)($xform(zero(eltype(A))), zero(eltype(B))) + + ($op)($xform(zero(eltype(A))), zero(eltype(B)))) BB = similar(B, TAB, size(B)) copy!(BB, B) - return LowerTriangular($f2(convert(AbstractMatrix{TAB}, A), BB)) + return LowerTriangular(($ipop)($xform(convert(AbstractMatrix{TAB}, A)), BB)) end - function ($f1)(A::UnitUpperTriangular, B::LowerTriangular) + function ($op)(xformA::($xform){<:Any,<:UnitUpperTriangular}, B::LowerTriangular) + A = xformA.parent TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) + (*)(zero(eltype(A)), zero(eltype(B)))) BB = similar(B, TAB, size(B)) copy!(BB, B) - return LowerTriangular($f2(convert(AbstractMatrix{TAB}, A), BB)) + return LowerTriangular($ipop($xform(convert(AbstractMatrix{TAB}, A)), BB)) end - function ($f1)(A::LowerTriangular, B::UpperTriangular) - TAB = typeof(($f1)(zero(eltype(A)), zero(eltype(B))) + - ($f1)(zero(eltype(A)), zero(eltype(B)))) + function ($op)(xformA::($xform){<:Any,<:LowerTriangular}, B::UpperTriangular) + A = xformA.parent + TAB = typeof(($op)($xform(zero(eltype(A))), zero(eltype(B))) + + ($op)($xform(zero(eltype(A))), zero(eltype(B)))) BB = similar(B, TAB, size(B)) copy!(BB, B) - return UpperTriangular($f2(convert(AbstractMatrix{TAB}, A), BB)) + return UpperTriangular($ipop($xform(convert(AbstractMatrix{TAB}, A)), BB)) end - function ($f1)(A::UnitLowerTriangular, B::UpperTriangular) + function ($op)(xformA::($xform){<:Any,<:UnitLowerTriangular}, B::UpperTriangular) + A = xformA.parent TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) + (*)(zero(eltype(A)), zero(eltype(B)))) BB = similar(B, TAB, size(B)) copy!(BB, B) - return UpperTriangular($f2(convert(AbstractMatrix{TAB}, A), BB)) + return UpperTriangular($ipop($xform(convert(AbstractMatrix{TAB}, A)), BB)) end end end @@ -1513,203 +1588,309 @@ function (/)(A::LowerTriangular, B::LowerTriangular) (/)(zero(eltype(A)), zero(eltype(B)))) AA = similar(A, TAB, size(A)) copy!(AA, A) - return LowerTriangular(A_rdiv_B!(AA, convert(AbstractMatrix{TAB}, B))) + return LowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B))) end function (/)(A::LowerTriangular, B::UnitLowerTriangular) TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) + (*)(zero(eltype(A)), zero(eltype(B)))) AA = similar(A, TAB, size(A)) copy!(AA, A) - return LowerTriangular(A_rdiv_B!(AA, convert(AbstractMatrix{TAB}, B))) + return LowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B))) end function (/)(A::UpperTriangular, B::UpperTriangular) TAB = typeof((/)(zero(eltype(A)), zero(eltype(B))) + (/)(zero(eltype(A)), zero(eltype(B)))) AA = similar(A, TAB, size(A)) copy!(AA, A) - return UpperTriangular(A_rdiv_B!(AA, convert(AbstractMatrix{TAB}, B))) + return UpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B))) end function (/)(A::UpperTriangular, B::UnitUpperTriangular) TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) + (*)(zero(eltype(A)), zero(eltype(B)))) AA = similar(A, TAB, size(A)) copy!(AA, A) - return UpperTriangular(A_rdiv_B!(AA, convert(AbstractMatrix{TAB}, B))) + return UpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B))) end -for (f1, f2) in ((:A_mul_Bc, :A_mul_Bc!), (:A_mul_Bt, :A_mul_Bt!), - (:A_rdiv_Bc, :A_rdiv_Bc!), (:A_rdiv_Bt, :A_rdiv_Bt!)) +for (ipop, op, xform) in ( + (:mul!, :*, :Adjoint), + (:mul!, :*, :Transpose), + (:rdiv!, :/, :Adjoint), + (:rdiv!, :/, :Transpose)) @eval begin - function $f1(A::LowerTriangular, B::UpperTriangular) - TAB = typeof(($f1)(zero(eltype(A)), zero(eltype(B))) + - ($f1)(zero(eltype(A)), zero(eltype(B)))) + function ($op)(A::LowerTriangular, xformB::($xform){<:Any,<:UpperTriangular}) + B = xformB.parent + TAB = typeof(($op)(zero(eltype(A)), $xform(zero(eltype(B)))) + + ($op)(zero(eltype(A)), $xform(zero(eltype(B))))) AA = similar(A, TAB, size(A)) copy!(AA, A) - return LowerTriangular($f2(AA, convert(AbstractMatrix{TAB}, B))) + return LowerTriangular($ipop(AA, $xform(convert(AbstractMatrix{TAB}, B)))) end - function $f1(A::LowerTriangular, B::UnitUpperTriangular) + function ($op)(A::LowerTriangular, xformB::($xform){<:Any,<:UnitUpperTriangular}) + B = xformB.parent TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) + (*)(zero(eltype(A)), zero(eltype(B)))) AA = similar(A, TAB, size(A)) copy!(AA, A) - return LowerTriangular($f2(AA, convert(AbstractMatrix{TAB}, B))) + return LowerTriangular($ipop(AA, $xform(convert(AbstractMatrix{TAB}, B)))) end - function $f1(A::UpperTriangular, B::LowerTriangular) - TAB = typeof(($f1)(zero(eltype(A)), zero(eltype(B))) + - ($f1)(zero(eltype(A)), zero(eltype(B)))) + function ($op)(A::UpperTriangular, xformB::($xform){<:Any,<:LowerTriangular}) + B = xformB.parent + TAB = typeof(($op)(zero(eltype(A)), $xform(zero(eltype(B)))) + + ($op)(zero(eltype(A)), $xform(zero(eltype(B))))) AA = similar(A, TAB, size(A)) copy!(AA, A) - return UpperTriangular($f2(AA, convert(AbstractMatrix{TAB}, B))) + return UpperTriangular($ipop(AA, $xform(convert(AbstractMatrix{TAB}, B)))) end - function $f1(A::UpperTriangular, B::UnitLowerTriangular) + function ($op)(A::UpperTriangular, xformB::($xform){<:Any,<:UnitLowerTriangular}) + B = xformB.parent TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) + (*)(zero(eltype(A)), zero(eltype(B)))) AA = similar(A, TAB, size(A)) copy!(AA, A) - return UpperTriangular($f2(AA, convert(AbstractMatrix{TAB}, B))) + return UpperTriangular($ipop(AA, $xform(convert(AbstractMatrix{TAB}, B)))) end end end ## The general promotion methods -for (f, g) in ((:*, :A_mul_B!), (:Ac_mul_B, :Ac_mul_B!), (:At_mul_B, :At_mul_B!)) +function *(A::AbstractTriangular, B::AbstractTriangular) + TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) + BB = similar(B, TAB, size(B)) + copy!(BB, B) + mul!(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)) + copy!(BB, B) + mul!(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)) + copy!(BB, B) + mul!(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)) + copy!(AA, A) + mul!(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)) + copy!(AA, A) + mul!(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 ($f)(A::AbstractTriangular, B::AbstractTriangular) + 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)) copy!(BB, B) - ($g)(convert(AbstractArray{TAB}, A), BB) + mul!(convert(AbstractArray{TAB}, A), BB) end - end -end -for (f, g) in ((:A_mul_Bc, :A_mul_Bc!), (:A_mul_Bt, :A_mul_Bt!)) - @eval begin - function ($f)(A::AbstractTriangular, B::AbstractTriangular) + function *(adjA::Adjoint{<:Any,<:AbstractTriangular}, B::$mat) + A = adjA.parent TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) - AA = similar(A, TAB, size(A)) - copy!(AA, A) - ($g)(AA, convert(AbstractArray{TAB}, B)) + BB = similar(B, TAB, size(B)) + copy!(BB, B) + mul!(Adjoint(convert(AbstractArray{TAB}, A)), BB) end - end -end - -for mat in (:AbstractVector, :AbstractMatrix) - -### Multiplication with triangle to the left and hence rhs cannot be transposed. -for (f, g) in ((:*, :A_mul_B!), (:Ac_mul_B, :Ac_mul_B!), (:At_mul_B, :At_mul_B!)) - @eval begin - function ($f)(A::AbstractTriangular, B::$mat) + 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)) copy!(BB, B) - ($g)(convert(AbstractArray{TAB}, A), BB) + mul!(Transpose(convert(AbstractArray{TAB}, A)), BB) end end -end -### Left division with triangle to the left hence rhs cannot be transposed. No quotients. -for (f, g) in ((:\, :A_ldiv_B!), (:Ac_ldiv_B, :Ac_ldiv_B!), (:At_ldiv_B, :At_ldiv_B!)) + ### Left division with triangle to the left hence rhs cannot be transposed. No quotients. @eval begin - function ($f)(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::$mat) + function \(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::$mat) TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) BB = similar(B, TAB, size(B)) copy!(BB, B) - ($g)(convert(AbstractArray{TAB}, A), BB) + ldiv!(convert(AbstractArray{TAB}, A), BB) + end + function \(adjA::Adjoint{<:Any,<:Union{UnitUpperTriangular,UnitLowerTriangular}}, 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)) + copy!(BB, B) + ldiv!(Adjoint(convert(AbstractArray{TAB}, A)), BB) + end + function \(transA::Transpose{<:Any,<:Union{UnitUpperTriangular,UnitLowerTriangular}}, 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)) + copy!(BB, B) + ldiv!(Transpose(convert(AbstractArray{TAB}, A)), BB) end end -end -### Left division with triangle to the left hence rhs cannot be transposed. Quotients. -for (f, g) in ((:\, :A_ldiv_B!), (:Ac_ldiv_B, :Ac_ldiv_B!), (:At_ldiv_B, :At_ldiv_B!)) + ### Left division with triangle to the left hence rhs cannot be transposed. Quotients. @eval begin - function ($f)(A::Union{UpperTriangular,LowerTriangular}, B::$mat) + function \(A::Union{UpperTriangular,LowerTriangular}, B::$mat) + TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A))) + BB = similar(B, TAB, size(B)) + copy!(BB, B) + ldiv!(convert(AbstractArray{TAB}, A), BB) + end + function \(adjA::Adjoint{<:Any,<:Union{UpperTriangular,LowerTriangular}}, B::$mat) + A = adjA.parent + TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A))) + BB = similar(B, TAB, size(B)) + copy!(BB, B) + ldiv!(Adjoint(convert(AbstractArray{TAB}, A)), BB) + end + function \(transA::Transpose{<:Any,<:Union{UpperTriangular,LowerTriangular}}, B::$mat) + A = transA.parent TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A))) BB = similar(B, TAB, size(B)) copy!(BB, B) - ($g)(convert(AbstractArray{TAB}, A), BB) + ldiv!(Transpose(convert(AbstractArray{TAB}, A)), BB) end end -end -### Multiplication with triangle to the right and hence lhs cannot be transposed. -for (f, g) in ((:*, :A_mul_B!), (:A_mul_Bc, :A_mul_Bc!), (:A_mul_Bt, :A_mul_Bt!)) - mat != :AbstractVector && @eval begin - function ($f)(A::$mat, B::AbstractTriangular) + ### Right division with triangle to the right hence lhs cannot be transposed. No quotients. + @eval begin + function /(A::$mat, B::Union{UnitUpperTriangular, UnitLowerTriangular}) TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) AA = similar(A, TAB, size(A)) copy!(AA, A) - ($g)(AA, convert(AbstractArray{TAB}, B)) + rdiv!(AA, convert(AbstractArray{TAB}, B)) end - end -end -### Right division with triangle to the right hence lhs cannot be transposed. No quotients. -for (f, g) in ((:/, :A_rdiv_B!), (:A_rdiv_Bc, :A_rdiv_Bc!), (:A_rdiv_Bt, :A_rdiv_Bt!)) - @eval begin - function ($f)(A::$mat, B::Union{UnitUpperTriangular, UnitLowerTriangular}) + function /(A::$mat, adjB::Adjoint{<:Any,<:Union{UnitUpperTriangular, UnitLowerTriangular}}) + B = adjB.parent TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) AA = similar(A, TAB, size(A)) copy!(AA, A) - ($g)(AA, convert(AbstractArray{TAB}, B)) + rdiv!(AA, Adjoint(convert(AbstractArray{TAB}, B))) + end + function /(A::$mat, transB::Transpose{<:Any,<:Union{UnitUpperTriangular, UnitLowerTriangular}}) + B = transB.parent + TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) + AA = similar(A, TAB, size(A)) + copy!(AA, A) + rdiv!(AA, Transpose(convert(AbstractArray{TAB}, B))) end end -end - -### Right division with triangle to the right hence lhs cannot be transposed. Quotients. -for (f, g) in ((:/, :A_rdiv_B!), (:A_rdiv_Bc, :A_rdiv_Bc!), (:A_rdiv_Bt, :A_rdiv_Bt!)) + ### Right division with triangle to the right hence lhs cannot be transposed. Quotients. @eval begin - function ($f)(A::$mat, B::Union{UpperTriangular,LowerTriangular}) + function /(A::$mat, B::Union{UpperTriangular,LowerTriangular}) + TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A))) + AA = similar(A, TAB, size(A)) + copy!(AA, A) + rdiv!(AA, convert(AbstractArray{TAB}, B)) + end + function /(A::$mat, adjB::Adjoint{<:Any,<:Union{UpperTriangular,LowerTriangular}}) + B = adjB.parent + TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A))) + AA = similar(A, TAB, size(A)) + copy!(AA, A) + rdiv!(AA, Adjoint(convert(AbstractArray{TAB}, B))) + end + function /(A::$mat, transB::Transpose{<:Any,<:Union{UpperTriangular,LowerTriangular}}) + B = transB.parent TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A))) AA = similar(A, TAB, size(A)) copy!(AA, A) - ($g)(AA, convert(AbstractArray{TAB}, B)) + rdiv!(AA, Transpose(convert(AbstractArray{TAB}, B))) end end 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) + TAB = typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))) + AA = similar(A, TAB, size(A)) + copy!(AA, A) + mul!(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)) + copy!(AA, A) + mul!(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)) + copy!(AA, A) + mul!(AA, Transpose(convert(AbstractArray{TAB}, B))) +end +# ambiguity resolution with definitions in linalg/rowvector.jl +*(transA::Transpose{<:Any,<:AbstractVector}, B::AbstractTriangular) = *(transpose(transA.parent), B) +*(adjA::Adjoint{<:Any,<:AbstractVector}, B::AbstractTriangular) = *(adjoint(adjA.parent), B) +*(transA::Transpose{<:Any,<:AbstractVector}, transB::Transpose{<:Any,<:AbstractTriangular}) = *(transpose(transA.parent), transB) +*(adjA::Adjoint{<:Any,<:AbstractVector}, adjB::Adjoint{<:Any,<:AbstractTriangular}) = *(adjoint(adjA.parent), adjB) + # 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. -Ac_mul_B(A::AbstractMatrix, B::AbstractTriangular) = (*)(adjoint(A), B) -At_mul_B(A::AbstractMatrix, B::AbstractTriangular) = (*)(transpose(A), B) -A_mul_Bc(A::AbstractTriangular, B::AbstractMatrix) = (*)(A, adjoint(B)) -A_mul_Bt(A::AbstractTriangular, B::AbstractMatrix) = (*)(A, transpose(B)) -Ac_mul_Bc(A::AbstractTriangular, B::AbstractTriangular) = Ac_mul_B(A, B') -Ac_mul_Bc(A::AbstractTriangular, B::AbstractMatrix) = Ac_mul_B(A, B') -Ac_mul_Bc(A::AbstractMatrix, B::AbstractTriangular) = A_mul_Bc(A', B) -At_mul_Bt(A::AbstractTriangular, B::AbstractTriangular) = At_mul_B(A, B.') -At_mul_Bt(A::AbstractTriangular, B::AbstractMatrix) = At_mul_B(A, B.') -At_mul_Bt(A::AbstractMatrix, B::AbstractTriangular) = A_mul_Bt(A.', B) +*(adjA::Adjoint{<:Any,<:AbstractMatrix}, B::AbstractTriangular) = (*)(adjoint(adjA.parent), B) +*(transA::Transpose{<:Any,<:AbstractMatrix}, B::AbstractTriangular) = (*)(transpose(transA.parent), B) +*(A::AbstractTriangular, adjB::Adjoint{<:Any,<:AbstractMatrix}) = (*)(A, adjoint(adjB.parent)) +*(A::AbstractTriangular, transB::Transpose{<:Any,<:AbstractMatrix}) = (*)(A, transpose(transB.parent)) +*(adjA::Adjoint{<:Any,<:AbstractTriangular}, adjB::Adjoint{<:Any,<:AbstractTriangular}) = *(adjA, adjoint(adjB.parent)) +*(adjA::Adjoint{<:Any,<:AbstractTriangular}, adjB::Adjoint{<:Any,<:AbstractMatrix}) = *(adjA, adjoint(adjB.parent)) +*(adjA::Adjoint{<:Any,<:AbstractMatrix}, adjB::Adjoint{<:Any,<:AbstractTriangular}) = *(adjoint(adjA.parent), adjB) +*(transA::Transpose{<:Any,<:AbstractTriangular}, transB::Transpose{<:Any,<:AbstractTriangular}) = *(transA, transpose(transB.parent)) +*(transA::Transpose{<:Any,<:AbstractTriangular}, transB::Transpose{<:Any,<:AbstractMatrix}) = *(transA, transpose(transB.parent)) +*(transA::Transpose{<:Any,<:AbstractMatrix}, transB::Transpose{<:Any,<:AbstractTriangular}) = *(transpose(transA.parent), transB) # Specializations for RowVector -@inline *(rowvec::RowVector, A::AbstractTriangular) = transpose(A * transpose(rowvec)) -@inline A_mul_Bt(rowvec::RowVector, A::AbstractTriangular) = transpose(A * transpose(rowvec)) -@inline A_mul_Bt(A::AbstractTriangular, rowvec::RowVector) = A * transpose(rowvec) -@inline At_mul_Bt(A::AbstractTriangular, rowvec::RowVector) = A.' * transpose(rowvec) -@inline A_mul_Bc(rowvec::RowVector, A::AbstractTriangular) = adjoint(A * adjoint(rowvec)) -@inline A_mul_Bc(A::AbstractTriangular, rowvec::RowVector) = A * adjoint(rowvec) -@inline Ac_mul_Bc(A::AbstractTriangular, rowvec::RowVector) = A' * adjoint(rowvec) +*(rowvec::RowVector, A::AbstractTriangular) = transpose(transpose(A) * transpose(rowvec)) +*(rowvec::RowVector, transA::Transpose{<:Any,<:AbstractTriangular}) = transpose(transA.parent * transpose(rowvec)) +*(A::AbstractTriangular, transrowvec::Transpose{<:Any,<:RowVector}) = A * transpose(transrowvec.parent) +*(transA::Transpose{<:Any,<:AbstractTriangular}, transrowvec::Transpose{<:Any,<:RowVector}) = transA.parent.' * transpose(transrowvec.parent) +*(rowvec::RowVector, adjA::Adjoint{<:Any,<:AbstractTriangular}) = adjoint(adjA.parent * adjoint(rowvec)) +*(A::AbstractTriangular, adjrowvec::Adjoint{<:Any,<:RowVector}) = A * adjoint(adjrowvec.parent) +*(adjA::Adjoint{<:Any,<:AbstractTriangular}, adjrowvec::Adjoint{<:Any,<:RowVector}) = adjA.parent' * adjoint(adjrowvec.parent) @inline /(rowvec::RowVector, A::Union{UpperTriangular,LowerTriangular}) = transpose(transpose(A) \ transpose(rowvec)) @inline /(rowvec::RowVector, A::Union{UnitUpperTriangular,UnitLowerTriangular}) = transpose(transpose(A) \ transpose(rowvec)) -@inline A_rdiv_Bt(rowvec::RowVector, A::Union{UpperTriangular,LowerTriangular}) = transpose(A \ transpose(rowvec)) -@inline A_rdiv_Bt(rowvec::RowVector, A::Union{UnitUpperTriangular,UnitLowerTriangular}) = transpose(A \ transpose(rowvec)) - -@inline A_rdiv_Bc(rowvec::RowVector, A::Union{UpperTriangular,LowerTriangular}) = adjoint(A \ adjoint(rowvec)) -@inline A_rdiv_Bc(rowvec::RowVector, A::Union{UnitUpperTriangular,UnitLowerTriangular}) = adjoint(A \ adjoint(rowvec)) +/(rowvec::RowVector, transA::Transpose{<:Any,<:Union{UpperTriangular,LowerTriangular}}) = + transpose(transA.parent \ transpose(rowvec)) +/(rowvec::RowVector, transA::Transpose{<:Any,<:Union{UnitUpperTriangular,UnitLowerTriangular}}) = + transpose(transA.parent \ transpose(rowvec)) +# ambiguity resolution with definitions in linalg/rowvector.jl +/(rowvec::RowVector, adjA::Adjoint{<:Any,<:Union{UpperTriangular,LowerTriangular}}) = + /(rowvec, adjoint(adjA.parent)) +/(rowvec::RowVector, adjA::Adjoint{<:Any,<:Union{UnitUpperTriangular,UnitLowerTriangular}}) = + /(rowvec, adjoint(adjA.parent)) + +rdiv(rowvec::RowVector, adjA::Adjoint{<:Any,<:Union{UpperTriangular,LowerTriangular}}) = + adjoint(adjA.parent \ adjoint(rowvec)) +rdiv(rowvec::RowVector, adjA::Adjoint{<:Any,<:Union{UnitUpperTriangular,UnitLowerTriangular}}) = + adjoint(adjA.parent \ adjoint(rowvec)) \(::Union{UpperTriangular,LowerTriangular}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) \(::Union{UnitUpperTriangular,UnitLowerTriangular}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) -At_ldiv_B(::Union{UpperTriangular,LowerTriangular}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) -At_ldiv_B(::Union{UnitUpperTriangular,UnitLowerTriangular}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) +\(::Transpose{<:Any,<:Union{UpperTriangular,LowerTriangular}}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) +\(::Transpose{<:Any,<:Union{UnitUpperTriangular,UnitLowerTriangular}}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) -Ac_ldiv_B(::Union{UpperTriangular,LowerTriangular}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) -Ac_ldiv_B(::Union{UnitUpperTriangular,UnitLowerTriangular}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) +\(::Adjoint{<:Any,<:Union{UpperTriangular,LowerTriangular}}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) +\(::Adjoint{<:Any,<:Union{UnitUpperTriangular,UnitLowerTriangular}}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) # Complex matrix power for upper triangular factor, see: # Higham and Lin, "A Schur-Padé algorithm for fractional powers of a Matrix", @@ -1749,7 +1930,7 @@ function powm!(A0::UpperTriangular{<:BlasFloat}, p::Real) end copy!(Stmp, S) scale!(S, A, c) - A_ldiv_B!(Stmp, S.data) + ldiv!(Stmp, S.data) c = (p - j) / (j4 - 2) for i = 1:n @@ -1757,21 +1938,21 @@ function powm!(A0::UpperTriangular{<:BlasFloat}, p::Real) end copy!(Stmp, S) scale!(S, A, c) - A_ldiv_B!(Stmp, S.data) + ldiv!(Stmp, S.data) end for i = 1:n S[i, i] = S[i, i] + 1 end copy!(Stmp, S) scale!(S, A, -p) - A_ldiv_B!(Stmp, S.data) + ldiv!(Stmp, S.data) for i = 1:n @inbounds S[i, i] = S[i, i] + 1 end blockpower!(A0, S, p/(2^s)) for m = 1:s - A_mul_B!(Stmp.data, S, S) + mul!(Stmp.data, S, S) copy!(S, Stmp) blockpower!(A0, S, p/(2^(s-m))) end @@ -2212,3 +2393,25 @@ for func in (:svd, :svdfact, :svdfact!, :svdvals) end factorize(A::AbstractTriangular) = A + +# dismabiguation methods: *(AbstractTriangular, Adj/Trans of AbstractVector) +*(A::AbstractTriangular, B::Adjoint{<:Any,<:AbstractVector}) = A * adjoint(B.parent) +*(A::AbstractTriangular, B::Transpose{<:Any,<:AbstractVector}) = A * transpose(B.parent) +# dismabiguation methods: *(Adj/Trans of AbstractTriangular, Trans/Ajd of AbstractTriangular) +*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractTriangular}) = adjoint(A.parent) * B +*(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractTriangular}) = transpose(A.parent) * B +# dismabiguation methods: *(Adj/Trans of AbstractTriangular, Adj/Trans of AbsVec or AbsMat) +*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVector}) = A * adjoint(B.parent) +*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractMatrix}) = A * transpose(B.parent) +*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVector}) = A * transpose(B.parent) +*(A::Transpose{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:AbstractVector}) = A * transpose(B.parent) +*(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractVector}) = A * adjoint(B.parent) +*(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:AbstractMatrix}) = A * adjoint(B.parent) +# dismabiguation methods: *(Adj/Trans of AbsVec or AbsMat, Adj/Trans of AbstractTriangular) +*(A::Adjoint{<:Any,<:AbstractVector}, B::Transpose{<:Any,<:AbstractTriangular}) = adjoint(A.parent) * B +*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:AbstractTriangular}) = adjoint(A.parent) * B +*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractTriangular}) = transpose(A.parent) * B +*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractTriangular}) = transpose(A.parent) * B +# dismabiguation methods: *(Adj/Trans of AbstractTriangular, Trans/Adj of RowVector) +*(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:RowVector}) = A * transpose(B.parent) +*(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:RowVector}) = A * adjoint(B.parent) diff --git a/base/linalg/tridiag.jl b/base/linalg/tridiag.jl index dbd6a56b4f687..53d2e1d4ed8b6 100644 --- a/base/linalg/tridiag.jl +++ b/base/linalg/tridiag.jl @@ -153,7 +153,7 @@ end /(A::SymTridiagonal, B::Number) = SymTridiagonal(A.dv/B, A.ev/B) ==(A::SymTridiagonal, B::SymTridiagonal) = (A.dv==B.dv) && (A.ev==B.ev) -function A_mul_B!(C::StridedVecOrMat, S::SymTridiagonal, B::StridedVecOrMat) +function mul!(C::StridedVecOrMat, S::SymTridiagonal, B::StridedVecOrMat) m, n = size(B, 1), size(B, 2) if !(m == size(S, 1) == size(C, 1)) throw(DimensionMismatch("A has first dimension $(size(S,1)), B has $(size(B,1)), C has $(size(C,1)) but all must match")) @@ -536,6 +536,8 @@ broadcast(::typeof(ceil), ::Type{T}, M::Tridiagonal) where {T<:Integer} = transpose(M::Tridiagonal) = Tridiagonal(M.du, M.d, M.dl) adjoint(M::Tridiagonal) = conj(transpose(M)) +\(A::Adjoint{<:Any,<:Tridiagonal}, B::Adjoint{<:Any,<:StridedVecOrMat}) = adjoint(A.parent) \ adjoint(B.parent) + function diag(M::Tridiagonal{T}, n::Integer=0) where T # every branch call similar(..., ::Int) to make sure the # same vector type is returned independent of n diff --git a/base/linalg/uniformscaling.jl b/base/linalg/uniformscaling.jl index d87e42b4a2e78..e159b647d9fe8 100644 --- a/base/linalg/uniformscaling.jl +++ b/base/linalg/uniformscaling.jl @@ -63,7 +63,9 @@ end copy(J::UniformScaling) = UniformScaling(J.λ) transpose(J::UniformScaling) = J +Transpose(S::UniformScaling) = transpose(S) adjoint(J::UniformScaling) = UniformScaling(conj(J.λ)) +Adjoint(S::UniformScaling) = adjoint(S) one(::Type{UniformScaling{T}}) where {T} = UniformScaling(one(T)) one(J::UniformScaling{T}) where {T} = one(UniformScaling{T}) diff --git a/base/operators.jl b/base/operators.jl index d40cf227410e1..c6eb8c3ccaef3 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -762,142 +762,6 @@ julia> adjoint(A) adjoint(x) = conj(transpose(x)) conj(x) = x -# transposed multiply - -""" - Ac_mul_B(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ⋅B``. -""" -Ac_mul_B(a,b) = adjoint(a)*b - -""" - A_mul_Bc(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``A⋅Bᴴ``. -""" -A_mul_Bc(a,b) = a*adjoint(b) - -""" - Ac_mul_Bc(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ Bᴴ``. -""" -Ac_mul_Bc(a,b) = adjoint(a)*adjoint(b) - -""" - At_mul_B(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ⋅B``. -""" -At_mul_B(a,b) = transpose(a)*b - -""" - A_mul_Bt(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``A⋅Bᵀ``. -""" -A_mul_Bt(a,b) = a*transpose(b) - -""" - At_mul_Bt(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ⋅Bᵀ``. -""" -At_mul_Bt(a,b) = transpose(a)*transpose(b) - -# transposed divide - -""" - Ac_rdiv_B(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ / B``. -""" -Ac_rdiv_B(a,b) = adjoint(a)/b - -""" - A_rdiv_Bc(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``A / Bᴴ``. -""" -A_rdiv_Bc(a,b) = a/adjoint(b) - -""" - Ac_rdiv_Bc(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ / Bᴴ``. -""" -Ac_rdiv_Bc(a,b) = adjoint(a)/adjoint(b) - -""" - At_rdiv_B(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ / B``. -""" -At_rdiv_B(a,b) = transpose(a)/b - -""" - A_rdiv_Bt(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``A / Bᵀ``. -""" -A_rdiv_Bt(a,b) = a/transpose(b) - -""" - At_rdiv_Bt(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ / Bᵀ``. -""" -At_rdiv_Bt(a,b) = transpose(a)/transpose(b) - -""" - Ac_ldiv_B(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ`` \\ ``B``. -""" -Ac_ldiv_B(a,b) = adjoint(a)\b - -""" - A_ldiv_Bc(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``A`` \\ ``Bᴴ``. -""" -A_ldiv_Bc(a,b) = a\adjoint(b) - -""" - Ac_ldiv_Bc(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ`` \\ ``Bᴴ``. -""" -Ac_ldiv_Bc(a,b) = adjoint(a)\adjoint(b) - -""" - At_ldiv_B(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ`` \\ ``B``. -""" -At_ldiv_B(a,b) = transpose(a)\b - -""" - A_ldiv_Bt(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``A`` \\ ``Bᵀ``. -""" -A_ldiv_Bt(a,b) = a\transpose(b) - -""" - At_ldiv_Bt(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᵀ`` \\ ``Bᵀ``. -""" -At_ldiv_Bt(a,b) = At_ldiv_B(a,transpose(b)) - -""" - Ac_ldiv_Bt(A, B) - -For matrices or vectors ``A`` and ``B``, calculates ``Aᴴ`` \\ ``Bᵀ``. -""" -Ac_ldiv_Bt(a,b) = Ac_ldiv_B(a,transpose(b)) """ widen(x) diff --git a/base/sparse/linalg.jl b/base/sparse/linalg.jl index 388a8f63f4922..c30c0e7fc6e50 100644 --- a/base/sparse/linalg.jl +++ b/base/sparse/linalg.jl @@ -1,21 +1,24 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +using Base.LinAlg: Adjoint, Transpose import Base.LinAlg: checksquare ## sparse matrix multiplication -function (*)(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} - (*)(sppromote(A, B)...) -end -for f in (:A_mul_Bt, :A_mul_Bc, - :At_mul_B, :Ac_mul_B, - :At_mul_Bt, :Ac_mul_Bc) - @eval begin - function ($f)(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} - ($f)(sppromote(A, B)...) - end - end -end +*(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} = + *(sppromote(A, B)...) +*(A::SparseMatrixCSC{TvA,TiA}, transB::Transpose{<:Any,<:SparseMatrixCSC{TvB,TiB}}) where {TvA,TiA,TvB,TiB} = + (B = transB.parent; (pA, pB) = sppromote(A, B); *(pA, Transpose(pB))) +*(A::SparseMatrixCSC{TvA,TiA}, adjB::Adjoint{<:Any,<:SparseMatrixCSC{TvB,TiB}}) where {TvA,TiA,TvB,TiB} = + (B = adjB.parent; (pA, pB) = sppromote(A, B); *(pA, Adjoint(pB))) +*(transA::Transpose{<:Any,<:SparseMatrixCSC{TvA,TiA}}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} = + (A = transA.parent; (pA, pB) = sppromote(A, B); *(Transpose(pA), pB)) +*(adjA::Adjoint{<:Any,<:SparseMatrixCSC{TvA,TiA}}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} = + (A = adjA.parent; (pA, pB) = sppromote(A, B); *(Adjoint(pA), pB)) +*(transA::Transpose{<:Any,<:SparseMatrixCSC{TvA,TiA}}, transB::Transpose{<:Any,<:SparseMatrixCSC{TvB,TiB}}) where {TvA,TiA,TvB,TiB} = + (A = transA.parent; B = transB.parent; (pA, pB) = sppromote(A, B); *(Transpose(pA), Transpose(pB))) +*(adjA::Adjoint{<:Any,<:SparseMatrixCSC{TvA,TiA}}, adjB::Adjoint{<:Any,<:SparseMatrixCSC{TvB,TiB}}) where {TvA,TiA,TvB,TiB} = + (A = adjA.parent; B = adjB.parent; (pA, pB) = sppromote(A, B); *(Adjoint(pA), Adjoint(pB))) function sppromote(A::SparseMatrixCSC{TvA,TiA}, B::SparseMatrixCSC{TvB,TiB}) where {TvA,TiA,TvB,TiB} Tv = promote_type(TvA, TvB) @@ -27,60 +30,90 @@ end # In matrix-vector multiplication, the correct orientation of the vector is assumed. -for (f, op, transp) in ((:A_mul_B, :identity, false), - (:Ac_mul_B, :adjoint, true), - (:At_mul_B, :transpose, true)) - @eval begin - function $(Symbol(f,:!))(α::Number, A::SparseMatrixCSC, B::StridedVecOrMat, β::Number, C::StridedVecOrMat) - if $transp - A.n == size(C, 1) || throw(DimensionMismatch()) - A.m == size(B, 1) || throw(DimensionMismatch()) - else - A.n == size(B, 1) || throw(DimensionMismatch()) - A.m == size(C, 1) || throw(DimensionMismatch()) - end - size(B, 2) == size(C, 2) || throw(DimensionMismatch()) - nzv = A.nzval - rv = A.rowval - if β != 1 - β != 0 ? scale!(C, β) : fill!(C, zero(eltype(C))) - end - for k = 1:size(C, 2) - for col = 1:A.n - if $transp - tmp = zero(eltype(C)) - @inbounds for j = A.colptr[col]:(A.colptr[col + 1] - 1) - tmp += $(op)(nzv[j])*B[rv[j],k] - end - C[col,k] += α*tmp - else - αxj = α*B[col,k] - @inbounds for j = A.colptr[col]:(A.colptr[col + 1] - 1) - C[rv[j], k] += nzv[j]*αxj - end - end - end +function mul!(α::Number, A::SparseMatrixCSC, B::StridedVecOrMat, β::Number, C::StridedVecOrMat) + A.n == size(B, 1) || throw(DimensionMismatch()) + A.m == size(C, 1) || throw(DimensionMismatch()) + size(B, 2) == size(C, 2) || throw(DimensionMismatch()) + nzv = A.nzval + rv = A.rowval + if β != 1 + β != 0 ? scale!(C, β) : fill!(C, zero(eltype(C))) + end + for k = 1:size(C, 2) + for col = 1:A.n + αxj = α*B[col,k] + @inbounds for j = A.colptr[col]:(A.colptr[col + 1] - 1) + C[rv[j], k] += nzv[j]*αxj end - C end - - function $(f)(A::SparseMatrixCSC{TA,S}, x::StridedVector{Tx}) where {TA,S,Tx} - T = promote_type(TA, Tx) - $(Symbol(f,:!))(one(T), A, x, zero(T), similar(x, T, A.n)) + end + C +end +*(A::SparseMatrixCSC{TA,S}, x::StridedVector{Tx}) where {TA,S,Tx} = + (T = promote_type(TA, Tx); mul!(one(T), A, x, zero(T), similar(x, T, A.m))) +*(A::SparseMatrixCSC{TA,S}, B::StridedMatrix{Tx}) where {TA,S,Tx} = + (T = promote_type(TA, Tx); mul!(one(T), A, B, zero(T), similar(B, T, (A.m, size(B, 2))))) + +function mul!(α::Number, adjA::Adjoint{<:Any,<:SparseMatrixCSC}, B::StridedVecOrMat, β::Number, C::StridedVecOrMat) + A = adjA.parent + A.n == size(C, 1) || throw(DimensionMismatch()) + A.m == size(B, 1) || throw(DimensionMismatch()) + size(B, 2) == size(C, 2) || throw(DimensionMismatch()) + nzv = A.nzval + rv = A.rowval + if β != 1 + β != 0 ? scale!(C, β) : fill!(C, zero(eltype(C))) + end + for k = 1:size(C, 2) + for col = 1:A.n + tmp = zero(eltype(C)) + @inbounds for j = A.colptr[col]:(A.colptr[col + 1] - 1) + tmp += adjoint(nzv[j])*B[rv[j],k] + end + C[col,k] += α*tmp end - function $(f)(A::SparseMatrixCSC{TA,S}, B::StridedMatrix{Tx}) where {TA,S,Tx} - T = promote_type(TA, Tx) - $(Symbol(f,:!))(one(T), A, B, zero(T), similar(B, T, (A.n, size(B, 2)))) + end + C +end +*(adjA::Adjoint{<:Any,<:SparseMatrixCSC{TA,S}}, x::StridedVector{Tx}) where {TA,S,Tx} = + (A = adjA.parent; T = promote_type(TA, Tx); mul!(one(T), Adjoint(A), x, zero(T), similar(x, T, A.n))) +*(adjA::Adjoint{<:Any,<:SparseMatrixCSC{TA,S}}, B::StridedMatrix{Tx}) where {TA,S,Tx} = + (A = adjA.parent; T = promote_type(TA, Tx); mul!(one(T), Adjoint(A), B, zero(T), similar(B, T, (A.n, size(B, 2))))) + +function mul!(α::Number, transA::Transpose{<:Any,<:SparseMatrixCSC}, B::StridedVecOrMat, β::Number, C::StridedVecOrMat) + A = transA.parent + A.n == size(C, 1) || throw(DimensionMismatch()) + A.m == size(B, 1) || throw(DimensionMismatch()) + size(B, 2) == size(C, 2) || throw(DimensionMismatch()) + nzv = A.nzval + rv = A.rowval + if β != 1 + β != 0 ? scale!(C, β) : fill!(C, zero(eltype(C))) + end + for k = 1:size(C, 2) + for col = 1:A.n + tmp = zero(eltype(C)) + @inbounds for j = A.colptr[col]:(A.colptr[col + 1] - 1) + tmp += transpose(nzv[j])*B[rv[j],k] + end + C[col,k] += α*tmp end end + C end +*(transA::Transpose{<:Any,<:SparseMatrixCSC{TA,S}}, x::StridedVector{Tx}) where {TA,S,Tx} = + (A = transA.parent; T = promote_type(TA, Tx); mul!(one(T), Transpose(A), x, zero(T), similar(x, T, A.n))) +*(transA::Transpose{<:Any,<:SparseMatrixCSC{TA,S}}, B::StridedMatrix{Tx}) where {TA,S,Tx} = + (A = transA.parent; T = promote_type(TA, Tx); mul!(one(T), Transpose(A), B, zero(T), similar(B, T, (A.n, size(B, 2))))) # For compatibility with dense multiplication API. Should be deleted when dense multiplication # API is updated to follow BLAS API. -A_mul_B!(C::StridedVecOrMat, A::SparseMatrixCSC, B::StridedVecOrMat) = A_mul_B!(one(eltype(B)), A, B, zero(eltype(C)), C) -Ac_mul_B!(C::StridedVecOrMat, A::SparseMatrixCSC, B::StridedVecOrMat) = Ac_mul_B!(one(eltype(B)), A, B, zero(eltype(C)), C) -At_mul_B!(C::StridedVecOrMat, A::SparseMatrixCSC, B::StridedVecOrMat) = At_mul_B!(one(eltype(B)), A, B, zero(eltype(C)), C) - +mul!(C::StridedVecOrMat, A::SparseMatrixCSC, B::StridedVecOrMat) = + mul!(one(eltype(B)), A, B, zero(eltype(C)), C) +mul!(C::StridedVecOrMat, adjA::Adjoint{<:Any,<:SparseMatrixCSC}, B::StridedVecOrMat) = + (A = adjA.parent; mul!(one(eltype(B)), Adjoint(A), B, zero(eltype(C)), C)) +mul!(C::StridedVecOrMat, transA::Transpose{<:Any,<:SparseMatrixCSC}, B::StridedVecOrMat) = + (A = transA.parent; mul!(one(eltype(B)), Transpose(A), B, zero(eltype(C)), C)) function (*)(X::StridedMatrix{TX}, A::SparseMatrixCSC{TvA,TiA}) where {TX,TvA,TiA} mX, nX = size(X) @@ -107,18 +140,18 @@ end # http://dl.acm.org/citation.cfm?id=355796 (*)(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = spmatmul(A,B) -for (f, opA, opB) in ((:A_mul_Bt, :identity, :transpose), - (:A_mul_Bc, :identity, :adjoint), - (:At_mul_B, :transpose, :identity), - (:Ac_mul_B, :adjoint, :identity), - (:At_mul_Bt, :transpose, :transpose), - (:Ac_mul_Bc, :adjoint, :adjoint)) - @eval begin - function ($f)(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} - spmatmul(($opA)(A), ($opB)(B)) - end - end -end +*(A::SparseMatrixCSC{Tv,Ti}, transB::Transpose{<:Any,<:SparseMatrixCSC{Tv,Ti}}) where {Tv,Ti} = + (B = transB.parent; spmatmul(A, transpose(B))) +*(A::SparseMatrixCSC{Tv,Ti}, adjB::Adjoint{<:Any,<:SparseMatrixCSC{Tv,Ti}}) where {Tv,Ti} = + (B = adjB.parent; spmatmul(A, adjoint(B))) +*(transA::Transpose{<:Any,<:SparseMatrixCSC{Tv,Ti}}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = + (A = transA.parent; spmatmul(tranpsose(A), B)) +*(adjA::Adjoint{<:Any,<:SparseMatrixCSC{Tv,Ti}}, B::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = + (A = adjA.parent; spmatmul(adjoint(A), B)) +*(transA::Transpose{<:Any,<:SparseMatrixCSC{Tv,Ti}}, transB::Transpose{<:Any,<:SparseMatrixCSC{Tv,Ti}}) where {Tv,Ti} = + (A = transA.parent; B = transB.parent; spmatmul(transpose(A), transpose(B))) +*(adjA::Adjoint{<:Any,<:SparseMatrixCSC{Tv,Ti}}, adjB::Adjoint{<:Any,<:SparseMatrixCSC{Tv,Ti}}) where {Tv,Ti} = + (A = adjA.parent; B = adjB.parent; spmatmul(adjoint(A), adjoint(B))) function spmatmul(A::SparseMatrixCSC{Tv,Ti}, B::SparseMatrixCSC{Tv,Ti}; sortindices::Symbol = :sortcols) where {Tv,Ti} @@ -268,13 +301,16 @@ function bwdTriSolve!(A::SparseMatrixCSCUnion, B::AbstractVecOrMat) B end -A_ldiv_B!(L::LowerTriangular{T,<:SparseMatrixCSCUnion{T}}, B::StridedVecOrMat) where {T} = fwdTriSolve!(L.data, B) -A_ldiv_B!(U::UpperTriangular{T,<:SparseMatrixCSCUnion{T}}, B::StridedVecOrMat) where {T} = bwdTriSolve!(U.data, B) +ldiv!(L::LowerTriangular{T,<:SparseMatrixCSCUnion{T}}, B::StridedVecOrMat) where {T} = fwdTriSolve!(L.data, B) +ldiv!(U::UpperTriangular{T,<:SparseMatrixCSCUnion{T}}, B::StridedVecOrMat) where {T} = bwdTriSolve!(U.data, B) -(\)(L::LowerTriangular{T,<:SparseMatrixCSCUnion{T}}, B::SparseMatrixCSC) where {T} = A_ldiv_B!(L, Array(B)) -(\)(U::UpperTriangular{T,<:SparseMatrixCSCUnion{T}}, B::SparseMatrixCSC) where {T} = A_ldiv_B!(U, Array(B)) +(\)(L::LowerTriangular{T,<:SparseMatrixCSCUnion{T}}, B::SparseMatrixCSC) where {T} = ldiv!(L, Array(B)) +(\)(U::UpperTriangular{T,<:SparseMatrixCSCUnion{T}}, B::SparseMatrixCSC) where {T} = ldiv!(U, Array(B)) +\(A::Transpose{<:Real,<:Hermitian{<:Real,<:SparseMatrixCSC}}, B::Vector) = A.parent \ B +\(A::Transpose{<:Complex,<:Hermitian{<:Complex,<:SparseMatrixCSC}}, B::Vector) = transpose(A.parent) \ B +\(A::Transpose{<:Number,<:Symmetric{<:Number,<:SparseMatrixCSC}}, B::Vector) = A.parent \ B -function A_rdiv_B!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where T +function rdiv!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where T dd = D.diag if (k = length(dd)) ≠ A.n throw(DimensionMismatch("size(A, 2)=$(A.n) should be size(D, 1)=$k")) @@ -292,8 +328,10 @@ function A_rdiv_B!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where T A end -A_rdiv_Bc!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where {T} = A_rdiv_B!(A, conj(D)) -A_rdiv_Bt!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where {T} = A_rdiv_B!(A, D) +rdiv!(A::SparseMatrixCSC{T}, adjD::Adjoint{<:Any,<:Diagonal{T}}) where {T} = + (D = adjD.parent; rdiv!(A, conj(D))) +rdiv!(A::SparseMatrixCSC{T}, transD::Transpose{<:Any,<:Diagonal{T}}) where {T} = + (D = transD.parent; rdiv!(A, D)) ## triu, tril @@ -883,29 +921,51 @@ end scale!(A::SparseMatrixCSC, b::Number) = (scale!(A.nzval, b); A) scale!(b::Number, A::SparseMatrixCSC) = (scale!(b, A.nzval); A) -for f in (:\, :Ac_ldiv_B, :At_ldiv_B) +function \(A::SparseMatrixCSC, B::AbstractVecOrMat) + m, n = size(A) + if m == n + if istril(A) + if istriu(A) + return \(Diagonal(Vector(diag(A))), B) + else + return \(LowerTriangular(A), B) + end + elseif istriu(A) + return \(UpperTriangular(A), B) + end + if ishermitian(A) + return \(Hermitian(A), B) + end + return \(lufact(A), B) + else + return \(qrfact(A), B) + end +end +\(::SparseMatrixCSC, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) +for xform in (:Adjoint, :Transpose) @eval begin - function ($f)(A::SparseMatrixCSC, B::AbstractVecOrMat) + function \(xformA::($xform){<:Any,<:SparseMatrixCSC}, B::AbstractVecOrMat) + A = xformA.parent m, n = size(A) if m == n if istril(A) if istriu(A) - return ($f)(Diagonal(Vector(diag(A))), B) + return \($xform(Diagonal(Vector(diag(A)))), B) else - return ($f)(LowerTriangular(A), B) + return \($xform(LowerTriangular(A)), B) end elseif istriu(A) - return ($f)(UpperTriangular(A), B) + return \($xform(UpperTriangular(A)), B) end if ishermitian(A) - return ($f)(Hermitian(A), B) + return \($xform(Hermitian(A)), B) end - return ($f)(lufact(A), B) + return \($xform(lufact(A)), B) else - return ($f)(qrfact(A), B) + return \($xform(qrfact(A)), B) end end - ($f)(::SparseMatrixCSC, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) + \(::($xform){<:Any,<:SparseMatrixCSC}, ::RowVector) = throw(DimensionMismatch("Cannot left-divide matrix by transposed vector")) end end diff --git a/base/sparse/sparse.jl b/base/sparse/sparse.jl index 0b41b9e073113..dcc9665c20fd6 100644 --- a/base/sparse/sparse.jl +++ b/base/sparse/sparse.jl @@ -13,7 +13,7 @@ import Base: +, -, *, \, /, &, |, xor, == import Base: A_mul_B!, Ac_mul_B, Ac_mul_B!, At_mul_B, At_mul_B! import Base: A_mul_Bc, A_mul_Bt, Ac_mul_Bc, At_mul_Bt import Base: At_ldiv_B, Ac_ldiv_B, A_ldiv_B! -import Base.LinAlg: At_ldiv_B!, Ac_ldiv_B!, A_rdiv_B!, A_rdiv_Bc! +import Base.LinAlg: At_ldiv_B!, Ac_ldiv_B!, A_rdiv_B!, A_rdiv_Bc!, mul!, ldiv!, rdiv! import Base: @get!, acos, acosd, acot, acotd, acsch, asech, asin, asind, asinh, atan, atand, atanh, broadcast!, chol, conj!, cos, cosc, cosd, cosh, cospi, cot, diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index 76e09d34ce39a..d9dd98f05f534 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -2,6 +2,7 @@ ### Common definitions +using Base.LinAlg: Adjoint, Transpose import Base: scalarmax, scalarmin, sort, find, findnz import Base.LinAlg: promote_to_array_type, promote_to_arrays_ @@ -1561,20 +1562,20 @@ function LinAlg.lowrankupdate!(A::StridedMatrix, x::StridedVector, y::SparseVect return A end -# A_mul_B +# * and mul! function (*)(A::StridedMatrix{Ta}, x::AbstractSparseVector{Tx}) where {Ta,Tx} m, n = size(A) length(x) == n || throw(DimensionMismatch()) Ty = promote_type(Ta, Tx) y = Vector{Ty}(uninitialized, m) - A_mul_B!(y, A, x) + mul!(y, A, x) end -A_mul_B!(y::StridedVector{Ty}, A::StridedMatrix, x::AbstractSparseVector{Tx}) where {Tx,Ty} = - A_mul_B!(one(Tx), A, x, zero(Ty), y) +mul!(y::StridedVector{Ty}, A::StridedMatrix, x::AbstractSparseVector{Tx}) where {Tx,Ty} = + mul!(one(Tx), A, x, zero(Ty), y) -function A_mul_B!(α::Number, A::StridedMatrix, x::AbstractSparseVector, β::Number, y::StridedVector) +function mul!(α::Number, A::StridedMatrix, x::AbstractSparseVector, β::Number, y::StridedVector) m, n = size(A) length(x) == n && length(y) == m || throw(DimensionMismatch()) m == 0 && return y @@ -1598,20 +1599,22 @@ function A_mul_B!(α::Number, A::StridedMatrix, x::AbstractSparseVector, β::Num return y end -# At_mul_B +# * and mul!(C, Transpose(A), B) -function At_mul_B(A::StridedMatrix{Ta}, x::AbstractSparseVector{Tx}) where {Ta,Tx} +function *(transA::Transpose{<:Any,<:StridedMatrix{Ta}}, x::AbstractSparseVector{Tx}) where {Ta,Tx} + A = transA.parent m, n = size(A) length(x) == m || throw(DimensionMismatch()) Ty = promote_type(Ta, Tx) y = Vector{Ty}(uninitialized, n) - At_mul_B!(y, A, x) + mul!(y, Transpose(A), x) end -At_mul_B!(y::StridedVector{Ty}, A::StridedMatrix, x::AbstractSparseVector{Tx}) where {Tx,Ty} = - At_mul_B!(one(Tx), A, x, zero(Ty), y) +mul!(y::StridedVector{Ty}, transA::Transpose{<:Any,<:StridedMatrix}, x::AbstractSparseVector{Tx}) where {Tx,Ty} = + (A = transA.parent; mul!(one(Tx), Transpose(A), x, zero(Ty), y)) -function At_mul_B!(α::Number, A::StridedMatrix, x::AbstractSparseVector, β::Number, y::StridedVector) +function mul!(α::Number, transA::Transpose{<:Any,<:StridedMatrix}, x::AbstractSparseVector, β::Number, y::StridedVector) + A = transA.parent m, n = size(A) length(x) == m && length(y) == n || throw(DimensionMismatch()) n == 0 && return y @@ -1653,23 +1656,23 @@ function densemv(A::SparseMatrixCSC, x::AbstractSparseVector; trans::Char='N') T = promote_type(eltype(A), eltype(x)) y = Vector{T}(uninitialized, ylen) if trans == 'N' || trans == 'N' - A_mul_B!(y, A, x) + mul!(y, A, x) elseif trans == 'T' || trans == 't' - At_mul_B!(y, A, x) + mul!(y, Transpose(A), x) elseif trans == 'C' || trans == 'c' - Ac_mul_B!(y, A, x) + mul!(y, Adjoint(A), x) else throw(ArgumentError("Invalid trans character $trans")) end y end -# A_mul_B +# * and mul! -A_mul_B!(y::StridedVector{Ty}, A::SparseMatrixCSC, x::AbstractSparseVector{Tx}) where {Tx,Ty} = - A_mul_B!(one(Tx), A, x, zero(Ty), y) +mul!(y::StridedVector{Ty}, A::SparseMatrixCSC, x::AbstractSparseVector{Tx}) where {Tx,Ty} = + mul!(one(Tx), A, x, zero(Ty), y) -function A_mul_B!(α::Number, A::SparseMatrixCSC, x::AbstractSparseVector, β::Number, y::StridedVector) +function mul!(α::Number, A::SparseMatrixCSC, x::AbstractSparseVector, β::Number, y::StridedVector) m, n = size(A) length(x) == n && length(y) == m || throw(DimensionMismatch()) m == 0 && return y @@ -1697,19 +1700,19 @@ function A_mul_B!(α::Number, A::SparseMatrixCSC, x::AbstractSparseVector, β::N return y end -# At_mul_B +# * and *(Tranpose(A), B) -At_mul_B!(y::StridedVector{Ty}, A::SparseMatrixCSC, x::AbstractSparseVector{Tx}) where {Tx,Ty} = - At_mul_B!(one(Tx), A, x, zero(Ty), y) +mul!(y::StridedVector{Ty}, transA::Transpose{<:Any,<:SparseMatrixCSC}, x::AbstractSparseVector{Tx}) where {Tx,Ty} = + (A = transA.parent; mul!(one(Tx), Transpose(A), x, zero(Ty), y)) -At_mul_B!(α::Number, A::SparseMatrixCSC, x::AbstractSparseVector, β::Number, y::StridedVector) = - _At_or_Ac_mul_B!(*, α, A, x, β, y) +mul!(α::Number, transA::Transpose{<:Any,<:SparseMatrixCSC}, x::AbstractSparseVector, β::Number, y::StridedVector) = + (A = transA.parent; _At_or_Ac_mul_B!(*, α, A, x, β, y)) -Ac_mul_B!(y::StridedVector{Ty}, A::SparseMatrixCSC, x::AbstractSparseVector{Tx}) where {Tx,Ty} = - Ac_mul_B!(one(Tx), A, x, zero(Ty), y) +mul!(y::StridedVector{Ty}, adjA::Adjoint{<:Any,<:SparseMatrixCSC}, x::AbstractSparseVector{Tx}) where {Tx,Ty} = + (A = adjA.parent; mul!(one(Tx), Adjoint(A), x, zero(Ty), y)) -Ac_mul_B!(α::Number, A::SparseMatrixCSC, x::AbstractSparseVector, β::Number, y::StridedVector) = - _At_or_Ac_mul_B!(dot, α, A, x, β, y) +mul!(α::Number, adjA::Adjoint{<:Any,<:SparseMatrixCSC}, x::AbstractSparseVector, β::Number, y::StridedVector) = + (A = adjA.parent; _At_or_Ac_mul_B!(dot, α, A, x, β, y)) function _At_or_Ac_mul_B!(tfun::Function, α::Number, A::SparseMatrixCSC, x::AbstractSparseVector, @@ -1747,11 +1750,11 @@ function *(A::SparseMatrixCSC, x::AbstractSparseVector) _dense2sparsevec(y, initcap) end -At_mul_B(A::SparseMatrixCSC, x::AbstractSparseVector) = - _At_or_Ac_mul_B(*, A, x) +*(transA::Transpose{<:Any,<:SparseMatrixCSC}, x::AbstractSparseVector) = + (A = transA.parent; _At_or_Ac_mul_B(*, A, x)) -Ac_mul_B(A::SparseMatrixCSC, x::AbstractSparseVector) = - _At_or_Ac_mul_B(dot, A, x) +*(adjA::Adjoint{<:Any,<:SparseMatrixCSC}, x::AbstractSparseVector) = + (A = adjA.parent; _At_or_Ac_mul_B(dot, A, x)) function _At_or_Ac_mul_B(tfun::Function, A::SparseMatrixCSC{TvA,TiA}, x::AbstractSparseVector{TvX,TiX}) where {TvA,TiA,TvX,TiX} m, n = size(A) @@ -1797,22 +1800,28 @@ for isunittri in (true, false), islowertri in (true, false) tritype = :(Base.LinAlg.$(Symbol(unitstr, halfstr, "Triangular"))) # build out-of-place left-division operations - for (istrans, func, ipfunc) in ( - (false, :(\), :(A_ldiv_B!)), - (true, :(At_ldiv_B), :(At_ldiv_B!)), - (true, :(Ac_ldiv_B), :(Ac_ldiv_B!)) ) + for (istrans, applyxform, xform) in ( + (false, false, :identity), + (true, true, :Transpose), + (true, true, :Adjoint) ) # broad method where elements are Numbers - @eval function ($func)(A::$tritype{TA,<:AbstractMatrix}, b::SparseVector{Tb}) where {TA<:Number,Tb<:Number} + xformtritype = applyxform ? :($xform{<:TA,<:$tritype{<:Any,<:AbstractMatrix}}) : + :($tritype{<:TA,<:AbstractMatrix}) + @eval function \(xformA::$xformtritype, b::SparseVector{Tb}) where {TA<:Number,Tb<:Number} + A = $(applyxform ? :(xformA.parent) : :(xformA) ) TAb = $(isunittri ? :(typeof(zero(TA)*zero(Tb) + zero(TA)*zero(Tb))) : :(typeof((zero(TA)*zero(Tb) + zero(TA)*zero(Tb))/one(TA))) ) - ($ipfunc)(convert(AbstractArray{TAb}, A), convert(Array{TAb}, b)) + Base.LinAlg.ldiv!($xform(convert(AbstractArray{TAb}, A)), convert(Array{TAb}, b)) end # faster method requiring good view support of the # triangular matrix type. hence the StridedMatrix restriction. - @eval function ($func)(A::$tritype{TA,<:StridedMatrix}, b::SparseVector{Tb}) where {TA<:Number,Tb<:Number} + xformtritype = applyxform ? :($xform{<:TA,<:$tritype{<:Any,<:StridedMatrix}}) : + :($tritype{<:TA,<:StridedMatrix}) + @eval function \(xformA::$xformtritype, b::SparseVector{Tb}) where {TA<:Number,Tb<:Number} + A = $(applyxform ? :(xformA.parent) : :(xformA) ) TAb = $(isunittri ? :(typeof(zero(TA)*zero(Tb) + zero(TA)*zero(Tb))) : :(typeof((zero(TA)*zero(Tb) + zero(TA)*zero(Tb))/one(TA))) ) @@ -1826,25 +1835,32 @@ for isunittri in (true, false), islowertri in (true, false) :(1:b.nzind[end]) ) nzrangeviewr = view(r, nzrange) nzrangeviewA = $tritype(view(A.data, nzrange, nzrange)) - ($ipfunc)(convert(AbstractArray{TAb}, nzrangeviewA), nzrangeviewr) + Base.LinAlg.ldiv!($xform(convert(AbstractArray{TAb}, nzrangeviewA)), nzrangeviewr) end r end # fallback where elements are not Numbers - @eval ($func)(A::$tritype, b::SparseVector) = ($ipfunc)(A, copy(b)) + xformtritype = applyxform ? :($xform{<:Any,<:$tritype}) : :($tritype) + @eval function \(xformA::$xformtritype, b::SparseVector) + A = $(applyxform ? :(xformA.parent) : :(xformA) ) + Base.LinAlg.ldiv!($xform(A), copy(b)) + end end # build in-place left-division operations - for (istrans, func) in ( - (false, :(A_ldiv_B!)), - (true, :(At_ldiv_B!)), - (true, :(Ac_ldiv_B!)) ) + for (istrans, applyxform, xform) in ( + (false, false, :identity), + (true, true, :Transpose), + (true, true, :Adjoint) ) + xformtritype = applyxform ? :($xform{<:Any,<:$tritype{<:Any,<:StridedMatrix}}) : + :($tritype{<:Any,<:StridedMatrix}) # the generic in-place left-division methods handle these cases, but # we can achieve greater efficiency where the triangular matrix provides # good view support. hence the StridedMatrix restriction. - @eval function ($func)(A::$tritype{<:Any,<:StridedMatrix}, b::SparseVector) + @eval function ldiv!(xformA::$xformtritype, b::SparseVector) + A = $(applyxform ? :(xformA.parent) : :(xformA) ) # If b has no nonzero entries, the result is necessarily zero and this call # reduces to a no-op. If b has nonzero entries, then... if nnz(b) != 0 @@ -1862,8 +1878,7 @@ for isunittri in (true, false), islowertri in (true, false) :(1:b.nzind[end]) ) nzrangeviewbnz = view(b.nzval, nzrange .- (b.nzind[1] - 1)) nzrangeviewA = $tritype(view(A.data, nzrange, nzrange)) - ($func)(nzrangeviewA, nzrangeviewbnz) - # could strip any miraculous zeros here perhaps + Base.LinAlg.ldiv!($xform(nzrangeviewA), nzrangeviewbnz) end b end diff --git a/base/statistics.jl b/base/statistics.jl index 0a2b0268b61bc..b0080206005e9 100644 --- a/base/statistics.jl +++ b/base/statistics.jl @@ -327,11 +327,11 @@ unscaled_covzm(x::AbstractMatrix, vardim::Int) = (vardim == 1 ? _conj(x'x) : x * unscaled_covzm(x::AbstractVector, y::AbstractVector) = dot(y, x) unscaled_covzm(x::AbstractVector, y::AbstractMatrix, vardim::Int) = - (vardim == 1 ? At_mul_B(x, _conj(y)) : At_mul_Bt(x, _conj(y))) + (vardim == 1 ? *(Transpose(x), _conj(y)) : *(Transpose(x), Transpose(_conj(y)))) unscaled_covzm(x::AbstractMatrix, y::AbstractVector, vardim::Int) = - (c = vardim == 1 ? At_mul_B(x, _conj(y)) : x * _conj(y); reshape(c, length(c), 1)) + (c = vardim == 1 ? *(Transpose(x), _conj(y)) : x * _conj(y); reshape(c, length(c), 1)) unscaled_covzm(x::AbstractMatrix, y::AbstractMatrix, vardim::Int) = - (vardim == 1 ? At_mul_B(x, _conj(y)) : A_mul_Bc(x, y)) + (vardim == 1 ? *(Transpose(x), _conj(y)) : *(x, Adjoint(y))) # covzm (with centered data) diff --git a/stdlib/IterativeEigenSolvers/src/IterativeEigenSolvers.jl b/stdlib/IterativeEigenSolvers/src/IterativeEigenSolvers.jl index 780c7c19940ee..23c8f2511bc1c 100644 --- a/stdlib/IterativeEigenSolvers/src/IterativeEigenSolvers.jl +++ b/stdlib/IterativeEigenSolvers/src/IterativeEigenSolvers.jl @@ -7,7 +7,7 @@ Arnoldi and Lanczos iteration for computing eigenvalues """ module IterativeEigenSolvers -using Base.LinAlg: BlasFloat, BlasInt, SVD, checksquare +using Base.LinAlg: BlasFloat, BlasInt, SVD, checksquare, mul!, Adjoint, Transpose export eigs, svds @@ -152,7 +152,7 @@ function _eigs(A, B; end # Refer to ex-*.doc files in ARPACK/DOCUMENTS for calling sequence - matvecA!(y, x) = A_mul_B!(y, A, x) + matvecA!(y, x) = mul!(y, A, x) if !isgeneral # Standard problem matvecB = x -> x if !isshift # Regular mode @@ -205,10 +205,10 @@ function SVDAugmented(A::AbstractMatrix{T}) where T SVDAugmented{Tnew,typeof(Anew)}(Anew) end -function Base.A_mul_B!(y::StridedVector{T}, A::SVDAugmented{T}, x::StridedVector{T}) where T +function Base.LinAlg.mul!(y::StridedVector{T}, A::SVDAugmented{T}, x::StridedVector{T}) where T m, mn = size(A.X, 1), length(x) - A_mul_B!( view(y, 1:m), A.X, view(x, m + 1:mn)) # left singular vector - Ac_mul_B!(view(y, m + 1:mn), A.X, view(x, 1:m)) # right singular vector + mul!( view(y, 1:m), A.X, view(x, m + 1:mn)) # left singular vector + mul!(view(y, m + 1:mn), Adjoint(A.X), view(x, 1:m)) # right singular vector return y end Base.size(A::SVDAugmented) = ((+)(size(A.X)...), (+)(size(A.X)...)) @@ -225,13 +225,13 @@ function AtA_or_AAt(A::AbstractMatrix{T}) where T AtA_or_AAt{Tnew,typeof(Anew)}(Anew, Vector{Tnew}(uninitialized, max(size(A)...))) end -function Base.A_mul_B!(y::StridedVector{T}, A::AtA_or_AAt{T}, x::StridedVector{T}) where T +function Base.LinAlg.mul!(y::StridedVector{T}, A::AtA_or_AAt{T}, x::StridedVector{T}) where T if size(A.A, 1) >= size(A.A, 2) - A_mul_B!(A.buffer, A.A, x) - return Ac_mul_B!(y, A.A, A.buffer) + mul!(A.buffer, A.A, x) + return mul!(y, Adjoint(A.A), A.buffer) else - Ac_mul_B!(A.buffer, A.A, x) - return A_mul_B!(y, A.A, A.buffer) + mul!(A.buffer, Adjoint(A.A), x) + return mul!(y, A.A, A.buffer) end end Base.size(A::AtA_or_AAt) = ntuple(i -> min(size(A.A)...), Val(2)) @@ -331,4 +331,6 @@ function _svds(X; nsv::Int = 6, ritzvec::Bool = true, tol::Float64 = 0.0, maxite end end +include("deprecated.jl") + end # module diff --git a/stdlib/IterativeEigenSolvers/src/deprecated.jl b/stdlib/IterativeEigenSolvers/src/deprecated.jl new file mode 100644 index 0000000000000..2d83f5d4e260e --- /dev/null +++ b/stdlib/IterativeEigenSolvers/src/deprecated.jl @@ -0,0 +1,6 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +@eval IterativeEigenSolvers begin + Base.A_mul_B!(y::StridedVector{T}, A::AtA_or_AAt{T}, x::StridedVector{T}) where {T} = Base.LinAlg.mul!(y, A, x) + Base.A_mul_B!(y::StridedVector{T}, A::SVDAugmented{T}, x::StridedVector{T}) where {T} = Base.LinAlg.mul!(y, A, x) +end diff --git a/stdlib/IterativeEigenSolvers/test/runtests.jl b/stdlib/IterativeEigenSolvers/test/runtests.jl index 9c56af6a26b52..52b8e197a7079 100644 --- a/stdlib/IterativeEigenSolvers/test/runtests.jl +++ b/stdlib/IterativeEigenSolvers/test/runtests.jl @@ -105,7 +105,7 @@ using Test end end -# Problematic example from #6965 +# Problematic example from #6965A let A6965 = [ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 -1.0 2.0 0.0 0.0 0.0 0.0 0.0 1.0 @@ -138,8 +138,7 @@ end size(Phi::CPM) = (size(Phi.kraus,1)^2,size(Phi.kraus,3)^2) issymmetric(Phi::CPM) = false ishermitian(Phi::CPM) = false -import Base: A_mul_B! -function A_mul_B!(rho2::StridedVector{T},Phi::CPM{T},rho::StridedVector{T}) where {T<:Base.LinAlg.BlasFloat} +function Base.LinAlg.mul!(rho2::StridedVector{T},Phi::CPM{T},rho::StridedVector{T}) where {T<:Base.LinAlg.BlasFloat} rho = reshape(rho,(size(Phi.kraus,3),size(Phi.kraus,3))) rho1 = zeros(T,(size(Phi.kraus,1),size(Phi.kraus,1))) for s = 1:size(Phi.kraus,2) @@ -148,6 +147,8 @@ function A_mul_B!(rho2::StridedVector{T},Phi::CPM{T},rho::StridedVector{T}) wher end return copy!(rho2,rho1) end +Base.LinAlg.A_mul_B!(rho2::StridedVector{T},Phi::CPM{T},rho::StridedVector{T}) where {T<:Base.LinAlg.BlasFloat} = Base.LinAlg.mul!(rho2, Phi, rho) +# after the A_mul_B! deprecation, remove this A_mul_B! def let # Generate random isometry diff --git a/stdlib/SuiteSparse/src/SuiteSparse.jl b/stdlib/SuiteSparse/src/SuiteSparse.jl index 87073f010de7c..6b7558310a1d0 100644 --- a/stdlib/SuiteSparse/src/SuiteSparse.jl +++ b/stdlib/SuiteSparse/src/SuiteSparse.jl @@ -4,8 +4,8 @@ __precompile__(true) module SuiteSparse -import Base: At_ldiv_B, Ac_ldiv_B, A_ldiv_B! -import Base.LinAlg: At_ldiv_B!, Ac_ldiv_B!, A_rdiv_B!, A_rdiv_Bc! +import Base: \ +import Base.LinAlg: ldiv!, rdiv! ## Functions to switch to 0-based indexing to call external sparse solvers @@ -27,6 +27,7 @@ if Base.USE_GPL_LIBS include("umfpack.jl") include("cholmod.jl") include("spqr.jl") + include("deprecated.jl") end end # module SuiteSparse diff --git a/stdlib/SuiteSparse/src/cholmod.jl b/stdlib/SuiteSparse/src/cholmod.jl index b0d535d6dd893..c6d99bf1d7c8f 100644 --- a/stdlib/SuiteSparse/src/cholmod.jl +++ b/stdlib/SuiteSparse/src/cholmod.jl @@ -5,9 +5,10 @@ module CHOLMOD import Base: (*), convert, copy, eltype, getindex, show, size, IndexStyle, IndexLinear, IndexCartesian, adjoint -import Base.LinAlg: (\), A_mul_Bc, A_mul_Bt, Ac_ldiv_B, Ac_mul_B, At_ldiv_B, At_mul_B, +import Base.LinAlg: (\), cholfact, cholfact!, det, diag, ishermitian, isposdef, - issuccess, issymmetric, ldltfact, ldltfact!, logdet + issuccess, issymmetric, ldltfact, ldltfact!, logdet, + Adjoint, Transpose using ..SparseArrays @@ -1293,7 +1294,8 @@ end (*)(A::Sparse, B::Dense) = sdmult!(A, false, 1., 0., B, zeros(size(A, 1), size(B, 2))) (*)(A::Sparse, B::VecOrMat) = (*)(A, Dense(B)) -function A_mul_Bc(A::Sparse{Tv}, B::Sparse{Tv}) where Tv<:VRealTypes +function *(A::Sparse{Tv}, adjB::Adjoint{Tv,Sparse{Tv}}) where Tv<:VRealTypes + B = adjB.parent if A !== B aa1 = transpose_(B, 2) ## result of ssmult will have stype==0, contain numerical values and be sorted @@ -1312,17 +1314,20 @@ function A_mul_Bc(A::Sparse{Tv}, B::Sparse{Tv}) where Tv<:VRealTypes end end -function Ac_mul_B(A::Sparse, B::Sparse) +function *(adjA::Adjoint{<:Any,<:Sparse}, B::Sparse) + A = adjA.parent aa1 = transpose_(A, 2) if A === B - return A_mul_Bc(aa1, aa1) + return *(aa1, Adjoint(aa1)) end ## result of ssmult will have stype==0, contain numerical values and be sorted return ssmult(aa1, B, 0, true, true) end -Ac_mul_B(A::Sparse, B::Dense) = sdmult!(A, true, 1., 0., B, zeros(size(A, 2), size(B, 2))) -Ac_mul_B(A::Sparse, B::VecOrMat) = Ac_mul_B(A, Dense(B)) +*(adjA::Adjoint{<:Any,<:Sparse}, B::Dense) = + (A = adjA.parent; sdmult!(A, true, 1., 0., B, zeros(size(A, 2), size(B, 2)))) +*(adjA::Adjoint{<:Any,<:Sparse}, B::VecOrMat) = + (A = adjA.parent; *(Adjoint(A), Dense(B))) ## Factorization methods @@ -1672,8 +1677,8 @@ function (\)(L::FactorComponent, B::SparseVecOrMat) sparse(L\Sparse(B,0)) end -Ac_ldiv_B(L::FactorComponent, B) = adjoint(L)\B -Ac_ldiv_B(L::FactorComponent, B::RowVector) = adjoint(L)\B # ambiguity +\(adjL::Adjoint{<:Any,<:FactorComponent}, B::Union{VecOrMat,SparseVecOrMat}) = (L = adjL.parent; adjoint(L)\B) +\(adjL::Adjoint{<:Any,<:FactorComponent}, B::RowVector) = (L = adjL.parent; adjoint(L)\B) # ambiguity (\)(L::Factor{T}, B::Dense{T}) where {T<:VTypes} = solve(CHOLMOD_A, L, B) # Explicit typevars are necessary to avoid ambiguities with defs in linalg/factorizations.jl @@ -1686,25 +1691,39 @@ Ac_ldiv_B(L::FactorComponent, B::RowVector) = adjoint(L)\B # ambiguity # When right hand side is sparse, we have to ensure that the rhs is not marked as symmetric. (\)(L::Factor, B::SparseVecOrMat) = sparse(spsolve(CHOLMOD_A, L, Sparse(B, 0))) -Ac_ldiv_B(L::Factor, B::Dense) = solve(CHOLMOD_A, L, B) -Ac_ldiv_B(L::Factor, B::VecOrMat) = convert(Matrix, solve(CHOLMOD_A, L, Dense(B))) -Ac_ldiv_B(L::Factor, B::Sparse) = spsolve(CHOLMOD_A, L, B) -Ac_ldiv_B(L::Factor, B::SparseVecOrMat) = Ac_ldiv_B(L, Sparse(B)) - -for f in (:\, :Ac_ldiv_B) - @eval function ($f)(A::Union{Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}, - Hermitian{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}, - Hermitian{Complex{Float64},SparseMatrixCSC{Complex{Float64},SuiteSparse_long}}}, B::StridedVecOrMat) - F = cholfact(A) +\(adjL::Adjoint{<:Any,<:Factor}, B::Dense) = (L = adjL.parent; solve(CHOLMOD_A, L, B)) +\(adjL::Adjoint{<:Any,<:Factor}, B::VecOrMat) = (L = adjL.parent; convert(Matrix, solve(CHOLMOD_A, L, Dense(B)))) +\(adjL::Adjoint{<:Any,<:Factor}, B::Sparse) = (L = adjL.parent; spsolve(CHOLMOD_A, L, B)) +\(adjL::Adjoint{<:Any,<:Factor}, B::SparseVecOrMat) = (L = adjL.parent; \(Adjoint(L), Sparse(B))) + +const RealHermSymComplexHermF64SSL = Union{ + Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}, + Hermitian{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}, + Hermitian{Complex{Float64},SparseMatrixCSC{Complex{Float64},SuiteSparse_long}}} +function \(A::RealHermSymComplexHermF64SSL, B::StridedVecOrMat) + F = cholfact(A) + if issuccess(F) + return \(F, B) + else + ldltfact!(F, A) if issuccess(F) - return ($f)(F, B) + return \(F, B) else - ldltfact!(F, A) - if issuccess(F) - return ($f)(F, B) - else - return ($f)(lufact(convert(SparseMatrixCSC{eltype(A), SuiteSparse_long}, A)), B) - end + return \(lufact(convert(SparseMatrixCSC{eltype(A), SuiteSparse_long}, A)), B) + end + end +end +function \(adjA::Adjoint{<:Any,<:RealHermSymComplexHermF64SSL}, B::StridedVecOrMat) + A = adjA.parent + F = cholfact(A) + if issuccess(F) + return \(Adjoint(F), B) + else + ldltfact!(F, A) + if issuccess(F) + return \(Adjoint(F), B) + else + return \(Adjoint(lufact(convert(SparseMatrixCSC{eltype(A), SuiteSparse_long}, A))), B) end end end diff --git a/stdlib/SuiteSparse/src/deprecated.jl b/stdlib/SuiteSparse/src/deprecated.jl new file mode 100644 index 0000000000000..974bb6ab5c119 --- /dev/null +++ b/stdlib/SuiteSparse/src/deprecated.jl @@ -0,0 +1,49 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from src/cholmod.jl, to deprecate +@eval SuiteSparse.CHOLMOD begin + using Base.LinAlg: Adjoint, Transpose + Base.Ac_ldiv_B(A::RealHermSymComplexHermF64SSL, B::StridedVecOrMat) = \(Adjoint(A), B) + Base.Ac_ldiv_B(L::Factor, B::Dense) = \(Adjoint(L), B) + Base.Ac_ldiv_B(L::Factor, B::VecOrMat) = \(Adjoint(L), B) + Base.Ac_ldiv_B(L::Factor, B::Sparse) = \(Adjoint(L), B) + Base.Ac_ldiv_B(L::Factor, B::SparseVecOrMat) = \(Adjoint(L), B) + Base.Ac_ldiv_B(L::FactorComponent, B) = \(Adjoint(L), B) + Base.Ac_ldiv_B(L::FactorComponent, B::RowVector) = \(Adjoint(L), B) + Base.Ac_mul_B(A::Sparse, B::Dense) = *(Adjoint(A), B) + Base.Ac_mul_B(A::Sparse, B::VecOrMat) = *(Adjoint(A), B) + Base.Ac_mul_B(A::Sparse, B::Sparse) = *(Adjoint(A), B) + Base.A_mul_Bc(A::Sparse{Tv}, B::Sparse{Tv}) where {Tv<:VRealTypes} = *(A, Adjoint(B)) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from src/umfpack.jl, to deprecate +@eval SuiteSparse.UMFPACK begin + using Base.LinAlg: Adjoint, Transpose + Base.A_ldiv_B!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = + Base.LinAlg.ldiv!(X, lu, B) + Base.At_ldiv_B!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = + Base.LinAlg.ldiv!(X, Transpose(lu), B) + Base.Ac_ldiv_B!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = + Base.LinAlg.ldiv!(X, Adjoint(lu), B) + Base.A_ldiv_B!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = + Base.LinAlg.ldiv!(X, lu, B) + Base.At_ldiv_B!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = + Base.LinAlg.ldiv!(X, Transpose(lu), B) + Base.Ac_ldiv_B!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = + Base.LinAlg.ldiv!(X, Adjoint(lu), B) + Base.A_ldiv_B!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = Base.LinAlg.ldiv!(lu, B) + Base.At_ldiv_B!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = Base.LinAlg.ldiv!(Transpose(lu), B) + Base.Ac_ldiv_B!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = Base.LinAlg.ldiv!(Adjoint(lu), B) + Base.A_ldiv_B!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = Base.LinAlg.ldiv!(lu, B) + Base.At_ldiv_B!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = Base.LinAlg.ldiv!(Transpose(lu), B) + Base.Ac_ldiv_B!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = Base.LinAlg.ldiv!(Adjoint(lu), B) +end + +# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from src/spqr.jl, to deprecate +@eval SuiteSparse.SPQR begin + using Base.LinAlg: Adjoint, Transpose + Base.A_mul_Bc!(A::StridedMatrix, Q::QRSparseQ) = Base.LinAlg.mul!(A, Adjoint(Q)) + Base.Ac_mul_B!(Q::QRSparseQ, A::StridedVecOrMat) = Base.LinAlg.mul!(Adjoint(Q), A) + Base.A_mul_B!(A::StridedMatrix, Q::QRSparseQ) = Base.LinAlg.mul!(A, Q) + Base.A_mul_B!(Q::QRSparseQ, A::StridedVecOrMat) = Base.LinAlg.mul!(Q, A) +end diff --git a/stdlib/SuiteSparse/src/spqr.jl b/stdlib/SuiteSparse/src/spqr.jl index fe6237b80854a..c675839baef6d 100644 --- a/stdlib/SuiteSparse/src/spqr.jl +++ b/stdlib/SuiteSparse/src/spqr.jl @@ -3,6 +3,7 @@ module SPQR import Base: \ +using Base.LinAlg: Adjoint, Transpose # ordering options */ const ORDERING_FIXED = Int32(0) @@ -197,7 +198,7 @@ Base.LinAlg.qrfact(A::SparseMatrixCSC; tol = _default_tol(A)) = qrfact(A, Val{tr Base.LinAlg.qr(A::SparseMatrixCSC; tol = _default_tol(A)) = qr(A, Val{true}, tol = tol) -function Base.A_mul_B!(Q::QRSparseQ, A::StridedVecOrMat) +function Base.LinAlg.mul!(Q::QRSparseQ, A::StridedVecOrMat) if size(A, 1) != size(Q, 1) throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))")) end @@ -212,7 +213,7 @@ function Base.A_mul_B!(Q::QRSparseQ, A::StridedVecOrMat) return A end -function Base.A_mul_B!(A::StridedMatrix, Q::QRSparseQ) +function Base.LinAlg.mul!(A::StridedMatrix, Q::QRSparseQ) if size(A, 2) != size(Q, 1) throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))")) end @@ -220,13 +221,14 @@ function Base.A_mul_B!(A::StridedMatrix, Q::QRSparseQ) for l in 1:size(Q.factors, 2) τl = -Q.τ[l] h = view(Q.factors, :, l) - A_mul_B!(tmp, A, h) + Base.LinAlg.mul!(tmp, A, h) LinAlg.lowrankupdate!(A, tmp, h, τl) end return A end -function Base.Ac_mul_B!(Q::QRSparseQ, A::StridedVecOrMat) +function Base.LinAlg.mul!(adjQ::Adjoint{<:Any,<:QRSparseQ}, A::StridedVecOrMat) + Q = adjQ.parent if size(A, 1) != size(Q, 1) throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))")) end @@ -241,7 +243,8 @@ function Base.Ac_mul_B!(Q::QRSparseQ, A::StridedVecOrMat) return A end -function Base.A_mul_Bc!(A::StridedMatrix, Q::QRSparseQ) +function Base.LinAlg.mul!(A::StridedMatrix, adjQ::Adjoint{<:Any,<:QRSparseQ}) + Q = adjQ.parent if size(A, 2) != size(Q, 1) throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))")) end @@ -249,7 +252,7 @@ function Base.A_mul_Bc!(A::StridedMatrix, Q::QRSparseQ) for l in size(Q.factors, 2):-1:1 τl = -Q.τ[l] h = view(Q.factors, :, l) - A_mul_B!(tmp, A, h) + Base.LinAlg.mul!(tmp, A, h) LinAlg.lowrankupdate!(A, tmp, h, τl') end return A @@ -330,7 +333,7 @@ end # the complex rhs as a real rhs with twice the number of columns # # This definition is similar to the definition in factorization.jl except that -# here we have to use \ instead of A_ldiv_B! because of limitations in SPQR +# here we have to use \ instead of ldiv! because of limitations in SPQR ## Two helper methods _ret_size(F::QRSparse, b::AbstractVector) = (size(F, 2),) @@ -376,13 +379,13 @@ function _ldiv_basic(F::QRSparse, B::StridedVecOrMat) X0 = view(X, 1:size(B, 1), :) # Apply Q' to B - Ac_mul_B!(LinAlg.getq(F), X0) + Base.LinAlg.mul!(Adjoint(LinAlg.getq(F)), X0) # Zero out to get basic solution X[rnk + 1:end, :] = 0 # Solve R*X = B - A_ldiv_B!(UpperTriangular(view(F.R, :, Base.OneTo(rnk))), view(X0, Base.OneTo(rnk), :)) + Base.LinAlg.ldiv!(UpperTriangular(view(F.R, :, Base.OneTo(rnk))), view(X0, Base.OneTo(rnk), :)) # Apply right permutation and extract solution from X return getindex(X, ntuple(i -> i == 1 ? invperm(F.cpiv) : :, Val(ndims(B)))...) diff --git a/stdlib/SuiteSparse/src/umfpack.jl b/stdlib/SuiteSparse/src/umfpack.jl index fad1158d178b9..0749ddcf2f3f9 100644 --- a/stdlib/SuiteSparse/src/umfpack.jl +++ b/stdlib/SuiteSparse/src/umfpack.jl @@ -4,8 +4,9 @@ module UMFPACK export UmfpackLU -import Base: (\), Ac_ldiv_B, At_ldiv_B, findnz, getindex, show, size -import Base.LinAlg: A_ldiv_B!, Ac_ldiv_B!, At_ldiv_B!, Factorization, det, lufact +import Base: (\), findnz, getindex, show, size +import Base.LinAlg: Factorization, det, lufact, ldiv! +using Base.LinAlg: Adjoint, Transpose using ..SparseArrays import ..SparseArrays: nnz @@ -384,25 +385,31 @@ function nnz(lu::UmfpackLU) end ### Solve with Factorization -A_ldiv_B!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = A_ldiv_B!(B, lu, copy(B)) -At_ldiv_B!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = At_ldiv_B!(B, lu, copy(B)) -Ac_ldiv_B!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = Ac_ldiv_B!(B, lu, copy(B)) -A_ldiv_B!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = A_ldiv_B!(B, lu, copy(B)) -At_ldiv_B!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = At_ldiv_B!(B, lu, copy(B)) -Ac_ldiv_B!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = Ac_ldiv_B!(B, lu, copy(B)) - -A_ldiv_B!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = +ldiv!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = + ldiv!(B, lu, copy(B)) +ldiv!(translu::Transpose{T,<:UmfpackLU{T}}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = + (lu = translu.parent; ldiv!(B, Transpose(lu), copy(B))) +ldiv!(adjlu::Adjoint{T,<:UmfpackLU{T}}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = + (lu = adjlu.parent; ldiv!(B, Adjoint(lu), copy(B))) +ldiv!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = + ldiv!(B, lu, copy(B)) +ldiv!(translu::Transpose{Float64,<:UmfpackLU{Float64}}, B::StridedVecOrMat{<:Complex}) = + (lu = translu.parent; ldiv!(B, Transpose(lu), copy(B))) +ldiv!(adjlu::Adjoint{Float64,<:UmfpackLU{Float64}}, B::StridedVecOrMat{<:Complex}) = + (lu = adjlu.parent; ldiv!(B, Adjoint(lu), copy(B))) + +ldiv!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = _Aq_ldiv_B!(X, lu, B, UMFPACK_A) -At_ldiv_B!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = - _Aq_ldiv_B!(X, lu, B, UMFPACK_Aat) -Ac_ldiv_B!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = - _Aq_ldiv_B!(X, lu, B, UMFPACK_At) -A_ldiv_B!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = +ldiv!(X::StridedVecOrMat{T}, translu::Transpose{T,<:UmfpackLU{T}}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = + (lu = translu.parent; _Aq_ldiv_B!(X, lu, B, UMFPACK_Aat)) +ldiv!(X::StridedVecOrMat{T}, adjlu::Adjoint{T,<:UmfpackLU{T}}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = + (lu = adjlu.parent; _Aq_ldiv_B!(X, lu, B, UMFPACK_At)) +ldiv!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = _Aq_ldiv_B!(X, lu, B, UMFPACK_A) -At_ldiv_B!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = - _Aq_ldiv_B!(X, lu, B, UMFPACK_Aat) -Ac_ldiv_B!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = - _Aq_ldiv_B!(X, lu, B, UMFPACK_At) +ldiv!(X::StridedVecOrMat{Tb}, translu::Transpose{Float64,<:UmfpackLU{Float64}}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = + (lu = translu.parent; _Aq_ldiv_B!(X, lu, B, UMFPACK_Aat)) +ldiv!(X::StridedVecOrMat{Tb}, adjlu::Adjoint{Float64,<:UmfpackLU{Float64}}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = + (lu = adjlu.parent; _Aq_ldiv_B!(X, lu, B, UMFPACK_At)) function _Aq_ldiv_B!(X::StridedVecOrMat, lu::UmfpackLU, B::StridedVecOrMat, transposeoptype) if size(X, 2) != size(B, 2) diff --git a/stdlib/SuiteSparse/test/spqr.jl b/stdlib/SuiteSparse/test/spqr.jl index 8601f7fa4ac37..970c91fabef5e 100644 --- a/stdlib/SuiteSparse/test/spqr.jl +++ b/stdlib/SuiteSparse/test/spqr.jl @@ -2,6 +2,7 @@ using SuiteSparse.SPQR using SuiteSparse.CHOLMOD +using Base.LinAlg: mul!, Adjoint, Transpose @testset "Sparse QR" begin m, n = 100, 10 @@ -42,10 +43,10 @@ nn = 100 @test norm(R0[n + 1:end, :], 1) < 1e-12 offsizeA = Matrix{Float64}(I, m+1, m+1) - @test_throws DimensionMismatch A_mul_B!(Q, offsizeA) - @test_throws DimensionMismatch Ac_mul_B!(Q, offsizeA) - @test_throws DimensionMismatch A_mul_B!(offsizeA, Q) - @test_throws DimensionMismatch A_mul_Bc!(offsizeA, Q) + @test_throws DimensionMismatch mul!(Q, offsizeA) + @test_throws DimensionMismatch mul!(Adjoint(Q), offsizeA) + @test_throws DimensionMismatch mul!(offsizeA, Q) + @test_throws DimensionMismatch mul!(offsizeA, Adjoint(Q)) end @testset "element type of B: $eltyB" for eltyB in (Int, Float64, Complex{Float64}) diff --git a/stdlib/SuiteSparse/test/umfpack.jl b/stdlib/SuiteSparse/test/umfpack.jl index ebb48dffd6ea9..5f3b1a0c6c5fc 100644 --- a/stdlib/SuiteSparse/test/umfpack.jl +++ b/stdlib/SuiteSparse/test/umfpack.jl @@ -8,6 +8,7 @@ # based on deps/Suitesparse-4.0.2/UMFPACK/Demo/umfpack_di_demo.c using SuiteSparse.increment! + using Base.LinAlg: Adjoint, Transpose A0 = sparse(increment!([0,4,1,1,2,2,0,1,2,3,4,4]), increment!([0,4,0,2,1,2,1,4,3,2,1,2]), @@ -31,11 +32,11 @@ @test A*x ≈ b z = complex.(b) - x = SuiteSparse.A_ldiv_B!(lua, z) + x = SuiteSparse.ldiv!(lua, z) @test x ≈ float([1:5;]) @test z === x y = similar(z) - A_ldiv_B!(y, lua, complex.(b)) + Base.LinAlg.ldiv!(y, lua, complex.(b)) @test y ≈ x @test A*x ≈ b @@ -46,11 +47,11 @@ @test A'*x ≈ b z = complex.(b) - x = SuiteSparse.Ac_ldiv_B!(lua, z) + x = SuiteSparse.ldiv!(Adjoint(lua), z) @test x ≈ float([1:5;]) @test x === z y = similar(x) - SuiteSparse.Ac_ldiv_B!(y, lua, complex.(b)) + SuiteSparse.ldiv!(y, Adjoint(lua), complex.(b)) @test y ≈ x @test A'*x ≈ b @@ -58,10 +59,10 @@ @test x ≈ float([1:5;]) @test A.'*x ≈ b - x = SuiteSparse.At_ldiv_B!(lua,complex.(b)) + x = SuiteSparse.ldiv!(Transpose(lua), complex.(b)) @test x ≈ float([1:5;]) y = similar(x) - SuiteSparse.At_ldiv_B!(y, lua,complex.(b)) + SuiteSparse.ldiv!(y, Transpose(lua), complex.(b)) @test y ≈ x @test A.'*x ≈ b @@ -161,9 +162,9 @@ X = zeros(Complex{Float64}, N, N) B = complex.(rand(N, N), rand(N, N)) luA, lufA = lufact(A), lufact(Array(A)) - @test A_ldiv_B!(copy(X), luA, B) ≈ A_ldiv_B!(copy(X), lufA, B) - @test At_ldiv_B!(copy(X), luA, B) ≈ At_ldiv_B!(copy(X), lufA, B) - @test Ac_ldiv_B!(copy(X), luA, B) ≈ Ac_ldiv_B!(copy(X), lufA, B) + @test Base.LinAlg.ldiv!(copy(X), luA, B) ≈ Base.LinAlg.ldiv!(copy(X), lufA, B) + @test Base.LinAlg.ldiv!(copy(X), Adjoint(luA), B) ≈ Base.LinAlg.ldiv!(copy(X), Adjoint(lufA), B) + @test Base.LinAlg.ldiv!(copy(X), Transpose(luA), B) ≈ Base.LinAlg.ldiv!(copy(X), Transpose(lufA), B) end end diff --git a/test/choosetests.jl b/test/choosetests.jl index dd76d15ee2406..0279080578ad5 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -126,7 +126,7 @@ function choosetests(choices = []) "linalg/cholesky", "linalg/lu", "linalg/symmetric", "linalg/generic", "linalg/uniformscaling", "linalg/lq", "linalg/hessenberg", "linalg/rowvector", "linalg/conjarray", - "linalg/blas"] + "linalg/blas", "linalg/adjtrans"] if "linalg" in skip_tests filter!(x -> (x != "linalg" && !(x in linalgtests)), tests) diff --git a/test/linalg/adjtrans.jl b/test/linalg/adjtrans.jl new file mode 100644 index 0000000000000..b21c8ee31e529 --- /dev/null +++ b/test/linalg/adjtrans.jl @@ -0,0 +1,288 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# This file is a part of Julia. License is MIT: https://julialang.org/license + +using Test +using Base.LinAlg: Adjoint, Transpose + +@testset "Adjoint and Transpose inner constructor basics" begin + intvec, intmat = [1, 2], [1 2; 3 4] + # Adjoint/Transpose eltype must match the type of the Adjoint/Transpose of the input eltype + @test_throws ErrorException Adjoint{Float64,Vector{Int}}(intvec) + @test_throws ErrorException Adjoint{Float64,Matrix{Int}}(intmat) + @test_throws ErrorException Transpose{Float64,Vector{Int}}(intvec) + @test_throws ErrorException Transpose{Float64,Matrix{Int}}(intmat) + # Adjoint/Transpose wrapped array type must match the input array type + @test_throws MethodError Adjoint{Int,Vector{Float64}}(intvec) + @test_throws MethodError Adjoint{Int,Matrix{Float64}}(intmat) + @test_throws MethodError Transpose{Int,Vector{Float64}}(intvec) + @test_throws MethodError Transpose{Int,Matrix{Float64}}(intmat) + # Adjoint/Transpose inner constructor basic functionality, concrete scalar eltype + @test (Adjoint{Int,Vector{Int}}(intvec)::Adjoint{Int,Vector{Int}}).parent === intvec + @test (Adjoint{Int,Matrix{Int}}(intmat)::Adjoint{Int,Matrix{Int}}).parent === intmat + @test (Transpose{Int,Vector{Int}}(intvec)::Transpose{Int,Vector{Int}}).parent === intvec + @test (Transpose{Int,Matrix{Int}}(intmat)::Transpose{Int,Matrix{Int}}).parent === intmat + # Adjoint/Transpose inner constructor basic functionality, abstract scalar eltype + anyvec, anymat = Any[1, 2], Any[1 2; 3 4] + @test (Adjoint{Any,Vector{Any}}(anyvec)::Adjoint{Any,Vector{Any}}).parent === anyvec + @test (Adjoint{Any,Matrix{Any}}(anymat)::Adjoint{Any,Matrix{Any}}).parent === anymat + @test (Transpose{Any,Vector{Any}}(anyvec)::Transpose{Any,Vector{Any}}).parent === anyvec + @test (Transpose{Any,Matrix{Any}}(anymat)::Transpose{Any,Matrix{Any}}).parent === anymat + # Adjoint/Transpose inner constructor basic functionality, concrete array eltype + intvecvec = [[1, 2], [3, 4]] + intmatmat = [[[1 2]] [[3 4]] [[5 6]]; [[7 8]] [[9 10]] [[11 12]]] + @test (X = Adjoint{Adjoint{Int,Vector{Int}},Vector{Vector{Int}}}(intvecvec); + isa(X, Adjoint{Adjoint{Int,Vector{Int}},Vector{Vector{Int}}}) && X.parent === intvecvec) + @test (X = Adjoint{Adjoint{Int,Matrix{Int}},Matrix{Matrix{Int}}}(intmatmat); + isa(X, Adjoint{Adjoint{Int,Matrix{Int}},Matrix{Matrix{Int}}}) && X.parent === intmatmat) + @test (X = Transpose{Transpose{Int,Vector{Int}},Vector{Vector{Int}}}(intvecvec); + isa(X, Transpose{Transpose{Int,Vector{Int}},Vector{Vector{Int}}}) && X.parent === intvecvec) + @test (X = Transpose{Transpose{Int,Matrix{Int}},Matrix{Matrix{Int}}}(intmatmat); + isa(X, Transpose{Transpose{Int,Matrix{Int}},Matrix{Matrix{Int}}}) && X.parent === intmatmat) +end + +@testset "Adjoint and Transpose outer constructor basics" begin + intvec, intmat = [1, 2], [1 2; 3 4] + # the wrapped array's eltype strictly determines the Adjoint/Transpose eltype + # so Adjoint{T}/Transpose{T} constructors are somewhat unnecessary and error-prone + # so ascertain that such calls throw whether or not T and the input eltype are compatible + @test_throws MethodError Adjoint{Int}(intvec) + @test_throws MethodError Adjoint{Int}(intmat) + @test_throws MethodError Adjoint{Float64}(intvec) + @test_throws MethodError Adjoint{Float64}(intmat) + @test_throws MethodError Transpose{Int}(intvec) + @test_throws MethodError Transpose{Int}(intmat) + @test_throws MethodError Transpose{Float64}(intvec) + @test_throws MethodError Transpose{Float64}(intmat) + # Adjoint/Transpose outer constructor basic functionality, concrete scalar eltype + @test (Adjoint(intvec)::Adjoint{Int,Vector{Int}}).parent === intvec + @test (Adjoint(intmat)::Adjoint{Int,Matrix{Int}}).parent === intmat + @test (Transpose(intvec)::Transpose{Int,Vector{Int}}).parent === intvec + @test (Transpose(intmat)::Transpose{Int,Matrix{Int}}).parent === intmat + # the tests for the inner constructors exercise abstract scalar and concrete array eltype, forgoing here +end + +@testset "Adjoint and Transpose of Numbers" begin + @test Adjoint(1) == 1 + @test Adjoint(1.0) == 1.0 + @test Adjoint(1im) == -1im + @test Adjoint(1.0im) == -1.0im + @test Transpose(1) == 1 + @test Transpose(1.0) == 1.0 + @test Transpose(1im) == 1im + @test Transpose(1.0im) == 1.0im +end + +@testset "Adjoint and Transpose unwrapping" begin + intvec, intmat = [1, 2], [1 2; 3 4] + @test Adjoint(Adjoint(intvec)) === intvec + @test Adjoint(Adjoint(intmat)) === intmat + @test Transpose(Transpose(intvec)) === intvec + @test Transpose(Transpose(intmat)) === intmat +end + +@testset "Adjoint and Transpose basic AbstractArray functionality" begin + # vectors and matrices with real scalar eltype, and their adjoints/transposes + intvec, intmat = [1, 2], [1 2 3; 4 5 6] + tintvec, tintmat = [1 2], [1 4; 2 5; 3 6] + @testset "length methods" begin + @test length(Adjoint(intvec)) == length(intvec) + @test length(Adjoint(intmat)) == length(intmat) + @test length(Transpose(intvec)) == length(intvec) + @test length(Transpose(intmat)) == length(intmat) + end + @testset "size methods" begin + @test size(Adjoint(intvec)) == (1, length(intvec)) + @test size(Adjoint(intmat)) == reverse(size(intmat)) + @test size(Transpose(intvec)) == (1, length(intvec)) + @test size(Transpose(intmat)) == reverse(size(intmat)) + end + @testset "indices methods" begin + @test indices(Adjoint(intvec)) == (Base.OneTo(1), Base.OneTo(length(intvec))) + @test indices(Adjoint(intmat)) == reverse(indices(intmat)) + @test indices(Transpose(intvec)) == (Base.OneTo(1), Base.OneTo(length(intvec))) + @test indices(Transpose(intmat)) == reverse(indices(intmat)) + end + @testset "IndexStyle methods" begin + @test IndexStyle(Adjoint(intvec)) == IndexLinear() + @test IndexStyle(Adjoint(intmat)) == IndexCartesian() + @test IndexStyle(Transpose(intvec)) == IndexLinear() + @test IndexStyle(Transpose(intmat)) == IndexCartesian() + end + # vectors and matrices with complex scalar eltype, and their adjoints/transposes + complexintvec, complexintmat = [1im, 2im], [1im 2im 3im; 4im 5im 6im] + tcomplexintvec, tcomplexintmat = [1im 2im], [1im 4im; 2im 5im; 3im 6im] + acomplexintvec, acomplexintmat = conj.(tcomplexintvec), conj.(tcomplexintmat) + # vectors and matrices with real-vector and real-matrix eltype, and their adjoints/transposes + intvecvec = [[1, 2], [3, 4]] + tintvecvec = [[[1 2]] [[3 4]]] + intmatmat = [[[1 2]] [[3 4]] [[ 5 6]]; + [[7 8]] [[9 10]] [[11 12]]] + tintmatmat = [[hcat([1, 2])] [hcat([7, 8])]; + [hcat([3, 4])] [hcat([9, 10])]; + [hcat([5, 6])] [hcat([11, 12])]] + # vectors and matrices with complex-vector and complex-matrix eltype, and their adjoints/transposes + complexintvecvec, complexintmatmat = im .* (intvecvec, intmatmat) + tcomplexintvecvec, tcomplexintmatmat = im .* (tintvecvec, tintmatmat) + acomplexintvecvec, acomplexintmatmat = conj.(tcomplexintvecvec), conj.(tcomplexintmatmat) + @testset "getindex methods, elementary" begin + # implicitly test elementary definitions, for arrays with concrete real scalar eltype + @test Adjoint(intvec) == tintvec + @test Adjoint(intmat) == tintmat + @test Transpose(intvec) == tintvec + @test Transpose(intmat) == tintmat + # implicitly test elementary definitions, for arrays with concrete complex scalar eltype + @test Adjoint(complexintvec) == acomplexintvec + @test Adjoint(complexintmat) == acomplexintmat + @test Transpose(complexintvec) == tcomplexintvec + @test Transpose(complexintmat) == tcomplexintmat + # implicitly test elementary definitions, for arrays with concrete real-array eltype + @test Adjoint(intvecvec) == tintvecvec + @test Adjoint(intmatmat) == tintmatmat + @test Transpose(intvecvec) == tintvecvec + @test Transpose(intmatmat) == tintmatmat + # implicitly test elementary definitions, for arrays with concrete complex-array type + @test Adjoint(complexintvecvec) == acomplexintvecvec + @test Adjoint(complexintmatmat) == acomplexintmatmat + @test Transpose(complexintvecvec) == tcomplexintvecvec + @test Transpose(complexintmatmat) == tcomplexintmatmat + end + @testset "getindex(::AdjOrTransVec, ::Colon, ::AbstractArray{Int}) methods that preserve wrapper type" begin + # for arrays with concrete scalar eltype + @test Adjoint(intvec)[:, [1, 2]] == Adjoint(intvec) + @test Transpose(intvec)[:, [1, 2]] == Transpose(intvec) + @test Adjoint(complexintvec)[:, [1, 2]] == Adjoint(complexintvec) + @test Transpose(complexintvec)[:, [1, 2]] == Transpose(complexintvec) + # for arrays with concrete array eltype + @test Adjoint(intvecvec)[:, [1, 2]] == Adjoint(intvecvec) + @test Transpose(intvecvec)[:, [1, 2]] == Transpose(intvecvec) + @test Adjoint(complexintvecvec)[:, [1, 2]] == Adjoint(complexintvecvec) + @test Transpose(complexintvecvec)[:, [1, 2]] == Transpose(complexintvecvec) + end + @testset "getindex(::AdjOrTransVec, ::Colon, ::Colon) methods that preserve wrapper type" begin + # for arrays with concrete scalar eltype + @test Adjoint(intvec)[:, :] == Adjoint(intvec) + @test Transpose(intvec)[:, :] == Transpose(intvec) + @test Adjoint(complexintvec)[:, :] == Adjoint(complexintvec) + @test Transpose(complexintvec)[:, :] == Transpose(complexintvec) + # for arrays with concrete array elype + @test Adjoint(intvecvec)[:, :] == Adjoint(intvecvec) + @test Transpose(intvecvec)[:, :] == Transpose(intvecvec) + @test Adjoint(complexintvecvec)[:, :] == Adjoint(complexintvecvec) + @test Transpose(complexintvecvec)[:, :] == Transpose(complexintvecvec) + end + @testset "getindex(::AdjOrTransVec, ::Colon, ::Int) should preserve wrapper type on result entries" begin + # for arrays with concrete scalar eltype + @test Adjoint(intvec)[:, 2] == intvec[2:2] + @test Transpose(intvec)[:, 2] == intvec[2:2] + @test Adjoint(complexintvec)[:, 2] == conj.(complexintvec[2:2]) + @test Transpose(complexintvec)[:, 2] == complexintvec[2:2] + # for arrays with concrete array eltype + @test Adjoint(intvecvec)[:, 2] == Adjoint.(intvecvec[2:2]) + @test Transpose(intvecvec)[:, 2] == Transpose.(intvecvec[2:2]) + @test Adjoint(complexintvecvec)[:, 2] == Adjoint.(complexintvecvec[2:2]) + @test Transpose(complexintvecvec)[:, 2] == Transpose.(complexintvecvec[2:2]) + end + @testset "setindex! methods" begin + # for vectors with real scalar eltype + @test (wv = Adjoint(copy(intvec)); + wv === setindex!(wv, 3, 2) && + wv == setindex!(copy(tintvec), 3, 1, 2) ) + @test (wv = Transpose(copy(intvec)); + wv === setindex!(wv, 4, 2) && + wv == setindex!(copy(tintvec), 4, 1, 2) ) + # for matrices with real scalar eltype + @test (wA = Adjoint(copy(intmat)); + wA === setindex!(wA, 7, 3, 1) && + wA == setindex!(copy(tintmat), 7, 3, 1) ) + @test (wA = Transpose(copy(intmat)); + wA === setindex!(wA, 7, 3, 1) && + wA == setindex!(copy(tintmat), 7, 3, 1) ) + # for vectors with complex scalar eltype + @test (wz = Adjoint(copy(complexintvec)); + wz === setindex!(wz, 3im, 2) && + wz == setindex!(copy(acomplexintvec), 3im, 1, 2) ) + @test (wz = Transpose(copy(complexintvec)); + wz === setindex!(wz, 4im, 2) && + wz == setindex!(copy(tcomplexintvec), 4im, 1, 2) ) + # for matrices with complex scalar eltype + @test (wZ = Adjoint(copy(complexintmat)); + wZ === setindex!(wZ, 7im, 3, 1) && + wZ == setindex!(copy(acomplexintmat), 7im, 3, 1) ) + @test (wZ = Transpose(copy(complexintmat)); + wZ === setindex!(wZ, 7im, 3, 1) && + wZ == setindex!(copy(tcomplexintmat), 7im, 3, 1) ) + # for vectors with concrete real-vector eltype + @test (wv = Adjoint(copy(intvecvec)); + wv === setindex!(wv, Adjoint([5, 6]), 2) && + wv == setindex!(copy(tintvecvec), [5 6], 2)) + @test (wv = Transpose(copy(intvecvec)); + wv === setindex!(wv, Transpose([5, 6]), 2) && + wv == setindex!(copy(tintvecvec), [5 6], 2)) + # for matrices with concrete real-matrix eltype + @test (wA = Adjoint(copy(intmatmat)); + wA === setindex!(wA, Adjoint([13 14]), 3, 1) && + wA == setindex!(copy(tintmatmat), hcat([13, 14]), 3, 1)) + @test (wA = Transpose(copy(intmatmat)); + wA === setindex!(wA, Transpose([13 14]), 3, 1) && + wA == setindex!(copy(tintmatmat), hcat([13, 14]), 3, 1)) + # for vectors with concrete complex-vector eltype + @test (wz = Adjoint(copy(complexintvecvec)); + wz === setindex!(wz, Adjoint([5im, 6im]), 2) && + wz == setindex!(copy(acomplexintvecvec), [-5im -6im], 2)) + @test (wz = Transpose(copy(complexintvecvec)); + wz === setindex!(wz, Transpose([5im, 6im]), 2) && + wz == setindex!(copy(tcomplexintvecvec), [5im 6im], 2)) + # for matrices with concrete complex-matrix eltype + @test (wZ = Adjoint(copy(complexintmatmat)); + wZ === setindex!(wZ, Adjoint([13im 14im]), 3, 1) && + wZ == setindex!(copy(acomplexintmatmat), hcat([-13im, -14im]), 3, 1)) + @test (wZ = Transpose(copy(complexintmatmat)); + wZ === setindex!(wZ, Transpose([13im 14im]), 3, 1) && + wZ == setindex!(copy(tcomplexintmatmat), hcat([13im, 14im]), 3, 1)) + end +end + +@testset "Adjoint and Transpose convert methods that convert underlying storage" begin + intvec, intmat = [1, 2], [1 2 3; 4 5 6] + @test convert(Adjoint{Float64,Vector{Float64}}, Adjoint(intvec))::Adjoint{Float64,Vector{Float64}} == Adjoint(intvec) + @test convert(Adjoint{Float64,Matrix{Float64}}, Adjoint(intmat))::Adjoint{Float64,Matrix{Float64}} == Adjoint(intmat) + @test convert(Transpose{Float64,Vector{Float64}}, Transpose(intvec))::Transpose{Float64,Vector{Float64}} == Transpose(intvec) + @test convert(Transpose{Float64,Matrix{Float64}}, Transpose(intmat))::Transpose{Float64,Matrix{Float64}} == Transpose(intmat) +end + +@testset "Adjoint and Transpose similar methods" begin + intvec, intmat = [1, 2], [1 2 3; 4 5 6] + # similar with no additional specifications, vector (rewrapping) semantics + @test size(similar(Adjoint(intvec))::Adjoint{Int,Vector{Int}}) == size(Adjoint(intvec)) + @test size(similar(Transpose(intvec))::Transpose{Int,Vector{Int}}) == size(Transpose(intvec)) + # similar with no additional specifications, matrix (no-rewrapping) semantics + @test size(similar(Adjoint(intmat))::Matrix{Int}) == size(Adjoint(intmat)) + @test size(similar(Transpose(intmat))::Matrix{Int}) == size(Transpose(intmat)) + # similar with element type specification, vector (rewrapping) semantics + @test size(similar(Adjoint(intvec), Float64)::Adjoint{Float64,Vector{Float64}}) == size(Adjoint(intvec)) + @test size(similar(Transpose(intvec), Float64)::Transpose{Float64,Vector{Float64}}) == size(Transpose(intvec)) + # similar with element type specification, matrix (no-rewrapping) semantics + @test size(similar(Adjoint(intmat), Float64)::Matrix{Float64}) == size(Adjoint(intmat)) + @test size(similar(Transpose(intmat), Float64)::Matrix{Float64}) == size(Transpose(intmat)) + # similar with element type and arbitrary dims specifications + shape = (2, 2, 2) + @test size(similar(Adjoint(intvec), Float64, shape)::Array{Float64,3}) == shape + @test size(similar(Adjoint(intmat), Float64, shape)::Array{Float64,3}) == shape + @test size(similar(Transpose(intvec), Float64, shape)::Array{Float64,3}) == shape + @test size(similar(Transpose(intmat), Float64, shape)::Array{Float64,3}) == shape +end + +@testset "Adjoint and Transpose parent methods" begin + intvec, intmat = [1, 2], [1 2 3; 4 5 6] + @test parent(Adjoint(intvec)) === intvec + @test parent(Adjoint(intmat)) === intmat + @test parent(Transpose(intvec)) === intvec + @test parent(Transpose(intmat)) === intmat +end + +@testset "Adjoint and Transpose vector vec methods" begin + intvec = [1, 2] + @test vec(Adjoint(intvec)) === intvec + @test vec(Transpose(intvec)) === intvec +end diff --git a/test/linalg/bidiag.jl b/test/linalg/bidiag.jl index 0cf9c5bc346b3..3ab9d9e58634c 100644 --- a/test/linalg/bidiag.jl +++ b/test/linalg/bidiag.jl @@ -1,6 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Test +using Base.LinAlg: mul!, Adjoint, Transpose import Base.LinAlg: BlasReal, BlasFloat n = 10 #Size of test matrix @@ -182,8 +183,8 @@ srand(1) @test_throws DimensionMismatch T \ RowVector(ones(elty,n+1)) @test_throws DimensionMismatch T.' \ RowVector(ones(elty,n+1)) @test_throws DimensionMismatch T' \ RowVector(ones(elty,n+1)) - @test_throws DimensionMismatch Base.LinAlg.At_ldiv_B(T, RowVector(ones(elty,n+1))) - @test_throws DimensionMismatch Base.LinAlg.Ac_ldiv_B(T, RowVector(ones(elty,n+1))) + @test_throws DimensionMismatch Transpose(T) \ RowVector(ones(elty,n+1)) + @test_throws DimensionMismatch Adjoint(T) \ RowVector(ones(elty,n+1)) let bb = b, cc = c for atype in ("Array", "SubArray") if atype == "Array" @@ -275,10 +276,10 @@ srand(1) @test Array(op(T, T2)) ≈ op(Tfull, Tfull2) end end - # test pass-through of A_mul_B! for SymTridiagonal*Bidiagonal + # test pass-through of mul! for SymTridiagonal*Bidiagonal TriSym = SymTridiagonal(T.dv, T.ev) @test Array(TriSym*T) ≈ Array(TriSym)*Array(T) - # test pass-through of A_mul_B! for AbstractTriangular*Bidiagonal + # test pass-through of mul! for AbstractTriangular*Bidiagonal Tri = UpperTriangular(diagm(1 => T.ev)) @test Array(Tri*T) ≈ Array(Tri)*Array(T) end diff --git a/test/linalg/diagonal.jl b/test/linalg/diagonal.jl index d601f8a27c570..289f5f1228c33 100644 --- a/test/linalg/diagonal.jl +++ b/test/linalg/diagonal.jl @@ -1,8 +1,8 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Test -import Base.LinAlg: BlasFloat, BlasComplex, SingularException, A_rdiv_B!, A_rdiv_Bt!, - A_rdiv_Bc! +using Base.LinAlg: mul!, ldiv!, rdiv!, Adjoint, Transpose +import Base.LinAlg: BlasFloat, BlasComplex, SingularException n=12 #Size of matrix problem to test srand(1) @@ -97,37 +97,37 @@ srand(1) atol_three = 2n^3 * eps(relty) * (1 + (elty <: Complex)) @test D\v ≈ DM\v atol=atol_two @test D\U ≈ DM\U atol=atol_three - @test A_ldiv_B!(D, copy(v)) ≈ DM\v atol=atol_two - @test At_ldiv_B!(D, copy(v)) ≈ DM\v atol=atol_two - @test Ac_ldiv_B!(conj(D), copy(v)) ≈ DM\v atol=atol_two - @test A_ldiv_B!(D, copy(U)) ≈ DM\U atol=atol_three - @test At_ldiv_B!(D, copy(U)) ≈ DM\U atol=atol_three - @test Ac_ldiv_B!(conj(D), copy(U)) ≈ DM\U atol=atol_three + @test ldiv!(D, copy(v)) ≈ DM\v atol=atol_two + @test ldiv!(Transpose(D), copy(v)) ≈ DM\v atol=atol_two + @test ldiv!(Adjoint(conj(D)), copy(v)) ≈ DM\v atol=atol_two + @test ldiv!(D, copy(U)) ≈ DM\U atol=atol_three + @test ldiv!(Transpose(D), copy(U)) ≈ DM\U atol=atol_three + @test ldiv!(Adjoint(conj(D)), copy(U)) ≈ DM\U atol=atol_three Uc = adjoint(U) target = scale!(Uc, inv.(D.diag)) - @test A_rdiv_B!(Uc, D) ≈ target atol=atol_three - @test_throws DimensionMismatch A_rdiv_B!(Matrix{elty}(I, n-1, n-1), D) - @test_throws SingularException A_rdiv_B!(Uc, Diagonal(fill!(similar(D.diag), 0))) - @test A_rdiv_Bt!(Uc, D) ≈ target atol=atol_three - @test A_rdiv_Bc!(Uc, conj(D)) ≈ target atol=atol_three - @test A_ldiv_B!(D, Matrix{eltype(D)}(I, size(D))) ≈ D \ Matrix{eltype(D)}(I, size(D)) atol=atol_three - @test_throws DimensionMismatch A_ldiv_B!(D, ones(elty, n + 1)) - @test_throws SingularException A_ldiv_B!(Diagonal(zeros(relty, n)), copy(v)) + @test rdiv!(Uc, D) ≈ target atol=atol_three + @test_throws DimensionMismatch rdiv!(Matrix{elty}(I, n-1, n-1), D) + @test_throws SingularException rdiv!(Uc, Diagonal(fill!(similar(D.diag), 0))) + @test rdiv!(Uc, Transpose(D)) ≈ target atol=atol_three + @test rdiv!(Uc, Adjoint(conj(D))) ≈ target atol=atol_three + @test ldiv!(D, Matrix{eltype(D)}(I, size(D))) ≈ D \ Matrix{eltype(D)}(I, size(D)) atol=atol_three + @test_throws DimensionMismatch ldiv!(D, ones(elty, n + 1)) + @test_throws SingularException ldiv!(Diagonal(zeros(relty, n)), copy(v)) b = rand(elty, n, n) b = sparse(b) - @test A_ldiv_B!(D, copy(b)) ≈ Array(D)\Array(b) - @test_throws SingularException A_ldiv_B!(Diagonal(zeros(elty, n)), copy(b)) + @test ldiv!(D, copy(b)) ≈ Array(D)\Array(b) + @test_throws SingularException ldiv!(Diagonal(zeros(elty, n)), copy(b)) b = view(rand(elty, n), collect(1:n)) b2 = copy(b) - c = A_ldiv_B!(D, b) + c = ldiv!(D, b) d = Array(D)\b2 @test c ≈ d - @test_throws SingularException A_ldiv_B!(Diagonal(zeros(elty, n)), b) + @test_throws SingularException ldiv!(Diagonal(zeros(elty, n)), b) b = rand(elty, n+1, n+1) b = sparse(b) - @test_throws DimensionMismatch A_ldiv_B!(D, copy(b)) + @test_throws DimensionMismatch ldiv!(D, copy(b)) b = view(rand(elty, n+1), collect(1:n+1)) - @test_throws DimensionMismatch A_ldiv_B!(D, b) + @test_throws DimensionMismatch ldiv!(D, b) end end end @@ -146,9 +146,9 @@ srand(1) if relty <: BlasFloat b = rand(elty,n,n) b = sparse(b) - @test A_mul_B!(copy(D), copy(b)) ≈ Array(D)*Array(b) - @test At_mul_B!(copy(D), copy(b)) ≈ Array(D).'*Array(b) - @test Ac_mul_B!(copy(D), copy(b)) ≈ Array(D)'*Array(b) + @test mul!(copy(D), copy(b)) ≈ Array(D)*Array(b) + @test mul!(Transpose(copy(D)), copy(b)) ≈ Array(D).'*Array(b) + @test mul!(Adjoint(copy(D)), copy(b)) ≈ Array(D)'*Array(b) end end @@ -164,26 +164,26 @@ srand(1) # Performance specialisations for A*_mul_B! vvv = similar(vv) - @test (r = Matrix(D) * vv ; A_mul_B!(vvv, D, vv) ≈ r ≈ vvv) - @test (r = Matrix(D)' * vv ; Ac_mul_B!(vvv, D, vv) ≈ r ≈ vvv) - @test (r = Matrix(D).' * vv ; At_mul_B!(vvv, D, vv) ≈ r ≈ vvv) + @test (r = Matrix(D) * vv ; mul!(vvv, D, vv) ≈ r ≈ vvv) + @test (r = Matrix(D)' * vv ; mul!(vvv, Adjoint(D), vv) ≈ r ≈ vvv) + @test (r = Matrix(D).' * vv ; mul!(vvv, Transpose(D), vv) ≈ r ≈ vvv) UUU = similar(UU) - @test (r = Matrix(D) * UU ; A_mul_B!(UUU, D, UU) ≈ r ≈ UUU) - @test (r = Matrix(D)' * UU ; Ac_mul_B!(UUU, D, UU) ≈ r ≈ UUU) - @test (r = Matrix(D).' * UU ; At_mul_B!(UUU, D, UU) ≈ r ≈ UUU) + @test (r = Matrix(D) * UU ; mul!(UUU, D, UU) ≈ r ≈ UUU) + @test (r = Matrix(D)' * UU ; mul!(UUU, Adjoint(D), UU) ≈ r ≈ UUU) + @test (r = Matrix(D).' * UU ; mul!(UUU, Transpose(D), UU) ≈ r ≈ UUU) - # make sure that A_mul_B{c,t}! works with B as a Diagonal + # make sure that mul!(A, {Adj|Trans}(B)) works with B as a Diagonal VV = Array(D) DD = copy(D) r = VV * Matrix(D) - @test Array(A_mul_B!(VV, DD)) ≈ r ≈ Array(D)*Array(D) + @test Array(mul!(VV, DD)) ≈ r ≈ Array(D)*Array(D) DD = copy(D) r = VV * (Array(D).') - @test Array(A_mul_Bt!(VV, DD)) ≈ r + @test Array(mul!(VV, Transpose(DD))) ≈ r DD = copy(D) r = VV * (Array(D)') - @test Array(A_mul_Bc!(VV, DD)) ≈ r + @test Array(mul!(VV, Adjoint(DD))) ≈ r end @testset "triu/tril" begin @test istriu(D) @@ -347,9 +347,9 @@ end end let D1 = Diagonal(rand(5)), D2 = Diagonal(rand(5)) - @test_throws MethodError A_mul_B!(D1,D2) - @test_throws MethodError At_mul_B!(D1,D2) - @test_throws MethodError Ac_mul_B!(D1,D2) + @test_throws MethodError mul!(D1,D2) + @test_throws MethodError mul!(Transpose(D1),D2) + @test_throws MethodError mul!(Adjoint(D1),D2) end @testset "multiplication of QR Q-factor and Diagonal (#16615 spot test)" begin @@ -357,7 +357,7 @@ end Q = qrfact(randn(5, 5))[:Q] @test D * Q' == Array(D) * Q' Q = qrfact(randn(5, 5), Val(true))[:Q] - @test_throws MethodError A_mul_B!(Q, D) + @test_throws MethodError mul!(Q, D) end @testset "block diagonal matrices" begin @@ -394,11 +394,13 @@ end A = randn(T, n, n); A = A'A S = Symmetric(A) H = Hermitian(A) - for f in (*, Ac_mul_B, A_mul_Bc, Ac_mul_Bc, At_mul_B, A_mul_Bt, At_mul_Bt) - @test f(D, S) ≈ f(Matrix(D), Matrix(S)) - @test f(D, H) ≈ f(Matrix(D), Matrix(H)) - @test f(S, D) ≈ f(Matrix(S), Matrix(D)) - @test f(S, H) ≈ f(Matrix(S), Matrix(H)) + for (transform1, transform2) in ((identity, identity), + (identity, Adjoint ), (Adjoint, identity ), (Adjoint, Adjoint ), + (identity, Transpose), (Transpose, identity ), (Transpose, Transpose) ) + @test *(transform1(D), transform2(S)) ≈ *(transform1(Matrix(D)), transform2(Matrix(S))) + @test *(transform1(D), transform2(H)) ≈ *(transform1(Matrix(D)), transform2(Matrix(H))) + @test *(transform1(S), transform2(D)) ≈ *(transform1(Matrix(S)), transform2(Matrix(D))) + @test *(transform1(S), transform2(H)) ≈ *(transform1(Matrix(S)), transform2(Matrix(H))) end end end @@ -411,9 +413,11 @@ end BB = Diagonal([randn(T, 2, 2), rand(T, 2, 2)]) fullDD = copy!(Matrix{Matrix{T}}(uninitialized, 2, 2), DD) fullBB = copy!(Matrix{Matrix{T}}(uninitialized, 2, 2), BB) - for f in (*, Ac_mul_B, A_mul_Bc, Ac_mul_Bc, At_mul_B, A_mul_Bt, At_mul_Bt) - @test f(D, B)::typeof(D) ≈ f(Matrix(D), Matrix(B)) atol=2 * eps() - @test f(DD, BB)::typeof(DD) == f(fullDD, fullBB) + for (transform1, transform2) in ((identity, identity), + (identity, Adjoint ), (Adjoint, identity ), (Adjoint, Adjoint ), + (identity, Transpose), (Transpose, identity ), (Transpose, Transpose) ) + @test *(transform1(D), transform2(B))::typeof(D) ≈ *(transform1(Matrix(D)), transform2(Matrix(B))) atol=2 * eps() + @test *(transform1(DD), transform2(BB))::typeof(DD) == *(transform1(fullDD), transform2(fullBB)) end end end diff --git a/test/linalg/generic.jl b/test/linalg/generic.jl index b6a670d1a116f..a53168789395e 100644 --- a/test/linalg/generic.jl +++ b/test/linalg/generic.jl @@ -361,7 +361,10 @@ Base.zero(::Type{ModInt{n}}) where {n} = ModInt{n}(0) Base.zero(::ModInt{n}) where {n} = ModInt{n}(0) Base.one(::Type{ModInt{n}}) where {n} = ModInt{n}(1) Base.one(::ModInt{n}) where {n} = ModInt{n}(1) +Base.adjoint(a::ModInt{n}) where {n} = ModInt{n}(conj(a)) Base.transpose(a::ModInt{n}) where {n} = a # see Issue 20978 +Base.LinAlg.Adjoint(a::ModInt{n}) where {n} = adjoint(a) +Base.LinAlg.Transpose(a::ModInt{n}) where {n} = transpose(a) @testset "Issue 22042" begin A = [ModInt{2}(1) ModInt{2}(0); ModInt{2}(1) ModInt{2}(1)] diff --git a/test/linalg/givens.jl b/test/linalg/givens.jl index f587d9ed265af..355eab97c69ef 100644 --- a/test/linalg/givens.jl +++ b/test/linalg/givens.jl @@ -1,6 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Test +using Base.LinAlg: mul!, Adjoint, Transpose # Test givens rotations @testset for elty in (Float32, Float64, Complex64, Complex128) @@ -15,11 +16,11 @@ using Test for j = 1:8 for i = j+2:10 G, _ = givens(A, j+1, i, j) - A_mul_B!(G, A) - A_mul_Bc!(A, G) - A_mul_B!(G, R) + mul!(G, A) + mul!(A, Adjoint(G)) + mul!(G, R) - @test A_mul_B!(G,Matrix{elty}(I, 10, 10)) == [G[i,j] for i=1:10,j=1:10] + @test mul!(G,Matrix{elty}(I, 10, 10)) == [G[i,j] for i=1:10,j=1:10] @testset "transposes" begin @test adjoint(G)*G*Matrix(elty(1)I, 10, 10) ≈ Matrix(I, 10, 10) @@ -32,8 +33,8 @@ using Test @test_throws ArgumentError givens(A, 3, 3, 2) @test_throws ArgumentError givens(one(elty),zero(elty),2,2) G, _ = givens(one(elty),zero(elty),11,12) - @test_throws DimensionMismatch A_mul_B!(G, A) - @test_throws DimensionMismatch A_mul_Bc!(A,G) + @test_throws DimensionMismatch mul!(G, A) + @test_throws DimensionMismatch mul!(A, Adjoint(G)) @test abs.(A) ≈ abs.(hessfact(Ac)[:H]) @test norm(R*Matrix{elty}(I, 10, 10)) ≈ one(elty) diff --git a/test/linalg/lq.jl b/test/linalg/lq.jl index 9c1ccac0a28eb..37211bab29a51 100644 --- a/test/linalg/lq.jl +++ b/test/linalg/lq.jl @@ -2,7 +2,7 @@ using Test -using Base.LinAlg: BlasComplex, BlasFloat, BlasReal +using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, mul!, Adjoint, Transpose n = 10 @@ -21,7 +21,7 @@ breal = randn(n,2)/2 bimg = randn(n,2)/2 # helper functions to unambiguously recover explicit forms of an LQPackedQ -squareQ(Q::LinAlg.LQPackedQ) = (n = size(Q.factors, 2); A_mul_B!(Q, Matrix{eltype(Q)}(I, n, n))) +squareQ(Q::LinAlg.LQPackedQ) = (n = size(Q.factors, 2); mul!(Q, Matrix{eltype(Q)}(I, n, n))) rectangularQ(Q::LinAlg.LQPackedQ) = convert(Array, Q) @testset for eltya in (Float32, Float64, Complex64, Complex128) @@ -68,7 +68,7 @@ rectangularQ(Q::LinAlg.LQPackedQ) = convert(Array, Q) @testset "Binary ops" begin @test a*(lqa\b) ≈ b atol=3000ε @test lqa*b ≈ qra[:Q]*qra[:R]*b atol=3000ε - @test (sq = size(q.factors, 2); A_mul_Bc(Matrix{eltyb}(I, sq, sq), q)*squareQ(q)) ≈ Matrix(I, n, n) atol=5000ε + @test (sq = size(q.factors, 2); *(Matrix{eltyb}(I, sq, sq), Adjoint(q))*squareQ(q)) ≈ Matrix(I, n, n) atol=5000ε if eltya != Int @test Matrix{eltyb}(I, n, n)*q ≈ convert(AbstractMatrix{tab},q) end @@ -81,7 +81,7 @@ rectangularQ(Q::LinAlg.LQPackedQ) = convert(Array, Q) @test a'*q ≈ a'*squareQ(q) atol=100ε @test a'*q' ≈ a'*squareQ(q)' atol=100ε @test_throws DimensionMismatch q*b[1:n1 + 1] - @test_throws DimensionMismatch Ac_mul_B(q,ones(eltya,n+2,n+2)) + @test_throws DimensionMismatch Adjoint(q) * ones(eltya,n+2,n+2) @test_throws DimensionMismatch ones(eltyb,n+2,n+2)*q if isa(a, DenseArray) && isa(b, DenseArray) # use this to test 2nd branch in mult code @@ -100,9 +100,9 @@ rectangularQ(Q::LinAlg.LQPackedQ) = convert(Array, Q) l,q = lqa[:L], lqa[:Q] @test rectangularQ(q)*rectangularQ(q)' ≈ Matrix(I, n1, n1) @test squareQ(q)'*squareQ(q) ≈ Matrix(I, n1, n1) - @test_throws DimensionMismatch A_mul_B!(Matrix{eltya}(I, n+1, n+1),q) - @test Ac_mul_B!(q, rectangularQ(q)) ≈ Matrix(I, n1, n1) - @test_throws DimensionMismatch A_mul_Bc!(Matrix{eltya}(I, n+1, n+1),q) + @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n+1),q) + @test mul!(Adjoint(q), rectangularQ(q)) ≈ Matrix(I, n1, n1) + @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n+1), Adjoint(q)) @test_throws BoundsError size(q,-1) end end @@ -150,7 +150,7 @@ end function getqs(F::Base.LinAlg.LQ) implicitQ = F[:Q] sq = size(implicitQ.factors, 2) - explicitQ = A_mul_B!(implicitQ, Matrix{eltype(implicitQ)}(I, sq, sq)) + explicitQ = mul!(implicitQ, Matrix{eltype(implicitQ)}(I, sq, sq)) return implicitQ, explicitQ end @@ -191,7 +191,7 @@ end @testset "postmultiplication with / right-application of LQPackedQ (#23779)" begin function getqs(F::Base.LinAlg.LQ) implicitQ = F[:Q] - explicitQ = A_mul_B!(implicitQ, Matrix{eltype(implicitQ)}(I, size(implicitQ)...)) + explicitQ = mul!(implicitQ, Matrix{eltype(implicitQ)}(I, size(implicitQ)...)) return implicitQ, explicitQ end # for any shape m-by-n of LQ-factored matrix, where Q is an LQPackedQ @@ -201,9 +201,9 @@ end implicitQ, explicitQ = getqs(lqfact(randn(mA, nA))) C = randn(nA, nA) @test *(C, implicitQ) ≈ *(C, explicitQ) - @test A_mul_Bc(C, implicitQ) ≈ A_mul_Bc(C, explicitQ) - @test Ac_mul_B(C, implicitQ) ≈ Ac_mul_B(C, explicitQ) - @test Ac_mul_Bc(C, implicitQ) ≈ Ac_mul_Bc(C, explicitQ) + @test *(C, Adjoint(implicitQ)) ≈ *(C, Adjoint(explicitQ)) + @test *(Adjoint(C), implicitQ) ≈ *(Adjoint(C), explicitQ) + @test *(Adjoint(C), Adjoint(implicitQ)) ≈ *(Adjoint(C), Adjoint(explicitQ)) end # where the LQ-factored matrix has at least as many rows m as columns n, # Q's full/square and reduced/rectangular forms have the same shape (n-by-n). hence we expect @@ -220,7 +220,7 @@ end zeroextCright = hcat(C, zeros(eltype(C), mA)) zeroextCdown = vcat(C, zeros(eltype(C), (1, mA))) @test *(C, implicitQ) ≈ *(zeroextCright, explicitQ) - @test Ac_mul_B(C, implicitQ) ≈ Ac_mul_B(zeroextCdown, explicitQ) - @test_throws DimensionMismatch A_mul_Bc(C, implicitQ) - @test_throws DimensionMismatch Ac_mul_Bc(C, implicitQ) + @test *(Adjoint(C), implicitQ) ≈ *(Adjoint(zeroextCdown), explicitQ) + @test_throws DimensionMismatch C * Adjoint(implicitQ) + @test_throws DimensionMismatch Adjoint(C) * Adjoint(implicitQ) end diff --git a/test/linalg/lu.jl b/test/linalg/lu.jl index a22ed82002256..e396fff01d95e 100644 --- a/test/linalg/lu.jl +++ b/test/linalg/lu.jl @@ -1,6 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Test +using Base.LinAlg: ldiv!, Adjoint, Transpose import Base.LinAlg.BlasInt, Base.LinAlg.BlasFloat n = 10 @@ -119,18 +120,18 @@ dimg = randn(n)/2 b_dest = similar(b, resultT) c_dest = similar(c, resultT) - A_ldiv_B!(b_dest, lua, b) - A_ldiv_B!(c_dest, lua, c) + ldiv!(b_dest, lua, b) + ldiv!(c_dest, lua, c) @test norm(b_dest - lua \ b, 1) < ε*κ*2n @test norm(c_dest - lua \ c, 1) < ε*κ*n - At_ldiv_B!(b_dest, lua, b) - At_ldiv_B!(c_dest, lua, c) + ldiv!(b_dest, Transpose(lua), b) + ldiv!(c_dest, Transpose(lua), c) @test norm(b_dest - lua.' \ b, 1) < ε*κ*2n @test norm(c_dest - lua.' \ c, 1) < ε*κ*n - Ac_ldiv_B!(b_dest, lua, b) - Ac_ldiv_B!(c_dest, lua, c) + ldiv!(b_dest, Adjoint(lua), b) + ldiv!(c_dest, Adjoint(lua), c) @test norm(b_dest - lua' \ b, 1) < ε*κ*2n @test norm(c_dest - lua' \ c, 1) < ε*κ*n end @@ -145,14 +146,14 @@ dimg = randn(n)/2 @test_throws DimensionMismatch lud\f @test_throws DimensionMismatch lud.'\f @test_throws DimensionMismatch lud'\f - @test_throws DimensionMismatch Base.LinAlg.At_ldiv_B!(lud, f) + @test_throws DimensionMismatch Base.LinAlg.ldiv!(Transpose(lud), f) let Bs = copy(b) for bb in (Bs, view(Bs, 1:n, 1)) @test norm(d*(lud\bb) - bb, 1) < ε*κd*n*2 # Two because the right hand side has two columns if eltya <: Real @test norm((lud.'\bb) - Array(d.')\bb, 1) < ε*κd*n*2 # Two because the right hand side has two columns if eltya != Int && eltyb != Int - @test norm(Base.LinAlg.At_ldiv_B!(lud, copy(bb)) - Array(d.')\bb, 1) < ε*κd*n*2 + @test norm(Base.LinAlg.ldiv!(Transpose(lud), copy(bb)) - Array(d.')\bb, 1) < ε*κd*n*2 end end if eltya <: Complex diff --git a/test/linalg/matmul.jl b/test/linalg/matmul.jl index fdb6b94e8963b..429d05810401b 100644 --- a/test/linalg/matmul.jl +++ b/test/linalg/matmul.jl @@ -2,6 +2,8 @@ using Test +using Base.LinAlg: mul!, Adjoint, Transpose + ## Test Julia fallbacks to BLAS routines @testset "matrices with zero dimensions" begin @@ -24,19 +26,19 @@ end BBi = BB+(2.5*im).*AA[[2,1],[2,1]] for A in (copy(AA), view(AA, 1:2, 1:2)), B in (copy(BB), view(BB, 1:2, 1:2)) @test A*B == [19 22; 43 50] - @test At_mul_B(A, B) == [26 30; 38 44] - @test A_mul_Bt(A, B) == [17 23; 39 53] - @test At_mul_Bt(A, B) == [23 31; 34 46] + @test *(Transpose(A), B) == [26 30; 38 44] + @test *(A, Transpose(B)) == [17 23; 39 53] + @test *(Transpose(A), Transpose(B)) == [23 31; 34 46] end for Ai in (copy(AAi), view(AAi, 1:2, 1:2)), Bi in (copy(BBi), view(BBi, 1:2, 1:2)) @test Ai*Bi == [-21+53.5im -4.25+51.5im; -12+95.5im 13.75+85.5im] - @test Ac_mul_B(Ai, Bi) == [68.5-12im 57.5-28im; 88-3im 76.5-25im] - @test A_mul_Bc(Ai, Bi) == [64.5+5.5im 43+31.5im; 104-18.5im 80.5+31.5im] - @test Ac_mul_Bc(Ai, Bi) == [-28.25-66im 9.75-58im; -26-89im 21-73im] + @test *(Adjoint(Ai), Bi) == [68.5-12im 57.5-28im; 88-3im 76.5-25im] + @test *(Ai, Adjoint(Bi)) == [64.5+5.5im 43+31.5im; 104-18.5im 80.5+31.5im] + @test *(Adjoint(Ai), Adjoint(Bi)) == [-28.25-66im 9.75-58im; -26-89im 21-73im] @test_throws DimensionMismatch [1 2; 0 0; 0 0] * [1 2] end CC = ones(3, 3) - @test_throws DimensionMismatch A_mul_B!(CC, AA, BB) + @test_throws DimensionMismatch mul!(CC, AA, BB) end @testset "3x3 matmul" begin AA = [1 2 3; 4 5 6; 7 8 9].-5 @@ -45,19 +47,19 @@ end BBi = BB+(2.5*im).*AA[[2,1,3],[2,3,1]] for A in (copy(AA), view(AA, 1:3, 1:3)), B in (copy(BB), view(BB, 1:3, 1:3)) @test A*B == [-26 38 -27; 1 -4 -6; 28 -46 15] - @test Ac_mul_B(A, B) == [-6 2 -25; 3 -12 -18; 12 -26 -11] - @test A_mul_Bc(A, B) == [-14 0 6; 4 -3 -3; 22 -6 -12] - @test Ac_mul_Bc(A, B) == [6 -8 -6; 12 -9 -9; 18 -10 -12] + @test *(Adjoint(A), B) == [-6 2 -25; 3 -12 -18; 12 -26 -11] + @test *(A, Adjoint(B)) == [-14 0 6; 4 -3 -3; 22 -6 -12] + @test *(Adjoint(A), Adjoint(B)) == [6 -8 -6; 12 -9 -9; 18 -10 -12] end for Ai in (copy(AAi), view(AAi, 1:3, 1:3)), Bi in (copy(BBi), view(BBi, 1:3, 1:3)) @test Ai*Bi == [-44.75+13im 11.75-25im -38.25+30im; -47.75-16.5im -51.5+51.5im -56+6im; 16.75-4.5im -53.5+52im -15.5im] - @test Ac_mul_B(Ai, Bi) == [-21+2im -1.75+49im -51.25+19.5im; 25.5+56.5im -7-35.5im 22+35.5im; -3+12im -32.25+43im -34.75-2.5im] - @test A_mul_Bc(Ai, Bi) == [-20.25+15.5im -28.75-54.5im 22.25+68.5im; -12.25+13im -15.5+75im -23+27im; 18.25+im 1.5+94.5im -27-54.5im] - @test Ac_mul_Bc(Ai, Bi) == [1+2im 20.75+9im -44.75+42im; 19.5+17.5im -54-36.5im 51-14.5im; 13+7.5im 11.25+31.5im -43.25-14.5im] + @test *(Adjoint(Ai), Bi) == [-21+2im -1.75+49im -51.25+19.5im; 25.5+56.5im -7-35.5im 22+35.5im; -3+12im -32.25+43im -34.75-2.5im] + @test *(Ai, Adjoint(Bi)) == [-20.25+15.5im -28.75-54.5im 22.25+68.5im; -12.25+13im -15.5+75im -23+27im; 18.25+im 1.5+94.5im -27-54.5im] + @test *(Adjoint(Ai), Adjoint(Bi)) == [1+2im 20.75+9im -44.75+42im; 19.5+17.5im -54-36.5im 51-14.5im; 13+7.5im 11.25+31.5im -43.25-14.5im] @test_throws DimensionMismatch [1 2 3; 0 0 0; 0 0 0] * [1 2 3] end CC = ones(4, 4) - @test_throws DimensionMismatch A_mul_B!(CC, AA, BB) + @test_throws DimensionMismatch mul!(CC, AA, BB) end # Generic AbstractArrays @@ -80,7 +82,7 @@ end BB = [2 -2; 3 -5; -4 7] for A in (copy(AA), view(AA, 1:2, 1:3)), B in (copy(BB), view(BB, 1:3, 1:2)) @test A*B == [-7 9; -4 9] - @test At_mul_Bt(A, B) == [-6 -11 15; -6 -13 18; -6 -15 21] + @test *(Transpose(A), Transpose(B)) == [-6 -11 15; -6 -13 18; -6 -15 21] end AA = ones(Int, 2, 100) BB = ones(Int, 100, 3) @@ -91,23 +93,23 @@ end BB = rand(1:20, 5, 5) .- 10 CC = Matrix{Int}(uninitialized, size(AA, 1), size(BB, 2)) for A in (copy(AA), view(AA, 1:5, 1:5)), B in (copy(BB), view(BB, 1:5, 1:5)), C in (copy(CC), view(CC, 1:5, 1:5)) - @test At_mul_B(A, B) == A'*B - @test A_mul_Bt(A, B) == A*B' + @test *(Transpose(A), B) == A'*B + @test *(A, Transpose(B)) == A*B' # Preallocated - @test A_mul_B!(C, A, B) == A*B - @test At_mul_B!(C, A, B) == A'*B - @test A_mul_Bt!(C, A, B) == A*B' - @test At_mul_Bt!(C, A, B) == A'*B' - @test Base.LinAlg.Ac_mul_Bt!(C, A, B) == A'*B.' + @test mul!(C, A, B) == A*B + @test mul!(C, Transpose(A), B) == A'*B + @test mul!(C, A, Transpose(B)) == A*B' + @test mul!(C, Transpose(A), Transpose(B)) == A'*B' + @test Base.LinAlg.mul!(C, Adjoint(A), Transpose(B)) == A'*B.' #test DimensionMismatch for generic_matmatmul - @test_throws DimensionMismatch Base.LinAlg.Ac_mul_Bt!(C,A,ones(Int,4,4)) - @test_throws DimensionMismatch Base.LinAlg.Ac_mul_Bt!(C,ones(Int,4,4),B) + @test_throws DimensionMismatch Base.LinAlg.mul!(C, Adjoint(A), Transpose(ones(Int,4,4))) + @test_throws DimensionMismatch Base.LinAlg.mul!(C, Adjoint(ones(Int,4,4)), Transpose(B)) end vv = [1,2] CC = Matrix{Int}(uninitialized, 2, 2) for v in (copy(vv), view(vv, 1:2)), C in (copy(CC), view(CC, 1:2, 1:2)) - @test @inferred(A_mul_Bc!(C, v, v)) == [1 2; 2 4] + @test @inferred(mul!(C, v, Adjoint(v))) == [1 2; 2 4] end end @@ -121,12 +123,12 @@ end vv = [1,2,3] CC = Matrix{Int}(uninitialized, 3, 3) for v in (copy(vv), view(vv, 1:3)), C in (copy(CC), view(CC, 1:3, 1:3)) - @test A_mul_Bt!(C, v, v) == v*v' + @test mul!(C, v, Transpose(v)) == v*v' end vvf = map(Float64,vv) CC = Matrix{Float64}(uninitialized, 3, 3) for vf in (copy(vvf), view(vvf, 1:3)), C in (copy(CC), view(CC, 1:3, 1:3)) - @test A_mul_Bt!(C, vf, vf) == vf*vf' + @test mul!(C, vf, Transpose(vf)) == vf*vf' end end @@ -135,9 +137,9 @@ end BB = rand(Float64,6,6) CC = zeros(Float64,6,6) for A in (copy(AA), view(AA, 1:6, 1:6)), B in (copy(BB), view(BB, 1:6, 1:6)), C in (copy(CC), view(CC, 1:6, 1:6)) - @test Base.LinAlg.At_mul_Bt!(C,A,B) == A.'*B.' - @test Base.LinAlg.A_mul_Bc!(C,A,B) == A*B.' - @test Base.LinAlg.Ac_mul_B!(C,A,B) == A.'*B + @test Base.LinAlg.mul!(C, Transpose(A), Transpose(B)) == A.'*B.' + @test Base.LinAlg.mul!(C, A, Adjoint(B)) == A*B.' + @test Base.LinAlg.mul!(C, Adjoint(A), B) == A.'*B end end @@ -147,13 +149,13 @@ end Asub = view(A, 1:2:5, 1:2:4) b = [1.2,-2.5] @test (Aref*b) == (Asub*b) - @test At_mul_B(Asub, Asub) == At_mul_B(Aref, Aref) - @test A_mul_Bt(Asub, Asub) == A_mul_Bt(Aref, Aref) + @test *(Transpose(Asub), Asub) == *(Transpose(Aref), Aref) + @test *(Asub, Transpose(Asub)) == *(Aref, Transpose(Aref)) Ai = A .+ im Aref = Ai[1:2:end,1:2:end] Asub = view(Ai, 1:2:5, 1:2:4) - @test Ac_mul_B(Asub, Asub) == Ac_mul_B(Aref, Aref) - @test A_mul_Bc(Asub, Asub) == A_mul_Bc(Aref, Aref) + @test *(Adjoint(Asub), Asub) == *(Adjoint(Aref), Aref) + @test *(Asub, Adjoint(Asub)) == *(Aref, Adjoint(Aref)) end @testset "issue #15286" begin @@ -161,33 +163,33 @@ end C = zeros(8, 8) sC = view(C, 1:2:8, 1:2:8) B = reshape(map(Float64,-9:10),5,4) - @test At_mul_B!(sC, A, A) == A'*A - @test At_mul_B!(sC, A, B) == A'*B + @test mul!(sC, Transpose(A), A) == A'*A + @test mul!(sC, Transpose(A), B) == A'*B Aim = A .- im C = zeros(Complex128,8,8) sC = view(C, 1:2:8, 1:2:8) B = reshape(map(Float64,-9:10),5,4) .+ im - @test Ac_mul_B!(sC, Aim, Aim) == Aim'*Aim - @test Ac_mul_B!(sC, Aim, B) == Aim'*B + @test mul!(sC, Adjoint(Aim), Aim) == Aim'*Aim + @test mul!(sC, Adjoint(Aim), B) == Aim'*B end @testset "syrk & herk" begin AA = reshape(1:1503, 501, 3).-750.0 res = Float64[135228751 9979252 -115270247; 9979252 10481254 10983256; -115270247 10983256 137236759] for A in (copy(AA), view(AA, 1:501, 1:3)) - @test At_mul_B(A, A) == res - @test A_mul_Bt(A',A') == res + @test *(Transpose(A), A) == res + @test *(A', Transpose(A')) == res end cutoff = 501 A = reshape(1:6*cutoff,2*cutoff,3).-(6*cutoff)/2 Asub = view(A, 1:2:2*cutoff, 1:3) Aref = A[1:2:2*cutoff, 1:3] - @test At_mul_B(Asub, Asub) == At_mul_B(Aref, Aref) + @test *(Transpose(Asub), Asub) == *(Transpose(Aref), Aref) Ai = A .- im Asub = view(Ai, 1:2:2*cutoff, 1:3) Aref = Ai[1:2:2*cutoff, 1:3] - @test Ac_mul_B(Asub, Asub) == Ac_mul_B(Aref, Aref) + @test *(Adjoint(Asub), Asub) == *(Adjoint(Aref), Aref) @test_throws DimensionMismatch Base.LinAlg.syrk_wrapper!(zeros(5,5),'N',ones(6,5)) @test_throws DimensionMismatch Base.LinAlg.herk_wrapper!(zeros(5,5),'N',ones(6,5)) @@ -281,9 +283,9 @@ end aa = rand(3,3) bb = rand(3,3) for a in (copy(aa), view(aa, 1:3, 1:3)), b in (copy(bb), view(bb, 1:3, 1:3)) - @test_throws ArgumentError A_mul_B!(a, a, b) - @test_throws ArgumentError A_mul_B!(a, b, a) - @test_throws ArgumentError A_mul_B!(a, a, a) + @test_throws ArgumentError mul!(a, a, b) + @test_throws ArgumentError mul!(a, b, a) + @test_throws ArgumentError mul!(a, a, a) end end @@ -299,7 +301,7 @@ transpose(x::RootInt) = x @testset "#14293" begin a = [RootInt(3)] C = [0] - A_mul_Bt!(C, a, a) + mul!(C, a, Transpose(a)) @test C[1] == 9 a = [RootInt(2),RootInt(10)] @test a*a' == [4 20; 20 100] @@ -308,12 +310,12 @@ transpose(x::RootInt) = x end function test_mul(C, A, B) - A_mul_B!(C, A, B) + mul!(C, A, B) @test Array(A) * Array(B) ≈ C @test A*B ≈ C end -@testset "A_mul_B! vs A_mul_B for special types" begin +@testset "mul! vs * for special types" begin eltypes = [Float32, Float64, Int64] for k in [3, 4, 10] T = rand(eltypes) @@ -355,11 +357,11 @@ end full24 = randn(2, 4) full33 = randn(3, 3) full44 = randn(4, 4) - @test_throws DimensionMismatch A_mul_B!(full43, tri44, tri33) - @test_throws DimensionMismatch A_mul_B!(full44, tri44, tri33) - @test_throws DimensionMismatch A_mul_B!(full44, tri44, full43) - @test_throws DimensionMismatch A_mul_B!(full43, tri33, full43) - @test_throws DimensionMismatch A_mul_B!(full43, full43, tri44) + @test_throws DimensionMismatch mul!(full43, tri44, tri33) + @test_throws DimensionMismatch mul!(full44, tri44, tri33) + @test_throws DimensionMismatch mul!(full44, tri44, full43) + @test_throws DimensionMismatch mul!(full43, tri33, full43) + @test_throws DimensionMismatch mul!(full43, full43, tri44) end end diff --git a/test/linalg/qr.jl b/test/linalg/qr.jl index b9f69a2aba04d..0c6c1a1c70e10 100644 --- a/test/linalg/qr.jl +++ b/test/linalg/qr.jl @@ -2,7 +2,7 @@ using Test -using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted +using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, mul!, Adjoint, Transpose n = 10 @@ -20,7 +20,7 @@ breal = randn(n,2)/2 bimg = randn(n,2)/2 # helper functions to unambiguously recover explicit forms of an implicit QR Q -squareQ(Q::LinAlg.AbstractQ) = (sq = size(Q.factors, 1); A_mul_B!(Q, Matrix{eltype(Q)}(I, sq, sq))) +squareQ(Q::LinAlg.AbstractQ) = (sq = size(Q.factors, 1); mul!(Q, Matrix{eltype(Q)}(I, sq, sq))) rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @testset for eltya in (Float32, Float64, Complex64, Complex128, BigFloat, Int) @@ -60,7 +60,7 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @test a*(qra\b) ≈ b atol=3000ε @test Array(qra) ≈ a sq = size(q.factors, 2) - @test A_mul_Bc(Matrix{eltyb}(I, sq, sq), q) * squareQ(q) ≈ Matrix(I, sq, sq) atol=5000ε + @test *(Matrix{eltyb}(I, sq, sq), Adjoint(q)) * squareQ(q) ≈ Matrix(I, sq, sq) atol=5000ε if eltya != Int @test Matrix{eltyb}(I, a_1, a_1)*q ≈ convert(AbstractMatrix{tab}, q) ac = copy(a) @@ -83,7 +83,7 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @test_throws DimensionMismatch q*b[1:n1 + 1] @test_throws DimensionMismatch b[1:n1 + 1]*q' sq = size(q.factors, 2) - @test A_mul_Bc(UpperTriangular(Matrix{eltyb}(I, sq, sq)), q)*squareQ(q) ≈ Matrix(I, n1, a_1) atol=5000ε + @test *(UpperTriangular(Matrix{eltyb}(I, sq, sq)), Adjoint(q))*squareQ(q) ≈ Matrix(I, n1, a_1) atol=5000ε if eltya != Int @test Matrix{eltyb}(I, a_1, a_1)*q ≈ convert(AbstractMatrix{tab},q) end @@ -124,7 +124,7 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @test_throws DimensionMismatch q*b[1:n1+1] @test_throws DimensionMismatch b[1:n1+1]*q' sq = size(q.factors, 2) - @test A_mul_Bc(UpperTriangular(Matrix{eltyb}(I, sq, sq)), q)*squareQ(q) ≈ Matrix(I, n1, a_1) atol=5000ε + @test *(UpperTriangular(Matrix{eltyb}(I, sq, sq)), Adjoint(q))*squareQ(q) ≈ Matrix(I, n1, a_1) atol=5000ε if eltya != Int @test Matrix{eltyb}(I, a_1, a_1)*q ≈ convert(AbstractMatrix{tab},q) end @@ -135,20 +135,20 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) a = raw_a qrpa = factorize(a[:,1:n1]) q, r = qrpa[:Q], qrpa[:R] - @test A_mul_B!(squareQ(q)', q) ≈ Matrix(I, n, n) - @test_throws DimensionMismatch A_mul_B!(Matrix{eltya}(I, n+1, n+1),q) - @test A_mul_Bc!(squareQ(q), q) ≈ Matrix(I, n, n) - @test_throws DimensionMismatch A_mul_Bc!(Matrix{eltya}(I, n+1, n+1),q) + @test mul!(squareQ(q)', q) ≈ Matrix(I, n, n) + @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n+1),q) + @test mul!(squareQ(q), Adjoint(q)) ≈ Matrix(I, n, n) + @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n+1), Adjoint(q)) @test_throws BoundsError size(q,-1) - @test_throws DimensionMismatch Base.LinAlg.A_mul_B!(q,zeros(eltya,n1+1)) - @test_throws DimensionMismatch Base.LinAlg.Ac_mul_B!(q,zeros(eltya,n1+1)) + @test_throws DimensionMismatch Base.LinAlg.mul!(q,zeros(eltya,n1+1)) + @test_throws DimensionMismatch Base.LinAlg.mul!(Adjoint(q), zeros(eltya,n1+1)) qra = qrfact(a[:,1:n1], Val(false)) q, r = qra[:Q], qra[:R] - @test A_mul_B!(squareQ(q)', q) ≈ Matrix(I, n, n) - @test_throws DimensionMismatch A_mul_B!(Matrix{eltya}(I, n+1, n+1),q) - @test A_mul_Bc!(squareQ(q), q) ≈ Matrix(I, n, n) - @test_throws DimensionMismatch A_mul_Bc!(Matrix{eltya}(I, n+1, n+1),q) + @test mul!(squareQ(q)', q) ≈ Matrix(I, n, n) + @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n+1),q) + @test mul!(squareQ(q), Adjoint(q)) ≈ Matrix(I, n, n) + @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n+1),Adjoint(q)) @test_throws BoundsError size(q,-1) @test_throws DimensionMismatch q * Matrix{Int8}(I, n+4, n+4) end diff --git a/test/linalg/special.jl b/test/linalg/special.jl index 295882508eaf8..9df77f616c9d0 100644 --- a/test/linalg/special.jl +++ b/test/linalg/special.jl @@ -2,6 +2,8 @@ using Test +using Base.LinAlg: mul!, Adjoint, Transpose + n= 10 #Size of matrix to test srand(1) @@ -114,11 +116,11 @@ end atri = typ(a) b = rand(n,n) qrb = qrfact(b,Val(true)) - @test Base.LinAlg.A_mul_Bc(atri,qrb[:Q]) ≈ Matrix(atri) * qrb[:Q]' - @test Base.LinAlg.A_mul_Bc!(copy(atri),qrb[:Q]) ≈ Matrix(atri) * qrb[:Q]' + @test *(atri, Adjoint(qrb[:Q])) ≈ Matrix(atri) * qrb[:Q]' + @test mul!(copy(atri), Adjoint(qrb[:Q])) ≈ Matrix(atri) * qrb[:Q]' qrb = qrfact(b,Val(false)) - @test Base.LinAlg.A_mul_Bc(atri,qrb[:Q]) ≈ Matrix(atri) * qrb[:Q]' - @test Base.LinAlg.A_mul_Bc!(copy(atri),qrb[:Q]) ≈ Matrix(atri) * qrb[:Q]' + @test *(atri, Adjoint(qrb[:Q])) ≈ Matrix(atri) * qrb[:Q]' + @test mul!(copy(atri), Adjoint(qrb[:Q])) ≈ Matrix(atri) * qrb[:Q]' end end diff --git a/test/linalg/symmetric.jl b/test/linalg/symmetric.jl index 0119558f792ba..63421bd140cfe 100644 --- a/test/linalg/symmetric.jl +++ b/test/linalg/symmetric.jl @@ -307,14 +307,14 @@ end @test a * Hermitian(aherm) ≈ a * aherm @test Hermitian(aherm) * Hermitian(aherm) ≈ aherm*aherm @test_throws DimensionMismatch Hermitian(aherm) * ones(eltya,n+1) - Base.LinAlg.A_mul_B!(C,a,Hermitian(aherm)) + Base.LinAlg.mul!(C,a,Hermitian(aherm)) @test C ≈ a*aherm @test Symmetric(asym) * Symmetric(asym) ≈ asym*asym @test Symmetric(asym) * a ≈ asym * a @test a * Symmetric(asym) ≈ a * asym @test_throws DimensionMismatch Symmetric(asym) * ones(eltya,n+1) - Base.LinAlg.A_mul_B!(C,a,Symmetric(asym)) + Base.LinAlg.mul!(C,a,Symmetric(asym)) @test C ≈ a*asym tri_b = UpperTriangular(triu(b)) diff --git a/test/linalg/triangular.jl b/test/linalg/triangular.jl index 0d8b5d8dbb083..6badb09afab71 100644 --- a/test/linalg/triangular.jl +++ b/test/linalg/triangular.jl @@ -2,7 +2,9 @@ debug = false using Test -using Base.LinAlg: BlasFloat, errorbounds, full!, naivesub!, transpose!, UnitUpperTriangular, UnitLowerTriangular, A_rdiv_B!, A_rdiv_Bt!, A_rdiv_Bc! +using Base.LinAlg: BlasFloat, errorbounds, full!, naivesub!, transpose!, + UnitUpperTriangular, UnitLowerTriangular, + mul!, rdiv!, Adjoint, Transpose debug && println("Triangular matrices") @@ -318,7 +320,7 @@ for elty1 in (Float32, Float64, BigFloat, Complex64, Complex128, Complex{BigFloa if !(eltyB in (BigFloat, Complex{BigFloat})) # rand does not support BigFloat and Complex{BigFloat} as of Dec 2015 Tri = Tridiagonal(rand(eltyB,n-1),rand(eltyB,n),rand(eltyB,n-1)) - @test Base.LinAlg.A_mul_B!(Tri,copy(A1)) ≈ Tri*Matrix(A1) + @test mul!(Tri,copy(A1)) ≈ Tri*Matrix(A1) end # Triangular-dense Matrix/vector multiplication @@ -343,24 +345,24 @@ for elty1 in (Float32, Float64, BigFloat, Complex64, Complex128, Complex{BigFloa @test B'A1' ≈ B'Matrix(A1)' if eltyB == elty1 - @test A_mul_B!(similar(B),A1,B) ≈ A1*B - @test A_mul_Bc!(similar(B),A1,B) ≈ A1*B' - @test A_mul_Bt!(similar(B),A1,B) ≈ A1*B.' - @test Ac_mul_B!(similar(B),A1,B) ≈ A1'*B - @test At_mul_B!(similar(B),A1,B) ≈ A1.'*B + @test mul!(similar(B),A1,B) ≈ A1*B + @test mul!(similar(B), A1, Adjoint(B)) ≈ A1*B' + @test mul!(similar(B), A1, Transpose(B)) ≈ A1*B.' + @test mul!(similar(B), Adjoint(A1), B) ≈ A1'*B + @test mul!(similar(B), Transpose(A1), B) ≈ A1.'*B # test also vector methods B1 = vec(B[1,:]) - @test A_mul_B!(similar(B1),A1,B1) ≈ A1*B1 - @test Ac_mul_B!(similar(B1),A1,B1) ≈ A1'*B1 - @test At_mul_B!(similar(B1),A1,B1) ≈ A1.'*B1 + @test mul!(similar(B1),A1,B1) ≈ A1*B1 + @test mul!(similar(B1), Adjoint(A1), B1) ≈ A1'*B1 + @test mul!(similar(B1), Transpose(A1), B1) ≈ A1.'*B1 end #error handling - @test_throws DimensionMismatch Base.LinAlg.A_mul_B!(A1, ones(eltyB,n+1)) - @test_throws DimensionMismatch Base.LinAlg.A_mul_B!(ones(eltyB,n+1,n+1), A1) - @test_throws DimensionMismatch Base.LinAlg.At_mul_B!(A1, ones(eltyB,n+1)) - @test_throws DimensionMismatch Base.LinAlg.Ac_mul_B!(A1, ones(eltyB,n+1)) - @test_throws DimensionMismatch Base.LinAlg.A_mul_Bc!(ones(eltyB,n+1,n+1),A1) - @test_throws DimensionMismatch Base.LinAlg.A_mul_Bt!(ones(eltyB,n+1,n+1),A1) + @test_throws DimensionMismatch mul!(A1, ones(eltyB,n+1)) + @test_throws DimensionMismatch mul!(ones(eltyB,n+1,n+1), A1) + @test_throws DimensionMismatch mul!(Transpose(A1), ones(eltyB,n+1)) + @test_throws DimensionMismatch mul!(Adjoint(A1), ones(eltyB,n+1)) + @test_throws DimensionMismatch mul!(ones(eltyB,n+1,n+1), Adjoint(A1)) + @test_throws DimensionMismatch mul!(ones(eltyB,n+1,n+1), Transpose(A1)) # ... and division @test A1\B[:,1] ≈ Matrix(A1)\B[:,1] @@ -489,20 +491,20 @@ end let n = 5 A = rand(Float16, n, n) B = rand(Float16, n-1, n-1) - @test_throws DimensionMismatch A_rdiv_B!(A, LowerTriangular(B)) - @test_throws DimensionMismatch A_rdiv_B!(A, UpperTriangular(B)) - @test_throws DimensionMismatch A_rdiv_B!(A, UnitLowerTriangular(B)) - @test_throws DimensionMismatch A_rdiv_B!(A, UnitUpperTriangular(B)) - - @test_throws DimensionMismatch A_rdiv_Bc!(A, LowerTriangular(B)) - @test_throws DimensionMismatch A_rdiv_Bc!(A, UpperTriangular(B)) - @test_throws DimensionMismatch A_rdiv_Bc!(A, UnitLowerTriangular(B)) - @test_throws DimensionMismatch A_rdiv_Bc!(A, UnitUpperTriangular(B)) - - @test_throws DimensionMismatch A_rdiv_Bt!(A, LowerTriangular(B)) - @test_throws DimensionMismatch A_rdiv_Bt!(A, UpperTriangular(B)) - @test_throws DimensionMismatch A_rdiv_Bt!(A, UnitLowerTriangular(B)) - @test_throws DimensionMismatch A_rdiv_Bt!(A, UnitUpperTriangular(B)) + @test_throws DimensionMismatch rdiv!(A, LowerTriangular(B)) + @test_throws DimensionMismatch rdiv!(A, UpperTriangular(B)) + @test_throws DimensionMismatch rdiv!(A, UnitLowerTriangular(B)) + @test_throws DimensionMismatch rdiv!(A, UnitUpperTriangular(B)) + + @test_throws DimensionMismatch rdiv!(A, Adjoint(LowerTriangular(B))) + @test_throws DimensionMismatch rdiv!(A, Adjoint(UpperTriangular(B))) + @test_throws DimensionMismatch rdiv!(A, Adjoint(UnitLowerTriangular(B))) + @test_throws DimensionMismatch rdiv!(A, Adjoint(UnitUpperTriangular(B))) + + @test_throws DimensionMismatch rdiv!(A, Transpose(LowerTriangular(B))) + @test_throws DimensionMismatch rdiv!(A, Transpose(UpperTriangular(B))) + @test_throws DimensionMismatch rdiv!(A, Transpose(UnitLowerTriangular(B))) + @test_throws DimensionMismatch rdiv!(A, Transpose(UnitUpperTriangular(B))) end # Test that UpperTriangular(LowerTriangular) throws. See #16201 diff --git a/test/linalg/tridiag.jl b/test/linalg/tridiag.jl index 187e015a96110..8cf9d39532aa9 100644 --- a/test/linalg/tridiag.jl +++ b/test/linalg/tridiag.jl @@ -214,12 +214,12 @@ guardsrand(123) do @test A*UpperTriangular(Matrix(1.0I, n, n)) ≈ fA @test A*LowerTriangular(Matrix(1.0I, n, n)) ≈ fA end - @testset "A_mul_B! errors" begin - @test_throws DimensionMismatch Base.LinAlg.A_mul_B!(similar(fA),A,ones(elty,n,n+1)) - @test_throws DimensionMismatch Base.LinAlg.A_mul_B!(similar(fA),A,ones(elty,n+1,n)) - @test_throws DimensionMismatch A_mul_B!(zeros(elty,n,n),B,ones(elty,n+1,n)) - @test_throws DimensionMismatch A_mul_B!(zeros(elty,n+1,n),B,ones(elty,n,n)) - @test_throws DimensionMismatch A_mul_B!(zeros(elty,n,n+1),B,ones(elty,n,n)) + @testset "mul! errors" begin + @test_throws DimensionMismatch Base.LinAlg.mul!(similar(fA),A,ones(elty,n,n+1)) + @test_throws DimensionMismatch Base.LinAlg.mul!(similar(fA),A,ones(elty,n+1,n)) + @test_throws DimensionMismatch Base.LinAlg.mul!(zeros(elty,n,n),B,ones(elty,n+1,n)) + @test_throws DimensionMismatch Base.LinAlg.mul!(zeros(elty,n+1,n),B,ones(elty,n,n)) + @test_throws DimensionMismatch Base.LinAlg.mul!(zeros(elty,n,n+1),B,ones(elty,n,n)) end end if mat_type == SymTridiagonal diff --git a/test/linalg/uniformscaling.jl b/test/linalg/uniformscaling.jl index cab11607c7ba4..14cc00a9e9d63 100644 --- a/test/linalg/uniformscaling.jl +++ b/test/linalg/uniformscaling.jl @@ -69,7 +69,7 @@ let @testset "transpose, conj, inv" begin @test ndims(J) == 2 @test transpose(J) == J - @test J * [1 0; 0 1] == conj(Ac_mul_B(J, [1 0; 0 1])) # ctranpose (and A(c)_mul_B) + @test J * [1 0; 0 1] == conj(*(Base.LinAlg.Adjoint(J), [1 0; 0 1])) # ctranpose (and A(c)_mul_B) @test I + I === UniformScaling(2) # + @test inv(I) == I @test inv(J) == UniformScaling(inv(λ)) diff --git a/test/perf/blas/level3.jl b/test/perf/blas/level3.jl index a9c07a27841d3..0a64a83519337 100644 --- a/test/perf/blas/level3.jl +++ b/test/perf/blas/level3.jl @@ -6,7 +6,7 @@ function matmultest(n, iter) a = rand(n,n) b = similar(a) for i=1:iter - A_mul_B!(b, a, a) + Base.LinAlg.mul!(b, a, a) end b end diff --git a/test/perf/threads/stockcorr/pstockcorr.jl b/test/perf/threads/stockcorr/pstockcorr.jl index 5031b7caba032..a049cb7b6f02f 100644 --- a/test/perf/threads/stockcorr/pstockcorr.jl +++ b/test/perf/threads/stockcorr/pstockcorr.jl @@ -48,7 +48,7 @@ function runpath!(n, Wiener, CorrWiener, SA, SB, T, UpperTriangle, k11, k12, k21 #for i = 1:n randn!(rngs[threadid()], Wiener) #randn!(rngs[1], Wiener) - A_mul_B!(CorrWiener, Wiener, UpperTriangle) + Base.LinAlg.mul!(CorrWiener, Wiener, UpperTriangle) @simd for j = 2:T @inbounds SA[j, i] = SA[j-1, i] * exp(k11 + k12*CorrWiener[j-1, 1]) @inbounds SB[j, i] = SB[j-1, i] * exp(k21 + k22*CorrWiener[j-1, 2]) diff --git a/test/sparse/sparse.jl b/test/sparse/sparse.jl index c156f4f0ca9dd..cca70e78d1052 100644 --- a/test/sparse/sparse.jl +++ b/test/sparse/sparse.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +using Base.LinAlg: mul!, ldiv!, rdiv!, Adjoint, Transpose + @testset "issparse" begin @test issparse(sparse(ones(5,5))) @test !issparse(ones(5,5)) @@ -191,10 +193,10 @@ end α = rand(Complex128) β = rand(Complex128) @test (maximum(abs.(a*b - Array(a)*b)) < 100*eps()) - @test (maximum(abs.(A_mul_B!(similar(b), a, b) - Array(a)*b)) < 100*eps()) # for compatibility with present matmul API. Should go away eventually. - @test (maximum(abs.(A_mul_B!(similar(c), a, c) - Array(a)*c)) < 100*eps()) # for compatibility with present matmul API. Should go away eventually. - @test (maximum(abs.(At_mul_B!(similar(b), a, b) - Array(a).'*b)) < 100*eps()) # for compatibility with present matmul API. Should go away eventually. - @test (maximum(abs.(At_mul_B!(similar(c), a, c) - Array(a).'*c)) < 100*eps()) # for compatibility with present matmul API. Should go away eventually. + @test (maximum(abs.(mul!(similar(b), a, b) - Array(a)*b)) < 100*eps()) # for compatibility with present matmul API. Should go away eventually. + @test (maximum(abs.(mul!(similar(c), a, c) - Array(a)*c)) < 100*eps()) # for compatibility with present matmul API. Should go away eventually. + @test (maximum(abs.(mul!(similar(b), Transpose(a), b) - Array(a).'*b)) < 100*eps()) # for compatibility with present matmul API. Should go away eventually. + @test (maximum(abs.(mul!(similar(c), Transpose(a), c) - Array(a).'*c)) < 100*eps()) # for compatibility with present matmul API. Should go away eventually. @test (maximum(abs.(a'b - Array(a)'b)) < 100*eps()) @test (maximum(abs.(a.'b - Array(a).'b)) < 100*eps()) @test (maximum(abs.(a\b - Array(a)\b)) < 1000*eps()) @@ -340,11 +342,11 @@ dA = Array(sA) bi = inv.(b) dAt = transpose(dA) sAt = transpose(sA) - @test scale!(copy(dAt), bi) ≈ Base.LinAlg.A_rdiv_B!(copy(sAt), Diagonal(b)) - @test scale!(copy(dAt), bi) ≈ Base.LinAlg.A_rdiv_Bt!(copy(sAt), Diagonal(b)) - @test scale!(copy(dAt), conj(bi)) ≈ Base.LinAlg.A_rdiv_Bc!(copy(sAt), Diagonal(b)) - @test_throws DimensionMismatch Base.LinAlg.A_rdiv_B!(copy(sAt), Diagonal(ones(length(b) + 1))) - @test_throws LinAlg.SingularException Base.LinAlg.A_rdiv_B!(copy(sAt), Diagonal(zeros(length(b)))) + @test scale!(copy(dAt), bi) ≈ rdiv!(copy(sAt), Diagonal(b)) + @test scale!(copy(dAt), bi) ≈ rdiv!(copy(sAt), Transpose(Diagonal(b))) + @test scale!(copy(dAt), conj(bi)) ≈ rdiv!(copy(sAt), Adjoint(Diagonal(b))) + @test_throws DimensionMismatch rdiv!(copy(sAt), Diagonal(ones(length(b) + 1))) + @test_throws LinAlg.SingularException rdiv!(copy(sAt), Diagonal(zeros(length(b)))) end end @@ -1842,7 +1844,7 @@ end m = 5 intmat = fill(1, m, m) ltintmat = LowerTriangular(rand(1:5, m, m)) - @test At_ldiv_B(ltintmat, sparse(intmat)) ≈ At_ldiv_B(ltintmat, intmat) + @test \(Transpose(ltintmat), sparse(intmat)) ≈ \(Transpose(ltintmat), intmat) end # Test temporary fix for issue #16548 in PR #16979. Somewhat brittle. Expect to remove with `\` revisions. diff --git a/test/sparse/sparsevector.jl b/test/sparse/sparsevector.jl index 36eef43aa195a..474e24ee90c22 100644 --- a/test/sparse/sparsevector.jl +++ b/test/sparse/sparsevector.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +using Base.LinAlg: mul!, ldiv!, Adjoint, Transpose + ### Data spv_x1 = SparseVector(8, [2, 5, 6], [1.25, -0.75, 3.5]) @@ -816,7 +818,7 @@ end for α in [0.0, 1.0, 2.0], β in [0.0, 0.5, 1.0] y = rand(9) rr = α*A*xf + β*y - @test A_mul_B!(α, A, x, β, y) === y + @test mul!(α, A, x, β, y) === y @test y ≈ rr end y = A*x @@ -829,12 +831,12 @@ end for α in [0.0, 1.0, 2.0], β in [0.0, 0.5, 1.0] y = rand(9) rr = α*A'xf + β*y - @test At_mul_B!(α, A, x, β, y) === y + @test mul!(α, Transpose(A), x, β, y) === y @test y ≈ rr end - y = At_mul_B(A, x) + y = *(Transpose(A), x) @test isa(y, Vector{Float64}) - @test y ≈ At_mul_B(A, xf) + @test y ≈ *(Transpose(A), xf) end end @testset "sparse A * sparse x -> dense y" begin @@ -844,7 +846,7 @@ end for α in [0.0, 1.0, 2.0], β in [0.0, 0.5, 1.0] y = rand(9) rr = α*Af*xf + β*y - @test A_mul_B!(α, A, x, β, y) === y + @test mul!(α, A, x, β, y) === y @test y ≈ rr end y = SparseArrays.densemv(A, x) @@ -858,12 +860,12 @@ end for α in [0.0, 1.0, 2.0], β in [0.0, 0.5, 1.0] y = rand(9) rr = α*Af'xf + β*y - @test At_mul_B!(α, A, x, β, y) === y + @test mul!(α, Transpose(A), x, β, y) === y @test y ≈ rr end y = SparseArrays.densemv(A, x; trans='T') @test isa(y, Vector{Float64}) - @test y ≈ At_mul_B(Af, xf) + @test y ≈ *(Transpose(Af), xf) end let A = complex.(sprandn(7, 8, 0.5), sprandn(7, 8, 0.5)), @@ -889,7 +891,7 @@ end @test all(nonzeros(y) .!= 0.0) @test Array(y) ≈ Af * xf - y = At_mul_B(A, x2) + y = *(Transpose(A), x2) @test isa(y, SparseVector{Float64,Int}) @test all(nonzeros(y) .!= 0.0) @test Array(y) ≈ Af'x2f @@ -906,11 +908,11 @@ end @test isa(y, SparseVector{Complex128,Int}) @test Array(y) ≈ Af * xf - y = At_mul_B(A, x2) + y = *(Transpose(A), x2) @test isa(y, SparseVector{Complex128,Int}) @test Array(y) ≈ Af.' * x2f - y = Ac_mul_B(A, x2) + y = *(Adjoint(A), x2) @test isa(y, SparseVector{Complex128,Int}) @test Array(y) ≈ Af'x2f end @@ -955,19 +957,25 @@ end for spvec in spvecs fspvec = convert(Array, spvec) # test out-of-place left-division methods - for mat in (trimats..., unittrimats...), func in (\, At_ldiv_B, Ac_ldiv_B) - @test func(mat, spvec) ≈ func(mat, fspvec) + for mat in (trimats..., unittrimats...) + @test \(mat, spvec) ≈ \(mat, fspvec) + @test \(Adjoint(mat), spvec) ≈ \(Adjoint(mat), fspvec) + @test \(Transpose(mat), spvec) ≈ \(Transpose(mat), fspvec) end # test in-place left-division methods not involving quotients if eltypevec == typeof(zero(eltypemat)*zero(eltypevec) + zero(eltypemat)*zero(eltypevec)) - for mat in unittrimats, func in (A_ldiv_B!, Base.LinAlg.At_ldiv_B!, Base.LinAlg.Ac_ldiv_B!) - @test func(mat, copy(spvec)) ≈ func(mat, copy(fspvec)) + for mat in unittrimats + @test ldiv!(mat, copy(spvec)) ≈ ldiv!(mat, copy(fspvec)) + @test ldiv!(Adjoint(mat), copy(spvec)) ≈ ldiv!(Adjoint(mat), copy(fspvec)) + @test ldiv!(Transpose(mat), copy(spvec)) ≈ ldiv!(Transpose(mat), copy(fspvec)) end end # test in-place left-division methods involving quotients if eltypevec == typeof((zero(eltypemat)*zero(eltypevec) + zero(eltypemat)*zero(eltypevec))/one(eltypemat)) - for mat in trimats, func in (A_ldiv_B!, Base.LinAlg.At_ldiv_B!, Base.LinAlg.Ac_ldiv_B!) - @test func(mat, copy(spvec)) ≈ func(mat, copy(fspvec)) + for mat in trimats + @test ldiv!(mat, copy(spvec)) ≈ ldiv!(mat, copy(fspvec)) + @test ldiv!(Adjoint(mat), copy(spvec)) ≈ ldiv!(Adjoint(mat), copy(fspvec)) + @test ldiv!(Transpose(mat), copy(spvec)) ≈ ldiv!(Transpose(mat), copy(fspvec)) end end end @@ -987,12 +995,12 @@ end zerodvec = zeros(Float64, 2) for mat in (utmat, ltmat, uutmat, ultmat) - for func in (\, At_ldiv_B, Ac_ldiv_B) - @test isequal((func)(mat, zerospvec), zerodvec) - end - for ipfunc in (A_ldiv_B!, Base.LinAlg.At_ldiv_B!, Base.LinAlg.Ac_ldiv_B!) - @test isequal((ipfunc)(mat, copy(zerospvec)), zerospvec) - end + @test isequal(\(mat, zerospvec), zerodvec) + @test isequal(\(Adjoint(mat), zerospvec), zerodvec) + @test isequal(\(Transpose(mat), zerospvec), zerodvec) + @test isequal(ldiv!(mat, copy(zerospvec)), zerospvec) + @test isequal(ldiv!(Adjoint(mat), copy(zerospvec)), zerospvec) + @test isequal(ldiv!(Transpose(mat), copy(zerospvec)), zerospvec) end end end