|
1 | 1 | use super::field::element::FieldElement; |
2 | | -use crate::field::traits::{IsField, IsSubFieldOf}; |
3 | | -use alloc::{borrow::ToOwned, vec, vec::Vec}; |
| 2 | +use crate::field::traits::{IsField, IsPrimeField, IsSubFieldOf}; |
| 3 | +use alloc::string::{String, ToString}; |
| 4 | +use alloc::{borrow::ToOwned, format, vec, vec::Vec}; |
4 | 5 | use core::{fmt::Display, ops}; |
5 | | - |
6 | 6 | pub mod dense_multilinear_poly; |
7 | 7 | mod error; |
8 | 8 | pub mod sparse_multilinear_poly; |
@@ -140,6 +140,19 @@ impl<F: IsField> Polynomial<FieldElement<F>> { |
140 | 140 | self.coefficients().len() |
141 | 141 | } |
142 | 142 |
|
| 143 | + /// Returns the derivative of the polynomial with respect to x. |
| 144 | + pub fn differentiate(&self) -> Self { |
| 145 | + let degree = self.degree(); |
| 146 | + if degree == 0 { |
| 147 | + return Polynomial::zero(); |
| 148 | + } |
| 149 | + let mut derivative = Vec::with_capacity(degree); |
| 150 | + for (i, coeff) in self.coefficients().iter().enumerate().skip(1) { |
| 151 | + derivative.push(FieldElement::<F>::from(i as u64) * coeff); |
| 152 | + } |
| 153 | + Polynomial::new(&derivative) |
| 154 | + } |
| 155 | + |
143 | 156 | /// Computes quotient with `x - b` in place. |
144 | 157 | pub fn ruffini_division_inplace(&mut self, b: &FieldElement<F>) { |
145 | 158 | let mut c = FieldElement::zero(); |
@@ -302,6 +315,44 @@ impl<F: IsField> Polynomial<FieldElement<F>> { |
302 | 315 | } |
303 | 316 | } |
304 | 317 |
|
| 318 | +impl<F: IsPrimeField> Polynomial<FieldElement<F>> { |
| 319 | + // Print the polynomial as a string ready to be used in SageMath, or just for pretty printing. |
| 320 | + pub fn print_as_sage_poly(&self, var_name: Option<char>) -> String { |
| 321 | + let var_name = var_name.unwrap_or('x'); |
| 322 | + if self.coefficients.is_empty() |
| 323 | + || self.coefficients.len() == 1 && self.coefficients[0] == FieldElement::zero() |
| 324 | + { |
| 325 | + return String::new(); |
| 326 | + } |
| 327 | + |
| 328 | + let mut string = String::new(); |
| 329 | + let zero = FieldElement::<F>::zero(); |
| 330 | + |
| 331 | + for (i, coeff) in self.coefficients.iter().rev().enumerate() { |
| 332 | + if *coeff == zero { |
| 333 | + continue; |
| 334 | + } |
| 335 | + |
| 336 | + let coeff_str = coeff.representative().to_string(); |
| 337 | + |
| 338 | + if i == self.coefficients.len() - 1 { |
| 339 | + string.push_str(&coeff_str); |
| 340 | + } else if i == self.coefficients.len() - 2 { |
| 341 | + string.push_str(&format!("{}*{} + ", coeff_str, var_name)); |
| 342 | + } else { |
| 343 | + string.push_str(&format!( |
| 344 | + "{}*{}^{} + ", |
| 345 | + coeff_str, |
| 346 | + var_name, |
| 347 | + self.coefficients.len() - 1 - i |
| 348 | + )); |
| 349 | + } |
| 350 | + } |
| 351 | + |
| 352 | + string |
| 353 | + } |
| 354 | +} |
| 355 | + |
305 | 356 | pub fn pad_with_zero_coefficients_to_length<F: IsField>( |
306 | 357 | pa: &mut Polynomial<FieldElement<F>>, |
307 | 358 | n: usize, |
@@ -1177,4 +1228,25 @@ mod tests { |
1177 | 1228 | assert_eq!(lhs, g); |
1178 | 1229 | assert_eq!(g, p3); |
1179 | 1230 | } |
| 1231 | + |
| 1232 | + #[test] |
| 1233 | + fn test_differentiate() { |
| 1234 | + // 3x^2 + 2x + 42 |
| 1235 | + let px = Polynomial::new(&[FE::new(42), FE::new(2), FE::new(3)]); |
| 1236 | + // 6x + 2 |
| 1237 | + let dpdx = px.differentiate(); |
| 1238 | + assert_eq!(dpdx, Polynomial::new(&[FE::new(2), FE::new(6)])); |
| 1239 | + |
| 1240 | + // 128 |
| 1241 | + let px = Polynomial::new(&[FE::new(128)]); |
| 1242 | + // 0 |
| 1243 | + let dpdx = px.differentiate(); |
| 1244 | + assert_eq!(dpdx, Polynomial::new(&[FE::new(0)])); |
| 1245 | + } |
| 1246 | + |
| 1247 | + #[test] |
| 1248 | + fn test_print_as_sage_poly() { |
| 1249 | + let p = Polynomial::new(&[FE::new(1), FE::new(2), FE::new(3)]); |
| 1250 | + assert_eq!(p.print_as_sage_poly(None), "3*x^2 + 2*x + 1"); |
| 1251 | + } |
1180 | 1252 | } |
0 commit comments