conspire/math/tensor/
mod.rs1pub 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
24pub type Scalar = TensorRank0;
26
27pub type Scalars = Vector;
29
30pub type ScalarList<const N: usize> = TensorRank0List<N>;
32
33pub type ScalarListVec<const N: usize> = TensorRank0ListVec<N>;
35
36#[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
67pub trait Solution
69where
70 Self: From<Vector> + Tensor,
71{
72 fn decrement_from(&mut self, other: &Vector);
74 fn decrement_from_chained(&mut self, other: &mut Vector, vector: Vector);
76 fn decrement_from_retained(&mut self, _retained: &[bool], _other: &Vector) {
78 unimplemented!()
79 }
80}
81
82pub trait Jacobian
84where
85 Self:
86 From<Vector> + Tensor + Sub<Vector, Output = Self> + for<'a> Sub<&'a Vector, Output = Self>,
87{
88 fn fill_into(self, vector: &mut Vector);
90 fn fill_into_chained(self, other: Vector, vector: &mut Vector);
92 fn retain_from(self, _retained: &[bool]) -> Vector {
94 unimplemented!()
95 }
96 fn zero_out(&mut self, _indices: &[usize]) {
98 unimplemented!()
99 }
100}
101
102pub trait Hessian
104where
105 Self: Tensor,
106{
107 fn fill_into(self, square_matrix: &mut SquareMatrix);
109 fn retain_from(self, _retained: &[bool]) -> SquareMatrix {
111 unimplemented!()
112 }
113}
114
115pub trait Rank2
117where
118 Self: Sized,
119{
120 type Transpose;
122 fn deviatoric(&self) -> Self;
124 fn deviatoric_and_trace(&self) -> (Self, TensorRank0);
126 fn is_diagonal(&self) -> bool;
128 fn is_identity(&self) -> bool;
130 fn is_symmetric(&self) -> bool;
132 fn second_invariant(&self) -> TensorRank0 {
134 0.5 * (self.trace().powi(2) - self.squared_trace())
135 }
136 fn squared_trace(&self) -> TensorRank0;
138 fn trace(&self) -> TensorRank0;
140 fn transpose(&self) -> Self::Transpose;
142}
143
144#[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 + DivAssign<TensorRank0>
160 + DivAssign<&'a TensorRank0>
161 + Mul<TensorRank0, Output = Self>
162 + 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 type Item;
174 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 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 fn is_zero(&self) -> bool {
198 self.iter().filter(|entry| !entry.is_zero()).count() == 0
199 }
200 fn iter(&self) -> impl Iterator<Item = &Self::Item>;
204 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item>;
208 fn len(&self) -> usize;
210 fn norm(&self) -> TensorRank0 {
212 self.norm_squared().sqrt()
213 }
214 fn norm_inf(&self) -> TensorRank0 {
216 self.iter()
217 .fold(0.0, |acc, entry| entry.norm_inf().max(acc))
218 }
219 fn norm_squared(&self) -> TensorRank0 {
221 self.full_contraction(self)
222 }
223 fn normalize(&mut self) {
225 *self /= self.norm()
226 }
227 fn normalized(self) -> Self {
229 let norm = self.norm();
230 self / norm
231 }
232 fn size(&self) -> usize;
234 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 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
258pub trait TensorArray {
260 type Array;
262 type Item;
264 fn as_array(&self) -> Self::Array;
266 fn identity() -> Self;
268 fn zero() -> Self;
270}
271
272pub trait TensorVec
274where
275 Self: FromIterator<Self::Item> + Index<usize, Output = Self::Item> + IndexMut<usize>,
276{
277 type Item;
279 fn append(&mut self, other: &mut Self);
281 fn capacity(&self) -> usize;
283 fn is_empty(&self) -> bool;
285 fn new() -> Self;
287 fn push(&mut self, item: Self::Item);
289 fn remove(&mut self, _index: usize) -> Self::Item;
291 fn retain<F>(&mut self, f: F)
293 where
294 F: FnMut(&Self::Item) -> bool;
295 fn swap_remove(&mut self, _index: usize) -> Self::Item;
297}