Initial vendor packages

Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
2024-01-08 01:21:28 +04:00
parent 5ecd8cf2cb
commit 1b6a04ca55
7309 changed files with 2160054 additions and 0 deletions

104
vendor/smawk/tests/agreement.rs vendored Normal file
View File

@ -0,0 +1,104 @@
#![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
);
}
}
}

83
vendor/smawk/tests/complexity.rs vendored Normal file
View File

@ -0,0 +1,83 @@
#![cfg(feature = "ndarray")]
use ndarray::{Array1, Array2};
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
use smawk::online_column_minima;
mod random_monge;
use random_monge::random_monge_matrix;
#[derive(Debug)]
struct LinRegression {
alpha: f64,
beta: f64,
r_squared: f64,
}
/// Square an expression. Works equally well for floats and matrices.
macro_rules! squared {
($x:expr) => {
$x * $x
};
}
/// Compute the mean of a 1-dimensional array.
macro_rules! mean {
($a:expr) => {
$a.mean().expect("Mean of empty array")
};
}
/// Compute a simple linear regression from the list of values.
///
/// See <https://en.wikipedia.org/wiki/Simple_linear_regression>.
fn linear_regression(values: &[(usize, i32)]) -> LinRegression {
let xs = values.iter().map(|&(x, _)| x as f64).collect::<Array1<_>>();
let ys = values.iter().map(|&(_, y)| y as f64).collect::<Array1<_>>();
let xs_mean = mean!(&xs);
let ys_mean = mean!(&ys);
let xs_ys_mean = mean!(&xs * &ys);
let cov_xs_ys = ((&xs - xs_mean) * (&ys - ys_mean)).sum();
let var_xs = squared!(&xs - xs_mean).sum();
let beta = cov_xs_ys / var_xs;
let alpha = ys_mean - beta * xs_mean;
let r_squared = squared!(xs_ys_mean - xs_mean * ys_mean)
/ ((mean!(&xs * &xs) - squared!(xs_mean)) * (mean!(&ys * &ys) - squared!(ys_mean)));
LinRegression {
alpha: alpha,
beta: beta,
r_squared: r_squared,
}
}
/// Check that the number of matrix accesses in `online_column_minima`
/// grows as O(*n*) for *n* ✕ *n* matrix.
#[test]
fn online_linear_complexity() {
let mut rng = ChaCha20Rng::seed_from_u64(0);
let mut data = vec![];
for &size in &[1, 2, 3, 4, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100] {
let matrix: Array2<i32> = random_monge_matrix(size, size, &mut rng);
let count = std::cell::RefCell::new(0);
online_column_minima(0, size, |_, i, j| {
*count.borrow_mut() += 1;
matrix[[i, j]]
});
data.push((size, count.into_inner()));
}
let lin_reg = linear_regression(&data);
assert!(
lin_reg.r_squared > 0.95,
"r² = {:.4} is lower than expected for a linear fit\nData points: {:?}\n{:?}",
lin_reg.r_squared,
data,
lin_reg
);
}

83
vendor/smawk/tests/monge.rs vendored Normal file
View File

