8282
8383# Given a symmetric tridiagonal matrix H with H[i,i] = 0 and
8484# H[i-1,i] = H[i,i-1] = b[i-1], compute p(z) = det(z I - H) and its
85- # derivative p'(z), returning (p,p').
86- function eigpoly (b:: AbstractVector{<:Real} ,z:: Number ,m:: Integer = length (b)+ 1 )
85+ # derivative p'(z), returning the ratio p / p'
86+ function eigpolyrat (b:: AbstractVector{<:Real} ,z:: Number ,m:: Integer = length (b)+ 1 )
8787 d1 = z
8888 d1deriv = d2 = one (z)
8989 d2deriv = zero (z)
9090 for i = 2 : m
9191 b2 = b[i- 1 ]^ 2
9292 d = z * d1 - b2 * d2
9393 dderiv = d1 + z * d1deriv - b2 * d2deriv
94- d2 = d1
95- d1 = d
96- d2deriv = d1deriv
97- d1deriv = dderiv
94+ if iszero (dderiv)
95+ d2, d1 = d1, d
96+ d2deriv, d1deriv = d1deriv, dderiv
97+ else # rescale to suppress under/overflow
98+ dderiv⁻¹ = inv (dderiv)
99+ d2, d1 = d1 * dderiv⁻¹, d * dderiv⁻¹
100+ d2deriv, d1deriv = d1deriv * dderiv⁻¹, one (dderiv)
101+ end
98102 end
99- return (d1, d1deriv)
103+ return d1 / d1deriv
100104end
101- eigpoly (H:: HollowSymTridiagonal{<:Real} ,z) = eigpoly (H. ev, z)
105+ eigpolyrat (H:: HollowSymTridiagonal{<:Real} ,z) = eigpolyrat (H. ev, z)
102106
103107# as above, but for general symmetric tridiagonal (diagonal ≠ 0)
104- function eigpoly (H:: SymTridiagonal{<:Real} ,z:: Number )
108+ function eigpolyrat (H:: SymTridiagonal{<:Real} ,z:: Number )
105109 d1 = z - H. dv[1 ]
106110 d1deriv = d2 = one (d1)
107111 d2deriv = zero (d1)
@@ -110,12 +114,16 @@ function eigpoly(H::SymTridiagonal{<:Real},z::Number)
110114 a = z - H. dv[i]
111115 d = a * d1 - b2 * d2
112116 dderiv = d1 + a * d1deriv - b2 * d2deriv
113- d2 = d1
114- d1 = d
115- d2deriv = d1deriv
116- d1deriv = dderiv
117+ if iszero (dderiv)
118+ d2, d1 = d1, d
119+ d2deriv, d1deriv = d1deriv, dderiv
120+ else # rescale to suppress under/overflow
121+ dderiv⁻¹ = inv (dderiv)
122+ d2, d1 = d1 * dderiv⁻¹, d * dderiv⁻¹
123+ d2deriv, d1deriv = d1deriv * dderiv⁻¹, one (dderiv)
124+ end
117125 end
118- return (d1, d1deriv)
126+ return d1 / d1deriv
119127end
120128
121129# compute the n smallest eigenvalues of the symmetric tridiagonal matrix H
@@ -127,14 +135,14 @@ function eignewt(H::AbstractSymTri{T}, n::Integer) where {T<:Real}
127135 lambda = Vector {float(T)} (lambda0)
128136 for i = 1 : n
129137 for k = 1 : 1000
130- (p,pderiv) = eigpoly (H,lambda[i])
131- δλ = p / pderiv # may be NaN or Inf if pderiv underflows to 0.0
138+ δλ = eigpolyrat (H,lambda[i])
132139 if isfinite (δλ)
133140 lambda[i] -= δλ
134141 if abs (δλ) ≤ 10 * eps (lambda[i])
135142 # do one final Newton iteration for luck and profit:
136- δλ = (/ )(eigpoly (H,lambda[i])... ) # = p / pderiv
137- isfinite (δλ) && (lambda[i] -= δλ)
143+ δλ = eigpolyrat (H,lambda[i])
144+ lambda[i] -= δλ
145+ break
138146 end
139147 else
140148 break
0 commit comments