|
465 | 465 | Base.propertynames(F::QRPivoted, private::Bool=false) = |
466 | 466 | (:R, :Q, :p, :P, (private ? fieldnames(typeof(F)) : ())...) |
467 | 467 |
|
| 468 | +adjoint(F::Union{QR,QRPivoted,QRCompactWY}) = Adjoint(F) |
| 469 | + |
468 | 470 | abstract type AbstractQ{T} <: AbstractMatrix{T} end |
469 | 471 |
|
470 | 472 | inv(Q::AbstractQ) = Q' |
@@ -932,28 +934,35 @@ function ldiv!(A::QRPivoted, B::StridedMatrix) |
932 | 934 | B |
933 | 935 | end |
934 | 936 |
|
935 | | -# convenience methods |
936 | | -## return only the solution of a least squares problem while avoiding promoting |
937 | | -## vectors to matrices. |
938 | | -_cut_B(x::AbstractVector, r::UnitRange) = length(x) > length(r) ? x[r] : x |
939 | | -_cut_B(X::AbstractMatrix, r::UnitRange) = size(X, 1) > length(r) ? X[r,:] : X |
940 | | - |
941 | | -## append right hand side with zeros if necessary |
942 | | -_zeros(::Type{T}, b::AbstractVector, n::Integer) where {T} = zeros(T, max(length(b), n)) |
943 | | -_zeros(::Type{T}, B::AbstractMatrix, n::Integer) where {T} = zeros(T, max(size(B, 1), n), size(B, 2)) |
| 937 | +function _apply_permutation!(F::QRPivoted, B::AbstractVecOrMat) |
| 938 | + # Apply permutation but only to the top part of the solution vector since |
| 939 | + # it's padded with zeros for underdetermined problems |
| 940 | + B[1:length(F.p), :] = B[F.p, :] |
| 941 | + return B |
| 942 | +end |
| 943 | +_apply_permutation!(F::Factorization, B::AbstractVecOrMat) = B |
944 | 944 |
|
945 | | -function (\)(A::Union{QR{TA},QRCompactWY{TA},QRPivoted{TA}}, B::AbstractVecOrMat{TB}) where {TA,TB} |
| 945 | +function ldiv!(Fadj::Adjoint{<:Any,<:Union{QR,QRCompactWY,QRPivoted}}, B::AbstractVecOrMat) |
946 | 946 | require_one_based_indexing(B) |
947 | | - S = promote_type(TA,TB) |
948 | | - m, n = size(A) |
949 | | - m == size(B,1) || throw(DimensionMismatch("Both inputs should have the same number of rows")) |
| 947 | + m, n = size(Fadj) |
950 | 948 |
|
951 | | - AA = Factorization{S}(A) |
| 949 | + # We don't allow solutions overdetermined systems. It would at least be |
| 950 | + if m > n |
| 951 | + throw(DimensionMismatch("overdetermined systems are not supported")) |
| 952 | + end |
| 953 | + if n != size(B, 1) |
| 954 | + throw(DimensionMismatch("inputs should have the same number of rows")) |
| 955 | + end |
| 956 | + F = parent(Fadj) |
952 | 957 |
|
953 | | - X = _zeros(S, B, n) |
954 | | - X[1:size(B, 1), :] = B |
955 | | - ldiv!(AA, X) |
956 | | - return _cut_B(X, 1:n) |
| 958 | + B = _apply_permutation!(F, B) |
| 959 | + |
| 960 | + # For underdetermined system, the triangular solve should only be applied to the top |
| 961 | + # part of B that contains the rhs. For square problems, the view corresponds to B itself |
| 962 | + ldiv!(LowerTriangular(adjoint(F.R)), view(B, 1:size(F.R, 2), :)) |
| 963 | + lmul!(F.Q, B) |
| 964 | + |
| 965 | + return B |
957 | 966 | end |
958 | 967 |
|
959 | 968 | # With a real lhs and complex rhs with the same precision, we can reinterpret the complex |
|
0 commit comments