You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
5.0 KiB
Rust

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<T: Copy, const N: usize> Vector<T, N> {
/** 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<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),
}
}
}
/// Cross product operations for column vectors in $RR^3$
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)
}
}
/// Operations for Matrices
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;
}
/// 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<R, O>(self, rhs: R) -> O
where
Self: Pow<R, Output = O>,
{
Pow::pow(self, rhs)
}
}
// Sum up matrices
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)
}
}
// Product of matrices
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)
}
}
/// 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<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()
}
}
/// Pow for $Matrix^{scalar}$
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()
}
}
/// Pow for $Matrix^{Matrix}$
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()
}
}