pub mod test;
pub mod list;
pub mod rank_0;
pub mod rank_1;
pub mod rank_2;
pub mod rank_3;
pub mod rank_4;
pub mod tuple;
pub mod vec;
use super::{SquareMatrix, Vector};
use crate::defeat_message;
use rank_0::{
TensorRank0,
list::{TensorRank0List, vec::TensorRank0ListVec},
};
use std::{
fmt::{self, Debug, Display, Formatter},
iter::Sum,
ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
};
pub type Scalar = TensorRank0;
pub type Scalars = Vector;
pub type ScalarList<const N: usize> = TensorRank0List<N>;
pub type ScalarListVec<const N: usize> = TensorRank0ListVec<N>;
#[derive(PartialEq)]
pub enum TensorError {
NotPositiveDefinite,
SymmetricMatrixComplexEigenvalues,
}
impl Debug for TensorError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let error = match self {
Self::NotPositiveDefinite => "\x1b[1;91mResult is not positive definite.".to_string(),
Self::SymmetricMatrixComplexEigenvalues => {
"\x1b[1;91mSymmetric matrix produced complex eigenvalues".to_string()
}
};
write!(f, "\n{error}\n\x1b[0;2;31m{}\x1b[0m\n", defeat_message())
}
}
impl Display for TensorError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let error = match self {
Self::NotPositiveDefinite => "\x1b[1;91mResult is not positive definite.".to_string(),
Self::SymmetricMatrixComplexEigenvalues => {
"\x1b[1;91mSymmetric matrix produced complex eigenvalues".to_string()
}
};
write!(f, "{error}\x1b[0m")
}
}
pub trait Solution
where
Self: From<Vector> + Tensor,
{
fn decrement_from(&mut self, other: &Vector);
fn decrement_from_chained(&mut self, other: &mut Vector, vector: Vector);
fn decrement_from_retained(&mut self, _retained: &[bool], _other: &Vector) {
unimplemented!()
}
}
pub trait Jacobian
where
Self:
From<Vector> + Tensor + Sub<Vector, Output = Self> + for<'a> Sub<&'a Vector, Output = Self>,
{
fn fill_into(self, vector: &mut Vector);
fn fill_into_chained(self, other: Vector, vector: &mut Vector);
fn retain_from(self, _retained: &[bool]) -> Vector {
unimplemented!()
}
fn zero_out(&mut self, _indices: &[usize]) {
unimplemented!()
}
}
pub trait Hessian
where
Self: Tensor,
{
fn fill_into(self, square_matrix: &mut SquareMatrix);
fn retain_from(self, _retained: &[bool]) -> SquareMatrix {
unimplemented!()
}
}
pub trait Rank2
where
Self: Sized,
{
type Transpose;
fn deviatoric(&self) -> Self;
fn deviatoric_and_trace(&self) -> (Self, TensorRank0);
fn is_diagonal(&self) -> bool;
fn is_identity(&self) -> bool;
fn is_symmetric(&self) -> bool;
fn second_invariant(&self) -> TensorRank0 {
0.5 * (self.trace().powi(2) - self.squared_trace())
}
fn squared_trace(&self) -> TensorRank0;
fn trace(&self) -> TensorRank0;
fn transpose(&self) -> Self::Transpose;
}
#[allow(clippy::len_without_is_empty)]
pub trait Tensor
where
for<'a> Self: Sized
+ Add<Self, Output = Self>
+ Add<&'a Self, Output = Self>
+ AddAssign
+ AddAssign<&'a Self>
+ Clone
+ Debug
+ Default
+ Display
+ Div<TensorRank0, Output = Self>
+ DivAssign<TensorRank0>
+ DivAssign<&'a TensorRank0>
+ Mul<TensorRank0, Output = Self>
+ MulAssign<TensorRank0>
+ MulAssign<&'a TensorRank0>
+ Sub<Self, Output = Self>
+ Sub<&'a Self, Output = Self>
+ SubAssign
+ SubAssign<&'a Self>
+ Sum,
Self::Item: Tensor,
{
type Item;
fn error_count(&self, other: &Self, tol_abs: Scalar, tol_rel: Scalar) -> Option<usize> {
let error_count = self
.iter()
.zip(other.iter())
.filter_map(|(self_entry, other_entry)| {
self_entry.error_count(other_entry, tol_abs, tol_rel)
})
.sum();
if error_count > 0 {
Some(error_count)
} else {
None
}
}
fn full_contraction(&self, tensor: &Self) -> TensorRank0 {
self.iter()
.zip(tensor.iter())
.map(|(self_entry, tensor_entry)| self_entry.full_contraction(tensor_entry))
.sum()
}
fn is_zero(&self) -> bool {
self.iter().filter(|entry| !entry.is_zero()).count() == 0
}
fn iter(&self) -> impl Iterator<Item = &Self::Item>;
fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item>;
fn len(&self) -> usize;
fn norm(&self) -> TensorRank0 {
self.norm_squared().sqrt()
}
fn norm_inf(&self) -> TensorRank0 {
self.iter()
.fold(0.0, |acc, entry| entry.norm_inf().max(acc))
}
fn norm_squared(&self) -> TensorRank0 {
self.full_contraction(self)
}
fn normalize(&mut self) {
*self /= self.norm()
}
fn normalized(self) -> Self {
let norm = self.norm();
self / norm
}
fn size(&self) -> usize;
fn sub_abs(&self, other: &Self) -> Self {
let mut difference = self.clone();
difference
.iter_mut()
.zip(self.iter().zip(other.iter()))
.for_each(|(entry, (self_entry, other_entry))| {
*entry = self_entry.sub_abs(other_entry)
});
difference
}
fn sub_rel(&self, other: &Self) -> Self {
let mut difference = self.clone();
difference
.iter_mut()
.zip(self.iter().zip(other.iter()))
.for_each(|(entry, (self_entry, other_entry))| {
*entry = self_entry.sub_rel(other_entry)
});
difference
}
}
pub trait TensorArray {
type Array;
type Item;
fn as_array(&self) -> Self::Array;
fn identity() -> Self;
fn zero() -> Self;
}
pub trait TensorVec
where
Self: FromIterator<Self::Item> + Index<usize, Output = Self::Item> + IndexMut<usize>,
{
type Item;
fn append(&mut self, other: &mut Self);
fn capacity(&self) -> usize;
fn is_empty(&self) -> bool;
fn new() -> Self;
fn push(&mut self, item: Self::Item);
fn remove(&mut self, _index: usize) -> Self::Item;
fn retain<F>(&mut self, f: F)
where
F: FnMut(&Self::Item) -> bool;
fn swap_remove(&mut self, _index: usize) -> Self::Item;
}