Skip to content

Commit b6dc180

Browse files
authored
poly: small refactor and unit tests for SparsePolynomial (#868)
* poly: small refactor and unit tests for SparsePolynomial * Update poly/src/lib.rs
1 parent 6af88cb commit b6dc180

File tree

1 file changed

+115
-14
lines changed

1 file changed

+115
-14
lines changed

poly/src/polynomial/multivariate/sparse.rs

Lines changed: 115 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl<F: Field> Polynomial<F> for SparsePolynomial<F, SparseTerm> {
5757
.iter()
5858
.map(|(_, term)| term.degree())
5959
.max()
60-
.unwrap_or(0)
60+
.unwrap_or_default()
6161
}
6262

6363
/// Evaluates `self` at the given `point` in `Self::Point`.
@@ -136,19 +136,22 @@ impl<F: Field> DenseMVPolynomial<F> for SparsePolynomial<F, SparseTerm> {
136136
terms.sort_by(|(_, t1), (_, t2)| t1.cmp(t2));
137137
// If any terms are duplicated, add them together
138138
let mut terms_dedup: Vec<(F, SparseTerm)> = Vec::new();
139-
for term in terms {
140-
if let Some(prev) = terms_dedup.last_mut() {
141-
if prev.1 == term.1 {
142-
*prev = (prev.0 + term.0, prev.1.clone());
143-
continue;
144-
}
145-
};
139+
for (coeff, term) in terms {
146140
// Assert correct number of indeterminates
147141
assert!(
148-
term.1.iter().all(|(var, _)| *var < num_vars),
142+
term.iter().all(|(var, _)| *var < num_vars),
149143
"Invalid number of indeterminates"
150144
);
151-
terms_dedup.push(term);
145+
146+
if let Some((prev_coeff, prev_term)) = terms_dedup.last_mut() {
147+
// If terms match, add the coefficients.
148+
if prev_term == &term {
149+
*prev_coeff += coeff;
150+
continue;
151+
}
152+
}
153+
154+
terms_dedup.push((coeff, term));
152155
}
153156
let mut result = Self {
154157
num_vars,
@@ -278,10 +281,7 @@ impl<F: Field, T: Term> fmt::Debug for SparsePolynomial<F, T> {
278281
impl<F: Field, T: Term> Zero for SparsePolynomial<F, T> {
279282
/// Returns the zero polynomial.
280283
fn zero() -> Self {
281-
Self {
282-
num_vars: 0,
283-
terms: Vec::new(),
284-
}
284+
Self::default()
285285
}
286286

287287
/// Checks if the given polynomial is zero.
@@ -464,4 +464,105 @@ mod tests {
464464
);
465465
assert_eq!(expected, result);
466466
}
467+
468+
#[test]
469+
fn test_polynomial_with_zero_coefficients() {
470+
let rng = &mut test_rng();
471+
let max_degree = 10;
472+
let p1 = rand_poly(3, max_degree, rng);
473+
474+
let p2 = SparsePolynomial::from_coefficients_vec(
475+
3,
476+
vec![
477+
(Fr::zero(), SparseTerm::new(vec![(0, 1)])), // A zero coefficient term
478+
(Fr::from(2), SparseTerm::new(vec![(1, 1)])),
479+
],
480+
);
481+
482+
let sum = &p1 + &p2;
483+
484+
// Ensure that the zero coefficient term is ignored in the evaluation.
485+
let point = vec![Fr::from(1), Fr::from(2), Fr::from(3)];
486+
let result = sum.evaluate(&point);
487+
488+
assert_eq!(result, p1.evaluate(&point) + p2.evaluate(&point)); // Should be the sum of the evaluations
489+
}
490+
491+
#[test]
492+
fn test_constant_polynomial() {
493+
let constant_term = SparsePolynomial::from_coefficients_vec(
494+
3,
495+
vec![(Fr::from(5), SparseTerm::new(vec![]))],
496+
);
497+
498+
let point = vec![Fr::from(1), Fr::from(2), Fr::from(3)];
499+
assert_eq!(constant_term.evaluate(&point), Fr::from(5));
500+
}
501+
502+
#[test]
503+
fn test_polynomial_addition_with_overlapping_terms() {
504+
let poly1 = SparsePolynomial::from_coefficients_vec(
505+
3,
506+
vec![
507+
(Fr::from(2), SparseTerm::new(vec![(0, 1)])),
508+
(Fr::from(3), SparseTerm::new(vec![(1, 1)])),
509+
],
510+
);
511+
512+
let poly2 = SparsePolynomial::from_coefficients_vec(
513+
3,
514+
vec![
515+
(Fr::from(4), SparseTerm::new(vec![(0, 1)])),
516+
(Fr::from(1), SparseTerm::new(vec![(2, 1)])),
517+
],
518+
);
519+
520+
let expected = SparsePolynomial::from_coefficients_vec(
521+
3,
522+
vec![
523+
(Fr::from(6), SparseTerm::new(vec![(0, 1)])),
524+
(Fr::from(3), SparseTerm::new(vec![(1, 1)])),
525+
(Fr::from(1), SparseTerm::new(vec![(2, 1)])),
526+
],
527+
);
528+
529+
let result = &poly1 + &poly2;
530+
531+
assert_eq!(expected, result);
532+
}
533+
534+
#[test]
535+
fn test_polynomial_degree() {
536+
// Polynomial: 2*x_0^3 + x_1*x_2
537+
let poly1 = SparsePolynomial::<Fr, SparseTerm>::from_coefficients_vec(
538+
3,
539+
vec![
540+
(Fr::from(2), SparseTerm::new(vec![(0, 3)])), // term with degree 3
541+
(Fr::from(1), SparseTerm::new(vec![(1, 1), (2, 1)])), // term with degree 2
542+
],
543+
);
544+
545+
// Polynomial: x_0^2 + x_1^2 + 1
546+
let poly2 = SparsePolynomial::<Fr, SparseTerm>::from_coefficients_vec(
547+
3,
548+
vec![
549+
(Fr::from(1), SparseTerm::new(vec![(0, 2)])), // term with degree 2
550+
(Fr::from(1), SparseTerm::new(vec![(1, 2)])), // term with degree 2
551+
(Fr::from(1), SparseTerm::new(vec![])), // constant term (degree 0)
552+
],
553+
);
554+
555+
// Polynomial: 3
556+
let poly3 = SparsePolynomial::<Fr, SparseTerm>::from_coefficients_vec(
557+
3,
558+
vec![
559+
(Fr::from(3), SparseTerm::new(vec![])), // constant term (degree 0)
560+
],
561+
);
562+
563+
// Test the degree method
564+
assert_eq!(poly1.degree(), 3, "Degree of poly1 should be 3");
565+
assert_eq!(poly2.degree(), 2, "Degree of poly2 should be 2");
566+
assert_eq!(poly3.degree(), 0, "Degree of poly3 should be 0");
567+
}
467568
}

0 commit comments

Comments
 (0)