Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic matrixcompare functionality #631

Merged
merged 4 commits into from Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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()
Andlon marked this conversation as resolved.
Show resolved Hide resolved
}
}

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 @@ -10,5 +10,8 @@ mod matrix_slice;
mod mint;
mod serde;

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

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