1use alloc::vec;
2use alloc::vec::Vec;
3
4use p3_field::{Field, PackedField, PackedFieldPow2, PackedValue, PrimeCharacteristicRing};
5use rand::distr::{Distribution, StandardUniform};
6use rand::rngs::SmallRng;
7use rand::{Rng, SeedableRng};
8
9fn packed_from_random<PV>(seed: u64) -> PV
10where
11 PV: PackedValue,
12 StandardUniform: Distribution<PV::Value>,
13{
14 let mut rng = SmallRng::seed_from_u64(seed);
15 PV::from_fn(|_| rng.random())
16}
17
18fn interleave<T: Copy + Default>(arr1: &[T], arr2: &[T], i: usize) -> (Vec<T>, Vec<T>) {
20 let width = arr1.len();
21 assert_eq!(width, arr2.len());
22 assert_eq!(width % i, 0);
23
24 if i == width {
25 return (arr1.to_vec(), arr2.to_vec());
26 }
27
28 let mut outleft = vec![T::default(); width];
29 let mut outright = vec![T::default(); width];
30
31 let mut flag = false;
32
33 for j in 0..width {
34 if j.is_multiple_of(i) {
35 flag = !flag;
36 }
37 if flag {
38 outleft[j] = arr1[j];
39 outleft[j + i] = arr2[j];
40 } else {
41 outright[j - i] = arr1[j];
42 outright[j] = arr2[j];
43 }
44 }
45
46 (outleft, outright)
47}
48
49fn test_interleave<PF>(i: usize)
50where
51 PF: PackedFieldPow2 + Eq,
52 StandardUniform: Distribution<PF::Scalar>,
53{
54 assert!(PF::WIDTH.is_multiple_of(i));
55
56 let vec1 = packed_from_random::<PF>(0x4ff5dec04791e481);
57 let vec2 = packed_from_random::<PF>(0x5806c495e9451f8e);
58
59 let arr1 = vec1.as_slice();
60 let arr2 = vec2.as_slice();
61
62 let (res1, res2) = vec1.interleave(vec2, i);
63 let (out1, out2) = interleave(arr1, arr2, i);
64
65 assert_eq!(
66 res1.as_slice(),
67 &out1,
68 "Error in left output when testing interleave {i}. Data is: \n {arr1:?} \n {arr2:?} \n {res1:?} \n {res2:?} \n {out1:?} \n {out2:?}.",
69 );
70 assert_eq!(
71 res2.as_slice(),
72 &out2,
73 "Error in right output when testing interleave {i}.",
74 );
75}
76
77pub fn test_interleaves<PF>()
78where
79 PF: PackedFieldPow2 + Eq,
80 StandardUniform: Distribution<PF::Scalar>,
81{
82 let mut i = 1;
83 while i <= PF::WIDTH {
84 test_interleave::<PF>(i);
85 i *= 2;
86 }
87}
88
89pub fn test_packed_linear_combination<PF: PackedField + Eq>()
90where
91 StandardUniform: Distribution<PF> + Distribution<PF::Scalar>,
92{
93 let mut rng = SmallRng::seed_from_u64(1);
94 let u: [PF::Scalar; 64] = rng.random();
95 let v: [PF; 64] = rng.random();
96
97 let mut dot = PF::ZERO;
98 assert_eq!(dot, PF::packed_linear_combination::<0>(&u[..0], &v[..0]));
99 dot += v[0] * u[0];
100 assert_eq!(dot, PF::packed_linear_combination::<1>(&u[..1], &v[..1]));
101 dot += v[1] * u[1];
102 assert_eq!(dot, PF::packed_linear_combination::<2>(&u[..2], &v[..2]));
103 dot += v[2] * u[2];
104 assert_eq!(dot, PF::packed_linear_combination::<3>(&u[..3], &v[..3]));
105 dot += v[3] * u[3];
106 assert_eq!(dot, PF::packed_linear_combination::<4>(&u[..4], &v[..4]));
107 dot += v[4] * u[4];
108 assert_eq!(dot, PF::packed_linear_combination::<5>(&u[..5], &v[..5]));
109 dot += v[5] * u[5];
110 assert_eq!(dot, PF::packed_linear_combination::<6>(&u[..6], &v[..6]));
111 dot += v[6] * u[6];
112 assert_eq!(dot, PF::packed_linear_combination::<7>(&u[..7], &v[..7]));
113 dot += v[7] * u[7];
114 assert_eq!(dot, PF::packed_linear_combination::<8>(&u[..8], &v[..8]));
115 dot += v[8] * u[8];
116 assert_eq!(dot, PF::packed_linear_combination::<9>(&u[..9], &v[..9]));
117 dot += v[9] * u[9];
118 assert_eq!(dot, PF::packed_linear_combination::<10>(&u[..10], &v[..10]));
119 dot += v[10] * u[10];
120 assert_eq!(dot, PF::packed_linear_combination::<11>(&u[..11], &v[..11]));
121 dot += v[11] * u[11];
122 assert_eq!(dot, PF::packed_linear_combination::<12>(&u[..12], &v[..12]));
123 dot += v[12] * u[12];
124 assert_eq!(dot, PF::packed_linear_combination::<13>(&u[..13], &v[..13]));
125 dot += v[13] * u[13];
126 assert_eq!(dot, PF::packed_linear_combination::<14>(&u[..14], &v[..14]));
127 dot += v[14] * u[14];
128 assert_eq!(dot, PF::packed_linear_combination::<15>(&u[..15], &v[..15]));
129 dot += v[15] * u[15];
130 assert_eq!(dot, PF::packed_linear_combination::<16>(&u[..16], &v[..16]));
131
132 let dot_64: PF = u
133 .iter()
134 .zip(v.iter())
135 .fold(PF::ZERO, |acc, (&lhs, &rhs)| acc + (rhs * lhs));
136 assert_eq!(dot_64, PF::packed_linear_combination::<64>(&u, &v));
137}
138
139pub fn test_vs_scalar<PF>(special_vals: PF)
140where
141 PF: PackedField + Eq,
142 StandardUniform: Distribution<PF::Scalar>,
143{
144 let vec0: PF = packed_from_random(0x278d9e202925a1d1);
145 let vec1: PF = packed_from_random(0xf04cbac0cbad419f);
146 let vec_special = special_vals;
147
148 let arr0 = vec0.as_slice();
149 let arr1 = vec1.as_slice();
150
151 let vec_sum = vec0 + vec1;
152 let arr_sum = vec_sum.as_slice();
153 let vec_special_sum_left = vec_special + vec0;
154 let arr_special_sum_left = vec_special_sum_left.as_slice();
155 let vec_special_sum_right = vec1 + vec_special;
156 let arr_special_sum_right = vec_special_sum_right.as_slice();
157
158 let vec_sub = vec0 - vec1;
159 let arr_sub = vec_sub.as_slice();
160 let vec_special_sub_left = vec_special - vec0;
161 let arr_special_sub_left = vec_special_sub_left.as_slice();
162 let vec_special_sub_right = vec1 - vec_special;
163 let arr_special_sub_right = vec_special_sub_right.as_slice();
164
165 let vec_mul = vec0 * vec1;
166 let arr_mul = vec_mul.as_slice();
167 let vec_special_mul_left = vec_special * vec0;
168 let arr_special_mul_left = vec_special_mul_left.as_slice();
169 let vec_special_mul_right = vec1 * vec_special;
170 let arr_special_mul_right = vec_special_mul_right.as_slice();
171
172 let vec_neg = -vec0;
173 let arr_neg = vec_neg.as_slice();
174 let vec_special_neg = -vec_special;
175 let arr_special_neg = vec_special_neg.as_slice();
176
177 let vec_exp_3 = vec0.exp_const_u64::<3>();
178 let arr_exp_3 = vec_exp_3.as_slice();
179 let vec_special_exp_3 = vec_special.exp_const_u64::<3>();
180 let arr_special_exp_3 = vec_special_exp_3.as_slice();
181
182 let vec_exp_5 = vec0.exp_const_u64::<5>();
183 let arr_exp_5 = vec_exp_5.as_slice();
184 let vec_special_exp_5 = vec_special.exp_const_u64::<5>();
185 let arr_special_exp_5 = vec_special_exp_5.as_slice();
186
187 let vec_exp_7 = vec0.exp_const_u64::<7>();
188 let arr_exp_7 = vec_exp_7.as_slice();
189 let vec_special_exp_7 = vec_special.exp_const_u64::<7>();
190 let arr_special_exp_7 = vec_special_exp_7.as_slice();
191
192 let special_vals = special_vals.as_slice();
193 for i in 0..PF::WIDTH {
194 assert_eq!(
195 arr_sum[i],
196 arr0[i] + arr1[i],
197 "Error when testing add consistency of packed and scalar at location {i}.",
198 );
199 assert_eq!(
200 arr_special_sum_left[i],
201 special_vals[i] + arr0[i],
202 "Error when testing consistency of left add for special values for packed and scalar at location {i}.",
203 );
204 assert_eq!(
205 arr_special_sum_right[i],
206 arr1[i] + special_vals[i],
207 "Error when testing consistency of right add for special values for packed and scalar at location {i}.",
208 );
209
210 assert_eq!(
211 arr_sub[i],
212 arr0[i] - arr1[i],
213 "Error when testing sub consistency of packed and scalar at location {i}.",
214 );
215 assert_eq!(
216 arr_special_sub_left[i],
217 special_vals[i] - arr0[i],
218 "Error when testing consistency of left sub for special values for packed and scalar at location {i}.",
219 );
220 assert_eq!(
221 arr_special_sub_right[i],
222 arr1[i] - special_vals[i],
223 "Error when testing consistency of right sub for special values for packed and scalar at location {i}.",
224 );
225
226 assert_eq!(
227 arr_mul[i],
228 arr0[i] * arr1[i],
229 "Error when testing mul consistency of packed and scalar at location {i}.",
230 );
231 assert_eq!(
232 arr_special_mul_left[i],
233 special_vals[i] * arr0[i],
234 "Error when testing consistency of left mul for special values for packed and scalar at location {i}.",
235 );
236 assert_eq!(
237 arr_special_mul_right[i],
238 arr1[i] * special_vals[i],
239 "Error when testing consistency of right mul for special values for packed and scalar at location {i}.",
240 );
241
242 assert_eq!(
243 arr_neg[i], -arr0[i],
244 "Error when testing neg consistency of packed and scalar at location {i}.",
245 );
246 assert_eq!(
247 arr_special_neg[i], -special_vals[i],
248 "Error when testing consistency of neg for special values for packed and scalar at location {i}.",
249 );
250 assert_eq!(
251 arr_exp_3[i],
252 arr0[i].exp_const_u64::<3>(),
253 "Error when testing exp_const_u64::<3> consistency of packed and scalar at location {i}.",
254 );
255 assert_eq!(
256 arr_special_exp_3[i],
257 special_vals[i].exp_const_u64::<3>(),
258 "Error when testing consistency of exp_const_u64::<3> for special values for packed and scalar at location {i}.",
259 );
260 assert_eq!(
261 arr_exp_5[i],
262 arr0[i].exp_const_u64::<5>(),
263 "Error when testing exp_const_u64::<5> consistency of packed and scalar at location {i}.",
264 );
265 assert_eq!(
266 arr_special_exp_5[i],
267 special_vals[i].exp_const_u64::<5>(),
268 "Error when testing consistency of exp_const_u64::<5> for special values for packed and scalar at location {i}.",
269 );
270 assert_eq!(
271 arr_exp_7[i],
272 arr0[i].exp_const_u64::<7>(),
273 "Error when testing exp_const_u64::<7> consistency of packed and scalar at location {i}.",
274 );
275 assert_eq!(
276 arr_special_exp_7[i],
277 special_vals[i].exp_const_u64::<7>(),
278 "Error when testing consistency of exp_const_u64::<7> for special values for packed and scalar at location {i}.",
279 );
280 }
281}
282
283pub fn test_multiplicative_inverse<PF>()
284where
285 PF: PackedField + Eq,
286 StandardUniform: Distribution<PF::Scalar>,
287{
288 let vec: PF = packed_from_random(0xb0c7a5153103c5a8);
289 let arr = vec.as_slice();
290 let vec_inv = PF::from_fn(|i| arr[i].inverse());
291 let res = vec * vec_inv;
292 assert_eq!(
293 res,
294 PF::ONE,
295 "Error when testing multiplication by inverse."
296 );
297}
298
299#[macro_export]
300macro_rules! test_packed_field {
301 ($packedfield:ty, $zeros:expr, $ones:expr, $specials:expr) => {
302 $crate::test_ring_with_eq!($packedfield, $zeros, $ones);
303
304 mod packed_field_tests {
305 use p3_field::PrimeCharacteristicRing;
306
307 #[test]
308 fn test_interleaves() {
309 $crate::test_interleaves::<$packedfield>();
310 }
311 #[test]
312 fn test_packed_linear_combination() {
313 $crate::test_packed_linear_combination::<$packedfield>();
314 }
315 #[test]
316 fn test_vs_scalar() {
317 $crate::test_vs_scalar::<$packedfield>($specials);
318 }
319 #[test]
320 fn test_multiplicative_inverse() {
321 $crate::test_multiplicative_inverse::<$packedfield>();
322 }
323 }
324 };
325}
326
327#[macro_export]
328macro_rules! test_packed_extension_field {
329 ($packedextfield:ty, $zeros:expr, $ones:expr) => {
330 mod packed_field_tests {
331 use p3_field::PrimeCharacteristicRing;
332
333 #[test]
335 fn test_ring_with_eq() {
336 $crate::test_ring_with_eq::<$packedextfield>($zeros, $ones);
337 }
338 }
339 };
340}