mvpoly/
pbt.rs

1//! This module contains a list of property tests for the `MVPoly` trait.
2//!
3//! Any type that implements the `MVPoly` trait should pass these tests.
4//!
5//! For instance, one can call the `test_mul_by_one` as follows:
6//!
7//! ```rust
8//! use mvpoly::MVPoly;
9//! use mvpoly::prime::Dense;
10//! use mina_curves::pasta::Fp;
11//!
12//! fn test_mul_by_one() {
13//!     mvpoly::pbt::test_mul_by_one::<Fp, 2, 2, Dense<Fp, 2, 2>>();
14//!     mvpoly::pbt::test_mul_by_one::<Fp, 4, 2, Dense<Fp, 4, 2>>();
15//! }
16//! ```
17
18use crate::MVPoly;
19use ark_ff::PrimeField;
20use rand::{seq::SliceRandom, Rng};
21use std::ops::Neg;
22
23pub fn test_mul_by_one<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
24    let mut rng = o1_utils::tests::make_test_rng(None);
25    let p1 = unsafe { T::random(&mut rng, None) };
26    let one = T::one();
27    let p2 = p1.clone() * one.clone();
28    assert_eq!(p1.clone(), p2);
29    let p3 = one * p1.clone();
30    assert_eq!(p1.clone(), p3);
31}
32
33pub fn test_mul_by_zero<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
34    let mut rng = o1_utils::tests::make_test_rng(None);
35    let p1 = unsafe { T::random(&mut rng, None) };
36    let zero = T::zero();
37    let p2 = p1.clone() * zero.clone();
38    assert_eq!(zero, p2);
39    let p3 = zero.clone() * p1.clone();
40    assert_eq!(zero.clone(), p3);
41}
42
43pub fn test_add_zero<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
44    let mut rng = o1_utils::tests::make_test_rng(None);
45    let p1 = unsafe { T::random(&mut rng, None) };
46    let zero = T::zero();
47    let p2 = p1.clone() + zero.clone();
48    assert_eq!(p1.clone(), p2);
49    let p3 = zero.clone() + p1.clone();
50    assert_eq!(p1.clone(), p3);
51}
52
53pub fn test_double_is_add_twice<
54    F: PrimeField,
55    const N: usize,
56    const D: usize,
57    T: MVPoly<F, N, D>,
58>() {
59    let mut rng = o1_utils::tests::make_test_rng(None);
60    let p1 = unsafe { T::random(&mut rng, None) };
61    let p2 = p1.clone() + p1.clone();
62    let p3 = p1.clone().double();
63    assert_eq!(p2, p3);
64}
65
66pub fn test_sub_zero<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
67    let mut rng = o1_utils::tests::make_test_rng(None);
68    let p1 = unsafe { T::random(&mut rng, None) };
69    let zero = T::zero();
70    let p2 = p1.clone() - zero.clone();
71    assert_eq!(p1.clone(), p2);
72}
73
74pub fn test_neg<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
75    let mut rng = o1_utils::tests::make_test_rng(None);
76    let p1 = unsafe { T::random(&mut rng, None) };
77    let p2 = -p1.clone();
78    // Test that p1 + (-p1) = 0
79    let sum = p1.clone() + p2.clone();
80    assert_eq!(sum, T::zero());
81    // Test that -(-p1) = p1
82    let p3 = -p2;
83    assert_eq!(p1, p3);
84    // Test negation of zero
85    let zero = T::zero();
86    let neg_zero = -zero.clone();
87    assert_eq!(zero, neg_zero);
88}
89
90pub fn test_eval_pbt_add<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>()
91where
92    for<'a> &'a T: std::ops::Add<T, Output = T> + std::ops::Add<&'a T, Output = T>,
93{
94    let mut rng = o1_utils::tests::make_test_rng(None);
95    let random_evaluation: [F; N] = std::array::from_fn(|_| F::rand(&mut rng));
96    let p1 = unsafe { T::random(&mut rng, None) };
97    let p2 = unsafe { T::random(&mut rng, None) };
98    let eval_p1 = p1.eval(&random_evaluation);
99    let eval_p2 = p2.eval(&random_evaluation);
100    {
101        let p3 = p1.clone() + p2.clone();
102        let eval_p3 = p3.eval(&random_evaluation);
103        assert_eq!(eval_p3, eval_p1 + eval_p2);
104    }
105    {
106        let p3 = p1.clone() + &p2;
107        let eval_p3 = p3.eval(&random_evaluation);
108        assert_eq!(eval_p3, eval_p1 + eval_p2);
109    }
110    {
111        let p3 = &p1 + p2.clone();
112        let eval_p3 = p3.eval(&random_evaluation);
113        assert_eq!(eval_p3, eval_p1 + eval_p2);
114    }
115    {
116        let p3 = &p1 + &p2;
117        let eval_p3 = p3.eval(&random_evaluation);
118        assert_eq!(eval_p3, eval_p1 + eval_p2);
119    }
120}
121
122pub fn test_eval_pbt_sub<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>()
123where
124    for<'a> &'a T: std::ops::Sub<T, Output = T> + std::ops::Sub<&'a T, Output = T>,
125{
126    let mut rng = o1_utils::tests::make_test_rng(None);
127    let random_evaluation: [F; N] = std::array::from_fn(|_| F::rand(&mut rng));
128    let p1 = unsafe { T::random(&mut rng, None) };
129    let p2 = unsafe { T::random(&mut rng, None) };
130    let eval_p1 = p1.eval(&random_evaluation);
131    let eval_p2 = p2.eval(&random_evaluation);
132    {
133        let p3 = p1.clone() - p2.clone();
134        let eval_p3 = p3.eval(&random_evaluation);
135        assert_eq!(eval_p3, eval_p1 - eval_p2);
136    }
137    {
138        let p3 = p1.clone() - &p2;
139        let eval_p3 = p3.eval(&random_evaluation);
140        assert_eq!(eval_p3, eval_p1 - eval_p2);
141    }
142    {
143        let p3 = &p1 - p2.clone();
144        let eval_p3 = p3.eval(&random_evaluation);
145        assert_eq!(eval_p3, eval_p1 - eval_p2);
146    }
147    {
148        let p3 = &p1 - &p2;
149        let eval_p3 = p3.eval(&random_evaluation);
150        assert_eq!(eval_p3, eval_p1 - eval_p2);
151    }
152}
153
154pub fn test_eval_pbt_mul_by_scalar<
155    F: PrimeField,
156    const N: usize,
157    const D: usize,
158    T: MVPoly<F, N, D>,
159>() {
160    let mut rng = o1_utils::tests::make_test_rng(None);
161    let random_evaluation: [F; N] = std::array::from_fn(|_| F::rand(&mut rng));
162    let p1 = unsafe { T::random(&mut rng, None) };
163    let c = F::rand(&mut rng);
164    let p2 = p1.clone() * T::from(c);
165    let eval_p1 = p1.eval(&random_evaluation);
166    let eval_p2 = p2.eval(&random_evaluation);
167    assert_eq!(eval_p2, eval_p1 * c);
168}
169
170pub fn test_eval_pbt_neg<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
171    let mut rng = o1_utils::tests::make_test_rng(None);
172    let random_evaluation: [F; N] = std::array::from_fn(|_| F::rand(&mut rng));
173    let p1 = unsafe { T::random(&mut rng, None) };
174    let p2 = -p1.clone();
175    let eval_p1 = p1.eval(&random_evaluation);
176    let eval_p2 = p2.eval(&random_evaluation);
177    assert_eq!(eval_p2, -eval_p1);
178}
179
180pub fn test_neg_ref<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>()
181where
182    for<'a> &'a T: Neg<Output = T>,
183{
184    let mut rng = o1_utils::tests::make_test_rng(None);
185    let p1 = unsafe { T::random(&mut rng, None) };
186    let p2 = -&p1;
187    // Test that p1 + (-&p1) = 0
188    let sum = p1.clone() + p2.clone();
189    assert_eq!(sum, T::zero());
190    // Test that -(-&p1) = p1
191    let p3 = -&p2;
192    assert_eq!(p1, p3);
193}
194
195pub fn test_mul_by_scalar<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
196    let mut rng = o1_utils::tests::make_test_rng(None);
197    let p1 = unsafe { T::random(&mut rng, None) };
198    let mut p2 = T::zero();
199    let c = F::rand(&mut rng);
200    p2.modify_monomial([0; N], c);
201    assert_eq!(p2 * p1.clone(), p1.clone().mul_by_scalar(c));
202}
203
204pub fn test_mul_by_scalar_with_zero<
205    F: PrimeField,
206    const N: usize,
207    const D: usize,
208    T: MVPoly<F, N, D>,
209>() {
210    let mut rng = o1_utils::tests::make_test_rng(None);
211    let p1 = unsafe { T::random(&mut rng, None) };
212    let c = F::zero();
213    assert_eq!(p1.mul_by_scalar(c), T::zero());
214}
215
216pub fn test_mul_by_scalar_with_one<
217    F: PrimeField,
218    const N: usize,
219    const D: usize,
220    T: MVPoly<F, N, D>,
221>() {
222    let mut rng = o1_utils::tests::make_test_rng(None);
223    let p1 = unsafe { T::random(&mut rng, None) };
224    let c = F::one();
225    assert_eq!(p1.mul_by_scalar(c), p1);
226}
227
228pub fn test_evaluation_zero_polynomial<
229    F: PrimeField,
230    const N: usize,
231    const D: usize,
232    T: MVPoly<F, N, D>,
233>() {
234    let mut rng = o1_utils::tests::make_test_rng(None);
235    let random_evaluation: [F; N] = std::array::from_fn(|_| F::rand(&mut rng));
236    let zero = T::zero();
237    let evaluation = zero.eval(&random_evaluation);
238    assert_eq!(evaluation, F::zero());
239}
240
241pub fn test_evaluation_constant_polynomial<
242    F: PrimeField,
243    const N: usize,
244    const D: usize,
245    T: MVPoly<F, N, D>,
246>() {
247    let mut rng = o1_utils::tests::make_test_rng(None);
248    let random_evaluation: [F; N] = std::array::from_fn(|_| F::rand(&mut rng));
249    let cst = F::rand(&mut rng);
250    let poly = T::from(cst);
251    let evaluation = poly.eval(&random_evaluation);
252    assert_eq!(evaluation, cst);
253}
254
255pub fn test_degree_constant<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
256    let mut rng = o1_utils::tests::make_test_rng(None);
257    let c = F::rand(&mut rng);
258    let p = T::from(c);
259    let degree = unsafe { p.degree() };
260    assert_eq!(degree, 0);
261    let p = T::zero();
262    let degree = unsafe { p.degree() };
263    assert_eq!(degree, 0);
264}
265
266pub fn test_degree_random_degree<
267    F: PrimeField,
268    const N: usize,
269    const D: usize,
270    T: MVPoly<F, N, D>,
271>() {
272    let mut rng = o1_utils::tests::make_test_rng(None);
273    let max_degree: usize = rng.gen_range(1..D);
274    let p = unsafe { T::random(&mut rng, Some(max_degree)) };
275    let degree = unsafe { p.degree() };
276    assert!(degree <= max_degree);
277}
278
279pub fn test_mvpoly_add_degree_pbt<
280    F: PrimeField,
281    const N: usize,
282    const D: usize,
283    T: MVPoly<F, N, D>,
284>() {
285    let mut rng = o1_utils::tests::make_test_rng(None);
286    let degree = rng.gen_range(1..D);
287    let p1 = unsafe { T::random(&mut rng, Some(degree)) };
288    let p2 = unsafe { T::random(&mut rng, Some(degree)) };
289    let p3 = p1.clone() + p2.clone();
290    let degree_p1 = unsafe { p1.degree() };
291    let degree_p2 = unsafe { p2.degree() };
292    let degree_p3 = unsafe { p3.degree() };
293    assert!(degree_p3 <= std::cmp::max(degree_p1, degree_p2));
294}
295
296pub fn test_mvpoly_sub_degree_pbt<
297    F: PrimeField,
298    const N: usize,
299    const D: usize,
300    T: MVPoly<F, N, D>,
301>() {
302    let mut rng = o1_utils::tests::make_test_rng(None);
303    let degree = rng.gen_range(1..D);
304    let p1 = unsafe { T::random(&mut rng, Some(degree)) };
305    let p2 = unsafe { T::random(&mut rng, Some(degree)) };
306    let p3 = p1.clone() - p2.clone();
307    let degree_p1 = unsafe { p1.degree() };
308    let degree_p2 = unsafe { p2.degree() };
309    let degree_p3 = unsafe { p3.degree() };
310    assert!(degree_p3 <= std::cmp::max(degree_p1, degree_p2));
311}
312
313pub fn test_mvpoly_neg_degree_pbt<
314    F: PrimeField,
315    const N: usize,
316    const D: usize,
317    T: MVPoly<F, N, D>,
318>() {
319    let mut rng = o1_utils::tests::make_test_rng(None);
320    let degree = rng.gen_range(1..D);
321    let p1 = unsafe { T::random(&mut rng, Some(degree)) };
322    let p2 = -p1.clone();
323    let degree_p1 = unsafe { p1.degree() };
324    let degree_p2 = unsafe { p2.degree() };
325    assert_eq!(degree_p1, degree_p2);
326}
327
328pub fn test_mvpoly_mul_by_scalar_degree_pbt<
329    F: PrimeField,
330    const N: usize,
331    const D: usize,
332    T: MVPoly<F, N, D>,
333>() {
334    let mut rng = o1_utils::tests::make_test_rng(None);
335    let max_degree = rng.gen_range(1..D / 2);
336    let p1 = unsafe { T::random(&mut rng, Some(max_degree)) };
337    let c = F::rand(&mut rng);
338    let p2 = p1.clone() * T::from(c);
339    let degree_p1 = unsafe { p1.degree() };
340    let degree_p2 = unsafe { p2.degree() };
341    assert!(degree_p2 <= degree_p1);
342}
343
344pub fn test_mvpoly_mul_degree_pbt<
345    F: PrimeField,
346    const N: usize,
347    const D: usize,
348    T: MVPoly<F, N, D>,
349>() {
350    let mut rng = o1_utils::tests::make_test_rng(None);
351    let max_degree = rng.gen_range(1..D / 2);
352    let p1 = unsafe { T::random(&mut rng, Some(max_degree)) };
353    let p2 = unsafe { T::random(&mut rng, Some(max_degree)) };
354    let p3 = p1.clone() * p2.clone();
355    let degree_p1 = unsafe { p1.degree() };
356    let degree_p2 = unsafe { p2.degree() };
357    let degree_p3 = unsafe { p3.degree() };
358    assert!(degree_p3 <= degree_p1 + degree_p2);
359}
360
361pub fn test_mvpoly_mul_eval_pbt<
362    F: PrimeField,
363    const N: usize,
364    const D: usize,
365    T: MVPoly<F, N, D>,
366>() {
367    let mut rng = o1_utils::tests::make_test_rng(None);
368    let max_degree = rng.gen_range(1..D / 2);
369    let p1 = unsafe { T::random(&mut rng, Some(max_degree)) };
370    let p2 = unsafe { T::random(&mut rng, Some(max_degree)) };
371    let p3 = p1.clone() * p2.clone();
372    let random_evaluation: [F; N] = std::array::from_fn(|_| F::rand(&mut rng));
373    let eval_p1 = p1.eval(&random_evaluation);
374    let eval_p2 = p2.eval(&random_evaluation);
375    let eval_p3 = p3.eval(&random_evaluation);
376    assert_eq!(eval_p3, eval_p1 * eval_p2);
377}
378
379pub fn test_mvpoly_mul_pbt<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
380    let mut rng = o1_utils::tests::make_test_rng(None);
381    let max_degree = rng.gen_range(1..D / 2);
382    let p1 = unsafe { T::random(&mut rng, Some(max_degree)) };
383    let p2 = unsafe { T::random(&mut rng, Some(max_degree)) };
384    assert_eq!(p1.clone() * p2.clone(), p2.clone() * p1.clone());
385}
386
387pub fn test_can_be_printed_with_debug<
388    F: PrimeField,
389    const N: usize,
390    const D: usize,
391    T: MVPoly<F, N, D>,
392>() {
393    let mut rng = o1_utils::tests::make_test_rng(None);
394    let p1 = unsafe { T::random(&mut rng, None) };
395    println!("{:?}", p1);
396}
397
398pub fn test_is_zero<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
399    let mut rng = o1_utils::tests::make_test_rng(None);
400    let p1 = T::zero();
401    assert!(p1.is_zero());
402    let p2 = unsafe { T::random(&mut rng, None) };
403    assert!(!p2.is_zero());
404}
405
406pub fn test_homogeneous_eval<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
407    let mut rng = o1_utils::tests::make_test_rng(None);
408    let random_eval = std::array::from_fn(|_| F::rand(&mut rng));
409    let u = F::rand(&mut rng);
410
411    // Homogeneous form is u^2
412    let p1 = T::one();
413    let homogenous_eval = p1.homogeneous_eval(&random_eval, u);
414    assert_eq!(homogenous_eval, u * u);
415
416    let mut p2 = T::zero();
417    let mut exp1 = [0; N];
418    exp1[0] = 1;
419    p2.add_monomial(exp1, F::one());
420    let homogenous_eval = p2.homogeneous_eval(&random_eval, u);
421    assert_eq!(homogenous_eval, random_eval[0] * u);
422
423    let mut p3 = T::zero();
424    let mut exp2 = [0; N];
425    exp2[1] = 1;
426    p3.add_monomial(exp2, F::one());
427    let homogenous_eval = p3.homogeneous_eval(&random_eval, u);
428    assert_eq!(homogenous_eval, random_eval[1] * u);
429
430    let mut p4 = T::zero();
431    let mut exp3 = [0; N];
432    exp3[0] = 1;
433    exp3[1] = 1;
434    p4.add_monomial(exp3, F::one());
435    let homogenous_eval = p4.homogeneous_eval(&random_eval, u);
436    assert_eq!(homogenous_eval, random_eval[0] * random_eval[1]);
437
438    let mut p5 = T::zero();
439    let mut exp4 = [0; N];
440    exp4[0] = 2;
441    p5.add_monomial(exp4, F::one());
442    let homogenous_eval = p5.homogeneous_eval(&random_eval, u);
443    assert_eq!(homogenous_eval, random_eval[0] * random_eval[0]);
444
445    let mut p6 = T::zero();
446    let mut exp5a = [0; N];
447    let mut exp5b = [0; N];
448    exp5a[1] = 2;
449    exp5b[0] = 2;
450    p6.add_monomial(exp5a, F::one());
451    p6.add_monomial(exp5b, F::one());
452    let homogenous_eval = p6.homogeneous_eval(&random_eval, u);
453    assert_eq!(
454        homogenous_eval,
455        random_eval[1] * random_eval[1] + random_eval[0] * random_eval[0]
456    );
457
458    let mut p7 = T::zero();
459    let mut exp6a = [0; N];
460    let mut exp6b = [0; N];
461    let mut exp6c = [0; N];
462    exp6a[1] = 2;
463    exp6b[0] = 2;
464    exp6c[0] = 1;
465    p7.add_monomial(exp6a, F::one());
466    p7.add_monomial(exp6b, F::one());
467    p7.add_monomial(exp6c, F::one());
468    p7.add_monomial([0; N], F::from(42u32));
469    let homogenous_eval = p7.homogeneous_eval(&random_eval, u);
470    assert_eq!(
471        homogenous_eval,
472        random_eval[1] * random_eval[1]
473            + random_eval[0] * random_eval[0]
474            + u * random_eval[0]
475            + u * u * F::from(42u32)
476    );
477}
478
479pub fn test_add_monomial<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
480    let mut rng = o1_utils::tests::make_test_rng(None);
481
482    // Adding constant monomial one to zero
483    let mut p1 = T::zero();
484    p1.add_monomial([0; N], F::one());
485    assert_eq!(p1, T::one());
486
487    // Adding random constant monomial one to zero
488    let mut p2 = T::zero();
489    let random_c = F::rand(&mut rng);
490    p2.add_monomial([0; N], random_c);
491    assert_eq!(p2, T::from(random_c));
492
493    let mut p3 = T::zero();
494    let random_c1 = F::rand(&mut rng);
495    let random_c2 = F::rand(&mut rng);
496    // X1 + X2
497    let mut exp1 = [0; N];
498    let mut exp2 = [0; N];
499    exp1[0] = 1;
500    exp2[1] = 1;
501    p3.add_monomial(exp1, random_c1);
502    p3.add_monomial(exp2, random_c2);
503
504    let random_eval = std::array::from_fn(|_| F::rand(&mut rng));
505    let eval_p3 = p3.eval(&random_eval);
506    let exp_eval_p3 = random_c1 * random_eval[0] + random_c2 * random_eval[1];
507    assert_eq!(eval_p3, exp_eval_p3);
508
509    let mut p4 = T::zero();
510    let random_c1 = F::rand(&mut rng);
511    let random_c2 = F::rand(&mut rng);
512    // X1^2 + X2^2
513    let mut exp1 = [0; N];
514    let mut exp2 = [0; N];
515    exp1[0] = 2;
516    exp2[1] = 2;
517    p4.add_monomial(exp1, random_c1);
518    p4.add_monomial(exp2, random_c2);
519    let eval_p4 = p4.eval(&random_eval);
520    let exp_eval_p4 =
521        random_c1 * random_eval[0] * random_eval[0] + random_c2 * random_eval[1] * random_eval[1];
522    assert_eq!(eval_p4, exp_eval_p4);
523}
524
525pub fn test_is_multilinear<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
526    let mut rng = o1_utils::tests::make_test_rng(None);
527
528    // Test with zero polynomial
529    let p1 = T::zero();
530    assert!(p1.is_multilinear());
531
532    // Test with a constant polynomial
533    let c = F::rand(&mut rng);
534    let p2 = T::from(c);
535    assert!(p2.is_multilinear());
536
537    // Test with a polynomial with one variable having a linear monomial
538    {
539        let mut p = T::zero();
540        let c = F::rand(&mut rng);
541        let idx = rng.gen_range(0..N);
542        let monomials_exponents = std::array::from_fn(|i| if i == idx { 1 } else { 0 });
543        p.add_monomial(monomials_exponents, c);
544        assert!(p.is_multilinear());
545    }
546
547    // Test with a multilinear polynomial with random variables
548    {
549        let mut p = T::zero();
550        let c = F::rand(&mut rng);
551        let nb_var = rng.gen_range(0..D);
552        let mut monomials_exponents: [usize; N] =
553            std::array::from_fn(|i| if i <= nb_var { 1 } else { 0 });
554        monomials_exponents.shuffle(&mut rng);
555        p.add_monomial(monomials_exponents, c);
556        assert!(p.is_multilinear());
557    }
558}
559
560pub fn test_is_constant<F: PrimeField, const N: usize, const D: usize, T: MVPoly<F, N, D>>() {
561    let mut rng = o1_utils::tests::make_test_rng(None);
562    let c = F::rand(&mut rng);
563    let p = T::from(c);
564    assert!(p.is_constant());
565
566    let p = T::zero();
567    assert!(p.is_constant());
568
569    let p = {
570        let mut res = T::zero();
571        let monomial: [usize; N] = std::array::from_fn(|i| if i == 0 { 1 } else { 0 });
572        res.add_monomial(monomial, F::one());
573        res
574    };
575    assert!(!p.is_constant());
576
577    let p = {
578        let mut res = T::zero();
579        let monomial: [usize; N] = std::array::from_fn(|i| if i == 1 { 1 } else { 0 });
580        res.add_monomial(monomial, F::one());
581        res
582    };
583    assert!(!p.is_constant());
584
585    // This might be flaky
586    let p = unsafe { T::random(&mut rng, None) };
587    assert!(!p.is_constant());
588}