1use crate::{
3 univariate::{DenseOrSparsePolynomial, SparsePolynomial},
4 DenseUVPolynomial, EvaluationDomain, Evaluations, GeneralEvaluationDomain, Polynomial,
5};
6use ark_ff::{FftField, Field, Zero};
7use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
8use ark_std::{
9 fmt,
10 ops::{Add, AddAssign, Deref, DerefMut, Div, Mul, Neg, Sub, SubAssign},
11 rand::Rng,
12 vec::*,
13};
14
15#[cfg(feature = "parallel")]
16use ark_std::cmp::max;
17#[cfg(feature = "parallel")]
18use rayon::prelude::*;
19
20#[derive(Clone, PartialEq, Eq, Hash, Default, CanonicalSerialize, CanonicalDeserialize)]
22pub struct DensePolynomial<F: Field> {
23 pub coeffs: Vec<F>,
25}
26
27impl<F: Field> Polynomial<F> for DensePolynomial<F> {
28 type Point = F;
29
30 fn degree(&self) -> usize {
32 if self.is_zero() {
33 0
34 } else {
35 assert!(self.coeffs.last().map_or(false, |coeff| !coeff.is_zero()));
36 self.coeffs.len() - 1
37 }
38 }
39
40 fn evaluate(&self, point: &F) -> F {
42 if self.is_zero() {
43 return F::zero();
44 } else if point.is_zero() {
45 return self.coeffs[0];
46 }
47 self.internal_evaluate(point)
48 }
49}
50
51#[cfg(feature = "parallel")]
52const MIN_ELEMENTS_PER_THREAD: usize = 16;
55
56impl<F: Field> DensePolynomial<F> {
57 #[inline]
58 fn horner_evaluate(poly_coeffs: &[F], point: &F) -> F {
60 poly_coeffs
61 .iter()
62 .rfold(F::zero(), move |result, coeff| result * point + coeff)
63 }
64
65 #[cfg(not(feature = "parallel"))]
66 fn internal_evaluate(&self, point: &F) -> F {
67 Self::horner_evaluate(&self.coeffs, point)
68 }
69
70 #[cfg(feature = "parallel")]
71 fn internal_evaluate(&self, point: &F) -> F {
72 let num_cpus_available = rayon::current_num_threads();
75 let num_coeffs = self.coeffs.len();
76 let num_elem_per_thread = max(num_coeffs / num_cpus_available, MIN_ELEMENTS_PER_THREAD);
77
78 let result = self
84 .coeffs
85 .par_chunks(num_elem_per_thread)
86 .enumerate()
87 .map(|(i, chunk)| {
88 let mut thread_result = Self::horner_evaluate(&chunk, point);
89 thread_result *= point.pow(&[(i * num_elem_per_thread) as u64]);
90 thread_result
91 })
92 .sum();
93 result
94 }
95}
96
97impl<F: Field> DenseUVPolynomial<F> for DensePolynomial<F> {
98 fn from_coefficients_slice(coeffs: &[F]) -> Self {
100 Self::from_coefficients_vec(coeffs.to_vec())
101 }
102
103 fn from_coefficients_vec(coeffs: Vec<F>) -> Self {
105 let mut result = Self { coeffs };
106 result.truncate_leading_zeros();
108 assert!(result.coeffs.last().map_or(true, |coeff| !coeff.is_zero()));
111 result
112 }
113
114 fn coeffs(&self) -> &[F] {
116 &self.coeffs
117 }
118
119 fn rand<R: Rng>(d: usize, rng: &mut R) -> Self {
135 let mut random_coeffs = Vec::new();
136
137 if d > 0 {
138 for _ in 0..=(d - 1) {
140 random_coeffs.push(F::rand(rng));
141 }
142 }
143
144 let mut leading_coefficient = F::rand(rng);
145
146 while leading_coefficient.is_zero() {
147 leading_coefficient = F::rand(rng);
148 }
149
150 random_coeffs.push(leading_coefficient);
151
152 Self::from_coefficients_vec(random_coeffs)
153 }
154}
155
156impl<F: FftField> DensePolynomial<F> {
157 pub fn mul_by_vanishing_poly<D: EvaluationDomain<F>>(&self, domain: D) -> DensePolynomial<F> {
160 let mut shifted = vec![F::zero(); domain.size()];
161 shifted.extend_from_slice(&self.coeffs);
162 cfg_iter_mut!(shifted)
163 .zip(&self.coeffs)
164 .for_each(|(s, c)| *s -= c);
165 DensePolynomial::from_coefficients_vec(shifted)
166 }
167
168 pub fn divide_by_vanishing_poly<D: EvaluationDomain<F>>(
171 &self,
172 domain: D,
173 ) -> (DensePolynomial<F>, DensePolynomial<F>) {
174 let domain_size = domain.size();
175
176 if self.coeffs.len() < domain_size {
177 (DensePolynomial::<F>::zero(), self.clone())
179 } else {
180 let mut quotient_vec = self.coeffs[domain_size..].to_vec();
189 for i in 1..(self.len() / domain_size) {
190 cfg_iter_mut!(quotient_vec)
191 .zip(&self.coeffs[domain_size * (i + 1)..])
192 .for_each(|(s, c)| *s += c);
193 }
194
195 let mut remainder_vec = self.coeffs[0..domain_size].to_vec();
208 cfg_iter_mut!(remainder_vec)
209 .zip("ient_vec)
210 .for_each(|(s, c)| *s += c);
211
212 let quotient = DensePolynomial::<F>::from_coefficients_vec(quotient_vec);
213 let remainder = DensePolynomial::<F>::from_coefficients_vec(remainder_vec);
214 (quotient, remainder)
215 }
216 }
217}
218
219impl<F: Field> DensePolynomial<F> {
220 fn truncate_leading_zeros(&mut self) {
221 while self.coeffs.last().map_or(false, |c| c.is_zero()) {
222 self.coeffs.pop();
223 }
224 }
225
226 pub fn naive_mul(&self, other: &Self) -> Self {
228 if self.is_zero() || other.is_zero() {
229 DensePolynomial::zero()
230 } else {
231 let mut result = vec![F::zero(); self.degree() + other.degree() + 1];
232 for (i, self_coeff) in self.coeffs.iter().enumerate() {
233 for (j, other_coeff) in other.coeffs.iter().enumerate() {
234 result[i + j] += &(*self_coeff * other_coeff);
235 }
236 }
237 DensePolynomial::from_coefficients_vec(result)
238 }
239 }
240}
241
242impl<F: FftField> DensePolynomial<F> {
243 pub fn evaluate_over_domain_by_ref<D: EvaluationDomain<F>>(
245 &self,
246 domain: D,
247 ) -> Evaluations<F, D> {
248 let poly: DenseOrSparsePolynomial<'_, F> = self.into();
249 DenseOrSparsePolynomial::<F>::evaluate_over_domain(poly, domain)
250 }
251
252 pub fn evaluate_over_domain<D: EvaluationDomain<F>>(self, domain: D) -> Evaluations<F, D> {
254 let poly: DenseOrSparsePolynomial<'_, F> = self.into();
255 DenseOrSparsePolynomial::<F>::evaluate_over_domain(poly, domain)
256 }
257}
258
259impl<F: Field> fmt::Debug for DensePolynomial<F> {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
261 for (i, coeff) in self.coeffs.iter().enumerate().filter(|(_, c)| !c.is_zero()) {
262 if i == 0 {
263 write!(f, "\n{:?}", coeff)?;
264 } else if i == 1 {
265 write!(f, " + \n{:?} * x", coeff)?;
266 } else {
267 write!(f, " + \n{:?} * x^{}", coeff, i)?;
268 }
269 }
270 Ok(())
271 }
272}
273
274impl<F: Field> Deref for DensePolynomial<F> {
275 type Target = [F];
276
277 fn deref(&self) -> &[F] {
278 &self.coeffs
279 }
280}
281
282impl<F: Field> DerefMut for DensePolynomial<F> {
283 fn deref_mut(&mut self) -> &mut [F] {
284 &mut self.coeffs
285 }
286}
287
288impl<'a, 'b, F: Field> Add<&'a DensePolynomial<F>> for &'b DensePolynomial<F> {
289 type Output = DensePolynomial<F>;
290
291 fn add(self, other: &'a DensePolynomial<F>) -> DensePolynomial<F> {
292 let mut result = if self.is_zero() {
293 other.clone()
294 } else if other.is_zero() {
295 self.clone()
296 } else if self.degree() >= other.degree() {
297 let mut result = self.clone();
298 result
299 .coeffs
300 .iter_mut()
301 .zip(&other.coeffs)
302 .for_each(|(a, b)| {
303 *a += b;
304 });
305 result
306 } else {
307 let mut result = other.clone();
308 result
309 .coeffs
310 .iter_mut()
311 .zip(&self.coeffs)
312 .for_each(|(a, b)| {
313 *a += b;
314 });
315 result
316 };
317 result.truncate_leading_zeros();
318 result
319 }
320}
321
322impl<'a, 'b, F: Field> Add<&'a SparsePolynomial<F>> for &'b DensePolynomial<F> {
323 type Output = DensePolynomial<F>;
324
325 #[inline]
326 fn add(self, other: &'a SparsePolynomial<F>) -> DensePolynomial<F> {
327 if self.is_zero() {
328 other.clone().into()
329 } else if other.is_zero() {
330 self.clone()
331 } else {
332 let mut result = self.clone();
333 let mut upper_coeffs = match other.degree() > result.degree() {
336 true => vec![F::zero(); other.degree() - result.degree()],
337 false => Vec::new(),
338 };
339 for (pow, coeff) in other.iter() {
340 if *pow <= result.degree() {
341 result.coeffs[*pow] += coeff;
342 } else {
343 upper_coeffs[*pow - result.degree() - 1] = *coeff;
344 }
345 }
346 result.coeffs.extend(upper_coeffs);
347 result
348 }
349 }
350}
351
352impl<'a, F: Field> AddAssign<&'a DensePolynomial<F>> for DensePolynomial<F> {
353 fn add_assign(&mut self, other: &'a DensePolynomial<F>) {
354 if self.is_zero() {
355 self.coeffs.truncate(0);
356 self.coeffs.extend_from_slice(&other.coeffs);
357 } else if other.is_zero() {
358 } else if self.degree() >= other.degree() {
359 self.coeffs
360 .iter_mut()
361 .zip(&other.coeffs)
362 .for_each(|(a, b)| {
363 *a += b;
364 });
365 } else {
366 self.coeffs.resize(other.coeffs.len(), F::zero());
368 self.coeffs
369 .iter_mut()
370 .zip(&other.coeffs)
371 .for_each(|(a, b)| {
372 *a += b;
373 });
374 }
375 self.truncate_leading_zeros();
376 }
377}
378
379impl<'a, F: Field> AddAssign<(F, &'a DensePolynomial<F>)> for DensePolynomial<F> {
380 fn add_assign(&mut self, (f, other): (F, &'a DensePolynomial<F>)) {
381 if self.is_zero() {
382 self.coeffs.truncate(0);
383 self.coeffs.extend_from_slice(&other.coeffs);
384 self.coeffs.iter_mut().for_each(|c| *c *= &f);
385 return;
386 } else if other.is_zero() {
387 return;
388 } else if self.degree() >= other.degree() {
389 } else {
390 self.coeffs.resize(other.coeffs.len(), F::zero());
392 }
393 self.coeffs
394 .iter_mut()
395 .zip(&other.coeffs)
396 .for_each(|(a, b)| {
397 *a += &(f * b);
398 });
399 self.truncate_leading_zeros();
403 }
404}
405
406impl<'a, F: Field> AddAssign<&'a SparsePolynomial<F>> for DensePolynomial<F> {
407 #[inline]
408 fn add_assign(&mut self, other: &'a SparsePolynomial<F>) {
409 if self.is_zero() {
410 self.coeffs.truncate(0);
411 self.coeffs.resize(other.degree() + 1, F::zero());
412
413 for (i, coeff) in other.iter() {
414 self.coeffs[*i] = *coeff;
415 }
416 } else if other.is_zero() {
417 } else {
418 let mut upper_coeffs = match other.degree() > self.degree() {
421 true => vec![F::zero(); other.degree() - self.degree()],
422 false => Vec::new(),
423 };
424 for (pow, coeff) in other.iter() {
425 if *pow <= self.degree() {
426 self.coeffs[*pow] += coeff;
427 } else {
428 upper_coeffs[*pow - self.degree() - 1] = *coeff;
429 }
430 }
431 self.coeffs.extend(upper_coeffs);
432 }
433 }
434}
435
436impl<F: Field> Neg for DensePolynomial<F> {
437 type Output = DensePolynomial<F>;
438
439 #[inline]
440 fn neg(mut self) -> DensePolynomial<F> {
441 self.coeffs.iter_mut().for_each(|coeff| {
442 *coeff = -*coeff;
443 });
444 self
445 }
446}
447
448impl<'a, 'b, F: Field> Sub<&'a DensePolynomial<F>> for &'b DensePolynomial<F> {
449 type Output = DensePolynomial<F>;
450
451 #[inline]
452 fn sub(self, other: &'a DensePolynomial<F>) -> DensePolynomial<F> {
453 let mut result = if self.is_zero() {
454 let mut result = other.clone();
455 result.coeffs.iter_mut().for_each(|c| *c = -(*c));
456 result
457 } else if other.is_zero() {
458 self.clone()
459 } else if self.degree() >= other.degree() {
460 let mut result = self.clone();
461 result
462 .coeffs
463 .iter_mut()
464 .zip(&other.coeffs)
465 .for_each(|(a, b)| *a -= b);
466 result
467 } else {
468 let mut result = self.clone();
469 result.coeffs.resize(other.coeffs.len(), F::zero());
470 result
471 .coeffs
472 .iter_mut()
473 .zip(&other.coeffs)
474 .for_each(|(a, b)| *a -= b);
475 result
476 };
477 result.truncate_leading_zeros();
478 result
479 }
480}
481
482impl<'a, 'b, F: Field> Sub<&'a SparsePolynomial<F>> for &'b DensePolynomial<F> {
483 type Output = DensePolynomial<F>;
484
485 #[inline]
486 fn sub(self, other: &'a SparsePolynomial<F>) -> DensePolynomial<F> {
487 if self.is_zero() {
488 let result = other.clone();
489 result.neg().into()
490 } else if other.is_zero() {
491 self.clone()
492 } else {
493 let mut result = self.clone();
494 let mut upper_coeffs = match other.degree() > result.degree() {
497 true => vec![F::zero(); other.degree() - result.degree()],
498 false => Vec::new(),
499 };
500 for (pow, coeff) in other.iter() {
501 if *pow <= result.degree() {
502 result.coeffs[*pow] -= coeff;
503 } else {
504 upper_coeffs[*pow - result.degree() - 1] = -*coeff;
505 }
506 }
507 result.coeffs.extend(upper_coeffs);
508 result
509 }
510 }
511}
512
513impl<'a, F: Field> SubAssign<&'a DensePolynomial<F>> for DensePolynomial<F> {
514 #[inline]
515 fn sub_assign(&mut self, other: &'a DensePolynomial<F>) {
516 if self.is_zero() {
517 self.coeffs.resize(other.coeffs.len(), F::zero());
518 } else if other.is_zero() {
519 return;
520 } else if self.degree() >= other.degree() {
521 } else {
522 self.coeffs.resize(other.coeffs.len(), F::zero());
524 }
525 self.coeffs
526 .iter_mut()
527 .zip(&other.coeffs)
528 .for_each(|(a, b)| {
529 *a -= b;
530 });
531 self.truncate_leading_zeros();
535 }
536}
537
538impl<'a, F: Field> SubAssign<&'a SparsePolynomial<F>> for DensePolynomial<F> {
539 #[inline]
540 fn sub_assign(&mut self, other: &'a SparsePolynomial<F>) {
541 if self.is_zero() {
542 self.coeffs.truncate(0);
543 self.coeffs.resize(other.degree() + 1, F::zero());
544
545 for (i, coeff) in other.iter() {
546 self.coeffs[*i] = (*coeff).neg();
547 }
548 } else if other.is_zero() {
549 } else {
550 let mut upper_coeffs = match other.degree() > self.degree() {
553 true => vec![F::zero(); other.degree() - self.degree()],
554 false => Vec::new(),
555 };
556 for (pow, coeff) in other.iter() {
557 if *pow <= self.degree() {
558 self.coeffs[*pow] -= coeff;
559 } else {
560 upper_coeffs[*pow - self.degree() - 1] = -*coeff;
561 }
562 }
563 self.coeffs.extend(upper_coeffs);
564 }
565 }
566}
567
568impl<'a, 'b, F: Field> Div<&'a DensePolynomial<F>> for &'b DensePolynomial<F> {
569 type Output = DensePolynomial<F>;
570
571 #[inline]
572 fn div(self, divisor: &'a DensePolynomial<F>) -> DensePolynomial<F> {
573 let a = DenseOrSparsePolynomial::from(self);
574 let b = DenseOrSparsePolynomial::from(divisor);
575 a.divide_with_q_and_r(&b).expect("division failed").0
576 }
577}
578
579impl<'b, F: Field> Mul<F> for &'b DensePolynomial<F> {
580 type Output = DensePolynomial<F>;
581
582 #[inline]
583 fn mul(self, elem: F) -> DensePolynomial<F> {
584 if self.is_zero() || elem.is_zero() {
585 DensePolynomial::zero()
586 } else {
587 let mut result = self.clone();
588 cfg_iter_mut!(result).for_each(|e| {
589 *e *= elem;
590 });
591 result
592 }
593 }
594}
595
596impl<F: Field> Mul<F> for DensePolynomial<F> {
597 type Output = DensePolynomial<F>;
598
599 #[inline]
600 fn mul(self, elem: F) -> DensePolynomial<F> {
601 &self * elem
602 }
603}
604
605impl<'a, 'b, F: FftField> Mul<&'a DensePolynomial<F>> for &'b DensePolynomial<F> {
607 type Output = DensePolynomial<F>;
608
609 #[inline]
610 fn mul(self, other: &'a DensePolynomial<F>) -> DensePolynomial<F> {
611 if self.is_zero() || other.is_zero() {
612 DensePolynomial::zero()
613 } else {
614 let domain = GeneralEvaluationDomain::new(self.coeffs.len() + other.coeffs.len() - 1)
615 .expect("field is not smooth enough to construct domain");
616 let mut self_evals = self.evaluate_over_domain_by_ref(domain);
617 let other_evals = other.evaluate_over_domain_by_ref(domain);
618 self_evals *= &other_evals;
619 self_evals.interpolate()
620 }
621 }
622}
623
624macro_rules! impl_op {
625 ($trait:ident, $method:ident, $field_bound:ident) => {
626 impl<F: $field_bound> $trait<DensePolynomial<F>> for DensePolynomial<F> {
627 type Output = DensePolynomial<F>;
628
629 #[inline]
630 fn $method(self, other: DensePolynomial<F>) -> DensePolynomial<F> {
631 (&self).$method(&other)
632 }
633 }
634
635 impl<'a, F: $field_bound> $trait<&'a DensePolynomial<F>> for DensePolynomial<F> {
636 type Output = DensePolynomial<F>;
637
638 #[inline]
639 fn $method(self, other: &'a DensePolynomial<F>) -> DensePolynomial<F> {
640 (&self).$method(other)
641 }
642 }
643
644 impl<'a, F: $field_bound> $trait<DensePolynomial<F>> for &'a DensePolynomial<F> {
645 type Output = DensePolynomial<F>;
646
647 #[inline]
648 fn $method(self, other: DensePolynomial<F>) -> DensePolynomial<F> {
649 self.$method(&other)
650 }
651 }
652 };
653}
654
655impl<F: Field> Zero for DensePolynomial<F> {
656 fn zero() -> Self {
658 Self { coeffs: Vec::new() }
659 }
660
661 fn is_zero(&self) -> bool {
663 self.coeffs.is_empty() || self.coeffs.iter().all(|coeff| coeff.is_zero())
664 }
665}
666
667impl_op!(Add, add, Field);
668impl_op!(Sub, sub, Field);
669impl_op!(Mul, mul, FftField);
670impl_op!(Div, div, Field);
671
672#[cfg(test)]
673mod tests {
674 use crate::{polynomial::univariate::*, GeneralEvaluationDomain};
675 use ark_ff::{Fp64, MontBackend, MontConfig};
676 use ark_ff::{One, UniformRand};
677 use ark_std::{rand::Rng, test_rng};
678 use ark_test_curves::bls12_381::Fr;
679
680 fn rand_sparse_poly<R: Rng>(degree: usize, rng: &mut R) -> SparsePolynomial<Fr> {
681 let mut coeffs = vec![(degree, Fr::rand(rng))];
683 for i in 0..degree {
684 if !rng.gen_bool(0.8) {
685 coeffs.push((i, Fr::rand(rng)));
686 }
687 }
688 SparsePolynomial::from_coefficients_vec(coeffs)
689 }
690
691 #[test]
692 fn rand_dense_poly_degree() {
693 #[derive(MontConfig)]
694 #[modulus = "5"]
695 #[generator = "2"]
696 pub struct F5Config;
697
698 let rng = &mut test_rng();
699 pub type F5 = Fp64<MontBackend<F5Config, 1>>;
700
701 for i in 1..=30 {
704 assert_eq!(DensePolynomial::<F5>::rand(i, rng).degree(), i);
705 }
706 }
707
708 #[test]
709 fn double_polynomials_random() {
710 let rng = &mut test_rng();
711 for degree in 0..70 {
712 let p = DensePolynomial::<Fr>::rand(degree, rng);
713 let p_double = &p + &p;
714 let p_quad = &p_double + &p_double;
715 assert_eq!(&(&(&p + &p) + &p) + &p, p_quad);
716 }
717 }
718
719 #[test]
720 fn add_polynomials() {
721 let rng = &mut test_rng();
722 for a_degree in 0..70 {
723 for b_degree in 0..70 {
724 let p1 = DensePolynomial::<Fr>::rand(a_degree, rng);
725 let p2 = DensePolynomial::<Fr>::rand(b_degree, rng);
726 let res1 = &p1 + &p2;
727 let res2 = &p2 + &p1;
728 assert_eq!(res1, res2);
729 }
730 }
731 }
732
733 #[test]
734 fn add_sparse_polynomials() {
735 let rng = &mut test_rng();
736 for a_degree in 0..70 {
737 for b_degree in 0..70 {
738 let p1 = DensePolynomial::<Fr>::rand(a_degree, rng);
739 let p2 = rand_sparse_poly(b_degree, rng);
740 let res = &p1 + &p2;
741 assert_eq!(res, &p1 + &Into::<DensePolynomial<Fr>>::into(p2));
742 }
743 }
744 }
745
746 #[test]
747 fn add_assign_sparse_polynomials() {
748 let rng = &mut test_rng();
749 for a_degree in 0..70 {
750 for b_degree in 0..70 {
751 let p1 = DensePolynomial::<Fr>::rand(a_degree, rng);
752 let p2 = rand_sparse_poly(b_degree, rng);
753
754 let mut res = p1.clone();
755 res += &p2;
756 assert_eq!(res, &p1 + &Into::<DensePolynomial<Fr>>::into(p2));
757 }
758 }
759 }
760
761 #[test]
762 fn add_polynomials_with_mul() {
763 let rng = &mut test_rng();
764 for a_degree in 0..70 {
765 for b_degree in 0..70 {
766 let mut p1 = DensePolynomial::rand(a_degree, rng);
767 let p2 = DensePolynomial::rand(b_degree, rng);
768 let f = Fr::rand(rng);
769 let f_p2 = DensePolynomial::from_coefficients_vec(
770 p2.coeffs.iter().map(|c| f * c).collect(),
771 );
772 let res2 = &f_p2 + &p1;
773 p1 += (f, &p2);
774 let res1 = p1;
775 assert_eq!(res1, res2);
776 }
777 }
778 }
779
780 #[test]
781 fn sub_polynomials() {
782 let rng = &mut test_rng();
783 for a_degree in 0..70 {
784 for b_degree in 0..70 {
785 let p1 = DensePolynomial::<Fr>::rand(a_degree, rng);
786 let p2 = DensePolynomial::<Fr>::rand(b_degree, rng);
787 let res1 = &p1 - &p2;
788 let res2 = &p2 - &p1;
789 assert_eq!(&res1 + &p2, p1);
790 assert_eq!(res1, -res2);
791 }
792 }
793 }
794
795 #[test]
796 fn sub_sparse_polynomials() {
797 let rng = &mut test_rng();
798 for a_degree in 0..70 {
799 for b_degree in 0..70 {
800 let p1 = DensePolynomial::<Fr>::rand(a_degree, rng);
801 let p2 = rand_sparse_poly(b_degree, rng);
802 let res = &p1 - &p2;
803 assert_eq!(res, &p1 - &Into::<DensePolynomial<Fr>>::into(p2));
804 }
805 }
806 }
807
808 #[test]
809 fn sub_assign_sparse_polynomials() {
810 let rng = &mut test_rng();
811 for a_degree in 0..70 {
812 for b_degree in 0..70 {
813 let p1 = DensePolynomial::<Fr>::rand(a_degree, rng);
814 let p2 = rand_sparse_poly(b_degree, rng);
815
816 let mut res = p1.clone();
817 res -= &p2;
818 assert_eq!(res, &p1 - &Into::<DensePolynomial<Fr>>::into(p2));
819 }
820 }
821 }
822
823 #[test]
824 fn polynomial_additive_identity() {
825 let mut rng = test_rng();
827 for degree in 0..70 {
828 let poly = DensePolynomial::<Fr>::rand(degree, &mut rng);
829 let neg = -poly.clone();
830 let result = poly + neg;
831 assert!(result.is_zero());
832 assert_eq!(result.degree(), 0);
833
834 let poly = DensePolynomial::<Fr>::rand(degree, &mut rng);
836 let mut result = poly.clone();
837 result -= &poly;
838 assert!(result.is_zero());
839 assert_eq!(result.degree(), 0);
840 }
841 }
842
843 #[test]
844 fn divide_polynomials_fixed() {
845 let dividend = DensePolynomial::from_coefficients_slice(&[
846 "4".parse().unwrap(),
847 "8".parse().unwrap(),
848 "5".parse().unwrap(),
849 "1".parse().unwrap(),
850 ]);
851 let divisor = DensePolynomial::from_coefficients_slice(&[Fr::one(), Fr::one()]); let result = ÷nd / &divisor;
853 let expected_result = DensePolynomial::from_coefficients_slice(&[
854 "4".parse().unwrap(),
855 "4".parse().unwrap(),
856 "1".parse().unwrap(),
857 ]);
858 assert_eq!(expected_result, result);
859 }
860
861 #[test]
862 fn divide_polynomials_random() {
863 let rng = &mut test_rng();
864
865 for a_degree in 0..50 {
866 for b_degree in 0..50 {
867 let dividend = DensePolynomial::<Fr>::rand(a_degree, rng);
868 let divisor = DensePolynomial::<Fr>::rand(b_degree, rng);
869 if let Some((quotient, remainder)) = DenseOrSparsePolynomial::divide_with_q_and_r(
870 &(÷nd).into(),
871 &(&divisor).into(),
872 ) {
873 assert_eq!(dividend, &(&divisor * "ient) + &remainder)
874 }
875 }
876 }
877 }
878
879 #[test]
880 fn evaluate_polynomials() {
881 let rng = &mut test_rng();
882 for a_degree in 0..70 {
883 let p = DensePolynomial::rand(a_degree, rng);
884 let point: Fr = Fr::rand(rng);
885 let mut total = Fr::zero();
886 for (i, coeff) in p.coeffs.iter().enumerate() {
887 total += &(point.pow(&[i as u64]) * coeff);
888 }
889 assert_eq!(p.evaluate(&point), total);
890 }
891 }
892
893 #[test]
894 fn mul_random_element() {
895 let rng = &mut test_rng();
896 for degree in 0..70 {
897 let a = DensePolynomial::<Fr>::rand(degree, rng);
898 let e = Fr::rand(rng);
899 assert_eq!(
900 &a * e,
901 a.naive_mul(&DensePolynomial::from_coefficients_slice(&[e]))
902 )
903 }
904 }
905
906 #[test]
907 fn mul_polynomials_random() {
908 let rng = &mut test_rng();
909 for a_degree in 0..70 {
910 for b_degree in 0..70 {
911 let a = DensePolynomial::<Fr>::rand(a_degree, rng);
912 let b = DensePolynomial::<Fr>::rand(b_degree, rng);
913 assert_eq!(&a * &b, a.naive_mul(&b))
914 }
915 }
916 }
917
918 #[test]
919 fn mul_by_vanishing_poly() {
920 let rng = &mut test_rng();
921 for size in 1..10 {
922 let domain = GeneralEvaluationDomain::new(1 << size).unwrap();
923 for degree in 0..70 {
924 let p = DensePolynomial::<Fr>::rand(degree, rng);
925 let ans1 = p.mul_by_vanishing_poly(domain);
926 let ans2 = &p * &domain.vanishing_polynomial().into();
927 assert_eq!(ans1, ans2);
928 }
929 }
930 }
931
932 #[test]
933 fn divide_by_vanishing_poly() {
934 let rng = &mut test_rng();
935 for size in 1..10 {
936 let domain = GeneralEvaluationDomain::new(1 << size).unwrap();
937 for degree in 0..12 {
938 let p = DensePolynomial::<Fr>::rand(degree * 100, rng);
939 let (quotient, remainder) = p.divide_by_vanishing_poly(domain);
940 let p_recovered = quotient.mul_by_vanishing_poly(domain) + remainder;
941 assert_eq!(p, p_recovered);
942 }
943 }
944 }
945
946 #[test]
947 fn test_leading_zero() {
948 let n = 10;
949 let rand_poly = DensePolynomial::rand(n, &mut test_rng());
950 let coefficients = rand_poly.coeffs.clone();
951 let leading_coefficient: Fr = coefficients[n];
952
953 let negative_leading_coefficient = -leading_coefficient;
954 let inverse_leading_coefficient = leading_coefficient.inverse().unwrap();
955
956 let mut inverse_coefficients = coefficients.clone();
957 inverse_coefficients[n] = inverse_leading_coefficient;
958
959 let mut negative_coefficients = coefficients;
960 negative_coefficients[n] = negative_leading_coefficient;
961
962 let negative_poly = DensePolynomial::from_coefficients_vec(negative_coefficients);
963 let inverse_poly = DensePolynomial::from_coefficients_vec(inverse_coefficients);
964
965 let x = &inverse_poly * &rand_poly;
966 assert_eq!(x.degree(), 2 * n);
967 assert!(!x.coeffs.last().unwrap().is_zero());
968
969 let y = &negative_poly + &rand_poly;
970 assert_eq!(y.degree(), n - 1);
971 assert!(!y.coeffs.last().unwrap().is_zero());
972 }
973
974 #[test]
975 fn evaluate_over_domain_test() {
976 let rng = &mut ark_std::test_rng();
977 let domain = crate::domain::Radix2EvaluationDomain::<Fr>::new(1 << 10).unwrap();
978 let offset = Fr::GENERATOR;
979 let coset = domain.get_coset(offset).unwrap();
980 for _ in 0..100 {
981 let poly = DensePolynomial::<Fr>::rand(1 << 11, rng);
982 let evaluations = domain
983 .elements()
984 .map(|e| poly.evaluate(&e))
985 .collect::<Vec<_>>();
986 assert_eq!(evaluations, poly.evaluate_over_domain_by_ref(domain).evals);
987 let evaluations = coset
988 .elements()
989 .map(|e| poly.evaluate(&e))
990 .collect::<Vec<_>>();
991 assert_eq!(evaluations, poly.evaluate_over_domain(coset).evals);
992 }
993 let zero = DensePolynomial::zero();
994 let evaluations = domain
995 .elements()
996 .map(|e| zero.evaluate(&e))
997 .collect::<Vec<_>>();
998 assert_eq!(evaluations, zero.evaluate_over_domain(domain).evals);
999 }
1000
1001 use crate::Radix2EvaluationDomain;
1002
1003 #[test]
1004 fn evaluate_over_domain_regression_test() {
1005 #[derive(MontConfig)]
1007 #[modulus = "18446744069414584321"]
1008 #[generator = "7"]
1009 struct FrConfig64;
1010 type F = Fp64<MontBackend<FrConfig64, 1>>;
1011
1012 let degree = 17;
1013 let eval_domain_size = 16;
1014
1015 let poly = DensePolynomial::from_coefficients_vec(vec![F::ONE; degree]);
1016 let domain = Radix2EvaluationDomain::new(eval_domain_size).unwrap();
1017
1018 let offset = F::from(42u64);
1020 let domain = domain.get_coset(offset).unwrap();
1021
1022 let query_points: Vec<_> = domain.elements().collect();
1024
1025 let eval1 = poly.evaluate_over_domain_by_ref(domain).evals;
1026 let eval2 = query_points
1027 .iter()
1028 .map(|x| poly.evaluate(x))
1029 .collect::<Vec<_>>();
1030
1031 assert_eq!(eval1, eval2);
1032 }
1033}