conspire/math/tensor/
mod.rs

1// #[cfg(test)]
2pub mod test;
3
4pub mod rank_0;
5pub mod rank_1;
6pub mod rank_2;
7pub mod rank_3;
8pub mod rank_4;
9
10use super::{SquareMatrix, Vector};
11use crate::defeat_message;
12use rank_0::TensorRank0;
13use std::{
14    fmt::{self, Debug, Display, Formatter},
15    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, Sub, SubAssign},
16};
17
18/// Possible errors for tensors.
19#[derive(PartialEq)]
20pub enum TensorError {
21    NotPositiveDefinite,
22}
23
24impl Debug for TensorError {
25    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
26        let error = match self {
27            Self::NotPositiveDefinite => "\x1b[1;91mResult is not positive definite.".to_string(),
28        };
29        write!(f, "\n{}\n\x1b[0;2;31m{}\x1b[0m\n", error, defeat_message())
30    }
31}
32
33impl Display for TensorError {
34    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
35        let error = match self {
36            Self::NotPositiveDefinite => "\x1b[1;91mResult is not positive definite.".to_string(),
37        };
38        write!(f, "{}\x1b[0m", error)
39    }
40}
41
42/// Common methods for solutions.
43pub trait Solution
44where
45    Self: Tensor,
46{
47    /// Decrements the solution chained with a vector from another vector.
48    fn decrement_from_chained(&mut self, other: &mut Vector, vector: Vector);
49}
50
51/// Common methods for Jacobians.
52pub trait Jacobian
53where
54    Self: Tensor + Sub<Vector, Output = Self>,
55{
56    /// Fills the Jacobian into a vector.
57    fn fill_into(self, vector: &mut Vector);
58    /// Fills the Jacobian chained with a vector into another vector.
59    fn fill_into_chained(self, other: Vector, vector: &mut Vector);
60}
61
62/// Common methods for Hessians.
63pub trait Hessian
64where
65    Self: Tensor,
66{
67    /// Fills the Hessian into a square matrix.
68    fn fill_into(self, square_matrix: &mut SquareMatrix);
69    /// Checks whether the Hessian is positive-definite.
70    fn is_positive_definite(&self) -> bool;
71}
72
73/// Common methods for rank-2 tensors.
74pub trait Rank2
75where
76    Self: Sized,
77{
78    /// The type that is the transpose of the tensor.
79    type Transpose;
80    /// Returns the Cholesky decomposition of the rank-2 tensor.
81    fn cholesky_decomposition(&self) -> Result<Self, TensorError>;
82    /// Returns the deviatoric component of the rank-2 tensor.
83    fn deviatoric(&self) -> Self;
84    /// Returns the deviatoric component and trace of the rank-2 tensor.
85    fn deviatoric_and_trace(&self) -> (Self, TensorRank0);
86    /// Checks whether the tensor is a diagonal tensor.
87    fn is_diagonal(&self) -> bool;
88    /// Checks whether the tensor is the identity tensor.
89    fn is_identity(&self) -> bool;
90    /// Returns the second invariant of the rank-2 tensor.
91    fn second_invariant(&self) -> TensorRank0 {
92        0.5 * (self.trace().powi(2) - self.squared_trace())
93    }
94    /// Returns the trace of the rank-2 tensor squared.
95    fn squared_trace(&self) -> TensorRank0;
96    /// Returns the trace of the rank-2 tensor.
97    fn trace(&self) -> TensorRank0;
98    /// Returns the transpose of the rank-2 tensor.
99    fn transpose(&self) -> Self::Transpose;
100}
101
102/// Common methods for tensors.
103pub trait Tensor
104where
105    for<'a> Self: Sized
106        + Debug
107        + Display
108        + Add<Self, Output = Self>
109        + Add<&'a Self, Output = Self>
110        + AddAssign
111        + AddAssign<&'a Self>
112        + Clone
113        + Div<TensorRank0, Output = Self>
114        + DivAssign<TensorRank0>
115        + Mul<TensorRank0, Output = Self>
116        + Sub<Self, Output = Self>
117        + Sub<&'a Self, Output = Self>
118        + SubAssign
119        + SubAssign<&'a Self>,
120    Self::Item: Tensor,
121{
122    /// The type of item encountered when iterating over the tensor.
123    type Item;
124    /// Returns the full contraction with another tensor.
125    fn full_contraction(&self, tensor: &Self) -> TensorRank0 {
126        self.iter()
127            .zip(tensor.iter())
128            .map(|(self_entry, tensor_entry)| self_entry.full_contraction(tensor_entry))
129            .sum()
130    }
131    /// Checks whether the tensor is the zero tensor.
132    fn is_zero(&self) -> bool {
133        self.iter().filter(|entry| !entry.is_zero()).count() == 0
134    }
135    /// Returns an iterator.
136    ///
137    /// The iterator yields all items from start to end. [Read more](https://doc.rust-lang.org/std/iter/)
138    fn iter(&self) -> impl Iterator<Item = &Self::Item>;
139    /// Returns an iterator that allows modifying each value.
140    ///
141    /// The iterator yields all items from start to end. [Read more](https://doc.rust-lang.org/std/iter/)
142    fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item>;
143    /// Returns the tensor norm.
144    fn norm(&self) -> TensorRank0 {
145        self.norm_squared().sqrt()
146    }
147    /// Returns the infinity norm.
148    fn norm_inf(&self) -> TensorRank0 {
149        unimplemented!()
150    }
151    /// Returns the tensor norm squared.
152    fn norm_squared(&self) -> TensorRank0 {
153        self.full_contraction(self)
154    }
155    /// Normalizes the tensor.
156    fn normalize(&mut self) {
157        *self /= self.norm()
158    }
159    /// Returns the tensor normalized.
160    fn normalized(self) -> Self {
161        let norm = self.norm();
162        self / norm
163    }
164    /// Returns the total number of entries.
165    fn num_entries(&self) -> usize {
166        unimplemented!()
167    }
168}
169
170/// Common methods for tensors derived from arrays.
171pub trait TensorArray {
172    /// The type of array corresponding to the tensor.
173    type Array;
174    /// The type of item encountered when iterating over the tensor.
175    type Item;
176    /// Returns the tensor as an array.
177    fn as_array(&self) -> Self::Array;
178    /// Returns the identity tensor.
179    fn identity() -> Self;
180    /// Returns a tensor given an array.
181    fn new(array: Self::Array) -> Self;
182    /// Returns the zero tensor.
183    fn zero() -> Self;
184}
185
186/// Common methods for tensors derived from Vec.
187pub trait TensorVec
188where
189    Self: FromIterator<Self::Item> + Index<usize, Output = Self::Item> + IndexMut<usize>,
190{
191    /// The type of item encountered when iterating over the tensor.
192    type Item;
193    /// The type of slice corresponding to the tensor.
194    type Slice<'a>;
195    /// Moves all the items of other into self, leaving other empty.
196    fn append(&mut self, other: &mut Self);
197    /// Returns `true` if the vector contains no items.
198    fn is_empty(&self) -> bool;
199    /// Returns the number of items in the vector, also referred to as its ‘length’.
200    fn len(&self) -> usize;
201    /// Returns a tensor given a slice.
202    fn new(slice: Self::Slice<'_>) -> Self;
203    /// Appends an item to the back of the Vec.
204    fn push(&mut self, item: Self::Item);
205    /// Returns the zero tensor.
206    fn zero(len: usize) -> Self;
207}