11use crate :: Error ;
22use itertools:: Itertools as _;
3- use num:: FromPrimitive ;
4- use num:: One ;
5- use num:: Zero ;
63use rayon:: iter:: IntoParallelRefIterator as _;
74use rayon:: iter:: ParallelIterator as _;
85use std:: iter:: Sum ;
96use std:: ops:: AddAssign ;
107use std:: ops:: Sub ;
11- use std:: ops:: SubAssign ;
128
139fn vn_first_mono < T > (
1410 partition : & mut [ usize ] ,
@@ -39,18 +35,20 @@ where
3935 let ( min_load, mut max_load) = part_loads. iter ( ) . cloned ( ) . minmax ( ) . into_option ( ) . unwrap ( ) ;
4036 let mut imbalance = max_load. clone ( ) - min_load;
4137
42- let mut i = weights . len ( ) ;
38+ let mut i = 0 ;
4339 let mut i_last = 0 ;
4440 let mut algo_iterations = 0 ;
45- while i != i_last {
46- i = ( i + 1 ) % weights. len ( ) ;
47-
41+ loop {
4842 // loop through the weights.
4943 let p = partition[ i] ;
5044
5145 if part_loads[ p] < max_load {
5246 // weight #i is not in the heaviest partition, and thus the move
5347 // will not reduce the max imbalance.
48+ i = ( i + 1 ) % weights. len ( ) ;
49+ if i == i_last {
50+ break ;
51+ }
5452 continue ;
5553 }
5654
@@ -66,135 +64,29 @@ where
6664 let ( new_min_load, new_max_load) =
6765 part_loads. iter ( ) . cloned ( ) . minmax ( ) . into_option ( ) . unwrap ( ) ;
6866 let new_imbalance = new_max_load. clone ( ) - new_min_load. clone ( ) ;
69- if imbalance < new_imbalance {
67+ if new_imbalance <= imbalance {
68+ // The move decreases the partition imbalance.
69+ imbalance = new_imbalance;
70+ max_load = new_max_load;
71+ partition[ i] = q;
72+ i_last = i;
73+ } else {
7074 // The move does not decrease the partition imbalance.
7175 part_loads[ p] += weights[ i] . clone ( ) ;
7276 part_loads[ q] = part_loads[ p] . clone ( ) - weights[ i] . clone ( ) ;
7377 continue ;
7478 }
75- imbalance = new_imbalance;
76- max_load = new_max_load;
77- partition[ i] = q;
78- i_last = i;
79- }
80-
81- algo_iterations += 1 ;
82- }
83-
84- Ok ( algo_iterations)
85- }
86-
87- #[ allow( dead_code) ]
88- pub fn vn_first < const C : usize , T > (
89- partition : & mut [ usize ] ,
90- criteria : & [ [ T ; C ] ] ,
91- num_parts : usize ,
92- ) -> usize
93- where
94- T : AddAssign + SubAssign + Sub < Output = T > + Sum ,
95- T : Zero + One + FromPrimitive ,
96- T : Copy + Ord ,
97- {
98- if num_parts < 2 || criteria. is_empty ( ) || C == 0 {
99- return 0 ;
100- }
101-
102- assert_eq ! ( criteria. len( ) , partition. len( ) ) ;
103-
104- let mut part_loads_per_criterion = {
105- let mut loads = vec ! [ [ T :: zero( ) ; C ] ; num_parts] ;
106- for ( w, weight) in criteria. iter ( ) . enumerate ( ) {
107- for ( part_load, criterion) in loads[ partition[ w] ] . iter_mut ( ) . zip ( weight) {
108- * part_load += * criterion;
109- }
110- }
111- loads
112- } ;
113- let total_weight_per_criterion = {
114- // TODO replace with .collect() once [_; C] implements FromIterator.
115- let mut ws = [ T :: zero ( ) ; C ] ;
116- for c in 0 ..C {
117- ws[ c] = part_loads_per_criterion[ c] . iter ( ) . cloned ( ) . sum ( ) ;
118- }
119- ws
120- } ;
121- if total_weight_per_criterion. contains ( & T :: zero ( ) ) {
122- return 0 ;
123- }
124-
125- let min_max_loads = |part_loads_per_criterion : & Vec < [ T ; C ] > | -> [ ( T , T ) ; C ] {
126- // TODO replace with .collect() once [_; C] implements FromIterator.
127- let mut imbs = [ ( T :: zero ( ) , T :: zero ( ) ) ; C ] ;
128- for c in 0 ..C {
129- imbs[ c] = part_loads_per_criterion[ c]
130- . iter ( )
131- . cloned ( )
132- . minmax ( )
133- . into_option ( )
134- . unwrap ( ) ;
135- }
136- imbs
137- } ;
138-
139- let ( global_min_load, mut global_max_load) = * min_max_loads ( & part_loads_per_criterion)
140- . iter ( )
141- . max_by_key ( |( min_load, max_load) | * max_load - * min_load)
142- . unwrap ( ) ;
143- let mut imbalance = global_max_load - global_min_load;
144-
145- let mut i = 0 ;
146- let mut i_last = 0 ;
147- let mut algo_iterations = 0 ;
148- while i != i_last {
149- i = ( i + 1 ) % criteria. len ( ) ;
150-
151- // loop through the weights.
152- let p = partition[ i] ;
153-
154- if part_loads_per_criterion[ p]
155- . iter ( )
156- . all ( |criterion_load| * criterion_load < global_max_load)
157- {
158- // weight #i is not in the heaviest partition, and thus the move
159- // will not reduce the max imbalance.
160- continue ;
16179 }
16280
163- for q in 0 ..num_parts {
164- // loop through the parts.
165- if p == q {
166- // weight #i is already in partition #q.
167- continue ;
168- }
169-
170- for c in 0 ..C {
171- part_loads_per_criterion[ p] [ c] -= criteria[ i] [ c] ;
172- part_loads_per_criterion[ q] [ c] += criteria[ i] [ c] ;
173- }
174- let ( new_global_min_load, new_global_max_load) =
175- * min_max_loads ( & part_loads_per_criterion)
176- . iter ( )
177- . max_by_key ( |( min_load, max_load) | * max_load - * min_load)
178- . unwrap ( ) ;
179- let new_imbalance = new_global_max_load - new_global_min_load;
180- if imbalance < new_imbalance {
181- // The move does not decrease the partition imbalance.
182- for c in 0 ..C {
183- part_loads_per_criterion[ p] [ c] += criteria[ i] [ c] ;
184- part_loads_per_criterion[ q] [ c] -= criteria[ i] [ c] ;
185- }
186- continue ;
187- }
188- imbalance = new_imbalance;
189- global_max_load = new_global_max_load;
190- partition[ i] = q;
191- i_last = i;
81+ i = ( i + 1 ) % weights. len ( ) ;
82+ if i == i_last {
83+ break ;
19284 }
19385
19486 algo_iterations += 1 ;
19587 }
19688
197- algo_iterations
89+ Ok ( algo_iterations)
19890}
19991
20092/// Trait alias for values accepted as weights by [VnFirst].
@@ -306,18 +198,26 @@ mod tests {
306198 #[ test]
307199 fn small ( ) {
308200 const W : [ [ i32 ; 2 ] ; 6 ] = [ [ 1 , 2 ] , [ 2 , 4 ] , [ 3 , 6 ] , [ 8 , 4 ] , [ 10 , 5 ] , [ 12 , 6 ] ] ;
309- let mut part = [ 0 ; W . len ( ) ] ;
201+ let w: Vec < _ > = W
202+ . iter ( )
203+ . map ( |w| nalgebra:: SVector :: < i32 , 2 > :: from ( * w) )
204+ . collect ( ) ;
205+ let mut partition = [ 0 ; W . len ( ) ] ;
310206
311- vn_first ( & mut part, & W , 1 ) ;
207+ vn_first_mono ( & mut partition, & w, 2 ) . unwrap ( ) ;
208+ println ! ( "partition: {partition:?}" ) ;
312209 let imbs_ini: Vec < i32 > = ( 0 ..W [ 0 ] . len ( ) )
313- . map ( |c| imbalance:: max_imbalance ( 2 , & part, W . par_iter ( ) . map ( |w| w[ c] ) ) )
210+ . map ( |c| imbalance:: max_imbalance ( 2 , & partition, W . par_iter ( ) . map ( |w| w[ c] ) ) )
211+ . collect ( ) ;
212+ vn_first_mono ( & mut partition, & w, 2 ) . unwrap ( ) ;
213+ println ! ( "partition: {partition:?}" ) ;
214+ let imbs_end: Vec < i32 > = ( 0 ..W [ 0 ] . len ( ) )
215+ . map ( |c| imbalance:: max_imbalance ( 2 , & partition, W . par_iter ( ) . map ( |w| w[ c] ) ) )
314216 . collect ( ) ;
315- vn_first ( & mut part, & W , 2 ) ;
316- let imbs_end =
317- ( 0 ..W [ 0 ] . len ( ) ) . map ( |c| imbalance:: max_imbalance ( 2 , & part, W . par_iter ( ) . map ( |w| w[ c] ) ) ) ;
217+ println ! ( "imbalances: {imbs_end:?} < {imbs_ini:?}" ) ;
318218 for ( imb_ini, imb_end) in imbs_ini. into_iter ( ) . zip ( imbs_end) {
219+ println ! ( "imbalance: {imb_end} < {imb_ini}" ) ;
319220 assert ! ( imb_end <= imb_ini) ;
320- println ! ( "imbalance : {} < {}" , imb_end, imb_ini) ;
321221 }
322222 }
323223
@@ -329,7 +229,7 @@ mod tests {
329229 ( weights, mut partition) in
330230 ( 2 ..200_usize ) . prop_flat_map( |num_weights| {
331231 let weights = prop:: collection:: vec(
332- ( 1 ..1000_i32 , 1 ..1000_i32 ) . prop_map( |( a, b) | [ a, b] ) ,
232+ ( 1 ..1000_i32 , 1 ..1000_i32 ) . prop_map( |( a, b) | nalgebra :: SVector :: < i32 , 2 > :: new ( a, b) ) ,
333233 num_weights
334234 ) ;
335235 let partition = prop:: collection:: vec( 0 ..1_usize , num_weights) ;
@@ -339,7 +239,7 @@ mod tests {
339239 let imbs_ini: Vec <i32 > = ( 0 ..C )
340240 . map( |c| imbalance:: max_imbalance( 2 , & partition, weights. par_iter( ) . map( |w| w[ c] ) ) )
341241 . collect( ) ;
342- vn_first ( & mut partition, & weights, 2 ) ;
242+ vn_first_mono ( & mut partition, & weights, 2 ) . unwrap ( ) ;
343243 let imbs_end: Vec <i32 > = ( 0 ..C )
344244 . map( |c| imbalance:: max_imbalance( 2 , & partition, weights. par_iter( ) . map( |w| w[ c] ) ) )
345245 . collect( ) ;
0 commit comments