Proptest:生成向量向量的策略
Proptest: Strategy to generate vectors of vectors
我想用 proptest. The algorithm that I pick would be this. I've written the plain algorithm below -- but I need help transforming this to a proptest strategy 生成 DAG。
什么样的策略需要看起来像下面的代码一样,但不使用随机数生成器? (不用说,随机数生成器对基于 属性 的测试不利。)
没有protest策略的标准代码: (https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2de4a757a96d123bf83b5157e0633d33)
use rand::Rng;
fn main() {
println!("{:?}", random_vec_of_vec());
}
fn random_vec_of_vec() -> Vec<Vec<u16>> {
const N: u16 = 30;
const K: usize = 3;
let mut rng = rand::thread_rng();
let length: u16 = rng.gen_range(0, N);
let mut outer = vec![];
for index in 1..length {
let mut inner = vec![0u16; rng.gen_range(0, K)];
for e in &mut inner {
*e = rng.gen_range(0, index);
}
// De-duplicate elements. Particularly a problem with `index < K`.
inner.sort();
inner.dedup();
outer.push(inner);
}
outer
}
之前的作品
我尝试使用 vec 函数,但我需要嵌套两个 vec
函数。并且,内部 vec 函数只能生成外部向量中索引的值。
use proptest::collection::vec;
// INDEX should be the value of the position of the inner vector
// in the outer vector. How could the be found?
let strategy = vec(vec(1..INDEX, 0..K), 0..N);
index
方法没有帮助,因为仍然不知道正确的尺寸。
解决此问题的一种方法是用策略替换每个 rng.gen_range()
调用。嵌套策略必须与 prop_flat_map
.
在下面的代码中,我替换了我的模式
let length = rng.gen_range(0, N); for i in 1..length { .. }
,具有新功能 vec_from_length(length: usize)
,其中 returns 一个策略。
#[cfg(test)]
mod tests {
use super::*;
use proptest::collection::hash_set;
use proptest::prelude::*;
use std::collections::HashSet;
proptest! {
#[test]
fn meaningless_test(v in vec_of_vec()) {
let s = sum(&v); // sum of the sum of all vectors.
prop_assert!(s < 15);
}
}
fn vec_of_vec() -> impl Strategy<Value = Vec<Vec<u16>>> {
const N: u16 = 10;
let length = 0..N;
length.prop_flat_map(vec_from_length).prop_map(convert)
}
fn vec_from_length(length: u16) -> impl Strategy<Value = Vec<HashSet<u16>>> {
const K: usize = 5;
let mut result = vec![];
for index in 1..length {
// Using a hash_set instead of vec because the elements should be unique.
let inner = hash_set(0..index, 0..K);
result.push(inner);
}
result
}
/// Convert Vec<HashSet<T>> to Vec<Vec<T>>
fn convert(input: Vec<HashSet<u16>>) -> Vec<Vec<u16>> {
let mut output = vec![];
for inner in input {
output.push(inner.into_iter().collect())
}
output
}
}
还有一件事:impl Strategy<Value=Vec<T>>
可以从 vec
函数(向量策略)或策略向量中生成!在上面的代码中,我通过将 result
与 hash_set(..)
进行 push
编辑来实现这一点,这是一种策略。因此,该类型类似于 Vec<Strategy<T>>
而不是 Strategy<Vec<T>>
(迂腐:策略不是一种类型,也许)。