1use std::{
48 array,
49 fmt::Debug,
50 iter::{Product, Sum},
51 marker::PhantomData,
52 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
53};
54
55use bytemuck::Zeroable;
56use rand::distr::{Distribution, StandardUniform};
57
58use crate::{
59 Divisible, ExtensionField, Field, Maskable, PackedField, WideMul,
60 arithmetic_traits::{InvertOrZero, Square},
61 field::FieldOps,
62};
63
64#[repr(transparent)]
84pub struct SlicedPackedField<F, PSub, const N: usize>([PSub; N], PhantomData<F>);
85
86impl<F, PSub: Copy, const N: usize> Clone for SlicedPackedField<F, PSub, N> {
90 #[inline]
91 fn clone(&self) -> Self {
92 *self
93 }
94}
95
96impl<F, PSub: Copy, const N: usize> Copy for SlicedPackedField<F, PSub, N> {}
97
98impl<F, PSub: PartialEq, const N: usize> PartialEq for SlicedPackedField<F, PSub, N> {
99 #[inline]
100 fn eq(&self, other: &Self) -> bool {
101 self.0 == other.0
102 }
103}
104
105impl<F, PSub: Eq, const N: usize> Eq for SlicedPackedField<F, PSub, N> {}
106
107impl<F, PSub: PackedField, const N: usize> SlicedPackedField<F, PSub, N> {
108 #[inline]
110 pub const fn from_coords(coords: [PSub; N]) -> Self {
111 Self(coords, PhantomData)
112 }
113
114 #[inline]
116 pub const fn to_coords(self) -> [PSub; N] {
117 self.0
118 }
119}
120
121impl<F, PSub: PackedField, const N: usize> Default for SlicedPackedField<F, PSub, N> {
122 #[inline]
123 fn default() -> Self {
124 Self::from_coords([PSub::default(); N])
125 }
126}
127
128impl<F, PSub: PackedField, const N: usize> Debug for SlicedPackedField<F, PSub, N> {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 write!(f, "SlicedPacked<{N}>({:?})", self.0)
131 }
132}
133
134unsafe impl<F, PSub: Zeroable, const N: usize> Zeroable for SlicedPackedField<F, PSub, N> {}
137
138impl<F, PSub: PackedField, const N: usize> Neg for SlicedPackedField<F, PSub, N> {
141 type Output = Self;
142
143 #[inline]
144 fn neg(self) -> Self {
145 self
146 }
147}
148
149impl<F, PSub: PackedField, const N: usize> Add for SlicedPackedField<F, PSub, N> {
150 type Output = Self;
151
152 #[inline]
153 fn add(self, rhs: Self) -> Self {
154 Self::from_coords(array::from_fn(|j| self.0[j] + rhs.0[j]))
155 }
156}
157
158impl<F, PSub: PackedField, const N: usize> Sub for SlicedPackedField<F, PSub, N> {
159 type Output = Self;
160
161 #[inline]
162 fn sub(self, rhs: Self) -> Self {
163 Self::from_coords(array::from_fn(|j| self.0[j] - rhs.0[j]))
164 }
165}
166
167impl<F, PSub: PackedField, const N: usize> Add<&Self> for SlicedPackedField<F, PSub, N> {
168 type Output = Self;
169
170 #[inline]
171 fn add(self, rhs: &Self) -> Self {
172 self + *rhs
173 }
174}
175
176impl<F, PSub: PackedField, const N: usize> Sub<&Self> for SlicedPackedField<F, PSub, N> {
177 type Output = Self;
178
179 #[inline]
180 fn sub(self, rhs: &Self) -> Self {
181 self - *rhs
182 }
183}
184
185impl<F, PSub: PackedField, const N: usize> AddAssign for SlicedPackedField<F, PSub, N> {
186 #[inline]
187 fn add_assign(&mut self, rhs: Self) {
188 *self = *self + rhs;
189 }
190}
191
192impl<F, PSub: PackedField, const N: usize> SubAssign for SlicedPackedField<F, PSub, N> {
193 #[inline]
194 fn sub_assign(&mut self, rhs: Self) {
195 *self = *self - rhs;
196 }
197}
198
199impl<F, PSub: PackedField, const N: usize> AddAssign<&Self> for SlicedPackedField<F, PSub, N> {
200 #[inline]
201 fn add_assign(&mut self, rhs: &Self) {
202 *self = *self + *rhs;
203 }
204}
205
206impl<F, PSub: PackedField, const N: usize> SubAssign<&Self> for SlicedPackedField<F, PSub, N> {
207 #[inline]
208 fn sub_assign(&mut self, rhs: &Self) {
209 *self = *self - *rhs;
210 }
211}
212
213impl<F, PSub: PackedField, const N: usize> Sum for SlicedPackedField<F, PSub, N> {
214 #[inline]
215 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
216 iter.fold(Self::default(), |acc, x| acc + x)
217 }
218}
219
220impl<'a, F, PSub: PackedField, const N: usize> Sum<&'a Self> for SlicedPackedField<F, PSub, N> {
221 #[inline]
222 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
223 iter.fold(Self::default(), |acc, x| acc + *x)
224 }
225}
226
227impl<F, PSub: PackedField, const N: usize> Mul for SlicedPackedField<F, PSub, N>
230where
231 Self: WideMul,
232{
233 type Output = Self;
234
235 #[inline]
236 fn mul(self, rhs: Self) -> Self {
237 Self::reduce(Self::wide_mul(self, rhs))
238 }
239}
240
241impl<F, PSub: PackedField, const N: usize> Mul<&Self> for SlicedPackedField<F, PSub, N>
242where
243 Self: Mul<Output = Self>,
244{
245 type Output = Self;
246
247 #[inline]
248 fn mul(self, rhs: &Self) -> Self {
249 self * *rhs
250 }
251}
252
253impl<F, PSub: PackedField, const N: usize> MulAssign for SlicedPackedField<F, PSub, N>
254where
255 Self: Mul<Output = Self>,
256{
257 #[inline]
258 fn mul_assign(&mut self, rhs: Self) {
259 *self = *self * rhs;
260 }
261}
262
263impl<F, PSub: PackedField, const N: usize> MulAssign<&Self> for SlicedPackedField<F, PSub, N>
264where
265 Self: Mul<Output = Self>,
266{
267 #[inline]
268 fn mul_assign(&mut self, rhs: &Self) {
269 *self = *self * *rhs;
270 }
271}
272
273impl<F, PSub: PackedField, const N: usize> Product for SlicedPackedField<F, PSub, N>
274where
275 F: ExtensionField<PSub::Scalar>,
276 Self: Mul<Output = Self>,
277{
278 #[inline]
279 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
280 iter.fold(<Self as Divisible<F>>::broadcast(F::ONE), |acc, x| acc * x)
281 }
282}
283
284impl<'a, F, PSub: PackedField, const N: usize> Product<&'a Self> for SlicedPackedField<F, PSub, N>
285where
286 F: ExtensionField<PSub::Scalar>,
287 Self: Mul<Output = Self>,
288{
289 #[inline]
290 fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
291 iter.fold(<Self as Divisible<F>>::broadcast(F::ONE), |acc, x| acc * *x)
292 }
293}
294
295impl<F, PSub, const N: usize> Add<F> for SlicedPackedField<F, PSub, N>
298where
299 F: ExtensionField<PSub::Scalar>,
300 PSub: PackedField,
301{
302 type Output = Self;
303
304 #[inline]
305 fn add(self, rhs: F) -> Self {
306 self + <Self as Divisible<F>>::broadcast(rhs)
307 }
308}
309
310impl<F, PSub, const N: usize> Sub<F> for SlicedPackedField<F, PSub, N>
311where
312 F: ExtensionField<PSub::Scalar>,
313 PSub: PackedField,
314{
315 type Output = Self;
316
317 #[inline]
318 fn sub(self, rhs: F) -> Self {
319 self - <Self as Divisible<F>>::broadcast(rhs)
320 }
321}
322
323impl<F, PSub, const N: usize> Mul<F> for SlicedPackedField<F, PSub, N>
324where
325 F: ExtensionField<PSub::Scalar>,
326 PSub: PackedField,
327 Self: Mul<Output = Self>,
328{
329 type Output = Self;
330
331 #[inline]
332 fn mul(self, rhs: F) -> Self {
333 self * <Self as Divisible<F>>::broadcast(rhs)
334 }
335}
336
337impl<F, PSub, const N: usize> AddAssign<F> for SlicedPackedField<F, PSub, N>
338where
339 F: ExtensionField<PSub::Scalar>,
340 PSub: PackedField,
341{
342 #[inline]
343 fn add_assign(&mut self, rhs: F) {
344 *self = *self + rhs;
345 }
346}
347
348impl<F, PSub, const N: usize> SubAssign<F> for SlicedPackedField<F, PSub, N>
349where
350 F: ExtensionField<PSub::Scalar>,
351 PSub: PackedField,
352{
353 #[inline]
354 fn sub_assign(&mut self, rhs: F) {
355 *self = *self - rhs;
356 }
357}
358
359impl<F, PSub, const N: usize> MulAssign<F> for SlicedPackedField<F, PSub, N>
360where
361 F: ExtensionField<PSub::Scalar>,
362 PSub: PackedField,
363 Self: Mul<Output = Self>,
364{
365 #[inline]
366 fn mul_assign(&mut self, rhs: F) {
367 *self = *self * <Self as Divisible<F>>::broadcast(rhs);
368 }
369}
370
371impl<F, PSub, const N: usize> Divisible<F> for SlicedPackedField<F, PSub, N>
374where
375 F: ExtensionField<PSub::Scalar>,
376 PSub: PackedField,
377{
378 const LOG_N: usize = PSub::LOG_WIDTH;
380
381 #[inline]
382 fn value_iter(value: Self) -> impl ExactSizeIterator<Item = F> + Send + Clone {
383 (0..Self::N).map(move |i| unsafe { value.get_unchecked(i) })
384 }
385
386 #[inline]
387 fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = F> + Send + Clone + '_ {
388 let value = *value;
389 (0..Self::N).map(move |i| unsafe { value.get_unchecked(i) })
390 }
391
392 #[inline]
393 fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = F> + Send + Clone + '_ {
394 (0..slice.len() * Self::N).map(move |global| {
395 let (elem, lane) = (global / Self::N, global % Self::N);
396 unsafe { slice[elem].get_unchecked(lane) }
398 })
399 }
400
401 #[inline]
402 unsafe fn get_unchecked(&self, index: usize) -> F {
403 F::from_bases((0..N).map(|j| unsafe { self.0[j].get_unchecked(index) }))
406 }
407
408 #[inline]
409 unsafe fn set_unchecked(&mut self, index: usize, val: F) {
410 for (j, coord) in self.0.iter_mut().enumerate() {
411 unsafe {
414 coord.set_unchecked(index, val.get_base_unchecked(j));
415 }
416 }
417 }
418
419 #[inline]
420 fn broadcast(val: F) -> Self {
421 Self::from_coords(array::from_fn(|j| PSub::broadcast(val.get_base(j))))
422 }
423
424 #[inline]
425 fn from_iter(mut iter: impl Iterator<Item = F>) -> Self {
426 let mut result = Self::default();
427 for i in 0..Self::N {
428 match iter.next() {
429 Some(val) => result.set(i, val),
430 None => break,
431 }
432 }
433 result
434 }
435}
436
437impl<F, PSub, const N: usize> Maskable<F> for SlicedPackedField<F, PSub, N>
440where
441 F: ExtensionField<PSub::Scalar>,
442 PSub: PackedField,
443{
444 type Mask = PSub::Mask;
445
446 #[inline]
447 fn make_mask(selectors: impl Iterator<Item = bool>) -> Self::Mask {
448 PSub::make_mask(selectors)
449 }
450
451 #[inline]
452 fn select(&self, mask: &Self::Mask) -> Self {
453 Self::from_coords(array::from_fn(|j| self.0[j].select(mask)))
454 }
455}
456
457impl<F, PSub, const N: usize> FieldOps for SlicedPackedField<F, PSub, N>
458where
459 F: ExtensionField<PSub::Scalar>,
460 PSub: PackedField,
461 Self: Square + InvertOrZero + Mul<Output = Self>,
462{
463 type Scalar = F;
464
465 #[inline]
466 fn zero() -> Self {
467 Self::default()
468 }
469
470 #[inline]
471 fn one() -> Self {
472 <Self as Divisible<F>>::broadcast(F::ONE)
473 }
474
475 fn square_transpose<FSub: Field>(elems: &mut [Self])
476 where
477 F: ExtensionField<FSub>,
478 {
479 let degree = <F as ExtensionField<FSub>>::DEGREE;
480 assert_eq!(elems.len(), degree);
481
482 for lane in 0..PSub::WIDTH {
486 let column = (0..degree).map(|j| elems[j].get(lane)).collect::<Vec<F>>();
487 for (i, elem) in elems.iter_mut().enumerate() {
488 let transposed = <F as ExtensionField<FSub>>::from_bases(
489 (0..degree).map(|j| <F as ExtensionField<FSub>>::get_base(&column[j], i)),
490 );
491 elem.set(lane, transposed);
492 }
493 }
494 }
495}
496
497impl<F, PSub, const N: usize> PackedField for SlicedPackedField<F, PSub, N>
498where
499 F: ExtensionField<PSub::Scalar>,
500 PSub: PackedField,
501 Self:
502 Square + InvertOrZero + Mul<Output = Self> + WideMul<Output: Debug + Send + Sync + 'static>,
503{
504 #[inline]
508 fn interleave(self, other: Self, log_block_len: usize) -> (Self, Self) {
509 assert!(log_block_len < Self::LOG_WIDTH);
510 let pairs: [(PSub, PSub); N] =
513 array::from_fn(|j| self.0[j].interleave(other.0[j], log_block_len));
514 (Self::from_coords(pairs.map(|(c, _)| c)), Self::from_coords(pairs.map(|(_, d)| d)))
515 }
516
517 #[inline]
518 fn unzip(self, other: Self, log_block_len: usize) -> (Self, Self) {
519 assert!(log_block_len < Self::LOG_WIDTH);
520 let pairs: [(PSub, PSub); N] =
521 array::from_fn(|j| self.0[j].unzip(other.0[j], log_block_len));
522 (Self::from_coords(pairs.map(|(c, _)| c)), Self::from_coords(pairs.map(|(_, d)| d)))
523 }
524
525 #[inline]
526 fn from_fn(mut f: impl FnMut(usize) -> Self::Scalar) -> Self {
527 let mut result = Self::default();
528 for i in 0..Self::WIDTH {
529 result.set(i, f(i));
530 }
531 result
532 }
533
534 #[inline]
535 unsafe fn spread_unchecked(self, log_block_len: usize, block_idx: usize) -> Self {
536 Self::from_coords(array::from_fn(|j| unsafe {
538 self.0[j].spread_unchecked(log_block_len, block_idx)
539 }))
540 }
541}
542
543impl<F, PSub: PackedField, const N: usize> Distribution<SlicedPackedField<F, PSub, N>>
544 for StandardUniform
545{
546 #[inline]
547 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> SlicedPackedField<F, PSub, N> {
548 SlicedPackedField::from_coords(array::from_fn(|_| PSub::random(&mut *rng)))
549 }
550}