1use crate::traits::{Num, Real};
22use core::ops::{Add, Div, Mul, Sub};
23
24#[derive(Clone, Copy, PartialEq, Debug)]
41pub struct Array<T, const N: usize> {
42 data: [T; N],
43}
44
45impl<T: Num, const N: usize> Default for Array<T, N> {
46 fn default() -> Self {
47 Self::zeros()
48 }
49}
50
51impl<T: Num, const N: usize> Array<T, N> {
52 pub const fn new(data: [T; N]) -> Self {
54 Self { data }
55 }
56
57 pub fn from_fn<F: FnMut(usize) -> T>(mut f: F) -> Self {
65 let mut data = [T::zero(); N];
66 for (i, slot) in data.iter_mut().enumerate() {
67 *slot = f(i);
68 }
69 Self { data }
70 }
71
72 pub fn zeros() -> Self {
79 Self::from_fn(|_| T::zero())
80 }
81
82 pub fn ones() -> Self {
84 Self::from_fn(|_| T::one())
85 }
86
87 pub fn as_slice(&self) -> &[T] {
89 &self.data
90 }
91
92 pub fn as_mut_slice(&mut self) -> &mut [T] {
94 &mut self.data
95 }
96
97 pub fn get(&self, i: usize) -> T {
99 self.data[i]
100 }
101
102 pub fn set(&mut self, i: usize, value: T) {
104 self.data[i] = value;
105 }
106
107 pub fn try_get(&self, i: usize) -> Option<T> {
109 self.data.get(i).copied()
110 }
111
112 pub fn sum(&self) -> T {
114 let mut acc = T::zero();
115 for &x in &self.data {
116 acc = acc + x;
117 }
118 acc
119 }
120
121 pub fn dot(&self, other: &Self) -> T {
130 let mut acc = T::zero();
131 for i in 0..N {
132 acc = acc + self.data[i] * other.data[i];
133 }
134 acc
135 }
136
137 pub fn map<U: Num, F: FnMut(T) -> U>(&self, mut f: F) -> Array<U, N> {
139 Array::from_fn(|i| f(self.data[i]))
140 }
141
142 pub fn zip_with<U: Num, V: Num, F: FnMut(T, U) -> V>(
144 &self,
145 other: &Array<U, N>,
146 mut f: F,
147 ) -> Array<V, N> {
148 Array::from_fn(|i| f(self.data[i], other.data[i]))
149 }
150
151 pub fn component_mul(&self, other: &Self) -> Self {
153 self.zip_with(other, |x, y| x * y)
154 }
155
156 pub fn component_div(&self, other: &Self) -> Self
158 where
159 T: Div<Output = T>,
160 {
161 self.zip_with(other, |x, y| x / y)
162 }
163
164 pub fn cumulative_sum(&self) -> Self {
172 let mut acc = T::zero();
173 let mut out = [T::zero(); N];
174 for (i, slot) in out.iter_mut().enumerate() {
175 acc = acc + self.data[i];
176 *slot = acc;
177 }
178 Self { data: out }
179 }
180
181 pub fn reversed(&self) -> Self {
183 let mut out = [T::zero(); N];
184 for i in 0..N {
185 out[i] = self.data[N - 1 - i];
186 }
187 Self { data: out }
188 }
189
190 pub fn all_eq(&self, other: &Self) -> bool
192 where
193 T: PartialEq,
194 {
195 self.data == other.data
196 }
197}
198
199impl<T: Num, const N: usize> Array<T, N> {
200 pub fn add(&self, other: &Self) -> Self {
202 self.zip_with(other, |x, y| x + y)
203 }
204
205 pub fn sub(&self, other: &Self) -> Self {
207 self.zip_with(other, |x, y| x - y)
208 }
209
210 pub fn scalar_mul(&self, s: T) -> Self {
212 self.map(|x| x * s)
213 }
214
215 pub fn scalar_add(&self, s: T) -> Self {
217 self.map(|x| x + s)
218 }
219
220 pub fn scalar_div(&self, s: T) -> Self
222 where
223 T: Div<Output = T>,
224 {
225 self.map(|x| x / s)
226 }
227}
228
229impl<T: Real, const N: usize> Array<T, N> {
230 pub fn l2_norm(&self) -> T {
238 self.dot(self).sqrt()
239 }
240
241 pub fn l1_norm(&self) -> T {
243 let mut acc = T::zero();
244 for &x in &self.data {
245 acc = acc + x.abs();
246 }
247 acc
248 }
249
250 pub fn max_norm(&self) -> T {
252 let mut acc = T::zero();
253 for &x in &self.data {
254 let ax = x.abs();
255 if ax > acc {
256 acc = ax;
257 }
258 }
259 acc
260 }
261
262 pub fn try_normalize(&self) -> Option<Self> {
264 let n = self.l2_norm();
265 if n == T::zero() {
266 None
267 } else {
268 Some(self.scalar_div(n))
269 }
270 }
271
272 pub fn normalize(&self) -> Self {
274 self.try_normalize().unwrap_or_else(Self::zeros)
275 }
276
277 pub fn mean(&self) -> T {
279 self.sum() / T::from_f64(N as f64)
280 }
281}
282
283impl<T, const N: usize> From<[T; N]> for Array<T, N> {
284 fn from(data: [T; N]) -> Self {
285 Self { data }
286 }
287}
288
289impl<T, const N: usize> From<Array<T, N>> for [T; N] {
290 fn from(arr: Array<T, N>) -> Self {
291 arr.data
292 }
293}
294
295impl<T, const N: usize> AsRef<[T]> for Array<T, N> {
296 fn as_ref(&self) -> &[T] {
297 &self.data
298 }
299}
300
301impl<T, const N: usize> core::ops::Index<usize> for Array<T, N> {
302 type Output = T;
303
304 fn index(&self, index: usize) -> &Self::Output {
305 &self.data[index]
306 }
307}
308
309impl<T: Num, const N: usize> Add for Array<T, N> {
310 type Output = Self;
311
312 fn add(self, rhs: Self) -> Self::Output {
313 Self::add(&self, &rhs)
314 }
315}
316
317impl<T: Num, const N: usize> Sub for Array<T, N> {
318 type Output = Self;
319
320 fn sub(self, rhs: Self) -> Self::Output {
321 Self::sub(&self, &rhs)
322 }
323}
324
325impl<T: Num, const N: usize> Mul<T> for Array<T, N> {
326 type Output = Self;
327
328 fn mul(self, rhs: T) -> Self::Output {
329 self.scalar_mul(rhs)
330 }
331}
332
333impl<T: Num + Div<Output = T>, const N: usize> Div<T> for Array<T, N> {
334 type Output = Self;
335
336 fn div(self, rhs: T) -> Self::Output {
337 self.scalar_div(rhs)
338 }
339}
340
341#[cfg(test)]
342mod tests {
343 use super::*;
344
345 #[test]
346 fn basic_ops() {
347 let a = Array::from([1.0f64, 2.0, 3.0]);
348 let b = Array::from([4.0, 5.0, 6.0]);
349 assert_eq!(a + b, Array::from([5.0, 7.0, 9.0]));
350 assert_eq!(a.dot(&b), 32.0);
351 assert_eq!(a.sum(), 6.0);
352 }
353
354 #[test]
355 fn const_generic_sizes() {
356 let a: Array<u32, 4> = Array::ones();
357 assert_eq!(a.sum(), 4);
358 let b: Array<u32, 8> = Array::zeros();
359 assert_eq!(b.sum(), 0);
360 }
361
362 #[test]
363 fn norms() {
364 let a = Array::from([3.0f64, 4.0]);
365 assert!((a.l2_norm() - 5.0).abs() < 1e-12);
366 assert_eq!(a.l1_norm(), 7.0);
367 assert_eq!(a.max_norm(), 4.0);
368 assert!((a.try_normalize().unwrap().l2_norm() - 1.0).abs() < 1e-12);
369 }
370
371 #[test]
372 fn int_arrays() {
373 let a = Array::from([1i32, 2, 3]);
374 let b = Array::from([10, 20, 30]);
375 assert_eq!(a.component_mul(&b), Array::from([10, 40, 90]));
376 assert_eq!(a.cumulative_sum(), Array::from([1, 3, 6]));
377 }
378
379 #[test]
380 fn normalize_zero() {
381 let z: Array<f64, 3> = Array::zeros();
382 assert!(z.try_normalize().is_none());
383 assert_eq!(z.normalize(), z);
384 }
385}