|
@@ -1,22 +1,39 @@
|
|
|
use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign};
|
|
|
|
|
|
-use crate::{Numeric, Primitive};
|
|
|
+use crate::Numeric;
|
|
|
|
|
|
+/// Struct representing a dense matrix.
|
|
|
#[repr(transparent)]
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
|
-pub struct GenericMatrix<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> {
|
|
|
+pub struct GenericMatrix<T: Numeric, const ROWS: usize, const COLUMNS: usize> {
|
|
|
pub data: [[T; COLUMNS]; ROWS],
|
|
|
}
|
|
|
|
|
|
+/// Special kind of `GenericMatrix` where both dimensions are equal.
|
|
|
pub type SquareMatrix<T, const DIMENSION: usize> = GenericMatrix<T, DIMENSION, DIMENSION>;
|
|
|
+
|
|
|
+/// Special kind of `GenericMatrix` with just one column.
|
|
|
pub type ColumnVector<T, const ROWS: usize> = GenericMatrix<T, ROWS, 1>;
|
|
|
+
|
|
|
+/// Special kind of `GenericMatrix` with just one row.
|
|
|
pub type RowVector<T, const COLUMNS: usize> = GenericMatrix<T, 1, COLUMNS>;
|
|
|
|
|
|
+/// A macro for easier creation of row vectors.
|
|
|
+///
|
|
|
+/// # Example
|
|
|
+///
|
|
|
+/// ```rust
|
|
|
+/// # use lineal::{RowVector, rvec};
|
|
|
+/// let a = rvec![1.0, 2.0, 3.0];
|
|
|
+/// // is the same as
|
|
|
+/// let b = RowVector {
|
|
|
+/// data: [[1.0, 2.0, 3.0]],
|
|
|
+/// };
|
|
|
+/// ```
|
|
|
#[macro_export]
|
|
|
macro_rules! rvec {
|
|
|
($($value:expr),* $(,)?) => {
|
|
|
{
|
|
|
- use crate::RowVector;
|
|
|
RowVector {
|
|
|
data: [[$( $value, )*]],
|
|
|
}
|
|
@@ -24,11 +41,22 @@ macro_rules! rvec {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/// A macro for easier creation of column vectors.
|
|
|
+///
|
|
|
+/// # Example
|
|
|
+///
|
|
|
+/// ```rust
|
|
|
+/// # use lineal::{ColumnVector, cvec};
|
|
|
+/// let a = cvec![1.0, 2.0, 3.0];
|
|
|
+/// // is the same as
|
|
|
+/// let b = ColumnVector {
|
|
|
+/// data: [[1.0], [2.0], [3.0]],
|
|
|
+/// };
|
|
|
+/// ```
|
|
|
#[macro_export]
|
|
|
macro_rules! cvec {
|
|
|
($($value:expr),* $(,)?) => {
|
|
|
{
|
|
|
- use crate::ColumnVector;
|
|
|
ColumnVector {
|
|
|
data: [$( [$value], )*],
|
|
|
}
|
|
@@ -36,7 +64,8 @@ macro_rules! cvec {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Default for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Default for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+ /// Create a matrix with all cells being zero.
|
|
|
fn default() -> Self {
|
|
|
let zero = unsafe { T::whole(0) };
|
|
|
Self {
|
|
@@ -45,8 +74,18 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Default fo
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
- fn transpose(&self) -> GenericMatrix<T, COLUMNS, ROWS> {
|
|
|
+impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+ /// Create a transpose of the input matrix.
|
|
|
+ ///
|
|
|
+ /// # Example
|
|
|
+ ///
|
|
|
+ /// ```rust
|
|
|
+ /// # use lineal::{ColumnVector, RowVector, cvec, rvec};
|
|
|
+ /// let a = cvec![1, 2, 3];
|
|
|
+ /// let b = rvec![1, 2, 3];
|
|
|
+ /// assert_eq!(a.transposed(), b);
|
|
|
+ /// ```
|
|
|
+ pub fn transposed(&self) -> GenericMatrix<T, COLUMNS, ROWS> {
|
|
|
let mut result = GenericMatrix::default();
|
|
|
for r in 0..ROWS {
|
|
|
for c in 0..COLUMNS {
|
|
@@ -57,8 +96,23 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> GenericMat
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const DIMENSION: usize> SquareMatrix<T, DIMENSION> {
|
|
|
- fn identity() -> Self {
|
|
|
+impl<T: Numeric, const DIMENSION: usize> SquareMatrix<T, DIMENSION> {
|
|
|
+ /// Create a square identity matrix.
|
|
|
+ ///
|
|
|
+ /// In an identity matrix the main diagonal is filled with ones,
|
|
|
+ /// while the rest if the cells are zero.
|
|
|
+ ///
|
|
|
+ /// # Example
|
|
|
+ ///
|
|
|
+ /// ```rust
|
|
|
+ /// # use lineal::{SquareMatrix};
|
|
|
+ /// let a: SquareMatrix<f32, 3> = SquareMatrix::identity();
|
|
|
+ /// // is the same as
|
|
|
+ /// let b: SquareMatrix<f32, 3> = SquareMatrix {
|
|
|
+ /// data: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
|
|
|
+ /// };
|
|
|
+ /// ```
|
|
|
+ pub fn identity() -> Self {
|
|
|
let mut mat = Self::default();
|
|
|
let one = unsafe { T::whole(1) };
|
|
|
for i in 0..DIMENSION {
|
|
@@ -66,9 +120,33 @@ impl<T: Numeric + Primitive, const DIMENSION: usize> SquareMatrix<T, DIMENSION>
|
|
|
}
|
|
|
mat
|
|
|
}
|
|
|
+
|
|
|
+ /// Create a square matrix with its main diagonal filled with the given values.
|
|
|
+ ///
|
|
|
+ /// # Example
|
|
|
+ ///
|
|
|
+ /// ```rust
|
|
|
+ /// # use lineal::{SquareMatrix};
|
|
|
+ /// let a = SquareMatrix::diagonal(&[1, 2, 3]);
|
|
|
+ /// // is the same as
|
|
|
+ /// let b = SquareMatrix {
|
|
|
+ /// data: [
|
|
|
+ /// [1, 0, 0],
|
|
|
+ /// [0, 2, 0],
|
|
|
+ /// [0, 0, 3],
|
|
|
+ /// ],
|
|
|
+ /// };
|
|
|
+ /// ```
|
|
|
+ pub fn diagonal(values: &[T; DIMENSION]) -> Self {
|
|
|
+ let mut mat = Self::default();
|
|
|
+ for i in 0..DIMENSION {
|
|
|
+ mat.data[i][i] = values[i];
|
|
|
+ }
|
|
|
+ mat
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Index<(usize, usize)> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, 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 {
|
|
@@ -77,14 +155,14 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Index<(usi
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> IndexMut<(usize, usize)> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, 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> {
|
|
|
+impl<T: Numeric + Neg<Output=T>, const ROWS: usize, const COLUMNS: usize> Neg for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
type Output = Self;
|
|
|
|
|
|
fn neg(self) -> Self::Output {
|
|
@@ -98,7 +176,7 @@ impl<T: Numeric + Primitive + Neg<Output=T>, const ROWS: usize, const COLUMNS: u
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Add for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Add for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
type Output = Self;
|
|
|
|
|
|
fn add(mut self, rhs: Self) -> Self::Output {
|
|
@@ -107,7 +185,7 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Add for Ge
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> AddAssign for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, 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 {
|
|
@@ -117,7 +195,7 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> AddAssign
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Sub for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Sub for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
type Output = Self;
|
|
|
|
|
|
fn sub(mut self, rhs: Self) -> Self::Output {
|
|
@@ -126,7 +204,7 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Sub for Ge
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> SubAssign for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, 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 {
|
|
@@ -136,7 +214,7 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> SubAssign
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Mul<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Mul<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
type Output = Self;
|
|
|
|
|
|
fn mul(mut self, rhs: T) -> Self::Output {
|
|
@@ -145,7 +223,7 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Mul<T> for
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> MulAssign<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, 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 {
|
|
@@ -155,7 +233,7 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> MulAssign<
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Div<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Div<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
type Output = Self;
|
|
|
|
|
|
fn div(mut self, rhs: T) -> Self::Output {
|
|
@@ -164,7 +242,7 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> Div<T> for
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> DivAssign<T> for GenericMatrix<T, ROWS, COLUMNS> {
|
|
|
+impl<T: Numeric, 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 {
|
|
@@ -174,7 +252,7 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COLUMNS: usize> DivAssign<
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Numeric + Primitive, const ROWS: usize, const COMMON: usize, const COLUMNS: usize> Mul<GenericMatrix<T, COMMON, COLUMNS>> for GenericMatrix<T, ROWS, COMMON> {
|
|
|
+impl<T: Numeric, 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 {
|
|
@@ -192,8 +270,7 @@ impl<T: Numeric + Primitive, const ROWS: usize, const COMMON: usize, const COLUM
|
|
|
|
|
|
#[cfg(test)]
|
|
|
mod tests {
|
|
|
- use crate::GenericMatrix;
|
|
|
- use crate::types::matrix::generic::SquareMatrix;
|
|
|
+ use crate::{ColumnVector, Complex, cplx, GenericMatrix, RowVector, SquareMatrix};
|
|
|
|
|
|
#[test]
|
|
|
fn identity_matrix() {
|
|
@@ -205,6 +282,16 @@ mod tests {
|
|
|
assert_eq!(mat, expected);
|
|
|
}
|
|
|
|
|
|
+ #[test]
|
|
|
+ fn diagonal_matrix() {
|
|
|
+ let mat: SquareMatrix<f32, 3> = SquareMatrix::diagonal(&[1.0, 2.0, 3.0]);
|
|
|
+ let expected = SquareMatrix {
|
|
|
+ data: [[1.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 3.0]],
|
|
|
+ };
|
|
|
+
|
|
|
+ assert_eq!(mat, expected);
|
|
|
+ }
|
|
|
+
|
|
|
#[test]
|
|
|
#[should_panic = "index out of bounds"]
|
|
|
fn out_of_bounds_access() {
|
|
@@ -216,7 +303,7 @@ mod tests {
|
|
|
fn transposing_matrix() {
|
|
|
let mat = GenericMatrix {
|
|
|
data: [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]],
|
|
|
- }.transpose();
|
|
|
+ }.transposed();
|
|
|
let expected = GenericMatrix {
|
|
|
data: [[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]],
|
|
|
};
|
|
@@ -244,4 +331,29 @@ mod tests {
|
|
|
|
|
|
assert_eq!(product[(0, 0)], 3);
|
|
|
}
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn complex_matrix_multiplication() {
|
|
|
+ let a = SquareMatrix {
|
|
|
+ data: [
|
|
|
+ [cplx!(2.0, 1.0), cplx!(i = 5.0,)],
|
|
|
+ [cplx!(3.0), cplx!(3.0, -4.0)],
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ let b = SquareMatrix {
|
|
|
+ data: [
|
|
|
+ [cplx!(1.0, -1.0), cplx!(4.0, 2.0)],
|
|
|
+ [cplx!(1.0, -6.0), cplx!(3.0)],
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ let mat = a * b;
|
|
|
+ let expected = SquareMatrix {
|
|
|
+ data: [
|
|
|
+ [cplx!(33.0, 4.0), cplx!(6.0, 23.0)],
|
|
|
+ [cplx!(-18.0, -25.0), cplx!(21.0, -6.0)],
|
|
|
+ ],
|
|
|
+ };
|
|
|
+
|
|
|
+ assert_eq!(mat, expected);
|
|
|
+ }
|
|
|
}
|