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::TensorRank0;
15use std::{
16 fmt::{self, Debug, Display, Formatter},
17 iter::Sum,
18 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
19};
20
21pub type Scalar = TensorRank0;
23
24#[derive(PartialEq)]
26pub enum TensorError {
27 NotPositiveDefinite,
28}
29
30impl Debug for TensorError {
31 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
32 let error = match self {
33 Self::NotPositiveDefinite => "\x1b[1;91mResult is not positive definite.".to_string(),
34 };
35 write!(f, "\n{error}\n\x1b[0;2;31m{}\x1b[0m\n", defeat_message())
36 }
37}
38
39impl Display for TensorError {
40 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
41 let error = match self {
42 Self::NotPositiveDefinite => "\x1b[1;91mResult is not positive definite.".to_string(),
43 };
44 write!(f, "{error}\x1b[0m")
45 }
46}
47
48pub trait Solution
50where
51 Self: From<Vector> + Tensor,
52{
53 fn decrement_from(&mut self, other: &Vector);
55 fn decrement_from_chained(&mut self, other: &mut Vector, vector: Vector);
57 fn decrement_from_retained(&mut self, _retained: &[bool], _other: &Vector) {
59 unimplemented!()
60 }
61}
62
63pub trait Jacobian
65where
66 Self:
67 From<Vector> + Tensor + Sub<Vector, Output = Self> + for<'a> Sub<&'a Vector, Output = Self>,
68{
69 fn fill_into(self, vector: &mut Vector);
71 fn fill_into_chained(self, other: Vector, vector: &mut Vector);
73 fn retain_from(self, _retained: &[bool]) -> Vector {
75 unimplemented!()
76 }
77 fn zero_out(&mut self, _indices: &[usize]) {
79 unimplemented!()
80 }
81}
82
83pub trait Hessian
85where
86 Self: Tensor,
87{
88 fn fill_into(self, square_matrix: &mut SquareMatrix);
90 fn retain_from(self, _retained: &[bool]) -> SquareMatrix {
92 unimplemented!()
93 }
94}
95
96pub trait Rank2
98where
99 Self: Sized,
100{
101 type Transpose;
103 fn deviatoric(&self) -> Self;
105 fn deviatoric_and_trace(&self) -> (Self, TensorRank0);
107 fn is_diagonal(&self) -> bool;
109 fn is_identity(&self) -> bool;
111 fn is_symmetric(&self) -> bool;
113 fn second_invariant(&self) -> TensorRank0 {
115 0.5 * (self.trace().powi(2) - self.squared_trace())
116 }
117 fn squared_trace(&self) -> TensorRank0;
119 fn trace(&self) -> TensorRank0;
121 fn transpose(&self) -> Self::Transpose;
123}
124
125#[allow(clippy::len_without_is_empty)]
127pub trait Tensor
128where
129 for<'a> Self: Sized
130 + Add<Self, Output = Self>
131 + Add<&'a Self, Output = Self>
132 + AddAssign
133 + AddAssign<&'a Self>
134 + Clone
135 + Debug
136 + Default
137 + Display
138 + Div<TensorRank0, Output = Self>
139 + Div<&'a TensorRank0, Output = Self>
140 + DivAssign<TensorRank0>
141 + DivAssign<&'a TensorRank0>
142 + Mul<TensorRank0, Output = Self>
143 + Mul<&'a TensorRank0, Output = Self>
144 + MulAssign<TensorRank0>
145 + MulAssign<&'a TensorRank0>
146 + Sub<Self, Output = Self>
147 + Sub<&'a Self, Output = Self>
148 + SubAssign
149 + SubAssign<&'a Self>
150 + Sum,
151 Self::Item: Tensor,
152{
153 type Item;
155 fn error_count(&self, other: &Self, tol_abs: &Scalar, tol_rel: &Scalar) -> Option<usize> {
157 let error_count = self
158 .iter()
159 .zip(other.iter())
160 .filter_map(|(self_entry, other_entry)| {
161 self_entry.error_count(other_entry, tol_abs, tol_rel)
162 })
163 .sum();
164 if error_count > 0 {
165 Some(error_count)
166 } else {
167 None
168 }
169 }
170 fn full_contraction(&self, tensor: &Self) -> TensorRank0 {
172 self.iter()
173 .zip(tensor.iter())
174 .map(|(self_entry, tensor_entry)| self_entry.full_contraction(tensor_entry))
175 .sum()
176 }
177 fn is_zero(&self) -> bool {
179 self.iter().filter(|entry| !entry.is_zero()).count() == 0
180 }
181 fn iter(&self) -> impl Iterator<Item = &Self::Item>;
185 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item>;
189 fn len(&self) -> usize;
191 fn norm(&self) -> TensorRank0 {
193 self.norm_squared().sqrt()
194 }
195 fn norm_inf(&self) -> TensorRank0 {
197 self.iter()
198 .fold(0.0, |acc, entry| entry.norm_inf().max(acc))
199 }
200 fn norm_squared(&self) -> TensorRank0 {
202 self.full_contraction(self)
203 }
204 fn normalize(&mut self) {
206 *self /= self.norm()
207 }
208 fn normalized(self) -> Self {
210 let norm = self.norm();
211 self / norm
212 }
213 fn size(&self) -> usize;
215 fn sub_abs(&self, other: &Self) -> Self {
217 let mut difference = self.clone();
218 difference
219 .iter_mut()
220 .zip(self.iter().zip(other.iter()))
221 .for_each(|(entry, (self_entry, other_entry))| {
222 *entry = self_entry.sub_abs(other_entry)
223 });
224 difference
225 }
226 fn sub_rel(&self, other: &Self) -> Self {
228 let mut difference = self.clone();
229 difference
230 .iter_mut()
231 .zip(self.iter().zip(other.iter()))
232 .for_each(|(entry, (self_entry, other_entry))| {
233 *entry = self_entry.sub_rel(other_entry)
234 });
235 difference
236 }
237}
238
239pub trait TensorArray {
241 type Array;
243 type Item;
245 fn as_array(&self) -> Self::Array;
247 fn identity() -> Self;
249 fn new(array: Self::Array) -> Self;
251 fn zero() -> Self;
253}
254
255pub trait TensorVec
257where
258 Self: FromIterator<Self::Item> + Index<usize, Output = Self::Item> + IndexMut<usize>,
259{
260 type Item;
262 fn append(&mut self, other: &mut Self);
264 fn capacity(&self) -> usize;
266 fn is_empty(&self) -> bool;
268 fn new() -> Self;
270 fn push(&mut self, item: Self::Item);
272 fn remove(&mut self, _index: usize) -> Self::Item;
274 fn retain<F>(&mut self, f: F)
276 where
277 F: FnMut(&Self::Item) -> bool;
278 fn swap_remove(&mut self, _index: usize) -> Self::Item;
280}