Skip to main content

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

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