105 lines
3.9 KiB
Rust
105 lines
3.9 KiB
Rust
|
#![cfg(feature = "ndarray")]
|
||
|
|
||
|
use ndarray::{s, Array2};
|
||
|
use rand::SeedableRng;
|
||
|
use rand_chacha::ChaCha20Rng;
|
||
|
use smawk::{brute_force, online_column_minima, recursive};
|
||
|
|
||
|
mod random_monge;
|
||
|
use random_monge::random_monge_matrix;
|
||
|
|
||
|
/// Check that the brute force, recursive, and SMAWK functions
|
||
|
/// give identical results on a large number of randomly generated
|
||
|
/// Monge matrices.
|
||
|
#[test]
|
||
|
fn column_minima_agree() {
|
||
|
let sizes = vec![1, 2, 3, 4, 5, 10, 15, 20, 30];
|
||
|
let mut rng = ChaCha20Rng::seed_from_u64(0);
|
||
|
for _ in 0..4 {
|
||
|
for m in sizes.clone().iter() {
|
||
|
for n in sizes.clone().iter() {
|
||
|
let matrix: Array2<i32> = random_monge_matrix(*m, *n, &mut rng);
|
||
|
|
||
|
// Compute and test row minima.
|
||
|
let brute_force = brute_force::row_minima(&matrix);
|
||
|
let recursive = recursive::row_minima(&matrix);
|
||
|
let smawk = smawk::row_minima(&matrix);
|
||
|
assert_eq!(
|
||
|
brute_force, recursive,
|
||
|
"recursive and brute force differs on:\n{:?}",
|
||
|
matrix
|
||
|
);
|
||
|
assert_eq!(
|
||
|
brute_force, smawk,
|
||
|
"SMAWK and brute force differs on:\n{:?}",
|
||
|
matrix
|
||
|
);
|
||
|
|
||
|
// Do the same for the column minima.
|
||
|
let brute_force = brute_force::column_minima(&matrix);
|
||
|
let recursive = recursive::column_minima(&matrix);
|
||
|
let smawk = smawk::column_minima(&matrix);
|
||
|
assert_eq!(
|
||
|
brute_force, recursive,
|
||
|
"recursive and brute force differs on:\n{:?}",
|
||
|
matrix
|
||
|
);
|
||
|
assert_eq!(
|
||
|
brute_force, smawk,
|
||
|
"SMAWK and brute force differs on:\n{:?}",
|
||
|
matrix
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Check that the brute force and online SMAWK functions give
|
||
|
/// identical results on a large number of randomly generated
|
||
|
/// Monge matrices.
|
||
|
#[test]
|
||
|
fn online_agree() {
|
||
|
let sizes = vec![1, 2, 3, 4, 5, 10, 15, 20, 30, 50];
|
||
|
let mut rng = ChaCha20Rng::seed_from_u64(0);
|
||
|
for _ in 0..5 {
|
||
|
for &size in &sizes {
|
||
|
// Random totally monotone square matrix of the
|
||
|
// desired size.
|
||
|
let mut matrix: Array2<i32> = random_monge_matrix(size, size, &mut rng);
|
||
|
|
||
|
// Adjust matrix so the column minima are above the
|
||
|
// diagonal. The brute_force::column_minima will still
|
||
|
// work just fine on such a mangled Monge matrix.
|
||
|
let max = *matrix.iter().max().unwrap_or(&0);
|
||
|
for idx in 0..(size as isize) {
|
||
|
// Using the maximum value of the matrix instead
|
||
|
// of i32::max_value() makes for prettier matrices
|
||
|
// in case we want to print them.
|
||
|
matrix.slice_mut(s![idx..idx + 1, ..idx + 1]).fill(max);
|
||
|
}
|
||
|
|
||
|
// The online algorithm always returns the initial
|
||
|
// value for the left-most column -- without
|
||
|
// inspecting the column at all. So we fill the
|
||
|
// left-most column with this value to have the brute
|
||
|
// force algorithm do the same.
|
||
|
let initial = 42;
|
||
|
matrix.slice_mut(s![0.., ..1]).fill(initial);
|
||
|
|
||
|
// Brute-force computation of column minima, returned
|
||
|
// in the same form as online_column_minima.
|
||
|
let brute_force = brute_force::column_minima(&matrix)
|
||
|
.iter()
|
||
|
.enumerate()
|
||
|
.map(|(j, &i)| (i, matrix[[i, j]]))
|
||
|
.collect::<Vec<_>>();
|
||
|
let online = online_column_minima(initial, size, |_, i, j| matrix[[i, j]]);
|
||
|
assert_eq!(
|
||
|
brute_force, online,
|
||
|
"brute force and online differ on:\n{:3?}",
|
||
|
matrix
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|