@@ -13,59 +13,73 @@ where
1313 let n = a. nrows ( ) ;
1414 let n_coarse = coarse_of. iter ( ) . filter ( |& & c| c != usize:: MAX ) . count ( ) ;
1515
16+ // Better capacity estimation based on connectivity
17+ let f_points = marks. iter ( ) . filter ( |& & m| matches ! ( m, Mark :: F ) ) . count ( ) ;
18+ let estimated_nnz = n_coarse + f_points * 4 ; // More accurate estimate
19+
1620 let mut trip = CooMatrix :: new ( n, n_coarse) ;
17- // Pre-estimate capacity to reduce reallocations
18- let estimated_nnz = n + ( n - n_coarse) * 3 ; // Rough estimate
1921 trip. reserve ( estimated_nnz) ;
2022
23+ // Pre-allocate reusable vectors
24+ let mut c_neighbors = Vec :: with_capacity ( 8 ) ;
25+ let mut weights = Vec :: with_capacity ( 8 ) ;
26+
2127 for i in 0 ..n {
2228 match marks[ i] {
2329 Mark :: C => {
24- let j = coarse_of[ i] ;
25- trip. push ( i, j, N :: one ( ) ) ;
30+ trip. push ( i, coarse_of[ i] , N :: one ( ) ) ;
2631 }
2732 Mark :: F => {
28- // Find C-point neighbors in the strength graph
29- let c_neighbors: Vec < usize > = s[ i]
30- . iter ( )
31- . copied ( )
32- . filter ( |& nbr| matches ! ( marks[ nbr] , Mark :: C ) )
33- . collect ( ) ;
33+ c_neighbors. clear ( ) ;
34+ // Collect coarse neighbors
35+ for & nbr in & s[ i] {
36+ if matches ! ( marks[ nbr] , Mark :: C ) {
37+ c_neighbors. push ( nbr) ;
38+ }
39+ }
3440
41+ // If no coarse neighbors, add a zero entry
3542 if c_neighbors. is_empty ( ) {
36- // Fallback: connect to first coarse point if available
3743 if n_coarse > 0 {
3844 trip. push ( i, 0 , N :: one ( ) ) ;
3945 }
4046 continue ;
4147 }
4248
43- // Compute interpolation weights
44- if let Some ( diag_entry) = a. get_entry ( i, i) {
45- let diag = diag_entry. into_value ( ) ;
46- let mut weight_sum = N :: zero ( ) ;
47-
48- // First pass: compute weights
49- let mut weights = Vec :: with_capacity ( c_neighbors. len ( ) ) ;
49+ // Early exit if no diagonal entry
50+ let Some ( diag_entry) = a. get_entry ( i, i) else {
51+ let equal_weight = N :: one ( ) / N :: from_usize ( c_neighbors. len ( ) ) . unwrap ( ) ;
5052 for & nbr in & c_neighbors {
51- if let Some ( a_ij) = a. get_entry ( i, nbr) {
52- let w = -a_ij. into_value ( ) / diag;
53- weights. push ( ( coarse_of[ nbr] , w) ) ;
54- weight_sum += w;
55- }
53+ trip. push ( i, coarse_of[ nbr] , equal_weight) ;
54+ }
55+ continue ;
56+ } ;
57+
58+ let diag = diag_entry. into_value ( ) ;
59+ let mut weight_sum = N :: zero ( ) ;
60+
61+ weights. clear ( ) ;
62+ weights. reserve ( c_neighbors. len ( ) ) ;
63+
64+ // Compute weights in single pass
65+ for & nbr in & c_neighbors {
66+ if let Some ( a_ij) = a. get_entry ( i, nbr) {
67+ let w = -a_ij. into_value ( ) / diag;
68+ weights. push ( ( coarse_of[ nbr] , w) ) ;
69+ weight_sum += w;
5670 }
57-
58- // Normalize weights to sum to 1 for better stability
59- if weight_sum != N :: zero ( ) {
60- for ( col , w ) in weights {
61- trip . push ( i , col , w / weight_sum) ;
62- }
63- } else {
64- // Fallback: equal weights
65- let equal_weight = N :: one ( ) / N :: from_usize ( c_neighbors . len ( ) ) . unwrap ( ) ;
66- for & nbr in & c_neighbors {
67- trip . push ( i , coarse_of [ nbr ] , equal_weight ) ;
68- }
71+ }
72+
73+ // Add entries with normalized weights
74+ if weight_sum != N :: zero ( ) {
75+ let inv_sum = N :: one ( ) / weight_sum;
76+ for ( col , w ) in weights . drain ( .. ) {
77+ trip . push ( i , col , w * inv_sum ) ;
78+ }
79+ } else {
80+ let equal_weight = N :: one ( ) / N :: from_usize ( c_neighbors. len ( ) ) . unwrap ( ) ;
81+ for & nbr in & c_neighbors {
82+ trip . push ( i , coarse_of [ nbr ] , equal_weight ) ;
6983 }
7084 }
7185 }
0 commit comments