mollusk 0e4acfb8f2 fix incorrect folder name for julia-0.6.x
Former-commit-id: ef2c7401e0876f22d2f7762d182cfbcd5a7d9c70
2018-06-11 03:28:36 -07:00

564 lines
17 KiB
Julia
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# This file is a part of Julia. License is MIT: https://julialang.org/license
####################
# LU Factorization #
####################
struct LU{T,S<:AbstractMatrix} <: Factorization{T}
factors::S
ipiv::Vector{BlasInt}
info::BlasInt
LU{T,S}(factors::AbstractMatrix{T}, ipiv::Vector{BlasInt}, info::BlasInt) where {T,S} = new(factors, ipiv, info)
end
LU(factors::AbstractMatrix{T}, ipiv::Vector{BlasInt}, info::BlasInt) where {T} = LU{T,typeof(factors)}(factors, ipiv, info)
# StridedMatrix
function lufact!(A::StridedMatrix{T}, pivot::Union{Type{Val{false}}, Type{Val{true}}} = Val{true}) where T<:BlasFloat
if pivot === Val{false}
return generic_lufact!(A, pivot)
end
lpt = LAPACK.getrf!(A)
return LU{T,typeof(A)}(lpt[1], lpt[2], lpt[3])
end
"""
lufact!(A, pivot=Val{true}) -> LU
`lufact!` is the same as [`lufact`](@ref), 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.
"""
lufact!(A::StridedMatrix, pivot::Union{Type{Val{false}}, Type{Val{true}}} = Val{true}) = generic_lufact!(A, pivot)
function generic_lufact!(A::StridedMatrix{T}, ::Type{Val{Pivot}} = Val{true}) where {T,Pivot}
m, n = size(A)
minmn = min(m,n)
info = 0
ipiv = Vector{BlasInt}(minmn)
@inbounds begin
for k = 1:minmn
# find index max
kp = k
if Pivot
amax = real(zero(T))
for i = k:m
absi = abs(A[i,k])
if absi > amax
kp = i
amax = absi
end
end
end
ipiv[k] = kp
if A[kp,k] != 0
if k != kp
# Interchange
for i = 1:n
tmp = A[k,i]
A[k,i] = A[kp,i]
A[kp,i] = tmp
end
end
# Scale first column
Akkinv = inv(A[k,k])
for i = k+1:m
A[i,k] *= Akkinv
end
elseif info == 0
info = k
end
# Update the rest
for j = k+1:n
for i = k+1:m
A[i,j] -= A[i,k]*A[k,j]
end
end
end
end
LU{T,typeof(A)}(A, ipiv, convert(BlasInt, info))
end
# floating point types doesn't have to be promoted for LU, but should default to pivoting
lufact(A::Union{AbstractMatrix{T}, AbstractMatrix{Complex{T}}},
pivot::Union{Type{Val{false}}, Type{Val{true}}} = Val{true}) where {T<:AbstractFloat} =
lufact!(copy(A), pivot)
# for all other types we must promote to a type which is stable under division
"""
lufact(A [,pivot=Val{true}]) -> F::LU
Compute the LU factorization of `A`.
In most cases, if `A` is a subtype `S` of `AbstractMatrix{T}` with an element
type `T` supporting `+`, `-`, `*` and `/`, the return type is `LU{T,S{T}}`. If
pivoting is chosen (default) the element type should also support `abs` and
`<`.
The individual components of the factorization `F` can be accessed by indexing:
| Component | Description |
|:----------|:------------------------------------|
| `F[:L]` | `L` (lower triangular) part of `LU` |
| `F[:U]` | `U` (upper triangular) part of `LU` |
| `F[:p]` | (right) permutation `Vector` |
| `F[:P]` | (right) permutation `Matrix` |
The relationship between `F` and `A` is
`F[:L]*F[:U] == A[F[:p], :]`
`F` further supports the following functions:
| Supported function | `LU` | `LU{T,Tridiagonal{T}}` |
|:---------------------------------|:-----|:-----------------------|
| [`/`](@ref) | ✓ | |
| [`\\`](@ref) | ✓ | ✓ |
| [`cond`](@ref) | ✓ | |
| [`inv`](@ref) | ✓ | ✓ |
| [`det`](@ref) | ✓ | ✓ |
| [`logdet`](@ref) | ✓ | ✓ |
| [`logabsdet`](@ref) | ✓ | ✓ |
| [`size`](@ref) | ✓ | ✓ |
# Example
```jldoctest
julia> A = [4 3; 6 3]
2×2 Array{Int64,2}:
4 3
6 3
julia> F = lufact(A)
Base.LinAlg.LU{Float64,Array{Float64,2}} with factors L and U:
[1.0 0.0; 1.5 1.0]
[4.0 3.0; 0.0 -1.5]
julia> F[:L] * F[:U] == A[F[:p], :]
true
```
"""
function lufact(A::AbstractMatrix{T}, pivot::Union{Type{Val{false}}, Type{Val{true}}}) where T
S = typeof(zero(T)/one(T))
AA = similar(A, S, size(A))
copy!(AA, A)
lufact!(AA, pivot)
end
# We can't assume an ordered field so we first try without pivoting
function lufact(A::AbstractMatrix{T}) where T
S = typeof(zero(T)/one(T))
AA = similar(A, S, size(A))
copy!(AA, A)
F = lufact!(AA, Val{false})
if F.info == 0
return F
else
AA = similar(A, S, size(A))
copy!(AA, A)
return lufact!(AA, Val{true})
end
end
lufact(x::Number) = LU(fill(x, 1, 1), BlasInt[1], x == 0 ? one(BlasInt) : zero(BlasInt))
lufact(F::LU) = F
lu(x::Number) = (one(x), x, 1)
"""
lu(A, pivot=Val{true}) -> L, U, p
Compute the LU factorization of `A`, such that `A[p,:] = L*U`.
By default, pivoting is used. This can be overridden by passing
`Val{false}` for the second argument.
See also [`lufact`](@ref).
# Example
```jldoctest
julia> A = [4. 3.; 6. 3.]
2×2 Array{Float64,2}:
4.0 3.0
6.0 3.0
julia> L, U, p = lu(A)
([1.0 0.0; 0.666667 1.0], [6.0 3.0; 0.0 1.0], [2, 1])
julia> A[p, :] == L * U
true
```
"""
function lu(A::AbstractMatrix, pivot::Union{Type{Val{false}}, Type{Val{true}}} = Val{true})
F = lufact(A, pivot)
F[:L], F[:U], F[:p]
end
function convert(::Type{LU{T}}, F::LU) where T
M = convert(AbstractMatrix{T}, F.factors)
LU{T,typeof(M)}(M, F.ipiv, F.info)
end
convert(::Type{LU{T,S}}, F::LU) where {T,S} = LU{T,S}(convert(S, F.factors), F.ipiv, F.info)
convert(::Type{Factorization{T}}, F::LU{T}) where {T} = F
convert(::Type{Factorization{T}}, F::LU) where {T} = convert(LU{T}, F)
size(A::LU) = size(A.factors)
size(A::LU,n) = size(A.factors,n)
function ipiv2perm(v::AbstractVector{T}, maxi::Integer) where T
p = T[1:maxi;]
@inbounds for i in 1:length(v)
p[i], p[v[i]] = p[v[i]], p[i]
end
return p
end
function getindex(F::LU{T,<:StridedMatrix}, d::Symbol) where T
m, n = size(F)
if d == :L
L = tril!(F.factors[1:m, 1:min(m,n)])
for i = 1:min(m,n); L[i,i] = one(T); end
return L
elseif d == :U
return triu!(F.factors[1:min(m,n), 1:n])
elseif d == :p
return ipiv2perm(F.ipiv, m)
elseif d == :P
return eye(T, m)[:,invperm(F[:p])]
else
throw(KeyError(d))
end
end
function show(io::IO, C::LU)
println(io, "$(typeof(C)) with factors L and U:")
show(io, C[:L])
println(io)
show(io, C[:U])
end
A_ldiv_B!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} =
@assertnonsingular LAPACK.getrs!('N', A.factors, A.ipiv, B) A.info
A_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, b::StridedVector) =
A_ldiv_B!(UpperTriangular(A.factors),
A_ldiv_B!(UnitLowerTriangular(A.factors), b[ipiv2perm(A.ipiv, length(b))]))
A_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, B::StridedMatrix) =
A_ldiv_B!(UpperTriangular(A.factors),
A_ldiv_B!(UnitLowerTriangular(A.factors), B[ipiv2perm(A.ipiv, size(B, 1)),:]))
At_ldiv_B!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} =
@assertnonsingular LAPACK.getrs!('T', A.factors, A.ipiv, B) A.info
At_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, b::StridedVector) =
At_ldiv_B!(UnitLowerTriangular(A.factors),
At_ldiv_B!(UpperTriangular(A.factors), b))[invperm(ipiv2perm(A.ipiv, length(b)))]
At_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, B::StridedMatrix) =
At_ldiv_B!(UnitLowerTriangular(A.factors),
At_ldiv_B!(UpperTriangular(A.factors), B))[invperm(ipiv2perm(A.ipiv, size(B,1))),:]
Ac_ldiv_B!(F::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:Real} =
At_ldiv_B!(F, B)
Ac_ldiv_B!(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasComplex} =
@assertnonsingular LAPACK.getrs!('C', A.factors, A.ipiv, B) A.info
Ac_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, b::StridedVector) =
Ac_ldiv_B!(UnitLowerTriangular(A.factors),
Ac_ldiv_B!(UpperTriangular(A.factors), b))[invperm(ipiv2perm(A.ipiv, length(b)))]
Ac_ldiv_B!(A::LU{<:Any,<:StridedMatrix}, B::StridedMatrix) =
Ac_ldiv_B!(UnitLowerTriangular(A.factors),
Ac_ldiv_B!(UpperTriangular(A.factors), B))[invperm(ipiv2perm(A.ipiv, size(B,1))),:]
At_ldiv_Bt(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} =
@assertnonsingular LAPACK.getrs!('T', A.factors, A.ipiv, transpose(B)) A.info
At_ldiv_Bt(A::LU, B::StridedVecOrMat) = At_ldiv_B(A, transpose(B))
Ac_ldiv_Bc(A::LU{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasComplex} =
@assertnonsingular LAPACK.getrs!('C', A.factors, A.ipiv, ctranspose(B)) A.info
Ac_ldiv_Bc(A::LU, B::StridedVecOrMat) = Ac_ldiv_B(A, ctranspose(B))
function det(A::LU{T}) where T
n = checksquare(A)
A.info > 0 && return zero(T)
P = one(T)
c = 0
@inbounds for i = 1:n
P *= A.factors[i,i]
if A.ipiv[i] != i
c += 1
end
end
s = (isodd(c) ? -one(T) : one(T))
return P * s
end
function logabsdet(A::LU{T}) where T # return log(abs(det)) and sign(det)
n = checksquare(A)
A.info > 0 && return log(zero(real(T))), log(one(T))
c = 0
P = one(T)
abs_det = zero(real(T))
@inbounds for i = 1:n
dg_ii = A.factors[i,i]
P *= sign(dg_ii)
if A.ipiv[i] != i
c += 1
end
abs_det += log(abs(dg_ii))
end
s = ifelse(isodd(c), -one(real(T)), one(real(T))) * P
abs_det, s
end
inv!(A::LU{<:BlasFloat,<:StridedMatrix}) =
@assertnonsingular LAPACK.getri!(A.factors, A.ipiv) A.info
inv(A::LU{<:BlasFloat,<:StridedMatrix}) =
inv!(LU(copy(A.factors), copy(A.ipiv), copy(A.info)))
cond(A::LU{<:BlasFloat,<:StridedMatrix}, p::Number) =
inv(LAPACK.gecon!(p == 1 ? '1' : 'I', A.factors, norm((A[:L]*A[:U])[A[:p],:], p)))
cond(A::LU, p::Number) = norm(A[:L]*A[:U],p)*norm(inv(A),p)
# Tridiagonal
# See dgttrf.f
function lufact!(A::Tridiagonal{T}, pivot::Union{Type{Val{false}}, Type{Val{true}}} = Val{true}) where T
n = size(A, 1)
info = 0
ipiv = Vector{BlasInt}(n)
dl = A.dl
d = A.d
du = A.du
du2 = A.du2
@inbounds begin
for i = 1:n
ipiv[i] = i
end
for i = 1:n-2
# pivot or not?
if pivot === Val{false} || abs(d[i]) >= abs(dl[i])
# No interchange
if d[i] != 0
fact = dl[i]/d[i]
dl[i] = fact
d[i+1] -= fact*du[i]
du2[i] = 0
end
else
# Interchange
fact = d[i]/dl[i]
d[i] = dl[i]
dl[i] = fact
tmp = du[i]
du[i] = d[i+1]
d[i+1] = tmp - fact*d[i+1]
du2[i] = du[i+1]
du[i+1] = -fact*du[i+1]
ipiv[i] = i+1
end
end
if n > 1
i = n-1
if pivot === Val{false} || abs(d[i]) >= abs(dl[i])
if d[i] != 0
fact = dl[i]/d[i]
dl[i] = fact
d[i+1] -= fact*du[i]
end
else
fact = d[i]/dl[i]
d[i] = dl[i]
dl[i] = fact
tmp = du[i]
du[i] = d[i+1]
d[i+1] = tmp - fact*d[i+1]
ipiv[i] = i+1
end
end
# check for a zero on the diagonal of U
for i = 1:n
if d[i] == 0
info = i
break
end
end
end
LU{T,Tridiagonal{T}}(A, ipiv, convert(BlasInt, info))
end
factorize(A::Tridiagonal) = lufact(A)
function getindex(F::Base.LinAlg.LU{T,Tridiagonal{T}}, d::Symbol) where T
m, n = size(F)
if d == :L
L = Array(Bidiagonal(ones(T, n), F.factors.dl, false))
for i = 2:n
tmp = L[F.ipiv[i], 1:i - 1]
L[F.ipiv[i], 1:i - 1] = L[i, 1:i - 1]
L[i, 1:i - 1] = tmp
end
return L
elseif d == :U
U = Array(Bidiagonal(F.factors.d, F.factors.du, true))
for i = 1:n - 2
U[i,i + 2] = F.factors.du2[i]
end
return U
elseif d == :p
return ipiv2perm(F.ipiv, m)
elseif d == :P
return eye(T, m)[:,invperm(F[:p])]
end
throw(KeyError(d))
end
# See dgtts2.f
function A_ldiv_B!(A::LU{T,Tridiagonal{T}}, B::AbstractVecOrMat) where T
n = size(A,1)
if n != size(B,1)
throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows"))
end
nrhs = size(B,2)
dl = A.factors.dl
d = A.factors.d
du = A.factors.du
du2 = A.factors.du2
ipiv = A.ipiv
@inbounds begin
for j = 1:nrhs
for i = 1:n-1
ip = ipiv[i]
tmp = B[i+1-ip+i,j] - dl[i]*B[ip,j]
B[i,j] = B[ip,j]
B[i+1,j] = tmp
end
B[n,j] /= d[n]
if n > 1
B[n-1,j] = (B[n-1,j] - du[n-1]*B[n,j])/d[n-1]
end
for i = n-2:-1:1
B[i,j] = (B[i,j] - du[i]*B[i+1,j] - du2[i]*B[i+2,j])/d[i]
end
end
end
return B
end
function At_ldiv_B!(A::LU{T,Tridiagonal{T}}, B::AbstractVecOrMat) where T
n = size(A,1)
if n != size(B,1)
throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows"))
end
nrhs = size(B,2)
dl = A.factors.dl
d = A.factors.d
du = A.factors.du
du2 = A.factors.du2
ipiv = A.ipiv
@inbounds begin
for j = 1:nrhs
B[1,j] /= d[1]
if n > 1
B[2,j] = (B[2,j] - du[1]*B[1,j])/d[2]
end
for i = 3:n
B[i,j] = (B[i,j] - du[i-1]*B[i-1,j] - du2[i-2]*B[i-2,j])/d[i]
end
for i = n-1:-1:1
if ipiv[i] == i
B[i,j] = B[i,j] - dl[i]*B[i+1,j]
else
tmp = B[i+1,j]
B[i+1,j] = B[i,j] - dl[i]*tmp
B[i,j] = tmp
end
end
end
end
return B
end
# Ac_ldiv_B!(A::LU{T,Tridiagonal{T}}, B::AbstractVecOrMat) where {T<:Real} = At_ldiv_B!(A,B)
function Ac_ldiv_B!(A::LU{T,Tridiagonal{T}}, B::AbstractVecOrMat) where T
n = size(A,1)
if n != size(B,1)
throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows"))
end
nrhs = size(B,2)
dl = A.factors.dl
d = A.factors.d
du = A.factors.du
du2 = A.factors.du2
ipiv = A.ipiv
@inbounds begin
for j = 1:nrhs
B[1,j] /= conj(d[1])
if n > 1
B[2,j] = (B[2,j] - conj(du[1])*B[1,j])/conj(d[2])
end
for i = 3:n
B[i,j] = (B[i,j] - conj(du[i-1])*B[i-1,j] - conj(du2[i-2])*B[i-2,j])/conj(d[i])
end
for i = n-1:-1:1
if ipiv[i] == i
B[i,j] = B[i,j] - conj(dl[i])*B[i+1,j]
else
tmp = B[i+1,j]
B[i+1,j] = B[i,j] - conj(dl[i])*tmp
B[i,j] = tmp
end
end
end
end
return B
end
/(B::AbstractMatrix,A::LU) = At_ldiv_Bt(A,B).'
# Conversions
convert(::Type{AbstractMatrix}, F::LU) = (F[:L] * F[:U])[invperm(F[:p]),:]
convert(::Type{AbstractArray}, F::LU) = convert(AbstractMatrix, F)
convert(::Type{Matrix}, F::LU) = convert(Array, convert(AbstractArray, F))
convert(::Type{Array}, F::LU) = convert(Matrix, F)
full(F::LU) = convert(AbstractArray, F)
function convert(::Type{Tridiagonal}, F::Base.LinAlg.LU{T,Tridiagonal{T}}) where T
n = size(F, 1)
dl = copy(F.factors.dl)
d = copy(F.factors.d)
du = copy(F.factors.du)
du2 = copy(F.factors.du2)
for i = n - 1:-1:1
li = dl[i]
dl[i] = li*d[i]
d[i + 1] += li*du[i]
if i < n - 1
du[i + 1] += li*du2[i]
end
if F.ipiv[i] != i
tmp = dl[i]
dl[i] = d[i]
d[i] = tmp
tmp = d[i + 1]
d[i + 1] = du[i]
du[i] = tmp
if i < n - 1
tmp = du[i + 1]
du[i + 1] = du2[i]
du2[i] = tmp
end
end
end
return Tridiagonal(dl, d, du)
end
convert(::Type{AbstractMatrix}, F::Base.LinAlg.LU{T,Tridiagonal{T}}) where {T} =
convert(Tridiagonal, F)
convert(::Type{AbstractArray}, F::Base.LinAlg.LU{T,Tridiagonal{T}}) where {T} =
convert(AbstractMatrix, F)
convert(::Type{Matrix}, F::Base.LinAlg.LU{T,Tridiagonal{T}}) where {T} =
convert(Array, convert(AbstractArray, F))
convert(::Type{Array}, F::Base.LinAlg.LU{T,Tridiagonal{T}}) where {T} =
convert(Matrix, F)
full(F::Base.LinAlg.LU{T,Tridiagonal{T}}) where {T} = convert(AbstractArray, F)