1use core::array;
2use core::iter::{Product, Sum};
3use core::ops::{Add, AddAssign, Div, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign};
4
5use p3_util::{as_base_slice, as_base_slice_mut};
6
7use crate::batch_inverse::batch_multiplicative_inverse_general;
8use crate::{Algebra, Field, PackedValue, PrimeCharacteristicRing};
9
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11#[repr(transparent)] #[must_use]
13pub struct FieldArray<F: Field, const N: usize>(pub [F; N]);
14
15impl<F: Field, const N: usize> FieldArray<F, N> {
16 #[inline]
21 pub(crate) fn inverse(&self) -> Self {
22 let mut result = Self::default();
23 batch_multiplicative_inverse_general(&self.0, &mut result.0, |x| x.inverse());
24 result
25 }
26
27 #[inline]
29 pub fn map<Func, U: Field>(self, f: Func) -> FieldArray<U, N>
30 where
31 Func: FnMut(F) -> U,
32 {
33 FieldArray(self.map_into_array(f))
34 }
35
36 #[inline]
40 pub fn map_into_array<Func, U>(self, f: Func) -> [U; N]
41 where
42 Func: FnMut(F) -> U,
43 {
44 self.0.map(f)
45 }
46
47 #[inline]
51 pub const fn as_raw_slice(s: &[Self]) -> &[[F; N]] {
52 unsafe { as_base_slice(s) }
55 }
56
57 #[inline]
61 pub const fn as_raw_slice_mut(s: &mut [Self]) -> &mut [[F; N]] {
62 unsafe { as_base_slice_mut(s) }
65 }
66
67 #[inline]
71 pub const fn from_raw_slice(s: &[[F; N]]) -> &[Self] {
72 unsafe { as_base_slice(s) }
75 }
76
77 #[inline]
81 pub const fn from_raw_slice_mut(s: &mut [[F; N]]) -> &mut [Self] {
82 unsafe { as_base_slice_mut(s) }
85 }
86}
87
88impl<F: Field, const N: usize> IndexMut<usize> for FieldArray<F, N> {
89 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
90 self.0.index_mut(index)
91 }
92}
93
94impl<F: Field, const N: usize> Index<usize> for FieldArray<F, N> {
95 type Output = F;
96
97 fn index(&self, index: usize) -> &Self::Output {
98 self.0.index(index)
99 }
100}
101
102impl<F: Field, const N: usize> Default for FieldArray<F, N> {
103 fn default() -> Self {
104 Self::ZERO
105 }
106}
107
108impl<F: Field, const N: usize> From<F> for FieldArray<F, N> {
109 fn from(val: F) -> Self {
110 [val; N].into()
111 }
112}
113
114impl<F: Field, const N: usize> From<[F; N]> for FieldArray<F, N> {
115 fn from(arr: [F; N]) -> Self {
116 Self(arr)
117 }
118}
119
120impl<F: Field, const N: usize> PrimeCharacteristicRing for FieldArray<F, N> {
121 type PrimeSubfield = F::PrimeSubfield;
122
123 const ZERO: Self = Self([F::ZERO; N]);
124 const ONE: Self = Self([F::ONE; N]);
125 const TWO: Self = Self([F::TWO; N]);
126 const NEG_ONE: Self = Self([F::NEG_ONE; N]);
127
128 #[inline]
129 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
130 F::from_prime_subfield(f).into()
131 }
132
133 #[inline]
134 fn halve(&self) -> Self {
135 Self(self.0.map(|x| x.halve()))
136 }
137}
138
139impl<F: Field, const N: usize> Algebra<F> for FieldArray<F, N> {}
140
141unsafe impl<F: Field, const N: usize> PackedValue for FieldArray<F, N> {
142 type Value = F;
143
144 const WIDTH: usize = N;
145
146 fn from_slice(slice: &[Self::Value]) -> &Self {
147 assert_eq!(slice.len(), Self::WIDTH);
148 unsafe { &*slice.as_ptr().cast() }
149 }
150
151 fn from_slice_mut(slice: &mut [Self::Value]) -> &mut Self {
152 assert_eq!(slice.len(), Self::WIDTH);
153 unsafe { &mut *slice.as_mut_ptr().cast() }
154 }
155
156 fn from_fn<Fn>(f: Fn) -> Self
157 where
158 Fn: FnMut(usize) -> Self::Value,
159 {
160 Self(array::from_fn(f))
161 }
162
163 fn as_slice(&self) -> &[Self::Value] {
164 &self.0
165 }
166
167 fn as_slice_mut(&mut self) -> &mut [Self::Value] {
168 &mut self.0
169 }
170}
171
172impl<F: Field, const N: usize> Add for FieldArray<F, N> {
173 type Output = Self;
174
175 #[inline]
176 fn add(self, rhs: Self) -> Self::Output {
177 array::from_fn(|i| self.0[i] + rhs.0[i]).into()
178 }
179}
180
181impl<F: Field, const N: usize> Add<F> for FieldArray<F, N> {
182 type Output = Self;
183
184 #[inline]
185 fn add(self, rhs: F) -> Self::Output {
186 self.0.map(|x| x + rhs).into()
187 }
188}
189
190impl<F: Field, const N: usize> AddAssign for FieldArray<F, N> {
191 #[inline]
192 fn add_assign(&mut self, rhs: Self) {
193 self.0.iter_mut().zip(rhs.0).for_each(|(x, y)| *x += y);
194 }
195}
196
197impl<F: Field, const N: usize> AddAssign<F> for FieldArray<F, N> {
198 #[inline]
199 fn add_assign(&mut self, rhs: F) {
200 self.0.iter_mut().for_each(|x| *x += rhs);
201 }
202}
203
204impl<F: Field, const N: usize> Sub for FieldArray<F, N> {
205 type Output = Self;
206
207 #[inline]
208 fn sub(self, rhs: Self) -> Self::Output {
209 array::from_fn(|i| self.0[i] - rhs.0[i]).into()
210 }
211}
212
213impl<F: Field, const N: usize> Sub<F> for FieldArray<F, N> {
214 type Output = Self;
215
216 #[inline]
217 fn sub(self, rhs: F) -> Self::Output {
218 self.0.map(|x| x - rhs).into()
219 }
220}
221
222impl<F: Field, const N: usize> SubAssign for FieldArray<F, N> {
223 #[inline]
224 fn sub_assign(&mut self, rhs: Self) {
225 self.0.iter_mut().zip(rhs.0).for_each(|(x, y)| *x -= y);
226 }
227}
228
229impl<F: Field, const N: usize> SubAssign<F> for FieldArray<F, N> {
230 #[inline]
231 fn sub_assign(&mut self, rhs: F) {
232 self.0.iter_mut().for_each(|x| *x -= rhs);
233 }
234}
235
236impl<F: Field, const N: usize> Neg for FieldArray<F, N> {
237 type Output = Self;
238
239 #[inline]
240 fn neg(self) -> Self::Output {
241 self.0.map(|x| -x).into()
242 }
243}
244
245impl<F: Field, const N: usize> Mul for FieldArray<F, N> {
246 type Output = Self;
247
248 #[inline]
249 fn mul(self, rhs: Self) -> Self::Output {
250 array::from_fn(|i| self.0[i] * rhs.0[i]).into()
251 }
252}
253
254impl<F: Field, const N: usize> Mul<F> for FieldArray<F, N> {
255 type Output = Self;
256
257 #[inline]
258 fn mul(self, rhs: F) -> Self::Output {
259 self.0.map(|x| x * rhs).into()
260 }
261}
262
263impl<F: Field, const N: usize> MulAssign for FieldArray<F, N> {
264 #[inline]
265 fn mul_assign(&mut self, rhs: Self) {
266 self.0.iter_mut().zip(rhs.0).for_each(|(x, y)| *x *= y);
267 }
268}
269
270impl<F: Field, const N: usize> MulAssign<F> for FieldArray<F, N> {
271 #[inline]
272 fn mul_assign(&mut self, rhs: F) {
273 self.0.iter_mut().for_each(|x| *x *= rhs);
274 }
275}
276
277impl<F: Field, const N: usize> Div<F> for FieldArray<F, N> {
278 type Output = Self;
279
280 #[allow(clippy::suspicious_arithmetic_impl)]
281 #[inline]
282 fn div(self, rhs: F) -> Self::Output {
283 let rhs_inv = rhs.inverse();
284 self * rhs_inv
285 }
286}
287
288impl<F: Field, const N: usize> Sum for FieldArray<F, N> {
289 #[inline]
290 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
291 iter.reduce(|lhs, rhs| lhs + rhs).unwrap_or(Self::ZERO)
292 }
293}
294
295impl<F: Field, const N: usize> Product for FieldArray<F, N> {
296 #[inline]
297 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
298 iter.reduce(|lhs, rhs| lhs * rhs).unwrap_or(Self::ONE)
299 }
300}