use crate::field::{
element::FieldElement,
traits::{IsFFTField, RootsConfig},
};
use alloc::vec::Vec;
use crate::fft::errors::FFTError;
use super::bit_reversing::in_place_bit_reverse_permute;
pub fn get_powers_of_primitive_root<F: IsFFTField>(
n: u64,
count: usize,
config: RootsConfig,
) -> Result<Vec<FieldElement<F>>, FFTError> {
if count == 0 {
return Ok(Vec::new());
}
let root = match config {
RootsConfig::Natural | RootsConfig::BitReverse => F::get_primitive_root_of_unity(n)?,
_ => F::get_primitive_root_of_unity(n)?.inv().unwrap(),
};
let up_to = match config {
RootsConfig::Natural | RootsConfig::NaturalInversed => count,
_ => count.next_power_of_two(),
};
let mut results = Vec::with_capacity(up_to);
results.extend((0..up_to).scan(FieldElement::one(), |state, _| {
let res = state.clone();
*state = &(*state) * &root;
Some(res)
}));
if matches!(
config,
RootsConfig::BitReverse | RootsConfig::BitReverseInversed
) {
in_place_bit_reverse_permute(&mut results);
}
Ok(results)
}
pub fn get_powers_of_primitive_root_coset<F: IsFFTField>(
n: u64,
count: usize,
offset: &FieldElement<F>,
) -> Result<Vec<FieldElement<F>>, FFTError> {
let root = F::get_primitive_root_of_unity(n)?;
let results = (0..count).map(|i| offset * root.pow(i));
Ok(results.collect())
}
pub fn get_twiddles<F: IsFFTField>(
order: u64,
config: RootsConfig,
) -> Result<Vec<FieldElement<F>>, FFTError> {
if order > 63 {
return Err(FFTError::OrderError(order));
}
get_powers_of_primitive_root(order, (1 << order) / 2, config)
}
#[cfg(test)]
mod tests {
use crate::{
fft::{
cpu::{bit_reversing::in_place_bit_reverse_permute, roots_of_unity::get_twiddles},
errors::FFTError,
},
field::{test_fields::u64_test_field::U64TestField, traits::RootsConfig},
};
use alloc::format;
use proptest::prelude::*;
type F = U64TestField;
proptest! {
#[test]
fn test_gen_twiddles_bit_reversed_validity(n in 1..8_u64) {
let twiddles = get_twiddles::<F>(n, RootsConfig::Natural).unwrap();
let mut twiddles_to_reorder = get_twiddles(n, RootsConfig::BitReverse).unwrap();
in_place_bit_reverse_permute(&mut twiddles_to_reorder); prop_assert_eq!(twiddles, twiddles_to_reorder);
}
}
#[test]
fn gen_twiddles_with_order_greater_than_63_should_fail() {
let twiddles = get_twiddles::<F>(64, RootsConfig::Natural);
assert!(matches!(twiddles, Err(FFTError::OrderError(_))));
}
}