Skip to content

Commit

Permalink
Merge pull request #631 from Andlon/matrixcompare
Browse files Browse the repository at this point in the history
Basic matrixcompare functionality
  • Loading branch information
sebcrozet committed Jul 17, 2020
2 parents f9f7169 + d13b3de commit 2ab82be
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 2 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Expand Up @@ -30,6 +30,7 @@ sparse = [ ]
debug = [ "approx/num-complex", "rand/std" ]
alloc = [ ]
io = [ "pest", "pest_derive" ]
compare = [ "matrixcompare-core" ]

[dependencies]
typenum = "1.11"
Expand All @@ -50,6 +51,7 @@ mint = { version = "0.5", optional = true }
quickcheck = { version = "0.9", optional = true }
pest = { version = "2.0", optional = true }
pest_derive = { version = "2.0", optional = true }
matrixcompare-core = { version = "0.1", optional = true }

[dev-dependencies]
serde_json = "1.0"
Expand All @@ -61,6 +63,9 @@ rand_isaac = "0.2"
### https://github.com/rust-lang/cargo/issues/4866
#criterion = "0.2.10"

# For matrix comparison macro
matrixcompare = "0.1.3"

[workspace]
members = [ "nalgebra-lapack", "nalgebra-glm" ]

Expand Down
4 changes: 2 additions & 2 deletions Makefile
@@ -1,5 +1,5 @@
all:
cargo test --features "debug arbitrary serde-serialize abomonation-serialize"
cargo test --features "debug arbitrary serde-serialize abomonation-serialize compare"
# cargo check --features "debug arbitrary serde-serialize"

doc:
Expand All @@ -9,4 +9,4 @@ bench:
cargo bench

test:
cargo test --features "debug arbitrary serde-serialize abomonation-serialize"
cargo test --features "debug arbitrary serde-serialize abomonation-serialize compare"
82 changes: 82 additions & 0 deletions examples/matrixcompare.rs
@@ -0,0 +1,82 @@
extern crate nalgebra as na;

use matrixcompare::comparators::{AbsoluteElementwiseComparator, ExactElementwiseComparator};
use matrixcompare::compare_matrices;
use na::{MatrixMN, U3, U4};

fn compare_integers_fail() {
println!("Comparing two integer matrices.");

#[rustfmt::skip]
let a = MatrixMN::<_, U3, U4>::from_row_slice(&[
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, -2, 11
]);

#[rustfmt::skip]
let b = MatrixMN::<_, U3, U4>::from_row_slice(&[
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11
]);

if let Err(err) = compare_matrices(a, b, &ExactElementwiseComparator) {
println!("{}", err);
}
}

fn compare_different_size() {
println!("Comparing matrices of different size.");
#[rustfmt::skip]
let a = MatrixMN::<_, U3, U3>::from_row_slice(&[
0, 1, 2,
4, 5, 6,
8, 9, 10,
]);

#[rustfmt::skip]
let b = MatrixMN::<_, U3, U4>::from_row_slice(&[
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11
]);

if let Err(err) = compare_matrices(a, b, &ExactElementwiseComparator) {
println!("{}", err);
}
}

fn compare_f64_abs_tol_fail() {
println!("Comparing two f64 matrices.");

#[rustfmt::skip]
let a = MatrixMN::<f64, U3, U3>::from_row_slice(&[
0.0, 1.0, 2.0 + 1e-10,
4.0, 5.0, 6.0,
8.0, 9.0, 10.0,
]);

#[rustfmt::skip]
let b = MatrixMN::<_, U3, U3>::from_row_slice(&[
0.0, 1.0, 2.0,
4.0, 5.0, 6.0,
8.0, 9.0, 10.0
]);

let cmp = AbsoluteElementwiseComparator { tol: 1e-12 };
if let Err(err) = compare_matrices(a, b, &cmp) {
println!("{}", err);
}
}

fn main() {
// This example mostly serves the purpose of demonstrating the kind of error messages
// that are given upon comparison failure.
// The more typical use case is using `assert_matrix_eq!` in tests.
compare_integers_fail();
println!("======================================================");
compare_f64_abs_tol_fail();
println!("======================================================");
compare_different_size();
}
26 changes: 26 additions & 0 deletions src/base/matrix.rs
Expand Up @@ -159,6 +159,32 @@ impl<N: Scalar, R: Dim, C: Dim, S: Abomonation> Abomonation for Matrix<N, R, C,
}
}

