Skip to main content

conspire/math/tensor/rank_1/
mod.rs

1#[cfg(test)]
2mod test;
3
4pub mod list;
5pub mod list_2d;
6pub mod vec;
7pub mod vec_2d;
8
9use std::{
10    array::from_fn,
11    fmt::{self, Display, Formatter},
12    iter::Sum,
13    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
14};
15
16use crate::{
17    ABS_TOL,
18    math::{
19        matrix::vector::Vector,
20        tensor::{
21            Jacobian, Solution, Tensor, TensorArray, rank_0::TensorRank0,
22            rank_1::list::TensorRank1List, rank_2::TensorRank2,
23        },
24        write_tensor_rank_0,
25    },
26};
27
28#[cfg(test)]
29use super::test::ErrorTensor;
30
31/// A *d*-dimensional tensor of rank 1.
32///
33/// `D` is the dimension, `I` is the configuration.
34#[derive(Clone, Debug, PartialEq)]
35pub struct TensorRank1<const D: usize, const I: usize>([TensorRank0; D]);
36
37impl<const D: usize, const I: usize> TensorRank1<D, I> {
38    /// Associated function for const type conversion.
39    pub const fn const_from(array: [TensorRank0; D]) -> Self {
40        Self(array)
41    }
42}
43
44impl<const D: usize, const I: usize> Default for TensorRank1<D, I> {
45    fn default() -> Self {
46        Self::zero()
47    }
48}
49
50impl<const D: usize> From<TensorRank1<D, 0>> for TensorRank1<D, 1> {
51    fn from(tensor_rank_1: TensorRank1<D, 0>) -> Self {
52        Self(tensor_rank_1.0)
53    }
54}
55
56impl<const D: usize> From<&TensorRank1<D, 0>> for TensorRank1<D, 1> {
57    fn from(tensor_rank_1: &TensorRank1<D, 0>) -> Self {
58        Self(tensor_rank_1.0)
59    }
60}
61
62impl<const D: usize> From<TensorRank1<D, 1>> for TensorRank1<D, 0> {
63    fn from(tensor_rank_1: TensorRank1<D, 1>) -> Self {
64        Self(tensor_rank_1.0)
65    }
66}
67
68impl<const D: usize> From<&TensorRank1<D, 1>> for TensorRank1<D, 0> {
69    fn from(tensor_rank_1: &TensorRank1<D, 1>) -> Self {
70        Self(tensor_rank_1.0)
71    }
72}
73
74impl<const D: usize> From<TensorRank1<D, 9>> for TensorRank1<D, 0> {
75    fn from(tensor_rank_1: TensorRank1<D, 9>) -> Self {
76        Self(tensor_rank_1.0)
77    }
78}
79
80impl<const D: usize> From<&TensorRank1<D, 9>> for TensorRank1<D, 0> {
81    fn from(tensor_rank_1: &TensorRank1<D, 9>) -> Self {
82        Self(tensor_rank_1.0)
83    }
84}
85
86impl<const D: usize, const I: usize> Display for TensorRank1<D, I> {
87    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
88        write!(f, "\x1B[s")?;
89        write!(f, "[")?;
90        self.iter()
91            .try_for_each(|entry| write_tensor_rank_0(f, entry))?;
92        write!(f, "\x1B[2D]")
93    }
94}
95
96impl<const D: usize, const I: usize> TensorRank1<D, I> {
97    /// Returns a raw pointer to the slice’s buffer.
98    pub const fn as_ptr(&self) -> *const TensorRank0 {
99        self.0.as_ptr()
100    }
101    pub fn orthonormal_basis(&self) -> TensorRank1List<D, I, D> {
102        let norm = self.norm();
103        assert!(
104            norm > ABS_TOL,
105            "Cannot build an orthonormal basis from the zero vector"
106        );
107        let mut basis = TensorRank1List::zero();
108        basis[0] = self / norm;
109        let mut filled = 1;
110        for i in 0..D {
111            if filled == D {
112                break;
113            }
114            let mut v = zero();
115            v[i] = 1.0;
116            basis.iter().take(filled).for_each(|q| v -= q * (&v * q));
117            let v_norm = v.norm();
118            if v_norm > ABS_TOL {
119                basis[filled] = v / v_norm;
120                filled += 1;
121            }
122        }
123        assert!(filled == D, "Failed to construct full orthonormal basis");
124        basis
125    }
126}
127
128pub trait CrossProduct<T> {
129    type Output;
130    /// Returns the cross product with another rank-1 tensor.
131    fn cross(self, other: T) -> Self::Output;
132}
133
134// impl<const I: usize> CrossProduct<Self> for TensorRank1<3, I> {
135//     type Output = Self;
136//     fn cross(self, other: Self) -> Self::Output {
137//         Self::const_from([
138//             self[1] * other[2] - self[2] * other[1],
139//             self[2] * other[0] - self[0] * other[2],
140//             self[0] * other[1] - self[1] * other[0],
141//         ])
142//     }
143// }
144
145// impl<const I: usize> CrossProduct<&Self> for TensorRank1<3, I> {
146//     type Output = Self;
147//     fn cross(self, other: &Self) -> Self::Output {
148//         Self::const_from([
149//             self[1] * other[2] - self[2] * other[1],
150//             self[2] * other[0] - self[0] * other[2],
151//             self[0] * other[1] - self[1] * other[0],
152//         ])
153//     }
154// }
155
156impl<const I: usize> CrossProduct<TensorRank1<3, I>> for &TensorRank1<3, I> {
157    type Output = TensorRank1<3, I>;
158    fn cross(self, other: TensorRank1<3, I>) -> Self::Output {
159        TensorRank1::const_from([
160            self[1] * other[2] - self[2] * other[1],
161            self[2] * other[0] - self[0] * other[2],
162            self[0] * other[1] - self[1] * other[0],
163        ])
164    }
165}
166
167impl<const I: usize> CrossProduct<Self> for &TensorRank1<3, I> {
168    type Output = TensorRank1<3, I>;
169    fn cross(self, other: Self) -> Self::Output {
170        TensorRank1::const_from([
171            self[1] * other[2] - self[2] * other[1],
172            self[2] * other[0] - self[0] * other[2],
173            self[0] * other[1] - self[1] * other[0],
174        ])
175    }
176}
177
178#[cfg(test)]
179impl<const D: usize, const I: usize> ErrorTensor for TensorRank1<D, I> {
180    fn error_fd(&self, comparator: &Self, epsilon: TensorRank0) -> Option<(bool, usize)> {
181        let error_count = self
182            .iter()
183            .zip(comparator.iter())
184            .filter(|&(&self_i, &comparator_i)| {
185                (self_i / comparator_i - 1.0).abs() >= epsilon
186                    && (self_i.abs() >= epsilon || comparator_i.abs() >= epsilon)
187            })
188            .count();
189        if error_count > 0 {
190            Some((true, error_count))
191        } else {
192            None
193        }
194    }
195}
196
197impl<const D: usize, const I: usize> Solution for TensorRank1<D, I> {
198    fn decrement_from(&mut self, _other: &Vector) {
199        unimplemented!()
200    }
201    fn decrement_from_chained(&mut self, _other: &mut Vector, _vector: Vector) {
202        unimplemented!()
203    }
204}
205
206impl<const D: usize, const I: usize> Jacobian for TensorRank1<D, I> {
207    fn fill_into(self, _vector: &mut Vector) {
208        unimplemented!()
209    }
210    fn fill_into_chained(self, _other: Vector, _vector: &mut Vector) {
211        unimplemented!()
212    }
213}
214
215impl<const D: usize, const I: usize> Sub<Vector> for TensorRank1<D, I> {
216    type Output = Self;
217    fn sub(self, _vector: Vector) -> Self::Output {
218        unimplemented!()
219    }
220}
221
222impl<const D: usize, const I: usize> Sub<&Vector> for TensorRank1<D, I> {
223    type Output = Self;
224    fn sub(self, _vector: &Vector) -> Self::Output {
225        unimplemented!()
226    }
227}
228
229impl<const D: usize, const I: usize> Tensor for TensorRank1<D, I> {
230    type Item = TensorRank0;
231    fn full_contraction(&self, tensor_rank_1: &Self) -> TensorRank0 {
232        self * tensor_rank_1
233    }
234    fn iter(&self) -> impl Iterator<Item = &Self::Item> {
235        self.0.iter()
236    }
237    fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
238        self.0.iter_mut()
239    }
240    fn len(&self) -> usize {
241        D
242    }
243    fn size(&self) -> usize {
244        D
245    }
246}
247
248impl<const D: usize, const I: usize> IntoIterator for TensorRank1<D, I> {
249    type Item = TensorRank0;
250    type IntoIter = std::array::IntoIter<Self::Item, D>;
251    fn into_iter(self) -> Self::IntoIter {
252        self.0.into_iter()
253    }
254}
255
256impl<const D: usize, const I: usize> TensorArray for TensorRank1<D, I> {
257    type Array = [TensorRank0; D];
258    type Item = TensorRank0;
259    fn as_array(&self) -> Self::Array {
260        self.0
261    }
262    fn identity() -> Self {
263        ones()
264    }
265    fn zero() -> Self {
266        zero()
267    }
268}
269
270/// Returns the rank-1 tensor of ones as a constant.
271pub const fn ones<const D: usize, const I: usize>() -> TensorRank1<D, I> {
272    TensorRank1([1.0; D])
273}
274
275/// Returns the rank-1 zero tensor as a constant.
276pub const fn zero<const D: usize, const I: usize>() -> TensorRank1<D, I> {
277    TensorRank1([0.0; D])
278}
279
280impl<const D: usize, const I: usize> From<[TensorRank0; D]> for TensorRank1<D, I> {
281    fn from(array: [TensorRank0; D]) -> Self {
282        Self(array)
283    }
284}
285
286impl<const D: usize, const I: usize> From<TensorRank1<D, I>> for [TensorRank0; D] {
287    fn from(tensor_rank_1: TensorRank1<D, I>) -> Self {
288        tensor_rank_1.0
289    }
290}
291
292impl<const D: usize, const I: usize> From<Vec<TensorRank0>> for TensorRank1<D, I> {
293    fn from(vec: Vec<TensorRank0>) -> Self {
294        Self(vec.try_into().unwrap())
295    }
296}
297
298impl<const D: usize, const I: usize> From<TensorRank1<D, I>> for Vec<TensorRank0> {
299    fn from(tensor_rank_1: TensorRank1<D, I>) -> Self {
300        tensor_rank_1.0.to_vec()
301    }
302}
303
304impl<const D: usize, const I: usize> From<Vector> for TensorRank1<D, I> {
305    fn from(_vector: Vector) -> Self {
306        unimplemented!()
307    }
308}
309
310impl<const D: usize, const I: usize> FromIterator<TensorRank0> for TensorRank1<D, I> {
311    fn from_iter<Ii: IntoIterator<Item = TensorRank0>>(into_iterator: Ii) -> Self {
312        let mut tensor_rank_1 = zero();
313        tensor_rank_1
314            .iter_mut()
315            .zip(into_iterator)
316            .for_each(|(tensor_rank_1_i, value_i)| *tensor_rank_1_i = value_i);
317        tensor_rank_1
318    }
319}
320
321impl<const D: usize, const I: usize> Index<usize> for TensorRank1<D, I> {
322    type Output = TensorRank0;
323    fn index(&self, index: usize) -> &Self::Output {
324        &self.0[index]
325    }
326}
327
328impl<const D: usize, const I: usize> IndexMut<usize> for TensorRank1<D, I> {
329    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
330        &mut self.0[index]
331    }
332}
333
334impl<const D: usize, const I: usize> Sum for TensorRank1<D, I> {
335    fn sum<Ii>(iter: Ii) -> Self
336    where
337        Ii: Iterator<Item = Self>,
338    {
339        iter.reduce(|mut acc, item| {
340            acc += item;
341            acc
342        })
343        .unwrap_or_else(Self::default)
344    }
345}
346
347impl<'a, const D: usize, const I: usize> Sum<&'a Self> for TensorRank1<D, I> {
348    fn sum<Ii>(iter: Ii) -> Self
349    where
350        Ii: Iterator<Item = &'a Self>,
351    {
352        iter.fold(Self::default(), |mut acc, item| {
353            acc += item;
354            acc
355        })
356    }
357}
358
359impl<const D: usize, const I: usize> Neg for TensorRank1<D, I> {
360    type Output = Self;
361    fn neg(self) -> Self::Output {
362        from_fn(|i| -self[i]).into()
363    }
364}
365
366impl<const D: usize, const I: usize> Neg for &TensorRank1<D, I> {
367    type Output = TensorRank1<D, I>;
368    fn neg(self) -> Self::Output {
369        from_fn(|i| -self[i]).into()
370    }
371}
372
373impl<const D: usize, const I: usize> Div<TensorRank0> for TensorRank1<D, I> {
374    type Output = Self;
375    fn div(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
376        self /= tensor_rank_0;
377        self
378    }
379}
380
381impl<const D: usize, const I: usize> Div<TensorRank0> for &TensorRank1<D, I> {
382    type Output = TensorRank1<D, I>;
383    fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
384        self.iter().map(|self_i| self_i / tensor_rank_0).collect()
385    }
386}
387
388impl<const D: usize, const I: usize> Div<&TensorRank0> for TensorRank1<D, I> {
389    type Output = Self;
390    fn div(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
391        self /= tensor_rank_0;
392        self
393    }
394}
395
396impl<const D: usize, const I: usize> Div<&TensorRank0> for &TensorRank1<D, I> {
397    type Output = TensorRank1<D, I>;
398    fn div(self, tensor_rank_0: &TensorRank0) -> Self::Output {
399        self.iter().map(|self_i| self_i / tensor_rank_0).collect()
400    }
401}
402
403impl<const D: usize, const I: usize> DivAssign<TensorRank0> for TensorRank1<D, I> {
404    fn div_assign(&mut self, tensor_rank_0: TensorRank0) {
405        self.iter_mut().for_each(|self_i| *self_i /= &tensor_rank_0);
406    }
407}
408
409impl<const D: usize, const I: usize> DivAssign<&TensorRank0> for TensorRank1<D, I> {
410    fn div_assign(&mut self, tensor_rank_0: &TensorRank0) {
411        self.iter_mut().for_each(|self_i| *self_i /= tensor_rank_0);
412    }
413}
414
415impl<const D: usize, const I: usize> Mul<TensorRank0> for TensorRank1<D, I> {
416    type Output = Self;
417    fn mul(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
418        self *= tensor_rank_0;
419        self
420    }
421}
422
423impl<const D: usize, const I: usize> Mul<TensorRank0> for &TensorRank1<D, I> {
424    type Output = TensorRank1<D, I>;
425    fn mul(self, tensor_rank_0: TensorRank0) -> Self::Output {
426        self.iter().map(|self_i| self_i * tensor_rank_0).collect()
427    }
428}
429
430impl<const D: usize, const I: usize> Mul<&TensorRank0> for TensorRank1<D, I> {
431    type Output = Self;
432    fn mul(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
433        self *= tensor_rank_0;
434        self
435    }
436}
437
438impl<const D: usize, const I: usize> Mul<&TensorRank0> for &TensorRank1<D, I> {
439    type Output = TensorRank1<D, I>;
440    fn mul(self, tensor_rank_0: &TensorRank0) -> Self::Output {
441        self.iter().map(|self_i| self_i * tensor_rank_0).collect()
442    }
443}
444
445impl<const D: usize, const I: usize> MulAssign<TensorRank0> for TensorRank1<D, I> {
446    fn mul_assign(&mut self, tensor_rank_0: TensorRank0) {
447        self.iter_mut().for_each(|self_i| *self_i *= &tensor_rank_0);
448    }
449}
450
451impl<const D: usize, const I: usize> MulAssign<&TensorRank0> for TensorRank1<D, I> {
452    fn mul_assign(&mut self, tensor_rank_0: &TensorRank0) {
453        self.iter_mut().for_each(|self_i| *self_i *= tensor_rank_0);
454    }
455}
456
457impl<const D: usize, const I: usize> Add for TensorRank1<D, I> {
458    type Output = Self;
459    fn add(mut self, tensor_rank_1: Self) -> Self::Output {
460        self += tensor_rank_1;
461        self
462    }
463}
464
465impl<const D: usize, const I: usize> Add<&Self> for TensorRank1<D, I> {
466    type Output = Self;
467    fn add(mut self, tensor_rank_1: &Self) -> Self::Output {
468        self += tensor_rank_1;
469        self
470    }
471}
472
473impl<const D: usize, const I: usize> Add<TensorRank1<D, I>> for &TensorRank1<D, I> {
474    type Output = TensorRank1<D, I>;
475    fn add(self, mut tensor_rank_1: TensorRank1<D, I>) -> Self::Output {
476        tensor_rank_1 += self;
477        tensor_rank_1
478    }
479}
480
481impl<const D: usize, const I: usize> Add<Self> for &TensorRank1<D, I> {
482    type Output = TensorRank1<D, I>;
483    fn add(self, tensor_rank_1: Self) -> Self::Output {
484        tensor_rank_1
485            .iter()
486            .zip(self.iter())
487            .map(|(tensor_rank_1_i, self_i)| self_i + *tensor_rank_1_i)
488            .collect()
489    }
490}
491
492impl<const D: usize, const I: usize> AddAssign for TensorRank1<D, I> {
493    fn add_assign(&mut self, tensor_rank_1: Self) {
494        self.iter_mut()
495            .zip(tensor_rank_1)
496            .for_each(|(self_i, tensor_rank_1_i)| *self_i += tensor_rank_1_i);
497    }
498}
499
500impl<const D: usize, const I: usize> AddAssign<&Self> for TensorRank1<D, I> {
501    fn add_assign(&mut self, tensor_rank_1: &Self) {
502        self.iter_mut()
503            .zip(tensor_rank_1.iter())
504            .for_each(|(self_i, tensor_rank_1_i)| *self_i += tensor_rank_1_i);
505    }
506}
507
508impl<const D: usize, const I: usize> Sub for TensorRank1<D, I> {
509    type Output = Self;
510    fn sub(mut self, tensor_rank_1: Self) -> Self::Output {
511        self -= tensor_rank_1;
512        self
513    }
514}
515
516impl<const D: usize, const I: usize> Sub<&Self> for TensorRank1<D, I> {
517    type Output = Self;
518    fn sub(mut self, tensor_rank_1: &Self) -> Self::Output {
519        self -= tensor_rank_1;
520        self
521    }
522}
523
524impl<const D: usize, const I: usize> Sub<TensorRank1<D, I>> for &TensorRank1<D, I> {
525    type Output = TensorRank1<D, I>;
526    fn sub(self, mut tensor_rank_1: TensorRank1<D, I>) -> Self::Output {
527        tensor_rank_1
528            .iter_mut()
529            .zip(self.iter())
530            .for_each(|(tensor_rank_1_i, self_i)| *tensor_rank_1_i = self_i - *tensor_rank_1_i);
531        tensor_rank_1
532    }
533}
534
535impl<const D: usize, const I: usize> Sub<Self> for &TensorRank1<D, I> {
536    type Output = TensorRank1<D, I>;
537    fn sub(self, tensor_rank_1: Self) -> Self::Output {
538        tensor_rank_1
539            .iter()
540            .zip(self.iter())
541            .map(|(tensor_rank_1_i, self_i)| self_i - *tensor_rank_1_i)
542            .collect()
543    }
544}
545
546impl<const D: usize, const I: usize> SubAssign for TensorRank1<D, I> {
547    fn sub_assign(&mut self, tensor_rank_1: Self) {
548        self.iter_mut()
549            .zip(tensor_rank_1)
550            .for_each(|(self_i, tensor_rank_1_i)| *self_i -= tensor_rank_1_i);
551    }
552}
553
554impl<const D: usize, const I: usize> SubAssign<&Self> for TensorRank1<D, I> {
555    fn sub_assign(&mut self, tensor_rank_1: &Self) {
556        self.iter_mut()
557            .zip(tensor_rank_1.iter())
558            .for_each(|(self_i, tensor_rank_1_i)| *self_i -= tensor_rank_1_i);
559    }
560}
561
562impl<const D: usize, const I: usize> Mul for TensorRank1<D, I> {
563    type Output = TensorRank0;
564    fn mul(self, tensor_rank_1: Self) -> Self::Output {
565        self.into_iter()
566            .zip(tensor_rank_1)
567            .map(|(self_i, tensor_rank_1_i)| self_i * tensor_rank_1_i)
568            .sum()
569    }
570}
571
572impl<const D: usize, const I: usize> Mul<&Self> for TensorRank1<D, I> {
573    type Output = TensorRank0;
574    fn mul(self, tensor_rank_1: &Self) -> Self::Output {
575        self.into_iter()
576            .zip(tensor_rank_1.iter())
577            .map(|(self_i, tensor_rank_1_i)| self_i * tensor_rank_1_i)
578            .sum()
579    }
580}
581
582impl<const D: usize, const I: usize> Mul<TensorRank1<D, I>> for &TensorRank1<D, I> {
583    type Output = TensorRank0;
584    fn mul(self, tensor_rank_1: TensorRank1<D, I>) -> Self::Output {
585        self.iter()
586            .zip(tensor_rank_1)
587            .map(|(self_i, tensor_rank_1_i)| self_i * tensor_rank_1_i)
588            .sum()
589    }
590}
591
592impl<const D: usize, const I: usize> Mul for &TensorRank1<D, I> {
593    type Output = TensorRank0;
594    fn mul(self, tensor_rank_1: Self) -> Self::Output {
595        self.iter()
596            .zip(tensor_rank_1.iter())
597            .map(|(self_i, tensor_rank_1_i)| self_i * tensor_rank_1_i)
598            .sum()
599    }
600}
601
602#[allow(clippy::suspicious_arithmetic_impl)]
603impl<const D: usize, const I: usize, const J: usize> Div<TensorRank2<D, I, J>>
604    for &TensorRank1<D, I>
605{
606    type Output = TensorRank1<D, J>;
607    fn div(self, tensor_rank_2: TensorRank2<D, I, J>) -> Self::Output {
608        tensor_rank_2.inverse() * self
609    }
610}