diff --git a/mvpoly/src/prime.rs b/mvpoly/src/prime.rs index 3c066fd3ef..afdc209d81 100644 --- a/mvpoly/src/prime.rs +++ b/mvpoly/src/prime.rs @@ -301,6 +301,37 @@ impl Dense { D } + pub fn is_constant(&self) -> bool { + self.coeff.iter().skip(1).all(|c| c.is_zero()) + } + + /// Returns the degree of the polynomial. + /// + /// The degree of the polynomial is the maximum degree of the monomials + /// that have a non-zero coefficient. + /// + /// # Safety + /// + /// The zero polynomial as a degree equals to 0, as the degree of the + /// constant polynomials. We do use the `unsafe` keyword to warn the user + /// for this specific case. + pub unsafe fn degree(&self) -> usize { + if self.is_constant() { + return 0; + } + let mut prime_gen = PrimeNumberGenerator::new(); + self.coeff.iter().enumerate().fold(1, |acc, (i, c)| { + if *c != F::zero() { + let decomposition_of_i = + naive_prime_factors(self.normalized_indices[i], &mut prime_gen); + let monomial_degree = decomposition_of_i.iter().fold(0, |acc, (_, d)| acc + d); + acc.max(monomial_degree) + } else { + acc + } + }) + } + /// Output example for N = 2 and D = 2: /// ```text /// - 0 -> 1 diff --git a/mvpoly/tests/prime.rs b/mvpoly/tests/prime.rs index 529b1d74ae..7c27e49fec 100644 --- a/mvpoly/tests/prime.rs +++ b/mvpoly/tests/prime.rs @@ -5,6 +5,7 @@ use kimchi::circuits::{ }; use mina_curves::pasta::Fp; use mvpoly::{prime::Dense, utils::PrimeNumberGenerator}; +use rand::Rng; #[test] fn test_vector_space_dimension() { @@ -620,3 +621,45 @@ fn test_from_expr_ec_addition() { assert_eq!(eval, exp_eval); } } + +#[test] +fn test_degree_with_coeffs() { + let p = Dense::::from_coeffs(vec![ + Fp::from(2_u32), + Fp::from(3_u32), + Fp::from(4_u32), + Fp::from(5_u32), + Fp::from(6_u32), + Fp::from(7_u32), + ]); + let degree = unsafe { p.degree() }; + assert_eq!(degree, 2); +} + +#[test] +fn test_degree_constant() { + let mut rng = o1_utils::tests::make_test_rng(None); + let c = Fp::rand(&mut rng); + let p = Dense::::from(c); + let degree = unsafe { p.degree() }; + assert_eq!(degree, 0); + + let p = Dense::::zero(); + let degree = unsafe { p.degree() }; + assert_eq!(degree, 0); +} + +#[test] +fn test_degree_random_degree() { + let mut rng = o1_utils::tests::make_test_rng(None); + let max_degree: usize = rng.gen_range(1..5); + let p: Dense = unsafe { Dense::random(&mut rng, Some(max_degree)) }; + let degree = unsafe { p.degree() }; + assert!(degree <= max_degree); + + let max_degree: usize = rng.gen_range(1..20); + // univariate + let p = unsafe { Dense::::random(&mut rng, Some(max_degree)) }; + let degree = unsafe { p.degree() }; + assert!(degree <= max_degree); +}