use core::ops::{Deref, DerefMut};
use num_traits::{ConstZero, Zero};
use crate::{
impl_vector_ops,
traits::{
Array, BothSided, DivRing, Dual, Euclidean, Field, Form, Interval, Metric, Nondegenerate,
Point, Real, Right, Sesquilinear, Tensor,
calculus::{FormLift, Jet, JetMode, NondegenerateLift},
},
};
#[derive(Debug, Copy, Clone)]
pub struct Coords<F: Field, const N: usize, const M: usize = 0>(pub [F; N]);
impl<F: Field + ConstZero, const N: usize, const M: usize> ConstZero for Coords<F, N, M> {
const ZERO: Self = Self([F::ZERO; N]);
}
impl<F: Field> From<F> for Coords<F, 1> {
fn from(value: F) -> Self {
Self([value])
}
}
impl<F: Field, const N: usize, const M: usize> Deref for Coords<F, N, M> {
type Target = [F; N];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<F: Field, const N: usize, const M: usize> DerefMut for Coords<F, N, M> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<F: Field, const N: usize, const M: usize> From<[F; N]> for Coords<F, N, M> {
fn from(arr: [F; N]) -> Self {
Self(arr)
}
}
impl<F: Field, const N: usize, const M: usize> From<Coords<F, N, M>> for [F; N] {
fn from(c: Coords<F, N, M>) -> Self {
c.0
}
}
pub(crate) fn array_zip_map<A, B, C, const N: usize>(
a: [A; N],
b: [B; N],
f: fn(&A, &B) -> C,
) -> [C; N] {
core::array::from_fn(|i| f(&a[i], &b[i]))
}
impl_vector_ops!(Coords<F, N, M>, F: Field, const N: usize, const M: usize);
impl<F: Field, const N: usize, const M: usize> Tensor for Coords<F, N, M> {
type F = F;
type Hand = Right;
type Action = BothSided;
type Array<T: Point> = [T; N];
fn from_fn(f: impl FnMut(usize) -> Self::F) -> Self {
Self(core::array::from_fn(f))
}
}
impl<F: Field, const N: usize, const M: usize> AsRef<[F; N]> for Coords<F, N, M> {
fn as_ref(&self) -> &[F; N] {
&self.0
}
}
impl<F: Field, const N: usize, const M: usize> AsMut<[F; N]> for Coords<F, N, M> {
fn as_mut(&mut self) -> &mut [F; N] {
&mut self.0
}
}
impl<R: Real, F: Field<Fixed = R>, const N: usize, const M: usize> Interval for Coords<F, N, M> {
type R = R;
fn interval_squared(&self, other: &Self) -> R {
(*self - *other).norm_squared()
}
}
impl<R: Field + Real, const N: usize> Metric for Coords<R, N, 0> {
fn distance(&self, other: &Self) -> R {
let displacement = *self - *other;
displacement.dot(&displacement).sqrt()
}
}
impl<F: Field, const N: usize, const M: usize> PartialEq for Coords<F, N, M> {
fn eq(&self, other: &Self) -> bool {
let scale = self
.iter()
.fold(F::Fixed::zero(), |acc, x| acc + x.norm_squared());
self.iter().zip(other.iter()).all(|(&a, &b)| {
let diff_sq = (a + (-b)).norm_squared();
if scale == F::Fixed::zero() {
diff_sq == F::Fixed::zero()
} else {
F::Fixed::zero() == diff_sq.div(scale) }
})
}
}
impl<R: Field, const N: usize, const M: usize> Form for Coords<R, N, M> {
fn flat(&self) -> Dual<Self> {
Dual::from_fn(|i| if i < M { -self[i] } else { self[i] }.conj())
}
}
impl<R: Field, const N: usize, const M: usize> Nondegenerate for Coords<R, N, M> {
fn sharp(v: Dual<Self>) -> Self {
Self::from_fn(|i| if i < M { -v[i] } else { v[i] }.conj())
}
}
impl<R: Field, const N: usize, const M: usize> FormLift for Coords<R, N, M> {
fn jet_flat_array<S: Field, Mode: JetMode, const K: usize>(
value: &<Self as Tensor>::Array<Jet<S, Mode, K>>,
) -> <Dual<Self> as Tensor>::Array<Jet<S, Mode, K>>
where
Jet<S, Mode, K>: Field,
{
<Dual<Self> as Tensor>::Array::from_fn(|i| if i < M { -value[i] } else { value[i] }.conj())
}
}
impl<R: Field, const N: usize, const M: usize> NondegenerateLift for Coords<R, N, M> {
fn jet_sharp_array<S: Field, Mode: JetMode, const K: usize>(
value: &<Dual<Self> as Tensor>::Array<Jet<S, Mode, K>>,
) -> <Self as Tensor>::Array<Jet<S, Mode, K>>
where
Jet<S, Mode, K>: Field,
{
<Self as Tensor>::Array::from_fn(|i| if i < M { -value[i] } else { value[i] }.conj())
}
}
impl<F: Field, const N: usize, const M: usize> Sesquilinear for Coords<F, N, M> {}
impl<R: Real, const N: usize> Euclidean for Coords<R, N, 0> {}