|
1 | 1 | # Generic Cholesky decomposition for fixed-size matrices, mostly unrolled
|
2 | 2 | non_hermitian_error() = throw(LinearAlgebra.PosDefException(-1))
|
3 |
| -@inline function LinearAlgebra.cholesky(A::StaticMatrix) |
| 3 | +@inline function LinearAlgebra.cholesky(A::StaticMatrix; check::Bool = true) |
4 | 4 | ishermitian(A) || non_hermitian_error()
|
5 |
| - C = _cholesky(Size(A), A) |
6 |
| - return Cholesky(C, 'U', 0) |
| 5 | + _cholesky(Size(A), A, check) |
| 6 | + # (check && (info ≠ 0)) && throw(LinearAlgebra.PosDefException(info)) |
| 7 | + # return Cholesky(C, 'U', info) |
7 | 8 | end
|
8 | 9 |
|
9 |
| -@inline function LinearAlgebra.cholesky(A::LinearAlgebra.RealHermSymComplexHerm{<:Real, <:StaticMatrix}) |
10 |
| - C = _cholesky(Size(A), A.data) |
11 |
| - return Cholesky(C, 'U', 0) |
| 10 | +@inline function LinearAlgebra.cholesky(A::LinearAlgebra.RealHermSymComplexHerm{<:Real, <:StaticMatrix}; check::Bool = true) |
| 11 | + C = _cholesky(Size(A), A.data, check) |
| 12 | + # (check && (info ≠ 0)) && throw(LinearAlgebra.PosDefException(info)) |
| 13 | + # return Cholesky(C, 'U', 0) |
12 | 14 | end
|
13 | 15 | @inline LinearAlgebra._chol!(A::StaticMatrix, ::Type{UpperTriangular}) = (cholesky(A).U, 0)
|
14 | 16 |
|
15 |
| -@generated function _cholesky(::Size{S}, A::StaticMatrix{M,M}) where {S,M} |
| 17 | +@inline function _check_chol(A, info, check) |
| 18 | + if check |
| 19 | + throw(LinearAlgebra.PosDefException(info)) |
| 20 | + else |
| 21 | + return Cholesky(A, 'U', info) |
| 22 | + end |
| 23 | +end |
| 24 | +@inline _nonpdcheck(x::Real) = x < zero(x) |
| 25 | +@inline _nonpdcheck(x) = false |
| 26 | + |
| 27 | +@generated function _cholesky(::Size{S}, A::StaticMatrix{M,M}, check::Bool) where {S,M} |
16 | 28 | @assert (M,M) == S
|
17 | 29 | M > 24 && return :(_cholesky_large(Size{$S}(), A))
|
18 |
| - q = Expr(:block) |
| 30 | + q = Expr(:block, :(info = 0), :(failure = false)) |
19 | 31 | for n ∈ 1:M
|
20 | 32 | for m ∈ n:M
|
21 | 33 | L_m_n = Symbol(:L_,m,:_,n)
|
|
28 | 40 | push!(q.args, :($L_m_n = muladd(-$L_m_k, $L_n_k', $L_m_n)))
|
29 | 41 | end
|
30 | 42 | L_n_n = Symbol(:L_,n,:_,n)
|
31 |
| - push!(q.args, :($L_n_n = sqrt($L_n_n))) |
| 43 | + L_n_n_ltz = Symbol(:L_,n,:_,n,:_,:ltz) |
| 44 | + # x < 0.0 is check used in `sqrt`, letting LLVM eliminate that check and remove error code. |
| 45 | + # push!(q.args, :($L_n_n_ltz = ) |
| 46 | + push!(q.args, :($L_n_n = _nonpdcheck($L_n_n) ? (return _check_chol(A, $n, check)) : sqrt($L_n_n))) |
| 47 | + # push!(q.args, :(info = ($L_n_n_ltz & (!failure)) ? $n : info)) |
| 48 | + # push!(q.args, :(failure |= $L_n_n_ltz)) |
| 49 | + # push!(q.args, :($L_n_n = $L_n_n_ltz ? float(typeof($L_n_n))(NaN) : sqrt($L_n_n))) |
32 | 50 | Linv_n_n = Symbol(:Linv_,n,:_,n)
|
33 | 51 | push!(q.args, :($Linv_n_n = inv($L_n_n)))
|
34 | 52 | for m ∈ n+1:M
|
|
46 | 64 | push!(ret.args, :(zero(T)))
|
47 | 65 | end
|
48 | 66 | end
|
49 |
| - push!(q.args, :(similar_type(A, T)($ret))) |
| 67 | + push!(q.args, :(Cholesky(similar_type(A, T)($ret), 'U', 0))) |
50 | 68 | return Expr(:block, Expr(:meta, :inline), q)
|
51 | 69 | end
|
52 | 70 |
|
53 | 71 | # Otherwise default algorithm returning wrapped SizedArray
|
54 | 72 | @inline _cholesky_large(::Size{S}, A::StaticArray) where {S} =
|
55 |
| - similar_type(A)(cholesky(Hermitian(Matrix(A))).U) |
| 73 | + Cholesky(similar_type(A)(cholesky(Hermitian(Matrix(A))).U), 'U', 0) |
56 | 74 |
|
57 | 75 | LinearAlgebra.hermitian_type(::Type{SA}) where {T, S, SA<:SArray{S,T}} = Hermitian{T,SA}
|
58 | 76 |
|
|
0 commit comments