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}; /// Operations for column vectors impl Vector { /// Compute the dot product of two vectors, otherwise known as the scalar product. /// This is the sum of the elementwise product, or in math terms /// /// $vec(a) * vec(b) = sum_(i=1)^n a_i b_i = a_1 b_1 + a_2 b_2 + ... + a_n b_n$ /// /// for example, $[[1],[2],[3]] * [[4],[5],[6]] = (1 * 4) + (2 * 5) + (3 * 6) = 32$ /// /// For vectors in euclidean space, this has the property that it is equal to the magnitudes of /// the vectors times the cosine of the angle between them. /// /// $vec(a) * vec(b) = |vec(a)| |vec(b)| cos(theta)$ /// /// this also gives it the special property that the dot product of a vector and itself is the /// square of its magnitude. You may recognize the 2D version as the /// [pythagorean theorem](https://en.wikipedia.org/wiki/Pythagorean_theorem). /// /// see [dot product](https://en.wikipedia.org/wiki/Dot_product) on Wikipedia for more /// information. pub fn dot(&self, rhs: &R) -> T where for<'s> &'s Self: Mul<&'s R, Output = Self>, T: Sum, { (self * rhs).elements().cloned().sum() } pub fn sqrmag(&self) -> T where for<'s> &'s Self: Mul<&'s Self, Output = Self>, T: Sum, { self.dot(self) } pub fn mag(&self) -> T where T: Sum + Mul + Real, { self.sqrmag().sqrt() } pub fn normalized(&self) -> Option where T: Sum + Mul + Real, { match self.mag() { mag if mag.abs() < T::epsilon() => None, mag => Some(self / mag), } } } /// Cross product operations for column vectors in $RR^3$ impl Vector { pub fn cross_r(&self, rhs: &Vector) -> Self where T: NumOps + 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(&self, rhs: &Vector) -> Vector where R: NumOps + NumOps, { rhs.cross_r(self) } } /// Operations for Matrices impl Matrix { pub fn mmul(&self, rhs: &Matrix) -> Matrix where T: Default + NumOps + Sum, { let mut result: Matrix = Default::default(); for (m, a) in self.rows().enumerate() { for (n, b) in rhs.cols().enumerate() { result[(m, n)] = a.dot(&b) } } return result; } /// Computes the absolute value of each element of the matrix pub fn abs(&self) -> Self where T: Signed + Default, { self.elements().map(|&x| x.abs()).collect() } /// Computes the sign of each element of the matrix pub fn signum(&self) -> Self where T: Signed + Default, { self.elements().map(|&x| x.signum()).collect() } /// Raises every element to the power of rhs, where rhs is either a scalar or a matrix of exponents pub fn pow(self, rhs: R) -> O where Self: Pow, { Pow::pow(self, rhs) } } // Sum up matrices impl Sum for Matrix where Self: Zero + Add, { fn sum>(iter: I) -> Self { iter.fold(Self::zero(), Self::add) } } // Product of matrices impl Product for Matrix where Self: One + Mul, { fn product>(iter: I) -> Self { iter.fold(Self::one(), Self::mul) } } /// Inverse trait. Note that this is the elementwise inverse, not the matrix inverse. /// For the inverse matrix see [`LUDecomposable::inv()`](crate::decompose::LUDecompose::inv()) impl + Default, const M: usize, const N: usize> Inv for Matrix { type Output = Self; fn inv(self) -> Self::Output { self.elements().map(|t| t.inv()).collect() } } /// Pow for $Matrix^{scalar}$ impl Pow for Matrix where T: Copy + Pow, R: Copy + Num, O: Copy + Default, { type Output = Matrix; fn pow(self, rhs: R) -> Self::Output { self.elements().map(|&x| x.pow(rhs)).collect() } } /// Pow for $Matrix^{Matrix}$ impl Pow> for Matrix where T: Copy + Pow, R: Copy, O: Copy + Default, { type Output = Matrix; fn pow(self, rhs: Matrix) -> Self::Output { zip(self.elements(), rhs.elements()) .map(|(x, &r)| x.pow(r)) .collect() } }