polynomials/
lib.rs

1use ark_ff::PrimeField;
2
3use std::ops::{Add, Mul};
4
5/// Represents a single term in a polynomial, consisting of an exponent and a coefficient.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
7pub struct Monomial<F: PrimeField> {
8    /// The exponent of the monomial.
9    pub exponent: usize,
10    /// The coefficient of the monomial.
11    pub coefficients: F,
12}
13impl<F: PrimeField> Monomial<F> {
14    /// Creates a new `Monomial` with the given exponent and coefficient.
15    ///
16    /// # Arguments
17    ///
18    /// * `exponent` - The exponent of the monomial.
19    /// * `coefficients` - The coefficient of the monomial.
20    ///
21    /// # Returns
22    ///
23    /// A new `Monomial` instance.
24    pub fn new(exponent: usize, coefficients: F) -> Monomial<F> {
25        Monomial {
26            exponent,
27            coefficients,
28        }
29    }
30    /// Creates a default `Monomial` with an exponent of 0 and a coefficient of 0.0.
31    ///
32    /// # Returns
33    ///
34    /// A default `Monomial` instance.
35    pub fn default() -> Monomial<F> {
36        Monomial {
37            exponent: 0,
38            coefficients: F::zero(),
39        }
40    }
41}
42/// Represents a polynomial, which is a sum of monomials.
43#[derive(Debug, Clone)]
44pub struct UnivariatePolynomial<F: PrimeField> {
45    /// The list of monomials that make up the polynomial.
46    monomials: Vec<Monomial<F>>,
47    /// The degree of the polynomial, if known.
48    pub degree: Option<u32>,
49}
50impl<F: PrimeField> UnivariatePolynomial<F> {
51    /// Adds a monomial to the polynomial. If a monomial with the same exponent already exists,
52    /// their coefficients are combined.
53    ///
54    /// # Arguments
55    ///
56    /// * `exponent` - The exponent of the monomial to add.
57    /// * `coefficients` - The coefficient of the monomial to add.
58
59    pub fn new(monomials: Vec<Monomial<F>>) -> UnivariatePolynomial<F> {
60        UnivariatePolynomial {
61            monomials,
62            degree: None,
63        }
64    }
65    /// Creates a default `Polynomial` with no monomials and no degree.
66    ///
67    /// # Returns
68    ///
69    /// A default `Polynomial` instance.
70    pub fn default() -> UnivariatePolynomial<F> {
71        UnivariatePolynomial {
72            monomials: Vec::new(),
73            degree: None,
74        }
75    }
76
77    /// Evaluates the polynomial at a given value of `x`.
78    ///
79    /// # Arguments
80    ///
81    /// * `x` - The value at which to evaluate the polynomial.
82    ///
83    /// # Returns
84    ///
85    /// The result of evaluating the polynomial at `x`.
86    pub fn evaluate(&self, x: F) -> F {
87        let mut result: F = F::zero();
88        let n = self.monomials.len();
89        for i in 0..n {
90            result += self.monomials[i].coefficients
91                * F::from(x).pow(&[self.monomials[i].exponent as u64]);
92        }
93        return result;
94    }
95
96    /// Returns the degree of the polynomial.
97    ///
98    /// # Returns
99    ///
100    /// The degree of the polynomial, if known.
101    pub fn degree(&mut self) -> Option<u32> {
102        let n = self.monomials.len();
103        if self.degree.is_none() {
104            for i in 0..n {
105                if self.monomials[i].exponent as u32 > self.degree.unwrap_or(0) {
106                    self.degree = Some(self.monomials[i].exponent as u32);
107                }
108            }
109            return self.degree;
110        } else {
111            return self.degree;
112        }
113    }
114    /// Performs Lagrange interpolation to find a polynomial that passes through the given points.
115    ///
116    /// # Arguments
117    ///
118    /// * `x` - A vector of x-coordinates of the points.
119    /// * `y` - A vector of y-coordinates of the points.
120    ///
121    /// # Returns
122    ///
123    /// A `UnivariatePolynomial` that passes through the given points.
124    //add prime modulo
125    pub fn interpolate(x: Vec<F>, y: Vec<F>) -> UnivariatePolynomial<F> {
126        let n = x.len();
127        let mut result = UnivariatePolynomial::default();
128
129        // result.set_prime_modulo(p);
130
131        for i in 0..n {
132            let mut denominator = F::from(1);
133
134            let mut numerator = UnivariatePolynomial::new(vec![Monomial::new(0, F::one())]);
135
136            let mut a = y[i];
137            for j in 0..n {
138                if i != j {
139                    let x_n = Monomial::new(1, F::one()); // x
140                    let x_j = Monomial::new(0, F::from(-x[j]));
141                    let temp_poly = UnivariatePolynomial::new(vec![x_n, x_j]);
142
143                    numerator = numerator * temp_poly;
144
145                    denominator = denominator * (F::from(x[i]) - F::from(x[j]));
146                }
147            }
148
149            a /= denominator;
150
151            for monomial in &mut numerator.monomials {
152                monomial.coefficients *= F::from(a);
153            }
154
155            result = result + numerator;
156        }
157
158        result
159    }
160}
161
162impl<F: PrimeField> Mul for UnivariatePolynomial<F> {
163    type Output = UnivariatePolynomial<F>;
164    /// Multiplies two polynomials and returns the result.
165    ///
166    /// # Arguments
167    ///
168    /// * `p2` - The polynomial to multiply by.
169    ///
170    /// # Returns
171    ///
172    /// A new `Polynomial` representing the product of the two polynomials.
173
174    fn mul(self, p2: UnivariatePolynomial<F>) -> Self {
175        let p1: Vec<Monomial<F>> = self.monomials;
176        let p2: Vec<Monomial<F>> = p2.monomials;
177
178        let mut polynomial: Vec<Monomial<F>> = Vec::new();
179        for i in 0..p1.len() {
180            for j in 0..p2.len() {
181                polynomial.push(Monomial {
182                    coefficients: p1[i].coefficients * p2[j].coefficients,
183                    exponent: p1[i].exponent.wrapping_add(p2[j].exponent),
184                });
185            }
186        }
187        // Combine monomials with the same exponent
188
189        for i in 0..polynomial.len() {
190            let mut j = i + 1;
191            while j < polynomial.len() {
192                if polynomial[i].exponent == polynomial[j].exponent {
193                    let (left, right) = polynomial.split_at_mut(j);
194                    left[i].coefficients += right[0].coefficients;
195                    polynomial.remove(j);
196                } else {
197                    j += 1;
198                }
199            }
200        }
201        UnivariatePolynomial {
202            monomials: polynomial,
203            degree: None,
204        }
205    }
206}
207
208impl<F: PrimeField> Add for UnivariatePolynomial<F> {
209    type Output = UnivariatePolynomial<F>;
210    /// Adds two polynomials and returns the result.
211    ///
212    /// # Arguments
213    ///
214    /// * `p2` - The polynomial to add.
215    ///
216    /// # Returns
217    ///
218    /// A new `Polynomial` representing the sum of the two polynomials.
219
220    fn add(self, p2: UnivariatePolynomial<F>) -> Self {
221        let p1: Vec<Monomial<F>> = self.monomials;
222        let p2: Vec<Monomial<F>> = p2.monomials;
223        let mut polynomial: Vec<Monomial<F>> = Vec::new();
224        polynomial = [p1, p2].concat();
225        // Combine monomials with the same exponent
226
227        for i in 0..polynomial.len() {
228            let mut j = i + 1;
229            while j < polynomial.len() {
230                if polynomial[i].exponent == polynomial[j].exponent {
231                    let (left, right) = polynomial.split_at_mut(j);
232                    left[i].coefficients += right[0].coefficients;
233                    polynomial.remove(j);
234                } else {
235                    j += 1;
236                }
237            }
238        }
239        UnivariatePolynomial {
240            monomials: polynomial,
241            degree: None,
242        }
243    }
244}
245
246#[cfg(test)]
247mod tests {
248    use super::*;
249    use ark_bn254::Fq;
250
251    #[test]
252    /// Tests the `evaluate` method of the `Polynomial` struct.
253    fn test_evaluate() {
254        let default = UnivariatePolynomial::default();
255        let m1 = Monomial::new(2, Fq::from(3u32));
256        let m2 = Monomial::new(1, Fq::from(2u32));
257        let m3 = Monomial::new(0, Fq::from(5u32));
258
259        let p = UnivariatePolynomial {
260            monomials: vec![m1, m2, m3],
261            ..default
262        };
263        let result = p.evaluate(Fq::from(4));
264        assert_eq!(result, Fq::from(61u32));
265    }
266
267    /// Tests the `degree` method of the `UnivariatePolynomial` struct.
268
269    #[test]
270    fn test_degree() {
271        let default = UnivariatePolynomial::<Fq>::default();
272        let m1 = Monomial::new(2, Fq::from(3u32));
273        let m2 = Monomial::new(1, Fq::from(2u32));
274
275        let mut p = UnivariatePolynomial {
276            monomials: vec![m1, m2],
277            ..default
278        };
279        let result = p.degree();
280        assert_eq!(result, Some(2));
281    }
282
283    /// Tests the multiplication of two UnivariatePolynomials.
284
285    #[test]
286    fn test_multiplication() {
287        let default = UnivariatePolynomial::default();
288        let m1 = Monomial::new(3, Fq::from(4u32));
289        let m2 = Monomial::new(2, Fq::from(3u32));
290        let m5 = Monomial::new(1, Fq::from(3u32));
291        let m3 = Monomial::new(2, Fq::from(5u32));
292        let m4 = Monomial::new(1, Fq::from(7u32));
293
294        let p1 = UnivariatePolynomial {
295            monomials: vec![m1, m2, m5],
296            ..default
297        };
298        let p2 = UnivariatePolynomial {
299            monomials: vec![m3, m4],
300            ..default
301        };
302        let result = p1 * p2;
303        assert_eq!(result.monomials[0].coefficients, Fq::from(20u32));
304        assert_eq!(result.monomials[1].coefficients, Fq::from(43u32));
305        assert_eq!(result.monomials[2].coefficients, Fq::from(36u32));
306        assert_eq!(result.monomials[3].coefficients, Fq::from(21u32));
307        assert_eq!(result.monomials[0].exponent, 5);
308        assert_eq!(result.monomials[1].exponent, 4);
309        assert_eq!(result.monomials[2].exponent, 3);
310        assert_eq!(result.monomials[3].exponent, 2);
311    }
312
313    /// Tests the Lagrange interpolation method.
314    #[test]
315    fn test_interpolate() {
316        let x = vec![Fq::from(1), Fq::from(2), Fq::from(3)];
317        let y = vec![Fq::from(1), Fq::from(4), Fq::from(9)];
318        let result = UnivariatePolynomial::<Fq>::interpolate(x, y);
319        assert_eq!(result.monomials[0].coefficients, Fq::from(1u32));
320        assert_eq!(result.monomials[0].exponent, 2);
321    }
322}