use crate::{Matrix, Vector};
use num_traits::real::Real;
use num_traits::{Inv, Num, NumOps, One, Pow, Signed, Zero};
use std::iter::{zip, Product, Sum};
use std::ops::{Add, Mul};
impl<T: Copy, const N: usize> Vector<T, N> {
pub fn dot<R>(&self, rhs: &R) -> T
where
for<'s> &'s Self: Mul<&'s R, Output = Self>,
T: Sum<T>,
{
(self * rhs).elements().cloned().sum()
}
pub fn sqrmag(&self) -> T
where
for<'s> &'s Self: Mul<&'s Self, Output = Self>,
T: Sum<T>,
{
self.dot(self)
}
pub fn mag(&self) -> T
where
T: Sum<T> + Mul<T> + Real,
{
self.sqrmag().sqrt()
}
pub fn normalized(&self) -> Option<Self>
where
T: Sum<T> + Mul<T> + Real,
{
match self.mag() {
mag if mag.abs() < T::epsilon() => None,
mag => Some(self / mag),
}
}
}
impl<T: Copy> Vector<T, 3> {
pub fn cross_r<R: Copy>(&self, rhs: &Vector<R, 3>) -> Self
where
T: NumOps<R> + NumOps,
{
Self::vec([
(self[1] * rhs[2]) - (self[2] * rhs[1]),
(self[2] * rhs[0]) - (self[0] * rhs[2]),
(self[0] * rhs[1]) - (self[1] * rhs[0]),
])
}
pub fn cross_l<R: Copy>(&self, rhs: &Vector<R, 3>) -> Vector<R, 3>
where
R: NumOps<T> + NumOps,
{
rhs.cross_r(self)
}
}
impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
pub fn mmul<R: Copy, const P: usize>(&self, rhs: &Matrix<R, N, P>) -> Matrix<T, M, P>
where
T: Default + NumOps<R> + Sum,
{
let mut result: Matrix<T, M, P> = Default::default();
for (m, a) in self.rows().enumerate() {
for (n, b) in rhs.cols().enumerate() {
result[(m, n)] = a.dot(&b)
}
}
return result;
}
pub fn abs(&self) -> Self
where
T: Signed + Default,
{
self.elements().map(|&x| x.abs()).collect()
}
pub fn signum(&self) -> Self
where
T: Signed + Default,
{
self.elements().map(|&x| x.signum()).collect()
}
pub fn pow<R, O>(self, rhs: R) -> O
where
Self: Pow<R, Output = O>,
{
Pow::pow(self, rhs)
}
}
impl<T: Copy, const M: usize, const N: usize> Sum for Matrix<T, M, N>
where
Self: Zero + Add<Output = Self>,
{
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::zero(), Self::add)
}
}
impl<T: Copy, const M: usize, const N: usize> Product for Matrix<T, M, N>
where
Self: One + Mul<Output = Self>,
{
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::one(), Self::mul)
}
}
impl<T: Copy + Inv<Output = T> + Default, const M: usize, const N: usize> Inv for Matrix<T, M, N> {
type Output = Self;
fn inv(self) -> Self::Output {
self.elements().map(|t| t.inv()).collect()
}
}
impl<T, R, O, const M: usize, const N: usize> Pow<R> for Matrix<T, M, N>
where
T: Copy + Pow<R, Output = O>,
R: Copy + Num,
O: Copy + Default,
{
type Output = Matrix<O, M, N>;
fn pow(self, rhs: R) -> Self::Output {
self.elements().map(|&x| x.pow(rhs)).collect()
}
}
impl<T, R, O, const M: usize, const N: usize> Pow<Matrix<R, M, N>> for Matrix<T, M, N>
where
T: Copy + Pow<R, Output = O>,
R: Copy,
O: Copy + Default,
{
type Output = Matrix<O, M, N>;
fn pow(self, rhs: Matrix<R, M, N>) -> Self::Output {
zip(self.elements(), rhs.elements())
.map(|(x, &r)| x.pow(r))
.collect()
}
}