Skip to content

Commit a9cf2af

Browse files
committed
Make the algorithm for real powers of a matrix robust
1 parent 617b2a6 commit a9cf2af

File tree

2 files changed

+48
-47
lines changed

2 files changed

+48
-47
lines changed

base/linalg/diagonal.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,14 @@ expm(D::Diagonal) = Diagonal(exp.(D.diag))
251251
logm(D::Diagonal) = Diagonal(log.(D.diag))
252252
sqrtm(D::Diagonal) = Diagonal(sqrt.(D.diag))
253253

254+
# Matrix functions
255+
^(D::Diagonal, p::Real) = Diagonal((D.diag).^p)
256+
for (funm, func) in ([:expm,:exp], [:sqrtm,:sqrt], [:logm,:log])
257+
@eval begin
258+
($funm)(D::Diagonal) = Diagonal(($func)(D.diag))
259+
end
260+
end
261+
254262
#Linear solver
255263
function A_ldiv_B!(D::Diagonal, B::StridedVecOrMat)
256264
m, n = size(B, 1), size(B, 2)

base/linalg/triangular.jl

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,7 +1672,7 @@ powm(A::LowerTriangular, p::Real) = powm(A.', p::Real).'
16721672
# Based on the code available at http://eprints.ma.man.ac.uk/1851/02/logm.zip,
16731673
# Copyright (c) 2011, Awad H. Al-Mohy and Nicholas J. Higham
16741674
# Julia version relicensed with permission from original authors
1675-
function logm{T<:Union{Float32,Float64,Complex{Float32},Complex{Float64}}}(A0::UpperTriangular{T})
1675+
function logm{T<:Union{Float64,Complex{Float64}}}(A0::UpperTriangular{T})
16761676
theta = [1.586970738772063e-005,
16771677
2.313807884242979e-003,
16781678
1.938179313533253e-002,
@@ -1718,7 +1718,7 @@ function logm{T<:Union{Float32,Float64,Complex{Float32},Complex{Float64}}}(A0::U
17181718
scale!(2^s,Y.data)
17191719

17201720
# Compute accurate diagonal and superdiagonal of log(A)
1721-
for k = 1:n-1
1721+
@inbounds for k = 1:n-1
17221722
Ak = complex(A0[k,k])
17231723
Akp1 = complex(A0[k+1,k+1])
17241724
logAk = log(Ak)
@@ -1749,7 +1749,7 @@ logm(A::LowerTriangular) = logm(A.').'
17491749
# Numer. Algorithms, 59, (2012), 393–402.
17501750
function sqrt_diag!(A0::UpperTriangular, A::UpperTriangular, s)
17511751
n = checksquare(A0)
1752-
for i = 1:n
1752+
@inbounds for i = 1:n
17531753
a = complex(A0[i,i])
17541754
if s == 0
17551755
A[i,i] = a - 1
@@ -1806,60 +1806,53 @@ function invsquaring(A0::UpperTriangular, theta)
18061806
d2 = sqrt(norm(AmI^2, 1))
18071807
d3 = cbrt(norm(AmI^3, 1))
18081808
alpha2 = max(d2, d3)
1809-
foundm = false
18101809
if alpha2 <= theta[2]
18111810
m = alpha2<=theta[1]?1:2
1812-
foundm = true
1813-
end
1814-
1815-
while ~foundm
1816-
more = false
1817-
if s > s0
1818-
d3 = cbrt(norm(AmI^3, 1))
1819-
end
1820-
d4 = norm(AmI^4, 1)^(1/4)
1821-
alpha3 = max(d3, d4)
1822-
if alpha3 <= theta[tmax]
1823-
for j = 3:tmax
1824-
if alpha3 <= theta[j]
1811+
else
1812+
while true
1813+
more = false
1814+
if s > s0
1815+
d3 = cbrt(norm(AmI^3, 1))
1816+
end
1817+
d4 = norm(AmI^4, 1)^(1/4)
1818+
alpha3 = max(d3, d4)
1819+
if alpha3 <= theta[tmax]
1820+
for j = 3:tmax
1821+
if alpha3 <= theta[j]
1822+
break
1823+
end
1824+
end
1825+
if j <= 6
1826+
m = j
18251827
break
1828+
elseif alpha3 / 2 <= theta[5] && p < 2
1829+
more = true
1830+
p = p + 1
18261831
end
18271832
end
1828-
if j <= 6
1829-
m = j
1830-
foundm = true
1831-
break
1832-
elseif alpha3 / 2 <= theta[5] && p < 2
1833-
more = true
1834-
p = p + 1
1835-
end
1836-
end
1837-
1838-
if ~more
1839-
d5 = norm(AmI^5, 1)^(1/5)
1840-
alpha4 = max(d4, d5)
1841-
eta = min(alpha3, alpha4)
1842-
if eta <= theta[tmax]
1843-
j = 0
1844-
for j = 6:tmax
1845-
if eta <= theta[j]
1846-
m = j
1847-
break
1833+
if ~more
1834+
d5 = norm(AmI^5, 1)^(1/5)
1835+
alpha4 = max(d4, d5)
1836+
eta = min(alpha3, alpha4)
1837+
if eta <= theta[tmax]
1838+
j = 0
1839+
for j = 6:tmax
1840+
if eta <= theta[j]
1841+
m = j
1842+
break
1843+
end
18481844
end
1845+
break
18491846
end
1850-
foundm = true
1847+
end
1848+
if s == maxsqrt
1849+
m = tmax
18511850
break
18521851
end
1852+
A = sqrtm(A)
1853+
AmI = A - I
1854+
s = s + 1
18531855
end
1854-
1855-
if s == maxsqrt
1856-
m = tmax
1857-
foundm = true
1858-
break
1859-
end
1860-
A = sqrtm(A)
1861-
AmI = A - I
1862-
s = s + 1
18631856
end
18641857

18651858
# Compute accurate superdiagonal of T

0 commit comments

Comments
 (0)