conspire/math/tensor/
mod.rs1pub mod test;
2
3pub mod list;
4pub mod norm;
5pub mod rank_0;
6pub mod rank_1;
7pub mod rank_2;
8pub mod rank_3;
9pub mod rank_4;
10pub mod tuple;
11pub mod vec;
12
13pub use norm::Norm;
14
15use super::{SquareMatrix, Vector};
16use crate::math::{Style, StyledError, styled_error};
17use rank_0::{
18 TensorRank0,
19 list::{TensorRank0List, vec::TensorRank0ListVec},
20};
21use std::{
22 fmt::{Debug, Display},
23 iter::Sum,
24 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
25};
26
27pub type Scalar = TensorRank0;
29
30pub type Scalars = Vector;
32
33pub type ScalarList<const N: usize> = TensorRank0List<N>;
35
36pub type ScalarListVec<const N: usize> = TensorRank0ListVec<N>;
38
39#[derive(PartialEq)]
41pub enum TensorError {
42 NotPositiveDefinite,
43 SymmetricMatrixComplexEigenvalues,
44}
45
46impl StyledError for TensorError {
47 fn message(&self, style: &Style) -> String {
48 let h = style.headline;
49 match self {
50 Self::NotPositiveDefinite => format!("{h}Result is not positive definite."),
51 Self::SymmetricMatrixComplexEigenvalues => {
52 format!("{h}Symmetric matrix produced complex eigenvalues")
53 }
54 }
55 }
56}
57
58styled_error!(TensorError);
59
60pub trait Solution
62where
63 Self: From<Vector> + Tensor,
64{
65 fn decrement_from(&mut self, other: &Vector);
67 fn decrement_from_chained(&mut self, other: &mut Vector, vector: Vector);
69 fn decrement_from_retained(&mut self, _retained: &[bool], _other: &Vector) {
71 unimplemented!()
72 }
73}
74
75pub trait Jacobian
77where
78 Self:
79 From<Vector> + Tensor + Sub<Vector, Output = Self> + for<'a> Sub<&'a Vector, Output = Self>,
80{
81 fn fill_into(self, vector: &mut Vector);
83 fn fill_into_chained(self, other: Vector, vector: &mut Vector);
85 fn retain_from(self, _retained: &[bool]) -> Vector {
87 unimplemented!()
88 }
89 fn zero_out(&mut self, _indices: &[usize]) {
91 unimplemented!()
92 }
93}
94
95pub trait Hessian
97where
98 Self: Tensor,
99{
100 fn fill_into(self, square_matrix: &mut SquareMatrix);
102 fn retain_from(self, _retained: &[bool]) -> SquareMatrix {
104 unimplemented!()
105 }
106}
107
108pub trait Rank2
110where
111 Self: Sized,
112{
113 type Transpose;
115 fn deviatoric(&self) -> Self;
117 fn deviatoric_and_trace(&self) -> (Self, TensorRank0);
119 fn is_diagonal(&self) -> bool;
121 fn is_identity(&self) -> bool;
123 fn is_symmetric(&self) -> bool;
125 fn second_invariant(&self) -> TensorRank0 {
127 0.5 * (self.trace().powi(2) - self.squared_trace())
128 }
129 fn squared_trace(&self) -> TensorRank0;
131 fn trace(&self) -> TensorRank0;
133 fn transpose(&self) -> Self::Transpose;
135}
136
137#[allow(clippy::len_without_is_empty)]
139pub trait Tensor
140where
141 for<'a> Self: Sized
142 + Add<Self, Output = Self>
143 + Add<&'a Self, Output = Self>
144 + AddAssign
145 + AddAssign<&'a Self>
146 + Clone
147 + Debug
148 + Default
149 + Display
150 + Div<TensorRank0, Output = Self>
151 + DivAssign<TensorRank0>
153 + DivAssign<&'a TensorRank0>
154 + Mul<TensorRank0, Output = Self>
155 + MulAssign<TensorRank0>
157 + MulAssign<&'a TensorRank0>
158 + Sub<Self, Output = Self>
159 + Sub<&'a Self, Output = Self>
160 + SubAssign
161 + SubAssign<&'a Self>
162 + Sum,
163 Self::Item: Tensor,
164{
165 type Item;
167 fn error_count(&self, other: &Self, tol_abs: Scalar, tol_rel: Scalar) -> Option<usize> {
169 let error_count = self
170 .iter()
171 .zip(other.iter())
172 .filter_map(|(self_entry, other_entry)| {
173 self_entry.error_count(other_entry, tol_abs, tol_rel)
174 })
175 .sum();
176 if error_count > 0 {
177 Some(error_count)
178 } else {
179 None
180 }
181 }
182 fn full_contraction(&self, tensor: &Self) -> TensorRank0 {
184 self.iter()
185 .zip(tensor.iter())
186 .map(|(self_entry, tensor_entry)| self_entry.full_contraction(tensor_entry))
187 .sum()
188 }
189 fn is_zero(&self) -> bool {
191 self.iter().filter(|entry| !entry.is_zero()).count() == 0
192 }
193 fn iter(&self) -> impl Iterator<Item = &Self::Item>;
197 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item>;
201 fn len(&self) -> usize;
203 fn norm(&self) -> TensorRank0 {
205 self.norm_squared().sqrt()
206 }
207 fn norm_inf(&self) -> TensorRank0 {
209 self.iter()
210 .fold(0.0, |acc, entry| entry.norm_inf().max(acc))
211 }
212 fn norm_l1(&self) -> TensorRank0 {
214 self.iter().fold(0.0, |acc, entry| acc + entry.norm_l1())
215 }
216 fn norm_p_sum(&self, p: TensorRank0) -> TensorRank0 {
218 self.iter()
219 .fold(0.0, |acc, entry| acc + entry.norm_p_sum(p))
220 }
221 fn norm_p(&self, p: TensorRank0) -> TensorRank0 {
223 self.norm_p_sum(p).powf(1.0 / p)
224 }
225 fn norm_squared(&self) -> TensorRank0 {
227 self.full_contraction(self)
228 }
229 fn normalize(&mut self) {
231 *self /= self.norm()
232 }
233 fn normalized(self) -> Self {
235 let norm = self.norm();
236 self / norm
237 }
238 fn size(&self) -> usize;
240 fn sub_abs(&self, other: &Self) -> Self {
242 let mut difference = self.clone();
243 difference
244 .iter_mut()
245 .zip(self.iter().zip(other.iter()))
246 .for_each(|(entry, (self_entry, other_entry))| {
247 *entry = self_entry.sub_abs(other_entry)
248 });
249 difference
250 }
251 fn sub_rel(&self, other: &Self) -> Self {
253 let mut difference = self.clone();
254 difference
255 .iter_mut()
256 .zip(self.iter().zip(other.iter()))
257 .for_each(|(entry, (self_entry, other_entry))| {
258 *entry = self_entry.sub_rel(other_entry)
259 });
260 difference
261 }
262}
263
264pub trait TensorArray {
266 type Array;
268 type Item;
270 fn as_array(&self) -> Self::Array;
272 fn identity() -> Self;
274 fn zero() -> Self;
276}
277
278pub trait TensorVec
280where
281 Self: FromIterator<Self::Item> + Index<usize, Output = Self::Item> + IndexMut<usize>,
282{
283 type Item;
285 fn append(&mut self, other: &mut Self);
287 fn capacity(&self) -> usize;
289 fn is_empty(&self) -> bool;
291 fn new() -> Self;
293 fn push(&mut self, item: Self::Item);
295 fn remove(&mut self, index: usize) -> Self::Item;
297 fn reserve(&mut self, additional: usize);
299 fn retain<F>(&mut self, f: F)
301 where
302 F: FnMut(&Self::Item) -> bool;
303 fn swap_remove(&mut self, index: usize) -> Self::Item;
305 fn with_capacity(capacity: usize) -> Self;
307}