Skip to content

Commit aaa7688

Browse files
dkarrascharaujoms
andauthored
Add bidiagonal cholesky version (#1409)
Co-authored-by: Mateus Araújo <[email protected]>
1 parent 16f64e7 commit aaa7688

File tree

4 files changed

+67
-6
lines changed

4 files changed

+67
-6
lines changed

src/bidiag.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,35 @@ function inv(B::Bidiagonal{T}) where T
14671467
return B.uplo == 'U' ? UpperTriangular(dest) : LowerTriangular(dest)
14681468
end
14691469

1470+
# cholesky-version for (sym)tridiagonal matrices
1471+
for (T, uplo) in ((:UpperTriangular, :(:U)), (:LowerTriangular, :(:L)))
1472+
@eval function _chol!(A::Bidiagonal, ::Type{$T})
1473+
dv = real(A.dv)
1474+
ev = A.ev
1475+
n = length(dv)
1476+
@inbounds for i in 1:n-1
1477+
iszero(dv[i]) && throw(ZeroPivotException(i))
1478+
ev[i] /= dv[i]
1479+
dv[i+1] -= abs2(ev[i])*dv[i]
1480+
Akk = dv[i]
1481+
Akk, info = _chol!(Akk, UpperTriangular)
1482+
if info != 0
1483+
return $T(A), convert(BlasInt, i)
1484+
end
1485+
dv[i] = Akk
1486+
ev[i] *= dv[i]
1487+
end
1488+
Akk = dv[n]
1489+
Akk, info = _chol!(Akk, $T)
1490+
if info != 0
1491+
return $T(A), convert(BlasInt, n)
1492+
end
1493+
dv[n] = Akk
1494+
B = Bidiagonal(dv, ev, $uplo)
1495+
return $T(B), convert(BlasInt, 0)
1496+
end
1497+
end
1498+
14701499
# Eigensystems
14711500
eigvals(M::Bidiagonal) = copy(M.dv)
14721501
function eigvecs(M::Bidiagonal{T}) where T

src/special.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -605,8 +605,8 @@ function _hvcat(rows::Tuple{Vararg{Int}}, A::Union{AbstractArray,AbstractQ,Unifo
605605
end
606606
end
607607

608-
# factorizations
609-
function cholesky(S::RealHermSymComplexHerm{<:Real,<:SymTridiagonal}, ::NoPivot = NoPivot(); check::Bool = true)
608+
# tridiagonal cholesky factorization
609+
function cholesky(S::RealSymHermitian{<:BiTriSym}, ::NoPivot = NoPivot(); check::Bool = true)
610610
T = choltype(S)
611611
B = Bidiagonal{T}(diag(S, 0), diag(S, S.uplo == 'U' ? 1 : -1), sym_uplo(S.uplo))
612612
cholesky!(Hermitian(B, sym_uplo(S.uplo)), NoPivot(); check = check)

src/tridiag.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ function dot(x::AbstractVector, A::Tridiagonal, y::AbstractVector)
10391039
return r
10401040
end
10411041

1042-
function cholesky(S::SymTridiagonal, ::NoPivot = NoPivot(); check::Bool = true)
1042+
function cholesky(S::Union{SymTridiagonal,Tridiagonal}, ::NoPivot = NoPivot(); check::Bool = true)
10431043
if !ishermitian(S)
10441044
check && checkpositivedefinite(-1)
10451045
return Cholesky(S, 'U', convert(BlasInt, -1))

test/cholesky.jl

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,41 @@ end
492492
end
493493

494494
@testset "Cholesky for AbstractMatrix" begin
495-
S = SymTridiagonal(fill(2.0, 4), ones(3))
496-
C = cholesky(S)
497-
@test C.L * C.U S
495+
for T in (identity, big), M in (SymTridiagonal(fill(T(2.0), 4), ones(3)),
496+
Symmetric(SymTridiagonal(fill(T(2.0), 4), ones(3)), :U),
497+
Symmetric(SymTridiagonal(fill(T(2.0), 4), ones(3)), :L),
498+
Tridiagonal(ones(3), fill(T(2.0), 4), ones(3)),
499+
Hermitian(Tridiagonal(ones(3), fill(T(2.0), 4), ones(3)), :U),
500+
Hermitian(Bidiagonal(fill(T(2.0), 4), ones(3), :U), :U),
501+
Hermitian(Bidiagonal(fill(T(2.0), 4), ones(3), :U), :L),
502+
Hermitian(Bidiagonal(fill(T(2.0), 4), ones(3), :L), :L),
503+
)
504+
C = cholesky(M)
505+
@test C.L * C.U M
506+
@test parent(C.U) isa Bidiagonal
507+
M[1,1] *= -1
508+
@test_throws PosDefException cholesky(M)
509+
C = cholesky(M, check=false)
510+
@test C.info > 0
511+
M[1,1] *= -1
512+
M[end,end] *= -1
513+
@test_throws PosDefException cholesky(M)
514+
C = cholesky(M, check=false)
515+
@test C.info > 0
516+
end
517+
# test LowerTriangular version
518+
M = Hermitian(Bidiagonal(fill(2.0, 4), im * ones(3), :L), :L)
519+
C = cholesky!(copy(M))
520+
@test C.L * C.U M
521+
# non-(RealOrComplex) eltype
522+
A = Tridiagonal(randn(Quaternion{Float64}, 4, 4) |> t -> t't)
523+
C = cholesky(A)
524+
@test C.L * C.U A
525+
@test parent(C.U) isa Bidiagonal
526+
A = Hermitian(Tridiagonal(randn(Quaternion{Float64}, 4, 4) |> t -> t't), :L)
527+
C = cholesky(A)
528+
@test C.L * C.U A
529+
@test parent(C.U) isa Bidiagonal
498530
end
499531

500532
@testset "constructor with non-BlasInt arguments" begin

0 commit comments

Comments
 (0)