1use core::mem::MaybeUninit;
2
3use itertools::izip;
4use p3_field::{Field, PackedField, PackedValue};
5
6pub trait Butterfly<F: Field>: Copy + Send + Sync {
25 fn apply<PF: PackedField<Scalar = F>>(&self, x_1: PF, x_2: PF) -> (PF, PF);
35
36 #[inline]
40 fn apply_in_place<PF: PackedField<Scalar = F>>(&self, x_1: &mut PF, x_2: &mut PF) {
41 (*x_1, *x_2) = self.apply(*x_1, *x_2);
42 }
43
44 #[inline]
52 fn apply_to_rows(&self, row_1: &mut [F], row_2: &mut [F]) {
53 let (shorts_1, suffix_1) = F::Packing::pack_slice_with_suffix_mut(row_1);
54 let (shorts_2, suffix_2) = F::Packing::pack_slice_with_suffix_mut(row_2);
55 debug_assert_eq!(shorts_1.len(), shorts_2.len());
56 debug_assert_eq!(suffix_1.len(), suffix_2.len());
57 for (x_1, x_2) in shorts_1.iter_mut().zip(shorts_2) {
58 self.apply_in_place(x_1, x_2);
59 }
60 for (x_1, x_2) in suffix_1.iter_mut().zip(suffix_2) {
61 self.apply_in_place(x_1, x_2);
62 }
63 }
64
65 #[inline]
76 fn apply_to_rows_oop(
77 &self,
78 src_1: &[F],
79 dst_1: &mut [MaybeUninit<F>],
80 src_2: &[F],
81 dst_2: &mut [MaybeUninit<F>],
82 ) {
83 let (src_shorts_1, src_suffix_1) = F::Packing::pack_slice_with_suffix(src_1);
84 let (src_shorts_2, src_suffix_2) = F::Packing::pack_slice_with_suffix(src_2);
85 let (dst_shorts_1, dst_suffix_1) =
86 F::Packing::pack_maybe_uninit_slice_with_suffix_mut(dst_1);
87 let (dst_shorts_2, dst_suffix_2) =
88 F::Packing::pack_maybe_uninit_slice_with_suffix_mut(dst_2);
89 debug_assert_eq!(src_shorts_1.len(), src_shorts_2.len());
90 debug_assert_eq!(src_suffix_1.len(), src_suffix_2.len());
91 debug_assert_eq!(dst_shorts_1.len(), dst_shorts_2.len());
92 debug_assert_eq!(dst_suffix_1.len(), dst_suffix_2.len());
93 for (s_1, s_2, d_1, d_2) in izip!(src_shorts_1, src_shorts_2, dst_shorts_1, dst_shorts_2) {
94 let (res_1, res_2) = self.apply(*s_1, *s_2);
95 d_1.write(res_1);
96 d_2.write(res_2);
97 }
98 for (s_1, s_2, d_1, d_2) in izip!(src_suffix_1, src_suffix_2, dst_suffix_1, dst_suffix_2) {
99 let (res_1, res_2) = self.apply(*s_1, *s_2);
100 d_1.write(res_1);
101 d_2.write(res_2);
102 }
103 }
104}
105
106#[derive(Copy, Clone)]
117#[repr(transparent)] pub struct DifButterfly<F>(pub F);
119
120impl<F: Field> Butterfly<F> for DifButterfly<F> {
121 #[inline]
122 fn apply<PF: PackedField<Scalar = F>>(&self, x_1: PF, x_2: PF) -> (PF, PF) {
123 (x_1 + x_2, (x_1 - x_2) * self.0)
124 }
125}
126
127#[derive(Copy, Clone)]
138#[repr(transparent)] pub struct DifButterflyZeros<F>(pub F);
140
141impl<F: Field> Butterfly<F> for DifButterflyZeros<F> {
142 #[inline]
143 fn apply<PF: PackedField<Scalar = F>>(&self, x_1: PF, x_2: PF) -> (PF, PF) {
144 debug_assert!(x_2.as_slice().iter().all(|x| x.is_zero())); (x_1, x_1 * self.0)
146 }
147
148 #[inline]
149 fn apply_to_rows(&self, row_1: &mut [F], row_2: &mut [F]) {
150 let (shorts_1, suffix_1) = F::Packing::pack_slice_with_suffix(row_1);
151 let (shorts_2, suffix_2) = F::Packing::pack_slice_with_suffix_mut(row_2);
152 debug_assert_eq!(shorts_1.len(), shorts_2.len());
153 debug_assert_eq!(suffix_1.len(), suffix_2.len());
154 for (x_1, x_2) in shorts_1.iter().zip(shorts_2) {
155 debug_assert!(x_2.as_slice().iter().all(|x| x.is_zero())); *x_2 = *x_1 * self.0; }
158 for (x_1, x_2) in suffix_1.iter().zip(suffix_2) {
159 debug_assert!(x_2.is_zero());
160 *x_2 = *x_1 * self.0; }
162 }
163}
164
165#[derive(Copy, Clone)]
176#[repr(transparent)] pub struct DitButterfly<F>(pub F);
178
179impl<F: Field> Butterfly<F> for DitButterfly<F> {
180 #[inline]
181 fn apply<PF: PackedField<Scalar = F>>(&self, x_1: PF, x_2: PF) -> (PF, PF) {
182 let x_2_twiddle = x_2 * self.0;
183 (x_1 + x_2_twiddle, x_1 - x_2_twiddle)
184 }
185
186 #[inline]
191 fn apply_to_rows(&self, row_1: &mut [F], row_2: &mut [F]) {
192 let (shorts_1, suffix_1) = F::Packing::pack_slice_with_suffix_mut(row_1);
193 let (shorts_2, suffix_2) = F::Packing::pack_slice_with_suffix_mut(row_2);
194 debug_assert_eq!(shorts_1.len(), shorts_2.len());
195 debug_assert_eq!(suffix_1.len(), suffix_2.len());
196 let twiddle_packed = F::Packing::from(self.0);
198 for (x_1, x_2) in shorts_1.iter_mut().zip(shorts_2.iter_mut()) {
199 let x_2_twiddle = *x_2 * twiddle_packed;
200 let new_x1 = *x_1 + x_2_twiddle;
201 *x_2 = *x_1 - x_2_twiddle;
202 *x_1 = new_x1;
203 }
204 for (x_1, x_2) in suffix_1.iter_mut().zip(suffix_2.iter_mut()) {
205 self.apply_in_place(x_1, x_2);
206 }
207 }
208
209 #[inline]
211 fn apply_to_rows_oop(
212 &self,
213 src_1: &[F],
214 dst_1: &mut [MaybeUninit<F>],
215 src_2: &[F],
216 dst_2: &mut [MaybeUninit<F>],
217 ) {
218 let (src_shorts_1, src_suffix_1) = F::Packing::pack_slice_with_suffix(src_1);
219 let (src_shorts_2, src_suffix_2) = F::Packing::pack_slice_with_suffix(src_2);
220 let (dst_shorts_1, dst_suffix_1) =
221 F::Packing::pack_maybe_uninit_slice_with_suffix_mut(dst_1);
222 let (dst_shorts_2, dst_suffix_2) =
223 F::Packing::pack_maybe_uninit_slice_with_suffix_mut(dst_2);
224 debug_assert_eq!(src_shorts_1.len(), src_shorts_2.len());
225 debug_assert_eq!(src_suffix_1.len(), src_suffix_2.len());
226 debug_assert_eq!(dst_shorts_1.len(), dst_shorts_2.len());
227 debug_assert_eq!(dst_suffix_1.len(), dst_suffix_2.len());
228 let twiddle_packed = F::Packing::from(self.0);
230 for (s_1, s_2, d_1, d_2) in izip!(src_shorts_1, src_shorts_2, dst_shorts_1, dst_shorts_2) {
231 let x_2_twiddle = *s_2 * twiddle_packed;
232 d_1.write(*s_1 + x_2_twiddle);
233 d_2.write(*s_1 - x_2_twiddle);
234 }
235 for (s_1, s_2, d_1, d_2) in izip!(src_suffix_1, src_suffix_2, dst_suffix_1, dst_suffix_2) {
236 let (res_1, res_2) = self.apply(*s_1, *s_2);
237 d_1.write(res_1);
238 d_2.write(res_2);
239 }
240 }
241}
242
243#[derive(Copy, Clone)]
262pub struct ScaledDitButterfly<F> {
263 pub twiddle: F,
264 pub scale: F,
265 pub twiddle_times_scale: F,
267}
268
269impl<F: Field> ScaledDitButterfly<F> {
270 #[inline]
272 pub fn new(twiddle: F, scale: F) -> Self {
273 Self {
274 twiddle,
275 scale,
276 twiddle_times_scale: twiddle * scale,
277 }
278 }
279}
280
281impl<F: Field> Butterfly<F> for ScaledDitButterfly<F> {
282 #[inline]
283 fn apply<PF: PackedField<Scalar = F>>(&self, x_1: PF, x_2: PF) -> (PF, PF) {
284 let x_1_scale = x_1 * self.scale;
290 let x_2_twiddle_scale = x_2 * self.twiddle_times_scale;
291 (x_1_scale + x_2_twiddle_scale, x_1_scale - x_2_twiddle_scale)
292 }
293
294 #[inline]
297 fn apply_to_rows(&self, row_1: &mut [F], row_2: &mut [F]) {
298 let (shorts_1, suffix_1) = F::Packing::pack_slice_with_suffix_mut(row_1);
299 let (shorts_2, suffix_2) = F::Packing::pack_slice_with_suffix_mut(row_2);
300 debug_assert_eq!(shorts_1.len(), shorts_2.len());
301 debug_assert_eq!(suffix_1.len(), suffix_2.len());
302 let scale_packed = F::Packing::from(self.scale);
303 let twiddle_times_scale_packed = F::Packing::from(self.twiddle_times_scale);
304 for (x_1, x_2) in shorts_1.iter_mut().zip(shorts_2.iter_mut()) {
305 let x_1_scale = *x_1 * scale_packed;
306 let x_2_twiddle_scale = *x_2 * twiddle_times_scale_packed;
307 *x_1 = x_1_scale + x_2_twiddle_scale;
308 *x_2 = x_1_scale - x_2_twiddle_scale;
309 }
310 for (x_1, x_2) in suffix_1.iter_mut().zip(suffix_2.iter_mut()) {
311 self.apply_in_place(x_1, x_2);
312 }
313 }
314}
315
316#[derive(Copy, Clone)]
328pub struct TwiddleFreeButterfly;
329
330impl<F: Field> Butterfly<F> for TwiddleFreeButterfly {
331 #[inline]
332 fn apply<PF: PackedField<Scalar = F>>(&self, x_1: PF, x_2: PF) -> (PF, PF) {
333 (x_1 + x_2, x_1 - x_2)
334 }
335}