#[cfg(test)]
use alloc::vec;
#[cfg(test)]
use alloc::vec::Vec;
use p3_field::extension::Complex;
#[cfg(test)]
use p3_field::extension::ComplexExtendable;
use p3_field::{ExtensionField, Field};
#[cfg(test)]
use p3_matrix::dense::RowMajorMatrix;
#[cfg(test)]
use p3_util::{log2_strict_usize, reverse_slice_index_bits};
#[cfg(test)]
pub(crate) fn circle_basis<F: ComplexExtendable>(point: Complex<F>, log_n: usize) -> Vec<F> {
if log_n == 0 {
return vec![F::one()];
}
let mut basis = vec![F::one()];
basis.reserve(1 << log_n);
let mut cur = point.real();
for _ in 0..(log_n - 1) {
for i in 0..basis.len() {
basis.push(basis[i] * cur);
}
cur = F::two() * cur.square() - F::one();
}
reverse_slice_index_bits(&mut basis);
for i in 0..basis.len() {
basis.push(basis[i] * point.imag());
}
for (i, val) in basis.iter_mut().enumerate() {
let num_adjacent_ones = (i & (i >> 1)).count_ones();
if num_adjacent_ones % 2 == 1 {
*val = -*val;
}
}
basis
}
#[cfg(test)]
pub(crate) fn eval_circle_polys<F: ComplexExtendable>(
coeffs: &RowMajorMatrix<F>,
point: Complex<F>,
) -> Vec<F> {
use p3_matrix::Matrix;
let log_n = log2_strict_usize(coeffs.height());
coeffs.columnwise_dot_product(&circle_basis(point, log_n))
}
pub(crate) fn univariate_to_point<F: Field>(t: F) -> Option<Complex<F>> {
let t2 = t.square();
let inv_denom = (F::one() + t2).try_inverse()?;
Some(Complex::new(
(F::one() - t2) * inv_denom,
t.double() * inv_denom,
))
}
pub(crate) fn point_to_univariate<F: Field>(p: Complex<F>) -> Option<F> {
p.imag().try_div(p.real() + F::one())
}
#[allow(unused)]
pub(crate) fn rotate_univariate<F: Field, EF: ExtensionField<F>>(t1: EF, t2: F) -> Option<EF> {
(t1 + t2).try_div(EF::one() - t1 * t2)
}
pub(crate) fn v_n<F: Field>(mut p_x: F, log_n: usize) -> F {
for _ in 0..(log_n - 1) {
p_x = p_x.square().double() - F::one();
}
p_x
}
fn v_n_prime<F: Field>(p_x: F, log_n: usize) -> F {
F::two().exp_u64((2 * (log_n - 1)) as u64) * (1..log_n).map(|i| v_n(p_x, i)).product()
}
pub(crate) fn v_0<F: Field>(p: Complex<F>) -> F {
p.imag() / (p.real() + F::one())
}
pub(crate) fn s_p_at_p<F: Field>(p_x: F, p_y: F, log_n: usize) -> F {
-F::two() * v_n_prime(p_x, log_n) * p_y
}
#[cfg(test)]
mod tests {
use p3_field::AbstractField;
use p3_mersenne_31::Mersenne31;
use super::*;
type F = Mersenne31;
type C = Complex<F>;
#[test]
fn test_uni_to_point() {
assert_eq!(univariate_to_point(F::zero()), Some(C::new_real(F::one())));
assert_eq!(univariate_to_point(F::one()), Some(C::new_imag(F::one())));
assert_eq!(
univariate_to_point(F::neg_one()),
Some(C::new_imag(F::neg_one()))
);
}
#[test]
fn test_s_p_at_p() {
assert_eq!(
s_p_at_p(
F::from_canonical_u32(383393203),
F::from_canonical_u32(415518596),
3
),
F::from_canonical_u32(1612953309)
);
}
}