From 7c59842af9ad4c891815546d8bb9ff99e5060d07 Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Tue, 26 Nov 2024 17:58:15 +0100 Subject: [PATCH 1/4] poly: truncate leading zeros for poly add --- poly/src/lib.rs | 2 +- poly/src/polynomial/univariate/dense.rs | 75 ++++++++++++++++++------- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/poly/src/lib.rs b/poly/src/lib.rs index 327134689..236455ac1 100644 --- a/poly/src/lib.rs +++ b/poly/src/lib.rs @@ -1,6 +1,6 @@ //! This crate implements functions for manipulating polynomials over finite //! fields, including FFTs. -#![cfg_attr(not(feature = "std"), no_std)] +// #![cfg_attr(not(feature = "std"), no_std)] #![warn( unused, future_incompatible, diff --git a/poly/src/polynomial/univariate/dense.rs b/poly/src/polynomial/univariate/dense.rs index bbd57cc29..0bb624f9c 100644 --- a/poly/src/polynomial/univariate/dense.rs +++ b/poly/src/polynomial/univariate/dense.rs @@ -321,28 +321,42 @@ impl<'a, F: Field> Add<&'a SparsePolynomial> for &DensePolynomial { #[inline] fn add(self, other: &'a SparsePolynomial) -> DensePolynomial { + // If `self` is zero, the result is `other` (as adding zero doesn't change anything). if self.is_zero() { - other.clone().into() - } else if other.is_zero() { - self.clone() - } else { - let mut result = self.clone(); - // If `other` has higher degree than `self`, create a dense vector - // storing the upper coefficients of the addition - let mut upper_coeffs = match other.degree() > result.degree() { - true => vec![F::zero(); other.degree() - result.degree()], - false => Vec::new(), - }; - for (pow, coeff) in other.iter() { - if *pow <= result.degree() { - result.coeffs[*pow] += coeff; - } else { - upper_coeffs[*pow - result.degree() - 1] = *coeff; - } + return other.clone().into(); + } + + // If `other` is zero, the result is `self` (as adding zero doesn't change anything). + if other.is_zero() { + return self.clone(); + } + + let mut result = self.clone(); + + // Prepare a vector to store the coefficients of the upper terms of the addition. + let mut upper_coeffs = vec![F::zero(); other.degree().saturating_sub(result.degree())]; + + // Iterate over the sparse polynomial's non-zero terms. + for (pow, coeff) in other.iter() { + // If the power `pow` is within the degree of `result`, add the coefficient to the corresponding term. + if let Some(target) = result.coeffs.get_mut(*pow) { + *target += coeff; + } else { + // Otherwise, store the coefficient in the `upper_coeffs` vector at the appropriate position. + // + // The index is adjusted by subtracting the current length of `result.coeffs`. + upper_coeffs[pow - result.coeffs.len()] = *coeff; } - result.coeffs.extend(upper_coeffs); - result } + + // Extend the coefficient vector of `result` with the upper terms. + result.coeffs.extend(upper_coeffs); + + // Remove any trailing zeros from the coefficient vector to ensure it represents the correct polynomial. + // For example: `0 * x^2 + 0 * x + 1` should be represented as `1`. + result.truncate_leading_zeros(); + + result } } @@ -1282,4 +1296,27 @@ mod tests { assert!(poly1.is_zero()); assert_eq!(poly1.coeffs, vec![]); } + + #[test] + fn test_truncate_leading_zeros_after_sparse_addition() { + // Create a DensePolynomial with leading non-zero coefficients. + let poly1 = DensePolynomial { + coeffs: vec![Fr::from(3), Fr::from(2), Fr::from(1)], + }; + + // Create a SparsePolynomial to subtract the coefficients of poly1, + // leaving trailing zeros after addition. + let poly2 = SparsePolynomial::from_coefficients_slice(&[ + (0, -Fr::from(3)), + (1, -Fr::from(2)), + (2, -Fr::from(1)), + ]); + + // Perform addition using the Add implementation. + let result = &poly1 + &poly2; + + // Assert that the resulting polynomial is zero. + assert!(result.is_zero(), "The resulting polynomial should be zero."); + assert_eq!(result.coeffs, vec![], "Leading zeros were not truncated."); + } } From 446bbfe3976a90d4b77d7dac8286647a69020df9 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:58:51 +0100 Subject: [PATCH 2/4] Update poly/src/lib.rs --- poly/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poly/src/lib.rs b/poly/src/lib.rs index 236455ac1..327134689 100644 --- a/poly/src/lib.rs +++ b/poly/src/lib.rs @@ -1,6 +1,6 @@ //! This crate implements functions for manipulating polynomials over finite //! fields, including FFTs. -// #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), no_std)] #![warn( unused, future_incompatible, From 46fcb94f51a033d313ec170fb22ddb6f4ad7c23f Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Tue, 26 Nov 2024 17:59:51 +0100 Subject: [PATCH 3/4] clean up doc --- poly/src/polynomial/univariate/dense.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/poly/src/polynomial/univariate/dense.rs b/poly/src/polynomial/univariate/dense.rs index 0bb624f9c..28c81f103 100644 --- a/poly/src/polynomial/univariate/dense.rs +++ b/poly/src/polynomial/univariate/dense.rs @@ -321,30 +321,24 @@ impl<'a, F: Field> Add<&'a SparsePolynomial> for &DensePolynomial { #[inline] fn add(self, other: &'a SparsePolynomial) -> DensePolynomial { - // If `self` is zero, the result is `other` (as adding zero doesn't change anything). if self.is_zero() { return other.clone().into(); } - // If `other` is zero, the result is `self` (as adding zero doesn't change anything). if other.is_zero() { return self.clone(); } let mut result = self.clone(); - // Prepare a vector to store the coefficients of the upper terms of the addition. + // If `other` has higher degree than `self`, create a dense vector + // storing the upper coefficients of the addition let mut upper_coeffs = vec![F::zero(); other.degree().saturating_sub(result.degree())]; - // Iterate over the sparse polynomial's non-zero terms. for (pow, coeff) in other.iter() { - // If the power `pow` is within the degree of `result`, add the coefficient to the corresponding term. if let Some(target) = result.coeffs.get_mut(*pow) { *target += coeff; } else { - // Otherwise, store the coefficient in the `upper_coeffs` vector at the appropriate position. - // - // The index is adjusted by subtracting the current length of `result.coeffs`. upper_coeffs[pow - result.coeffs.len()] = *coeff; } } @@ -352,7 +346,7 @@ impl<'a, F: Field> Add<&'a SparsePolynomial> for &DensePolynomial { // Extend the coefficient vector of `result` with the upper terms. result.coeffs.extend(upper_coeffs); - // Remove any trailing zeros from the coefficient vector to ensure it represents the correct polynomial. + // Remove any leading zeros. // For example: `0 * x^2 + 0 * x + 1` should be represented as `1`. result.truncate_leading_zeros(); From 1b1ae74cbd77a798cc8b75e515e73dc49889f739 Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Tue, 26 Nov 2024 18:17:23 +0100 Subject: [PATCH 4/4] fix comment --- poly/src/polynomial/univariate/dense.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/poly/src/polynomial/univariate/dense.rs b/poly/src/polynomial/univariate/dense.rs index 28c81f103..162ae3fac 100644 --- a/poly/src/polynomial/univariate/dense.rs +++ b/poly/src/polynomial/univariate/dense.rs @@ -331,21 +331,23 @@ impl<'a, F: Field> Add<&'a SparsePolynomial> for &DensePolynomial { let mut result = self.clone(); - // If `other` has higher degree than `self`, create a dense vector - // storing the upper coefficients of the addition - let mut upper_coeffs = vec![F::zero(); other.degree().saturating_sub(result.degree())]; + // Reserve space for additional coefficients if `other` has a higher degree. + let additional_len = other.degree().saturating_sub(result.degree()); + result.coeffs.reserve(additional_len); + // Process each term in `other`. for (pow, coeff) in other.iter() { if let Some(target) = result.coeffs.get_mut(*pow) { *target += coeff; } else { - upper_coeffs[pow - result.coeffs.len()] = *coeff; + // Extend with zeros if the power exceeds the current length. + result + .coeffs + .extend(ark_std::iter::repeat(F::zero()).take(pow - result.coeffs.len())); + result.coeffs.push(*coeff); } } - // Extend the coefficient vector of `result` with the upper terms. - result.coeffs.extend(upper_coeffs); - // Remove any leading zeros. // For example: `0 * x^2 + 0 * x + 1` should be represented as `1`. result.truncate_leading_zeros();