-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
Copy pathfactorization.jl
120 lines (99 loc) · 4.02 KB
/
factorization.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# This file is a part of Julia. License is MIT: https://julialang.org/license
## Matrix factorizations and decompositions
abstract type Factorization{T} end
eltype(::Type{<:Factorization{T}}) where {T} = T
size(F::Adjoint{<:Any,<:Factorization}) = reverse(size(parent(F)))
size(F::Transpose{<:Any,<:Factorization}) = reverse(size(parent(F)))
checkpositivedefinite(info) = info == 0 || throw(PosDefException(info))
checknonsingular(info) = info == 0 || throw(SingularException(info))
"""
issuccess(F::Factorization)
Test that a factorization of a matrix succeeded.
```jldoctest
julia> F = cholesky([1 0; 0 1]);
julia> LinearAlgebra.issuccess(F)
true
julia> F = lu([1 0; 0 0]; check = false);
julia> LinearAlgebra.issuccess(F)
false
```
"""
issuccess(F::Factorization)
function logdet(F::Factorization)
d, s = logabsdet(F)
return d + log(s)
end
function det(F::Factorization)
d, s = logabsdet(F)
return exp(d)*s
end
convert(::Type{T}, f::T) where {T<:Factorization} = f
convert(::Type{T}, f::Factorization) where {T<:Factorization} = T(f)
convert(::Type{T}, f::Factorization) where {T<:AbstractArray} = T(f)
### General promotion rules
Factorization{T}(F::Factorization{T}) where {T} = F
inv(F::Factorization{T}) where {T} = (n = size(F, 1); ldiv!(F, Matrix{T}(I, n, n)))
Base.hash(F::Factorization, h::UInt) = mapreduce(f -> hash(getfield(F, f)), hash, 1:nfields(F); init=h)
Base.:(==)( F::T, G::T) where {T<:Factorization} = all(f -> getfield(F, f) == getfield(G, f), 1:nfields(F))
Base.isequal(F::T, G::T) where {T<:Factorization} = all(f -> isequal(getfield(F, f), getfield(G, f)), 1:nfields(F))::Bool
function Base.show(io::IO, x::Adjoint{<:Any,<:Factorization})
print(io, "Adjoint of ")
show(io, parent(x))
end
function Base.show(io::IO, x::Transpose{<:Any,<:Factorization})
print(io, "Transpose of ")
show(io, parent(x))
end
function Base.show(io::IO, ::MIME"text/plain", x::Adjoint{<:Any,<:Factorization})
print(io, "Adjoint of ")
show(io, MIME"text/plain"(), parent(x))
end
function Base.show(io::IO, ::MIME"text/plain", x::Transpose{<:Any,<:Factorization})
print(io, "Transpose of ")
show(io, MIME"text/plain"(), parent(x))
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
function (\)(F::Factorization{T}, B::VecOrMat{Complex{T}}) where T<:BlasReal
@assert !has_offset_axes(B)
c2r = reshape(copy(transpose(reinterpret(T, reshape(B, (1, length(B)))))), size(B, 1), 2*size(B, 2))
x = ldiv!(F, c2r)
return reshape(copy(reinterpret(Complex{T}, copy(transpose(reshape(x, div(length(x), 2), 2))))), _ret_size(F, B))
end
function \(F::Factorization, B::AbstractVecOrMat)
@assert !has_offset_axes(B)
TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F)))
BB = similar(B, TFB, size(B))
copyto!(BB, B)
ldiv!(F, BB)
end
function \(adjF::Adjoint{<:Any,<:Factorization}, B::AbstractVecOrMat)
@assert !has_offset_axes(B)
F = adjF.parent
TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F)))
BB = similar(B, TFB, size(B))
copyto!(BB, B)
ldiv!(adjoint(F), BB)
end
# support the same 3-arg idiom as in our other in-place A_*_B functions:
function ldiv!(Y::AbstractVecOrMat, A::Factorization, B::AbstractVecOrMat)
@assert !has_offset_axes(Y, B)
m, n = size(A, 1), size(A, 2)
if m > n
ldiv!(A, B)
return copyto!(Y, view(B, 1:n, :))
else
return ldiv!(A, copyto!(Y, view(B, 1:m, :)))
end
end
function ldiv!(Y::AbstractVecOrMat, adjA::Adjoint{<:Any,<:Factorization}, B::AbstractVecOrMat)
checksquare(adjA)
return ldiv!(adjA, copyto!(Y, B))
end
function ldiv!(Y::AbstractVecOrMat, transA::Transpose{<:Any,<:Factorization}, B::AbstractVecOrMat)
checksquare(transA)
return ldiv!(transA, copyto!(Y, B))
end
# fallback methods for transposed solves
\(F::Transpose{<:Any,<:Factorization{<:Real}}, B::AbstractVecOrMat) = adjoint(F.parent) \ B
\(F::Transpose{<:Any,<:Factorization}, B::AbstractVecOrMat) = conj.(adjoint(F.parent) \ conj.(B))