Skip to content

Commit 2231168

Browse files
authored
Merge pull request #1 from Antti/fix-augmentation-check
Fix augmentation check
2 parents a098110 + 04e863f commit 2231168

File tree

1 file changed

+35
-29
lines changed

1 file changed

+35
-29
lines changed

src/lib.rs

+35-29
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ pub fn lapjv<T>(costs: &Matrix<T>) -> Result<(Vec<usize>, Vec<usize>), LapJVErro
5151
LapJV::new(costs).solve()
5252
}
5353

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])])
5658
}
5759

5860
/// Solve LAP problem given cost matrix
@@ -82,20 +84,24 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
8284
return Err(LapJVError("Input error: matrix is not square"))
8385
}
8486
self.ccrrt_dense();
87+
debug!("after ccrrt_dense: {:?}", self);
8588

8689
let mut i = 0;
8790
while !self.free_rows.is_empty() && i < 2 {
8891
self.carr_dense();
8992
i+= 1;
9093
}
94+
debug!("after carr_dense: {:?}", self);
9195

9296
if !self.free_rows.is_empty() {
9397
self.ca_dense()?;
9498
}
99+
debug!("on result: {:?}", self);
95100

96101
Ok((self.in_row, self.in_col))
97102
}
98103

104+
// Column-reduction and reduction transfer for a dense cost matrix
99105
fn ccrrt_dense(&mut self) {
100106
let mut unique = vec![true; self.dim];
101107
let mut in_row_not_set = vec![true; self.dim];
@@ -108,13 +114,6 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
108114
self.v.push(min_value);
109115
}
110116

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-
118117
for j in (0..self.dim).into_iter().rev() {
119118
let i = self.in_col[j];
120119
if in_row_not_set[i] {
@@ -146,11 +145,12 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
146145
}
147146
}
148147

149-
// Augmenting row reduction for a dense cost matrix.
148+
// Augmenting row reduction for a dense cost matrix
150149
fn carr_dense(&mut self) {
151150
// AUGMENTING ROW REDUCTION
152151
// scan all free rows.
153152
// in some cases, a free row may be replaced with another one to be scanned next.
153+
trace!("carr_dense");
154154
let dim = self.dim;
155155
let mut current = 0;
156156
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 {
192192
new_free_rows += 1;
193193
}
194194
}
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;
200198
}
201199
self.in_row[free_i] = j1;
202200
self.in_col[j1] = free_i;
@@ -205,35 +203,34 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
205203
}
206204

207205

208-
// Augment for a dense cost matrix.
206+
// Augment for a dense cost matrix
209207
fn ca_dense(&mut self) -> Result<(), LapJVError> {
210208
let dim = self.dim;
211209
let mut pred = vec![0; dim];
212210

213211
let free_rows = std::mem::replace(&mut self.free_rows, vec![]);
214212
for freerow in free_rows {
215-
trace!("looking at free_i={}", freerow);
213+
trace!("looking at freerow={}", freerow);
216214

217215
let mut i = std::usize::MAX;
218216
let mut k = 0;
219217
let mut j = self.find_path_dense(freerow, &mut pred);
220-
assert!(j < dim);
218+
debug_assert!(j < dim);
221219
while i != freerow {
222220
i = pred[j];
223221
self.in_col[j] = i;
224-
225222
std::mem::swap(&mut j, &mut self.in_row[i]);
226223
k += 1;
227-
if k >= dim {
224+
if k > dim {
228225
return Err(LapJVError("Error: ca_dense will not finish"))
229226
}
230227
}
231228
}
232229
Ok(())
233230
}
234231

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
237234
fn find_path_dense(&mut self, start_i: usize, pred: &mut [usize]) -> usize {
238235
let dim = self.dim;
239236
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 {
270267

271268
if final_j.is_none() {
272269
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);
277271
}
278272
}
279273

280274
trace!("found final_j={:?}", final_j);
275+
trace!("cols={:?}", collist);
281276
let mind = d[collist[lo]];
282277
for &j in collist.iter().take(n_ready) {
283278
self.v[j] += d[j] - mind;
284279
}
285280
final_j.unwrap()
286281
}
282+
287283
// 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
289285
fn scan_dense(&self, plo: &mut usize, phi: &mut usize, d: &mut [T], collist: &mut [usize], pred: &mut [usize]) -> Option<usize> {
290286
let mut lo = *plo;
291287
let mut hi = *phi;
@@ -302,8 +298,7 @@ impl <'a, T>LapJV<'a, T> where T: LapJVCost {
302298
if cred_ij < d[j] {
303299
d[j] = cred_ij;
304300
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 {
307302
if self.in_col[j] == std::usize::MAX {
308303
return Some(j);
309304
}
@@ -459,6 +454,17 @@ mod tests {
459454
(m, result)
460455
}
461456

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+
462468
#[cfg(feature = "nightly")]
463469
mod benches {
464470
use test::Bencher;

0 commit comments

Comments
 (0)