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]
193 fn apply_to_rows(&self, row_1: &mut [F], row_2: &mut [F]) {
194 let (shorts_1, suffix_1) = F::Packing::pack_slice_with_suffix_mut(row_1);
195 let (shorts_2, suffix_2) = F::Packing::pack_slice_with_suffix_mut(row_2);
196 debug_assert_eq!(shorts_1.len(), shorts_2.len());
197 debug_assert_eq!(suffix_1.len(), suffix_2.len());
198 let twiddle_packed = F::Packing::from(self.0);
199 let mut c1 = shorts_1.chunks_exact_mut(4);
200 let mut c2 = shorts_2.chunks_exact_mut(4);
201 for (p1, p2) in (&mut c1).zip(&mut c2) {
202 let a1 = p1[0];
203 let b1 = p1[1];
204 let c1_ = p1[2];
205 let d1 = p1[3];
206 let a2 = p2[0];
207 let b2 = p2[1];
208 let c2_ = p2[2];
209 let d2 = p2[3];
210 let a2t = a2 * twiddle_packed;
211 let b2t = b2 * twiddle_packed;
212 let c2t = c2_ * twiddle_packed;
213 let d2t = d2 * twiddle_packed;
214 p1[0] = a1 + a2t;
215 p2[0] = a1 - a2t;
216 p1[1] = b1 + b2t;
217 p2[1] = b1 - b2t;
218 p1[2] = c1_ + c2t;
219 p2[2] = c1_ - c2t;
220 p1[3] = d1 + d2t;
221 p2[3] = d1 - d2t;
222 }
223 for (x_1, x_2) in c1
224 .into_remainder()
225 .iter_mut()
226 .zip(c2.into_remainder().iter_mut())
227 {
228 let x_2_twiddle = *x_2 * twiddle_packed;
229 let new_x1 = *x_1 + x_2_twiddle;
230 *x_2 = *x_1 - x_2_twiddle;
231 *x_1 = new_x1;
232 }
233 for (x_1, x_2) in suffix_1.iter_mut().zip(suffix_2.iter_mut()) {
234 self.apply_in_place(x_1, x_2);
235 }
236 }
237
238 #[inline]
240 fn apply_to_rows_oop(
241 &self,
242 src_1: &[F],
243 dst_1: &mut [MaybeUninit<F>],
244 src_2: &[F],
245 dst_2: &mut [MaybeUninit<F>],
246 ) {
247 let (src_shorts_1, src_suffix_1) = F::Packing::pack_slice_with_suffix(src_1);
248 let (src_shorts_2, src_suffix_2) = F::Packing::pack_slice_with_suffix(src_2);
249 let (dst_shorts_1, dst_suffix_1) =
250 F::Packing::pack_maybe_uninit_slice_with_suffix_mut(dst_1);
251 let (dst_shorts_2, dst_suffix_2) =
252 F::Packing::pack_maybe_uninit_slice_with_suffix_mut(dst_2);
253 debug_assert_eq!(src_shorts_1.len(), src_shorts_2.len());
254 debug_assert_eq!(src_suffix_1.len(), src_suffix_2.len());
255 debug_assert_eq!(dst_shorts_1.len(), dst_shorts_2.len());
256 debug_assert_eq!(dst_suffix_1.len(), dst_suffix_2.len());
257 let twiddle_packed = F::Packing::from(self.0);
258 let n = src_shorts_1.len();
259 let n4 = n - (n & 3);
260 let mut i = 0;
261 while i < n4 {
262 let a1 = src_shorts_1[i];
263 let b1 = src_shorts_1[i + 1];
264 let c1 = src_shorts_1[i + 2];
265 let d1 = src_shorts_1[i + 3];
266 let a2 = src_shorts_2[i];
267 let b2 = src_shorts_2[i + 1];
268 let c2 = src_shorts_2[i + 2];
269 let d2 = src_shorts_2[i + 3];
270 let a2t = a2 * twiddle_packed;
271 let b2t = b2 * twiddle_packed;
272 let c2t = c2 * twiddle_packed;
273 let d2t = d2 * twiddle_packed;
274 dst_shorts_1[i].write(a1 + a2t);
275 dst_shorts_2[i].write(a1 - a2t);
276 dst_shorts_1[i + 1].write(b1 + b2t);
277 dst_shorts_2[i + 1].write(b1 - b2t);
278 dst_shorts_1[i + 2].write(c1 + c2t);
279 dst_shorts_2[i + 2].write(c1 - c2t);
280 dst_shorts_1[i + 3].write(d1 + d2t);
281 dst_shorts_2[i + 3].write(d1 - d2t);
282 i += 4;
283 }
284 while i < n {
285 let s1 = src_shorts_1[i];
286 let s2 = src_shorts_2[i];
287 let x_2_twiddle = s2 * twiddle_packed;
288 dst_shorts_1[i].write(s1 + x_2_twiddle);
289 dst_shorts_2[i].write(s1 - x_2_twiddle);
290 i += 1;
291 }
292 for (s_1, s_2, d_1, d_2) in izip!(src_suffix_1, src_suffix_2, dst_suffix_1, dst_suffix_2) {
293 let (res_1, res_2) = self.apply(*s_1, *s_2);
294 d_1.write(res_1);
295 d_2.write(res_2);
296 }
297 }
298}
299
300#[derive(Copy, Clone)]
319pub struct ScaledDitButterfly<F> {
320 pub twiddle: F,
321 pub scale: F,
322 pub twiddle_times_scale: F,
324}
325
326impl<F: Field> ScaledDitButterfly<F> {
327 #[inline]
329 pub fn new(twiddle: F, scale: F) -> Self {
330 Self {
331 twiddle,
332 scale,
333 twiddle_times_scale: twiddle * scale,
334 }
335 }
336}
337
338impl<F: Field> Butterfly<F> for ScaledDitButterfly<F> {
339 #[inline]
340 fn apply<PF: PackedField<Scalar = F>>(&self, x_1: PF, x_2: PF) -> (PF, PF) {
341 let x_1_scale = x_1 * self.scale;
347 let x_2_twiddle_scale = x_2 * self.twiddle_times_scale;
348 (x_1_scale + x_2_twiddle_scale, x_1_scale - x_2_twiddle_scale)
349 }
350
351 #[inline]
354 fn apply_to_rows(&self, row_1: &mut [F], row_2: &mut [F]) {
355 let (shorts_1, suffix_1) = F::Packing::pack_slice_with_suffix_mut(row_1);
356 let (shorts_2, suffix_2) = F::Packing::pack_slice_with_suffix_mut(row_2);
357 debug_assert_eq!(shorts_1.len(), shorts_2.len());
358 debug_assert_eq!(suffix_1.len(), suffix_2.len());
359 let scale_packed = F::Packing::from(self.scale);
360 let twiddle_times_scale_packed = F::Packing::from(self.twiddle_times_scale);
361 let mut c1 = shorts_1.chunks_exact_mut(4);
364 let mut c2 = shorts_2.chunks_exact_mut(4);
365 for (p1, p2) in (&mut c1).zip(&mut c2) {
366 let a1 = p1[0];
367 let b1 = p1[1];
368 let c1_ = p1[2];
369 let d1 = p1[3];
370 let a2 = p2[0];
371 let b2 = p2[1];
372 let c2_ = p2[2];
373 let d2 = p2[3];
374 let a1s = a1 * scale_packed;
375 let b1s = b1 * scale_packed;
376 let c1s = c1_ * scale_packed;
377 let d1s = d1 * scale_packed;
378 let a2t = a2 * twiddle_times_scale_packed;
379 let b2t = b2 * twiddle_times_scale_packed;
380 let c2t = c2_ * twiddle_times_scale_packed;
381 let d2t = d2 * twiddle_times_scale_packed;
382 p1[0] = a1s + a2t;
383 p2[0] = a1s - a2t;
384 p1[1] = b1s + b2t;
385 p2[1] = b1s - b2t;
386 p1[2] = c1s + c2t;
387 p2[2] = c1s - c2t;
388 p1[3] = d1s + d2t;
389 p2[3] = d1s - d2t;
390 }
391 for (x_1, x_2) in c1
392 .into_remainder()
393 .iter_mut()
394 .zip(c2.into_remainder().iter_mut())
395 {
396 let x_1_scale = *x_1 * scale_packed;
397 let x_2_twiddle_scale = *x_2 * twiddle_times_scale_packed;
398 *x_1 = x_1_scale + x_2_twiddle_scale;
399 *x_2 = x_1_scale - x_2_twiddle_scale;
400 }
401 for (x_1, x_2) in suffix_1.iter_mut().zip(suffix_2.iter_mut()) {
402 self.apply_in_place(x_1, x_2);
403 }
404 }
405}
406
407#[derive(Copy, Clone)]
419pub struct TwiddleFreeButterfly;
420
421impl<F: Field> Butterfly<F> for TwiddleFreeButterfly {
422 #[inline]
423 fn apply<PF: PackedField<Scalar = F>>(&self, x_1: PF, x_2: PF) -> (PF, PF) {
424 (x_1 + x_2, x_1 - x_2)
425 }
426}