@@ -57,7 +57,7 @@ impl<F: Field> Polynomial<F> for SparsePolynomial<F, SparseTerm> {
57
57
. iter ( )
58
58
. map ( |( _, term) | term. degree ( ) )
59
59
. max ( )
60
- . unwrap_or ( 0 )
60
+ . unwrap_or_default ( )
61
61
}
62
62
63
63
/// Evaluates `self` at the given `point` in `Self::Point`.
@@ -136,19 +136,22 @@ impl<F: Field> DenseMVPolynomial<F> for SparsePolynomial<F, SparseTerm> {
136
136
terms. sort_by ( |( _, t1) , ( _, t2) | t1. cmp ( t2) ) ;
137
137
// If any terms are duplicated, add them together
138
138
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 {
146
140
// Assert correct number of indeterminates
147
141
assert ! (
148
- term. 1 . iter( ) . all( |( var, _) | * var < num_vars) ,
142
+ term. iter( ) . all( |( var, _) | * var < num_vars) ,
149
143
"Invalid number of indeterminates"
150
144
) ;
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) ) ;
152
155
}
153
156
let mut result = Self {
154
157
num_vars,
@@ -278,10 +281,7 @@ impl<F: Field, T: Term> fmt::Debug for SparsePolynomial<F, T> {
278
281
impl < F : Field , T : Term > Zero for SparsePolynomial < F , T > {
279
282
/// Returns the zero polynomial.
280
283
fn zero ( ) -> Self {
281
- Self {
282
- num_vars : 0 ,
283
- terms : Vec :: new ( ) ,
284
- }
284
+ Self :: default ( )
285
285
}
286
286
287
287
/// Checks if the given polynomial is zero.
@@ -464,4 +464,105 @@ mod tests {
464
464
) ;
465
465
assert_eq ! ( expected, result) ;
466
466
}
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
+ }
467
568
}
0 commit comments