@@ -4,12 +4,11 @@ use anyhow::Ok;
44use num_traits:: Float ;
55use rand:: { Rng , SeedableRng , seq:: SliceRandom } ;
66use rand_chacha:: ChaCha8Rng ;
7- use rayon:: iter:: { IntoParallelRefIterator , ParallelIterator } ;
87use single_utilities:: traits:: FloatOpsTS ;
98
109use crate :: {
1110 community_search:: leiden:: { ConsiderComms , LeidenConfig , partition:: VertexPartition } ,
12- network:: { Network , grouping:: NetworkGrouping } ,
11+ network:: { CSRNetwork , grouping:: NetworkGrouping } ,
1312} ;
1413
1514#[ derive( Debug , Clone ) ]
@@ -168,53 +167,111 @@ impl LeidenOptimizer {
168167 }
169168
170169 fn find_best_community_move < N , G , P > (
171- & self ,
172- v : usize ,
173- v_comm : usize ,
174- comms : & [ usize ] ,
175- partitions : & [ P ] ,
176- layer_weights : & [ N ] ,
177- max_comm_size : Option < usize > ,
178- ) -> anyhow:: Result < ( usize , N ) >
179- where
180- N : FloatOpsTS + ' static ,
181- G : NetworkGrouping ,
182- P : VertexPartition < N , G > ,
183- {
184- let mut max_comm = v_comm;
185- let mut max_improv = if let Some ( max_size) = max_comm_size {
186- if max_size < partitions[ 0 ] . csize ( v_comm) {
187- <N as Float >:: neg_infinity ( )
188- } else {
189- N :: from ( 10.0 ) . unwrap ( ) * <N as Float >:: epsilon ( )
190- }
170+ & self ,
171+ v : usize ,
172+ v_comm : usize ,
173+ comms : & [ usize ] ,
174+ partitions : & mut [ P ] , // Changed to mutable slice
175+ layer_weights : & [ N ] ,
176+ max_comm_size : Option < usize > ,
177+ ) -> anyhow:: Result < ( usize , N ) >
178+ where
179+ N : FloatOpsTS + ' static ,
180+ G : NetworkGrouping ,
181+ P : VertexPartition < N , G > ,
182+ {
183+ let mut max_comm = v_comm;
184+ let time = Instant :: now ( ) ;
185+ // println!("Finding best community move: {:?}", time.elapsed());
186+
187+ // Pre-compute these values once instead of in the loop
188+ let v_comm_size = partitions[ 0 ] . csize ( v_comm) ;
189+ let epsilon_threshold = N :: from ( 10.0 ) . unwrap ( ) * <N as Float >:: epsilon ( ) ;
190+
191+ let mut max_improv = if let Some ( max_size) = max_comm_size {
192+ if max_size < v_comm_size {
193+ <N as Float >:: neg_infinity ( )
191194 } else {
192- N :: from ( 10.0 ) . unwrap ( ) * <N as Float >:: epsilon ( )
193- } ;
195+ epsilon_threshold
196+ }
197+ } else {
198+ epsilon_threshold
199+ } ;
194200
195- let v_size = 1 ; // assuming unsit size
201+ const V_SIZE : usize = 1 ; // Made it a const for better optimization
196202
197- for & comm in comms {
198- if let Some ( max_size) = max_comm_size {
199- if max_size < partitions[ 0 ] . csize ( comm) + v_size {
200- continue ;
201- }
202- }
203+ // Early exit if no communities to check
204+ if comms. is_empty ( ) {
205+ return Ok ( ( max_comm, max_improv) ) ;
206+ }
207+
208+ // println!("Prefiltering valid comms {:?}", time.elapsed());
209+ // Pre-filter communities by size constraint to avoid repeated checks
210+ let valid_comms: Vec < usize > = if let Some ( max_size) = max_comm_size {
211+ comms
212+ . iter ( )
213+ . copied ( )
214+ . filter ( |& comm| partitions[ 0 ] . csize ( comm) + V_SIZE <= max_size)
215+ . collect ( )
216+ } else {
217+ comms. to_vec ( )
218+ } ;
219+ // println!("Filtered valid comms: {:?}", time.elapsed());
220+
221+ // Early exit if no valid communities
222+ if valid_comms. is_empty ( ) {
223+ return Ok ( ( max_comm, max_improv) ) ;
224+ }
203225
226+ // Optimized single-layer case
227+ if partitions. len ( ) == 1 && layer_weights[ 0 ] == N :: one ( ) {
228+ // println!("checking valid comms: {:?}", time.elapsed());
229+
230+ // Get mutable reference to the single partition
231+ let partition = & mut partitions[ 0 ] ;
232+
233+ for & comm in & valid_comms {
234+ let t = Instant :: now ( ) ;
235+ let possible_improv = partition. diff_move ( v, comm) ;
236+ // println!("Executed diff move, took: {:?}", t.elapsed());
237+
238+ if possible_improv > max_improv {
239+ max_comm = comm;
240+ max_improv = possible_improv;
241+ }
242+ }
243+ } else {
244+ // Multi-layer case
245+ for & comm in & valid_comms {
204246 let mut possible_improv = N :: zero ( ) ;
205- for ( layer, partition) in partitions. iter ( ) . enumerate ( ) {
206- let layer_improv = partition. diff_move ( v, comm) ;
207- possible_improv += layer_weights[ layer] * layer_improv;
247+
248+ for layer_idx in 0 ..partitions. len ( ) {
249+ // Get mutable reference to current partition
250+ let layer_improv = partitions[ layer_idx] . diff_move ( v, comm) ;
251+ possible_improv += layer_weights[ layer_idx] * layer_improv;
252+
253+ // Early termination optimization
254+ if possible_improv + epsilon_threshold < max_improv {
255+ let remaining_positive = layer_weights[ layer_idx + 1 ..]
256+ . iter ( )
257+ . all ( |& w| w >= N :: zero ( ) ) ;
258+
259+ if remaining_positive && layer_improv <= N :: zero ( ) {
260+ break ;
261+ }
262+ }
208263 }
209264
210265 if possible_improv > max_improv {
211266 max_comm = comm;
212267 max_improv = possible_improv;
213268 }
214269 }
215- Ok ( ( max_comm, max_improv) )
216270 }
217271
272+ Ok ( ( max_comm, max_improv) )
273+ }
274+
218275 fn collect_candidate_communities < N , G , P > (
219276 & mut self ,
220277 v : usize ,
@@ -330,7 +387,7 @@ impl LeidenOptimizer {
330387 P : VertexPartition < N , G > ,
331388 {
332389 let time = Instant :: now ( ) ;
333- println ! ( "MOVE_NODES | Starting | time: {:?}" , time. elapsed( ) ) ;
390+ // println!("MOVE_NODES | Starting | time: {:?}", time.elapsed());
334391 if partitions. is_empty ( ) {
335392 return Ok ( N :: from ( -1.0 ) . unwrap ( ) ) ;
336393 }
@@ -366,10 +423,10 @@ impl LeidenOptimizer {
366423 let mut comm_added = vec ! [ false ; partitions[ 0 ] . community_count( ) ] ;
367424 let mut comms = Vec :: new ( ) ;
368425
369- println ! (
370- "MOVE_NODES | Basic setup finished... | time: {:?}" ,
371- time. elapsed( )
372- ) ;
426+ // println!(
427+ // "MOVE_NODES | Basic setup finished... | time: {:?}",
428+ // time.elapsed()
429+ // );
373430 let mut i: i32 = 0 ;
374431 while let Some ( v) = vertex_order. pop_front ( ) {
375432 // println!(
@@ -394,24 +451,24 @@ impl LeidenOptimizer {
394451
395452 self . collect_candidate_communities (
396453 v,
397- & partitions,
454+ partitions,
398455 consider_comms,
399456 & mut comms,
400457 & mut comm_added,
401458 ) ;
402459
403- //println!(
404- // "MOVE_NODES | Found all candidates | time: {:?} | iteration: {:?}",
405- // time.elapsed(),
406- // i
407- //);
460+ // println!(
461+ // "MOVE_NODES | Found all candidates | time: {:?} | iteration: {:?}",
462+ // time.elapsed(),
463+ // i
464+ // );
408465
409466 if consider_empty_community && partitions[ 0 ] . cnodes ( v_comm) > 1 {
410- //println!(
411- // "MOVE_NODES | Considering empty move | time: {:?} | iteration: {:?}",
412- // time.elapsed(),
413- // i
414- //);
467+ // println!(
468+ // "MOVE_NODES | Considering empty move | time: {:?} | iteration: {:?}",
469+ // time.elapsed(),
470+ // i
471+ // );
415472 let n_comms_before = partitions[ 0 ] . community_count ( ) ;
416473 let empty_comm = partitions[ 0 ] . get_empty_community ( ) ;
417474 comms. push ( empty_comm) ;
@@ -668,7 +725,7 @@ impl LeidenOptimizer {
668725 v : usize ,
669726 v_comm : usize ,
670727 comms : & [ usize ] ,
671- partitions : & [ P ] ,
728+ partitions : & mut [ P ] ,
672729 layer_weights : & [ N ] ,
673730 max_comm_size : Option < usize > ,
674731 ) -> anyhow:: Result < ( usize , N ) >
@@ -698,7 +755,7 @@ impl LeidenOptimizer {
698755 }
699756
700757 let mut possible_improvement = N :: zero ( ) ;
701- for ( layer, partition) in partitions. iter ( ) . enumerate ( ) {
758+ for ( layer, partition) in partitions. iter_mut ( ) . enumerate ( ) {
702759 let layer_improv = partition. diff_move ( v, comm) ;
703760 possible_improvement += layer_weights[ layer] * layer_improv;
704761 }
@@ -823,7 +880,7 @@ impl LeidenOptimizer {
823880
824881 let mut possible_improv = N :: zero ( ) ;
825882
826- for ( layer, partition) in partitions. iter ( ) . enumerate ( ) {
883+ for ( layer, partition) in partitions. iter_mut ( ) . enumerate ( ) {
827884 let layer_imrpov = partition. diff_move ( v, comm) ;
828885 possible_improv += layer_weights[ layer] * layer_imrpov;
829886 }
@@ -910,9 +967,9 @@ impl LeidenOptimizer {
910967 for layer in 0 ..nb_layers {
911968 let collapsed_network = collapsed_partitions[ layer]
912969 . network ( )
913- . create_reduced_network ( sub_collapsed_partitions[ layer] . grouping ( ) ) ;
970+ . aggregate ( sub_collapsed_partitions[ layer] . grouping ( ) ) ;
914971 let refined_membership = sub_collapsed_partitions[ layer] . membership_vector ( ) ;
915- let mut new_membership = vec ! [ 0 ; collapsed_network. nodes ( ) ] ;
972+ let mut new_membership = vec ! [ 0 ; collapsed_network. node_count ( ) ] ;
916973
917974 for v in 0 ..collapsed_partitions[ layer] . node_count ( ) {
918975 let refined_comm = refined_membership[ v] ;
@@ -939,9 +996,7 @@ impl LeidenOptimizer {
939996 let mut new_collapsed_partitions = Vec :: new ( ) ;
940997
941998 for partition in collapsed_partitions {
942- let collapsed_network = partition
943- . network ( )
944- . create_reduced_network ( partition. grouping ( ) ) ;
999+ let collapsed_network = partition. network ( ) . aggregate ( partition. grouping ( ) ) ;
9451000 let new_partition = partition. create_like ( collapsed_network) ;
9461001 new_collapsed_partitions. push ( new_partition) ;
9471002 }
@@ -1042,7 +1097,7 @@ impl LeidenOptimizer {
10421097 }
10431098
10441099 // Initialize collapsed structures - start with original partitions
1045- let mut collapsed_partitions: Vec < P > = partitions. iter ( ) . cloned ( ) . collect ( ) ;
1100+ let mut collapsed_partitions: Vec < P > = partitions. to_vec ( ) ;
10461101 let mut is_collapsed_membership_fixed = is_membership_fixed. to_vec ( ) ;
10471102 let mut aggregate_node_per_individual_node: Vec < usize > = ( 0 ..n) . collect ( ) ;
10481103 let mut is_first_iteration = true ;
@@ -1172,7 +1227,7 @@ impl LeidenOptimizer {
11721227 Ok ( improvement)
11731228 }
11741229
1175- pub fn find_partition < N , G , P > ( & mut self , network : Network < N , N > ) -> anyhow:: Result < P >
1230+ pub fn find_partition < N , G , P > ( & mut self , network : CSRNetwork < N , N > ) -> anyhow:: Result < P >
11761231 where
11771232 N : FloatOpsTS + ' static ,
11781233 G : NetworkGrouping + Clone + Default ,
0 commit comments