Move nalgebra proptest slow tests into `slow` submodule
This way it's easier to keep track of what imports are only necessary for the slow tests.
This commit is contained in:
parent
f909638bf4
commit
402de4d045
|
@ -6,13 +6,6 @@ use proptest::prelude::*;
|
||||||
use proptest::strategy::ValueTree;
|
use proptest::strategy::ValueTree;
|
||||||
use proptest::test_runner::TestRunner;
|
use proptest::test_runner::TestRunner;
|
||||||
|
|
||||||
#[cfg(feature = "slow-tests")]
|
|
||||||
use {
|
|
||||||
itertools::Itertools,
|
|
||||||
std::iter::repeat,
|
|
||||||
std::collections::HashSet,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Generate a proptest that tests that all matrices generated with the
|
/// Generate a proptest that tests that all matrices generated with the
|
||||||
/// provided rows and columns conform to the constraints defined by the
|
/// provided rows and columns conform to the constraints defined by the
|
||||||
/// input.
|
/// input.
|
||||||
|
@ -96,62 +89,6 @@ proptest! {
|
||||||
fn ensure_arbitrary_test_compiles_dvector(_: DVector<i32>) {}
|
fn ensure_arbitrary_test_compiles_dvector(_: DVector<i32>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "slow-tests")]
|
|
||||||
#[test]
|
|
||||||
fn matrix_samples_all_possible_outputs() {
|
|
||||||
// Test that the proptest generation covers all possible outputs for a small space of inputs
|
|
||||||
// given enough samples.
|
|
||||||
|
|
||||||
// We use a deterministic test runner to make the test "stable".
|
|
||||||
let mut runner = TestRunner::deterministic();
|
|
||||||
|
|
||||||
// This number needs to be high enough so that we with high probability sample
|
|
||||||
// all possible cases
|
|
||||||
let num_generated_matrices = 200000;
|
|
||||||
|
|
||||||
let values = -1..=1;
|
|
||||||
let rows = 0..=2;
|
|
||||||
let cols = 0..=3;
|
|
||||||
let strategy = matrix(values.clone(), rows.clone(), cols.clone());
|
|
||||||
|
|
||||||
// Enumerate all possible combinations
|
|
||||||
let mut all_combinations = HashSet::new();
|
|
||||||
for nrows in rows {
|
|
||||||
for ncols in cols.clone() {
|
|
||||||
// For the given number of rows and columns
|
|
||||||
let n_values = nrows * ncols;
|
|
||||||
|
|
||||||
if n_values == 0 {
|
|
||||||
// If we have zero rows or columns, the set of matrices with the given
|
|
||||||
// rows and columns is a single element: an empty matrix
|
|
||||||
all_combinations.insert(DMatrix::from_row_slice(nrows, ncols, &[]));
|
|
||||||
} else {
|
|
||||||
// Otherwise, we need to sample all possible matrices.
|
|
||||||
// To do this, we generate the values as the (multi) Cartesian product
|
|
||||||
// of the value sets. For example, for a 2x2 matrices, we consider
|
|
||||||
// all possible 4-element arrays that the matrices can take by
|
|
||||||
// considering all elements in the cartesian product
|
|
||||||
// V x V x V x V
|
|
||||||
// where V is the set of eligible values, e.g. V := -1 ..= 1
|
|
||||||
for matrix_values in repeat(values.clone()).take(n_values).multi_cartesian_product() {
|
|
||||||
all_combinations.insert(DMatrix::from_row_slice(nrows, ncols, &matrix_values));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut visited_combinations = HashSet::new();
|
|
||||||
for _ in 0..num_generated_matrices {
|
|
||||||
let tree = strategy
|
|
||||||
.new_tree(&mut runner)
|
|
||||||
.expect("Tree generation should not fail");
|
|
||||||
let matrix = tree.current();
|
|
||||||
visited_combinations.insert(matrix.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(visited_combinations, all_combinations, "Did not sample all possible values.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn matrix_shrinking_satisfies_constraints() {
|
fn matrix_shrinking_satisfies_constraints() {
|
||||||
// We use a deterministic test runner to make the test "stable".
|
// We use a deterministic test runner to make the test "stable".
|
||||||
|
@ -206,3 +143,77 @@ fn matrix_shrinking_satisfies_constraints() {
|
||||||
|
|
||||||
maybeprintln!("========================== (end of generation process)");
|
maybeprintln!("========================== (end of generation process)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "slow-tests")]
|
||||||
|
mod slow {
|
||||||
|
use super::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::iter::repeat;
|
||||||
|
|
||||||
|
#[cfg(feature = "slow-tests")]
|
||||||
|
#[test]
|
||||||
|
fn matrix_samples_all_possible_outputs() {
|
||||||
|
// Test that the proptest generation covers all possible outputs for a small space of inputs
|
||||||
|
// given enough samples.
|
||||||
|
|
||||||
|
// We use a deterministic test runner to make the test "stable".
|
||||||
|
let mut runner = TestRunner::deterministic();
|
||||||
|
|
||||||
|
// This number needs to be high enough so that we with high probability sample
|
||||||
|
// all possible cases
|
||||||
|
let num_generated_matrices = 200000;
|
||||||
|
|
||||||
|
let values = -1..=1;
|
||||||
|
let rows = 0..=2;
|
||||||
|
let cols = 0..=3;
|
||||||
|
let strategy = matrix(values.clone(), rows.clone(), cols.clone());
|
||||||
|
|
||||||
|
// Enumerate all possible combinations
|
||||||
|
let mut all_combinations = HashSet::new();
|
||||||
|
for nrows in rows {
|
||||||
|
for ncols in cols.clone() {
|
||||||
|
// For the given number of rows and columns
|
||||||
|
let n_values = nrows * ncols;
|
||||||
|
|
||||||
|
if n_values == 0 {
|
||||||
|
// If we have zero rows or columns, the set of matrices with the given
|
||||||
|
// rows and columns is a single element: an empty matrix
|
||||||
|
all_combinations.insert(DMatrix::from_row_slice(nrows, ncols, &[]));
|
||||||
|
} else {
|
||||||
|
// Otherwise, we need to sample all possible matrices.
|
||||||
|
// To do this, we generate the values as the (multi) Cartesian product
|
||||||
|
// of the value sets. For example, for a 2x2 matrices, we consider
|
||||||
|
// all possible 4-element arrays that the matrices can take by
|
||||||
|
// considering all elements in the cartesian product
|
||||||
|
// V x V x V x V
|
||||||
|
// where V is the set of eligible values, e.g. V := -1 ..= 1
|
||||||
|
for matrix_values in repeat(values.clone())
|
||||||
|
.take(n_values)
|
||||||
|
.multi_cartesian_product()
|
||||||
|
{
|
||||||
|
all_combinations.insert(DMatrix::from_row_slice(
|
||||||
|
nrows,
|
||||||
|
ncols,
|
||||||
|
&matrix_values,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut visited_combinations = HashSet::new();
|
||||||
|
for _ in 0..num_generated_matrices {
|
||||||
|
let tree = strategy
|
||||||
|
.new_tree(&mut runner)
|
||||||
|
.expect("Tree generation should not fail");
|
||||||
|
let matrix = tree.current();
|
||||||
|
visited_combinations.insert(matrix.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
visited_combinations, all_combinations,
|
||||||
|
"Did not sample all possible values."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue