Compare commits

...

3 Commits

Author SHA1 Message Date
Andrew Cassidy bd1bde1657 Use block comments for docs
Much more readable in the raw source
11 months ago
Andrew Cassidy 9b14bebb2d Improve documentation on everything in lib.rs 11 months ago
Andrew Cassidy 4bbcabb2aa Document Index2D 11 months ago

@ -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
/// to be reused
pub fn det(&self) -> T {
self.parity * self.lu.diagonals().fold(T::one(), T::mul)
self.parity * self.lu.diagonals().fold(T::one(), |l, &r| l * r)
}
/// Calculate the inverse of the original matrix, such that $bbM xx bbM^{-1} = bbI$

@ -1,66 +0,0 @@
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())
}
}

@ -1,12 +1,78 @@
//! Helper trait for ergonomic matrix subscripting
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 {
/** 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)]
fn to_1d(self, height: usize, width: usize) -> Option<usize> {
let (r, c) = self.to_2d(height, width)?;
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)>;
}

@ -1,22 +1,22 @@
extern crate core;
use index::Index2D;
use num_traits::{Bounded, One, Zero};
use std::cmp::min;
use std::fmt::Debug;
use std::iter::{zip, Flatten};
use std::ops::{Index, IndexMut};
pub mod decompose;
mod identities;
pub mod index;
mod math;
mod ops;
mod util;
/// A 2D array of values which can be operated upon.
///
/// Matrices have a fixed size known at compile time
/** A 2D array of values which can be operated upon.
Matrices have a fixed size known at compile time */
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Matrix<T, const M: usize, const N: usize>
where
@ -37,22 +37,87 @@ 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
impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
/// Generate a new matrix from a 2D Array
///
/// # Arguments
///
/// * `data`: A 2D array of elements to copy into the new matrix
///
/// returns: Matrix<T, M, N>
///
/// # Examples
///
/// ```
/// # use vector_victor::Matrix;
/// let a = Matrix::mat([[1,2,3,4];4]);
/// ```
/** Generate a new matrix from a 2D Array
# Arguments
* `data`: A 2D array of elements to copy into the new matrix
# Examples
```
# use vector_victor::Matrix;
let a = Matrix::mat([[1,2,3,4];4]);
``` */
#[must_use]
pub fn mat(data: [[T; N]; M]) -> Self {
assert!(M > 0, "Matrix must have at least 1 row");
@ -60,22 +125,19 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Matrix::<T, M, N> { data }
}
/// Generate a new matrix from a single scalar
///
/// # Arguments
///
/// * `scalar`: Scalar value to copy into the new matrix.
///
/// returns: Matrix<T, M, N>
///
/// # Examples
///
/// ```
/// # 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]))
/// ```
/** Generate a new matrix from a single scalar
# Arguments
* `scalar`: Scalar value to copy into the new matrix.
# Examples
```
# use vector_victor::Matrix;
// these are equivalent
assert_eq!(Matrix::<i32,4,4>::fill(5), Matrix::mat([[5;4];4]))
``` */
#[must_use]
pub fn fill(scalar: T) -> Matrix<T, M, N> {
assert!(M > 0, "Matrix must have at least 1 row");
@ -85,22 +147,26 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
}
}
/// Create a matrix from an iterator of vectors
///
/// # Arguments
///
/// * `iter`: iterator of vectors to copy into rows
///
/// returns: Matrix<T, M, N>
///
/// # Examples
///
/// ```
/// # use vector_victor::Matrix;
/// let my_matrix = Matrix::mat([[1,2,3],[4,5,6]]);
/// let transpose : Matrix<_,3,2>= Matrix::from_rows(my_matrix.cols());
/// assert_eq!(transpose, Matrix::mat([[1,4],[2,5],[3,6]]))
/// ```
/** Create a matrix from an iterator of vectors
# Arguments
* `iter`: iterator of vectors to copy into rows
# Examples
The following is another way of performing [`Matrix::transpose()`]
```
# use vector_victor::Matrix;
let my_matrix = Matrix::mat([[1, 2, 3],
[4, 5, 6]]);
let transpose : Matrix<_,3,2>= Matrix::from_rows(my_matrix.cols());
assert_eq!(transpose, Matrix::mat([[1, 4],
[2, 5],
[3, 6]]))
``` */
#[must_use]
pub fn from_rows<I>(iter: I) -> Self
where
@ -114,22 +180,26 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
result
}
/// Create a matrix from an iterator of vectors
///
/// # Arguments
///
/// * `iter`: iterator of vectors to copy into columns
///
/// returns: Matrix<T, M, N>
///
/// # Examples
///
/// ```
/// # use vector_victor::Matrix;
/// let my_matrix = Matrix::mat([[1,2,3],[4,5,6]]);
/// let transpose : Matrix<_,3,2>= Matrix::from_cols(my_matrix.rows());
/// assert_eq!(transpose, Matrix::mat([[1,4],[2,5],[3,6]]))
/// ```
/** Create a matrix from an iterator of vectors
# Arguments
* `iter`: iterator of vectors to copy into columns
# Examples
The following is another way of performing [`Matrix::transpose()`]
```
# use vector_victor::Matrix;
let my_matrix = Matrix::mat([[1, 2, 3],
[4, 5, 6]]);
let transpose : Matrix<_,3,2>= Matrix::from_cols(my_matrix.rows());
assert_eq!(transpose, Matrix::mat([[1, 4],
[2, 5],
[3, 6]]))
``` */
#[must_use]
pub fn from_cols<I>(iter: I) -> Self
where
@ -146,16 +216,15 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
// Vector constructor
impl<T: Copy, const N: usize> Vector<T, N> {
/// Create a vector from a 1D array.
/// Note that vectors are always column vectors unless explicitly instantiated as row vectors
///
/// # Examples
/// ```
/// # use vector_victor::{Matrix, Vector};
/// let my_vector = Vector::vec([1,2,3,4]);
/// // is equivalent to
/// assert_eq!(my_vector, Matrix::mat([[1],[2],[3],[4]]));
/// ```
/** Create a vector from a 1D array.
Note that vectors are always column vectors unless explicitly instantiated as row vectors
# Examples
```
# use vector_victor::{Matrix, Vector};
// these are equivalent
assert_eq!(Vector::vec([1,2,3,4]), Matrix::mat([[1],[2],[3],[4]]));
``` */
pub fn vec(data: [T; N]) -> Self {
assert!(N > 0, "Vector must have at least 1 element");
return Vector::<T, N> {
@ -166,55 +235,99 @@ impl<T: Copy, const N: usize> Vector<T, N> {
// ACCESSORS AND MUTATORS
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.
///
/// # Examples
/// ```
/// # use vector_victor::Matrix;
/// let my_matrix = Matrix::mat([[1,2],[3,4]]);
/// assert!(vec![1,2,3,4].iter().eq(my_matrix.elements()))
/// ```
/** Returns an iterator over the elements of the matrix in row-major order.
This is identical to the behavior of [`IntoIterator`](#associatedtype.IntoIter)
# Examples
```
# use vector_victor::Matrix;
let my_matrix = Matrix::mat([[1, 2],
[3, 4]]);
itertools::assert_equal(my_matrix.elements(), [1,2,3,4].iter())
``` */
#[must_use]
pub fn elements<'a>(&'a self) -> impl Iterator<Item = &'a T> + 'a {
pub fn elements<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's {
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]
pub fn elements_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T> + 'a {
pub fn elements_mut<'s>(&'s mut self) -> impl Iterator<Item = &'s mut T> + 's {
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]
pub fn diagonals<'s>(&'s self) -> impl Iterator<Item = T> + 's {
(0..min(N, M)).map(|n| self[(n, n)])
pub fn diagonals<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's {
(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]
pub fn subdiagonals<'s>(&'s self) -> impl Iterator<Item = T> + 's {
(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.
///
/// # Examples
///
/// ```
/// # use vector_victor::Matrix;
/// let my_matrix = Matrix::mat([[1,2],[3,4]]);
///
/// // element at index 2 is the same as the element at (row 1, column 0).
/// 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);
/// ```
pub fn subdiagonals<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's {
(0..min(N, M - 1)).map(|n| &self[(n + 1, n)])
}
/** 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,
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 my_matrix = Matrix::mat([[1, 2],
[3, 4]]);
// element at index 2 is the same as the element at row 1, column 0.
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]
#[must_use]
pub fn get(&self, index: impl Index2D) -> Option<&T> {
@ -222,7 +335,29 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Some(&self.data[m][n])
}
/// Returns a mutable reference to the element at that position in the matrix, or `None` if out of bounds.
/** Returns a mutable reference to the element at that position in the matrix,
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]
#[must_use]
pub fn get_mut(&mut self, index: impl Index2D) -> Option<&mut T> {
@ -230,23 +365,28 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
Some(&mut self.data[m][n])
}
/// Returns a row of the matrix. or [None] if index is out of bounds
///
/// # Examples
///
/// ```
/// # use vector_victor::{Matrix, Vector};
/// let my_matrix = Matrix::mat([[1,2],[3,4]]);
///
/// // row at index 1
/// assert_eq!(my_matrix.row(1), Vector::vec([3,4]));
/// ```
/** Returns a row of the matrix.
# Panics
Panics if row index `m` is out of bounds.
# Examples
```
# use vector_victor::{Matrix, Vector};
let my_matrix = Matrix::mat([[1, 2],
[3, 4]]);
// row at index 1
assert_eq!(my_matrix.row(1), Vector::vec([3,4]));
``` */
#[inline]
#[must_use]
pub fn row(&self, m: usize) -> Vector<T, N> {
assert!(
m < M,
"Row index {} out of bounds for {}x{} matrix",
"Row index {} out of bounds for {}×{} matrix",
m,
M,
N
@ -254,11 +394,27 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
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]
pub fn set_row(&mut self, m: usize, val: &Vector<T, N>) {
assert!(
m < M,
"Row index {} out of bounds for {}x{} matrix",
"Row index {} out of bounds for {}×{} matrix",
m,
M,
N
@ -268,18 +424,28 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
}
}
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);
}
/** Returns a column of the matrix.
# 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]
#[must_use]
pub fn col(&self, n: usize) -> Vector<T, M> {
assert!(
n < N,
"Column index {} out of bounds for {}x{} matrix",
"Column index {} out of bounds for {}×{} matrix",
n,
M,
N
@ -287,11 +453,27 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, 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]
pub fn set_col(&mut self, n: usize, val: &Vector<T, M>) {
assert!(
n < N,
"Column index {} out of bounds for {}x{} matrix",
"Column index {} out of bounds for {}×{} matrix",
n,
M,
N
@ -302,22 +484,64 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
}
}
pub fn pivot_col(&mut self, n1: usize, n2: usize) {
let tmp = self.col(n2);
self.set_col(n2, &self.col(n1));
self.set_col(n1, &tmp);
}
/// 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) {
let tmp = self.col(n2);
self.set_col(n2, &self.col(n1));
self.set_col(n1, &tmp);
}
/** Apply a permutation matrix to the rows of a matrix
# Arguments
* `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]
pub fn permute_rows(&self, ms: &Vector<usize, M>) -> Self
where
@ -326,6 +550,16 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
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]
pub fn permute_cols(&self, ns: &Vector<usize, N>) -> Self
where
@ -334,6 +568,20 @@ impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, 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>
where
Matrix<T, N, M>: Default,
@ -353,7 +601,7 @@ where
#[inline(always)]
fn index(&self, index: I) -> &Self::Output {
self.get(index).expect(&*format!(
"index {:?} out of range for {}x{} Matrix",
"index {:?} out of range for {}×{} Matrix",
index, M, N
))
}
@ -368,7 +616,7 @@ where
#[inline(always)]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
self.get_mut(index).expect(&*format!(
"index {:?} out of range for {}x{} Matrix",
"index {:?} out of range for {}×{} Matrix",
index, M, N
))
}

@ -6,24 +6,25 @@ 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.
/** 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>,

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

Loading…
Cancel
Save