@@ -135,6 +135,16 @@ where
135135
136136 // Implicit double-shift QR method.
137137 let mut niter = 0 ;
138+ // Number of QR steps since the active window last shrank due to a deflation.
139+ let mut kdefl: usize = 0 ;
140+ // Apply Wilkinson's exceptional shift every kexsh stalled QR steps.
141+ let kexsh: usize = 10 ;
142+ // This is used by the exceptional shift algorithm as mentioned in
143+ // Wilkinson, J. H., & Reinsch, C. (1971).
144+ // Handbook for automatic computation (Vol. 2: Linear algebra)
145+ // P.373
146+ let exceptional_shift_a: T :: RealField = crate :: convert ( 0.75 ) ;
147+ let exceptional_shift_b: T :: RealField = crate :: convert ( -0.4375 ) ;
138148 let ( mut start, mut end) = Self :: delimit_subproblem ( & mut t, eps. clone ( ) , dim. value ( ) - 1 ) ;
139149
140150 while end != start {
@@ -150,10 +160,28 @@ where
150160 let h22 = t[ ( start + 1 , start + 1 ) ] . clone ( ) ;
151161 let h32 = t[ ( start + 2 , start + 1 ) ] . clone ( ) ;
152162
153- let hnn = t[ ( n, n) ] . clone ( ) ;
154- let hmm = t[ ( m, m) ] . clone ( ) ;
155- let hnm = t[ ( n, m) ] . clone ( ) ;
156- let hmn = t[ ( m, n) ] . clone ( ) ;
163+ let ( hnn, hmm, hnm, hmn) = if kdefl != 0 && kdefl % kexsh == 0 {
164+ let s = t[ ( start + 1 , start) ] . clone ( ) . norm1 ( )
165+ + t[ ( start + 2 , start + 1 ) ] . clone ( ) . norm1 ( ) ;
166+ let h = t[ ( start, start) ] . clone ( )
167+ + T :: from_real ( exceptional_shift_a. clone ( ) * s. clone ( ) ) ;
168+ // When the implicit QR step stalls, replace the trailing 2x2 Wilkinson shift
169+ // with the exceptional-shift coefficients from Wilkinson & Reinsch. This
170+ // perturbs the bulge start enough to escape the non-convergent cycle.
171+ (
172+ h. clone ( ) ,
173+ h,
174+ T :: from_real ( exceptional_shift_b. clone ( ) * s. clone ( ) ) ,
175+ T :: from_real ( s) ,
176+ )
177+ } else {
178+ (
179+ t[ ( n, n) ] . clone ( ) ,
180+ t[ ( m, m) ] . clone ( ) ,
181+ t[ ( n, m) ] . clone ( ) ,
182+ t[ ( m, n) ] . clone ( ) ,
183+ )
184+ } ;
157185
158186 let tra = hnn. clone ( ) + hmm. clone ( ) ;
159187 let det = hnn * hmm - hnm * hmn;
@@ -256,10 +284,19 @@ where
256284 }
257285 }
258286
287+ let prev_start = start;
288+ let prev_end = end;
259289 let sub = Self :: delimit_subproblem ( & mut t, eps. clone ( ) , end) ;
260290
261291 start = sub. 0 ;
262292 end = sub. 1 ;
293+ if end < prev_end || start > prev_start {
294+ // A split or deflation changed the active window, so restart the stall counter.
295+ kdefl = 0 ;
296+ } else {
297+ // No deflation occurred: count another QR step toward an exceptional shift.
298+ kdefl += 1 ;
299+ }
263300
264301 niter += 1 ;
265302 if niter == max_niter {
0 commit comments