Compare commits

..

No commits in common. "bd1bde165715a5e0fb50f341799b861aca5725c6" and "e2a2bc7529a5b3d0e22075bdd2f9238af5e83d00" have entirely different histories.

7 changed files with 228 additions and 478 deletions

View File

@ -124,7 +124,7 @@ impl<T: Copy + Default + Real, const N: usize> LUDecomposition<T, N> {
/// This is equivalent to [`LUDecompose::det`] while allowing the LU decomposition /// This is equivalent to [`LUDecompose::det`] while allowing the LU decomposition
/// to be reused /// to be reused
pub fn det(&self) -> T { pub fn det(&self) -> T {
self.parity * self.lu.diagonals().fold(T::one(), |l, &r| l * r) self.parity * self.lu.diagonals().fold(T::one(), T::mul)
} }
/// Calculate the inverse of the original matrix, such that $bbM xx bbM^{-1} = bbI$ /// Calculate the inverse of the original matrix, such that $bbM xx bbM^{-1} = bbI$

66
src/identities.rs Normal file
View File

@ -0,0 +1,66 @@
use crate::Matrix;
use num_traits::{Bounded, One, Zero};
// Identity
impl<T: Copy + Zero + One, const N: usize> Matrix<T, N, N> {
/// Create an identity matrix, a square matrix where the diagonals are 1 and all other elements
/// are 0.
/// for example,
///
/// $bbI = [[1,0,0],[0,1,0],[0,0,1]]$
///
/// Matrix multiplication between a matrix and the identity matrix always results in itself
///
/// $bbA xx bbI = bbA$
///
/// # Examples
/// ```
/// # use vector_victor::Matrix;
/// let i = Matrix::<i32,3,3>::identity();
/// assert_eq!(i, Matrix::mat([[1,0,0],[0,1,0],[0,0,1]]))
/// ```
///
/// Note that the identity only exists for matrices that are square, so this doesnt work:
/// ```compile_fail
/// # use vector_victor::Matrix;
/// let i = Matrix::<i32,4,2>::identity();
/// ```
#[must_use]
pub fn identity() -> Self {
let mut result = Self::zero();
for i in 0..N {
result[(i, i)] = T::one();
}
return result;
}
}
// Zero
impl<T: Copy + Zero, const M: usize, const N: usize> Zero for Matrix<T, M, N> {
fn zero() -> Self {
Matrix::fill(T::zero())
}
fn is_zero(&self) -> bool {
self.elements().all(|e| e.is_zero())
}
}
// One
impl<T: Copy + One, const M: usize, const N: usize> One for Matrix<T, M, N> {
fn one() -> Self {
Matrix::fill(T::one())
}
}
// min_value and max_value
// LowerBounded and UpperBounded are automatically implemented from this
impl<T: Copy + Bounded, const N: usize, const M: usize> Bounded for Matrix<T, N, M> {
fn min_value() -> Self {
Self::fill(T::min_value())
}
fn max_value() -> Self {
Self::fill(T::max_value())
}
}

View File

@ -1,78 +1,12 @@
//! Helper trait for ergonomic matrix subscripting
use std::fmt::Debug; use std::fmt::Debug;
/** Trait implemented by types that can be used as a matrix index
There are currently two implementations:
[`usize`](#impl-Index2D-for-usize) and [`(usize,usize)`](#impl-Index2D-for-(usize,+usize))
# Examples
Indexing by a `usize` indexes starting at the first element and
increments linearly in row-major order. This is especially useful for column vectors.
```
# use vector_victor::{Matrix, Vector};
let m = Matrix::mat([[1,2,3],[4,5,6],[7,8,9]]);
assert_eq!(m[0], 1);
assert_eq!(m[4], 5);
assert_eq!(m[7], 8);
let v = Vector::vec([4,8,15,16,23,42]);
assert_eq!(v[2], 15); // just like a std::vec
```
Indexing by a `(usize,usize)` indexes by row and column
```
# use vector_victor::{Matrix, Vector};
let m = Matrix::mat([[1,2,3],[4,5,6],[7,8,9]]);
assert_eq!(m[(0,0)], 1);
assert_eq!(m[(1,1)], 5);
assert_eq!(m[(2,1)], 8);
``` */
pub trait Index2D: Copy + Debug { pub trait Index2D: Copy + Debug {
/** Convert an index to its 1-D linear interpretation, given the `width` and `height` of the
matrix being subscripted.
If the index is out of bounds for the given dimensions, this returns `None`,
otherwise it returns `Some(usize)`
# Examples
```
# use vector_victor::index::Index2D;
assert_eq!(
(1usize,2usize).to_1d(3,3),
Some(5),
"(1,2) is index 5 in a 3×3 matrix");
assert_eq!(
(3usize, 2usize).to_1d(3,3),
None,
"row 3, column 2 is out of bounds for a 3×3 matrix");
``` */
#[inline(always)] #[inline(always)]
fn to_1d(self, height: usize, width: usize) -> Option<usize> { fn to_1d(self, height: usize, width: usize) -> Option<usize> {
let (r, c) = self.to_2d(height, width)?; let (r, c) = self.to_2d(height, width)?;
Some(r * width + c) Some(r * width + c)
} }
/** Convert an index to its 2-D interpretation, given the `width` and `height` of the
matrix being subscripted.
If the index is out of bounds for the given dimensions, this returns `None`,
otherwise it returns `Some((usize, usize))`
# Examples
```
# use vector_victor::index::Index2D;
assert_eq!(
5usize.to_2d(3,3),
Some((1usize,2usize)),
"index 5 is at row 1 column 2 in a 3×3 matrix");
assert_eq!(
10usize.to_2d(3,3),
None,
"a 3×3 matrix only has 9 elements, so index 10 is out of bounds.");
``` */
fn to_2d(self, height: usize, width: usize) -> Option<(usize, usize)>; fn to_2d(self, height: usize, width: usize) -> Option<(usize, usize)>;
} }

View File

@ -1,22 +1,22 @@
extern crate core; extern crate core;
use index::Index2D; use index::Index2D;
use num_traits::{Bounded, One, Zero};
use std::cmp::min; use std::cmp::min;
use std::fmt::Debug; use std::fmt::Debug;
use std::iter::{zip, Flatten}; use std::iter::{zip, Flatten};
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
pub mod decompose; pub mod decompose;
mod identities;
pub mod index; pub mod index;
mod math; mod math;
mod ops; mod ops;
mod util; mod util;
/** A 2D array of values which can be operated upon. /// A 2D array of values which can be operated upon.
///
Matrices have a fixed size known at compile time */ /// Matrices have a fixed size known at compile time
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub struct Matrix<T, const M: usize, const N: usize> pub struct Matrix<T, const M: usize, const N: usize>
where where
@ -37,87 +37,22 @@ impl<T: Copy + Default, const M: usize, const N: usize> Default for Matrix<T, M,
} }
} }
// Zero
impl<T: Copy + Zero, const M: usize, const N: usize> Zero for Matrix<T, M, N> {
fn zero() -> Self {
Matrix::fill(T::zero())
}
fn is_zero(&self) -> bool {
self.elements().all(|e| e.is_zero())
}
}
// One
impl<T: Copy + One, const M: usize, const N: usize> One for Matrix<T, M, N> {
fn one() -> Self {
Matrix::fill(T::one())
}
}
// min_value and max_value
// LowerBounded and UpperBounded are automatically implemented from this
impl<T: Copy + Bounded, const N: usize, const M: usize> Bounded for Matrix<T, N, M> {
fn min_value() -> Self {
Self::fill(T::min_value())
}
fn max_value() -> Self {
Self::fill(T::max_value())
}
}
// Identity
impl<T: Copy + Zero + One, const N: usize> Matrix<T, N, N> {
/** Create an identity matrix, a square matrix where the diagonals are 1 and
all other elements are 0.
for example,
$bbI = \[\[1,0,0],\[0,1,0],\[0,0,1]]$
Matrix multiplication between a matrix and the identity matrix always results in itself
$bbA xx bbI = bbA$
# Examples
```
# use vector_victor::Matrix;
let i = Matrix::<i32,3,3>::identity();
assert_eq!(i, Matrix::mat([[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]))
```
Note that the identity only exists for matrices that are square, so this doesnt work:
```compile_fail
# use vector_victor::Matrix;
let i = Matrix::<i32,4,2>::identity();
``` */
#[must_use]
pub fn identity() -> Self {
let mut result = Self::zero();
for i in 0..N {
result[(i, i)] = T::one();
}
return result;
}
}
// Matrix constructors // Matrix constructors
impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> { impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
/** Generate a new matrix from a 2D Array /// Generate a new matrix from a 2D Array
///
# Arguments /// # Arguments
///
* `data`: A 2D array of elements to copy into the new matrix /// * `data`: A 2D array of elements to copy into the new matrix
///
# Examples /// returns: Matrix<T, M, N>
///
``` /// # Examples
# use vector_victor::Matrix; ///
let a = Matrix::mat([[1,2,3,4];4]); /// ```
``` */ /// # use vector_victor::Matrix;
/// let a = Matrix::mat([[1,2,3,4];4]);
/// ```
#[must_use] #[must_use]
pub fn mat(data: [[T; N]; M]) -> Self { pub fn mat(data: [[T; N]; M]) -> Self {
assert!(M > 0, "Matrix must have at least 1 row"); assert!(M > 0, "Matrix must have at least 1 row");
@ -125,19 +60,22 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Matrix::<T, M, N> { data } Matrix::<T, M, N> { data }
} }
/** Generate a new matrix from a single scalar /// Generate a new matrix from a single scalar
///
# Arguments /// # Arguments
///
* `scalar`: Scalar value to copy into the new matrix. /// * `scalar`: Scalar value to copy into the new matrix.
///
# Examples /// returns: Matrix<T, M, N>
///
``` /// # Examples
# use vector_victor::Matrix; ///
// these are equivalent /// ```
assert_eq!(Matrix::<i32,4,4>::fill(5), Matrix::mat([[5;4];4])) /// # use vector_victor::Matrix;
``` */ /// let my_matrix = Matrix::<i32,4,4>::fill(5);
/// // is equivalent to
/// assert_eq!(my_matrix, Matrix::mat([[5;4];4]))
/// ```
#[must_use] #[must_use]
pub fn fill(scalar: T) -> Matrix<T, M, N> { pub fn fill(scalar: T) -> Matrix<T, M, N> {
assert!(M > 0, "Matrix must have at least 1 row"); assert!(M > 0, "Matrix must have at least 1 row");
@ -147,26 +85,22 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
} }
} }
/** Create a matrix from an iterator of vectors /// Create a matrix from an iterator of vectors
///
# Arguments /// # Arguments
///
* `iter`: iterator of vectors to copy into rows /// * `iter`: iterator of vectors to copy into rows
///
# Examples /// returns: Matrix<T, M, N>
///
The following is another way of performing [`Matrix::transpose()`] /// # Examples
``` ///
# use vector_victor::Matrix; /// ```
let my_matrix = Matrix::mat([[1, 2, 3], /// # use vector_victor::Matrix;
[4, 5, 6]]); /// let my_matrix = Matrix::mat([[1,2,3],[4,5,6]]);
/// let transpose : Matrix<_,3,2>= Matrix::from_rows(my_matrix.cols());
let transpose : Matrix<_,3,2>= Matrix::from_rows(my_matrix.cols()); /// assert_eq!(transpose, Matrix::mat([[1,4],[2,5],[3,6]]))
/// ```
assert_eq!(transpose, Matrix::mat([[1, 4],
[2, 5],
[3, 6]]))
``` */
#[must_use] #[must_use]
pub fn from_rows<I>(iter: I) -> Self pub fn from_rows<I>(iter: I) -> Self
where where
@ -180,26 +114,22 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
result result
} }
/** Create a matrix from an iterator of vectors /// Create a matrix from an iterator of vectors
///
# Arguments /// # Arguments
///
* `iter`: iterator of vectors to copy into columns /// * `iter`: iterator of vectors to copy into columns
///
# Examples /// returns: Matrix<T, M, N>
///
The following is another way of performing [`Matrix::transpose()`] /// # Examples
``` ///
# use vector_victor::Matrix; /// ```
let my_matrix = Matrix::mat([[1, 2, 3], /// # use vector_victor::Matrix;
[4, 5, 6]]); /// let my_matrix = Matrix::mat([[1,2,3],[4,5,6]]);
/// let transpose : Matrix<_,3,2>= Matrix::from_cols(my_matrix.rows());
let transpose : Matrix<_,3,2>= Matrix::from_cols(my_matrix.rows()); /// assert_eq!(transpose, Matrix::mat([[1,4],[2,5],[3,6]]))
/// ```
assert_eq!(transpose, Matrix::mat([[1, 4],
[2, 5],
[3, 6]]))
``` */
#[must_use] #[must_use]
pub fn from_cols<I>(iter: I) -> Self pub fn from_cols<I>(iter: I) -> Self
where where
@ -216,15 +146,16 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
// Vector constructor // Vector constructor
impl<T: Copy, const N: usize> Vector<T, N> { impl<T: Copy, const N: usize> Vector<T, N> {
/** Create a vector from a 1D array. /// Create a vector from a 1D array.
Note that vectors are always column vectors unless explicitly instantiated as row vectors /// Note that vectors are always column vectors unless explicitly instantiated as row vectors
///
# Examples /// # Examples
``` /// ```
# use vector_victor::{Matrix, Vector}; /// # use vector_victor::{Matrix, Vector};
// these are equivalent /// let my_vector = Vector::vec([1,2,3,4]);
assert_eq!(Vector::vec([1,2,3,4]), Matrix::mat([[1],[2],[3],[4]])); /// // is equivalent to
``` */ /// assert_eq!(my_vector, Matrix::mat([[1],[2],[3],[4]]));
/// ```
pub fn vec(data: [T; N]) -> Self { pub fn vec(data: [T; N]) -> Self {
assert!(N > 0, "Vector must have at least 1 element"); assert!(N > 0, "Vector must have at least 1 element");
return Vector::<T, N> { return Vector::<T, N> {
@ -235,99 +166,55 @@ impl<T: Copy, const N: usize> Vector<T, N> {
// ACCESSORS AND MUTATORS // ACCESSORS AND MUTATORS
impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> { impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
/** Returns an iterator over the elements of the matrix in row-major order. /// Returns an iterator over the elements of the matrix in row-major order.
///
This is identical to the behavior of [`IntoIterator`](#associatedtype.IntoIter) /// # Examples
/// ```
# Examples /// # use vector_victor::Matrix;
``` /// let my_matrix = Matrix::mat([[1,2],[3,4]]);
# use vector_victor::Matrix; /// assert!(vec![1,2,3,4].iter().eq(my_matrix.elements()))
let my_matrix = Matrix::mat([[1, 2], /// ```
[3, 4]]);
itertools::assert_equal(my_matrix.elements(), [1,2,3,4].iter())
``` */
#[must_use] #[must_use]
pub fn elements<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's { pub fn elements<'a>(&'a self) -> impl Iterator<Item = &'a T> + 'a {
self.data.iter().flatten() self.data.iter().flatten()
} }
/** Returns a mutable iterator over the elements of the matrix in row-major order. /// Returns a mutable iterator over the elements of the matrix in row-major order.
# Examples
```
# use vector_victor::Matrix;
let mut my_matrix = Matrix::mat([[1, 2],
[3, 4]]);
for elem in my_matrix.elements_mut() {*elem += 2;}
itertools::assert_equal(my_matrix.elements(), [3,4,5,6].iter())
``` */
#[must_use] #[must_use]
pub fn elements_mut<'s>(&'s mut self) -> impl Iterator<Item = &'s mut T> + 's { pub fn elements_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T> + 'a {
self.data.iter_mut().flatten() self.data.iter_mut().flatten()
} }
/** returns an iterator over the elements along the diagonal of a matrix /// returns an iterator over the elements along the diagonal of a matrix
# Examples
```
# use vector_victor::Matrix;
let my_matrix = Matrix::mat([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10,11,12]]);
itertools::assert_equal(my_matrix.diagonals(), [1,5,9].iter())
``` */
#[must_use] #[must_use]
pub fn diagonals<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's { pub fn diagonals<'s>(&'s self) -> impl Iterator<Item = T> + 's {
(0..min(N, M)).map(|n| &self[(n, n)]) (0..min(N, M)).map(|n| self[(n, n)])
} }
/** Returns an iterator over the elements directly below the diagonal of a matrix /// Returns an iterator over the elements directly below the diagonal of a matrix
# Examples
```
# use vector_victor::Matrix;
let my_matrix = Matrix::mat([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10,11,12]]);
itertools::assert_equal(my_matrix.subdiagonals(), [4,8,12].iter());
``` */
#[must_use] #[must_use]
pub fn subdiagonals<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's { pub fn subdiagonals<'s>(&'s self) -> impl Iterator<Item = T> + 's {
(0..min(N, M - 1)).map(|n| &self[(n + 1, n)]) (0..min(N, M) - 1).map(|n| self[(n, n + 1)])
} }
/** Returns a reference to the element at that position in the matrix, or `None` if out of bounds. /// Returns a reference to the element at that position in the matrix, or `None` if out of bounds.
///
[`Index`](#impl-Index%3CI%3E-for-Matrix%3CT,+M,+N%3E) behaves similarly, /// # Examples
but will panic if the index is out of bounds instead of returning an option ///
/// ```
# Arguments /// # use vector_victor::Matrix;
/// let my_matrix = Matrix::mat([[1,2],[3,4]]);
* `index`: a 1D or 2D index into the matrix. See [Index2D] for more information on matrix indexing. ///
/// // element at index 2 is the same as the element at (row 1, column 0).
# Examples /// assert_eq!(my_matrix.get(2), my_matrix.get((1,0)));
///
``` /// // my_matrix.get() is equivalent to my_matrix[],
# use vector_victor::Matrix; /// // but returns an Option instead of panicking
let my_matrix = Matrix::mat([[1, 2], /// assert_eq!(my_matrix.get(2), Some(&my_matrix[2]));
[3, 4]]); ///
/// // index 4 is out of range, so get(4) returns None.
// element at index 2 is the same as the element at row 1, column 0. /// assert_eq!(my_matrix.get(4), None);
assert_eq!(my_matrix.get(2), my_matrix.get((1,0))); /// ```
// my_matrix.get() is equivalent to my_matrix[],
// but returns an Option instead of panicking
assert_eq!(my_matrix.get(2), Some(&my_matrix[2]));
// index 4 is out of range, so get(4) returns None.
assert_eq!(my_matrix.get(4), None);
``` */
#[inline] #[inline]
#[must_use] #[must_use]
pub fn get(&self, index: impl Index2D) -> Option<&T> { pub fn get(&self, index: impl Index2D) -> Option<&T> {
@ -335,29 +222,7 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Some(&self.data[m][n]) Some(&self.data[m][n])
} }
/** Returns a mutable reference to the element at that position in the matrix, /// Returns a mutable reference to the element at that position in the matrix, or `None` if out of bounds.
or `None` if out of bounds.
[`IndexMut`](#impl-IndexMut%3CI%3E-for-Matrix%3CT,+M,+N%3E) behaves similarly,
but will panic if the index is out of bounds instead of returning an option
# Arguments
* `index`: a 1D or 2D index into the matrix. See [Index2D] for more information
on matrix indexing.
# Examples
```
# use vector_victor::Matrix;
let mut my_matrix = Matrix::mat([[1, 2],
[3, 4]]);
match my_matrix.get_mut(2) {
Some(t) => *t = 5,
None => panic!()};
assert_eq!(my_matrix, Matrix::mat([[1,2],[5,4]]))
``` */
#[inline] #[inline]
#[must_use] #[must_use]
pub fn get_mut(&mut self, index: impl Index2D) -> Option<&mut T> { pub fn get_mut(&mut self, index: impl Index2D) -> Option<&mut T> {
@ -365,28 +230,23 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Some(&mut self.data[m][n]) Some(&mut self.data[m][n])
} }
/** Returns a row of the matrix. /// Returns a row of the matrix. or [None] if index is out of bounds
///
# Panics /// # Examples
///
Panics if row index `m` is out of bounds. /// ```
/// # use vector_victor::{Matrix, Vector};
# Examples /// let my_matrix = Matrix::mat([[1,2],[3,4]]);
///
``` /// // row at index 1
# use vector_victor::{Matrix, Vector}; /// assert_eq!(my_matrix.row(1), Vector::vec([3,4]));
let my_matrix = Matrix::mat([[1, 2], /// ```
[3, 4]]);
// row at index 1
assert_eq!(my_matrix.row(1), Vector::vec([3,4]));
``` */
#[inline] #[inline]
#[must_use] #[must_use]
pub fn row(&self, m: usize) -> Vector<T, N> { pub fn row(&self, m: usize) -> Vector<T, N> {
assert!( assert!(
m < M, m < M,
"Row index {} out of bounds for {}×{} matrix", "Row index {} out of bounds for {}x{} matrix",
m, m,
M, M,
N N
@ -394,27 +254,11 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Vector::<T, N>::vec(self.data[m]) Vector::<T, N>::vec(self.data[m])
} }
/** Sets a row of the matrix.
# Panics
Panics if row index `m` is out of bounds.
# Examples
```
# use vector_victor::{Matrix, Vector};
let mut my_matrix = Matrix::mat([[1, 2],
[3, 4]]);
// row at index 1
my_matrix.set_row(1, &Vector::vec([5,6]));
assert_eq!(my_matrix, Matrix::mat([[1,2],[5,6]]));
``` */
#[inline] #[inline]
pub fn set_row(&mut self, m: usize, val: &Vector<T, N>) { pub fn set_row(&mut self, m: usize, val: &Vector<T, N>) {
assert!( assert!(
m < M, m < M,
"Row index {} out of bounds for {}×{} matrix", "Row index {} out of bounds for {}x{} matrix",
m, m,
M, M,
N N
@ -424,28 +268,18 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
} }
} }
/** Returns a column of the matrix. pub fn pivot_row(&mut self, m1: usize, m2: usize) {
let tmp = self.row(m2);
self.set_row(m2, &self.row(m1));
self.set_row(m1, &tmp);
}
# Panics
Panics if column index `n` is out of bounds.
# Examples
```
# use vector_victor::{Matrix, Vector};
let my_matrix = Matrix::mat([[1, 2],
[3, 4]]);
// column at index 1
assert_eq!(my_matrix.col(1), Vector::vec([2,4]));
``` */
#[inline] #[inline]
#[must_use] #[must_use]
pub fn col(&self, n: usize) -> Vector<T, M> { pub fn col(&self, n: usize) -> Vector<T, M> {
assert!( assert!(
n < N, n < N,
"Column index {} out of bounds for {}×{} matrix", "Column index {} out of bounds for {}x{} matrix",
n, n,
M, M,
N N
@ -453,27 +287,11 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Vector::<T, M>::vec(self.data.map(|r| r[n])) Vector::<T, M>::vec(self.data.map(|r| r[n]))
} }
/** Sets a column of the matrix.
# Panics
Panics if column index `n` is out of bounds.
# Examples
```
# use vector_victor::{Matrix, Vector};
let mut my_matrix = Matrix::mat([[1, 2],
[3, 4]]);
// column at index 1
my_matrix.set_col(1, &Vector::vec([5,6]));
assert_eq!(my_matrix, Matrix::mat([[1,5],[3,6]]));
``` */
#[inline] #[inline]
pub fn set_col(&mut self, n: usize, val: &Vector<T, M>) { pub fn set_col(&mut self, n: usize, val: &Vector<T, M>) {
assert!( assert!(
n < N, n < N,
"Column index {} out of bounds for {}×{} matrix", "Column index {} out of bounds for {}x{} matrix",
n, n,
M, M,
N N
@ -484,64 +302,22 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
} }
} }
/// Returns an iterator over the rows of the matrix, returning them as column vectors.
#[must_use]
pub fn rows<'a>(&'a self) -> impl Iterator<Item = Vector<T, N>> + 'a {
(0..M).map(|m| self.row(m))
}
/// Returns an iterator over the columns of the matrix, returning them as column vectors.
#[must_use]
pub fn cols<'a>(&'a self) -> impl Iterator<Item = Vector<T, M>> + 'a {
(0..N).map(|n| self.col(n))
}
/** Interchange two rows
# Panics
Panics if row index `m1` or `m2` are out of bounds */
pub fn pivot_row(&mut self, m1: usize, m2: usize) {
let tmp = self.row(m2);
self.set_row(m2, &self.row(m1));
self.set_row(m1, &tmp);
}
/** Interchange two columns
# Panics
Panics if column index `n1` or `n2` are out of bounds */
pub fn pivot_col(&mut self, n1: usize, n2: usize) { pub fn pivot_col(&mut self, n1: usize, n2: usize) {
let tmp = self.col(n2); let tmp = self.col(n2);
self.set_col(n2, &self.col(n1)); self.set_col(n2, &self.col(n1));
self.set_col(n1, &tmp); self.set_col(n1, &tmp);
} }
/** Apply a permutation matrix to the rows of a matrix #[must_use]
pub fn rows<'a>(&'a self) -> impl Iterator<Item = Vector<T, N>> + 'a {
(0..M).map(|m| self.row(m))
}
# Arguments #[must_use]
pub fn cols<'a>(&'a self) -> impl Iterator<Item = Vector<T, M>> + 'a {
(0..N).map(|n| self.col(n))
}
* `ms`: a [`Vector`] of [`usize`] of length M. Each entry is the index of the row that will
appear in the result
# Panics
Panics if any of the row indices in `ms` is out of bounds
# Examples
```
# use vector_victor::{Matrix, Vector};
let my_matrix = Matrix::mat([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]);
let permuted = my_matrix.permute_rows(&Vector::vec([1, 0, 2]));
assert_eq!(permuted, Matrix::mat([[4, 5, 6],
[1, 2, 3],
[7, 8, 9]]))
``` */
#[must_use] #[must_use]
pub fn permute_rows(&self, ms: &Vector<usize, M>) -> Self pub fn permute_rows(&self, ms: &Vector<usize, M>) -> Self
where where
@ -550,16 +326,6 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Self::from_rows(ms.elements().map(|&m| self.row(m))) Self::from_rows(ms.elements().map(|&m| self.row(m)))
} }
/** Apply a permutation matrix to the columns of a matrix
# Arguments
* `ns`: a [`Vector`] of [`usize`] of length N. Each entry is the index of the column that will
appear in the result
# Panics
Panics if any of the column indices in `ns` is out of bounds */
#[must_use] #[must_use]
pub fn permute_cols(&self, ns: &Vector<usize, N>) -> Self pub fn permute_cols(&self, ns: &Vector<usize, N>) -> Self
where where
@ -568,20 +334,6 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Self::from_cols(ns.elements().map(|&n| self.col(n))) Self::from_cols(ns.elements().map(|&n| self.col(n)))
} }
/** Returns the transpose $M^T$ of the matrix, or the matrix flipped across its diagonal.
# Examples
```
# use vector_victor::Matrix;
let my_matrix = Matrix::mat([[1, 2, 3],
[4, 5, 6]]);
assert_eq!(
my_matrix.transpose(),
Matrix::mat([[1, 4],
[2, 5],
[3, 6]]))
``` */
pub fn transpose(&self) -> Matrix<T, N, M> pub fn transpose(&self) -> Matrix<T, N, M>
where where
Matrix<T, N, M>: Default, Matrix<T, N, M>: Default,
@ -601,7 +353,7 @@ where
#[inline(always)] #[inline(always)]
fn index(&self, index: I) -> &Self::Output { fn index(&self, index: I) -> &Self::Output {
self.get(index).expect(&*format!( self.get(index).expect(&*format!(
"index {:?} out of range for {}×{} Matrix", "index {:?} out of range for {}x{} Matrix",
index, M, N index, M, N
)) ))
} }
@ -616,7 +368,7 @@ where
#[inline(always)] #[inline(always)]
fn index_mut(&mut self, index: I) -> &mut Self::Output { fn index_mut(&mut self, index: I) -> &mut Self::Output {
self.get_mut(index).expect(&*format!( self.get_mut(index).expect(&*format!(
"index {:?} out of range for {}×{} Matrix", "index {:?} out of range for {}x{} Matrix",
index, M, N index, M, N
)) ))
} }

View File

@ -6,25 +6,24 @@ use std::ops::{Add, Mul};
/// Operations for column vectors /// Operations for column vectors
impl<T: Copy, const N: usize> Vector<T, N> { impl<T: Copy, const N: usize> Vector<T, N> {
/** Compute the dot product of two vectors, otherwise known as the scalar product. /// 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
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$
$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 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
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.
the vectors times the cosine of the angle between them. ///
/// $vec(a) * vec(b) = |vec(a)| |vec(b)| cos(theta)$
$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
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
square of its magnitude. You may recognize the 2D version as the /// [pythagorean theorem](https://en.wikipedia.org/wiki/Pythagorean_theorem).
[pythagorean theorem](https://en.wikipedia.org/wiki/Pythagorean_theorem). ///
/// see [dot product](https://en.wikipedia.org/wiki/Dot_product) on Wikipedia for more
see [dot product](https://en.wikipedia.org/wiki/Dot_product) on Wikipedia for more /// information.
information. */
pub fn dot<R>(&self, rhs: &R) -> T pub fn dot<R>(&self, rhs: &R) -> T
where where
for<'s> &'s Self: Mul<&'s R, Output = Self>, for<'s> &'s Self: Mul<&'s R, Output = Self>,

1
src/mod.rs Normal file
View File

@ -0,0 +1 @@

View File

@ -1,5 +1,3 @@
//! Data structures and traits for decomposing and solving matrices
#[macro_use] #[macro_use]
mod common; mod common;