@@ -513,6 +513,8 @@ fn imtqlb<T: SvdFloat>(
513513 return Ok ( ( ) ) ;
514514 }
515515
516+ let matrix_size_factor = T :: from_f64 ( ( n as f64 ) . sqrt ( ) ) . unwrap ( ) ;
517+
516518 bnd[ 0 ] = T :: one ( ) ;
517519 let last = n - 1 ;
518520 for i in 1 ..=last {
@@ -523,24 +525,36 @@ fn imtqlb<T: SvdFloat>(
523525
524526 let mut i = 0 ;
525527
528+ let mut had_convergence_issues = false ;
529+
526530 for l in 0 ..=last {
527531 let mut iteration = 0 ;
532+ let mut p = d[ l] ;
533+ let mut f = bnd[ l] ;
534+
528535 while iteration <= max_imtqlb {
529536 let mut m = l;
530537 while m < n {
531538 if m == last {
532539 break ;
533540 }
541+
542+ // More forgiving convergence test for large/sparse matrices
534543 let test = d[ m] . abs ( ) + d[ m + 1 ] . abs ( ) ;
535- if compare ( test, test + e[ m] . abs ( ) ) {
536- break ; // convergence = true;
544+ // Scale tolerance with matrix size and magnitude
545+ let tol = T :: epsilon ( )
546+ * T :: from_f64 ( 100.0 ) . unwrap ( )
547+ * test. max ( T :: one ( ) )
548+ * matrix_size_factor;
549+
550+ if e[ m] . abs ( ) <= tol {
551+ break ; // Convergence achieved for this element
537552 }
538553 m += 1 ;
539554 }
540- let mut p = d[ l] ;
541- let mut f = bnd[ l] ;
555+
542556 if m == l {
543- // order the eigenvalues
557+ // Order the eigenvalues
544558 let mut exchange = true ;
545559 if l > 0 {
546560 i = l;
@@ -559,14 +573,25 @@ fn imtqlb<T: SvdFloat>(
559573 }
560574 d[ i] = p;
561575 bnd[ i] = f;
562- iteration = max_imtqlb + 1 ;
576+ iteration = max_imtqlb + 1 ; // Exit the loop
563577 } else {
578+ // Check if we've reached max iterations without convergence
564579 if iteration == max_imtqlb {
565- return Err ( SvdLibError :: ImtqlbError ( format ! (
566- "imtqlb no convergence to an eigenvalue after {} iterations" ,
567- max_imtqlb
568- ) ) ) ;
580+ // CRITICAL CHANGE: Don't fail, just note the issue and continue
581+ had_convergence_issues = true ;
582+
583+ // Set conservative error bounds for non-converged values
584+ for idx in l..=m {
585+ bnd[ idx] = bnd[ idx] . max ( T :: from_f64 ( 0.1 ) . unwrap ( ) ) ;
586+ }
587+
588+ // Force "convergence" by zeroing the problematic subdiagonal element
589+ e[ l] = T :: zero ( ) ;
590+
591+ // Break out of the iteration loop and move to next eigenvalue
592+ break ;
569593 }
594+
570595 iteration += 1 ;
571596 // ........ form shift ........
572597 let two = T :: from_f64 ( 2.0 ) . unwrap ( ) ;
@@ -585,14 +610,22 @@ fn imtqlb<T: SvdFloat>(
585610 let b = c * e[ i] ;
586611 r = svd_pythag ( f, g) ;
587612 e[ i + 1 ] = r;
588- if compare ( r, T :: zero ( ) ) {
613+
614+ // More forgiving underflow detection for sparse matrices
615+ if r < T :: epsilon ( ) * T :: from_f64 ( 1000.0 ) . unwrap ( ) * ( f. abs ( ) + g. abs ( ) ) {
589616 underflow = true ;
590617 break ;
591618 }
619+
620+ // Safety check for division by very small numbers
621+ if r. abs ( ) < T :: epsilon ( ) * T :: from_f64 ( 100.0 ) . unwrap ( ) {
622+ r = T :: epsilon ( ) * T :: from_f64 ( 100.0 ) . unwrap ( ) * svd_fsign ( T :: one ( ) , r) ;
623+ }
624+
592625 s = f / r;
593626 c = g / r;
594627 g = d[ i + 1 ] - p;
595- r = ( d[ i] - g) * s + two * c * b;
628+ r = ( d[ i] - g) * s + T :: from_f64 ( 2.0 ) . unwrap ( ) * c * b;
596629 p = s * r;
597630 d[ i + 1 ] = g + p;
598631 g = c * r - b;
@@ -615,6 +648,9 @@ fn imtqlb<T: SvdFloat>(
615648 }
616649 }
617650 }
651+ if had_convergence_issues {
652+ eprintln ! ( "Warning: imtqlb had some convergence issues but continued with best estimates. Results may have reduced accuracy." ) ;
653+ }
618654 Ok ( ( ) )
619655}
620656
@@ -1306,14 +1342,43 @@ fn lanso<T: SvdFloat>(
13061342 store : & mut Store < T > ,
13071343 random_seed : u32 ,
13081344) -> Result < usize , SvdLibError > {
1345+ let sparsity = T :: one ( )
1346+ - ( T :: from_usize ( A . nnz ( ) ) . unwrap ( )
1347+ / ( T :: from_usize ( A . nrows ( ) ) . unwrap ( ) * T :: from_usize ( A . ncols ( ) ) . unwrap ( ) ) ) ;
1348+ let max_iterations_imtqlb = if sparsity > T :: from_f64 ( 0.999 ) . unwrap ( ) {
1349+ // Ultra sparse (>99.9%) - needs many more iterations
1350+ Some ( 500 )
1351+ } else if sparsity > T :: from_f64 ( 0.99 ) . unwrap ( ) {
1352+ // Very sparse (>99%) - needs more iterations
1353+ Some ( 200 )
1354+ } else if sparsity > T :: from_f64 ( 0.9 ) . unwrap ( ) {
1355+ // Moderately sparse (>90%) - needs somewhat more iterations
1356+ Some ( 100 )
1357+ } else {
1358+ // Default iterations for less sparse matrices
1359+ Some ( 50 )
1360+ } ;
1361+
1362+ let epsilon = T :: epsilon ( ) ;
1363+ let adaptive_eps = if sparsity > T :: from_f64 ( 0.99 ) . unwrap ( ) {
1364+ // For very sparse matrices (>99%), use a more relaxed tolerance
1365+ epsilon * T :: from_f64 ( 100.0 ) . unwrap ( )
1366+ } else if sparsity > T :: from_f64 ( 0.9 ) . unwrap ( ) {
1367+ // For moderately sparse matrices (>90%), use a somewhat relaxed tolerance
1368+ epsilon * T :: from_f64 ( 10.0 ) . unwrap ( )
1369+ } else {
1370+ // For less sparse matrices, use standard epsilon
1371+ epsilon
1372+ } ;
1373+
13091374 let ( endl, endr) = ( end_interval[ 0 ] , end_interval[ 1 ] ) ;
13101375
13111376 /* take the first step */
13121377 let rnm_tol = stpone ( A , wrk, store, random_seed) ?;
13131378 let mut rnm = rnm_tol. 0 ;
13141379 let mut tol = rnm_tol. 1 ;
13151380
1316- let eps1 = T :: eps ( ) * T :: from_f64 ( wrk. ncols as f64 ) . unwrap ( ) . sqrt ( ) ;
1381+ let eps1 = adaptive_eps * T :: from_f64 ( wrk. ncols as f64 ) . unwrap ( ) . sqrt ( ) ;
13171382 wrk. eta [ 0 ] = eps1;
13181383 wrk. oldeta [ 0 ] = eps1;
13191384 let mut ll = 0 ;
@@ -1357,7 +1422,7 @@ fn lanso<T: SvdFloat>(
13571422
13581423 let mut i = l;
13591424 while i <= j {
1360- if compare ( wrk. bet [ i + 1 ] , T :: zero ( ) ) {
1425+ if wrk. bet [ i + 1 ] . abs ( ) <= adaptive_eps {
13611426 break ;
13621427 }
13631428 i += 1 ;
@@ -1374,8 +1439,8 @@ fn lanso<T: SvdFloat>(
13741439 & mut wrk. ritz [ l..] ,
13751440 & mut wrk. w5 [ l..] ,
13761441 & mut wrk. bnd [ l..] ,
1377- None ,
1378- ) ?; // TODO
1442+ max_iterations_imtqlb ,
1443+ ) ?;
13791444
13801445 for m in l..=i {
13811446 wrk. bnd [ m] = rnm * wrk. bnd [ m] . abs ( ) ;
@@ -1394,7 +1459,13 @@ fn lanso<T: SvdFloat>(
13941459 last = first + 9 ;
13951460 intro = first;
13961461 } else {
1397- last = first + 3 . max ( 1 + ( ( j - intro) * ( dim - * neig) ) / * neig) ;
1462+ let extra_steps = if sparsity > T :: from_f64 ( 0.99 ) . unwrap ( ) {
1463+ 5 // For very sparse matrices, add extra steps
1464+ } else {
1465+ 0
1466+ } ;
1467+
1468+ last = first + 3 . max ( 1 + ( ( j - intro) * ( dim - * neig) ) / * neig) + extra_steps;
13981469 }
13991470 last = last. min ( iterations) ;
14001471 } else {
0 commit comments