From 7c8d8bbbb9a9f169138d87e5d556dfc36d035f26 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Wed, 26 Feb 2025 11:00:11 +0000 Subject: [PATCH 1/4] Drop Julia , >=, /, ^, \, transpose, showerror, reindex, checkbounds, @propagate_inbounds @@ -53,6 +48,8 @@ const TransposeFact = isdefined(LinearAlgebra, :TransposeFactorization) ? Linear # objects are flexible in size when multiplied from the left, or its adjoint # from the right. abstract type LayoutQ{T} <: AbstractQ{T} end + + @_layoutlmul LayoutQ @_layoutlmul AdjointQtype{<:Any,<:LayoutQ} @_layoutrmul LayoutQ @@ -109,30 +106,6 @@ end *(A::AbstractTriangular, B::LayoutQ) = mul(A, B) *(A::AbstractTriangular, B::AdjointQtype{<:Any,<:LayoutQ}) = mul(A, B) -if VERSION < v"1.10-" - (*)(Q::LayoutQ, b::StridedVector) = _mul(Q, b) - (*)(Q::LayoutQ, B::StridedMatrix) = _mul(Q, B) - (*)(Q::LayoutQ, B::Adjoint{<:Any,<:StridedVecOrMat}) = _mul(Q, B) - (*)(A::StridedMatrix, adjQ::AdjointQtype{<:Any,<:LayoutQ}) = _mul(A, adjQ) - (*)(A::Adjoint{<:Any,<:StridedMatrix}, adjQ::AdjointQtype{<:Any,<:LayoutQ}) = _mul(A, adjQ) - - Base.@propagate_inbounds getindex(Q::LayoutQ, i::Int, j::Int) = Q[:, j][i] - function getindex(Q::LayoutQ, ::Colon, j::Int) - y = zeros(eltype(Q), size(Q, 2)) - y[j] = 1 - lmul!(Q, y) - end - Base.@propagate_inbounds layout_getindex(A::LayoutQ, I::CartesianIndex) = A[to_indices(A, (I,))...] - Base.@propagate_inbounds layout_getindex(A::LayoutQ, I::Int...) = - Base.invoke(Base.getindex, Tuple{AbstractQ, typeof.(I)...}, A, I...) - Base.@propagate_inbounds layout_getindex(A::LayoutQ, I::AbstractVector{Int}, J::AbstractVector{Int}) = - hcat((A[:, j][I] for j in J)...) - - (*)(Q::LayoutQ, adjQ::Adjoint{<:Any,<:LayoutQ}) = mul(Q, adjQ) - (*)(adjQ::Adjoint{<:Any,<:LayoutQ}, Q::LayoutQ) = mul(adjQ, Q) - (*)(adjQ::Adjoint{<:Any,<:LayoutQ}, adjP::Adjoint{<:Any,<:LayoutQ}) = mul(adjQ, adjP) -end - axes(Q::LayoutQ, dim::Integer) = axes(getfield(Q, :factors), dim == 2 ? 1 : dim) axes(Q::LayoutQ) = axes(Q, 1), axes(Q, 2) copy(Q::LayoutQ) = Q diff --git a/src/polar.jl b/src/polar.jl index 57983ef..5c10530 100644 --- a/src/polar.jl +++ b/src/polar.jl @@ -486,11 +486,6 @@ mutable struct QDWHUpdater{T} <: PolarUpdater L::T # a lower bound for the smallest singluar value of each update matrix U end - -if VERSION < v"1.7-" - ColumnNorm() = Val(true) -end - function update_U!(upd::QDWHUpdater, U::Matrix{T}) where {T} piv = upd.piv L = upd.L diff --git a/src/ql.jl b/src/ql.jl index 5764fcd..c6d0575 100644 --- a/src/ql.jl +++ b/src/ql.jl @@ -265,15 +265,7 @@ Matrix{T}(Q::QLPackedQ{S}) where {T,S} = convert(Matrix{T}, lmul!(Q, Matrix{S}(I, size(Q, 1), min(size(Q.factors)...)))) Matrix(Q::QLPackedQ{S}) where {S} = Matrix{S}(Q) -if VERSION < v"1.10-" - AbstractMatrix{T}(Q::QLPackedQ{T}) where {T} = Q - AbstractMatrix{T}(Q::QLPackedQ) where {T} = QLPackedQ{T}(Q) - convert(::Type{AbstractMatrix{T}}, Q::QLPackedQ) where {T} = QLPackedQ{T}(Q) - convert(::Type{AbstractMatrix{T}}, adjQ::Adjoint{<:Any,<:QLPackedQ}) where {T} = - (QLPackedQ{T}(parent(adjQ)))' -else - AbstractMatrix{T}(Q::QLPackedQ) where {T} = Matrix{T}(Q) -end +AbstractMatrix{T}(Q::QLPackedQ) where {T} = Matrix{T}(Q) size(Q::QLPackedQ, dim::Integer) = size(getfield(Q, :factors), dim == 2 ? 1 : dim) diff --git a/src/qr.jl b/src/qr.jl index 4e9e57f..397c9af 100644 --- a/src/qr.jl +++ b/src/qr.jl @@ -160,6 +160,9 @@ struct QRPackedQ{T,S<:AbstractMatrix{T},Tau<:AbstractVector{T}} <: LayoutQ{T} new{T,S,Tau}(factors, τ) end end + + + QRPackedQ(factors::AbstractMatrix{T}, τ::AbstractVector{T}) where {T} = QRPackedQ{T,typeof(factors),typeof(τ)}(factors, τ) function QRPackedQ{T}(factors::AbstractMatrix, τ::AbstractVector) where {T} QRPackedQ(convert(AbstractMatrix{T}, factors), convert(AbstractVector{T}, τ)) @@ -176,15 +179,7 @@ Matrix{T}(Q::QRPackedQ{S}) where {T,S} = convert(Matrix{T}, lmul!(Q, Matrix{S}(I, size(Q, 1), min(size(Q.factors)...)))) Matrix(Q::QRPackedQ{S}) where {S} = Matrix{S}(Q) -if VERSION < v"1.10-" - AbstractMatrix{T}(Q::QRPackedQ{T}) where {T} = Q - AbstractMatrix{T}(Q::QRPackedQ) where {T} = QRPackedQ{T}(Q) - convert(::Type{AbstractMatrix{T}}, Q::QRPackedQ) where {T} = QRPackedQ{T}(Q) - convert(::Type{AbstractMatrix{T}}, adjQ::Adjoint{<:Any,<:QRPackedQ}) where {T} = - (QRPackedQ{T}(parent(adjQ)))' -else - AbstractMatrix{T}(Q::QRPackedQ) where {T} = Matrix{T}(Q) -end +AbstractMatrix{T}(Q::QRPackedQ) where {T} = Matrix{T}(Q) size(F::QR, dim::Integer) = size(getfield(F, :factors), dim) size(F::QR) = size(getfield(F, :factors)) diff --git a/src/rq.jl b/src/rq.jl index 97b71a8..4499ca1 100644 --- a/src/rq.jl +++ b/src/rq.jl @@ -122,16 +122,7 @@ Matrix(Q::RQPackedQ{S}) where {S} = Matrix{S}(Q) AbstractQ{T}(Q::RQPackedQ{T}) where {T} = Q AbstractQ{T}(Q::RQPackedQ) where {T} = RQPackedQ{T}(Q) convert(::Type{AbstractQ{T}}, Q::RQPackedQ) where {T} = RQPackedQ{T}(Q) - -if VERSION < v"1.10-" - AbstractMatrix{T}(Q::RQPackedQ{T}) where {T} = Q - AbstractMatrix{T}(Q::RQPackedQ) where {T} = RQPackedQ{T}(Q) - convert(::Type{AbstractMatrix{T}}, Q::RQPackedQ) where {T} = RQPackedQ{T}(Q) - convert(::Type{AbstractMatrix{T}}, adjQ::Adjoint{<:Any,<:RQPackedQ}) where {T} = - (RQPackedQ{T}(parent(adjQ)))' -else - AbstractMatrix{T}(Q::RQPackedQ) where {T} = Matrix{T}(Q) -end +AbstractMatrix{T}(Q::RQPackedQ) where {T} = Matrix{T}(Q) Base.size(Q::RQPackedQ, dim::Integer) = size(getfield(Q, :factors), dim == 1 ? 2 : dim) Base.size(Q::RQPackedQ) = size(Q, 1), size(Q, 2) diff --git a/src/ul.jl b/src/ul.jl index f572c17..bb19af9 100644 --- a/src/ul.jl +++ b/src/ul.jl @@ -99,9 +99,7 @@ end # ul!(A.data, pivot; check = check) # end -if VERSION < v"1.7-" - _checknonsingular(info, ::Val{Pivot}) where Pivot = checknonsingular(info, Val{Pivot}()) -elseif VERSION < v"1.11-" +if VERSION < v"1.11-" _checknonsingular(info, ::Val{true}) = checknonsingular(info, RowMaximum()) _checknonsingular(info, ::Val{false}) = checknonsingular(info, NoPivot()) else diff --git a/test/test_ql.jl b/test/test_ql.jl index 67369bc..48eb0ca 100644 --- a/test/test_ql.jl +++ b/test/test_ql.jl @@ -95,11 +95,7 @@ using MatrixFactorizations, ArrayLayouts, Test sq = size(q.factors, 1) @test *(LowerTriangular(Matrix{eltyb}(I, sq, sq)), adjoint(q))*squareQ(q) ≈ Matrix(I, a_1, a_1) atol=5000ε if eltya != Int - if VERSION < v"1.10-" - @test Matrix{eltyb}(I, a_1, a_1)*q ≈ convert(AbstractMatrix{tab}, q) - else - @test Matrix{eltyb}(I, a_1, a_1)*q ≈ squareQ(convert(LinearAlgebra.AbstractQ{tab}, q)) - end + @test Matrix{eltyb}(I, a_1, a_1)*q ≈ squareQ(convert(LinearAlgebra.AbstractQ{tab}, q)) end end end diff --git a/test/test_qr.jl b/test/test_qr.jl index dcd59df..7183896 100644 --- a/test/test_qr.jl +++ b/test/test_qr.jl @@ -61,11 +61,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = Matrix(Q) # convert(Array, Q) sq = size(q.factors, 2) @test *(Matrix{eltyb}(I, sq, sq), adjoint(q)) * squareQ(q) ≈ Matrix(I, sq, sq) atol=5000ε if eltya != Int - if VERSION < v"1.10-" - @test Matrix{eltyb}(I, a_1, a_1)*q ≈ convert(AbstractMatrix{tab}, q) - else - @test Matrix{eltyb}(I, a_1, a_1)*q ≈ squareQ(convert(LinearAlgebra.AbstractQ{tab}, q)) - end + @test Matrix{eltyb}(I, a_1, a_1)*q ≈ squareQ(convert(LinearAlgebra.AbstractQ{tab}, q)) ac = copy(a) @test qrunblocked!(a[:, 1:5])\b == qrunblocked!(view(ac, :, 1:5))\b end @@ -91,11 +87,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = Matrix(Q) # convert(Array, Q) sq = size(q.factors, 1) @test *(LowerTriangular(Matrix{eltyb}(I, sq, sq)), adjoint(q))*squareQ(q) ≈ Matrix(I, a_1, a_1) atol=5000ε if eltya != Int - if VERSION < v"1.10-" - @test Matrix{eltyb}(I, a_1, a_1)*q ≈ convert(AbstractMatrix{tab}, q) - else - @test Matrix{eltyb}(I, a_1, a_1)*q ≈ squareQ(convert(LinearAlgebra.AbstractQ{tab}, q)) - end + @test Matrix{eltyb}(I, a_1, a_1)*q ≈ squareQ(convert(LinearAlgebra.AbstractQ{tab}, q)) end end end diff --git a/test/test_reversecholesky.jl b/test/test_reversecholesky.jl index 82a0829..a7654d2 100644 --- a/test/test_reversecholesky.jl +++ b/test/test_reversecholesky.jl @@ -298,10 +298,7 @@ end # complex, failing D[2, 2] = 0.0 + 0im - if VERSION ≥ v"1.10" - @test_throws PosDefException reversecholesky(D) - end - + @test_throws PosDefException reversecholesky(D) # InexactError for Int @test_throws InexactError reversecholesky!(Diagonal([2, 1])) diff --git a/test/test_rq.jl b/test/test_rq.jl index 7146355..4ae484f 100644 --- a/test/test_rq.jl +++ b/test/test_rq.jl @@ -105,11 +105,7 @@ const Our=MatrixFactorizations sq = size(q.factors, 2) @test *(Matrix{eltyb}(I, sq, sq), adjoint(q)) * q ≈ Matrix(I, sq, sq) atol=5000ε if eltya != Int - if VERSION < v"1.10-" - @test Matrix{eltyb}(I, a_1, a_1)*q ≈ convert(AbstractMatrix{tab}, q) - else - @test Matrix{eltyb}(I, a_1, a_1)*q ≈ squareQ(convert(LinearAlgebra.AbstractQ{tab}, q)) - end + @test Matrix{eltyb}(I, a_1, a_1)*q ≈ squareQ(convert(LinearAlgebra.AbstractQ{tab}, q)) ac = copy(a) # would need rectangular ldiv! method @test_throws DimensionMismatch rq!(a[:, 1:5])\b == rq!(view(ac, :, 1:5))\b From e2a5caf1de344e4f905726c6e9fd4a33465feb66 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Wed, 26 Feb 2025 11:05:53 +0000 Subject: [PATCH 2/4] Update ci.yml --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1053fdc..8233e3e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,9 +20,8 @@ jobs: fail-fast: false matrix: version: - - '1.9' + - 'lts' - '1' - - '^1.11.0-0' os: - ubuntu-latest - macOS-latest From 65e79f90b6fcbc490b6445bcf4dbc7b41697f3eb Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Wed, 26 Feb 2025 11:20:45 +0000 Subject: [PATCH 3/4] Introduce QRPackedQMatrix --- src/MatrixFactorizations.jl | 15 +++++++++--- src/qr.jl | 49 +++++++++++++++++++++++++++---------- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/MatrixFactorizations.jl b/src/MatrixFactorizations.jl index c90b621..f055c95 100644 --- a/src/MatrixFactorizations.jl +++ b/src/MatrixFactorizations.jl @@ -50,12 +50,18 @@ const TransposeFact = isdefined(LinearAlgebra, :TransposeFactorization) ? Linear abstract type LayoutQ{T} <: AbstractQ{T} end +# Support orthogonal matrices as an abstract matrix +abstract type LayoutQMatrix{T} <: LayoutMatrix{T} end + +const LayoutQTypes{T} = Union{LayoutQ{T}, LayoutQMatrix{T}} + + @_layoutlmul LayoutQ @_layoutlmul AdjointQtype{<:Any,<:LayoutQ} @_layoutrmul LayoutQ @_layoutrmul AdjointQtype{<:Any,<:LayoutQ} -LinearAlgebra.copymutable(Q::LayoutQ) = copymutable_size(size(Q), Q) +LinearAlgebra.copymutable(Q::LayoutQTypes) = copymutable_size(size(Q), Q) copymutable_size(sz, Q) = lmul!(Q, Matrix{eltype(Q)}(I, sz)) (*)(Q::LayoutQ, b::AbstractVector) = _mul(Q, b) @@ -106,10 +112,11 @@ end *(A::AbstractTriangular, B::LayoutQ) = mul(A, B) *(A::AbstractTriangular, B::AdjointQtype{<:Any,<:LayoutQ}) = mul(A, B) -axes(Q::LayoutQ, dim::Integer) = axes(getfield(Q, :factors), dim == 2 ? 1 : dim) -axes(Q::LayoutQ) = axes(Q, 1), axes(Q, 2) -copy(Q::LayoutQ) = Q +axes(Q::LayoutQTypes, dim::Integer) = axes(getfield(Q, :factors), dim == 2 ? 1 : dim) +axes(Q::LayoutQTypes) = axes(Q, 1), axes(Q, 2) +copy(Q::LayoutQTypes) = Q Base.@propagate_inbounds getindex(A::LayoutQ, I...) = layout_getindex(A, I...) +Base.@propagate_inbounds getindex(A::LayoutQMatrix, I...) = AbstractQ(A)[I...] # by default, fall back to AbstractQ methods layout_getindex(A::LayoutQ, I...) = Base.invoke(Base.getindex, Tuple{AbstractQ, typeof.(I)...}, A, I...) diff --git a/src/qr.jl b/src/qr.jl index 397c9af..c9771ed 100644 --- a/src/qr.jl +++ b/src/qr.jl @@ -145,6 +145,8 @@ ldiv!(F::QR, B::AbstractVecOrMat) = ArrayLayouts.ldiv!(F, B) ldiv!(F::QR, B::LayoutVector) = ArrayLayouts.ldiv!(F, B) ldiv!(F::QR, B::LayoutMatrix) = ArrayLayouts.ldiv!(F, B) +size(F::QR, dim::Integer) = size(getfield(F, :factors), dim) +size(F::QR) = size(getfield(F, :factors)) """ QRPackedQ <: LinearAlgebra.AbstractQ @@ -163,28 +165,49 @@ end -QRPackedQ(factors::AbstractMatrix{T}, τ::AbstractVector{T}) where {T} = QRPackedQ{T,typeof(factors),typeof(τ)}(factors, τ) -function QRPackedQ{T}(factors::AbstractMatrix, τ::AbstractVector) where {T} - QRPackedQ(convert(AbstractMatrix{T}, factors), convert(AbstractVector{T}, τ)) +""" + QRPackedQMatrix <: LayoutQMatrix + +The orthogonal/unitary ``Q`` matrix of a QR factorization stored in [`QR`](@ref), +conforming to the `AbstractMatrix` interface. +""" +struct QRPackedQMatrix{T,S<:AbstractMatrix{T},Tau<:AbstractVector{T}} <: LayoutQMatrix{T} + factors::S + τ::Tau + + function QRPackedQMatrix{T,S,Tau}(factors, τ) where {T,S<:AbstractMatrix{T},Tau<:AbstractVector{T}} + require_one_based_indexing(factors) + new{T,S,Tau}(factors, τ) + end end -QRPackedQ{T}(Q::QRPackedQ) where {T} = QRPackedQ(convert(AbstractMatrix{T}, Q.factors), convert(AbstractVector{T}, Q.τ)) -QRPackedQ(Q::LinearAlgebra.QRPackedQ) = QRPackedQ(Q.factors, Q.τ) + +for QType in (:QRPackedQ, :QRPackedQMatrix) + @eval begin + $QTyp(factors::AbstractMatrix{T}, τ::AbstractVector{T}) where {T} = $QTyp{T,typeof(factors),typeof(τ)}(factors, τ) + function $QTyp{T}(factors::AbstractMatrix, τ::AbstractVector) where {T} + $QTyp(convert(AbstractMatrix{T}, factors), convert(AbstractVector{T}, τ)) + end + + $QTyp{T}(Q::$QTyp) where {T} = $QTyp(convert(AbstractMatrix{T}, Q.factors), convert(AbstractVector{T}, Q.τ)) + $QTyp(Q::LinearAlgebra.$QTyp) = $QTyp(Q.factors, Q.τ) + end +end + +const QRPackedQTypes{T,S<:AbstractMatrix{T},Tau<:AbstractVector{T}} = Union{QRPackedQ{T,S,Tau}, QRPackedQMatrix{T,S,Tau}} + +Matrix{T}(Q::QRPackedQTypes{S}) where {T,S} = convert(Matrix{T}, lmul!(Q, Matrix{S}(I, size(Q, 1), min(size(Q.factors)...)))) +Matrix(Q::QRPackedQTypes{S}) where {S} = Matrix{S}(Q) AbstractQ{T}(Q::QRPackedQ{T}) where {T} = Q AbstractQ{T}(Q::QRPackedQ) where {T} = QRPackedQ{T}(Q) +AbstractQ{T}(Q::QRPackedQMatrix{T}) where {T} = QRPackedQ(Q.factors, Q.τ) +AbstractQ{T}(Q::QRPackedQMatrix) where {T} = QRPackedQ{T}(Q.factors, Q.τ) convert(::Type{AbstractQ{T}}, Q::QRPackedQ) where {T} = QRPackedQ{T}(Q) - -Matrix{T}(Q::QRPackedQ{S}) where {T,S} = - convert(Matrix{T}, lmul!(Q, Matrix{S}(I, size(Q, 1), min(size(Q.factors)...)))) -Matrix(Q::QRPackedQ{S}) where {S} = Matrix{S}(Q) - AbstractMatrix{T}(Q::QRPackedQ) where {T} = Matrix{T}(Q) -size(F::QR, dim::Integer) = size(getfield(F, :factors), dim) -size(F::QR) = size(getfield(F, :factors)) -MemoryLayout(::Type{<:QRPackedQ{<:Any,S,T}}) where {S,T} = +MemoryLayout(::Type{<:QRPackedQTypes{<:Any,S,T}}) where {S,T} = QRPackedQLayout{typeof(MemoryLayout(S)),typeof(MemoryLayout(T))}() MemoryLayout(::Type{<:QR{<:Any,S,T}}) where {S,T} = From bed51d0c340551350f733550c984f1d5a9190907 Mon Sep 17 00:00:00 2001 From: Sheehan Olver Date: Wed, 26 Feb 2025 11:51:10 +0000 Subject: [PATCH 4/4] QRPackedQ functionality --- src/MatrixFactorizations.jl | 8 ++++---- src/qr.jl | 12 ++++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/MatrixFactorizations.jl b/src/MatrixFactorizations.jl index f055c95..04aebe1 100644 --- a/src/MatrixFactorizations.jl +++ b/src/MatrixFactorizations.jl @@ -1,6 +1,6 @@ module MatrixFactorizations using Base, LinearAlgebra, ArrayLayouts -import Base: axes, axes1, getproperty, iterate, tail, oneto +import Base: axes, axes1, getproperty, iterate, tail, oneto, BroadcastStyle import LinearAlgebra: BlasInt, BlasReal, BlasFloat, BlasComplex, axpy!, copy_oftype, checksquare, adjoint, transpose, AdjOrTrans, HermOrSym, det, logdet, logabsdet, isposdef @@ -116,13 +116,13 @@ axes(Q::LayoutQTypes, dim::Integer) = axes(getfield(Q, :factors), dim == 2 ? 1 : axes(Q::LayoutQTypes) = axes(Q, 1), axes(Q, 2) copy(Q::LayoutQTypes) = Q Base.@propagate_inbounds getindex(A::LayoutQ, I...) = layout_getindex(A, I...) -Base.@propagate_inbounds getindex(A::LayoutQMatrix, I...) = AbstractQ(A)[I...] +Base.@propagate_inbounds getindex(A::LayoutQMatrix, k::Int, j::Int) = AbstractQ(A)[k, j] # by default, fall back to AbstractQ methods layout_getindex(A::LayoutQ, I...) = Base.invoke(Base.getindex, Tuple{AbstractQ, typeof.(I)...}, A, I...) -size(Q::LayoutQ, dim::Integer) = size(getfield(Q, :factors), dim == 2 ? 1 : dim) -size(Q::LayoutQ) = size(Q, 1), size(Q, 2) +size(Q::LayoutQTypes, dim::Integer) = size(getfield(Q, :factors), dim == 2 ? 1 : dim) +size(Q::LayoutQTypes) = size(Q, 1), size(Q, 2) include("ul.jl") include("qr.jl") diff --git a/src/qr.jl b/src/qr.jl index c9771ed..650c8cc 100644 --- a/src/qr.jl +++ b/src/qr.jl @@ -182,7 +182,7 @@ struct QRPackedQMatrix{T,S<:AbstractMatrix{T},Tau<:AbstractVector{T}} <: LayoutQ end -for QType in (:QRPackedQ, :QRPackedQMatrix) +for QTyp in (:QRPackedQ, :QRPackedQMatrix) @eval begin $QTyp(factors::AbstractMatrix{T}, τ::AbstractVector{T}) where {T} = $QTyp{T,typeof(factors),typeof(τ)}(factors, τ) function $QTyp{T}(factors::AbstractMatrix, τ::AbstractVector) where {T} @@ -190,10 +190,11 @@ for QType in (:QRPackedQ, :QRPackedQMatrix) end $QTyp{T}(Q::$QTyp) where {T} = $QTyp(convert(AbstractMatrix{T}, Q.factors), convert(AbstractVector{T}, Q.τ)) - $QTyp(Q::LinearAlgebra.$QTyp) = $QTyp(Q.factors, Q.τ) end end +QRPackedQ(Q::LinearAlgebra.QRPackedQ) = QRPackedQ(Q.factors, Q.τ) + const QRPackedQTypes{T,S<:AbstractMatrix{T},Tau<:AbstractVector{T}} = Union{QRPackedQ{T,S,Tau}, QRPackedQMatrix{T,S,Tau}} Matrix{T}(Q::QRPackedQTypes{S}) where {T,S} = convert(Matrix{T}, lmul!(Q, Matrix{S}(I, size(Q, 1), min(size(Q.factors)...)))) @@ -203,6 +204,7 @@ AbstractQ{T}(Q::QRPackedQ{T}) where {T} = Q AbstractQ{T}(Q::QRPackedQ) where {T} = QRPackedQ{T}(Q) AbstractQ{T}(Q::QRPackedQMatrix{T}) where {T} = QRPackedQ(Q.factors, Q.τ) AbstractQ{T}(Q::QRPackedQMatrix) where {T} = QRPackedQ{T}(Q.factors, Q.τ) +AbstractQ(Q::QRPackedQMatrix) = QRPackedQ(Q.factors, Q.τ) convert(::Type{AbstractQ{T}}, Q::QRPackedQ) where {T} = QRPackedQ{T}(Q) AbstractMatrix{T}(Q::QRPackedQ) where {T} = Matrix{T}(Q) @@ -250,3 +252,9 @@ function (\)(A::QR{T}, BIn::VecOrMat{Complex{T}}) where T<:BlasReal XX = reshape(collect(reinterpret(Complex{T}, copy(transpose(reshape(X, div(length(X), 2), 2))))), _ret_size(A, BIn)) return _cut_B(XX, 1:n) end + + + +# support lazy broadcasting + +BroadcastStyle(::Type{<:QRPackedQMatrix{<:Any,F}}) where {F} = BroadcastStyle(F) # TODO: broken for banded? \ No newline at end of file