conspire 0.7.2

The Rust interface to conspire.
Documentation
use super::CscMatrix;
use crate::math::assert::Assert;
use crate::math::{Vector, assert::AssertionError};

fn laplacian(k: usize) -> CscMatrix {
    let n = k * k;
    let mut pattern: Vec<(usize, usize)> = (0..n).map(|i| (i, i)).collect();
    (0..k).for_each(|a| {
        (0..k).for_each(|b| {
            let i = k * a + b;
            if b + 1 < k {
                pattern.push((i, i + 1));
                pattern.push((i + 1, i));
            }
            if a + 1 < k {
                pattern.push((i, i + k));
                pattern.push((i + k, i));
            }
        })
    });
    let mut matrix = CscMatrix::from_pattern(n, n, pattern);
    matrix.fill(|i, j| if i == j { 4.0 } else { -1.0 });
    matrix
}

fn asymmetric(n: usize) -> CscMatrix {
    let mut pattern: Vec<(usize, usize)> = (0..n).map(|i| (i, i)).collect();
    (0..n).for_each(|i| {
        pattern.push((i, (3 * i + 1) % n));
        pattern.push(((5 * i + 2) % n, i));
        pattern.push((i, (i + 7) % n));
    });
    let mut matrix = CscMatrix::from_pattern(n, n, pattern);
    matrix.fill(|i, j| if i == j { 8.0 } else { -1.0 });
    matrix
}

fn assert_permutation(permutation: &[usize], n: usize) {
    assert_eq!(permutation.len(), n);
    let mut sorted = permutation.to_vec();
    sorted.sort_unstable();
    assert!(sorted.into_iter().eq(0..n));
}

#[test]
fn permutation_asymmetric() {
    assert_permutation(&asymmetric(100).amd(), 100);
}

#[test]
fn permutation_diagonal() {
    let mut matrix = CscMatrix::from_pattern(5, 5, (0..5).map(|i| (i, i)).collect());
    matrix.fill(|_, _| 1.0);
    assert_permutation(&matrix.amd(), 5);
}

#[test]
fn permutation_laplacian() {
    assert_permutation(&laplacian(20).amd(), 400);
}

#[test]
fn reduces_fill() {
    let matrix = laplacian(20);
    let natural = matrix.lu().expect("Factorization failed.").nonzeros();
    let ordered = matrix.lu_amd().expect("Factorization failed.").nonzeros();
    assert!(2 * ordered < natural);
}

#[test]
fn solve_laplacian() -> Result<(), AssertionError> {
    let matrix = laplacian(20);
    let b: Vector = (0..400).map(|i| (i % 17) as f64 - 8.0).collect();
    let lu = matrix.lu_amd().map_err(|_| AssertionError {
        message: "Factorization failed.".to_string(),
    })?;
    Assert::default().eq_within_tols(&(&matrix * &lu.solve(&b)), &b)
}

#[test]
fn solve_asymmetric() -> Result<(), AssertionError> {
    let matrix = asymmetric(100);
    let b: Vector = (0..100).map(|i| (i % 13) as f64 - 6.0).collect();
    let lu = matrix.lu_amd().map_err(|_| AssertionError {
        message: "Factorization failed.".to_string(),
    })?;
    Assert::default().eq_within_tols(&(&matrix * &lu.solve(&b)), &b)
}