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