|
@@ -0,0 +1,247 @@
|
|
|
|
+use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign};
|
|
|
|
+
|
|
|
|
+use crate::{Numeric, Primitive};
|
|
|
|
+
|
|
|
|
+#[repr(transparent)]
|
|
|
|
+#[derive(Copy, Clone, Debug, PartialEq)]
|
|
|
|
+pub struct GenericMatrix<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> {
|
|
|
|
+ pub data: [[T; COLUMNS]; ROWS],
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub type SquareMatrix<T, const DIMENSION: usize> = GenericMatrix<T, DIMENSION, DIMENSION>;
|
|
|
|
+pub type ColumnVector<T, const ROWS: usize> = GenericMatrix<T, ROWS, 1>;
|
|
|
|
+pub type RowVector<T, const COLUMNS: usize> = GenericMatrix<T, 1, COLUMNS>;
|
|
|
|
+
|
|
|
|
+#[macro_export]
|
|
|
|
+macro_rules! rvec {
|
|
|
|
+ ($($value:expr),* $(,)?) => {
|
|
|
|
+ {
|
|
|
|
+ use crate::RowVector;
|
|
|
|
+ RowVector {
|
|
|
|
+ data: [[$( $value, )*]],
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[macro_export]
|
|
|
|
+macro_rules! cvec {
|
|
|
|
+ ($($value:expr),* $(,)?) => {
|
|
|
|
+ {
|
|
|
|
+ use crate::ColumnVector;
|
|
|
|
+ ColumnVector {
|
|
|
|
+ data: [$( [$value], )*],
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Default for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ fn default() -> Self {
|
|
|
|
+ let zero = unsafe { T::whole(0) };
|
|
|
|
+ Self {
|
|
|
|
+ data: [[zero; COLUMNS]; ROWS],
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ fn transpose(&self) -> GenericMatrix<T, COLUMNS, ROWS> {
|
|
|
|
+ let mut result = GenericMatrix::default();
|
|
|
|
+ for r in 0..ROWS {
|
|
|
|
+ for c in 0..COLUMNS {
|
|
|
|
+ result.data[c][r] = self.data[r][c];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ result
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const DIMENSION: usize> SquareMatrix<T, DIMENSION> {
|
|
|
|
+ fn identity() -> Self {
|
|
|
|
+ let mut mat = Self::default();
|
|
|
|
+ let one = unsafe { T::whole(1) };
|
|
|
|
+ for i in 0..DIMENSION {
|
|
|
|
+ mat.data[i][i] = one;
|
|
|
|
+ }
|
|
|
|
+ mat
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Index<(usize, usize)> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ type Output = T;
|
|
|
|
+
|
|
|
|
+ fn index(&self, index: (usize, usize)) -> &Self::Output {
|
|
|
|
+ let (row, column) = index;
|
|
|
|
+ &self.data[row][column]
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> IndexMut<(usize, usize)> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
|
|
|
|
+ let (row, column) = index;
|
|
|
|
+ &mut self.data[row][column]
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive + Neg<Output=T>, const ROWS: usize, const COLUMNS: usize> Neg for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ type Output = Self;
|
|
|
|
+
|
|
|
|
+ fn neg(self) -> Self::Output {
|
|
|
|
+ let mut result = Self::default();
|
|
|
|
+ for r in 0..ROWS {
|
|
|
|
+ for c in 0..COLUMNS {
|
|
|
|
+ result.data[r][c] = -self.data[r][c];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ result
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Add for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ type Output = Self;
|
|
|
|
+
|
|
|
|
+ fn add(mut self, rhs: Self) -> Self::Output {
|
|
|
|
+ self += rhs;
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> AddAssign for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ fn add_assign(&mut self, rhs: Self) {
|
|
|
|
+ for r in 0..ROWS {
|
|
|
|
+ for c in 0..COLUMNS {
|
|
|
|
+ self.data[r][c] += rhs.data[r][c];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Sub for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ type Output = Self;
|
|
|
|
+
|
|
|
|
+ fn sub(mut self, rhs: Self) -> Self::Output {
|
|
|
|
+ self -= rhs;
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> SubAssign for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ fn sub_assign(&mut self, rhs: Self) {
|
|
|
|
+ for r in 0..ROWS {
|
|
|
|
+ for c in 0..COLUMNS {
|
|
|
|
+ self.data[r][c] -= rhs.data[r][c];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Mul<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ type Output = Self;
|
|
|
|
+
|
|
|
|
+ fn mul(mut self, rhs: T) -> Self::Output {
|
|
|
|
+ self *= rhs;
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> MulAssign<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ fn mul_assign(&mut self, rhs: T) {
|
|
|
|
+ for r in 0..ROWS {
|
|
|
|
+ for c in 0..COLUMNS {
|
|
|
|
+ self.data[r][c] *= rhs;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Div<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ type Output = Self;
|
|
|
|
+
|
|
|
|
+ fn div(mut self, rhs: T) -> Self::Output {
|
|
|
|
+ self /= rhs;
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> DivAssign<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
|
+ fn div_assign(&mut self, rhs: T) {
|
|
|
|
+ for r in 0..ROWS {
|
|
|
|
+ for c in 0..COLUMNS {
|
|
|
|
+ self.data[r][c] /= rhs;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Numeric + Primitive, const ROWS: usize, const COMMON: usize, const COLUMNS: usize> Mul<GenericMatrix<T, COMMON, COLUMNS>> for GenericMatrix<T, ROWS, COMMON> {
|
|
|
|
+ type Output = GenericMatrix<T, ROWS, COLUMNS>;
|
|
|
|
+
|
|
|
|
+ fn mul(self, rhs: GenericMatrix<T, COMMON, COLUMNS>) -> Self::Output {
|
|
|
|
+ let mut result = Self::Output::default();
|
|
|
|
+ for i in 0..ROWS {
|
|
|
|
+ for j in 0..COLUMNS {
|
|
|
|
+ for k in 0..COMMON {
|
|
|
|
+ result.data[i][j] += self.data[i][k] * rhs.data[k][j];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ result
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(test)]
|
|
|
|
+mod tests {
|
|
|
|
+ use crate::GenericMatrix;
|
|
|
|
+ use crate::types::matrix::generic::SquareMatrix;
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn identity_matrix() {
|
|
|
|
+ let mat: SquareMatrix<f64, 3> = SquareMatrix::identity();
|
|
|
|
+ let expected = SquareMatrix {
|
|
|
|
+ data: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ assert_eq!(mat, expected);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ #[should_panic = "index out of bounds"]
|
|
|
|
+ fn out_of_bounds_access() {
|
|
|
|
+ let mat: SquareMatrix<f32, 1> = SquareMatrix::identity();
|
|
|
|
+ mat[(1, 0)];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn transposing_matrix() {
|
|
|
|
+ let mat = GenericMatrix {
|
|
|
|
+ data: [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]],
|
|
|
|
+ }.transpose();
|
|
|
|
+ let expected = GenericMatrix {
|
|
|
|
+ data: [[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]],
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ assert_eq!(mat, expected);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn negating_matrix() {
|
|
|
|
+ let mat = -GenericMatrix {
|
|
|
|
+ data: [[1, -1], [2, -2]],
|
|
|
|
+ };
|
|
|
|
+ let expected = GenericMatrix {
|
|
|
|
+ data: [[-1, 1], [-2, 2]],
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ assert_eq!(mat, expected);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn dot_product_of_vectors() {
|
|
|
|
+ let a = rvec![1, 3, -5];
|
|
|
|
+ let b = cvec![4, -2, -1];
|
|
|
|
+ let product = a * b;
|
|
|
|
+
|
|
|
|
+ assert_eq!(product[(0, 0)], 3);
|
|
|
|
+ }
|
|
|
|
+}
|