use core::ops::{Add, Index, IndexMut, Mul, Neg, Sub};
use num_traits::{Zero, real::Real as _};
#[cfg(feature = "testing")]
use super::Chart;
use super::{Field, LieGroup, Metric, Real, calculus::NondegenerateLift};
use crate::{
impl_group_via_add, impl_vector_ops,
traits::{Interval, Point},
};
pub trait Euclidean:
Bilinear<F: Real, Action = BothSided> + InnerProduct + NondegenerateLift + Vector
{
#[cfg(feature = "testing")]
fn check_pythagorean(a: &Self, b: &Self) -> bool {
let dist_sq = a.distance(b);
let dist_sq = dist_sq * dist_sq;
let diff = a.clone() - b.clone();
let norm_sq = diff.norm_squared();
dist_sq == norm_sq
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Dual<V: Tensor>(V);
#[doc(hidden)]
pub enum Undecorated {}
#[doc(hidden)]
pub enum Dualized {}
#[doc(hidden)]
pub enum Sinistered {}
#[doc(hidden)]
pub enum DualSinistered {}
#[doc(hidden)]
pub trait TensorDecoration {
type ToggleDual: TensorDecoration;
type ToggleSinister: TensorDecoration;
type Hand<H: Handedness>: Handedness;
}
impl TensorDecoration for Undecorated {
type ToggleDual = Dualized;
type ToggleSinister = Sinistered;
type Hand<H: Handedness> = H;
}
impl TensorDecoration for Dualized {
type ToggleDual = Undecorated;
type ToggleSinister = DualSinistered;
type Hand<H: Handedness> = H::Opposite;
}
impl TensorDecoration for Sinistered {
type ToggleDual = DualSinistered;
type ToggleSinister = Undecorated;
type Hand<H: Handedness> = H::Opposite;
}
impl TensorDecoration for DualSinistered {
type ToggleDual = Sinistered;
type ToggleSinister = Dualized;
type Hand<H: Handedness> = H;
}
#[doc(hidden)]
pub trait ApplyTensorDecoration<V: Tensor>: TensorDecoration {
type Output: Tensor<F = V::F, Action = V::Action, Hand = Self::Hand<V::Hand>>;
fn apply(v: V) -> Self::Output;
}
impl<V: Tensor> ApplyTensorDecoration<V> for Undecorated {
type Output = V;
fn apply(v: V) -> V {
v
}
}
impl<V: Tensor> ApplyTensorDecoration<V> for Dualized {
type Output = Dual<V>;
fn apply(v: V) -> Dual<V> {
Dual(v)
}
}
impl<V: Tensor<Action = BothSided>> ApplyTensorDecoration<V> for Sinistered {
type Output = Sinister<V>;
fn apply(v: V) -> Sinister<V> {
Sinister(v)
}
}
impl<V: Tensor<Action = BothSided>> ApplyTensorDecoration<V> for DualSinistered {
type Output = Sinister<Dual<V>>;
fn apply(v: V) -> Sinister<Dual<V>> {
Sinister(Dual(v))
}
}
#[doc(hidden)]
pub trait NormalizeWith<D: TensorDecoration>: Tensor {
type Normalized: Tensor<F = Self::F, Action = Self::Action, Hand = D::Hand<Self::Hand>>;
fn normalize_with(self) -> Self::Normalized;
}
pub struct Atomic;
#[doc(hidden)]
pub struct NormalizeDual;
#[doc(hidden)]
pub struct NormalizeSinister;
impl<T: Tensor> TensorNormalizer<T> for Atomic {
type Undecorated = T;
type Dualized = Dual<T>;
type Sinistered
= Sinister<T>
where
T::Action: Rehandable;
type DualSinistered
= Sinister<Dual<T>>
where
T::Action: Rehandable;
fn undecorated(tensor: T) -> Self::Undecorated {
tensor
}
fn dualized(tensor: T) -> Self::Dualized {
Dual(tensor)
}
fn sinistered(tensor: T) -> Self::Sinistered
where
T::Action: Rehandable,
{
Sinister(tensor)
}
fn dual_sinistered(tensor: T) -> Self::DualSinistered
where
T::Action: Rehandable,
{
Sinister(Dual(tensor))
}
}
pub trait Normalize: Tensor + NormalizeWith<Undecorated> {
fn normalize(self) -> <Self as NormalizeWith<Undecorated>>::Normalized {
<Self as NormalizeWith<Undecorated>>::normalize_with(self)
}
}
impl<T: Tensor + NormalizeWith<Undecorated>> Normalize for T {}
impl<V: Tensor> Dual<V> {
pub fn from_raw(v: V) -> Self {
Self(v)
}
pub fn to_raw(v: Self) -> V {
v.0
}
}
impl<V: Tensor> TensorNormalizer<Dual<V>> for NormalizeDual {
type Undecorated = <V as NormalizeWith<Dualized>>::Normalized;
type Dualized = <V as NormalizeWith<Undecorated>>::Normalized;
type Sinistered
= <V as NormalizeWith<DualSinistered>>::Normalized
where
V::Action: Rehandable;
type DualSinistered
= <V as NormalizeWith<Sinistered>>::Normalized
where
V::Action: Rehandable;
fn undecorated(tensor: Dual<V>) -> Self::Undecorated {
<V as NormalizeWith<Dualized>>::normalize_with(tensor.0)
}
fn dualized(tensor: Dual<V>) -> Self::Dualized {
<V as NormalizeWith<Undecorated>>::normalize_with(tensor.0)
}
fn sinistered(tensor: Dual<V>) -> Self::Sinistered
where
V::Action: Rehandable,
{
<V as NormalizeWith<DualSinistered>>::normalize_with(tensor.0)
}
fn dual_sinistered(tensor: Dual<V>) -> Self::DualSinistered
where
V::Action: Rehandable,
{
<V as NormalizeWith<Sinistered>>::normalize_with(tensor.0)
}
}
impl<V: Tensor> Tensor for Dual<V> {
type Normalization = NormalizeDual;
type F = V::F;
type Hand = <V::Hand as Handedness>::Opposite;
type Action = V::Action;
type Array<T: Point> = V::Array<T>;
fn from_fn(f: impl FnMut(usize) -> Self::F) -> Self {
Self(V::from_fn(f))
}
}
impl_vector_ops!(Dual<V>, V: Tensor);
impl<V: Tensor> AsRef<<Dual<V> as Tensor>::Array<V::F>> for Dual<V> {
fn as_ref(&self) -> &<Dual<V> as Tensor>::Array<V::F> {
self.0.as_ref()
}
}
impl<V: Tensor> AsMut<<Dual<V> as Tensor>::Array<V::F>> for Dual<V> {
fn as_mut(&mut self) -> &mut <Dual<V> as Tensor>::Array<V::F> {
self.0.as_mut()
}
}
impl<V: Nondegenerate> Form for Dual<V> {
fn flat(&self) -> Dual<Self> {
Dual(Dual(V::sharp(self.clone())))
}
}
impl<V: Nondegenerate> Nondegenerate for Dual<V> {
fn sharp(v: Dual<Self>) -> Self {
v.0.0.flat()
}
}
impl<V: Nondegenerate + Sesquilinear> Sesquilinear for Dual<V> where Self: Vector {}
impl<V: Nondegenerate + Interval> Interval for Dual<V> {
type R = V::R;
fn interval_squared(&self, other: &Self) -> Self::R {
let a = V::sharp(self.clone());
let b = V::sharp(other.clone());
a.interval_squared(&b)
}
}
impl<V: Nondegenerate + Metric> Metric for Dual<V> {}
impl<V: Euclidean> Euclidean for Dual<V> {}
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Sinister<V: Tensor<Action: Rehandable>>(pub V);
pub trait ApplicableTensorDecoration<T: Tensor>:
TensorDecoration + ApplyTensorDecoration<T>
{
}
impl<T: Tensor> ApplicableTensorDecoration<T> for Undecorated {}
impl<T: Tensor> ApplicableTensorDecoration<T> for Dualized {}
impl<T: Tensor<Action = BothSided>> ApplicableTensorDecoration<T> for Sinistered {}
impl<T: Tensor<Action = BothSided>> ApplicableTensorDecoration<T> for DualSinistered {}
#[doc(hidden)]
pub trait TensorNormalizer<T: Tensor> {
type Undecorated: Tensor<F = T::F, Action = T::Action, Hand = T::Hand>;
type Dualized: Tensor<F = T::F, Action = T::Action, Hand = <T::Hand as Handedness>::Opposite>;
type Sinistered: Tensor<F = T::F, Action = T::Action, Hand = <T::Hand as Handedness>::Opposite>
where
T::Action: Rehandable;
type DualSinistered: Tensor<F = T::F, Action = T::Action, Hand = T::Hand>
where
T::Action: Rehandable;
fn undecorated(tensor: T) -> Self::Undecorated;
fn dualized(tensor: T) -> Self::Dualized;
fn sinistered(tensor: T) -> Self::Sinistered
where
T::Action: Rehandable;
fn dual_sinistered(tensor: T) -> Self::DualSinistered
where
T::Action: Rehandable;
}
impl<V> TensorNormalizer<Sinister<V>> for NormalizeSinister
where
V: Tensor<Action: Rehandable>,
{
type Undecorated = <V as NormalizeWith<Sinistered>>::Normalized;
type Dualized = <V as NormalizeWith<DualSinistered>>::Normalized;
type Sinistered = <V as NormalizeWith<Undecorated>>::Normalized;
type DualSinistered = <V as NormalizeWith<Dualized>>::Normalized;
fn undecorated(tensor: Sinister<V>) -> Self::Undecorated {
<V as NormalizeWith<Sinistered>>::normalize_with(tensor.0)
}
fn dualized(tensor: Sinister<V>) -> Self::Dualized {
<V as NormalizeWith<DualSinistered>>::normalize_with(tensor.0)
}
fn sinistered(tensor: Sinister<V>) -> Self::Sinistered {
<V as NormalizeWith<Undecorated>>::normalize_with(tensor.0)
}
fn dual_sinistered(tensor: Sinister<V>) -> Self::DualSinistered {
<V as NormalizeWith<Dualized>>::normalize_with(tensor.0)
}
}
impl<V: Tensor<Action: Rehandable>> Tensor for Sinister<V> {
type Normalization = NormalizeSinister;
type F = V::F;
type Hand = <V::Hand as Handedness>::Opposite;
type Action = V::Action;
type Array<T: Point> = V::Array<T>;
fn from_fn(f: impl FnMut(usize) -> Self::F) -> Self {
Self(V::from_fn(f))
}
}
impl<T: Tensor> NormalizeWith<Undecorated> for T {
type Normalized = <T::Normalization as TensorNormalizer<T>>::Undecorated;
fn normalize_with(self) -> Self::Normalized {
<T::Normalization as TensorNormalizer<T>>::undecorated(self)
}
}
impl<T: Tensor> NormalizeWith<Dualized> for T {
type Normalized = <T::Normalization as TensorNormalizer<T>>::Dualized;
fn normalize_with(self) -> Self::Normalized {
<T::Normalization as TensorNormalizer<T>>::dualized(self)
}
}
impl<T> NormalizeWith<Sinistered> for T
where
T: Tensor,
T::Action: Rehandable,
{
type Normalized = <T::Normalization as TensorNormalizer<T>>::Sinistered;
fn normalize_with(self) -> Self::Normalized {
<T::Normalization as TensorNormalizer<T>>::sinistered(self)
}
}
impl<T> NormalizeWith<DualSinistered> for T
where
T: Tensor,
T::Action: Rehandable,
{
type Normalized = <T::Normalization as TensorNormalizer<T>>::DualSinistered;
fn normalize_with(self) -> Self::Normalized {
<T::Normalization as TensorNormalizer<T>>::dual_sinistered(self)
}
}
impl_vector_ops!(
Sinister<V>,
V: Tensor<Action: Rehandable>
);
impl<V: Tensor<Action: Rehandable>> AsRef<<Sinister<V> as Tensor>::Array<V::F>> for Sinister<V> {
fn as_ref(&self) -> &<Sinister<V> as Tensor>::Array<V::F> {
self.0.as_ref()
}
}
impl<V: Tensor<Action: Rehandable>> AsMut<<Sinister<V> as Tensor>::Array<V::F>> for Sinister<V> {
fn as_mut(&mut self) -> &mut <Sinister<V> as Tensor>::Array<V::F> {
self.0.as_mut()
}
}
impl<V> Form for Sinister<V>
where
V: Form<Action = BothSided>,
{
fn flat(&self) -> Dual<Self> {
let flat: Dual<V> = self.0.flat();
Dual(Sinister(flat.0))
}
}
impl<V: Nondegenerate<Action = BothSided>> Nondegenerate for Sinister<V> {
fn sharp(v: Dual<Self>) -> Self {
Sinister(V::sharp(Dual(v.0.0)))
}
}
impl<V: Bilinear<Action = BothSided>> Sesquilinear for Sinister<V> {}
impl<V: Tensor<Action = BothSided> + Interval> Interval for Sinister<V> {
type R = V::R;
fn interval_squared(&self, other: &Self) -> Self::R {
self.0.interval_squared(&other.0)
}
}
impl<V: Tensor<Action = BothSided> + Metric> Metric for Sinister<V> {}
impl<V: Euclidean> Euclidean for Sinister<V> {}
#[derive(Debug, Copy, Clone)]
pub enum Hand {
Left,
Right,
}
pub trait Handedness {
type Opposite: Handedness<Opposite = Self>;
const H: Hand;
}
pub enum Left {}
pub enum Right {}
impl Handedness for Left {
type Opposite = Right;
const H: Hand = Hand::Left;
}
impl Handedness for Right {
type Opposite = Left;
const H: Hand = Hand::Right;
}
pub trait Sidedness: Copy + Clone + core::fmt::Debug {
type Meet<T: Sidedness>: Sidedness;
#[doc(hidden)]
type MeetOne: Sidedness;
const S: Side;
}
#[derive(Debug, Copy, Clone)]
pub enum Side {
None,
Same,
Both,
}
#[derive(Debug, Copy, Clone)]
pub enum NoSided {}
#[derive(Debug, Copy, Clone)]
pub enum OneSided {}
#[derive(Debug, Copy, Clone)]
pub enum BothSided {}
pub trait ActionExists: Sidedness {
type Product<T: ActionExists>: Sidedness;
#[doc(hidden)]
type ProductOne: Sidedness;
}
impl ActionExists for OneSided {
type Product<T: ActionExists> = <T as ActionExists>::ProductOne;
type ProductOne = NoSided;
}
impl ActionExists for BothSided {
type Product<T: ActionExists> = T;
type ProductOne = OneSided;
}
pub trait Rehandable: ActionExists {}
impl Rehandable for BothSided {}
pub trait TensorProductAction<Rhs: ActionExists>: ActionExists {
type Action: Sidedness;
type Hand: Handedness;
}
impl<T: ActionExists> TensorProductAction<T> for OneSided {
type Action = <OneSided as ActionExists>::Product<T>;
type Hand = Right;
}
impl TensorProductAction<OneSided> for BothSided {
type Action = OneSided;
type Hand = Left;
}
impl TensorProductAction<BothSided> for BothSided {
type Action = BothSided;
type Hand = Right;
}
impl Sidedness for OneSided {
type Meet<T: Sidedness> = T::MeetOne;
type MeetOne = OneSided;
const S: Side = Side::Same;
}
impl Sidedness for BothSided {
type Meet<T: Sidedness> = T;
type MeetOne = OneSided;
const S: Side = Side::Both;
}
impl Sidedness for NoSided {
type Meet<T: Sidedness> = NoSided;
type MeetOne = NoSided;
const S: Side = Side::None;
}
pub trait Array<T: Point>:
Point + Sized + Index<usize, Output = T> + IndexMut<usize> + IntoIterator<Item = T>
{
const N: usize;
type Iter<'a>: Iterator<Item = &'a T>
where
Self: 'a,
T: 'a;
type IterMut<'a>: Iterator<Item = &'a mut T>
where
Self: 'a,
T: 'a;
fn iter(&self) -> Self::Iter<'_>;
fn iter_mut(&mut self) -> Self::IterMut<'_>;
fn from_fn(f: impl FnMut(usize) -> T) -> Self;
}
impl<T: Point, const N: usize> Array<T> for [T; N] {
const N: usize = N;
type Iter<'a>
= core::slice::Iter<'a, T>
where
Self: 'a,
T: 'a;
type IterMut<'a>
= core::slice::IterMut<'a, T>
where
Self: 'a,
T: 'a;
fn iter(&self) -> Self::Iter<'_> {
self.as_slice().iter()
}
fn iter_mut(&mut self) -> Self::IterMut<'_> {
self.as_mut_slice().iter_mut()
}
fn from_fn(f: impl FnMut(usize) -> T) -> Self {
core::array::from_fn(f)
}
}
impl<V: Tensor<Action = BothSided>> Sinister<Sinister<V>> {
pub fn collapse(self) -> V {
self.0.0
}
}
impl<V: Tensor> Dual<Dual<V>> {
pub fn collapse(self) -> V {
self.0.0
}
}
impl<V: Tensor<Action = BothSided>> Dual<Sinister<V>> {
pub fn dual_sinister(self) -> Sinister<Dual<V>> {
Sinister(Dual(self.0.0))
}
}
impl<V: Tensor<Action = BothSided>> Sinister<Dual<V>> {
pub fn sinister_dual(self) -> Dual<Sinister<V>> {
Dual(Sinister(self.0.0))
}
}
pub trait Tensor:
Add<Output = Self>
+ Sub<Output = Self>
+ Neg<Output = Self>
+ Zero
+ Index<usize, Output = Self::F>
+ IndexMut<usize>
+ Point
+ AsRef<Self::Array<Self::F>>
+ AsMut<Self::Array<Self::F>>
{
type F: Field;
const N: usize = Self::Array::<Self::F>::N;
type Array<T: Point>: Array<T>;
type Hand: Handedness;
type Action: Sidedness;
type Normalization: TensorNormalizer<Self>;
fn from_fn(f: impl FnMut(usize) -> Self::F) -> Self;
fn iter(&self) -> <Self::Array<Self::F> as Array<Self::F>>::Iter<'_> {
self.as_ref().iter()
}
fn map(&self, mut f: impl FnMut(Self::F) -> Self::F) -> Self {
Self::from_fn(|i| f(self[i]))
}
fn pairing(&self, rhs: &Dual<Self>) -> Self::F {
self.iter()
.zip(rhs.iter())
.fold(Self::F::zero(), |acc, (&vector, &covector)| {
acc + match <Self::Hand as Handedness>::H {
Hand::Left => vector * covector,
Hand::Right => covector * vector,
}
})
}
fn from_iter(iter: impl IntoIterator<Item = Self::F>) -> Self {
let mut iter = iter.into_iter();
let out = Self::from_fn(|_| {
iter.next()
.unwrap_or_else(|| panic!("iterator contained fewer than {} elements", Self::N))
});
assert!(
iter.next().is_none(),
"iterator contained more than {} elements",
Self::N,
);
out
}
fn flatten_index<const R: usize>(index: [usize; R]) -> usize {
let dimension = (1..=Self::N)
.find(|&i| i.pow(R as u32) == Self::N)
.expect("tensor component count is not an exact R-th power");
index.into_iter().fold(0, |flat, i| {
assert!(
i < dimension,
"tensor component index {i} out of bounds for dimension {dimension}"
);
flat * dimension + i
})
}
#[cfg(feature = "testing")]
fn check_global_chart(p: &Self, q: &Self) -> bool {
let chart = Self::chart_at(p);
chart.to_local(q).is_some()
}
#[cfg(feature = "testing")]
fn check_global_geodesic_scaling(p: &Self, v: Self, t: <Self::F as Field>::Fixed) -> bool
where
Self: Vector + PartialEq,
{
let t = Self::F::from_fixed(t);
let chart = Self::chart_at(p);
match (
chart.to_local(&chart.to_global(v.clone() * t)),
chart.to_local(&chart.to_global(v)),
) {
(Some(tv_local), Some(v_local)) => tv_local == v_local * t,
_ => false,
}
}
}
pub trait Vector: Tensor<Action: ActionExists> + Mul<Self::F, Output = Self> {}
impl<V: Tensor<Action: ActionExists> + Mul<Self::F, Output = Self>> Vector for V {}
#[macro_export]
macro_rules! impl_vector_ops {
($target:ty, $($generics:tt)*) => {
impl<$($generics)*> core::ops::Add<Self> for $target {
type Output = $target;
fn add(self, rhs: Self) -> Self::Output {
Self::from_fn(|i| self[i] + rhs[i])
}
}
impl<$($generics)*> core::ops::Sub<Self> for $target {
type Output = $target;
fn sub(self, rhs: Self) -> Self::Output {
Self::from_fn(|i| self[i] - rhs[i])
}
}
impl<$($generics)*> core::ops::Neg for $target {
type Output = $target;
fn neg(self) -> Self::Output {
Self::from_fn(|i| -self[i])
}
}
impl<$($generics)*> core::ops::Mul<<$target as $crate::traits::Tensor>::F> for $target
where
$target: $crate::traits::Tensor<Action: $crate::traits::ActionExists>,
{
type Output = $target;
fn mul(self, scalar: <$target as $crate::traits::Tensor>::F) -> Self::Output {
Self::from_fn(|i| match <<$target as $crate::traits::Tensor>::Hand as $crate::traits::Handedness>::H {
$crate::traits::Hand::Left => scalar * self[i],
$crate::traits::Hand::Right => self[i] * scalar,
})
}
}
impl<$($generics)*> num_traits::Zero for $target {
fn zero() -> Self {
Self::from_fn(|_| <$target as $crate::traits::Tensor>::F::zero())
}
fn is_zero(&self) -> bool {
self.iter().all(num_traits::Zero::is_zero)
}
}
impl<$($generics)*> core::ops::Index<usize> for $target {
type Output = <$target as $crate::traits::Tensor>::F;
fn index(&self, index: usize) -> &Self::Output {
&self.as_ref()[index]
}
}
impl<$($generics)*> core::ops::IndexMut<usize> for $target {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.as_mut()[index]
}
}
impl<const R: usize, $($generics)*> core::ops::Index<[usize; R]> for $target
where
$target: $crate::traits::Tensor,
{
type Output = <$target as $crate::traits::Tensor>::F;
fn index(&self, index: [usize; R]) -> &Self::Output {
&self[<$target as $crate::traits::Tensor>::flatten_index(index)]
}
}
impl<const R: usize, $($generics)*> core::ops::IndexMut<[usize; R]> for $target
where
$target: $crate::traits::Tensor,
{
fn index_mut(&mut self, index: [usize; R]) -> &mut Self::Output {
let flat =
<$target as $crate::traits::Tensor>::flatten_index(index);
&mut self[flat]
}
}
};
}
pub trait Form: Tensor {
fn flat(&self) -> Dual<Self>;
fn dot(&self, b: &Self) -> Self::F {
self.pairing(&b.flat())
}
fn self_dot(&self) -> Self::F {
self.dot(self)
}
#[cfg(feature = "testing")]
fn check_dot_agrees_with_pairing(a: &Self, b: &Self) -> bool {
a.pairing(&b.flat()) == a.dot(b)
}
#[cfg(feature = "testing")]
fn check_translation_invariance(a: &Self, b: &Self, c: &Self) -> bool {
let diff = a.clone() - b.clone();
let diff_translated = (a.clone() + c.clone()) - (b.clone() + c.clone());
diff.self_dot() == diff_translated.self_dot()
}
}
pub trait Nondegenerate: Form {
fn sharp(v: Dual<Self>) -> Self;
#[cfg(feature = "testing")]
fn check_isomorphism(a: &Self) -> bool
where
Self: PartialEq<Self>,
{
let flat = a.flat();
Self::sharp(flat.clone()) == *a && Dual::<Self>::sharp(flat.flat()) == flat
}
}
impl_group_via_add!(V, V: Tensor);
impl<V: Tensor> LieGroup<V> for V {
fn identity_exp(v: V) -> Self {
v
}
fn identity_log(p: &Self) -> Option<V> {
Some(p.clone())
}
}
pub trait Bilinear: Sesquilinear {}
impl<F: Field<Fixed = F>, V: Sesquilinear<F = F>> Bilinear for V {}
pub trait Sesquilinear: Form + Vector {
fn norm_squared(&self) -> <Self::F as Field>::Fixed {
self.dot(self).to_fixed()
}
#[cfg(feature = "testing")]
fn check_hermitian_symmetry(a: Self, b: Self) -> bool {
a.dot(&b) == b.dot(&a).conj()
}
#[cfg(feature = "testing")]
fn check_additivity(a: Self, b: Self, c: Self) -> bool {
(a.clone() + b.clone()).dot(&c) == a.dot(&c) + b.dot(&c)
}
#[cfg(feature = "testing")]
fn check_scalar_linearity(a: Self, c: Self, k: Self::F) -> bool {
let dot = a.dot(&c);
(a * k).dot(&c)
== match <Self as Tensor>::Hand::H {
Hand::Right => dot * k,
Hand::Left => k * dot,
}
}
}
pub trait InnerProduct:
Sesquilinear + Nondegenerate + Metric<R = <Self::F as Field>::Fixed>
where
<Self::F as Field>::Fixed: Real,
{
fn norm(&self) -> <Self::F as Field>::Fixed {
self.norm_squared().sqrt()
}
#[cfg(feature = "testing")]
fn check_positive_definite(a: Self) -> bool
where
Self: Zero + PartialEq,
{
a == Self::zero() || a.norm() > <Self::F as Field>::Fixed::zero()
}
#[cfg(feature = "testing")]
fn check_metric_compatibility(a: Self, b: Self) -> bool {
a.clone().sub(b.clone()).norm_squared().sqrt() == a.distance(&b)
}
}
impl<P: Sesquilinear + Nondegenerate + Metric<R = <Self::F as Field>::Fixed>> InnerProduct for P where
<Self::F as Field>::Fixed: Real
{
}