use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Mul, Neg, Sub};
use num_traits::{ConstZero, Zero};
use crate::traits::{
DivRing, Dual, Euclidean, Field, Form, Interval, Metric, Nondegenerate, Real, Sesquilinear,
Vector,
};
#[derive(Debug, Copy, Clone)]
pub struct Coords<F: Field, const N: usize, const M: usize = 0>([F; N]);
impl<F: Field, const N: usize, const M: usize> Zero for Coords<F, N, M> {
fn zero() -> Self {
[F::zero(); N].into()
}
fn is_zero(&self) -> bool {
self.iter().all(|x| x == &F::zero())
}
}
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, 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
}
}
impl<F: Field, const N: usize, const M: usize> Index<usize> for Coords<F, N, M> {
type Output = F;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl<F: Field, const N: usize, const M: usize> IndexMut<usize> for Coords<F, N, M> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
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] {
std::array::from_fn(|i| f(&a[i], &b[i]))
}
impl<F: Field, const N: usize, const M: usize> Add for Coords<F, N, M> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
array_zip_map(*self, *rhs, |&a, &b| a + b).into()
}
}
impl<F: Field, const N: usize, const M: usize> Sub for Coords<F, N, M> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
array_zip_map(*self, *rhs, |&a, &b| a - b).into()
}
}
impl<F: Field, const N: usize, const M: usize> Mul<F> for Coords<F, N, M> {
type Output = Self;
fn mul(self, rhs: F) -> Self::Output {
self.map(|x| x * rhs).into()
}
}
impl<F: Field, const N: usize, const M: usize> Neg for Coords<F, N, M> {
type Output = Self;
fn neg(self) -> Self::Output {
self.map(|x| -x).into()
}
}
impl<F: Field, const N: usize, const M: usize> Vector for Coords<F, N, M> {
type F = F;
const N: usize = N;
type Iter<'a>
= std::slice::Iter<'a, F>
where
Self: 'a;
fn iter(&self) -> Self::Iter<'_> {
self.0.iter()
}
fn from_fn(f: impl Fn(usize) -> Self::F) -> Self {
std::array::from_fn(f).into()
}
}
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<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> {}