Add: julia-0.6.2

Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
2018-02-10 10:27:19 -07:00
parent 94220957d7
commit 019f8e3064
723 changed files with 276164 additions and 0 deletions

View File

@@ -0,0 +1,847 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license
# QR and Hessenberg Factorizations
"""
QR <: Factorization
A QR matrix factorization stored in a packed format, typically obtained from
[`qrfact`](@ref). If ``A`` is an `m`×`n` matrix, then
```math
A = Q R
```
where ``Q`` is an orthogonal/unitary matrix and ``R`` is upper triangular.
The matrix ``Q`` is stored as a sequence of Householder reflectors ``v_i``
and coefficients ``\\tau_i`` where:
```math
Q = \\prod_{i=1}^{\\min(m,n)} (I - \\tau_i v_i v_i^T).
```
The object has two fields:
* `factors` is an `m`×`n` matrix.
- The upper triangular part contains the elements of ``R``, that is `R =
triu(F.factors)` for a `QR` object `F`.
- The subdiagonal part contains the reflectors ``v_i`` stored in a packed format where
``v_i`` is the ``i``th column of the matrix `V = eye(m,n) + tril(F.factors,-1)`.
* `τ` is a vector of length `min(m,n)` containing the coefficients ``\tau_i``.
"""
struct QR{T,S<:AbstractMatrix} <: Factorization{T}
factors::S
τ::Vector{T}
QR{T,S}(factors::AbstractMatrix{T}, τ::Vector{T}) where {T,S<:AbstractMatrix} = new(factors, τ)
end
QR(factors::AbstractMatrix{T}, τ::Vector{T}) where {T} = QR{T,typeof(factors)}(factors, τ)
# Note. For QRCompactWY factorization without pivoting, the WY representation based method introduced in LAPACK 3.4
"""
QRCompactWY <: Factorization
A QR matrix factorization stored in a compact blocked format, typically obtained from
[`qrfact`](@ref). If ``A`` is an `m`×`n` matrix, then
```math
A = Q R
```
where ``Q`` is an orthogonal/unitary matrix and ``R`` is upper triangular. It is similar
to the [`QR`](@ref) format except that the orthogonal/unitary matrix ``Q`` is stored in
*Compact WY* format [^Schreiber1989], as a lower trapezoidal matrix ``V`` and an upper
triangular matrix ``T`` where
```math
Q = \\prod_{i=1}^{\\min(m,n)} (I - \\tau_i v_i v_i^T) = I - V T V^T
```
such that ``v_i`` is the ``i``th column of ``V``, and ``\tau_i`` is the ``i``th diagonal
element of ``T``.
The object has two fields:
* `factors`, as in the [`QR`](@ref) type, is an `m`×`n` matrix.
- The upper triangular part contains the elements of ``R``, that is `R =
triu(F.factors)` for a `QR` object `F`.
- The subdiagonal part contains the reflectors ``v_i`` stored in a packed format such
that `V = eye(m,n) + tril(F.factors,-1)`.
* `T` is a square matrix with `min(m,n)` columns, whose upper triangular part gives the
matrix ``T`` above (the subdiagonal elements are ignored).
!!! note
This format should not to be confused with the older *WY* representation
[^Bischof1987].
[^Bischof1987]: C Bischof and C Van Loan, "The WY representation for products of Householder matrices", SIAM J Sci Stat Comput 8 (1987), s2-s13. [doi:10.1137/0908009](http://dx.doi.org/10.1137/0908009)
[^Schreiber1989]: R Schreiber and C Van Loan, "A storage-efficient WY representation for products of Householder transformations", SIAM J Sci Stat Comput 10 (1989), 53-57. [doi:10.1137/0910005](http://dx.doi.org/10.1137/0910005)
"""
struct QRCompactWY{S,M<:AbstractMatrix} <: Factorization{S}
factors::M
T::Matrix{S}
QRCompactWY{S,M}(factors::AbstractMatrix{S}, T::AbstractMatrix{S}) where {S,M<:AbstractMatrix} = new(factors, T)
end
QRCompactWY(factors::AbstractMatrix{S}, T::AbstractMatrix{S}) where {S} = QRCompactWY{S,typeof(factors)}(factors, T)
"""
QRPivoted <: Factorization
A QR matrix factorization with column pivoting in a packed format, typically obtained from
[`qrfact`](@ref). If ``A`` is an `m`×`n` matrix, then
```math
A P = Q R
```
where ``P`` is a permutation matrix, ``Q`` is an orthogonal/unitary matrix and ``R`` is
upper triangular. The matrix ``Q`` is stored as a sequence of Householder reflectors:
```math
Q = \\prod_{i=1}^{\\min(m,n)} (I - \\tau_i v_i v_i^T).
```
The object has three fields:
* `factors` is an `m`×`n` matrix.
- The upper triangular part contains the elements of ``R``, that is `R =
triu(F.factors)` for a `QR` object `F`.
- The subdiagonal part contains the reflectors ``v_i`` stored in a packed format where
``v_i`` is the ``i``th column of the matrix `V = eye(m,n) + tril(F.factors,-1)`.
* `τ` is a vector of length `min(m,n)` containing the coefficients ``\tau_i``.
* `jpvt` is an integer vector of length `n` corresponding to the permutation ``P``.
"""
struct QRPivoted{T,S<:AbstractMatrix} <: Factorization{T}
factors::S
τ::Vector{T}
jpvt::Vector{BlasInt}
QRPivoted{T,S}(factors::AbstractMatrix{T}, τ::Vector{T}, jpvt::Vector{BlasInt}) where {T,S<:AbstractMatrix} =
new(factors, τ, jpvt)
end
QRPivoted(factors::AbstractMatrix{T}, τ::Vector{T}, jpvt::Vector{BlasInt}) where {T} =
QRPivoted{T,typeof(factors)}(factors, τ, jpvt)
function qrfactUnblocked!(A::AbstractMatrix{T}) where {T}
m, n = size(A)
τ = zeros(T, min(m,n))
for k = 1:min(m - 1 + !(T<:Real), n)
x = view(A, k:m, k)
τk = reflector!(x)
τ[k] = τk
reflectorApply!(x, τk, view(A, k:m, k + 1:n))
end
QR(A, τ)
end
# Find index for columns with largest two norm
function indmaxcolumn(A::StridedMatrix)
mm = norm(view(A, :, 1))
ii = 1
for i = 2:size(A, 2)
mi = norm(view(A, :, i))
if abs(mi) > mm
mm = mi
ii = i
end
end
return ii
end
function qrfactPivotedUnblocked!(A::StridedMatrix)
m, n = size(A)
piv = collect(UnitRange{BlasInt}(1,n))
τ = Vector{eltype(A)}(min(m,n))
for j = 1:min(m,n)
# Find column with maximum norm in trailing submatrix
jm = indmaxcolumn(view(A, j:m, j:n)) + j - 1
if jm != j
# Flip elements in pivoting vector
tmpp = piv[jm]
piv[jm] = piv[j]
piv[j] = tmpp
# Update matrix with
for i = 1:m
tmp = A[i,jm]
A[i,jm] = A[i,j]
A[i,j] = tmp
end
end
# Compute reflector of columns j
x = view(A, j:m, j)
τj = LinAlg.reflector!(x)
τ[j] = τj
# Update trailing submatrix with reflector
LinAlg.reflectorApply!(x, τj, view(A, j:m, j+1:n))
end
return LinAlg.QRPivoted{eltype(A), typeof(A)}(A, τ, piv)
end
# LAPACK version
qrfact!(A::StridedMatrix{<:BlasFloat}, ::Type{Val{false}}) = QRCompactWY(LAPACK.geqrt!(A, min(minimum(size(A)), 36))...)
qrfact!(A::StridedMatrix{<:BlasFloat}, ::Type{Val{true}}) = QRPivoted(LAPACK.geqp3!(A)...)
qrfact!(A::StridedMatrix{<:BlasFloat}) = qrfact!(A, Val{false})
# Generic fallbacks
"""
qrfact!(A, pivot=Val{false})
`qrfact!` is the same as [`qrfact`](@ref) when `A` is a subtype of
`StridedMatrix`, but saves space by overwriting the input `A`, instead of creating a copy.
An [`InexactError`](@ref) exception is thrown if the factorization produces a number not
representable by the element type of `A`, e.g. for integer types.
"""
qrfact!(A::StridedMatrix, ::Type{Val{false}}) = qrfactUnblocked!(A)
qrfact!(A::StridedMatrix, ::Type{Val{true}}) = qrfactPivotedUnblocked!(A)
qrfact!(A::StridedMatrix) = qrfact!(A, Val{false})
"""
qrfact(A, pivot=Val{false}) -> F
Compute the QR factorization of the matrix `A`: an orthogonal (or unitary if `A` is
complex-valued) matrix `Q`, and an upper triangular matrix `R` such that
```math
A = Q R
```
The returned object `F` stores the factorization in a packed format:
- if `pivot == Val{true}` then `F` is a [`QRPivoted`](@ref) object,
- otherwise if the element type of `A` is a BLAS type ([`Float32`](@ref), [`Float64`](@ref),
`Complex64` or `Complex128`), then `F` is a [`QRCompactWY`](@ref) object,
- otherwise `F` is a [`QR`](@ref) object.
The individual components of the factorization `F` can be accessed by indexing with a symbol:
- `F[:Q]`: the orthogonal/unitary matrix `Q`
- `F[:R]`: the upper triangular matrix `R`
- `F[:p]`: the permutation vector of the pivot ([`QRPivoted`](@ref) only)
- `F[:P]`: the permutation matrix of the pivot ([`QRPivoted`](@ref) only)
The following functions are available for the `QR` objects: [`inv`](@ref), [`size`](@ref),
and [`\\`](@ref). When `A` is rectangular, `\\` will return a least squares
solution and if the solution is not unique, the one with smallest norm is returned.
Multiplication with respect to either thin or full `Q` is allowed, i.e. both `F[:Q]*F[:R]`
and `F[:Q]*A` are supported. A `Q` matrix can be converted into a regular matrix with
[`full`](@ref) which has a named argument `thin`.
# Example
```jldoctest
julia> A = [3.0 -6.0; 4.0 -8.0; 0.0 1.0]
3×2 Array{Float64,2}:
3.0 -6.0
4.0 -8.0
0.0 1.0
julia> F = qrfact(A)
Base.LinAlg.QRCompactWY{Float64,Array{Float64,2}} with factors Q and R:
[-0.6 0.0 0.8; -0.8 0.0 -0.6; 0.0 -1.0 0.0]
[-5.0 10.0; 0.0 -1.0]
julia> F[:Q] * F[:R] == A
true
```
!!! note
`qrfact` returns multiple types because LAPACK uses several representations
that minimize the memory storage requirements of products of Householder
elementary reflectors, so that the `Q` and `R` matrices can be stored
compactly rather as two separate dense matrices.
"""
function qrfact(A::AbstractMatrix{T}, arg) where T
AA = similar(A, typeof(zero(T)/norm(one(T))), size(A))
copy!(AA, A)
return qrfact!(AA, arg)
end
function qrfact(A::AbstractMatrix{T}) where T
AA = similar(A, typeof(zero(T)/norm(one(T))), size(A))
copy!(AA, A)
return qrfact!(AA)
end
qrfact(x::Number) = qrfact(fill(x,1,1))
"""
qr(A, pivot=Val{false}; thin::Bool=true) -> Q, R, [p]
Compute the (pivoted) QR factorization of `A` such that either `A = Q*R` or `A[:,p] = Q*R`.
Also see [`qrfact`](@ref).
The default is to compute a thin factorization. Note that `R` is not
extended with zeros when the full `Q` is requested.
"""
qr(A::Union{Number, AbstractMatrix}, pivot::Union{Type{Val{false}}, Type{Val{true}}}=Val{false}; thin::Bool=true) =
_qr(A, pivot, thin=thin)
function _qr(A::Union{Number, AbstractMatrix}, ::Type{Val{false}}; thin::Bool=true)
F = qrfact(A, Val{false})
full(getq(F), thin=thin), F[:R]::Matrix{eltype(F)}
end
function _qr(A::Union{Number, AbstractMatrix}, ::Type{Val{true}}; thin::Bool=true)
F = qrfact(A, Val{true})
full(getq(F), thin=thin), F[:R]::Matrix{eltype(F)}, F[:p]::Vector{BlasInt}
end
"""
qr(v::AbstractVector) -> w, r
Computes the polar decomposition of a vector.
Returns `w`, a unit vector in the direction of `v`, and
`r`, the norm of `v`.
See also [`normalize`](@ref), [`normalize!`](@ref),
and [`LinAlg.qr!`](@ref).
# Example
```jldoctest
julia> v = [1; 2]
2-element Array{Int64,1}:
1
2
julia> w, r = qr(v)
([0.447214, 0.894427], 2.23606797749979)
julia> w*r == v
true
```
"""
function qr(v::AbstractVector)
nrm = norm(v)
if !isempty(v)
vv = copy_oftype(v, typeof(v[1]/nrm))
return __normalize!(vv, nrm), nrm
else
T = typeof(zero(eltype(v))/nrm)
return T[], oneunit(T)
end
end
"""
LinAlg.qr!(v::AbstractVector) -> w, r
Computes the polar decomposition of a vector. Instead of returning a new vector
as `qr(v::AbstractVector)`, this function mutates the input vector `v` in place.
Returns `w`, a unit vector in the direction of `v` (this is a mutation of `v`),
and `r`, the norm of `v`.
See also [`normalize`](@ref), [`normalize!`](@ref),
and [`qr`](@ref).
"""
function qr!(v::AbstractVector)
nrm = norm(v)
__normalize!(v, nrm), nrm
end
# Conversions
convert(::Type{QR{T}}, A::QR) where {T} = QR(convert(AbstractMatrix{T}, A.factors), convert(Vector{T}, A.τ))
convert(::Type{Factorization{T}}, A::QR{T}) where {T} = A
convert(::Type{Factorization{T}}, A::QR) where {T} = convert(QR{T}, A)
convert(::Type{QRCompactWY{T}}, A::QRCompactWY) where {T} = QRCompactWY(convert(AbstractMatrix{T}, A.factors), convert(AbstractMatrix{T}, A.T))
convert(::Type{Factorization{T}}, A::QRCompactWY{T}) where {T} = A
convert(::Type{Factorization{T}}, A::QRCompactWY) where {T} = convert(QRCompactWY{T}, A)
convert(::Type{AbstractMatrix}, F::Union{QR,QRCompactWY}) = F[:Q] * F[:R]
convert(::Type{AbstractArray}, F::Union{QR,QRCompactWY}) = convert(AbstractMatrix, F)
convert(::Type{Matrix}, F::Union{QR,QRCompactWY}) = convert(Array, convert(AbstractArray, F))
convert(::Type{Array}, F::Union{QR,QRCompactWY}) = convert(Matrix, F)
full(F::Union{QR,QRCompactWY}) = convert(AbstractArray, F)
convert(::Type{QRPivoted{T}}, A::QRPivoted) where {T} = QRPivoted(convert(AbstractMatrix{T}, A.factors), convert(Vector{T}, A.τ), A.jpvt)
convert(::Type{Factorization{T}}, A::QRPivoted{T}) where {T} = A
convert(::Type{Factorization{T}}, A::QRPivoted) where {T} = convert(QRPivoted{T}, A)
convert(::Type{AbstractMatrix}, F::QRPivoted) = (F[:Q] * F[:R])[:,invperm(F[:p])]
convert(::Type{AbstractArray}, F::QRPivoted) = convert(AbstractMatrix, F)
convert(::Type{Matrix}, F::QRPivoted) = convert(Array, convert(AbstractArray, F))
convert(::Type{Array}, F::QRPivoted) = convert(Matrix, F)
full(F::QRPivoted) = convert(AbstractArray, F)
function show(io::IO, F::Union{QR, QRCompactWY, QRPivoted})
println(io, "$(typeof(F)) with factors Q and R:")
show(io, F[:Q])
println(io)
show(io, F[:R])
end
function getindex(A::QR, d::Symbol)
m, n = size(A)
if d == :R
return triu!(A.factors[1:min(m,n), 1:n])
elseif d == :Q
return getq(A)
else
throw(KeyError(d))
end
end
function getindex(A::QRCompactWY, d::Symbol)
m, n = size(A)
if d == :R
return triu!(A.factors[1:min(m,n), 1:n])
elseif d == :Q
return getq(A)
else
throw(KeyError(d))
end
end
function getindex(A::QRPivoted{T}, d::Symbol) where T
m, n = size(A)
if d == :R
return triu!(A.factors[1:min(m,n), 1:n])
elseif d == :Q
return getq(A)
elseif d == :p
return A.jpvt
elseif d == :P
p = A[:p]
n = length(p)
P = zeros(T, n, n)
for i in 1:n
P[p[i],i] = one(T)
end
return P
else
throw(KeyError(d))
end
end
# Type-stable interface to get Q
getq(A::QRCompactWY) = QRCompactWYQ(A.factors,A.T)
getq(A::Union{QR, QRPivoted}) = QRPackedQ(A.factors,A.τ)
"""
QRPackedQ <: AbstractMatrix
The orthogonal/unitary ``Q`` matrix of a QR factorization stored in [`QR`](@ref) or
[`QRPivoted`](@ref) format.
"""
struct QRPackedQ{T,S<:AbstractMatrix} <: AbstractMatrix{T}
factors::S
τ::Vector{T}
QRPackedQ{T,S}(factors::AbstractMatrix{T}, τ::Vector{T}) where {T,S<:AbstractMatrix} = new(factors, τ)
end
QRPackedQ(factors::AbstractMatrix{T}, τ::Vector{T}) where {T} = QRPackedQ{T,typeof(factors)}(factors, τ)
"""
QRCompactWYQ <: AbstractMatrix
The orthogonal/unitary ``Q`` matrix of a QR factorization stored in [`QRCompactWY`](@ref)
format.
"""
struct QRCompactWYQ{S, M<:AbstractMatrix} <: AbstractMatrix{S}
factors::M
T::Matrix{S}
QRCompactWYQ{S,M}(factors::AbstractMatrix{S}, T::Matrix{S}) where {S,M<:AbstractMatrix} = new(factors, T)
end
QRCompactWYQ(factors::AbstractMatrix{S}, T::Matrix{S}) where {S} = QRCompactWYQ{S,typeof(factors)}(factors, T)
convert(::Type{QRPackedQ{T}}, Q::QRPackedQ) where {T} = QRPackedQ(convert(AbstractMatrix{T}, Q.factors), convert(Vector{T}, Q.τ))
convert(::Type{AbstractMatrix{T}}, Q::QRPackedQ{T}) where {T} = Q
convert(::Type{AbstractMatrix{T}}, Q::QRPackedQ) where {T} = convert(QRPackedQ{T}, Q)
convert(::Type{QRCompactWYQ{S}}, Q::QRCompactWYQ) where {S} = QRCompactWYQ(convert(AbstractMatrix{S}, Q.factors), convert(AbstractMatrix{S}, Q.T))
convert(::Type{AbstractMatrix{S}}, Q::QRCompactWYQ{S}) where {S} = Q
convert(::Type{AbstractMatrix{S}}, Q::QRCompactWYQ) where {S} = convert(QRCompactWYQ{S}, Q)
convert(::Type{Matrix}, A::Union{QRPackedQ{T},QRCompactWYQ{T}}) where {T} = A_mul_B!(A, eye(T, size(A.factors, 1), minimum(size(A.factors))))
convert(::Type{Array}, A::Union{QRPackedQ,QRCompactWYQ}) = convert(Matrix, A)
"""
full(A::Union{QRPackedQ,QRCompactWYQ}; thin::Bool=true) -> Matrix
Converts an orthogonal or unitary matrix stored as a `QRCompactWYQ` object, i.e. in the
compact WY format [^Bischof1987], or in the `QRPackedQ` format, to a dense matrix.
Optionally takes a `thin` Boolean argument, which if `true` omits the columns that span the
rows of `R` in the QR factorization that are zero. The resulting matrix is the `Q` in a thin
QR factorization (sometimes called the reduced QR factorization). If `false`, returns a `Q`
that spans all rows of `R` in its corresponding QR factorization.
"""
function full{T}(A::Union{QRPackedQ{T},QRCompactWYQ{T}}; thin::Bool = true)
if thin
convert(Array, A)
else
A_mul_B!(A, eye(T, size(A.factors, 1)))
end
end
size(A::Union{QR,QRCompactWY,QRPivoted}, dim::Integer) = size(A.factors, dim)
size(A::Union{QR,QRCompactWY,QRPivoted}) = size(A.factors)
size(A::Union{QRPackedQ,QRCompactWYQ}, dim::Integer) = 0 < dim ? (dim <= 2 ? size(A.factors, 1) : 1) : throw(BoundsError())
size(A::Union{QRPackedQ,QRCompactWYQ}) = size(A, 1), size(A, 2)
function getindex(A::Union{QRPackedQ,QRCompactWYQ}, i::Integer, j::Integer)
x = zeros(eltype(A), size(A, 1))
x[i] = 1
y = zeros(eltype(A), size(A, 2))
y[j] = 1
return dot(x, A_mul_B!(A, y))
end
## Multiplication by Q
### QB
A_mul_B!(A::QRCompactWYQ{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = LAPACK.gemqrt!('L','N',A.factors,A.T,B)
A_mul_B!(A::QRPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = LAPACK.ormqr!('L','N',A.factors,A.τ,B)
function A_mul_B!(A::QRPackedQ, B::AbstractVecOrMat)
mA, nA = size(A.factors)
mB, nB = size(B,1), size(B,2)
if mA != mB
throw(DimensionMismatch("matrix A has dimensions ($mA,$nA) but B has dimensions ($mB, $nB)"))
end
Afactors = A.factors
@inbounds begin
for k = min(mA,nA):-1:1
for j = 1:nB
vBj = B[k,j]
for i = k+1:mB
vBj += conj(Afactors[i,k])*B[i,j]
end
vBj = A.τ[k]*vBj
B[k,j] -= vBj
for i = k+1:mB
B[i,j] -= Afactors[i,k]*vBj
end
end
end
end
B
end
function (*)(A::Union{QRPackedQ,QRCompactWYQ}, b::StridedVector)
TAb = promote_type(eltype(A), eltype(b))
Anew = convert(AbstractMatrix{TAb}, A)
if size(A.factors, 1) == length(b)
bnew = copy_oftype(b, TAb)
elseif size(A.factors, 2) == length(b)
bnew = [b; zeros(TAb, size(A.factors, 1) - length(b))]
else
throw(DimensionMismatch("vector must have length either $(size(A.factors, 1)) or $(size(A.factors, 2))"))
end
A_mul_B!(Anew, bnew)
end
function (*)(A::Union{QRPackedQ,QRCompactWYQ}, B::StridedMatrix)
TAB = promote_type(eltype(A), eltype(B))
Anew = convert(AbstractMatrix{TAB}, A)
if size(A.factors, 1) == size(B, 1)
Bnew = copy_oftype(B, TAB)
elseif size(A.factors, 2) == size(B, 1)
Bnew = [B; zeros(TAB, size(A.factors, 1) - size(B,1), size(B, 2))]
else
throw(DimensionMismatch("first dimension of matrix must have size either $(size(A.factors, 1)) or $(size(A.factors, 2))"))
end
A_mul_B!(Anew, Bnew)
end
### QcB
Ac_mul_B!(A::QRCompactWYQ{T}, B::StridedVecOrMat{T}) where {T<:BlasReal} = LAPACK.gemqrt!('L','T',A.factors,A.T,B)
Ac_mul_B!(A::QRCompactWYQ{T}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = LAPACK.gemqrt!('L','C',A.factors,A.T,B)
Ac_mul_B!(A::QRPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasReal} = LAPACK.ormqr!('L','T',A.factors,A.τ,B)
Ac_mul_B!(A::QRPackedQ{T}, B::StridedVecOrMat{T}) where {T<:BlasComplex} = LAPACK.ormqr!('L','C',A.factors,A.τ,B)
function Ac_mul_B!(A::QRPackedQ, B::AbstractVecOrMat)
mA, nA = size(A.factors)
mB, nB = size(B,1), size(B,2)
if mA != mB
throw(DimensionMismatch("matrix A has dimensions ($mA,$nA) but B has dimensions ($mB, $nB)"))
end
Afactors = A.factors
@inbounds begin
for k = 1:min(mA,nA)
for j = 1:nB
vBj = B[k,j]
for i = k+1:mB
vBj += conj(Afactors[i,k])*B[i,j]
end
vBj = conj(A.τ[k])*vBj
B[k,j] -= vBj
for i = k+1:mB
B[i,j] -= Afactors[i,k]*vBj
end
end
end
end
B
end
function Ac_mul_B(Q::Union{QRPackedQ,QRCompactWYQ}, B::StridedVecOrMat)
TQB = promote_type(eltype(Q), eltype(B))
return Ac_mul_B!(convert(AbstractMatrix{TQB}, Q), copy_oftype(B, TQB))
end
### QBc/QcBc
for (f1, f2) in ((:A_mul_Bc, :A_mul_B!),
(:Ac_mul_Bc, :Ac_mul_B!))
@eval begin
function ($f1)(Q::Union{QRPackedQ,QRCompactWYQ}, B::StridedVecOrMat)
TQB = promote_type(eltype(Q), eltype(B))
Bc = similar(B, TQB, (size(B, 2), size(B, 1)))
ctranspose!(Bc, B)
return ($f2)(convert(AbstractMatrix{TQB}, Q), Bc)
end
end
end
### AQ
A_mul_B!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T}) where {T<:BlasFloat} = LAPACK.gemqrt!('R','N', B.factors, B.T, A)
A_mul_B!(A::StridedVecOrMat{T}, B::QRPackedQ{T}) where {T<:BlasFloat} = LAPACK.ormqr!('R', 'N', B.factors, B.τ, A)
function A_mul_B!(A::StridedMatrix,Q::QRPackedQ)
mQ, nQ = size(Q.factors)
mA, nA = size(A,1), size(A,2)
if nA != mQ
throw(DimensionMismatch("matrix A has dimensions ($mA,$nA) but matrix Q has dimensions ($mQ, $nQ)"))
end
Qfactors = Q.factors
@inbounds begin
for k = 1:min(mQ,nQ)
for i = 1:mA
vAi = A[i,k]
for j = k+1:mQ
vAi += A[i,j]*Qfactors[j,k]
end
vAi = vAi*Q.τ[k]
A[i,k] -= vAi
for j = k+1:nA
A[i,j] -= vAi*conj(Qfactors[j,k])
end
end
end
end
A
end
function (*)(A::StridedMatrix, Q::Union{QRPackedQ,QRCompactWYQ})
TAQ = promote_type(eltype(A), eltype(Q))
return A_mul_B!(copy_oftype(A, TAQ), convert(AbstractMatrix{TAQ}, Q))
end
### AQc
A_mul_Bc!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T}) where {T<:BlasReal} = LAPACK.gemqrt!('R','T',B.factors,B.T,A)
A_mul_Bc!(A::StridedVecOrMat{T}, B::QRCompactWYQ{T}) where {T<:BlasComplex} = LAPACK.gemqrt!('R','C',B.factors,B.T,A)
A_mul_Bc!(A::StridedVecOrMat{T}, B::QRPackedQ{T}) where {T<:BlasReal} = LAPACK.ormqr!('R','T',B.factors,B.τ,A)
A_mul_Bc!(A::StridedVecOrMat{T}, B::QRPackedQ{T}) where {T<:BlasComplex} = LAPACK.ormqr!('R','C',B.factors,B.τ,A)
function A_mul_Bc!(A::AbstractMatrix,Q::QRPackedQ)
mQ, nQ = size(Q.factors)
mA, nA = size(A,1), size(A,2)
if nA != mQ
throw(DimensionMismatch("matrix A has dimensions ($mA,$nA) but matrix Q has dimensions ($mQ, $nQ)"))
end
Qfactors = Q.factors
@inbounds begin
for k = min(mQ,nQ):-1:1
for i = 1:mA
vAi = A[i,k]
for j = k+1:mQ
vAi += A[i,j]*Qfactors[j,k]
end
vAi = vAi*conj(Q.τ[k])
A[i,k] -= vAi
for j = k+1:nA
A[i,j] -= vAi*conj(Qfactors[j,k])
end
end
end
end
A
end
function A_mul_Bc(A::AbstractMatrix, B::Union{QRCompactWYQ,QRPackedQ})
TAB = promote_type(eltype(A),eltype(B))
BB = convert(AbstractMatrix{TAB}, B)
if size(A,2) == size(B.factors, 1)
AA = similar(A, TAB, size(A))
copy!(AA, A)
return A_mul_Bc!(AA, BB)
elseif size(A,2) == size(B.factors,2)
return A_mul_Bc!([A zeros(TAB, size(A, 1), size(B.factors, 1) - size(B.factors, 2))], BB)
else
throw(DimensionMismatch("matrix A has dimensions $(size(A)) but matrix B has dimensions $(size(B))"))
end
end
@inline A_mul_Bc(rowvec::RowVector, B::Union{LinAlg.QRCompactWYQ,LinAlg.QRPackedQ}) = ctranspose(B*ctranspose(rowvec))
### AcQ/AcQc
for (f1, f2) in ((:Ac_mul_B, :A_mul_B!),
(:Ac_mul_Bc, :A_mul_Bc!))
@eval begin
function ($f1)(A::StridedVecOrMat, Q::Union{QRPackedQ,QRCompactWYQ})
TAQ = promote_type(eltype(A), eltype(Q))
Ac = similar(A, TAQ, (size(A, 2), size(A, 1)))
ctranspose!(Ac, A)
return ($f2)(Ac, convert(AbstractMatrix{TAQ}, Q))
end
end
end
A_ldiv_B!(A::QRCompactWY{T}, b::StridedVector{T}) where {T<:BlasFloat} = (A_ldiv_B!(UpperTriangular(A[:R]), view(Ac_mul_B!(A[:Q], b), 1:size(A, 2))); b)
A_ldiv_B!(A::QRCompactWY{T}, B::StridedMatrix{T}) where {T<:BlasFloat} = (A_ldiv_B!(UpperTriangular(A[:R]), view(Ac_mul_B!(A[:Q], B), 1:size(A, 2), 1:size(B, 2))); B)
# Julia implementation similarly to xgelsy
function A_ldiv_B!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:BlasFloat
mA, nA = size(A.factors)
nr = min(mA,nA)
nrhs = size(B, 2)
if nr == 0
return B, 0
end
ar = abs(A.factors[1])
if ar == 0
B[1:nA, :] = 0
return B, 0
end
rnk = 1
xmin = ones(T, 1)
xmax = ones(T, 1)
tmin = tmax = ar
while rnk < nr
tmin, smin, cmin = LAPACK.laic1!(2, xmin, tmin, view(A.factors, 1:rnk, rnk + 1), A.factors[rnk + 1, rnk + 1])
tmax, smax, cmax = LAPACK.laic1!(1, xmax, tmax, view(A.factors, 1:rnk, rnk + 1), A.factors[rnk + 1, rnk + 1])
tmax*rcond > tmin && break
push!(xmin, cmin)
push!(xmax, cmax)
for i = 1:rnk
xmin[i] *= smin
xmax[i] *= smax
end
rnk += 1
end
C, τ = LAPACK.tzrzf!(A.factors[1:rnk,:])
A_ldiv_B!(UpperTriangular(C[1:rnk,1:rnk]),view(Ac_mul_B!(getq(A),view(B, 1:mA, 1:nrhs)),1:rnk,1:nrhs))
B[rnk+1:end,:] = zero(T)
LAPACK.ormrz!('L', eltype(B)<:Complex ? 'C' : 'T', C, τ, view(B,1:nA,1:nrhs))
B[1:nA,:] = view(B, 1:nA, :)[invperm(A[:p]::Vector{BlasInt}),:]
return B, rnk
end
A_ldiv_B!(A::QRPivoted{T}, B::StridedVector{T}) where {T<:BlasFloat} = vec(A_ldiv_B!(A,reshape(B,length(B),1)))
A_ldiv_B!(A::QRPivoted{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = A_ldiv_B!(A, B, maximum(size(A))*eps(real(float(one(eltype(B))))))[1]
function A_ldiv_B!(A::QR{T}, B::StridedMatrix{T}) where T
m, n = size(A)
minmn = min(m,n)
mB, nB = size(B)
Ac_mul_B!(A[:Q], view(B, 1:m, :))
R = A[:R]
@inbounds begin
if n > m # minimum norm solution
τ = zeros(T,m)
for k = m:-1:1 # Trapezoid to triangular by elementary operation
x = view(R, k, [k; m + 1:n])
τk = reflector!(x)
τ[k] = τk'
for i = 1:k - 1
vRi = R[i,k]
for j = m + 1:n
vRi += R[i,j]*x[j - m + 1]'
end
vRi *= τk
R[i,k] -= vRi
for j = m + 1:n
R[i,j] -= vRi*x[j - m + 1]
end
end
end
end
Base.A_ldiv_B!(UpperTriangular(view(R, :, 1:minmn)), view(B, 1:minmn, :))
if n > m # Apply elementary transformation to solution
B[m + 1:mB,1:nB] = zero(T)
for j = 1:nB
for k = 1:m
vBj = B[k,j]
for i = m + 1:n
vBj += B[i,j]*R[k,i]'
end
vBj *= τ[k]
B[k,j] -= vBj
for i = m + 1:n
B[i,j] -= R[k,i]*vBj
end
end
end
end
end
return B
end
A_ldiv_B!(A::QR, B::StridedVector) = A_ldiv_B!(A, reshape(B, length(B), 1))[:]
function A_ldiv_B!(A::QRPivoted, b::StridedVector)
A_ldiv_B!(QR(A.factors,A.τ), b)
b[1:size(A.factors, 2)] = view(b, 1:size(A.factors, 2))[invperm(A.jpvt)]
b
end
function A_ldiv_B!(A::QRPivoted, B::StridedMatrix)
A_ldiv_B!(QR(A.factors, A.τ), B)
B[1:size(A.factors, 2),:] = view(B, 1:size(A.factors, 2), :)[invperm(A.jpvt),:]
B
end
# convenience methods
## return only the solution of a least squares problem while avoiding promoting
## vectors to matrices.
_cut_B(x::AbstractVector, r::UnitRange) = length(x) > length(r) ? x[r] : x
_cut_B(X::AbstractMatrix, r::UnitRange) = size(X, 1) > length(r) ? X[r,:] : X
## append right hand side with zeros if necessary
_zeros(::Type{T}, b::AbstractVector, n::Integer) where {T} = zeros(T, max(length(b), n))
_zeros(::Type{T}, B::AbstractMatrix, n::Integer) where {T} = zeros(T, max(size(B, 1), n), size(B, 2))
function (\)(A::Union{QR{TA},QRCompactWY{TA},QRPivoted{TA}}, B::AbstractVecOrMat{TB}) where {TA,TB}
S = promote_type(TA,TB)
m, n = size(A)
m == size(B,1) || throw(DimensionMismatch("left hand side has $m rows, but right hand side has $(size(B,1)) rows"))
AA = convert(Factorization{S}, A)
X = _zeros(S, B, n)
X[1:size(B, 1), :] = B
A_ldiv_B!(AA, X)
return _cut_B(X, 1:n)
end
# With a real lhs and complex rhs with the same precision, we can reinterpret the complex
# rhs as a real rhs with twice the number of columns.
# convenience methods to compute the return size correctly for vectors and matrices
_ret_size(A::Factorization, b::AbstractVector) = (max(size(A, 2), length(b)),)
_ret_size(A::Factorization, B::AbstractMatrix) = (max(size(A, 2), size(B, 1)), size(B, 2))
function (\)(A::Union{QR{T},QRCompactWY{T},QRPivoted{T}}, BIn::VecOrMat{Complex{T}}) where T<:BlasReal
m, n = size(A)
m == size(BIn, 1) || throw(DimensionMismatch("left hand side has $m rows, but right hand side has $(size(BIn,1)) rows"))
# |z1|z3| reinterpret |x1|x2|x3|x4| transpose |x1|y1| reshape |x1|y1|x3|y3|
# |z2|z4| -> |y1|y2|y3|y4| -> |x2|y2| -> |x2|y2|x4|y4|
# |x3|y3|
# |x4|y4|
B = reshape(transpose(reinterpret(T, BIn, (2, length(BIn)))), size(BIn, 1), 2*size(BIn, 2))
X = _zeros(T, B, n)
X[1:size(B, 1), :] = B
A_ldiv_B!(A, X)
# |z1|z3| reinterpret |x1|x2|x3|x4| transpose |x1|y1| reshape |x1|y1|x3|y3|
# |z2|z4| <- |y1|y2|y3|y4| <- |x2|y2| <- |x2|y2|x4|y4|
# |x3|y3|
# |x4|y4|
XX = reinterpret(Complex{T}, transpose(reshape(X, div(length(X), 2), 2)), _ret_size(A, BIn))
return _cut_B(XX, 1:n)
end
##TODO: Add methods for rank(A::QRP{T}) and adjust the (\) method accordingly
## Add rcond methods for Cholesky, LU, QR and QRP types
## Lower priority: Add LQ, QL and RQ factorizations
# FIXME! Should add balancing option through xgebal