@@ -51,8 +51,10 @@ pub fn lapjv<T>(costs: &Matrix<T>) -> Result<(Vec<usize>, Vec<usize>), LapJVErro
51
51
LapJV :: new ( costs) . solve ( )
52
52
}
53
53
54
- pub fn cost < T > ( input : & Matrix < T > , x : & [ usize ] ) -> T where T : LapJVCost {
55
- ( 0 ..x. len ( ) ) . into_iter ( ) . fold ( T :: zero ( ) , |acc, i| acc + input[ ( i, x[ i] ) ] )
54
+
55
+ /// Calculate solution cost by a result row
56
+ pub fn cost < T > ( input : & Matrix < T > , row : & [ usize ] ) -> T where T : LapJVCost {
57
+ ( 0 ..row. len ( ) ) . into_iter ( ) . fold ( T :: zero ( ) , |acc, i| acc + input[ ( i, row[ i] ) ] )
56
58
}
57
59
58
60
/// Solve LAP problem given cost matrix
@@ -82,20 +84,24 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
82
84
return Err ( LapJVError ( "Input error: matrix is not square" ) )
83
85
}
84
86
self . ccrrt_dense ( ) ;
87
+ debug ! ( "after ccrrt_dense: {:?}" , self ) ;
85
88
86
89
let mut i = 0 ;
87
90
while !self . free_rows . is_empty ( ) && i < 2 {
88
91
self . carr_dense ( ) ;
89
92
i+= 1 ;
90
93
}
94
+ debug ! ( "after carr_dense: {:?}" , self ) ;
91
95
92
96
if !self . free_rows . is_empty ( ) {
93
97
self . ca_dense ( ) ?;
94
98
}
99
+ debug ! ( "on result: {:?}" , self ) ;
95
100
96
101
Ok ( ( self . in_row , self . in_col ) )
97
102
}
98
103
104
+ // Column-reduction and reduction transfer for a dense cost matrix
99
105
fn ccrrt_dense ( & mut self ) {
100
106
let mut unique = vec ! [ true ; self . dim] ;
101
107
let mut in_row_not_set = vec ! [ true ; self . dim] ;
@@ -108,13 +114,6 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
108
114
self . v . push ( min_value) ;
109
115
}
110
116
111
- // for ((i, j), &c) in self.costs.indexed_iter() {
112
- // if c < self.v[j] {
113
- // self.v[j] = c;
114
- // self.in_col[j] = i;
115
- // }
116
- // }
117
-
118
117
for j in ( 0 ..self . dim ) . into_iter ( ) . rev ( ) {
119
118
let i = self . in_col [ j] ;
120
119
if in_row_not_set[ i] {
@@ -146,11 +145,12 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
146
145
}
147
146
}
148
147
149
- // Augmenting row reduction for a dense cost matrix.
148
+ // Augmenting row reduction for a dense cost matrix
150
149
fn carr_dense ( & mut self ) {
151
150
// AUGMENTING ROW REDUCTION
152
151
// scan all free rows.
153
152
// in some cases, a free row may be replaced with another one to be scanned next.
153
+ trace ! ( "carr_dense" ) ;
154
154
let dim = self . dim ;
155
155
let mut current = 0 ;
156
156
let mut new_free_rows = 0 ; // start list of rows still free after augmenting row reduction.
@@ -192,11 +192,9 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
192
192
new_free_rows += 1 ;
193
193
}
194
194
}
195
- } else {
196
- if i0 != std:: usize:: MAX {
197
- self . free_rows [ new_free_rows] = i0;
198
- new_free_rows += 1 ;
199
- }
195
+ } else if i0 != std:: usize:: MAX {
196
+ self . free_rows [ new_free_rows] = i0;
197
+ new_free_rows += 1 ;
200
198
}
201
199
self . in_row [ free_i] = j1;
202
200
self . in_col [ j1] = free_i;
@@ -205,35 +203,34 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
205
203
}
206
204
207
205
208
- // Augment for a dense cost matrix.
206
+ // Augment for a dense cost matrix
209
207
fn ca_dense ( & mut self ) -> Result < ( ) , LapJVError > {
210
208
let dim = self . dim ;
211
209
let mut pred = vec ! [ 0 ; dim] ;
212
210
213
211
let free_rows = std:: mem:: replace ( & mut self . free_rows , vec ! [ ] ) ;
214
212
for freerow in free_rows {
215
- trace ! ( "looking at free_i ={}" , freerow) ;
213
+ trace ! ( "looking at freerow ={}" , freerow) ;
216
214
217
215
let mut i = std:: usize:: MAX ;
218
216
let mut k = 0 ;
219
217
let mut j = self . find_path_dense ( freerow, & mut pred) ;
220
- assert ! ( j < dim) ;
218
+ debug_assert ! ( j < dim) ;
221
219
while i != freerow {
222
220
i = pred[ j] ;
223
221
self . in_col [ j] = i;
224
-
225
222
std:: mem:: swap ( & mut j, & mut self . in_row [ i] ) ;
226
223
k += 1 ;
227
- if k >= dim {
224
+ if k > dim {
228
225
return Err ( LapJVError ( "Error: ca_dense will not finish" ) )
229
226
}
230
227
}
231
228
}
232
229
Ok ( ( ) )
233
230
}
234
231
235
- /// Single iteration of modified Dijkstra shortest path algorithm as explained in the JV paper.
236
- /// return The closest free column index.
232
+ /// Single iteration of modified Dijkstra shortest path algorithm as explained in the JV paper
233
+ /// return The closest free column index
237
234
fn find_path_dense ( & mut self , start_i : usize , pred : & mut [ usize ] ) -> usize {
238
235
let dim = self . dim ;
239
236
let mut collist = Vec :: with_capacity ( dim) ; // list of columns to be scanned in various ways.
@@ -270,22 +267,21 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
270
267
271
268
if final_j. is_none ( ) {
272
269
trace ! ( "{}..{} -> scan" , lo, hi) ;
273
- let maybe_final_j = self . scan_dense ( & mut lo, & mut hi, & mut d, & mut collist, pred) ;
274
- if let Some ( val) = maybe_final_j {
275
- final_j = Some ( val) ;
276
- }
270
+ final_j = self . scan_dense ( & mut lo, & mut hi, & mut d, & mut collist, pred) ;
277
271
}
278
272
}
279
273
280
274
trace ! ( "found final_j={:?}" , final_j) ;
275
+ trace ! ( "cols={:?}" , collist) ;
281
276
let mind = d[ collist[ lo] ] ;
282
277
for & j in collist. iter ( ) . take ( n_ready) {
283
278
self . v [ j] += d[ j] - mind;
284
279
}
285
280
final_j. unwrap ( )
286
281
}
282
+
287
283
// Scan all columns in TODO starting from arbitrary column in SCAN
288
- // and try to decrease d of the TODO columns using the SCAN column.
284
+ // and try to decrease d of the TODO columns using the SCAN column
289
285
fn scan_dense ( & self , plo : & mut usize , phi : & mut usize , d : & mut [ T ] , collist : & mut [ usize ] , pred : & mut [ usize ] ) -> Option < usize > {
290
286
let mut lo = * plo;
291
287
let mut hi = * phi;
@@ -302,8 +298,7 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
302
298
if cred_ij < d[ j] {
303
299
d[ j] = cred_ij;
304
300
pred[ j] = i;
305
- if ( cred_ij - mind) . abs ( ) < T :: epsilon ( ) {
306
- // if cred_ij == mind {
301
+ if ( cred_ij - mind) . abs ( ) < T :: epsilon ( ) { // if cred_ij == mind {
307
302
if self . in_col [ j] == std:: usize:: MAX {
308
303
return Some ( j) ;
309
304
}
@@ -459,6 +454,17 @@ mod tests {
459
454
( m, result)
460
455
}
461
456
457
+ #[ test]
458
+ fn dim_size_augmentation_path ( ) {
459
+ let m = vec ! [ 849.096136535884 , 964.7344199800348 , 1658.3745235461179 , 1324.4750426251608 ,
460
+ 1565.0473271789378 , 1777.6465563492143 , 4280.139067225529 , 3411.9521087119633 ,
461
+ 1360.3260879628992 , 1546.701932942709 , 1304.724155636392 , 1048.3839719313205 ,
462
+ 1559.5777872153571 , 1769.1684309771547 , 3663.2542984837355 , 2926.089718214265 ] ;
463
+ let matrix = Matrix :: from_shape_vec ( ( 4 , 4 ) , m) . unwrap ( ) ;
464
+ let result = lapjv ( & matrix) ;
465
+ result. unwrap ( ) ;
466
+ }
467
+
462
468
#[ cfg( feature = "nightly" ) ]
463
469
mod benches {
464
470
use test:: Bencher ;
0 commit comments