Skip to content

Commit f47ec0b

Browse files
committed
field: add Powers iterator
This adds some new methods to Field, which have default impls and are therefore non-breaking. (And they are general-purpose "field" things.)
1 parent c389d72 commit f47ec0b

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

src/primitives/field.rs

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

33
//! Generic Field Traits
44
5+
use core::iter::{Skip, Take};
56
use core::{fmt, hash, iter, ops};
67

78
/// A generic field.
@@ -88,6 +89,20 @@ pub trait Field:
8889
"bug: `ExtensionField::MULTIPLICATIVE_ORDER_FACTORS` did not include full group order"
8990
);
9091
}
92+
93+
/// Constructs an iterator over all the powers of an element from 0 onward.
94+
fn powers(self) -> Powers<Self> { Powers { base: self, next: Self::ONE } }
95+
96+
/// Constructs an iterator over all the powers of an element within a given range.
97+
///
98+
/// # Panics
99+
///
100+
/// Panics if given a range whose start is greater than its end, or whose range
101+
/// is from 0 to `usize::MAX`. Its intended use is with [`crate::Checksum::ROOT_EXPONENTS`]
102+
/// for which neither of these conditions should ever be true.
103+
fn powers_range(self, range: ops::RangeInclusive<usize>) -> Take<Skip<Powers<Self>>> {
104+
self.powers().skip(*range.start()).take(*range.end() - range.start() + 1)
105+
}
91106
}
92107

93108
/// Trait describing a simple extension field (field obtained from another by
@@ -338,3 +353,35 @@ macro_rules! impl_ops_for_fe {
338353
};
339354
}
340355
pub(super) use impl_ops_for_fe;
356+
357+
/// An iterator over the powers of a field, starting from zero.
358+
///
359+
/// This iterator starts from 1, but has an optimized version of [`Iterator::nth`]
360+
/// which allows efficient construction.
361+
pub struct Powers<F: Field> {
362+
base: F,
363+
next: F,
364+
}
365+
366+
impl<F: Field> Iterator for Powers<F> {
367+
type Item = F;
368+
369+
fn next(&mut self) -> Option<F> {
370+
let ret = Some(self.next.clone());
371+
self.next *= &self.base;
372+
ret
373+
}
374+
375+
/// Compute next by calling `F::powi`.
376+
///
377+
/// The default implementation of `nth` will simply call the iterator `n`
378+
/// times, throwing away the result, which takes O(n) field multiplications.
379+
/// For a power iterator we can do much better, taking O(log(n)) multiplications.
380+
///
381+
/// This is important because this method is called internally by `Iterator::skip`.
382+
fn nth(&mut self, n: usize) -> Option<F> {
383+
let ni64 = (n % F::MULTIPLICATIVE_ORDER) as i64; // cast ok since modulus should be small
384+
self.next *= self.base.powi(ni64);
385+
self.next()
386+
}
387+
}

0 commit comments

Comments
 (0)