Skip to content

Commit bf93119

Browse files
committed
use faster code (ldlt-based)
1 parent e3b0282 commit bf93119

File tree

2 files changed

+26
-77
lines changed

2 files changed

+26
-77
lines changed

src/bidiag.jl

Lines changed: 19 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,89 +1468,32 @@ function inv(B::Bidiagonal{T}) where T
14681468
end
14691469

14701470
# cholesky-version for (sym)tridiagonal matrices
1471-
function _chol!(A::Bidiagonal{<:BlasFloat,<:StridedVector}, ::Type{UpperTriangular})
1472-
d = real(A.dv)
1473-
e = A.ev
1474-
dv, ev = LAPACK.pttrf!(d, e)
1475-
for k in eachindex(dv)
1476-
Akk = dv[k]
1477-
Akk, info = _chol!(Akk, UpperTriangular)
1478-
if info != 0
1479-
return UpperTriangular(A), convert(BlasInt, k)
1480-
end
1481-
dv[k] = Akk
1482-
end
1483-
@views ev .*= dv[1:end-1]
1484-
U = Bidiagonal(dv, ev, :U)
1485-
return UpperTriangular(U), convert(BlasInt, 0)
1486-
end
1487-
function _chol!(A::Bidiagonal, ::Type{UpperTriangular})
1488-
require_one_based_indexing(A)
1489-
n = checksquare(A)
1490-
realdiag = eltype(A) <: Complex
1491-
dv = A.dv
1492-
ev = A.ev
1493-
@inbounds begin
1494-
for k = 1:n
1495-
Akk = realdiag ? real(dv[k]) : dv[k]
1496-
if k > 1
1497-
Akk -= realdiag ? abs2(ev[k-1]) : ev[k-1]'ev[k-1]
1498-
end
1499-
dv[k] = Akk
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]
15001481
Akk, info = _chol!(Akk, UpperTriangular)
15011482
if info != 0
1502-
return UpperTriangular(A), convert(BlasInt, k)
1503-
end
1504-
dv[k] = Akk
1505-
AkkInv = inv(copy(Akk'))
1506-
if k < n
1507-
ev[k] = AkkInv*ev[k]
1483+
return $T(A), convert(BlasInt, i)
15081484
end
1485+
dv[i] = Akk
1486+
ev[i] *= dv[i]
15091487
end
1510-
end
1511-
return UpperTriangular(A), convert(BlasInt, 0)
1512-
end
1513-
function _chol!(A::Bidiagonal{<:BlasFloat,<:StridedVector}, ::Type{LowerTriangular})
1514-
d = real(A.dv)
1515-
e = A.ev
1516-
dv, ev = LAPACK.pttrf!(d, e)
1517-
for k in eachindex(dv)
1518-
Akk = dv[k]
1519-
Akk, info = _chol!(Akk, LowerTriangular)
1488+
Akk = dv[n]
1489+
Akk, info = _chol!(Akk, $T)
15201490
if info != 0
1521-
return LowerTriangular(A), convert(BlasInt, k)
1491+
return $T(A), convert(BlasInt, n)
15221492
end
1523-
dv[k] = Akk
1493+
dv[n] = Akk
1494+
B = Bidiagonal(dv, ev, $uplo)
1495+
return $T(B), convert(BlasInt, 0)
15241496
end
1525-
@views ev .*= dv[1:end-1]
1526-
L = Bidiagonal(dv, ev, :L)
1527-
return LowerTriangular(L), convert(BlasInt, 0)
1528-
end
1529-
function _chol!(A::Bidiagonal, ::Type{LowerTriangular})
1530-
require_one_based_indexing(A)
1531-
n = checksquare(A)
1532-
realdiag = eltype(A) <: Complex
1533-
dv = A.dv
1534-
ev = A.ev
1535-
@inbounds begin
1536-
for k = 1:n
1537-
Akk = realdiag ? real(dv[k]) : dv[k]
1538-
if k > 1
1539-
Akk -= realdiag ? abs2(ev[k-1]) : ev[k-1]*ev[k-1]'
1540-
end
1541-
dv[k] = Akk
1542-
Akk, info = _chol!(Akk, LowerTriangular)
1543-
if info != 0
1544-
return LowerTriangular(A), convert(BlasInt, k)
1545-
end
1546-
dv[k] = Akk
1547-
AkkInv = inv(copy(Akk'))
1548-
if k < n
1549-
ev[k] *= AkkInv
1550-
end
1551-
end
1552-
end
1553-
return LowerTriangular(A), convert(BlasInt, 0)
15541497
end
15551498

15561499
# Eigensystems

test/cholesky.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,9 @@ end
512512
Hermitian(Tridiagonal(ones(3), fill(T(-2.0), 4), ones(3)), :U),
513513
Hermitian(Bidiagonal(fill(T(-2.0), 4), ones(3), :U), :U),
514514
)
515-
@test_throws (T == identity ? LAPACKException : PosDefException) cholesky(M)
515+
@test_throws PosDefException cholesky(M)
516+
C = cholesky(M, check=false)
517+
@test C.info > 0
516518
end
517519
# test LowerTriangular version
518520
M = Hermitian(Bidiagonal(fill(2.0, 4), im * ones(3), :L), :L)
@@ -523,6 +525,10 @@ end
523525
C = cholesky(A)
524526
@test C.L * C.U A
525527
@test parent(C.U) isa Bidiagonal
528+
A = Hermitian(Tridiagonal(randn(Quaternion{Float64}, 4, 4) |> t -> t't), :L)
529+
C = cholesky(A)
530+
@test C.L * C.U A
531+
@test parent(C.U) isa Bidiagonal
526532
end
527533

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

0 commit comments

Comments
 (0)