1 | #[cfg (test)] |
2 | macro_rules! test { |
3 | ($ty:ident) => { |
4 | mod $ty { |
5 | use approx::relative_eq; |
6 | use quickcheck::quickcheck; |
7 | use quickcheck::TestResult; |
8 | |
9 | use crate::stats::univariate::{Sample, mixed, self}; |
10 | |
11 | quickcheck!{ |
12 | fn mean(size: u8, start: u8, nresamples: u8) -> TestResult { |
13 | let size = size as usize; |
14 | let start = start as usize; |
15 | let nresamples = nresamples as usize; |
16 | if let Some(v) = crate::stats::test::vec::<$ty>(size, start) { |
17 | let sample = Sample::new(&v[start..]); |
18 | |
19 | let means = if nresamples > 0 { |
20 | sample.bootstrap(nresamples, |s| (s.mean(),)).0 |
21 | } else { |
22 | return TestResult::discard(); |
23 | }; |
24 | |
25 | let min = sample.min(); |
26 | let max = sample.max(); |
27 | |
28 | TestResult::from_bool( |
29 | // Computed the correct number of resamples |
30 | means.len() == nresamples && |
31 | // No uninitialized values |
32 | means.iter().all(|&x| { |
33 | (x > min || relative_eq!(x, min)) && |
34 | (x < max || relative_eq!(x, max)) |
35 | }) |
36 | ) |
37 | } else { |
38 | TestResult::discard() |
39 | } |
40 | } |
41 | } |
42 | |
43 | quickcheck!{ |
44 | fn mean_median(size: u8, start: u8, nresamples: u8) -> TestResult { |
45 | let size = size as usize; |
46 | let start = start as usize; |
47 | let nresamples = nresamples as usize; |
48 | if let Some(v) = crate::stats::test::vec::<$ty>(size, start) { |
49 | let sample = Sample::new(&v[start..]); |
50 | |
51 | let (means, medians) = if nresamples > 0 { |
52 | sample.bootstrap(nresamples, |s| (s.mean(), s.median())) |
53 | } else { |
54 | return TestResult::discard(); |
55 | }; |
56 | |
57 | let min = sample.min(); |
58 | let max = sample.max(); |
59 | |
60 | TestResult::from_bool( |
61 | // Computed the correct number of resamples |
62 | means.len() == nresamples && |
63 | medians.len() == nresamples && |
64 | // No uninitialized values |
65 | means.iter().all(|&x| { |
66 | (x > min || relative_eq!(x, min)) && |
67 | (x < max || relative_eq!(x, max)) |
68 | }) && |
69 | medians.iter().all(|&x| { |
70 | (x > min || relative_eq!(x, min)) && |
71 | (x < max || relative_eq!(x, max)) |
72 | }) |
73 | ) |
74 | } else { |
75 | TestResult::discard() |
76 | } |
77 | } |
78 | } |
79 | |
80 | quickcheck!{ |
81 | fn mixed_two_sample( |
82 | a_size: u8, a_start: u8, |
83 | b_size: u8, b_start: u8, |
84 | nresamples: u8 |
85 | ) -> TestResult { |
86 | let a_size = a_size as usize; |
87 | let b_size = b_size as usize; |
88 | let a_start = a_start as usize; |
89 | let b_start = b_start as usize; |
90 | let nresamples = nresamples as usize; |
91 | if let (Some(a), Some(b)) = |
92 | (crate::stats::test::vec::<$ty>(a_size, a_start), crate::stats::test::vec::<$ty>(b_size, b_start)) |
93 | { |
94 | let a = Sample::new(&a); |
95 | let b = Sample::new(&b); |
96 | |
97 | let distribution = if nresamples > 0 { |
98 | mixed::bootstrap(a, b, nresamples, |a, b| (a.mean() - b.mean(),)).0 |
99 | } else { |
100 | return TestResult::discard(); |
101 | }; |
102 | |
103 | let min = <$ty>::min(a.min() - b.max(), b.min() - a.max()); |
104 | let max = <$ty>::max(a.max() - b.min(), b.max() - a.min()); |
105 | |
106 | TestResult::from_bool( |
107 | // Computed the correct number of resamples |
108 | distribution.len() == nresamples && |
109 | // No uninitialized values |
110 | distribution.iter().all(|&x| { |
111 | (x > min || relative_eq!(x, min)) && |
112 | (x < max || relative_eq!(x, max)) |
113 | }) |
114 | ) |
115 | } else { |
116 | TestResult::discard() |
117 | } |
118 | } |
119 | } |
120 | |
121 | quickcheck!{ |
122 | fn two_sample( |
123 | a_size: u8, a_start: u8, |
124 | b_size: u8, b_start: u8, |
125 | nresamples: u8 |
126 | ) -> TestResult { |
127 | let a_size = a_size as usize; |
128 | let b_size = b_size as usize; |
129 | let a_start = a_start as usize; |
130 | let b_start = b_start as usize; |
131 | let nresamples = nresamples as usize; |
132 | if let (Some(a), Some(b)) = |
133 | (crate::stats::test::vec::<$ty>(a_size, a_start), crate::stats::test::vec::<$ty>(b_size, b_start)) |
134 | { |
135 | let a = Sample::new(&a[a_start..]); |
136 | let b = Sample::new(&b[b_start..]); |
137 | |
138 | let distribution = if nresamples > 0 { |
139 | univariate::bootstrap(a, b, nresamples, |a, b| (a.mean() - b.mean(),)).0 |
140 | } else { |
141 | return TestResult::discard(); |
142 | }; |
143 | |
144 | let min = <$ty>::min(a.min() - b.max(), b.min() - a.max()); |
145 | let max = <$ty>::max(a.max() - b.min(), b.max() - a.min()); |
146 | |
147 | // Computed the correct number of resamples |
148 | let pass = distribution.len() == nresamples && |
149 | // No uninitialized values |
150 | distribution.iter().all(|&x| { |
151 | (x > min || relative_eq!(x, min)) && |
152 | (x < max || relative_eq!(x, max)) |
153 | }); |
154 | |
155 | if !pass { |
156 | println!("A: {:?} (len={})" , a.as_ref(), a.len()); |
157 | println!("B: {:?} (len={})" , b.as_ref(), b.len()); |
158 | println!("Dist: {:?} (len={})" , distribution.as_ref(), distribution.len()); |
159 | println!("Min: {}, Max: {}, nresamples: {}" , |
160 | min, max, nresamples); |
161 | } |
162 | |
163 | TestResult::from_bool(pass) |
164 | } else { |
165 | TestResult::discard() |
166 | } |
167 | } |
168 | } |
169 | } |
170 | } |
171 | } |
172 | |
173 | #[cfg (test)] |
174 | mod test { |
175 | test!(f32); |
176 | test!(f64); |
177 | } |
178 | |