#[cfg(feature = "compare")]
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> matrixcompare_core::Matrix<N>
for Matrix<N, R, C, S>
{
fn rows(&self) -> usize {
self.nrows()
}

fn cols(&self) -> usize {
self.ncols()
}

fn access(&self) -> matrixcompare_core::Access<N> {
matrixcompare_core::Access::Dense(self)
}
}

#[cfg(feature = "compare")]
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> matrixcompare_core::DenseAccess<N>
for Matrix<N, R, C, S>
{
fn fetch_single(&self, row: usize, col: usize) -> N {
self.index((row, col)).clone()
}
}

impl<N: Scalar, R: Dim, C: Dim, S> Matrix<N, R, C, S> {
/// Creates a new matrix with the given data without statically checking that the matrix
/// dimension matches the storage dimension.
Expand Down
85 changes: 85 additions & 0 deletions tests/core/matrixcompare.rs
@@ -0,0 +1,85 @@
//! Tests for `matrixcompare` integration.
//!
//! The `matrixcompare` crate itself is responsible for testing the actual comparison.
//! The tests here only check that the necessary trait implementations are correctly implemented,
//! in addition to some sanity checks with example input.

use nalgebra::{DMatrix, MatrixMN, U4, U5};

use matrixcompare::{assert_matrix_eq, DenseAccess};

#[cfg(feature = "arbitrary")]
quickcheck! {
fn fetch_single_is_equivalent_to_index_f64(matrix: DMatrix<f64>) -> bool {
for i in 0 .. matrix.nrows() {
for j in 0 .. matrix.ncols() {
if matrix.fetch_single(i, j) != *matrix.index((i, j)) {
return false;
}
}
}

true
}

fn matrixcompare_shape_agrees_with_matrix(matrix: DMatrix<f64>) -> bool {
matrix.nrows() == <DMatrix<f64> as matrixcompare::Matrix<f64>>::rows(&matrix)
&&
matrix.ncols() == <DMatrix<f64> as matrixcompare::Matrix<f64>>::cols(&matrix)
}
}

#[test]
fn assert_matrix_eq_dense_positive_comparison() {
#[rustfmt::skip]
let a = MatrixMN::<_, U4, U5>::from_row_slice(&[
1210, 1320, 1430, 1540, 1650,
2310, 2420, 2530, 2640, 2750,
3410, 3520, 3630, 3740, 3850,
4510, 4620, 4730, 4840, 4950,
]);

#[rustfmt::skip]
let b = MatrixMN::<_, U4, U5>::from_row_slice(&[
1210, 1320, 1430, 1540, 1650,
2310, 2420, 2530, 2640, 2750,
3410, 3520, 3630, 3740, 3850,
4510, 4620, 4730, 4840, 4950,
]);

// Test matrices of static size
assert_matrix_eq!(a, b);
assert_matrix_eq!(&a, b);
assert_matrix_eq!(a, &b);
assert_matrix_eq!(&a, &b);

// Test matrices of dynamic size
let a_dyn = a.index((0..4, 0..5));
let b_dyn = b.index((0..4, 0..5));
assert_matrix_eq!(a_dyn, b_dyn);
assert_matrix_eq!(a_dyn, &b_dyn);
assert_matrix_eq!(&a_dyn, b_dyn);
assert_matrix_eq!(&a_dyn, &b_dyn);
}

#[test]
#[should_panic]
fn assert_matrix_eq_dense_negative_comparison() {
#[rustfmt::skip]
let a = MatrixMN::<_, U4, U5>::from_row_slice(&[
1210, 1320, 1430, 1540, 1650,
2310, 2420, 2530, 2640, 2750,
3410, 3520, 3630, 3740, 3850,
4510, 4620, -4730, 4840, 4950,
]);

#[rustfmt::skip]
let b = MatrixMN::<_, U4, U5>::from_row_slice(&[
1210, 1320, 1430, 1540, 1650,
2310, 2420, 2530, 2640, 2750,
3410, 3520, 3630, 3740, 3850,
4510, 4620, 4730, 4840, 4950,
]);

assert_matrix_eq!(a, b);
}
3 changes: 3 additions & 0 deletions tests/core/mod.rs
Expand Up @@ -11,5 +11,8 @@ mod matrix_slice;
mod mint;
mod serde;

#[cfg(feature = "compare")]
mod matrixcompare;

#[cfg(feature = "arbitrary")]
pub mod helper;

0 comments on commit 2ab82be

Please sign in to comment.