@@ -205,10 +205,21 @@ where
205205 diag[ start + 1 ] . clone ( ) ,
206206 ) ;
207207 let eigvals = m. eigenvalues ( ) . unwrap ( ) ;
208- let basis = Vector2 :: new (
209- eigvals. x . clone ( ) - diag[ start + 1 ] . clone ( ) ,
210- off_diag[ start] . clone ( ) ,
211- ) ;
208+
209+ // Choose the basis least likely to experience cancellation
210+ let basis = if ( eigvals. x . clone ( ) - diag[ start + 1 ] . clone ( ) ) . abs ( )
211+ > ( eigvals. x . clone ( ) - diag[ start] . clone ( ) ) . abs ( )
212+ {
213+ Vector2 :: new (
214+ eigvals. x . clone ( ) - diag[ start + 1 ] . clone ( ) ,
215+ off_diag[ start] . clone ( ) ,
216+ )
217+ } else {
218+ Vector2 :: new (
219+ off_diag[ start] . clone ( ) ,
220+ eigvals. x . clone ( ) - diag[ start] . clone ( ) ,
221+ )
222+ } ;
212223
213224 diag[ start] = eigvals[ 0 ] . clone ( ) ;
214225 diag[ start + 1 ] = eigvals[ 1 ] . clone ( ) ;
@@ -348,7 +359,36 @@ where
348359
349360#[ cfg( test) ]
350361mod test {
351- use crate :: base:: Matrix2 ;
362+ use crate :: base:: { Matrix2 , Matrix4 } ;
363+
364+ /// Exercises bug reported in issue #1109 of nalgebra (https://github.com/dimforge/nalgebra/issues/1109)
365+ #[ test]
366+ fn symmetric_eigen_regression_issue_1109 ( ) {
367+ let m = Matrix4 :: new (
368+ -19884.07f64 ,
369+ -10.07188 ,
370+ 11.277279 ,
371+ -188560.63 ,
372+ -10.07188 ,
373+ 12.518197 ,
374+ 1.3770627 ,
375+ -102.97504 ,
376+ 11.277279 ,
377+ 1.3770627 ,
378+ 14.587362 ,
379+ 113.26099 ,
380+ -188560.63 ,
381+ -102.97504 ,
382+ 113.26099 ,
383+ -1788112.3 ,
384+ ) ;
385+ let eig = m. symmetric_eigen ( ) ;
386+ assert ! ( relative_eq!(
387+ m. lower_triangle( ) ,
388+ eig. recompose( ) . lower_triangle( ) ,
389+ epsilon = 1.0e-5
390+ ) ) ;
391+ }
352392
353393 fn expected_shift ( m : Matrix2 < f64 > ) -> f64 {
354394 let vals = m. eigenvalues ( ) . unwrap ( ) ;
0 commit comments