Skip to content

Commit b76adbe

Browse files
committed
polynomial: add some extra functionality enabled by FieldVec
1 parent 690fc7d commit b76adbe

File tree

3 files changed

+132
-4
lines changed

3 files changed

+132
-4
lines changed

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@
134134
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
135135
// Coding conventions
136136
#![deny(missing_docs)]
137+
#![allow(clippy::suspicious_arithmetic_impl)] // this lint is literally always wrong
138+
#![allow(clippy::suspicious_op_assign_impl)] // ...and "always wrong" loves company
137139

138140
#[cfg(bench)]
139141
extern crate test;

src/primitives/fieldvec.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
6060
#[cfg(all(feature = "alloc", not(feature = "std")))]
6161
use alloc::vec::Vec;
62-
use core::{iter, ops, slice};
62+
use core::{iter, mem, ops, slice};
6363

6464
use super::Field;
6565
use crate::primitives::correction::NO_ALLOC_MAX_LENGTH;
@@ -206,12 +206,45 @@ impl<F: Default> FieldVec<F> {
206206
self.inner_a[self.len - 1] = item;
207207
} else {
208208
if self.len == NO_ALLOC_MAX_LENGTH + 1 {
209-
let inner_a = core::mem::take(&mut self.inner_a);
209+
let inner_a = mem::take(&mut self.inner_a);
210210
self.inner_v = inner_a.into();
211211
}
212212
self.inner_v.push(item);
213213
}
214214
}
215+
216+
/// Pops an item off the end of the vector.
217+
///
218+
/// # Panics
219+
///
220+
/// Panics if [`Self::has_data`] is false.
221+
pub fn pop(&mut self) -> Option<F> {
222+
self.assert_has_data();
223+
if self.len == 0 {
224+
return None;
225+
}
226+
227+
self.len -= 1;
228+
#[cfg(not(feature = "alloc"))]
229+
{
230+
Some(mem::take(&mut self.inner_a[self.len]))
231+
}
232+
233+
#[cfg(feature = "alloc")]
234+
if self.len < NO_ALLOC_MAX_LENGTH {
235+
Some(mem::take(&mut self.inner_a[self.len]))
236+
} else {
237+
use core::convert::TryFrom;
238+
239+
let ret = self.inner_v.pop();
240+
let inner_v = mem::take(&mut self.inner_v);
241+
match <[F; NO_ALLOC_MAX_LENGTH]>::try_from(inner_v) {
242+
Ok(arr) => self.inner_a = arr,
243+
Err(vec) => self.inner_v = vec,
244+
}
245+
ret
246+
}
247+
}
215248
}
216249

