conspire 0.7.2

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

const D: usize = 9;

fn dense() -> [[Scalar; D]; D] {
    [
        [2.0, 2.0, 4.0, 0.0, 0.0, 1.0, 0.0, 3.0, 3.0],
        [0.0, 3.0, 1.0, 0.0, 0.0, 1.0, 4.0, 0.0, 1.0],
        [3.0, 0.0, 1.0, 2.0, 0.0, 3.0, 4.0, 4.0, 0.0],
        [4.0, 4.0, 0.0, 2.0, 1.0, 1.0, 0.0, 0.0, 4.0],
        [0.0, 1.0, 0.0, 1.0, 1.0, 3.0, 0.0, 1.0, 1.0],
        [4.0, 2.0, 3.0, 0.0, 2.0, 4.0, 3.0, 0.0, 4.0],
        [1.0, 3.0, 2.0, 0.0, 0.0, 0.0, 2.0, 4.0, 2.0],
        [0.0, 2.0, 2.0, 4.0, 1.0, 0.0, 4.0, 2.0, 2.0],
        [1.0, 2.0, 3.0, 4.0, 0.0, 1.0, 4.0, 0.0, 1.0],
    ]
}

fn vector() -> Vector {
    Vector::from([2.0, 1.0, 3.0, 2.0, 1.0, 3.0, 2.0, 1.0, 3.0])
}

fn pattern() -> Vec<(usize, usize)> {
    let matrix = dense();
    let mut pattern: Vec<(usize, usize)> = (0..D)
        .flat_map(|i| (0..D).filter(move |&j| i != j).map(move |j| (i, j)))
        .filter(|&(i, j)| matrix[i][j] != 0.0)
        .collect();
    pattern.reverse();
    (0..D).for_each(|i| pattern.push((i, i)));
    pattern
}

fn sparse() -> CscMatrix {
    let matrix = dense();
    let mut sparse = CscMatrix::from_pattern(D, D, pattern());
    sparse.fill(|i, j| matrix[i][j]);
    sparse
}

fn assert_eq_dense(sparse: &CscMatrix, dense: &[[Scalar; D]; D]) {
    assert_eq!(sparse.height(), D);
    assert_eq!(sparse.width(), D);
    let mut entries = sparse.iter();
    (0..D).for_each(|j| {
        (0..D).for_each(|i| {
            if dense[i][j] != 0.0 {
                assert_eq!(entries.next(), Some((i, j, &dense[i][j])));
            }
        })
    });
    assert!(entries.next().is_none());
}

#[test]
fn from_pattern_and_fill() {
    assert_eq_dense(&sparse(), &dense())
}

#[test]
fn fill_sums_duplicates() {
    let matrix = dense();
    let mut pattern = pattern();
    pattern.push((3, 0));
    pattern.push((3, 0));
    let mut sparse = CscMatrix::from_pattern(D, D, pattern);
    sparse.fill(|i, j| matrix[i][j] / if (i, j) == (3, 0) { 3.0 } else { 1.0 });
    assert_eq_dense(&sparse, &matrix)
}

#[test]
fn multiply_vector() -> Result<(), AssertionError> {
    let vector = vector();
    let product: Vector = dense()
        .iter()
        .map(|dense_i| {
            dense_i
                .iter()
                .zip(vector.iter())
                .map(|(dense_ij, vector_j)| dense_ij * vector_j)
                .sum()
        })
        .collect();
    Assert::eq(&(&sparse() * &vector), &product)
}

#[test]
fn nonzeros() {
    assert_eq!(sparse().nonzeros(), pattern().len());
}

#[test]
fn refill() {
    let matrix = dense();
    let mut doubled = matrix;
    doubled
        .iter_mut()
        .for_each(|row| row.iter_mut().for_each(|entry| *entry *= 2.0));
    let mut sparse = sparse();
    sparse.fill(|i, j| 2.0 * matrix[i][j]);
    assert_eq_dense(&sparse, &doubled)
}

#[test]
fn transpose() {
    let matrix = dense();
    let mut transposed = matrix;
    (0..D).for_each(|i| (0..D).for_each(|j| transposed[i][j] = matrix[j][i]));
    let sparse = sparse();
    let transpose = sparse.transpose();
    assert_eq_dense(&transpose, &transposed);
    assert_eq!(transpose.transpose(), sparse);
}