1use core::array;
8use core::iter::{Product, Sum};
9use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
10
11use crate::{
12 Algebra, BasedVectorSpace, ExtensionField, Field, PackedFieldExtension, PackedValue,
13 PrimeCharacteristicRing,
14};
15
16#[derive(Clone, Copy, Debug)]
30#[repr(transparent)]
31#[must_use]
32pub struct Vectorized<F: Field, const N: usize>(pub [F::Packing; N]);
33
34#[derive(Clone, Copy, Debug)]
40#[repr(transparent)]
41#[must_use]
42pub struct VectorizedExt<F: Field, EF: ExtensionField<F>, const N: usize>(
43 pub [EF::ExtensionPacking; N],
44);
45
46impl<F: Field, const N: usize> Vectorized<F, N> {
47 #[inline]
49 fn map(self, f: impl FnMut(F::Packing) -> F::Packing) -> Self {
50 Self(self.0.map(f))
51 }
52
53 #[inline]
55 fn zip_with<T: Copy>(
56 self,
57 rhs: &[T; N],
58 mut f: impl FnMut(F::Packing, T) -> F::Packing,
59 ) -> Self {
60 Self(array::from_fn(|i| f(self.0[i], rhs[i])))
61 }
62}
63
64impl<F: Field, EF: ExtensionField<F>, const N: usize> VectorizedExt<F, EF, N> {
65 #[inline]
67 fn map(self, f: impl FnMut(EF::ExtensionPacking) -> EF::ExtensionPacking) -> Self {
68 Self(self.0.map(f))
69 }
70
71 #[inline]
73 fn zip_with<T: Copy>(
74 self,
75 rhs: &[T; N],
76 mut f: impl FnMut(EF::ExtensionPacking, T) -> EF::ExtensionPacking,
77 ) -> Self {
78 Self(array::from_fn(|i| f(self.0[i], rhs[i])))
79 }
80
81 #[inline]
89 pub fn from_vectorized_basis_coefficients(coefficients: &[Vectorized<F, N>]) -> Self {
90 debug_assert_eq!(coefficients.len(), EF::DIMENSION);
91 Self(array::from_fn(|i| {
92 EF::ExtensionPacking::from_basis_coefficients_fn(|d| coefficients[d].0[i])
93 }))
94 }
95
96 #[inline]
101 pub fn extract(&self, i: usize) -> EF {
102 let width = F::Packing::WIDTH;
103 self.0[i / width].extract(i % width)
104 }
105}
106
107impl<F: Field, const N: usize> Default for Vectorized<F, N> {
108 #[inline]
109 fn default() -> Self {
110 Self::ZERO
111 }
112}
113
114impl<F: Field, EF: ExtensionField<F>, const N: usize> Default for VectorizedExt<F, EF, N> {
115 #[inline]
116 fn default() -> Self {
117 Self::ZERO
118 }
119}
120
121impl<F: Field, const N: usize> From<F> for Vectorized<F, N> {
122 #[inline]
123 fn from(value: F) -> Self {
124 Self([F::Packing::from(value); N])
125 }
126}
127
128impl<F: Field, EF: ExtensionField<F>, const N: usize> From<EF> for VectorizedExt<F, EF, N> {
129 #[inline]
130 fn from(value: EF) -> Self {
131 Self([EF::ExtensionPacking::from(value); N])
132 }
133}
134
135impl<F: Field, EF: ExtensionField<F>, const N: usize> From<Vectorized<F, N>>
136 for VectorizedExt<F, EF, N>
137{
138 #[inline]
139 fn from(value: Vectorized<F, N>) -> Self {
140 Self(value.0.map(EF::ExtensionPacking::from))
141 }
142}
143
144macro_rules! impl_binary_ops {
145 ($ty:ty, $($bound:tt)*) => {
146 impl<$($bound)*> Add for $ty {
147 type Output = Self;
148 #[inline]
149 fn add(self, rhs: Self) -> Self {
150 self.zip_with(&rhs.0, |x, y| x + y)
151 }
152 }
153
154 impl<$($bound)*> Sub for $ty {
155 type Output = Self;
156 #[inline]
157 fn sub(self, rhs: Self) -> Self {
158 self.zip_with(&rhs.0, |x, y| x - y)
159 }
160 }
161
162 impl<$($bound)*> Mul for $ty {
163 type Output = Self;
164 #[inline]
165 fn mul(self, rhs: Self) -> Self {
166 self.zip_with(&rhs.0, |x, y| x * y)
167 }
168 }
169
170 impl<$($bound)*> Neg for $ty {
171 type Output = Self;
172 #[inline]
173 fn neg(self) -> Self {
174 self.map(|x| -x)
175 }
176 }
177
178 impl<$($bound)*> AddAssign for $ty {
179 #[inline]
180 fn add_assign(&mut self, rhs: Self) {
181 *self = *self + rhs;
182 }
183 }
184
185 impl<$($bound)*> SubAssign for $ty {
186 #[inline]
187 fn sub_assign(&mut self, rhs: Self) {
188 *self = *self - rhs;
189 }
190 }
191
192 impl<$($bound)*> MulAssign for $ty {
193 #[inline]
194 fn mul_assign(&mut self, rhs: Self) {
195 *self = *self * rhs;
196 }
197 }
198
199 impl<$($bound)*> Sum for $ty {
200 #[inline]
201 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
202 iter.fold(Self::ZERO, |acc, x| acc + x)
203 }
204 }
205
206 impl<$($bound)*> Product for $ty {
207 #[inline]
208 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
209 iter.fold(Self::ONE, |acc, x| acc * x)
210 }
211 }
212 };
213}
214
215macro_rules! impl_scalar_ops {
216 ($ty:ty, $scalar:ty, $($bound:tt)*) => {
217 impl<$($bound)*> Add<$scalar> for $ty {
218 type Output = Self;
219 #[inline]
220 fn add(self, rhs: $scalar) -> Self {
221 self.map(|x| x + rhs)
222 }
223 }
224
225 impl<$($bound)*> Sub<$scalar> for $ty {
226 type Output = Self;
227 #[inline]
228 fn sub(self, rhs: $scalar) -> Self {
229 self.map(|x| x - rhs)
230 }
231 }
232
233 impl<$($bound)*> Mul<$scalar> for $ty {
234 type Output = Self;
235 #[inline]
236 fn mul(self, rhs: $scalar) -> Self {
237 self.map(|x| x * rhs)
238 }
239 }
240
241 impl<$($bound)*> AddAssign<$scalar> for $ty {
242 #[inline]
243 fn add_assign(&mut self, rhs: $scalar) {
244 *self = *self + rhs;
245 }
246 }
247
248 impl<$($bound)*> SubAssign<$scalar> for $ty {
249 #[inline]
250 fn sub_assign(&mut self, rhs: $scalar) {
251 *self = *self - rhs;
252 }
253 }
254
255 impl<$($bound)*> MulAssign<$scalar> for $ty {
256 #[inline]
257 fn mul_assign(&mut self, rhs: $scalar) {
258 *self = *self * rhs;
259 }
260 }
261 };
262}
263
264impl_binary_ops!(Vectorized<F, N>, F: Field, const N: usize);
265impl_scalar_ops!(Vectorized<F, N>, F, F: Field, const N: usize);
266impl_binary_ops!(VectorizedExt<F, EF, N>, F: Field, EF: ExtensionField<F>, const N: usize);
267impl_scalar_ops!(VectorizedExt<F, EF, N>, EF, F: Field, EF: ExtensionField<F>, const N: usize);
268
269impl<F: Field, EF: ExtensionField<F>, const N: usize> Add<Vectorized<F, N>>
270 for VectorizedExt<F, EF, N>
271{
272 type Output = Self;
273 #[inline]
274 fn add(self, rhs: Vectorized<F, N>) -> Self {
275 self.zip_with(&rhs.0, |x, y| x + y)
276 }
277}
278
279impl<F: Field, EF: ExtensionField<F>, const N: usize> Sub<Vectorized<F, N>>
280 for VectorizedExt<F, EF, N>
281{
282 type Output = Self;
283 #[inline]
284 fn sub(self, rhs: Vectorized<F, N>) -> Self {
285 self.zip_with(&rhs.0, |x, y| x - y)
286 }
287}
288
289impl<F: Field, EF: ExtensionField<F>, const N: usize> Mul<Vectorized<F, N>>
290 for VectorizedExt<F, EF, N>
291{
292 type Output = Self;
293 #[inline]
294 fn mul(self, rhs: Vectorized<F, N>) -> Self {
295 self.zip_with(&rhs.0, |x, y| x * y)
296 }
297}
298
299impl<F: Field, EF: ExtensionField<F>, const N: usize> AddAssign<Vectorized<F, N>>
300 for VectorizedExt<F, EF, N>
301{
302 #[inline]
303 fn add_assign(&mut self, rhs: Vectorized<F, N>) {
304 *self = *self + rhs;
305 }
306}
307
308impl<F: Field, EF: ExtensionField<F>, const N: usize> SubAssign<Vectorized<F, N>>
309 for VectorizedExt<F, EF, N>
310{
311 #[inline]
312 fn sub_assign(&mut self, rhs: Vectorized<F, N>) {
313 *self = *self - rhs;
314 }
315}
316
317impl<F: Field, EF: ExtensionField<F>, const N: usize> MulAssign<Vectorized<F, N>>
318 for VectorizedExt<F, EF, N>
319{
320 #[inline]
321 fn mul_assign(&mut self, rhs: Vectorized<F, N>) {
322 *self = *self * rhs;
323 }
324}
325
326impl<F: Field, const N: usize> PrimeCharacteristicRing for Vectorized<F, N> {
327 type PrimeSubfield = F::PrimeSubfield;
328
329 const ZERO: Self = Self([F::Packing::ZERO; N]);
330 const ONE: Self = Self([F::Packing::ONE; N]);
331 const TWO: Self = Self([F::Packing::TWO; N]);
332 const NEG_ONE: Self = Self([F::Packing::NEG_ONE; N]);
333
334 #[inline]
335 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
336 F::from_prime_subfield(f).into()
337 }
338
339 #[inline]
340 fn double(&self) -> Self {
341 self.map(|x| x.double())
342 }
343
344 #[inline]
345 fn halve(&self) -> Self {
346 self.map(|x| x.halve())
347 }
348
349 #[inline]
350 fn square(&self) -> Self {
351 self.map(|x| x.square())
352 }
353
354 #[inline]
355 fn cube(&self) -> Self {
356 self.map(|x| x.cube())
357 }
358
359 #[inline]
360 fn exp_const_u64<const POWER: u64>(&self) -> Self {
361 self.map(|x| x.exp_const_u64::<POWER>())
362 }
363
364 #[inline]
365 fn mul_2exp_u64(&self, exp: u64) -> Self {
366 self.map(|x| x.mul_2exp_u64(exp))
367 }
368
369 #[inline]
370 fn dot_product<const M: usize>(u: &[Self; M], v: &[Self; M]) -> Self {
371 Self(array::from_fn(|i| {
372 F::Packing::dot_product::<M>(
373 &array::from_fn::<_, M, _>(|j| u[j].0[i]),
374 &array::from_fn::<_, M, _>(|j| v[j].0[i]),
375 )
376 }))
377 }
378
379 #[inline]
380 fn sum_array<const M: usize>(input: &[Self]) -> Self {
381 assert_eq!(input.len(), M);
382 Self(array::from_fn(|i| {
383 F::Packing::sum_array::<M>(&array::from_fn::<_, M, _>(|j| input[j].0[i]))
384 }))
385 }
386}
387
388impl<F: Field, EF: ExtensionField<F>, const N: usize> PrimeCharacteristicRing
389 for VectorizedExt<F, EF, N>
390{
391 type PrimeSubfield = <EF::ExtensionPacking as PrimeCharacteristicRing>::PrimeSubfield;
392
393 const ZERO: Self = Self([EF::ExtensionPacking::ZERO; N]);
394 const ONE: Self = Self([EF::ExtensionPacking::ONE; N]);
395 const TWO: Self = Self([EF::ExtensionPacking::TWO; N]);
396 const NEG_ONE: Self = Self([EF::ExtensionPacking::NEG_ONE; N]);
397
398 #[inline]
399 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
400 Self([EF::ExtensionPacking::from_prime_subfield(f); N])
401 }
402
403 #[inline]
404 fn double(&self) -> Self {
405 self.map(|x| x.double())
406 }
407
408 #[inline]
409 fn halve(&self) -> Self {
410 self.map(|x| x.halve())
411 }
412
413 #[inline]
414 fn square(&self) -> Self {
415 self.map(|x| x.square())
416 }
417
418 #[inline]
419 fn cube(&self) -> Self {
420 self.map(|x| x.cube())
421 }
422
423 #[inline]
424 fn exp_const_u64<const POWER: u64>(&self) -> Self {
425 self.map(|x| x.exp_const_u64::<POWER>())
426 }
427
428 #[inline]
429 fn mul_2exp_u64(&self, exp: u64) -> Self {
430 self.map(|x| x.mul_2exp_u64(exp))
431 }
432
433 #[inline]
434 fn dot_product<const M: usize>(u: &[Self; M], v: &[Self; M]) -> Self {
435 Self(array::from_fn(|i| {
436 EF::ExtensionPacking::dot_product::<M>(
437 &array::from_fn::<_, M, _>(|j| u[j].0[i]),
438 &array::from_fn::<_, M, _>(|j| v[j].0[i]),
439 )
440 }))
441 }
442
443 #[inline]
444 fn sum_array<const M: usize>(input: &[Self]) -> Self {
445 assert_eq!(input.len(), M);
446 Self(array::from_fn(|i| {
447 EF::ExtensionPacking::sum_array::<M>(&array::from_fn::<_, M, _>(|j| input[j].0[i]))
448 }))
449 }
450}
451
452impl<F: Field, const N: usize> Algebra<F> for Vectorized<F, N> {
453 const BATCHED_LC_CHUNK: usize = <F::Packing as Algebra<F>>::BATCHED_LC_CHUNK;
454
455 #[inline]
456 fn mixed_dot_product<const M: usize>(a: &[Self; M], f: &[F; M]) -> Self {
457 Self(array::from_fn(|i| {
458 F::Packing::mixed_dot_product(&array::from_fn(|j| a[j].0[i]), f)
459 }))
460 }
461}
462
463impl<F: Field, EF: ExtensionField<F>, const N: usize> Algebra<EF> for VectorizedExt<F, EF, N> {
464 const BATCHED_LC_CHUNK: usize = <EF::ExtensionPacking as Algebra<EF>>::BATCHED_LC_CHUNK;
465
466 #[inline]
467 fn mixed_dot_product<const M: usize>(a: &[Self; M], f: &[EF; M]) -> Self {
468 Self(array::from_fn(|i| {
469 EF::ExtensionPacking::mixed_dot_product(&array::from_fn(|j| a[j].0[i]), f)
470 }))
471 }
472}
473
474impl<F: Field, EF: ExtensionField<F>, const N: usize> Algebra<Vectorized<F, N>>
475 for VectorizedExt<F, EF, N>
476{
477}
478
479unsafe impl<F: Field, const N: usize> PackedValue for Vectorized<F, N> {
487 type Value = F;
488
489 const WIDTH: usize = F::Packing::WIDTH * N;
490
491 #[inline]
492 fn from_fn<Fn>(mut f: Fn) -> Self
493 where
494 Fn: FnMut(usize) -> Self::Value,
495 {
496 Self(array::from_fn(|i| {
497 F::Packing::from_fn(|j| f(i * F::Packing::WIDTH + j))
498 }))
499 }
500
501 #[inline]
502 fn from_slice(slice: &[Self::Value]) -> &Self {
503 assert_eq!(slice.len(), Self::WIDTH);
504 unsafe { &*slice.as_ptr().cast() }
505 }
506
507 #[inline]
508 fn from_slice_mut(slice: &mut [Self::Value]) -> &mut Self {
509 assert_eq!(slice.len(), Self::WIDTH);
510 unsafe { &mut *slice.as_mut_ptr().cast() }
511 }
512
513 #[inline]
514 fn as_slice(&self) -> &[Self::Value] {
515 unsafe { core::slice::from_raw_parts(core::ptr::from_ref(self).cast(), Self::WIDTH) }
516 }
517
518 #[inline]
519 fn as_slice_mut(&mut self) -> &mut [Self::Value] {
520 unsafe { core::slice::from_raw_parts_mut(core::ptr::from_mut(self).cast(), Self::WIDTH) }
521 }
522}