From 20d0a1bf87191dc844174a2180af01c498fdc4c5 Mon Sep 17 00:00:00 2001 From: Sacha Verweij Date: Wed, 13 Dec 2017 21:30:44 -0800 Subject: [PATCH] Transition base to Adjoint/Transpose (flip switch, clean up fallout). --- base/deprecated.jl | 39 ++++++------ base/linalg/adjtrans.jl | 42 +++++++++---- base/linalg/rowvector.jl | 114 ++++++++++++++++++++---------------- base/linalg/triangular.jl | 8 +-- base/sparse/sparsevector.jl | 4 +- test/linalg/adjtrans.jl | 10 ++-- test/linalg/conjarray.jl | 20 +++++-- test/linalg/pinv.jl | 4 +- 8 files changed, 142 insertions(+), 99 deletions(-) diff --git a/base/deprecated.jl b/base/deprecated.jl index b78f15fad62524..9ade001760d6e2 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -2985,9 +2985,9 @@ end # methods involving RowVector from base/linalg/diagonal.jl, to deprecate @eval Base.LinAlg begin - *(rowvec::RowVector, D::Diagonal) = transpose(D * transpose(rowvec)) # seems potentially incorrect without also transposing D? - *(D::Diagonal, transrowvec::Transpose{<:Any,<:RowVector}) = (rowvec = transrowvec.parent; D*transpose(rowvec)) - *(D::Diagonal, adjrowvec::Adjoint{<:Any,<:RowVector}) = (rowvec = adjrowvec.parent; D*adjoint(rowvec)) + *(rowvec::RowVector, D::Diagonal) = rvtranspose(D * rvtranspose(rowvec)) # seems potentially incorrect without also transposing D? + *(D::Diagonal, transrowvec::Transpose{<:Any,<:RowVector}) = (rowvec = transrowvec.parent; D*rvtranspose(rowvec)) + *(D::Diagonal, adjrowvec::Adjoint{<:Any,<:RowVector}) = (rowvec = adjrowvec.parent; D*rvadjoint(rowvec)) end # methods involving RowVector from base/sparse/linalg.jl, to deprecate @@ -2999,7 +2999,7 @@ end # methods involving RowVector from base/linalg/qr.jl, to deprecate @eval Base.LinAlg begin - *(rowvec::RowVector, adjB::Adjoint{<:Any,<:AbstractQ}) = (B = adjB.parent; adjoint(B*adjoint(rowvec))) + *(rowvec::RowVector, adjB::Adjoint{<:Any,<:AbstractQ}) = (B = adjB.parent; rvadjoint(B*rvadjoint(rowvec))) end # methods involving RowVector from base/linalg/qr.jl, to deprecate @@ -3044,8 +3044,8 @@ end 1.0 ``` """ - norm(tv::RowVector, q::Real) = q == Inf ? norm(transpose(tv), 1) : norm(transpose(tv), q/(q-1)) - norm(tv::RowVector) = norm(transpose(tv)) + norm(tv::RowVector, q::Real) = q == Inf ? norm(rvtranspose(tv), 1) : norm(rvtranspose(tv), q/(q-1)) + norm(tv::RowVector) = norm(rvtranspose(tv)) end # methods involving RowVector from base/linalg/factorization.jl, to deprecate @@ -3071,30 +3071,29 @@ end *(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Transpose{<:Any,<:RowVector}) = A.parent * B end - # methods involving RowVector from base/linalg/triangular.jl, to deprecate @eval Base.LinAlg begin - *(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) + *(rowvec::RowVector, A::AbstractTriangular) = rvtranspose(transpose(A) * rvtranspose(rowvec)) + *(rowvec::RowVector, transA::Transpose{<:Any,<:AbstractTriangular}) = rvtranspose(transA.parent * rvtranspose(rowvec)) + *(A::AbstractTriangular, transrowvec::Transpose{<:Any,<:RowVector}) = A * rvtranspose(transrowvec.parent) + *(transA::Transpose{<:Any,<:AbstractTriangular}, transrowvec::Transpose{<:Any,<:RowVector}) = transA.parent.' * rvtranspose(transrowvec.parent) + *(rowvec::RowVector, adjA::Adjoint{<:Any,<:AbstractTriangular}) = rvadjoint(adjA.parent * rvadjoint(rowvec)) + *(A::AbstractTriangular, adjrowvec::Adjoint{<:Any,<:RowVector}) = A * rvadjoint(adjrowvec.parent) + *(adjA::Adjoint{<:Any,<:AbstractTriangular}, adjrowvec::Adjoint{<:Any,<:RowVector}) = adjA.parent' * rvadjoint(adjrowvec.parent) \(::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")) \(::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")) \(::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")) - /(rowvec::RowVector, A::Union{UpperTriangular,LowerTriangular}) = transpose(transpose(A) \ transpose(rowvec)) - /(rowvec::RowVector, A::Union{UnitUpperTriangular,UnitLowerTriangular}) = transpose(transpose(A) \ transpose(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)) + /(rowvec::RowVector, A::Union{UpperTriangular,LowerTriangular}) = rvtranspose(transpose(A) \ rvtranspose(rowvec)) + /(rowvec::RowVector, A::Union{UnitUpperTriangular,UnitLowerTriangular}) = rvtranspose(transpose(A) \ rvtranspose(rowvec)) + /(rowvec::RowVector, transA::Transpose{<:Any,<:Union{UpperTriangular,LowerTriangular}}) = rvtranspose(transA.parent \ rvtranspose(rowvec)) + /(rowvec::RowVector, transA::Transpose{<:Any,<:Union{UnitUpperTriangular,UnitLowerTriangular}}) = rvtranspose(transA.parent \ rvtranspose(rowvec)) /(rowvec::RowVector, adjA::Adjoint{<:Any,<:Union{UpperTriangular,LowerTriangular}}) = /(rowvec, adjoint(adjA.parent)) /(rowvec::RowVector, adjA::Adjoint{<:Any,<:Union{UnitUpperTriangular,UnitLowerTriangular}}) = /(rowvec, adjoint(adjA.parent)) - *(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:RowVector}) = A * transpose(B.parent) - *(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:RowVector}) = A * adjoint(B.parent) + *(A::Adjoint{<:Any,<:AbstractTriangular}, B::Transpose{<:Any,<:RowVector}) = A * rvtranspose(B.parent) + *(A::Transpose{<:Any,<:AbstractTriangular}, B::Adjoint{<:Any,<:RowVector}) = A * rvadjoint(B.parent) end # issue #24822 diff --git a/base/linalg/adjtrans.jl b/base/linalg/adjtrans.jl index 4cbc1391e59433..7bb6f7269886a2 100644 --- a/base/linalg/adjtrans.jl +++ b/base/linalg/adjtrans.jl @@ -49,9 +49,27 @@ 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 +# normalizing unwrapping constructors +# technically suspect, but at least fine for now +Adjoint(A::Transpose) = conj(A.parent) +Transpose(A::Adjoint) = conj(A.parent) + +# eager lowercase quasi-constructors, unwrapping +# TODO: return copies after adjoint(vec)/transpose(vec) deprecation? +adjoint(A::Adjoint) = A.parent +transpose(A::Transpose) = A.parent +# eager lowercase quasi-constructors, normalizing +# technically suspect, but at least fine for now +# TODO: return copies after adjoint(vec)/transpose(vec) deprecation? +adjoint(A::Transpose) = conj(A.parent) +transpose(A::Adjoint) = conj(A.parent) + +# lowercase quasi-constructors for vectors, TODO: deprecate +adjoint(sv::AbstractVector) = Adjoint(sv) +transpose(sv::AbstractVector) = Transpose(sv) + # some aliases for internal convenience use const AdjOrTrans{T,S} = Union{Adjoint{T,S},Transpose{T,S}} where {T,S} @@ -173,8 +191,8 @@ end ## pseudoinversion -pinv(v::AdjointAbsVec, tol::Real = 0) = Adjoint(pinv(v.parent, tol)) -pinv(v::TransposeAbsVec, tol::Real = 0) = Transpose(pinv(v.parent, tol)) +pinv(v::AdjointAbsVec, tol::Real = 0) = pinv(v.parent, tol).parent +pinv(v::TransposeAbsVec, tol::Real = 0) = pinv(conj(v.parent)).parent ## left-division \ @@ -187,12 +205,14 @@ pinv(v::TransposeAbsVec, tol::Real = 0) = Transpose(pinv(v.parent, tol)) # 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::AdjointAbsVec, B::Transpose{<:Any,<:AbstractMatrix}) = A * transpose(B.parent) +*(A::TransposeAbsVec, B::Adjoint{<:Any,<:AbstractMatrix}) = 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 +*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:AbstractMatrix}) = A * transpose(B.parent) +# Adj/Trans-vector * Trans/Adj-vector, shouldn't exist, here for ambiguity resolution? TODO: test removal +*(A::Adjoint{<:Any,<:AbstractVector}, B::Transpose{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) +*(A::Transpose{<:Any,<:AbstractVector}, B::Adjoint{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) +# Adj/Trans-matrix * Trans/Adj-vector, shouldn't exist, here for ambiguity resolution? TODO: test removal +*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) +*(A::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) +*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:AbstractVector}) = throw(MethodError(*, (A, B))) diff --git a/base/linalg/rowvector.jl b/base/linalg/rowvector.jl index cb77732aa21a07..a6565d7dad006f 100644 --- a/base/linalg/rowvector.jl +++ b/base/linalg/rowvector.jl @@ -100,26 +100,38 @@ convert(::Type{RowVector{T,V}}, rowvec::RowVector) where {T,V<:AbstractVector} = @inline similar(rowvec::RowVector, ::Type{T}, dims::Dims{N}) where {T,N} = similar(parent(rowvec), T, dims) # Basic methods -""" - transpose(v::AbstractVector) - -The transposition operator (`.'`). - -# Examples -```jldoctest -julia> v = [1,2,3] -3-element Array{Int64,1}: - 1 - 2 - 3 -julia> transpose(v) -1×3 RowVector{Int64,Array{Int64,1}}: - 1 2 3 -``` -""" -@inline transpose(vec::AbstractVector) = RowVector(vec) -@inline adjoint(vec::AbstractVector) = RowVector(_conj(vec)) +# replaced in the Adjoint/Transpose transition +# """ +# transpose(v::AbstractVector) +# +# The transposition operator (`.'`). +# +# # Examples +# ```jldoctest +# julia> v = [1,2,3] +# 3-element Array{Int64,1}: +# 1 +# 2 +# 3 +# +# julia> transpose(v) +# 1×3 RowVector{Int64,Array{Int64,1}}: +# 1 2 3 +# ``` +# """ +# @inline transpose(vec::AbstractVector) = RowVector(vec) +# @inline adjoint(vec::AbstractVector) = RowVector(_conj(vec)) + +# methods necessary to preserve RowVector's behavior through the Adjoint/Transpose transition +rvadjoint(v::AbstractVector) = RowVector(_conj(v)) +rvtranspose(v::AbstractVector) = RowVector(v) +rvadjoint(v::RowVector) = conj(v.vec) +rvadjoint(v::RowVector{<:Real}) = v.vec +rvtranspose(v::RowVector) = v.vec +rvtranspose(v::ConjRowVector) = copy(v.vec) +rvadjoint(x) = adjoint(x) +rvtranspose(x) = transpose(x) @inline transpose(rowvec::RowVector) = rowvec.vec @inline transpose(rowvec::ConjRowVector) = copy(rowvec.vec) # remove the ConjArray wrapper from any raw vector @@ -157,22 +169,22 @@ julia> conj(v) IndexStyle(::RowVector) = IndexLinear() IndexStyle(::Type{<:RowVector}) = IndexLinear() -@propagate_inbounds getindex(rowvec::RowVector, i::Int) = transpose(rowvec.vec[i]) -@propagate_inbounds setindex!(rowvec::RowVector, v, i::Int) = (setindex!(rowvec.vec, transpose(v), i); rowvec) +@propagate_inbounds getindex(rowvec::RowVector, i::Int) = rvtranspose(rowvec.vec[i]) +@propagate_inbounds setindex!(rowvec::RowVector, v, i::Int) = (setindex!(rowvec.vec, rvtranspose(v), i); rowvec) # Keep a RowVector where appropriate -@propagate_inbounds getindex(rowvec::RowVector, ::Colon, i::Int) = transpose.(rowvec.vec[i:i]) +@propagate_inbounds getindex(rowvec::RowVector, ::Colon, i::Int) = rvtranspose.(rowvec.vec[i:i]) @propagate_inbounds getindex(rowvec::RowVector, ::Colon, inds::AbstractArray{Int}) = RowVector(rowvec.vec[inds]) @propagate_inbounds getindex(rowvec::RowVector, ::Colon, ::Colon) = RowVector(rowvec.vec[:]) # helper function for below -@inline to_vec(rowvec::RowVector) = map(transpose, transpose(rowvec)) +@inline to_vec(rowvec::RowVector) = map(rvtranspose, rvtranspose(rowvec)) @inline to_vec(x::Number) = x @inline to_vecs(rowvecs...) = (map(to_vec, rowvecs)...,) # map: Preserve the RowVector by un-wrapping and re-wrapping, but note that `f` # expects to operate within the transposed domain, so to_vec transposes the elements -@inline map(f, rowvecs::RowVector...) = RowVector(map(transpose∘f, to_vecs(rowvecs...)...)) +@inline map(f, rowvecs::RowVector...) = RowVector(map(rvtranspose∘f, to_vecs(rowvecs...)...)) # broacast (other combinations default to higher-dimensional array) @inline broadcast(f, rowvecs::Union{Number,RowVector}...) = @@ -180,13 +192,13 @@ IndexStyle(::Type{<:RowVector}) = IndexLinear() # Horizontal concatenation # -@inline hcat(X::RowVector...) = transpose(vcat(map(transpose, X)...)) -@inline hcat(X::Union{RowVector,Number}...) = transpose(vcat(map(transpose, X)...)) +@inline hcat(X::RowVector...) = rvtranspose(vcat(map(rvtranspose, X)...)) +@inline hcat(X::Union{RowVector,Number}...) = rvtranspose(vcat(map(rvtranspose, X)...)) @inline typed_hcat(::Type{T}, X::RowVector...) where {T} = - transpose(typed_vcat(T, map(transpose, X)...)) + rvtranspose(typed_vcat(T, map(rvtranspose, X)...)) @inline typed_hcat(::Type{T}, X::Union{RowVector,Number}...) where {T} = - transpose(typed_vcat(T, map(transpose, X)...)) + rvtranspose(typed_vcat(T, map(rvtranspose, X)...)) # Multiplication # @@ -202,7 +214,7 @@ IndexStyle(::Type{<:RowVector}) = IndexLinear() end sum(@inbounds(return rowvec[i]*vec[i]) for i = 1:length(vec)) end -@inline *(rowvec::RowVector, mat::AbstractMatrix) = transpose(mat.' * transpose(rowvec)) +@inline *(rowvec::RowVector, mat::AbstractMatrix) = rvtranspose(mat.' * rvtranspose(rowvec)) *(::RowVector, ::RowVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) @inline *(vec::AbstractVector, rowvec::RowVector) = vec .* rowvec *(vec::AbstractVector, rowvec::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) @@ -211,27 +223,27 @@ end *(::RowVector, ::Transpose{<:Any,<:AbstractVector}) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) *(rowvec::RowVector, transmat::Transpose{<:Any,<:AbstractMatrix}) = - (mat = transmat.parent; transpose(mat * transpose(rowvec))) + (mat = transmat.parent; rvtranspose(mat * rvtranspose(rowvec))) *(rowvec1::RowVector, transrowvec2::Transpose{<:Any,<:RowVector}) = - (rowvec2 = transrowvec2.parent; rowvec1*transpose(rowvec2)) + (rowvec2 = transrowvec2.parent; rowvec1*rvtranspose(rowvec2)) *(::AbstractVector, ::Transpose{<:Any,<:RowVector}) = throw(DimensionMismatch("Cannot multiply two vectors")) *(mat::AbstractMatrix, transrowvec::Transpose{<:Any,<:RowVector}) = - (rowvec = transrowvec.parent; mat * transpose(rowvec)) + (rowvec = transrowvec.parent; mat * rvtranspose(rowvec)) *(transrowvec::Transpose{<:Any,<:RowVector}, transvec::Transpose{<:Any,<:AbstractVector}) = - transpose(transrowvec.parent) * transpose(transvec.parent) + rvtranspose(transrowvec.parent) * transpose(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) + transpose(transvec.parent)*rvtranspose(transrowvec.parent) *(transmat::Transpose{<:Any,<:AbstractMatrix}, transrowvec::Transpose{<:Any,<:RowVector}) = - (transmat.parent).' * transpose(transrowvec.parent) + (transmat.parent).' * rvtranspose(transrowvec.parent) *(::Transpose{<:Any,<:RowVector}, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) *(transrowvec1::Transpose{<:Any,<:RowVector}, rowvec2::RowVector) = - transpose(transrowvec1.parent) * rowvec2 + rvtranspose(transrowvec1.parent) * rowvec2 *(transvec::Transpose{<:Any,<:AbstractVector}, rowvec::RowVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) @@ -239,29 +251,29 @@ end *(::RowVector, ::Adjoint{<:Any,<:AbstractVector}) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) *(rowvec::RowVector, adjmat::Adjoint{<:Any,<:AbstractMatrix}) = - adjoint(adjmat.parent * adjoint(rowvec)) + rvadjoint(adjmat.parent * rvadjoint(rowvec)) *(rowvec1::RowVector, adjrowvec2::Adjoint{<:Any,<:RowVector}) = - rowvec1 * adjoint(adjrowvec2.parent) + rowvec1 * rvadjoint(adjrowvec2.parent) *(vec::AbstractVector, adjrowvec::Adjoint{<:Any,<:RowVector}) = throw(DimensionMismatch("Cannot multiply two vectors")) *(mat::AbstractMatrix, adjrowvec::Adjoint{<:Any,<:RowVector}) = - mat * adjoint(adjrowvec.parent) + mat * rvadjoint(adjrowvec.parent) *(adjrowvec::Adjoint{<:Any,<:RowVector}, adjvec::Adjoint{<:Any,<:AbstractVector}) = - adjoint(adjrowvec.parent) * adjoint(adjvec.parent) + rvadjoint(adjrowvec.parent) * adjoint(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) + adjoint(adjvec.parent)*rvadjoint(adjrowvec.parent) *(adjmat::Adjoint{<:Any,<:AbstractMatrix}, adjrowvec::Adjoint{<:Any,<:RowVector}) = - (adjmat.parent)' * adjoint(adjrowvec.parent) + (adjmat.parent)' * rvadjoint(adjrowvec.parent) *(::Adjoint{<:Any,<:RowVector}, ::AbstractVector) = throw(DimensionMismatch("Cannot multiply two vectors")) -*(adjrowvec1::Adjoint{<:Any,<:RowVector}, rowvec2::RowVector) = adjoint(adjrowvec1.parent) * rowvec2 +*(adjrowvec1::Adjoint{<:Any,<:RowVector}, rowvec2::RowVector) = rvadjoint(adjrowvec1.parent) * rowvec2 *(adjvec::Adjoint{<:Any,<:AbstractVector}, rowvec::RowVector) = throw(DimensionMismatch("Cannot multiply two transposed vectors")) # Pseudo-inverse -pinv(v::RowVector, tol::Real=0) = pinv(v', tol)' +pinv(v::RowVector, tol::Real=0) = rvadjoint(pinv(rvadjoint(v), tol)) # Left Division # @@ -274,19 +286,19 @@ pinv(v::RowVector, tol::Real=0) = pinv(v', tol)' # Right Division # -@inline /(rowvec::RowVector, mat::AbstractMatrix) = transpose(transpose(mat) \ transpose(rowvec)) -/(rowvec::RowVector, transmat::Transpose{<:Any,<:AbstractMatrix}) = transpose(transmat.parent \ transpose(rowvec)) -/(rowvec::RowVector, adjmat::Adjoint{<:Any,<:AbstractMatrix}) = adjoint(adjmat.parent \ adjoint(rowvec)) +@inline /(rowvec::RowVector, mat::AbstractMatrix) = rvtranspose(transpose(mat) \ rvtranspose(rowvec)) +/(rowvec::RowVector, transmat::Transpose{<:Any,<:AbstractMatrix}) = rvtranspose(transmat.parent \ rvtranspose(rowvec)) +/(rowvec::RowVector, adjmat::Adjoint{<:Any,<:AbstractMatrix}) = rvadjoint(adjmat.parent \ rvadjoint(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)) +/(A::Number, B::Adjoint{<:Any,<:RowVector}) = /(A, rvadjoint(B.parent)) +/(A::Matrix, B::RowVector) = rvadjoint(rvadjoint(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::Adjoint{<:Any,<:AbstractMatrix}, B::Transpose{<:Any,<:RowVector}) = A * rvtranspose(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) +*(A::Transpose{<:Any,<:AbstractMatrix}, B::Adjoint{<:Any,<:RowVector}) = A * rvadjoint(B.parent) diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index c09700b01b55fe..079cd2ba602ee4 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -1834,10 +1834,10 @@ function *(A::AbstractMatrix, transB::Transpose{<:Any,<:AbstractTriangular}) 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) +*(v::AdjointAbsVec, A::AbstractTriangular) = Adjoint(Adjoint(A) * v.parent) +*(v::TransposeAbsVec, A::AbstractTriangular) = Transpose(Transpose(A) * v.parent) +*(v::AdjointAbsVec, A::Adjoint{<:Any,<:AbstractTriangular}) = Adjoint(A.parent * v.parent) +*(v::TransposeAbsVec, A::Transpose{<:Any,<:AbstractTriangular}) = Transpose(A.parent * v.parent) # If these are not defined, they will fallback to the versions in matmul.jl diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index 6f8187fafdbece..37ed1e394a773e 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -1438,8 +1438,8 @@ vecnorm(x::SparseVectorUnion, p::Real=2) = vecnorm(nonzeros(x), p) # Transpose # (The only sparse matrix structure in base is CSC, so a one-row sparse matrix is worse than dense) -@inline transpose(sv::SparseVector) = RowVector(sv) -@inline adjoint(sv::SparseVector) = RowVector(conj(sv)) +transpose(sv::SparseVector) = Transpose(sv) +adjoint(sv::SparseVector) = Adjoint(sv) ### BLAS Level-1 diff --git a/test/linalg/adjtrans.jl b/test/linalg/adjtrans.jl index 2f4ca7864bdecb..bfcbc794658425 100644 --- a/test/linalg/adjtrans.jl +++ b/test/linalg/adjtrans.jl @@ -374,14 +374,14 @@ end end @testset "Adjoint/Transpose-wrapped vector pseudoinversion" begin - realvec, complexvec = [1., 2., 3., 4.], [1.0im, 2., 3.0im, 4.] + realvec, complexvec = [1, 2, 3, 4], [1im, 2, 3im, 4] rowrealvec, rowcomplexvec = reshape(realvec, (1, 4)), reshape(complexvec, (1, 4)) # pinv(Adjoint/Transpose-vector) should match matrix equivalents # TODO tighten type asserts once pinv yields Transpose/Adjoint - @test pinv(Adjoint(realvec))::Adjoint ≈ pinv(rowrealvec) - @test pinv(Transpose(realvec))::Transpose ≈ pinv(rowrealvec) - @test pinv(Adjoint(complexvec))::Adjoint ≈ pinv(conj(rowcomplexvec)) - @test pinv(Transpose(complexvec))::Transpose ≈ pinv(rowcomplexvec) + @test pinv(Adjoint(realvec))::Vector{Float64} ≈ pinv(rowrealvec) + @test pinv(Transpose(realvec))::Vector{Float64} ≈ pinv(rowrealvec) + @test pinv(Adjoint(complexvec))::Vector{Complex{Float64}} ≈ pinv(conj(rowcomplexvec)) + @test pinv(Transpose(complexvec))::Vector{Complex{Float64}} ≈ pinv(rowcomplexvec) end @testset "Adjoint/Transpose-wrapped vector left-division" begin diff --git a/test/linalg/conjarray.jl b/test/linalg/conjarray.jl index 4ba4ac90ad5bb0..29839ff81bb5b8 100644 --- a/test/linalg/conjarray.jl +++ b/test/linalg/conjarray.jl @@ -17,12 +17,24 @@ end @testset "RowVector conjugates" begin + # these definitions are what adjoint(...) and transpose(...) meant + # meant prior to the Adjoint/Transpose transition, and the tests + # below are re-expressed in them to shield them against changes + # to adjoint(...), transpose(...), .', ', and A[ct]_(mul|ldiv|rdiv)_B[ct] + using Base.LinAlg: _conj, ConjRowVector + rvadjoint(v::AbstractVector) = RowVector(_conj(v)) + rvtranspose(v::AbstractVector) = RowVector(v) + rvadjoint(v::RowVector) = conj(v.vec) + rvadjoint(v::RowVector{<:Real}) = v.vec + rvtranspose(v::RowVector) = v.vec + rvtranspose(v::ConjRowVector) = copy(v.vec) + v = [1+im, 1-im] - rv = v' + rv = rvadjoint(v) @test (parent(rv) isa ConjArray) - @test rv' === v + @test rvadjoint(rv) === v # Currently, view behavior defaults to only RowVectors. - @test isa((v').', Vector) - @test isa((v.')', Vector) + @test isa(rvtranspose(rvadjoint(v)), Vector) + @test isa(rvadjoint(rvtranspose(v)), Vector) end diff --git a/test/linalg/pinv.jl b/test/linalg/pinv.jl index 2c20e9f54bb128..de2d2ef11c6c80 100644 --- a/test/linalg/pinv.jl +++ b/test/linalg/pinv.jl @@ -133,9 +133,9 @@ end a = rand(eltya, m) apinv = @inferred pinv(a) @test pinv(hcat(a)) ≈ apinv - @test apinv isa RowVector{eltya} + @test isa(apinv, eltya <: Complex ? Adjoint{eltya} : Transpose{eltya}) end - @testset "RowVector" begin + @testset "Adjoint/Transpose vector" begin a = rand(eltya, m)' apinv = @inferred pinv(a) @test pinv(vcat(a)) ≈ apinv