let (tmp_first, tmp_second) = tmp.split_at_mut(half_n); let (y_sub_first, y_sub_second) = y_sub.split_at_mut(half_n); let (roots_sub_first, roots_sub_second) = roots_sub.split_at_mut(half_n);
// Recurse on the first half for i in0..half_n {
y_sub_first[i] = ys[i] + ys[i + half_n];
roots_sub_first[i] = roots[2 * i];
}
fft_recurse(
tmp_first,
half_n,
roots_sub_first,
y_sub_first,
tmp_second,
y_sub_second,
roots_sub_second,
); for i in0..half_n {
out[2 * i] = tmp_first[i];
}
// Recurse on the second half for i in0..half_n {
y_sub_first[i] = ys[i] - ys[i + half_n];
y_sub_first[i] *= roots[i];
}
fft_recurse(
tmp_first,
half_n,
roots_sub_first,
y_sub_first,
tmp_second,
y_sub_second,
roots_sub_second,
); for i in0..half_n {
out[2 * i + 1] = tmp[i];
}
}
/// Calculate `count` number of roots of unity of order `count` fn fft_get_roots<F: FftFriendlyFieldElement>(count: usize, invert: bool) -> Vec<F> { letmut roots = vec![F::zero(); count]; letmutgen = F::generator(); if invert { gen = gen.inv();
}
roots[0] = F::one(); let step_size = F::generator_order() / F::Integer::try_from(count).unwrap(); // generator for subgroup of order count gen = gen.pow(step_size);
roots[1] = gen;
for i in2..count {
roots[i] = gen * roots[i - 1];
}
// Returns a polynomial that evaluates to `0` if the input is in range `[start, end)`. Otherwise, // the output is not `0`. pub(crate) fn poly_range_check<F: FftFriendlyFieldElement>(start: usize, end: usize) -> Vec<F> { letmut p = vec![F::one()]; letmut q = [F::zero(), F::one()]; for i in start..end {
q[0] = -F::from(F::Integer::try_from(i).unwrap());
p = poly_mul(&p, &q);
}
p
}
#[cfg(test)] mod tests { usecrate::{
field::{
FftFriendlyFieldElement, Field64, FieldElement, FieldElementWithInteger, FieldPrio2,
},
polynomial::{
fft_get_roots, poly_deg, poly_eval, poly_fft, poly_mul, poly_range_check, PolyAuxMemory,
},
}; use rand::prelude::*; use std::convert::TryFrom;
#[test] fn test_roots() { let count = 128; let roots = fft_get_roots::<FieldPrio2>(count, false); let roots_inv = fft_get_roots::<FieldPrio2>(count, true);
for i in0..count {
assert_eq!(roots[i] * roots_inv[i], 1);
assert_eq!(roots[i].pow(u32::try_from(count).unwrap()), 1);
assert_eq!(roots_inv[i].pow(u32::try_from(count).unwrap()), 1);
}
}
#[test] fn test_poly_mul() { let p = [
Field64::from(u64::try_from(2).unwrap()),
Field64::from(u64::try_from(3).unwrap()),
];
let q = [
Field64::one(),
Field64::zero(),
Field64::from(u64::try_from(5).unwrap()),
];
let want = [
Field64::from(u64::try_from(2).unwrap()),
Field64::from(u64::try_from(3).unwrap()),
Field64::from(u64::try_from(10).unwrap()),
Field64::from(u64::try_from(15).unwrap()),
];
let got = poly_mul(&p, &q);
assert_eq!(&got, &want);
}
#[test] fn test_poly_range_check() { let start = 74; let end = 112; let p = poly_range_check(start, end);
// Check each number in the range. for i in start..end { let x = Field64::from(i as u64); let y = poly_eval(&p, x);
assert_eq!(y, Field64::zero(), "range check failed for {i}");
}
// Check the number below the range. let x = Field64::from((start - 1) as u64); let y = poly_eval(&p, x);
assert_ne!(y, Field64::zero());
// Check a number above the range. let x = Field64::from(end as u64); let y = poly_eval(&p, x);
assert_ne!(y, Field64::zero());
}
#[test] fn test_fft() { let count = 128; letmut mem = PolyAuxMemory::new(count / 2);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.