1use alloc::vec;
2use alloc::vec::Vec;
3use core::iter::Sum;
4use core::mem::{ManuallyDrop, MaybeUninit};
5use core::ops::Mul;
6
7use num_bigint::BigUint;
8use p3_maybe_rayon::prelude::{IntoParallelRefMutIterator, ParallelIterator};
9
10use crate::field::Field;
11use crate::{FieldAlgebra, PackedValue, PrimeField, PrimeField32, TwoAdicField};
12
13pub fn two_adic_subgroup_zerofier<F: TwoAdicField>(log_n: usize, x: F) -> F {
15 x.exp_power_of_2(log_n) - F::ONE
16}
17
18pub fn two_adic_coset_zerofier<F: TwoAdicField>(log_n: usize, shift: F, x: F) -> F {
21 x.exp_power_of_2(log_n) - shift.exp_power_of_2(log_n)
22}
23
24pub fn cyclic_subgroup_known_order<F: Field>(
26 generator: F,
27 order: usize,
28) -> impl Iterator<Item = F> + Clone {
29 generator.powers().take(order)
30}
31
32pub fn cyclic_subgroup_coset_known_order<F: Field>(
34 generator: F,
35 shift: F,
36 order: usize,
37) -> impl Iterator<Item = F> + Clone {
38 generator.shifted_powers(shift).take(order)
39}
40
41#[must_use]
42pub fn add_vecs<F: Field>(v: Vec<F>, w: Vec<F>) -> Vec<F> {
43 assert_eq!(v.len(), w.len());
44 v.into_iter().zip(w).map(|(x, y)| x + y).collect()
45}
46
47pub fn sum_vecs<F: Field, I: Iterator<Item = Vec<F>>>(iter: I) -> Vec<F> {
48 iter.reduce(|v, w| add_vecs(v, w))
49 .expect("sum_vecs: empty iterator")
50}
51
52pub fn scale_vec<F: Field>(s: F, vec: Vec<F>) -> Vec<F> {
53 vec.into_iter().map(|x| s * x).collect()
54}
55
56pub fn scale_slice_in_place<F: Field>(s: F, slice: &mut [F]) {
57 let (packed, sfx) = F::Packing::pack_slice_with_suffix_mut(slice);
58 let packed_s: F::Packing = s.into();
59 packed.par_iter_mut().for_each(|x| *x *= packed_s);
60 sfx.iter_mut().for_each(|x| *x *= s);
61}
62
63pub fn add_scaled_slice_in_place<F, Y>(x: &mut [F], y: Y, s: F)
65where
66 F: Field,
67 Y: Iterator<Item = F>,
68{
69 x.iter_mut().zip(y).for_each(|(x_i, y_i)| *x_i += y_i * s);
71}
72
73union HackyWorkAround<T, const D: usize> {
106 complete: ManuallyDrop<MaybeUninit<[T; D]>>,
107 elements: ManuallyDrop<[MaybeUninit<T>; D]>,
108}
109
110impl<T, const D: usize> HackyWorkAround<T, D> {
111 const fn transpose(arr: [MaybeUninit<T>; D]) -> MaybeUninit<[T; D]> {
112 let transpose = Self {
116 elements: ManuallyDrop::new(arr),
117 };
118 unsafe { ManuallyDrop::into_inner(transpose.complete) }
119 }
120}
121
122#[inline]
125pub const fn field_to_array<FA: FieldAlgebra, const D: usize>(x: FA) -> [FA; D] {
126 let mut arr: [MaybeUninit<FA>; D] = unsafe { MaybeUninit::uninit().assume_init() };
127
128 arr[0] = MaybeUninit::new(x);
129 let mut acc = 1;
130 loop {
131 if acc == D {
132 break;
133 }
134 arr[acc] = MaybeUninit::new(FA::ZERO);
135 acc += 1;
136 }
137 unsafe { HackyWorkAround::transpose(arr).assume_init() }
141}
142
143pub fn naive_poly_mul<FA: FieldAlgebra>(a: &[FA], b: &[FA]) -> Vec<FA> {
145 let mut product = vec![FA::ZERO; a.len() + b.len() - 1];
147 for (i, c1) in a.iter().enumerate() {
148 for (j, c2) in b.iter().enumerate() {
149 product[i + j] += c1.clone() * c2.clone();
150 }
151 }
152 product
153}
154
155pub fn binomial_expand<FA: FieldAlgebra>(roots: &[FA]) -> Vec<FA> {
157 let mut coeffs = vec![FA::ZERO; roots.len() + 1];
158 coeffs[0] = FA::ONE;
159 for (i, x) in roots.iter().enumerate() {
160 for j in (1..i + 2).rev() {
161 coeffs[j] = coeffs[j - 1].clone() - x.clone() * coeffs[j].clone();
162 }
163 coeffs[0] *= -x.clone();
164 }
165 coeffs
166}
167
168pub fn eval_poly<FA: FieldAlgebra>(poly: &[FA], x: FA) -> FA {
169 let mut acc = FA::ZERO;
170 for coeff in poly.iter().rev() {
171 acc *= x.clone();
172 acc += coeff.clone();
173 }
174 acc
175}
176
177#[inline]
179pub fn halve_u32<const P: u32>(input: u32) -> u32 {
180 let shift = (P + 1) >> 1;
181 let shr = input >> 1;
182 let lo_bit = input & 1;
183 let shr_corr = shr + shift;
184 if lo_bit == 0 {
185 shr
186 } else {
187 shr_corr
188 }
189}
190
191#[inline]
193pub fn halve_u64<const P: u64>(input: u64) -> u64 {
194 let shift = (P + 1) >> 1;
195 let shr = input >> 1;
196 let lo_bit = input & 1;
197 let shr_corr = shr + shift;
198 if lo_bit == 0 {
199 shr
200 } else {
201 shr_corr
202 }
203}
204
205pub fn reduce_32<SF: PrimeField32, TF: PrimeField>(vals: &[SF]) -> TF {
207 let po2 = TF::from_canonical_u64(1u64 << 32);
208 let mut result = TF::ZERO;
209 for val in vals.iter().rev() {
210 result = result * po2 + TF::from_canonical_u32(val.as_canonical_u32());
211 }
212 result
213}
214
215pub fn split_32<SF: PrimeField, TF: PrimeField32>(val: SF, n: usize) -> Vec<TF> {
220 let po2 = BigUint::from(1u128 << 64);
221 let mut val = val.as_canonical_biguint();
222 let mut result = Vec::new();
223 for _ in 0..n {
224 let mask: BigUint = po2.clone() - BigUint::from(1u128);
225 let digit: BigUint = val.clone() & mask;
226 let digit_u64s = digit.to_u64_digits();
227 if !digit_u64s.is_empty() {
228 result.push(TF::from_wrapped_u64(digit_u64s[0]));
229 } else {
230 result.push(TF::ZERO)
231 }
232 val /= po2.clone();
233 }
234 result
235}
236
237pub fn dot_product<S, LI, RI>(li: LI, ri: RI) -> S
239where
240 LI: Iterator,
241 RI: Iterator,
242 LI::Item: Mul<RI::Item>,
243 S: Sum<<LI::Item as Mul<RI::Item>>::Output>,
244{
245 li.zip(ri).map(|(l, r)| l * r).sum()
246}