conspire/math/tensor/
mod.rs

1pub mod test;
2
3pub mod list;
4pub mod rank_0;
5pub mod rank_1;
6pub mod rank_2;
7pub mod rank_3;
8pub mod rank_4;
9pub mod tuple;
10pub mod vec;
11
12use super::{SquareMatrix, Vector};
13use crate::defeat_message;
14use rank_0::{
15    TensorRank0,
16    list::{TensorRank0List, vec::TensorRank0ListVec},
17};
18use std::{
19    fmt::{self, Debug, Display, Formatter},
20    iter::Sum,
21    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
22};
23
24/// A scalar.
25pub type Scalar = TensorRank0;
26
27/// A vector of scalars.
28pub type Scalars = Vector;
29
30/// A list of scalars.
31pub type ScalarList<const N: usize> = TensorRank0List<N>;
32
33/// A vector of lists of scalars.
34pub type ScalarListVec<const N: usize> = TensorRank0ListVec<N>;
35
36/// Possible errors for tensors.
37#[derive(PartialEq)]
38pub enum TensorError {
39    NotPositiveDefinite,
40    SymmetricMatrixComplexEigenvalues,
41}
42
43impl Debug for TensorError {
44    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
45        let error = match self {
46            Self::NotPositiveDefinite => "\x1b[1;91mResult is not positive definite.".to_string(),
47            Self::SymmetricMatrixComplexEigenvalues => {
48                "\x1b[1;91mSymmetric matrix produced complex eigenvalues".to_string()
49            }
50        };
51        write!(f, "\n{error}\n\x1b[0;2;31m{}\x1b[0m\n", defeat_message())
52    }
53}
54
55impl Display for TensorError {
56    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
57        let error = match self {
58            Self::NotPositiveDefinite => "\x1b[1;91mResult is not positive definite.".to_string(),
59            Self::SymmetricMatrixComplexEigenvalues => {
60                "\x1b[1;91mSymmetric matrix produced complex eigenvalues".to_string()
61            }
62        };
63        write!(f, "{error}\x1b[0m")
64    }
65}
66
67/// Common methods for solutions.
68pub trait Solution
69where
70    Self: From<Vector> + Tensor,
71{
72    /// Decrements the solution from another vector.
73    fn decrement_from(&mut self, other: &Vector);
74    /// Decrements the solution chained with a vector from another vector.
75    fn decrement_from_chained(&mut self, other: &mut Vector, vector: Vector);
76    /// Decrements the solution from another vector on retained entries.
77    fn decrement_from_retained(&mut self, _retained: &[bool], _other: &Vector) {
78        unimplemented!()
79    }
80}
81
82/// Common methods for Jacobians.
83pub trait Jacobian
84where
85    Self:
86        From<Vector> + Tensor + Sub<Vector, Output = Self> + for<'a> Sub<&'a Vector, Output = Self>,
87{
88    /// Fills the Jacobian into a vector.
89    fn fill_into(self, vector: &mut Vector);
90    /// Fills the Jacobian chained with a vector into another vector.
91    fn fill_into_chained(self, other: Vector, vector: &mut Vector);
92    /// Return only the retained indices.
93    fn retain_from(self, _retained: &[bool]) -> Vector {
94        unimplemented!()
95    }
96    /// Zero out the specified indices.
97    fn zero_out(&mut self, _indices: &[usize]) {
98        unimplemented!()
99    }
100}
101
102/// Common methods for Hessians.
103pub trait Hessian
104where
105    Self: Tensor,
106{
107    /// Fills the Hessian into a square matrix.
108    fn fill_into(self, square_matrix: &mut SquareMatrix);
109    /// Return only the retained indices.
110    fn retain_from(self, _retained: &[bool]) -> SquareMatrix {
111        unimplemented!()
112    }
113}
114
115/// Common methods for rank-2 tensors.
116pub trait Rank2
117where
118    Self: Sized,
119{
120    /// The type that is the transpose of the tensor.
121    type Transpose;
122    /// Returns the deviatoric component of the rank-2 tensor.
123    fn deviatoric(&self) -> Self;
124    /// Returns the deviatoric component and trace of the rank-2 tensor.
125    fn deviatoric_and_trace(&self) -> (Self, TensorRank0);
126    /// Checks whether the tensor is a diagonal tensor.
127    fn is_diagonal(&self) -> bool;
128    /// Checks whether the tensor is the identity tensor.
129    fn is_identity(&self) -> bool;
130    /// Checks whether the tensor is a symmetric tensor.
131    fn is_symmetric(&self) -> bool;
132    /// Returns the second invariant of the rank-2 tensor.
133    fn second_invariant(&self) -> TensorRank0 {
134        0.5 * (self.trace().powi(2) - self.squared_trace())
135    }
136    /// Returns the trace of the rank-2 tensor squared.
137    fn squared_trace(&self) -> TensorRank0;
138    /// Returns the trace of the rank-2 tensor.
139    fn trace(&self) -> TensorRank0;
140    /// Returns the transpose of the rank-2 tensor.
141    fn transpose(&self) -> Self::Transpose;
142}
143
144/// Common methods for tensors.
145#[allow(clippy::len_without_is_empty)]
146pub trait Tensor
147where
148    for<'a> Self: Sized
149        + Add<Self, Output = Self>
150        + Add<&'a Self, Output = Self>
151        + AddAssign
152        + AddAssign<&'a Self>
153        + Clone
154        + Debug
155        + Default
156        + Display
157        + Div<TensorRank0, Output = Self>
158        // + Div<&'a TensorRank0, Output = Self>
159        + DivAssign<TensorRank0>
160        + DivAssign<&'a TensorRank0>
161        + Mul<TensorRank0, Output = Self>
162        // + Mul<&'a TensorRank0, Output = Self>
163        + MulAssign<TensorRank0>
164        + MulAssign<&'a TensorRank0>
165        + Sub<Self, Output = Self>
166        + Sub<&'a Self, Output = Self>
167        + SubAssign
168        + SubAssign<&'a Self>
169        + Sum,
170    Self::Item: Tensor,
171{
172    /// The type of item encountered when iterating over the tensor.
173    type Item;
174    /// Returns number of different entries given absolute and relative tolerances.
175    fn error_count(&self, other: &Self, tol_abs: Scalar, tol_rel: Scalar) -> Option<usize> {
176        let error_count = self
177            .iter()
178            .zip(other.iter())
179            .filter_map(|(self_entry, other_entry)| {
180                self_entry.error_count(other_entry, tol_abs, tol_rel)
181            })
182            .sum();
183        if error_count > 0 {
184            Some(error_count)
185        } else {
186            None
187        }
188    }
189    /// Returns the full contraction with another tensor.
190    fn full_contraction(&self, tensor: &Self) -> TensorRank0 {
191        self.iter()
192            .zip(tensor.iter())
193            .map(|(self_entry, tensor_entry)| self_entry.full_contraction(tensor_entry))
194            .sum()
195    }
196    /// Checks whether the tensor is the zero tensor.
197    fn is_zero(&self) -> bool {
198        self.iter().filter(|entry| !entry.is_zero()).count() == 0
199    }
200    /// Returns an iterator.
201    ///
202    /// The iterator yields all items from start to end. [Read more](https://doc.rust-lang.org/std/iter/)
203    fn iter(&self) -> impl Iterator<Item = &Self::Item>;
204    /// Returns an iterator that allows modifying each value.
205    ///
206    /// The iterator yields all items from start to end. [Read more](https://doc.rust-lang.org/std/iter/)
207    fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item>;
208    /// Returns the number of elements, also referred to as the ‘length’.
209    fn len(&self) -> usize;
210    /// Returns the tensor norm.
211    fn norm(&self) -> TensorRank0 {
212        self.norm_squared().sqrt()
213    }
214    /// Returns the infinity norm.
215    fn norm_inf(&self) -> TensorRank0 {
216        self.iter()
217            .fold(0.0, |acc, entry| entry.norm_inf().max(acc))
218    }
219    /// Returns the tensor norm squared.
220    fn norm_squared(&self) -> TensorRank0 {
221        self.full_contraction(self)
222    }
223    /// Normalizes the tensor.
224    fn normalize(&mut self) {
225        *self /= self.norm()
226    }
227    /// Returns the tensor normalized.
228    fn normalized(self) -> Self {
229        let norm = self.norm();
230        self / norm
231    }
232    /// Returns the total number of entries.
233    fn size(&self) -> usize;
234    /// Returns the positive difference of the two tensors.
235    fn sub_abs(&self, other: &Self) -> Self {
236        let mut difference = self.clone();
237        difference
238            .iter_mut()
239            .zip(self.iter().zip(other.iter()))
240            .for_each(|(entry, (self_entry, other_entry))| {
241                *entry = self_entry.sub_abs(other_entry)
242            });
243        difference
244    }
245    /// Returns the relative difference of the two tensors.
246    fn sub_rel(&self, other: &Self) -> Self {
247        let mut difference = self.clone();
248        difference
249            .iter_mut()
250            .zip(self.iter().zip(other.iter()))
251            .for_each(|(entry, (self_entry, other_entry))| {
252                *entry = self_entry.sub_rel(other_entry)
253            });
254        difference
255    }
256}
257
258/// Common methods for tensors derived from arrays.
259pub trait TensorArray {
260    /// The type of array corresponding to the tensor.
261    type Array;
262    /// The type of item encountered when iterating over the tensor.
263    type Item;
264    /// Returns the tensor as an array.
265    fn as_array(&self) -> Self::Array;
266    /// Returns the identity tensor.
267    fn identity() -> Self;
268    /// Returns the zero tensor.
269    fn zero() -> Self;
270}
271
272/// Common methods for tensors derived from Vec.
273pub trait TensorVec
274where
275    Self: FromIterator<Self::Item> + Index<usize, Output = Self::Item> + IndexMut<usize>,
276{
277    /// The type of element encountered when iterating over the tensor.
278    type Item;
279    /// Moves all the elements of other into self, leaving other empty.
280    fn append(&mut self, other: &mut Self);
281    /// Returns the total number of elements the vector can hold without reallocating.
282    fn capacity(&self) -> usize;
283    /// Returns `true` if the vector contains no elements.
284    fn is_empty(&self) -> bool;
285    /// Constructs a new, empty Vec, not allocating until elements are pushed onto it.
286    fn new() -> Self;
287    /// Appends an element to the back of the Vec.
288    fn push(&mut self, item: Self::Item);
289    /// Removes an element from the Vec and returns it, shifting elements to the left.
290    fn remove(&mut self, _index: usize) -> Self::Item;
291    /// Retains only the elements specified by the predicate.
292    fn retain<F>(&mut self, f: F)
293    where
294        F: FnMut(&Self::Item) -> bool;
295    /// Removes an element from the Vec and returns it, replacing it with the last element.
296    fn swap_remove(&mut self, _index: usize) -> Self::Item;
297}