use crate::{BoundedPowers, TwoAdicField};
#[derive(Clone, Copy, Debug)]
pub struct TwoAdicMultiplicativeCoset<F: TwoAdicField> {
shift: F,
shift_inverse: F,
log_size: usize,
}
impl<F: TwoAdicField> TwoAdicMultiplicativeCoset<F> {
#[must_use]
pub fn new(shift: F, log_size: usize) -> Option<Self> {
(shift != F::ZERO && log_size <= F::TWO_ADICITY).then(|| {
let shift_inverse = shift.inverse();
Self {
shift,
shift_inverse,
log_size,
}
})
}
#[inline]
#[must_use]
pub fn subgroup_generator(&self) -> F {
F::two_adic_generator(self.log_size)
}
#[inline]
#[must_use]
pub const fn shift(&self) -> F {
self.shift
}
#[inline]
#[must_use]
pub const fn shift_inverse(&self) -> F {
self.shift_inverse
}
#[inline]
#[must_use]
pub const fn log_size(&self) -> usize {
self.log_size
}
#[inline]
#[must_use]
pub const fn size(&self) -> usize {
1 << self.log_size
}
#[inline]
#[must_use]
pub fn shrink_coset(&self, log_scale_factor: usize) -> Option<Self> {
self.log_size
.checked_sub(log_scale_factor)
.map(|new_log_size| Self {
shift: self.shift,
shift_inverse: self.shift_inverse,
log_size: new_log_size,
})
}
#[inline]
#[must_use]
pub fn exp_power_of_2(&self, log_scale_factor: usize) -> Option<Self> {
self.shrink_coset(log_scale_factor).map(|mut coset| {
coset.shift = self.shift.exp_power_of_2(log_scale_factor);
coset.shift_inverse = self.shift_inverse.exp_power_of_2(log_scale_factor);
coset
})
}
#[inline]
#[must_use]
pub fn shift_by(&self, scale: F) -> Self {
let shift = self.shift * scale;
Self {
shift,
shift_inverse: shift.inverse(),
log_size: self.log_size,
}
}
#[inline]
#[must_use]
pub fn set_shift(&self, shift: F) -> Self {
Self {
shift,
shift_inverse: shift.inverse(),
log_size: self.log_size,
}
}
#[inline]
#[must_use]
pub fn contains(&self, element: F) -> bool {
let (mut shift, mut element) = (self.shift, element);
for _ in 0..self.log_size {
if element == shift {
return true;
}
element = element.square();
shift = shift.square();
}
element == shift
}
#[inline]
#[must_use]
pub fn element(&mut self, index: usize) -> F {
self.shift * self.generator_exp(index)
}
#[inline]
#[must_use]
fn generator_exp(&self, exp: usize) -> F {
let mut gen_power = F::ONE;
let mut exp = exp & (self.size() - 1);
let mut i = self.log_size();
while exp > 0 {
if exp & 1 != 0 {
gen_power *= F::two_adic_generator(i);
}
exp >>= 1;
i -= 1;
}
gen_power
}
#[inline]
#[must_use]
pub fn iter(&self) -> BoundedPowers<F> {
self.subgroup_generator()
.shifted_powers(self.shift)
.take(self.size())
}
}
impl<F: TwoAdicField> IntoIterator for TwoAdicMultiplicativeCoset<F> {
type Item = F;
type IntoIter = BoundedPowers<F>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<F: TwoAdicField> IntoIterator for &TwoAdicMultiplicativeCoset<F> {
type Item = F;
type IntoIter = BoundedPowers<F>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}