Skip to content

Commit 9e122d5

Browse files
committed
Restrict the general \ definition that handles over- and underdetermined
systems to QR-like structs
1 parent d87949b commit 9e122d5

File tree

2 files changed

+51
-46
lines changed

2 files changed

+51
-46
lines changed

stdlib/LinearAlgebra/src/factorization.jl

Lines changed: 6 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -99,65 +99,25 @@ function (/)(B::VecOrMat{Complex{T}}, F::Factorization{T}) where T<:BlasReal
9999
return copy(reinterpret(Complex{T}, x))
100100
end
101101

102-
# convenience methods
103-
## return only the solution of a least squares problem while avoiding promoting
104-
## vectors to matrices.
105-
_cut_B(x::AbstractVector, r::UnitRange) = length(x) > length(r) ? x[r] : x
106-
_cut_B(X::AbstractMatrix, r::UnitRange) = size(X, 1) > length(r) ? X[r,:] : X
107-
108-
## append right hand side with zeros if necessary
109-
_zeros(::Type{T}, b::AbstractVector, n::Integer) where {T} = zeros(T, max(length(b), n))
110-
_zeros(::Type{T}, B::AbstractMatrix, n::Integer) where {T} = zeros(T, max(size(B, 1), n), size(B, 2))
111-
112-
# General fallback definition for handling under- and overdetermined system as well as square problems
113-
function \(F::Union{<:Factorization,Adjoint{<:Any,<:Factorization}}, B::AbstractVecOrMat)
114-
require_one_based_indexing(B)
115-
m, n = size(F)
116-
if m != size(B, 1)
117-
throw(DimensionMismatch("arguments must have the same number of rows"))
118-
end
119-
120-
TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F)))
121-
FF = Factorization{TFB}(F)
122-
123-
# For wide problem we (often) compute a minimum norm solution. The solution
124-
# is larger than the right hand side so we use size(F, 2).
125-
BB = _zeros(TFB, B, n)
126-
127-
if n > size(B, 1)
128-
# Underdetermined
129-
fill!(BB, 0)
130-
copyto!(view(BB, 1:m, :), B)
131-
else
132-
copyto!(BB, B)
133-
end
134-
135-
ldiv!(FF, BB)
136-
137-
# For tall problems, we compute a least sqaures solution so only part
138-
# of the rhs should be returned from \ while ldiv! uses (and returns)
139-
# the complete rhs
140-
return _cut_B(BB, 1:n)
141-
end
142-
143-
function /(B::AbstractMatrix, F::Factorization)
102+
function \(F::Union{Factorization, Adjoint{<:Any,<:Factorization}}, B::AbstractVecOrMat)
144103
require_one_based_indexing(B)
145104
TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F)))
146105
BB = similar(B, TFB, size(B))
147106
copyto!(BB, B)
148-
rdiv!(BB, F)
107+
ldiv!(F, BB)
149108
end
150-
function /(B::AbstractMatrix, adjF::Adjoint{<:Any,<:Factorization})
109+
110+
function /(B::AbstractMatrix, F::Union{Factorization, Adjoint{<:Any,<:Factorization}})
151111
require_one_based_indexing(B)
152-
F = adjF.parent
153112
TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F)))
154113
BB = similar(B, TFB, size(B))
155114
copyto!(BB, B)
156-
rdiv!(BB, adjoint(F))
115+
rdiv!(BB, F)
157116
end
158117
/(adjB::AdjointAbsVec, adjF::Adjoint{<:Any,<:Factorization}) = adjoint(adjF.parent \ adjB.parent)
159118
/(B::TransposeAbsVec, adjF::Adjoint{<:Any,<:Factorization}) = adjoint(adjF.parent \ adjoint(B))
160119

120+
161121
# support the same 3-arg idiom as in our other in-place A_*_B functions:
162122
function ldiv!(Y::AbstractVecOrMat, A::Factorization, B::AbstractVecOrMat)
163123
require_one_based_indexing(Y, B)

stdlib/LinearAlgebra/src/lq.jl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,51 @@ function (\)(F::LQ{T}, B::VecOrMat{Complex{T}}) where T<:BlasReal
331331
end
332332

333333

334+
# convenience methods
335+
## return only the solution of a least squares problem while avoiding promoting
336+
## vectors to matrices.
337+
_cut_B(x::AbstractVector, r::UnitRange) = length(x) > length(r) ? x[r] : x
338+
_cut_B(X::AbstractMatrix, r::UnitRange) = size(X, 1) > length(r) ? X[r,:] : X
339+
340+
## append right hand side with zeros if necessary
341+
_zeros(::Type{T}, b::AbstractVector, n::Integer) where {T} = zeros(T, max(length(b), n))
342+
_zeros(::Type{T}, B::AbstractMatrix, n::Integer) where {T} = zeros(T, max(size(B, 1), n), size(B, 2))
343+
344+
# General fallback definition for handling under- and overdetermined system as well as square problems
345+
# While this definition is pretty general, it does e.g. promote to common element type of lhs and rhs
346+
# which is required by LAPACK but not SuiteSpase which allows real-complex solves in some cases. Hence,
347+
# we restrict this method to only the QRLike factorizations in LinearAlgebra.
348+
const QRLike{T,S} = Union{QR{T,S}, QRCompactWY{T,S}, QRPivoted{T,S}, LQ{T,S}}
349+
function \(F::Union{<:QRLike,Adjoint{<:Any,<:QRLike}}, B::AbstractVecOrMat)
350+
require_one_based_indexing(B)
351+
m, n = size(F)
352+
if m != size(B, 1)
353+
throw(DimensionMismatch("arguments must have the same number of rows"))
354+
end
355+
356+
TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F)))
357+
FF = Factorization{TFB}(F)
358+
359+
# For wide problem we (often) compute a minimum norm solution. The solution
360+
# is larger than the right hand side so we use size(F, 2).
361+
BB = _zeros(TFB, B, n)
362+
363+
if n > size(B, 1)
364+
# Underdetermined
365+
fill!(BB, 0)
366+
copyto!(view(BB, 1:m, :), B)
367+
else
368+
copyto!(BB, B)
369+
end
370+
371+
ldiv!(FF, BB)
372+
373+
# For tall problems, we compute a least sqaures solution so only part
374+
# of the rhs should be returned from \ while ldiv! uses (and returns)
375+
# the complete rhs
376+
return _cut_B(BB, 1:n)
377+
end
378+
334379
function ldiv!(A::LQ, B::StridedVecOrMat)
335380
require_one_based_indexing(B)
336381
m, n = size(A)

0 commit comments

Comments
 (0)