Skip to main content

conspire/math/tensor/rank_1/list/
mod.rs

1#[cfg(test)]
2mod test;
3use crate::math::{Current, Projection, Reference};
4use crate::units::{Dimensionless, UnitMul};
5
6use crate::math::{
7    CrossProduct, Tensor, TensorRank0, TensorRank1, TensorRank2, tensor::list::TensorList,
8};
9use std::ops::Mul;
10
11use crate::math::assert::FiniteDifference;
12
13/// A list of rank-1 tensors.
14pub type TensorRank1List<const D: usize, I, const N: usize, U = Dimensionless> =
15    TensorList<TensorRank1<D, I, U>, N>;
16
17impl<const D: usize, I, const N: usize, U> TensorRank1List<D, I, N, U> {
18    pub fn bounding_box(&self) -> TensorRank1List<D, I, 2, U> {
19        self.iter()
20            .skip(1)
21            .fold(
22                [self[0].clone(), self[0].clone()],
23                |[mut min, mut max], entry| {
24                    entry
25                        .iter()
26                        .zip(min.iter_mut().zip(max.iter_mut()))
27                        .for_each(|(&entry_i, (min_i, max_i))| {
28                            *min_i = min_i.min(entry_i);
29                            *max_i = max_i.max(entry_i);
30                        });
31                    [min, max]
32                },
33            )
34            .into()
35    }
36}
37
38impl<I, U> TensorRank1List<3, I, 3, U>
39where
40    U: UnitMul<U>,
41{
42    /// Returns the scalar triple product, a number as a determinant is.
43    pub fn scalar_triple_product(&self) -> TensorRank0 {
44        let cross = self[1].cross(&self[2]);
45        self[0]
46            .iter()
47            .zip(cross.iter())
48            .map(|(self_i, cross_i)| self_i.value() * cross_i.value())
49            .sum()
50    }
51}
52
53impl<const D: usize, I, const N: usize, U> From<[[TensorRank0; D]; N]>
54    for TensorRank1List<D, I, N, U>
55{
56    fn from(array: [[TensorRank0; D]; N]) -> Self {
57        array.into_iter().map(|entry| entry.into()).collect()
58    }
59}
60
61impl<const D: usize, const N: usize, U> From<TensorRank1List<D, Projection, N, U>>
62    for TensorRank1List<D, Reference, N, U>
63{
64    fn from(tensor_rank_1_list: TensorRank1List<D, Projection, N, U>) -> Self {
65        tensor_rank_1_list
66            .into_iter()
67            .map(|entry| entry.into())
68            .collect()
69    }
70}
71
72impl<const D: usize, const N: usize, U> From<TensorRank1List<D, Reference, N, U>>
73    for TensorRank1List<D, Current, N, U>
74{
75    fn from(tensor_rank_1_list: TensorRank1List<D, Reference, N, U>) -> Self {
76        tensor_rank_1_list
77            .into_iter()
78            .map(|entry| entry.into())
79            .collect()
80    }
81}
82
83impl<const D: usize, I, J, const W: usize, U, V> Mul<TensorRank1List<D, J, W, V>>
84    for TensorRank1List<D, I, W, U>
85where
86    U: UnitMul<V>,
87{
88    type Output = TensorRank2<D, I, J, <U as UnitMul<V>>::Output>;
89    fn mul(self, tensor_rank_1_list: TensorRank1List<D, J, W, V>) -> Self::Output {
90        self.into_iter()
91            .zip(tensor_rank_1_list)
92            .map(|(self_entry, entry)| Self::Output::from((self_entry, entry)))
93            .sum()
94    }
95}
96
97impl<const D: usize, I, J, const W: usize, U, V> Mul<&TensorRank1List<D, J, W, V>>
98    for TensorRank1List<D, I, W, U>
99where
100    U: UnitMul<V>,
101{
102    type Output = TensorRank2<D, I, J, <U as UnitMul<V>>::Output>;
103    fn mul(self, tensor_rank_1_list: &TensorRank1List<D, J, W, V>) -> Self::Output {
104        self.into_iter()
105            .zip(tensor_rank_1_list.iter())
106            .map(|(self_entry, entry)| Self::Output::from((self_entry, entry)))
107            .sum()
108    }
109}
110
111impl<const D: usize, I, J, const W: usize, U, V> Mul<TensorRank1List<D, J, W, V>>
112    for &TensorRank1List<D, I, W, U>
113where
114    U: UnitMul<V>,
115{
116    type Output = TensorRank2<D, I, J, <U as UnitMul<V>>::Output>;
117    fn mul(self, tensor_rank_1_list: TensorRank1List<D, J, W, V>) -> Self::Output {
118        self.iter()
119            .zip(tensor_rank_1_list)
120            .map(|(self_entry, entry)| Self::Output::from((self_entry, entry)))
121            .sum()
122    }
123}
124
125impl<const D: usize, I, J, const W: usize, U, V> Mul<&TensorRank1List<D, J, W, V>>
126    for &TensorRank1List<D, I, W, U>
127where
128    U: UnitMul<V>,
129{
130    type Output = TensorRank2<D, I, J, <U as UnitMul<V>>::Output>;
131    fn mul(self, tensor_rank_1_list: &TensorRank1List<D, J, W, V>) -> Self::Output {
132        self.iter()
133            .zip(tensor_rank_1_list.iter())
134            .map(|(self_entry, entry)| Self::Output::from((self_entry, entry)))
135            .sum()
136    }
137}
138
139impl<const D: usize, I, const W: usize, U> FiniteDifference for TensorRank1List<D, I, W, U> {
140    fn error_fd(&self, comparator: &Self, epsilon: TensorRank0) -> Option<(bool, usize)> {
141        let error_count = self
142            .iter()
143            .zip(comparator.iter())
144            .map(|(entry, comparator_entry)| {
145                entry
146                    .iter()
147                    .zip(comparator_entry.iter())
148                    .filter(|&(&entry_i, &comparator_entry_i)| {
149                        entry_i.differs(comparator_entry_i, epsilon)
150                    })
151                    .count()
152            })
153            .sum();
154        if error_count > 0 {
155            let auxiliary = self
156                .iter()
157                .zip(comparator.iter())
158                .map(|(entry, comparator_entry)| {
159                    entry
160                        .iter()
161                        .zip(comparator_entry.iter())
162                        .filter(|&(&entry_i, &comparator_entry_i)| {
163                            entry_i.differs_severely(comparator_entry_i, epsilon)
164                        })
165                        .count()
166                })
167                .sum::<usize>()
168                > 0;
169            Some((auxiliary, error_count))
170        } else {
171            None
172        }
173    }
174}