diff --git a/stdlib/LinearAlgebra/src/abstractq.jl b/stdlib/LinearAlgebra/src/abstractq.jl index 853286f34048f..334a9a9235972 100644 --- a/stdlib/LinearAlgebra/src/abstractq.jl +++ b/stdlib/LinearAlgebra/src/abstractq.jl @@ -22,9 +22,14 @@ promote_rule(::Type{<:AbstractMatrix{T}}, ::Type{<:AbstractQ{T}}) where {T} = (@inline; Union{AbstractMatrix{T},AbstractQ{T}}) # conversion -AbstractQ{S}(Q::AbstractQ{S}) where {S} = Q -# the following eltype promotion needs to be defined for each subtype +# the following eltype promotion should be defined for each subtype `QType` # convert(::Type{AbstractQ{T}}, Q::QType) where {T} = QType{T}(Q) +# and then care has to be taken that +# QType{T}(Q::QType{T}) where T = ... +# is implemented as a no-op + +# the following conversion method ensures functionality when the above method is not defined +# (as for HessenbergQ), but no eltype conversion is required either (say, in multiplication) convert(::Type{AbstractQ{T}}, Q::AbstractQ{T}) where {T} = Q convert(::Type{AbstractQ{T}}, adjQ::AdjointQ{T}) where {T} = adjQ convert(::Type{AbstractQ{T}}, adjQ::AdjointQ) where {T} = convert(AbstractQ{T}, adjQ.Q)' @@ -36,7 +41,6 @@ Matrix(Q::AbstractQ{T}) where {T} = Matrix{T}(Q) Array{T}(Q::AbstractQ) where {T} = Matrix{T}(Q) Array(Q::AbstractQ) = Matrix(Q) convert(::Type{T}, Q::AbstractQ) where {T<:Array} = T(Q) -convert(::Type{T}, Q::AbstractQ) where {T<:Matrix} = T(Q) # legacy @deprecate(convert(::Type{AbstractMatrix{T}}, Q::AbstractQ) where {T}, convert(LinearAlgebra.AbstractQ{T}, Q)) @@ -227,11 +231,9 @@ QRCompactWYQ{S}(factors::AbstractMatrix, T::AbstractMatrix) where {S} = @deprecate(QRCompactWYQ{S,M}(factors::AbstractMatrix{S}, T::AbstractMatrix{S}) where {S,M}, QRCompactWYQ{S,M,typeof(T)}(factors, T), false) -QRPackedQ{T}(Q::QRPackedQ) where {T} = QRPackedQ(convert(AbstractMatrix{T}, Q.factors), convert(Vector{T}, Q.τ)) +QRPackedQ{T}(Q::QRPackedQ) where {T} = QRPackedQ(convert(AbstractMatrix{T}, Q.factors), convert(AbstractVector{T}, Q.τ)) QRCompactWYQ{S}(Q::QRCompactWYQ) where {S} = QRCompactWYQ(convert(AbstractMatrix{S}, Q.factors), convert(AbstractMatrix{S}, Q.T)) -AbstractQ{S}(Q::QRPackedQ) where {S} = QRPackedQ{S}(Q) -AbstractQ{S}(Q::QRCompactWYQ) where {S} = QRCompactWYQ{S}(Q) # override generic square fallback Matrix{T}(Q::Union{QRCompactWYQ{S},QRPackedQ{S}}) where {T,S} = convert(Matrix{T}, lmul!(Q, Matrix{S}(I, size(Q, 1), min(size(Q.factors)...)))) @@ -505,7 +507,7 @@ struct LQPackedQ{T,S<:AbstractMatrix{T},C<:AbstractVector{T}} <: AbstractQ{T} τ::C end -LQPackedQ{T}(Q::LQPackedQ) where {T} = LQPackedQ(convert(AbstractMatrix{T}, Q.factors), convert(Vector{T}, Q.τ)) +LQPackedQ{T}(Q::LQPackedQ) where {T} = LQPackedQ(convert(AbstractMatrix{T}, Q.factors), convert(AbstractVector{T}, Q.τ)) @deprecate(AbstractMatrix{T}(Q::LQPackedQ) where {T}, convert(AbstractQ{T}, Q), false) diff --git a/stdlib/LinearAlgebra/test/abstractq.jl b/stdlib/LinearAlgebra/test/abstractq.jl index b3ef5a1952244..e3f48c7b2e3fd 100644 --- a/stdlib/LinearAlgebra/test/abstractq.jl +++ b/stdlib/LinearAlgebra/test/abstractq.jl @@ -29,6 +29,9 @@ n = 5 A = rand(T, n, n) F = qr(A) Q = MyQ(F.Q) + @test ndims(Q) == 2 + T <: Real && @test transpose(Q) == adjoint(Q) + T <: Complex && @test_throws ErrorException transpose(Q) @test convert(AbstractQ{complex(T)}, Q) isa MyQ{complex(T)} @test convert(AbstractQ{complex(T)}, Q') isa AdjointQ{<:complex(T),<:MyQ{complex(T)}} @test Q*I ≈ Q.Q*I rtol=2eps(real(T)) @@ -50,14 +53,15 @@ n = 5 @test mul!(X, transQ(Q), transY(Y)) ≈ transQ(Q) * transY(Y) ≈ transQ(Q.Q) * transY(Y) @test mul!(X, transY(Y), transQ(Q)) ≈ transY(Y) * transQ(Q) ≈ transY(Y) * transQ(Q.Q) end - @test Matrix(Q) ≈ Q[:,:] ≈ copyto!(zeros(T, size(Q)), Q) ≈ Q.Q*I - @test Matrix(Q') ≈ (Q')[:,:] ≈ copyto!(zeros(T, size(Q)), Q') ≈ Q.Q'*I - @test Q[1,:] == Q.Q[1,:] - @test Q[:,1] == Q.Q[:,1] + @test convert(Matrix, Q) ≈ Matrix(Q) ≈ Q[:,:] ≈ copyto!(zeros(T, size(Q)), Q) ≈ Q.Q*I + @test convert(Matrix, Q') ≈ Matrix(Q') ≈ (Q')[:,:] ≈ copyto!(zeros(T, size(Q)), Q') ≈ Q.Q'*I + @test Q[1,:] == Q.Q[1,:] == view(Q, 1, :) + @test Q[:,1] == Q.Q[:,1] == view(Q, :, 1) @test Q[1,1] == Q.Q[1,1] @test Q[:] == Q.Q[:] - @test Q[:,1:3] == Q.Q[:,1:3] + @test Q[:,1:3] == Q.Q[:,1:3] == view(Q, :, 1:3) @test Q[:,1:3] ≈ Matrix(Q)[:,1:3] + @test Q[2:3,2:3] == view(Q, 2:3, 2:3) ≈ Matrix(Q)[2:3,2:3] @test_throws BoundsError Q[0,1] @test_throws BoundsError Q[n+1,1] @test_throws BoundsError Q[1,0]