217250
impl<F: Clone + Default> iter::FromIterator<F> for FieldVec<F> {

src/primitives/polynomial.rs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
//! Polynomials over Finite Fields
44
5-
use core::{iter, ops};
5+
use core::{fmt, iter, ops, slice};
66

77
use super::{ExtensionField, Field, FieldVec};
88

@@ -15,6 +15,13 @@ pub struct Polynomial<F> {
1515
}
1616

1717
impl<F: Field> Polynomial<F> {
18+
/// Determines whether the residue is representable, given the current
19+
/// compilation context.
20+
pub fn has_data(&self) -> bool { self.inner.has_data() }
21+
22+
/// Panics if [`Self::has_data`] is false, with an informative panic message.
23+
pub fn assert_has_data(&self) { self.inner.assert_has_data() }
24+
1825
/// Provides access to the underlying [`FieldVec`].
1926
pub fn into_inner(self) -> FieldVec<F> { self.inner }
2027

@@ -39,6 +46,18 @@ impl<F: Field> Polynomial<F> {
3946
degree_without_leading_zeros - leading_zeros
4047
}
4148

49+
/// An iterator over the coefficients of the polynomial.
50+
///
51+
/// Yields value in "little endian" order; that is, the constant term is returned first.
52+
///
53+
/// # Panics
54+
///
55+
/// Panics if [`Self::has_data`] is false.
56+
pub fn iter(&self) -> slice::Iter<F> {
57+
self.assert_has_data();
58+
self.inner.iter()
59+
}
60+
4261
/// The leading term of the polynomial.
4362
///
4463
/// For the constant 0 polynomial, will return 0.
@@ -55,7 +74,15 @@ impl<F: Field> Polynomial<F> {
5574
/// factor of the polynomial.
5675
pub fn zero_is_root(&self) -> bool { self.inner.is_empty() || self.leading_term() == F::ZERO }
5776

58-
/// An iterator over the roots of the residue, when interpreted as a polynomial.
77+
/// Helper function to add leading 0 terms until the polynomial has a specified
78+
/// length.
79+
fn zero_pad_up_to(&mut self, len: usize) {
80+
while self.inner.len() < len {
81+
self.inner.push(F::default());
82+
}
83+
}
84+
85+
/// An iterator over the roots of the polynomial.
5986
///
6087
/// Takes a base element `base`. The roots of the residue will be yielded as
6188
/// nonnegative integers between 0 and 1 less than the order of the base,
@@ -201,6 +228,19 @@ impl<F: Field> Polynomial<F> {
201228
}
202229
}
203230

231+
impl<F: Field> fmt::Display for Polynomial<F> {
232+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
233+
if self.has_data() {
234+
for fe in self.iter() {
235+
write!(f, "{}", fe)?;
236+
}
237+
Ok(())
238+
} else {
239+
f.write_str("<residue>")
240+
}
241+
}
242+
}
243+
204244
impl<F: Field> iter::FromIterator<F> for Polynomial<F> {
205245
#[inline]
206246
fn from_iter<I>(iter: I) -> Self
@@ -215,6 +255,59 @@ impl<F> From<FieldVec<F>> for Polynomial<F> {
215255
fn from(inner: FieldVec<F>) -> Self { Self { inner } }
216256
}
217257

258+
impl<F: Field> ops::Add<&Polynomial<F>> for Polynomial<F> {
259+
type Output = Polynomial<F>;
260+
261+
fn add(mut self, other: &Polynomial<F>) -> Polynomial<F> {
262+
self += other;
263+
self
264+
}
265+
}
266+
267+
impl<F: Field> ops::Add<Polynomial<F>> for Polynomial<F> {
268+
type Output = Polynomial<F>;
269+
fn add(self, other: Polynomial<F>) -> Polynomial<F> { self + &other }
270+
}
271+
272+
impl<F: Field> ops::Sub<&Polynomial<F>> for Polynomial<F> {
273+
type Output = Polynomial<F>;
274+
fn sub(mut self, other: &Polynomial<F>) -> Polynomial<F> {
275+
self -= other;
276+
self
277+
}
278+
}
279+
280+
impl<F: Field> ops::Sub<Polynomial<F>> for Polynomial<F> {
281+
type Output = Polynomial<F>;
282+
fn sub(self, other: Polynomial<F>) -> Polynomial<F> { self - &other }
283+
}
284+
285+
impl<F: Field> ops::AddAssign<&Polynomial<F>> for Polynomial<F> {
286+
fn add_assign(&mut self, other: &Self) {
287+
self.zero_pad_up_to(other.inner.len());
288+
for i in 0..other.inner.len() {
289+
self.inner[i] += &other.inner[i];
290+
}
291+
}
292+
}
293+
294+
impl<F: Field> ops::AddAssign for Polynomial<F> {
295+
fn add_assign(&mut self, other: Polynomial<F>) { *self += &other; }
296+
}
297+
298+
impl<F: Field> ops::SubAssign<&Polynomial<F>> for Polynomial<F> {
299+
fn sub_assign(&mut self, other: &Polynomial<F>) {
300+
self.zero_pad_up_to(other.inner.len());
301+
for i in 0..other.inner.len() {
302+
self.inner[i] -= &other.inner[i];
303+
}
304+
}
305+
}
306+
307+
impl<F: Field> ops::SubAssign for Polynomial<F> {
308+
fn sub_assign(&mut self, other: Polynomial<F>) { *self -= &other; }
309+
}
310+
218311
/// An iterator over the roots of a polynomial.
219312
///
220313
/// This iterator is constructed by the [`Polynomial::find_nonzero_distinct_roots`]

0 commit comments

Comments
 (0)