@ -0,0 +1,83 @@
#![cfg(feature = "ndarray")]
use ndarray::{arr2, Array, Array2};
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
use smawk::monge::is_monge;
mod random_monge;
use random_monge::{random_monge_matrix, MongePrim};
#[test]
fn random_monge() {
let mut rng = ChaCha20Rng::seed_from_u64(0);
let matrix: Array2<u8> = random_monge_matrix(5, 5, &mut rng);
assert!(is_monge(&matrix));
assert_eq!(
matrix,
arr2(&[
[2, 3, 4, 4, 5],
[5, 5, 6, 6, 7],
[3, 3, 4, 4, 5],
[5, 2, 3, 3, 4],
[5, 2, 3, 3, 4]
])
);
}
#[test]
fn monge_constant_rows() {
let mut rng = ChaCha20Rng::seed_from_u64(0);
let matrix: Array2<u8> = MongePrim::ConstantRows.to_matrix(5, 4, &mut rng);
assert!(is_monge(&matrix));
for row in matrix.rows() {
let elem = row[0];
assert_eq!(row, Array::from_elem(matrix.ncols(), elem));
}
}
#[test]
fn monge_constant_cols() {
let mut rng = ChaCha20Rng::seed_from_u64(0);
let matrix: Array2<u8> = MongePrim::ConstantCols.to_matrix(5, 4, &mut rng);
assert!(is_monge(&matrix));
for column in matrix.columns() {
let elem = column[0];
assert_eq!(column, Array::from_elem(matrix.nrows(), elem));
}
}
#[test]
fn monge_upper_right_ones() {
let mut rng = ChaCha20Rng::seed_from_u64(1);
let matrix: Array2<u8> = MongePrim::UpperRightOnes.to_matrix(5, 4, &mut rng);
assert!(is_monge(&matrix));
assert_eq!(
matrix,
arr2(&[
[0, 0, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1],
[0, 0, 0, 0],
[0, 0, 0, 0]
])
);
}
#[test]
fn monge_lower_left_ones() {
let mut rng = ChaCha20Rng::seed_from_u64(1);
let matrix: Array2<u8> = MongePrim::LowerLeftOnes.to_matrix(5, 4, &mut rng);
assert!(is_monge(&matrix));
assert_eq!(
matrix,
arr2(&[
[0, 0, 0, 0],
[0, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 0, 0],
[1, 1, 0, 0]
])
);
}

83
vendor/smawk/tests/random_monge/mod.rs vendored Normal file
View File

@ -0,0 +1,83 @@
//! Test functionality for generating random Monge matrices.
// The code is put here so we can reuse it in different integration
// tests, without Cargo finding it when `cargo test` is run. See the
// section on "Submodules in Integration Tests" in
// https://doc.rust-lang.org/book/ch11-03-test-organization.html
use ndarray::{s, Array2};
use num_traits::PrimInt;
use rand::distributions::{Distribution, Standard};
use rand::Rng;
/// A Monge matrix can be decomposed into one of these primitive
/// building blocks.
#[derive(Copy, Clone)]
pub enum MongePrim {
ConstantRows,
ConstantCols,
UpperRightOnes,
LowerLeftOnes,
}
impl MongePrim {
/// Generate a Monge matrix from a primitive.
pub fn to_matrix<T: PrimInt, R: Rng>(&self, m: usize, n: usize, rng: &mut R) -> Array2<T>
where
Standard: Distribution<T>,
{
let mut matrix = Array2::from_elem((m, n), T::zero());
// Avoid panic in UpperRightOnes and LowerLeftOnes below.
if m == 0 || n == 0 {
return matrix;
}
match *self {
MongePrim::ConstantRows => {
for mut row in matrix.rows_mut() {
if rng.gen::<bool>() {
row.fill(T::one())
}
}
}
MongePrim::ConstantCols => {
for mut col in matrix.columns_mut() {
if rng.gen::<bool>() {
col.fill(T::one())
}
}
}
MongePrim::UpperRightOnes => {
let i = rng.gen_range(0..(m + 1) as isize);
let j = rng.gen_range(0..(n + 1) as isize);
matrix.slice_mut(s![..i, -j..]).fill(T::one());
}
MongePrim::LowerLeftOnes => {
let i = rng.gen_range(0..(m + 1) as isize);
let j = rng.gen_range(0..(n + 1) as isize);
matrix.slice_mut(s![-i.., ..j]).fill(T::one());
}
}
matrix
}
}
/// Generate a random Monge matrix.
pub fn random_monge_matrix<R: Rng, T: PrimInt>(m: usize, n: usize, rng: &mut R) -> Array2<T>
where
Standard: Distribution<T>,
{
let monge_primitives = [
MongePrim::ConstantRows,
MongePrim::ConstantCols,
MongePrim::LowerLeftOnes,
MongePrim::UpperRightOnes,
];
let mut matrix = Array2::from_elem((m, n), T::zero());
for _ in 0..(m + n) {
let monge = monge_primitives[rng.gen_range(0..monge_primitives.len())];
matrix = matrix + monge.to_matrix(m, n, rng);
}
matrix
}

9
vendor/smawk/tests/version-numbers.rs vendored Normal file
View File

@ -0,0 +1,9 @@
#[test]
fn test_readme_deps() {
version_sync::assert_markdown_deps_updated!("README.md");
}
#[test]
fn test_html_root_url() {
version_sync::assert_html_root_url_updated!("src/lib.rs");
}