Skip to content

Commit 5ad9656

Browse files
Polynomial: differentiate & print methods. (#929)
* add differentiate method to poly * print_as_sage_poly * avoid duplicate call to .degree(). * Fix wasm target compilation. --------- Co-authored-by: Diego K <43053772+diegokingston@users.noreply.github.com>
1 parent e14cf2b commit 5ad9656

File tree

1 file changed

+75
-3
lines changed

1 file changed

+75
-3
lines changed

math/src/polynomial/mod.rs

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
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};
45
use core::{fmt::Display, ops};
5-
66
pub mod dense_multilinear_poly;
77
mod error;
88
pub mod sparse_multilinear_poly;
@@ -140,6 +140,19 @@ impl<F: IsField> Polynomial<FieldElement<F>> {
140140
self.coefficients().len()
141141
}
142142

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+
143156
/// Computes quotient with `x - b` in place.
144157
pub fn ruffini_division_inplace(&mut self, b: &FieldElement<F>) {
145158
let mut c = FieldElement::zero();
@@ -302,6 +315,44 @@ impl<F: IsField> Polynomial<FieldElement<F>> {
302315
}
303316
}
304317

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+
305356
pub fn pad_with_zero_coefficients_to_length<F: IsField>(
306357
pa: &mut Polynomial<FieldElement<F>>,
307358
n: usize,
@@ -1177,4 +1228,25 @@ mod tests {
11771228
assert_eq!(lhs, g);
11781229
assert_eq!(g, p3);
11791230
}
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+
}
11801252
}

0 commit comments

Comments
 (0)