Merge pull request #1039 from Andlon/remove-proptest-patch
Remove redundant proptest patch in `nalgebra-sparse`
This commit is contained in:
commit
56a4835b71
|
@ -5,11 +5,6 @@
|
||||||
//! The strategies provided here are generally expected to be able to generate the entire range
|
//! The strategies provided here are generally expected to be able to generate the entire range
|
||||||
//! of possible outputs given the constraints on dimensions and values. However, there are no
|
//! of possible outputs given the constraints on dimensions and values. However, there are no
|
||||||
//! particular guarantees on the distribution of possible values.
|
//! particular guarantees on the distribution of possible values.
|
||||||
|
|
||||||
// Contains some patched code from proptest that we can remove in the (hopefully near) future.
|
|
||||||
// See docs in file for more details.
|
|
||||||
mod proptest_patched;
|
|
||||||
|
|
||||||
use crate::coo::CooMatrix;
|
use crate::coo::CooMatrix;
|
||||||
use crate::csc::CscMatrix;
|
use crate::csc::CscMatrix;
|
||||||
use crate::csr::CsrMatrix;
|
use crate::csr::CsrMatrix;
|
||||||
|
@ -31,16 +26,10 @@ fn dense_row_major_coord_strategy(
|
||||||
let mut booleans = vec![true; nnz];
|
let mut booleans = vec![true; nnz];
|
||||||
booleans.append(&mut vec![false; (nrows * ncols) - nnz]);
|
booleans.append(&mut vec![false; (nrows * ncols) - nnz]);
|
||||||
// Make sure that exactly `nnz` of the booleans are true
|
// Make sure that exactly `nnz` of the booleans are true
|
||||||
|
Just(booleans)
|
||||||
// TODO: We cannot use the below code because of a bug in proptest, see
|
// Need to shuffle to make sure they are randomly distributed
|
||||||
// https://github.com/AltSysrq/proptest/pull/217
|
.prop_shuffle()
|
||||||
// so for now we're using a patched version of the Shuffle adapter
|
.prop_map(move |booleans| {
|
||||||
// (see also docs in `proptest_patched`
|
|
||||||
// Just(booleans)
|
|
||||||
// // Need to shuffle to make sure they are randomly distributed
|
|
||||||
// .prop_shuffle()
|
|
||||||
|
|
||||||
proptest_patched::Shuffle(Just(booleans)).prop_map(move |booleans| {
|
|
||||||
booleans
|
booleans
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
|
|
@ -1,146 +0,0 @@
|
||||||
//! Contains a modified implementation of `proptest::strategy::Shuffle`.
|
|
||||||
//!
|
|
||||||
//! The current implementation in `proptest` does not generate all permutations, which is
|
|
||||||
//! problematic for our proptest generators. The issue has been fixed in
|
|
||||||
//! https://github.com/AltSysrq/proptest/pull/217
|
|
||||||
//! but it has yet to be merged and released. As soon as this fix makes it into a new release,
|
|
||||||
//! the modified code here can be removed.
|
|
||||||
//!
|
|
||||||
/*!
|
|
||||||
This code has been copied and adapted from
|
|
||||||
https://github.com/AltSysrq/proptest/blob/master/proptest/src/strategy/shuffle.rs
|
|
||||||
The original licensing text is:
|
|
||||||
|
|
||||||
//-
|
|
||||||
// Copyright 2017 Jason Lingle
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
use proptest::num;
|
|
||||||
use proptest::prelude::Rng;
|
|
||||||
use proptest::strategy::{NewTree, Shuffleable, Strategy, ValueTree};
|
|
||||||
use proptest::test_runner::{TestRng, TestRunner};
|
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
#[must_use = "strategies do nothing unless used"]
|
|
||||||
pub struct Shuffle<S>(pub(super) S);
|
|
||||||
|
|
||||||
impl<S: Strategy> Strategy for Shuffle<S>
|
|
||||||
where
|
|
||||||
S::Value: Shuffleable,
|
|
||||||
{
|
|
||||||
type Tree = ShuffleValueTree<S::Tree>;
|
|
||||||
type Value = S::Value;
|
|
||||||
|
|
||||||
fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
|
|
||||||
let rng = runner.new_rng();
|
|
||||||
|
|
||||||
self.0.new_tree(runner).map(|inner| ShuffleValueTree {
|
|
||||||
inner,
|
|
||||||
rng,
|
|
||||||
dist: Cell::new(None),
|
|
||||||
simplifying_inner: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct ShuffleValueTree<V> {
|
|
||||||
inner: V,
|
|
||||||
rng: TestRng,
|
|
||||||
dist: Cell<Option<num::usize::BinarySearch>>,
|
|
||||||
simplifying_inner: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V: ValueTree> ShuffleValueTree<V>
|
|
||||||
where
|
|
||||||
V::Value: Shuffleable,
|
|
||||||
{
|
|
||||||
fn init_dist(&self, dflt: usize) -> usize {
|
|
||||||
if self.dist.get().is_none() {
|
|
||||||
self.dist.set(Some(num::usize::BinarySearch::new(dflt)));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dist.get().unwrap().current()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn force_init_dist(&self) {
|
|
||||||
if self.dist.get().is_none() {
|
|
||||||
let _ = self.init_dist(self.current().shuffle_len());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V: ValueTree> ValueTree for ShuffleValueTree<V>
|
|
||||||
where
|
|
||||||
V::Value: Shuffleable,
|
|
||||||
{
|
|
||||||
type Value = V::Value;
|
|
||||||
|
|
||||||
fn current(&self) -> V::Value {
|
|
||||||
let mut value = self.inner.current();
|
|
||||||
let len = value.shuffle_len();
|
|
||||||
// The maximum distance to swap elements. This could be larger than
|
|
||||||
// `value` if `value` has reduced size during shrinking; that's OK,
|
|
||||||
// since we only use this to filter swaps.
|
|
||||||
let max_swap = self.init_dist(len);
|
|
||||||
|
|
||||||
// If empty collection or all swaps will be filtered out, there's
|
|
||||||
// nothing to shuffle.
|
|
||||||
if 0 == len || 0 == max_swap {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rng = self.rng.clone();
|
|
||||||
|
|
||||||
for start_index in 0..len - 1 {
|
|
||||||
// Determine the other index to be swapped, then skip the swap if
|
|
||||||
// it is too far. This ordering is critical, as it ensures that we
|
|
||||||
// generate the same sequence of random numbers every time.
|
|
||||||
|
|
||||||
// NOTE: The below line is the whole reason for the existence of this adapted code
|
|
||||||
// We need to be able to swap with the same element, so that some elements remain in
|
|
||||||
// place rather being swapped
|
|
||||||
// let end_index = rng.gen_range(start_index + 1..len);
|
|
||||||
let end_index = rng.gen_range(start_index..len);
|
|
||||||
if end_index - start_index <= max_swap {
|
|
||||||
value.shuffle_swap(start_index, end_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
fn simplify(&mut self) -> bool {
|
|
||||||
if self.simplifying_inner {
|
|
||||||
self.inner.simplify()
|
|
||||||
} else {
|
|
||||||
// Ensure that we've initialised `dist` to *something* to give
|
|
||||||
// consistent non-panicking behaviour even if called in an
|
|
||||||
// unexpected sequence.
|
|
||||||
self.force_init_dist();
|
|
||||||
if self.dist.get_mut().as_mut().unwrap().simplify() {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
self.simplifying_inner = true;
|
|
||||||
self.inner.simplify()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn complicate(&mut self) -> bool {
|
|
||||||
if self.simplifying_inner {
|
|
||||||
self.inner.complicate()
|
|
||||||
} else {
|
|
||||||
self.force_init_dist();
|
|
||||||
self.dist.get_mut().as_mut().unwrap().complicate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue