1use p3_field::{Algebra, ExtensionField, Field, InjectiveMonomial};
2
3use crate::symbolic::variable::SymbolicVariable;
4use crate::symbolic::{SymLeaf, SymbolicExpr};
5
6#[derive(Clone, Debug)]
11pub enum BaseLeaf<F> {
12 Variable(SymbolicVariable<F>),
14
15 IsFirstRow,
17
18 IsLastRow,
20
21 IsTransition,
23
24 Constant(F),
26}
27
28pub type SymbolicExpression<F> = SymbolicExpr<BaseLeaf<F>>;
33
34impl<F: Field> SymLeaf for BaseLeaf<F> {
35 type F = F;
36
37 const ZERO: Self = Self::Constant(F::ZERO);
38 const ONE: Self = Self::Constant(F::ONE);
39 const TWO: Self = Self::Constant(F::TWO);
40 const NEG_ONE: Self = Self::Constant(F::NEG_ONE);
41
42 fn degree_multiple(&self) -> usize {
43 match self {
44 Self::Variable(v) => v.degree_multiple(),
45 Self::IsFirstRow | Self::IsLastRow => 1,
46 Self::IsTransition | Self::Constant(_) => 0,
47 }
48 }
49
50 fn as_const(&self) -> Option<&F> {
51 match self {
52 Self::Constant(c) => Some(c),
53 _ => None,
54 }
55 }
56
57 fn from_const(c: F) -> Self {
58 Self::Constant(c)
59 }
60}
61
62impl<F: Field, EF: ExtensionField<F>> From<SymbolicVariable<F>> for SymbolicExpression<EF> {
63 fn from(var: SymbolicVariable<F>) -> Self {
64 Self::Leaf(BaseLeaf::Variable(SymbolicVariable::new(
65 var.entry, var.index,
66 )))
67 }
68}
69
70impl<F: Field, EF: ExtensionField<F>> From<F> for SymbolicExpression<EF> {
71 fn from(f: F) -> Self {
72 Self::Leaf(BaseLeaf::Constant(f.into()))
73 }
74}
75
76impl<F: Field> Algebra<F> for SymbolicExpression<F> {}
77
78impl<F: Field> Algebra<SymbolicVariable<F>> for SymbolicExpression<F> {}
79
80impl<F: Field + InjectiveMonomial<N>, const N: u64> InjectiveMonomial<N> for SymbolicExpression<F> {}
83
84#[cfg(test)]
85mod tests {
86 use alloc::sync::Arc;
87 use alloc::vec;
88 use alloc::vec::Vec;
89
90 use p3_baby_bear::BabyBear;
91 use p3_field::PrimeCharacteristicRing;
92
93 use super::*;
94 use crate::symbolic::BaseEntry;
95
96 #[test]
97 fn test_symbolic_expression_degree_multiple() {
98 let constant_expr =
99 SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::Constant(BabyBear::new(5)));
100 assert_eq!(
101 constant_expr.degree_multiple(),
102 0,
103 "Constant should have degree 0"
104 );
105
106 let variable_expr = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::new(
107 BaseEntry::Main { offset: 0 },
108 1,
109 )));
110 assert_eq!(
111 variable_expr.degree_multiple(),
112 1,
113 "Main variable should have degree 1"
114 );
115
116 let preprocessed_var = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::new(
117 BaseEntry::Preprocessed { offset: 0 },
118 2,
119 )));
120 assert_eq!(
121 preprocessed_var.degree_multiple(),
122 1,
123 "Preprocessed variable should have degree 1"
124 );
125
126 let public_var = SymbolicExpression::Leaf(BaseLeaf::Variable(
127 SymbolicVariable::<BabyBear>::new(BaseEntry::Public, 4),
128 ));
129 assert_eq!(
130 public_var.degree_multiple(),
131 0,
132 "Public variable should have degree 0"
133 );
134
135 let is_first_row = SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::IsFirstRow);
136 assert_eq!(
137 is_first_row.degree_multiple(),
138 1,
139 "IsFirstRow should have degree 1"
140 );
141
142 let is_last_row = SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::IsLastRow);
143 assert_eq!(
144 is_last_row.degree_multiple(),
145 1,
146 "IsLastRow should have degree 1"
147 );
148
149 let is_transition = SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::IsTransition);
150 assert_eq!(
151 is_transition.degree_multiple(),
152 0,
153 "IsTransition should have degree 0"
154 );
155
156 let add_expr = SymbolicExpr::<BaseLeaf<BabyBear>>::Add {
157 x: Arc::new(variable_expr.clone()),
158 y: Arc::new(preprocessed_var.clone()),
159 degree_multiple: 1,
160 };
161 assert_eq!(
162 add_expr.degree_multiple(),
163 1,
164 "Addition should take max degree of inputs"
165 );
166
167 let sub_expr = SymbolicExpr::<BaseLeaf<BabyBear>>::Sub {
168 x: Arc::new(variable_expr.clone()),
169 y: Arc::new(preprocessed_var.clone()),
170 degree_multiple: 1,
171 };
172 assert_eq!(
173 sub_expr.degree_multiple(),
174 1,
175 "Subtraction should take max degree of inputs"
176 );
177
178 let neg_expr = SymbolicExpr::<BaseLeaf<BabyBear>>::Neg {
179 x: Arc::new(variable_expr.clone()),
180 degree_multiple: 1,
181 };
182 assert_eq!(
183 neg_expr.degree_multiple(),
184 1,
185 "Negation should keep the degree"
186 );
187
188 let mul_expr = SymbolicExpr::<BaseLeaf<BabyBear>>::Mul {
189 x: Arc::new(variable_expr),
190 y: Arc::new(preprocessed_var),
191 degree_multiple: 2,
192 };
193 assert_eq!(
194 mul_expr.degree_multiple(),
195 2,
196 "Multiplication should sum degrees"
197 );
198 }
199
200 #[test]
201 fn test_addition_of_constants() {
202 let a = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(3)));
203 let b = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(4)));
204 let result = a + b;
205 match result {
206 SymbolicExpr::Leaf(BaseLeaf::Constant(val)) => assert_eq!(val, BabyBear::new(7)),
207 _ => panic!("Addition of constants did not simplify correctly"),
208 }
209 }
210
211 #[test]
212 fn test_subtraction_of_constants() {
213 let a = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(10)));
214 let b = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(4)));
215 let result = a - b;
216 match result {
217 SymbolicExpr::Leaf(BaseLeaf::Constant(val)) => assert_eq!(val, BabyBear::new(6)),
218 _ => panic!("Subtraction of constants did not simplify correctly"),
219 }
220 }
221
222 #[test]
223 fn test_negation() {
224 let a = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(7)));
225 let result = -a;
226 match result {
227 SymbolicExpr::Leaf(BaseLeaf::Constant(val)) => {
228 assert_eq!(val, BabyBear::NEG_ONE * BabyBear::new(7));
229 }
230 _ => panic!("Negation did not work correctly"),
231 }
232 }
233
234 #[test]
235 fn test_multiplication_of_constants() {
236 let a = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(3)));
237 let b = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(5)));
238 let result = a * b;
239 match result {
240 SymbolicExpr::Leaf(BaseLeaf::Constant(val)) => assert_eq!(val, BabyBear::new(15)),
241 _ => panic!("Multiplication of constants did not simplify correctly"),
242 }
243 }
244
245 #[test]
246 fn test_degree_multiple_for_addition() {
247 let a = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
248 BaseEntry::Main { offset: 0 },
249 1,
250 )));
251 let b = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
252 BaseEntry::Main { offset: 0 },
253 2,
254 )));
255 let result = a + b;
256 match result {
257 SymbolicExpr::Add {
258 degree_multiple,
259 x,
260 y,
261 } => {
262 assert_eq!(degree_multiple, 1);
263 assert!(
264 matches!(&*x, SymbolicExpr::Leaf(BaseLeaf::Variable(v)) if v.index == 1 && matches!(v.entry, BaseEntry::Main { offset: 0 }))
265 );
266 assert!(
267 matches!(&*y, SymbolicExpr::Leaf(BaseLeaf::Variable(v)) if v.index == 2 && matches!(v.entry, BaseEntry::Main { offset: 0 }))
268 );
269 }
270 _ => panic!("Addition did not create an Add expression"),
271 }
272 }
273
274 #[test]
275 fn test_degree_multiple_for_multiplication() {
276 let a = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
277 BaseEntry::Main { offset: 0 },
278 1,
279 )));
280 let b = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
281 BaseEntry::Main { offset: 0 },
282 2,
283 )));
284 let result = a * b;
285
286 match result {
287 SymbolicExpr::Mul {
288 degree_multiple,
289 x,
290 y,
291 } => {
292 assert_eq!(degree_multiple, 2, "Multiplication should sum degrees");
293
294 assert!(
295 matches!(&*x, SymbolicExpr::Leaf(BaseLeaf::Variable(v))
296 if v.index == 1 && matches!(v.entry, BaseEntry::Main { offset: 0 })
297 ),
298 "Left operand should match `a`"
299 );
300
301 assert!(
302 matches!(&*y, SymbolicExpr::Leaf(BaseLeaf::Variable(v))
303 if v.index == 2 && matches!(v.entry, BaseEntry::Main { offset: 0 })
304 ),
305 "Right operand should match `b`"
306 );
307 }
308 _ => panic!("Multiplication did not create a `Mul` expression"),
309 }
310 }
311
312 #[test]
313 fn test_sum_operator() {
314 let expressions = vec![
315 SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(2))),
316 SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(3))),
317 SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(5))),
318 ];
319 let result: SymbolicExpression<BabyBear> = expressions.into_iter().sum();
320 match result {
321 SymbolicExpr::Leaf(BaseLeaf::Constant(val)) => assert_eq!(val, BabyBear::new(10)),
322 _ => panic!("Sum did not produce correct result"),
323 }
324 }
325
326 #[test]
327 fn test_product_operator() {
328 let expressions = vec![
329 SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(2))),
330 SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(3))),
331 SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(4))),
332 ];
333 let result: SymbolicExpression<BabyBear> = expressions.into_iter().product();
334 match result {
335 SymbolicExpr::Leaf(BaseLeaf::Constant(val)) => assert_eq!(val, BabyBear::new(24)),
336 _ => panic!("Product did not produce correct result"),
337 }
338 }
339
340 #[test]
341 fn test_default_is_zero() {
342 let expr: SymbolicExpression<BabyBear> = Default::default();
344
345 assert!(matches!(
347 expr,
348 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::ZERO
349 ));
350 }
351
352 #[test]
353 fn test_ring_constants() {
354 assert!(matches!(
356 SymbolicExpression::<BabyBear>::ZERO,
357 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::ZERO
358 ));
359 assert!(matches!(
361 SymbolicExpression::<BabyBear>::ONE,
362 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::ONE
363 ));
364 assert!(matches!(
366 SymbolicExpression::<BabyBear>::TWO,
367 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::TWO
368 ));
369 assert!(matches!(
371 SymbolicExpression::<BabyBear>::NEG_ONE,
372 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::NEG_ONE
373 ));
374 }
375
376 #[test]
377 fn test_from_symbolic_variable() {
378 let var = SymbolicVariable::<BabyBear>::new(BaseEntry::Main { offset: 0 }, 3);
380 let expr: SymbolicExpression<BabyBear> = var.into();
382 match expr {
384 SymbolicExpr::Leaf(BaseLeaf::Variable(v)) => {
385 assert!(matches!(v.entry, BaseEntry::Main { offset: 0 }));
386 assert_eq!(v.index, 3);
387 }
388 _ => panic!("Expected Variable variant"),
389 }
390 }
391
392 #[test]
393 fn test_from_field_element() {
394 let field_val = BabyBear::new(42);
396 let expr: SymbolicExpression<BabyBear> = field_val.into();
397 assert!(matches!(
399 expr,
400 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == field_val
401 ));
402 }
403
404 #[test]
405 fn test_from_prime_subfield() {
406 let prime_subfield_val = <BabyBear as PrimeCharacteristicRing>::PrimeSubfield::new(7);
408 let expr = SymbolicExpression::<BabyBear>::from_prime_subfield(prime_subfield_val);
409 assert!(matches!(
411 expr,
412 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::new(7)
413 ));
414 }
415
416 #[test]
417 fn test_assign_operators() {
418 let mut expr = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(5)));
420 expr += SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(3)));
421 assert!(matches!(
422 expr,
423 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::new(8)
424 ));
425
426 let mut expr = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(10)));
428 expr -= SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(4)));
429 assert!(matches!(
430 expr,
431 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::new(6)
432 ));
433
434 let mut expr = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(6)));
436 expr *= SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(7)));
437 assert!(matches!(
438 expr,
439 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::new(42)
440 ));
441 }
442
443 #[test]
444 fn test_subtraction_creates_sub_node() {
445 let a = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
447 BaseEntry::Main { offset: 0 },
448 0,
449 )));
450 let b = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
451 BaseEntry::Main { offset: 0 },
452 1,
453 )));
454
455 let result = a - b;
457
458 match result {
460 SymbolicExpr::Sub {
461 x,
462 y,
463 degree_multiple,
464 } => {
465 assert_eq!(degree_multiple, 1);
467
468 assert!(matches!(
470 x.as_ref(),
471 SymbolicExpr::Leaf(BaseLeaf::Variable(v))
472 if v.index == 0 && matches!(v.entry, BaseEntry::Main { offset: 0 })
473 ));
474
475 assert!(matches!(
477 y.as_ref(),
478 SymbolicExpr::Leaf(BaseLeaf::Variable(v))
479 if v.index == 1 && matches!(v.entry, BaseEntry::Main { offset: 0 })
480 ));
481 }
482 _ => panic!("Expected Sub variant"),
483 }
484 }
485
486 #[test]
487 fn test_negation_creates_neg_node() {
488 let var = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
490 BaseEntry::Main { offset: 0 },
491 0,
492 )));
493
494 let result = -var;
496
497 match result {
499 SymbolicExpr::Neg { x, degree_multiple } => {
500 assert_eq!(degree_multiple, 1);
502
503 assert!(matches!(
505 x.as_ref(),
506 SymbolicExpr::Leaf(BaseLeaf::Variable(v))
507 if v.index == 0 && matches!(v.entry, BaseEntry::Main { offset: 0 })
508 ));
509 }
510 _ => panic!("Expected Neg variant"),
511 }
512 }
513
514 #[test]
515 fn test_empty_sum_returns_zero() {
516 let empty: Vec<SymbolicExpression<BabyBear>> = vec![];
518 let result: SymbolicExpression<BabyBear> = empty.into_iter().sum();
519 assert!(matches!(
520 result,
521 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::ZERO
522 ));
523 }
524
525 #[test]
526 fn test_empty_product_returns_one() {
527 let empty: Vec<SymbolicExpression<BabyBear>> = vec![];
529 let result: SymbolicExpression<BabyBear> = empty.into_iter().product();
530 assert!(matches!(
531 result,
532 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::ONE
533 ));
534 }
535
536 #[test]
537 fn test_mixed_degree_addition() {
538 let constant = SymbolicExpression::Leaf(BaseLeaf::Constant(BabyBear::new(5)));
540
541 let var = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
543 BaseEntry::Main { offset: 0 },
544 0,
545 )));
546
547 let result = constant + var;
549
550 match result {
551 SymbolicExpr::Add {
552 x,
553 y,
554 degree_multiple,
555 } => {
556 assert_eq!(degree_multiple, 1);
558
559 assert!(matches!(
561 x.as_ref(),
562 SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if *c == BabyBear::new(5)
563 ));
564
565 assert!(matches!(
567 y.as_ref(),
568 SymbolicExpr::Leaf(BaseLeaf::Variable(v))
569 if v.index == 0 && matches!(v.entry, BaseEntry::Main { offset: 0 })
570 ));
571 }
572 _ => panic!("Expected Add variant"),
573 }
574 }
575
576 #[test]
577 fn test_chained_multiplication_degree() {
578 let a = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
580 BaseEntry::Main { offset: 0 },
581 0,
582 )));
583 let b = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
584 BaseEntry::Main { offset: 0 },
585 1,
586 )));
587 let c = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
588 BaseEntry::Main { offset: 0 },
589 2,
590 )));
591
592 let ab = a * b;
594 assert_eq!(ab.degree_multiple(), 2);
595
596 let abc = ab * c;
598 assert_eq!(abc.degree_multiple(), 3);
599 }
600
601 #[test]
602 fn test_add_zero_identity_folding() {
603 let var = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
604 BaseEntry::Main { offset: 0 },
605 0,
606 )));
607 let zero = SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::Constant(BabyBear::ZERO));
608
609 let result = var.clone() + zero.clone();
611 assert!(
612 matches!(result, SymbolicExpr::Leaf(BaseLeaf::Variable(_))),
613 "x + 0 should fold to x"
614 );
615
616 let result = zero + var;
618 assert!(
619 matches!(result, SymbolicExpr::Leaf(BaseLeaf::Variable(_))),
620 "0 + x should fold to x"
621 );
622 }
623
624 #[test]
625 fn test_sub_zero_identity_folding() {
626 let var = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
627 BaseEntry::Main { offset: 0 },
628 0,
629 )));
630 let zero = SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::Constant(BabyBear::ZERO));
631
632 let result = var.clone() - zero.clone();
634 assert!(
635 matches!(result, SymbolicExpr::Leaf(BaseLeaf::Variable(_))),
636 "x - 0 should fold to x"
637 );
638
639 let result = zero - var;
641 match result {
642 SymbolicExpr::Neg { x, degree_multiple } => {
643 assert_eq!(degree_multiple, 1);
644 assert!(matches!(
645 x.as_ref(),
646 SymbolicExpr::Leaf(BaseLeaf::Variable(v))
647 if v.index == 0 && v.entry == BaseEntry::Main { offset: 0 }
648 ));
649 }
650 _ => panic!("0 - x should fold to Neg(x)"),
651 }
652 }
653
654 #[test]
655 fn test_mul_zero_identity_folding() {
656 let var = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
657 BaseEntry::Main { offset: 0 },
658 0,
659 )));
660 let zero = SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::Constant(BabyBear::ZERO));
661
662 let result = var.clone() * zero.clone();
664 assert!(
665 matches!(result, SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::ZERO),
666 "x * 0 should fold to 0"
667 );
668
669 let result = zero * var;
671 assert!(
672 matches!(result, SymbolicExpr::Leaf(BaseLeaf::Constant(c)) if c == BabyBear::ZERO),
673 "0 * x should fold to 0"
674 );
675 }
676
677 #[test]
678 fn test_mul_one_identity_folding() {
679 let var = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
680 BaseEntry::Main { offset: 0 },
681 0,
682 )));
683 let one = SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::Constant(BabyBear::ONE));
684
685 let result = var.clone() * one.clone();
687 assert!(
688 matches!(result, SymbolicExpr::Leaf(BaseLeaf::Variable(_))),
689 "x * 1 should fold to x"
690 );
691
692 let result = one * var;
694 assert!(
695 matches!(result, SymbolicExpr::Leaf(BaseLeaf::Variable(_))),
696 "1 * x should fold to x"
697 );
698 }
699
700 #[test]
701 fn test_identity_folding_preserves_degree() {
702 let var = SymbolicExpression::Leaf(BaseLeaf::Variable(SymbolicVariable::<BabyBear>::new(
703 BaseEntry::Main { offset: 0 },
704 0,
705 )));
706 let zero = SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::Constant(BabyBear::ZERO));
707 let one = SymbolicExpression::<BabyBear>::Leaf(BaseLeaf::Constant(BabyBear::ONE));
708
709 let result = var.clone() + zero.clone();
711 assert_eq!(result.degree_multiple(), 1);
712
713 let result = var.clone() - zero.clone();
715 assert_eq!(result.degree_multiple(), 1);
716
717 let result = zero.clone() - var.clone();
719 assert_eq!(result.degree_multiple(), 1);
720
721 let result = var.clone() * one;
723 assert_eq!(result.degree_multiple(), 1);
724
725 let result = var * zero;
727 assert_eq!(result.degree_multiple(), 0);
728 }
729}