1use alloc::vec::Vec;
2use core::iter::Sum;
3use core::mem::MaybeUninit;
4use core::ops::Mul;
5
6use p3_maybe_rayon::prelude::*;
7
8use crate::field::Field;
9use crate::{PackedValue, PrimeCharacteristicRing, PrimeField, PrimeField32};
10
11pub fn cyclic_subgroup_known_order<F: Field>(
13 generator: F,
14 order: usize,
15) -> impl Iterator<Item = F> + Clone {
16 generator.powers().take(order)
17}
18
19pub fn cyclic_subgroup_coset_known_order<F: Field>(
21 generator: F,
22 shift: F,
23 order: usize,
24) -> impl Iterator<Item = F> + Clone {
25 generator.shifted_powers(shift).take(order)
26}
27
28pub fn scale_slice_in_place_single_core<F: Field>(slice: &mut [F], s: F) {
37 let (packed, sfx) = F::Packing::pack_slice_with_suffix_mut(slice);
38 let packed_s: F::Packing = s.into();
39 packed.iter_mut().for_each(|x| *x *= packed_s);
40 sfx.iter_mut().for_each(|x| *x *= s);
41}
42
43#[inline]
49pub fn par_scale_slice_in_place<F: Field>(slice: &mut [F], s: F) {
50 let (packed, sfx) = F::Packing::pack_slice_with_suffix_mut(slice);
51 let packed_s: F::Packing = s.into();
52 packed.par_iter_mut().for_each(|x| *x *= packed_s);
53 sfx.iter_mut().for_each(|x| *x *= s);
54}
55
56#[deprecated(
59 note = "use `par_scale_slice_in_place` instead which will replace this method in the future"
60)]
61pub fn scale_slice_in_place<F: Field>(s: F, slice: &mut [F]) {
62 par_scale_slice_in_place(slice, s)
63}
64
65pub fn add_scaled_slice_in_place<F: Field>(slice: &mut [F], other: &[F], s: F) {
70 debug_assert_eq!(slice.len(), other.len(), "slices must have equal length");
71 let (slice_packed, slice_sfx) = F::Packing::pack_slice_with_suffix_mut(slice);
72 let (other_packed, other_sfx) = F::Packing::pack_slice_with_suffix(other);
73 let packed_s: F::Packing = s.into();
74 slice_packed
75 .iter_mut()
76 .zip(other_packed)
77 .for_each(|(x, y)| *x += *y * packed_s);
78 slice_sfx
79 .iter_mut()
80 .zip(other_sfx)
81 .for_each(|(x, y)| *x += *y * s);
82}
83
84pub fn par_add_scaled_slice_in_place<F: Field>(slice: &mut [F], other: &[F], s: F) {
90 debug_assert_eq!(slice.len(), other.len(), "slices must have equal length");
91 let (slice_packed, slice_sfx) = F::Packing::pack_slice_with_suffix_mut(slice);
92 let (other_packed, other_sfx) = F::Packing::pack_slice_with_suffix(other);
93 let packed_s: F::Packing = s.into();
94 slice_packed
95 .par_iter_mut()
96 .zip(other_packed.par_iter())
97 .for_each(|(x, y)| *x += *y * packed_s);
98 slice_sfx
99 .iter_mut()
100 .zip(other_sfx)
101 .for_each(|(x, y)| *x += *y * s);
102}
103
104#[inline]
107pub const fn field_to_array<R: PrimeCharacteristicRing, const D: usize>(x: R) -> [R; D] {
108 let mut arr = [const { MaybeUninit::uninit() }; D];
109 arr[0] = MaybeUninit::new(x);
110 let mut i = 1;
111 while i < D {
112 arr[i] = MaybeUninit::new(R::ZERO);
113 i += 1;
114 }
115 unsafe { core::mem::transmute_copy::<_, [R; D]>(&arr) }
116}
117
118#[inline]
120pub const fn halve_u32<const P: u32>(x: u32) -> u32 {
121 let shift = (P + 1) >> 1;
122 let half = x >> 1;
123 if x & 1 == 0 { half } else { half + shift }
124}
125
126#[inline]
128pub const fn halve_u64<const P: u64>(x: u64) -> u64 {
129 let shift = (P + 1) >> 1;
130 let half = x >> 1;
131 if x & 1 == 0 { half } else { half + shift }
132}
133
134pub fn reduce_32<SF: PrimeField32, TF: PrimeField>(vals: &[SF]) -> TF {
144 let base = TF::from_int(1u64 << 32);
146 vals.iter().rev().fold(TF::ZERO, |acc, val| {
147 acc * base + TF::from_int(val.as_canonical_u32())
148 })
149}
150
151pub fn split_32<SF: PrimeField, TF: PrimeField32>(val: SF, n: usize) -> Vec<TF> {
162 let mut result: Vec<TF> = val
163 .as_canonical_biguint()
164 .to_u64_digits()
165 .iter()
166 .take(n)
167 .map(|d| TF::from_u64(*d))
168 .collect();
169
170 result.resize_with(n, || TF::ZERO);
172 result
173}
174
175pub fn dot_product<S, LI, RI>(li: LI, ri: RI) -> S
177where
178 LI: Iterator,
179 RI: Iterator,
180 LI::Item: Mul<RI::Item>,
181 S: Sum<<LI::Item as Mul<RI::Item>>::Output>,
182{
183 li.zip(ri).map(|(l, r)| l * r).sum()
184}