فهرست منبع

:sparkles: started working on generic matrices

Felix Bytow 2 سال پیش
والد
کامیت
7521ff1ebe
6فایلهای تغییر یافته به همراه307 افزوده شده و 23 حذف شده
  1. 1 1
      src/lib.rs
  2. 30 21
      src/types/complex.rs
  3. 247 0
      src/types/matrix/generic.rs
  4. 3 0
      src/types/matrix/mod.rs
  5. 5 1
      src/types/mod.rs
  6. 21 0
      src/types/quaternion.rs

+ 1 - 1
src/lib.rs

@@ -12,7 +12,7 @@
 //! As a consequence the complex types `Complex<f32>` and `Complex<f64>` are also considered
 //! `Float` in our context.
 pub use self::traits::{Float, Numeric, Primitive};
-pub use self::types::Complex;
+pub use self::types::{ColumnVector, Complex, GenericMatrix, Quaternion, RowVector};
 
 mod traits;
 mod types;

+ 30 - 21
src/types/complex.rs

@@ -7,14 +7,14 @@ use crate::{Float, Numeric, Primitive};
 /// # Example
 ///
 /// ```rust
-/// # use lineal::{Complex, complex, Float, Numeric};
+/// # use lineal::{Complex, cplx, Float, Numeric};
 /// let c = Complex { real: 9.0, imag: 0.0 };
 /// assert_eq!(format!("{:?}", c), "Complex { real: 9.0, imag: 0.0 }");
 ///
 /// let three = c.sqrt().real;
 /// assert_eq!(three, 3.0);
 ///
-/// let i: Complex<f32> = complex!(-1.0).sqrt();
+/// let i: Complex<f32> = cplx!(-1.0).sqrt();
 /// assert_eq!(i, Complex::i());
 ///
 /// let a = Complex { real: 2.0, imag: 0.5 };
@@ -23,7 +23,7 @@ use crate::{Float, Numeric, Primitive};
 /// assert_eq!(a_squared.sqrt(), a);
 ///
 /// let x = (16.0).sqrt();
-/// let y = complex!(16.0).sqrt().real;
+/// let y = cplx!(16.0).sqrt().real;
 /// assert_eq!(x, y);
 /// ```
 #[derive(Debug, Copy, Clone)]
@@ -39,30 +39,39 @@ pub struct Complex<T: Float + Numeric + Primitive> {
 /// # Example
 ///
 /// ```rust
-/// # use lineal::{Complex, complex};
+/// # use lineal::{Complex, cplx};
 /// // just a real number
-/// let a = complex!(25.0);
+/// let a = cplx!(25.0);
 /// // first real, second imaginary
-/// let b = complex!(1.0, -1.0);
+/// let b = cplx!(1.0, -1.0);
 /// // with named arguments
-/// let c = complex!(real = -1.0,);
-/// let d = complex!(imag = 1.0,);
-/// let e = complex!(real = 1.1, imag = 0.0,);
+/// let c = cplx!(real = -1.0,);
+/// let d = cplx!(imag = 1.0,);
+/// let e = cplx!(real = 1.1, imag = 0.0,);
 /// // even reverse order
-/// let f = complex!(imag = 42.0, real = 23.0,);
+/// let f = cplx!(imag = 42.0, real = 23.0,);
 /// ```
 #[macro_export]
-macro_rules! complex {
+macro_rules! cplx {
     ($real:expr, $imag:expr) => {
-        Complex { real: $real, imag: $imag }
+        {
+            use crate::Complex;
+            Complex { real: $real, imag: $imag }
+        }
     };
     ($real:expr) => {
-        Complex { real: $real, imag: 0.0 }
+        {
+            use crate::Complex;
+            Complex { real: $real, imag: 0.0 }
+        }
     };
     ($($field:ident = $value:expr),* $(,)?) => {
-        Complex {
-            $( $field: $value, )*
-            ..Complex::default()
+        {
+            use crate::Complex;
+            Complex {
+                $( $field: $value, )*
+                ..Complex::default()
+            }
         }
     }
 }
@@ -258,14 +267,14 @@ mod tests {
 
     #[test]
     fn macro_creation() {
-        let a = complex!(-1.0);
-        let b = complex!(real = -1.0,);
+        let a = cplx!(-1.0);
+        let b = cplx!(real = -1.0,);
         assert_eq!(a, b);
-        let c = complex!(imag = 1.0,);
+        let c = cplx!(imag = 1.0,);
         assert_eq!(a.sqrt(), c);
-        let d = complex!(real = -1.0, imag = 0.0,);
+        let d = cplx!(real = -1.0, imag = 0.0,);
         assert_eq!(c * c, d);
-        let e = complex!(-1.0, 0.0);
+        let e = cplx!(-1.0, 0.0);
         assert_eq!(a, e);
     }
 

+ 247 - 0
src/types/matrix/generic.rs

@@ -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);
+    }
+}

+ 3 - 0
src/types/matrix/mod.rs

@@ -0,0 +1,3 @@
+pub use self::generic::{ColumnVector, GenericMatrix, RowVector};
+
+mod generic;

+ 5 - 1
src/types/mod.rs

@@ -1,3 +1,7 @@
-pub use complex::Complex;
+pub use self::complex::Complex;
+pub use self::matrix::{ColumnVector, GenericMatrix, RowVector};
+pub use self::quaternion::Quaternion;
 
 mod complex;
+mod matrix;
+mod quaternion;

+ 21 - 0
src/types/quaternion.rs

@@ -0,0 +1,21 @@
+use crate::{Float, Numeric, Primitive};
+
+#[derive(Debug, Copy, Clone)]
+pub struct Quaternion<T: Float + Numeric + Primitive> {
+    pub r: T,
+    pub i: T,
+    pub j: T,
+    pub k: T,
+}
+
+impl<T: Float + Numeric + Primitive> Default for Quaternion<T> {
+    fn default() -> Self {
+        let zero = unsafe { T::whole(0) };
+        Self {
+            r: zero,
+            i: zero,
+            j: zero,
+            k: zero,
+        }
+    }
+}