Restructured matrix module, it is now separated into 1 primary module matrix (struct definition, init methods and getters) and 3 sub-modules: iter - structs and methods for iteration, arithmetic - impl of traits for arithmetic operations, ops - non-arithmetic matrix operations
Implemented Mul, MulAssign, Div and DivAssign traits for Matrix Added more tests
This commit is contained in:
parent
a2e311f295
commit
79d94bf357
6 changed files with 405 additions and 286 deletions
|
@ -1,5 +1,7 @@
|
||||||
mod matrix;
|
mod matrix;
|
||||||
pub use matrix::Matrix;
|
pub use matrix::Matrix;
|
||||||
|
pub use matrix::matrix;
|
||||||
|
|
||||||
mod sq_matrix;
|
mod sq_matrix;
|
||||||
pub use sq_matrix::SquareMatrix;
|
pub use sq_matrix::SquareMatrix;
|
||||||
|
pub use sq_matrix::sq_matrix;
|
|
@ -1,6 +1,10 @@
|
||||||
use std::ops::{Add, AddAssign, Index, IndexMut, Neg, Sub, SubAssign};
|
mod iter;
|
||||||
|
mod arithemtic;
|
||||||
|
mod ops;
|
||||||
|
|
||||||
use num::{traits::NumAssign, Num, Signed};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
use num::Num;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
pub struct Matrix<T: Num> {
|
pub struct Matrix<T: Num> {
|
||||||
|
@ -24,39 +28,6 @@ impl<T: Num + Clone> Matrix<T> {
|
||||||
pub fn new_zeroes(width: usize, height: usize) -> Self {
|
pub fn new_zeroes(width: usize, height: usize) -> Self {
|
||||||
Self::new_filled(T::zero(), width, height)
|
Self::new_filled(T::zero(), width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn minor(&self, row_index: usize, column_index: usize) -> Self {
|
|
||||||
if self.width < 2 {
|
|
||||||
panic!("Matrix width must be greater than 1 to form its minor, but got {}", self.width)
|
|
||||||
}
|
|
||||||
let height = self.height();
|
|
||||||
if height < 2 {
|
|
||||||
panic!("Matrix height must be greater than 1 to form its minor, but got {}", height)
|
|
||||||
}
|
|
||||||
if self.width == 2 && height == 2 {
|
|
||||||
panic!("Unable to form minor of a 2x2 matrix");
|
|
||||||
}
|
|
||||||
let minor_width = self.width - 1;
|
|
||||||
let mut minor_data = Box::new(Vec::with_capacity(minor_width * (height - 1)));
|
|
||||||
for (i, j, e) in self.iter_indexed() {
|
|
||||||
if i == row_index || j == column_index { continue; }
|
|
||||||
minor_data.push(e.clone());
|
|
||||||
}
|
|
||||||
Self { width: minor_width, data: minor_data }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transposed(&self) -> Self {
|
|
||||||
let mut transposed_data = Box::new(Vec::with_capacity(self.data.len()));
|
|
||||||
let height = self.height();
|
|
||||||
for j in 0..self.width {
|
|
||||||
let mut row_start = 0usize;
|
|
||||||
for _ in 0..height {
|
|
||||||
transposed_data.push(self.data[row_start + j].clone());
|
|
||||||
row_start += self.width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self { width: height, data: transposed_data }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Num> Matrix<T> {
|
impl<T: Num> Matrix<T> {
|
||||||
|
@ -89,95 +60,8 @@ impl<T: Num> Matrix<T> {
|
||||||
self.data.len()
|
self.data.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn indices(&self) -> IterIndices {
|
pub fn same_size(&self, other: &Self) -> bool {
|
||||||
IterIndices { i: 0, j: 0, width: self.width, height: self.height() }
|
return self.width == other.width && self.height() == other.height()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_iter(self) -> std::vec::IntoIter<T> {
|
|
||||||
self.data.into_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_iter_indexed(self) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_iter_rows(self) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> std::slice::Iter<T> {
|
|
||||||
self.data.iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_indexed(&self) -> IterIndexed<T> {
|
|
||||||
IterIndexed { indices: self.indices(), matrix_iter: self.iter() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_rows(&self) -> std::slice::Chunks<T> {
|
|
||||||
self.data.chunks(self.width)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_mut(&mut self) -> std::slice::IterMut<T> {
|
|
||||||
self.data.iter_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_indexed_mut(&mut self) -> IterIndexedMut<T> {
|
|
||||||
IterIndexedMut { i: 0, j: 0, width: self.width, matrix_iter_mut: self.iter_mut() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_rows_mut(&mut self) -> std::slice::ChunksMut<T> {
|
|
||||||
self.data.chunks_mut(self.width)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IterIndexed<'a, T: Num> {
|
|
||||||
indices: IterIndices,
|
|
||||||
matrix_iter: std::slice::Iter<'a, T>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IterIndexedMut<'a, T: Num> {
|
|
||||||
i: usize, j: usize, width: usize,
|
|
||||||
matrix_iter_mut: std::slice::IterMut<'a, T>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IterIndices {
|
|
||||||
i: usize, j: usize, width: usize, height: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: Num> Iterator for IterIndexed<'a, T> {
|
|
||||||
type Item = (usize, usize, &'a T);
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.indices.next()
|
|
||||||
.zip(self.matrix_iter.next())
|
|
||||||
.map(|((i, j), e)| (i, j, e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: Num> Iterator for IterIndexedMut<'a, T> {
|
|
||||||
type Item = (usize, usize, &'a mut T);
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.matrix_iter_mut.next().map(|e| {
|
|
||||||
let next = (self.i, self.j, e);
|
|
||||||
self.j += 1;
|
|
||||||
if self.j >= self.width {
|
|
||||||
self.i += 1;
|
|
||||||
self.j = 0;
|
|
||||||
}
|
|
||||||
next
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for IterIndices {
|
|
||||||
type Item = (usize, usize);
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.j += 1;
|
|
||||||
if self.j > self.width {
|
|
||||||
self.i += 1;
|
|
||||||
if self.i >= self.height { return None; }
|
|
||||||
self.j = 1;
|
|
||||||
}
|
|
||||||
Some((self.i, self.j - 1))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,83 +93,27 @@ impl<T: Num> IndexMut<(usize, usize)> for Matrix<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op<T, F>(this: Matrix<T>, rhs: Matrix<T>, op: F) -> Option<Matrix<T>>
|
|
||||||
where T: Num + Clone, F: Fn(T, T) -> T {
|
|
||||||
if this.width != rhs.width || this.height() != rhs.height() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let mut new = this.clone();
|
|
||||||
for (i, j) in new.indices() {
|
|
||||||
new[i][j] = op(new[i][j].clone(), rhs[i][j].clone());
|
|
||||||
}
|
|
||||||
Some(new)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn op_assign<T, F>(this: &mut Matrix<T>, rhs: Matrix<T>, op: F)
|
|
||||||
where T: NumAssign + Clone, F: Fn(&mut T, T) {
|
|
||||||
if this.width != rhs.width || this.height() != rhs.height() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (i, j, e) in this.iter_indexed_mut() {
|
|
||||||
op(e, rhs[i][j].clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Num + Clone> Add for Matrix<T> {
|
|
||||||
type Output = Option<Self>;
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
|
||||||
op(self, rhs, T::add)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: NumAssign + Clone> AddAssign for Matrix<T> {
|
|
||||||
fn add_assign(&mut self, rhs: Self) {
|
|
||||||
op_assign(self, rhs, T::add_assign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Num + Signed + Clone> Neg for Matrix<T> {
|
|
||||||
type Output = Self;
|
|
||||||
fn neg(mut self) -> Self::Output {
|
|
||||||
for e in self.iter_mut() {
|
|
||||||
*e = -e.clone();
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Num + Clone> Sub for Matrix<T> {
|
|
||||||
type Output = Option<Self>;
|
|
||||||
fn sub(self, rhs: Self) -> Self::Output {
|
|
||||||
op(self, rhs, T::sub)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: NumAssign + Clone> SubAssign for Matrix<T> {
|
|
||||||
fn sub_assign(&mut self, rhs: Self) {
|
|
||||||
op_assign(self, rhs, T::sub_assign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! matrix {
|
macro_rules! matrix {
|
||||||
[ $w:expr; $( $x:expr ),+ ] => {
|
[ $w:expr; $( $x:expr ),+ ] => {
|
||||||
Matrix::new(vec![$( $x, )+], $w)
|
$crate::math::Matrix::new(vec![$( $x, )+], $w)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use matrix;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic(expected = "exceeds usize limit")]
|
||||||
fn size_too_big() {
|
fn size_too_big() {
|
||||||
Matrix::<i32>::new_zeroes(usize::MAX, 2);
|
Matrix::<i32>::new_zeroes(usize::MAX, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic(expected = "size must be greater")]
|
||||||
fn size_too_small() {
|
fn size_too_small() {
|
||||||
Matrix::<i32>::new_zeroes(1, 1);
|
Matrix::<i32>::new_zeroes(1, 1);
|
||||||
}
|
}
|
||||||
|
@ -320,104 +148,4 @@ mod tests {
|
||||||
matrix[2][1] = 0;
|
matrix[2][1] = 0;
|
||||||
assert_eq!(matrix[2][1], 0);
|
assert_eq!(matrix[2][1], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn iter() {
|
|
||||||
let data = vec![1,2,3,4,5,6,7,8,9];
|
|
||||||
let mut matrix = Matrix::new(data.clone(), 3);
|
|
||||||
for (i, e) in matrix.iter().enumerate() {
|
|
||||||
assert_eq!(data[i], *e);
|
|
||||||
}
|
|
||||||
for (i, e) in matrix.iter_mut().enumerate() {
|
|
||||||
*e += 2;
|
|
||||||
assert_eq!(data[i] + 2, *e);
|
|
||||||
}
|
|
||||||
for (i, e) in matrix.into_iter().enumerate() {
|
|
||||||
assert_eq!(data[i] + 2, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn minor() {
|
|
||||||
let matrix = matrix![4;
|
|
||||||
1, 2, 3, 4,
|
|
||||||
5, 6, 7, 8,
|
|
||||||
9, 10, 11, 12
|
|
||||||
];
|
|
||||||
assert_eq!(matrix.minor(0, 0), matrix![3;
|
|
||||||
6, 7, 8,
|
|
||||||
10, 11, 12
|
|
||||||
]);
|
|
||||||
assert_eq!(matrix.minor(1, 2), matrix![3;
|
|
||||||
1, 2, 4,
|
|
||||||
9, 10, 12
|
|
||||||
]);
|
|
||||||
assert_eq!(matrix.minor(0, 0).minor(0, 0), matrix![2;
|
|
||||||
11, 12
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn minor_2x2_panic() {
|
|
||||||
matrix![2;
|
|
||||||
1, 2,
|
|
||||||
3, 4
|
|
||||||
].minor(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn minor_1xn_panic() {
|
|
||||||
matrix![1; 1, 2, 3, 4].minor(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn minor_nx1_panic() {
|
|
||||||
matrix![4; 1, 2, 3, 4].minor(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn transposed() {
|
|
||||||
let matrix = matrix![4;
|
|
||||||
1, 2, 3, 4,
|
|
||||||
5, 6, 7, 8,
|
|
||||||
9, 10, 11, 12
|
|
||||||
];
|
|
||||||
assert_eq!(matrix.transposed(), matrix![3;
|
|
||||||
1, 5, 9,
|
|
||||||
2, 6, 10,
|
|
||||||
3, 7, 11,
|
|
||||||
4, 8, 12
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn add() {
|
|
||||||
let mut matrix = matrix![2; 1, 2, 3, 4];
|
|
||||||
matrix += matrix![2; 2, 3, 5, 4];
|
|
||||||
assert_eq!(matrix, matrix![2; 3, 5, 8, 8]);
|
|
||||||
matrix += Matrix::new_filled(1, 3, 4);
|
|
||||||
assert_eq!(matrix, matrix![2; 3, 5, 8, 8]);
|
|
||||||
assert_eq!(matrix + matrix![2; 2, 3, 5, 4], Some(matrix![2; 5, 8, 13, 12]));
|
|
||||||
assert_eq!(Matrix::new_filled(1, 3, 3) + Matrix::new_filled(1, 3, 4), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sub() {
|
|
||||||
let mut matrix = matrix![2; 1, 2, 3, 4];
|
|
||||||
matrix -= matrix![2; 2, 3, 5, 4];
|
|
||||||
assert_eq!(matrix, matrix![2; -1, -1, -2, 0]);
|
|
||||||
matrix -= Matrix::new_filled(1, 3, 4);
|
|
||||||
assert_eq!(matrix, matrix![2; -1, -1, -2, 0]);
|
|
||||||
assert_eq!(matrix - matrix![2; 2, 3, 5, 4], Some(matrix![2; -3, -4, -7, -4]));
|
|
||||||
assert_eq!(Matrix::new_filled(1, 3, 3) - Matrix::new_filled(1, 3, 4), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn neg() {
|
|
||||||
let matrix = matrix![2; 1, 2, 3, 4];
|
|
||||||
assert_eq!(-matrix, matrix![2; -1, -2, -3, -4]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
176
src/math/matrix/arithemtic.rs
Normal file
176
src/math/matrix/arithemtic.rs
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
|
|
||||||
|
use num::{traits::NumAssign, Num, Signed};
|
||||||
|
|
||||||
|
impl<T: Num + Clone> Add for Matrix<T> {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
if !self.same_size(&rhs) {
|
||||||
|
panic!("Unable to add matrices with different sizes {}x{} and {}x{}",
|
||||||
|
self.width, self.height(), rhs.width, rhs.height());
|
||||||
|
}
|
||||||
|
let mut new_data = Box::new(Vec::with_capacity(self.size()));
|
||||||
|
for (e1, e2) in self.iter().zip(rhs.iter()) {
|
||||||
|
new_data.push(e1.clone() + e2.clone());
|
||||||
|
}
|
||||||
|
Self { width: self.width, data: new_data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NumAssign + Clone> AddAssign for Matrix<T> {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
if !self.same_size(&rhs) {
|
||||||
|
panic!("Unable to add matrices with different sizes {}x{} and {}x{}",
|
||||||
|
self.width, self.height(), rhs.width, rhs.height());
|
||||||
|
}
|
||||||
|
for (e1, e2) in self.iter_mut().zip(rhs.iter()) {
|
||||||
|
*e1 += e2.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Num + Signed + Clone> Neg for Matrix<T> {
|
||||||
|
type Output = Self;
|
||||||
|
fn neg(mut self) -> Self::Output {
|
||||||
|
for e in self.iter_mut() {
|
||||||
|
*e = -e.clone();
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Num + Clone> Sub for Matrix<T> {
|
||||||
|
type Output = Self;
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
if !self.same_size(&rhs) {
|
||||||
|
panic!("Unable to subtract matrices with different sizes {}x{} and {}x{}",
|
||||||
|
self.width, self.height(), rhs.width, rhs.height());
|
||||||
|
}
|
||||||
|
let mut new_data = Box::new(Vec::with_capacity(self.size()));
|
||||||
|
for (e1, e2) in self.iter().zip(rhs.iter()) {
|
||||||
|
new_data.push(e1.clone() - e2.clone());
|
||||||
|
}
|
||||||
|
Self { width: self.width, data: new_data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NumAssign + Clone> SubAssign for Matrix<T> {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
if !self.same_size(&rhs) {
|
||||||
|
panic!("Unable to subtract matrices with different sizes {}x{} and {}x{}",
|
||||||
|
self.width, self.height(), rhs.width, rhs.height());
|
||||||
|
}
|
||||||
|
for (e1, e2) in self.iter_mut().zip(rhs.iter()) {
|
||||||
|
*e1 -= e2.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Num + Clone> Mul<T> for Matrix<T> {
|
||||||
|
type Output = Self;
|
||||||
|
fn mul(self, rhs: T) -> Self::Output {
|
||||||
|
let mut new_data = Box::new(Vec::with_capacity(self.size()));
|
||||||
|
for e in self.iter() {
|
||||||
|
new_data.push(e.clone() * rhs.clone());
|
||||||
|
}
|
||||||
|
Self { width: self.width, data: new_data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NumAssign + Clone> MulAssign<T> for Matrix<T> {
|
||||||
|
fn mul_assign(&mut self, rhs: T) {
|
||||||
|
for e in self.iter_mut() {
|
||||||
|
*e *= rhs.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Num + Clone> Div<T> for Matrix<T> {
|
||||||
|
type Output = Self;
|
||||||
|
fn div(self, rhs: T) -> Self::Output {
|
||||||
|
let mut new_data = Box::new(Vec::with_capacity(self.size()));
|
||||||
|
for e in self.iter() {
|
||||||
|
new_data.push(e.clone() / rhs.clone());
|
||||||
|
}
|
||||||
|
Self { width: self.width, data: new_data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NumAssign + Clone> DivAssign<T> for Matrix<T> {
|
||||||
|
fn div_assign(&mut self, rhs: T) {
|
||||||
|
for e in self.iter_mut() {
|
||||||
|
*e /= rhs.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "different sizes")]
|
||||||
|
fn add_diff_sizes() {
|
||||||
|
let _ = Matrix::new_filled(1, 3, 3) + Matrix::new_filled(1, 3, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "different sizes")]
|
||||||
|
fn add_assign_diff_sizes() {
|
||||||
|
let mut matrix = Matrix::new_filled(1, 3, 3);
|
||||||
|
matrix += Matrix::new_filled(1, 3, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add() {
|
||||||
|
let mut matrix = matrix![2; 1, 2, 3, 4];
|
||||||
|
matrix += matrix![2; 2, 3, 5, 4];
|
||||||
|
assert_eq!(matrix, matrix![2; 3, 5, 8, 8]);
|
||||||
|
assert_eq!(matrix + matrix![2; 2, 3, 5, 4], matrix![2; 5, 8, 13, 12]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "different sizes")]
|
||||||
|
fn sub_diff_sizes() {
|
||||||
|
let _ = Matrix::new_filled(1, 3, 3) - Matrix::new_filled(1, 3, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "different sizes")]
|
||||||
|
fn sub_assign_diff_sizes() {
|
||||||
|
let mut matrix = Matrix::new_filled(1, 3, 3);
|
||||||
|
matrix -= Matrix::new_filled(1, 3, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub() {
|
||||||
|
let mut matrix = matrix![2; 1, 2, 3, 4];
|
||||||
|
matrix -= matrix![2; 2, 3, 5, 4];
|
||||||
|
assert_eq!(matrix, matrix![2; -1, -1, -2, 0]);
|
||||||
|
assert_eq!(matrix - matrix![2; 2, 3, 5, 4], matrix![2; -3, -4, -7, -4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn neg() {
|
||||||
|
assert_eq!(-matrix![2; 1, 2, 3, 4], matrix![2; -1, -2, -3, -4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul() {
|
||||||
|
let mut matrix = matrix![2; 1, 2, 3, 4];
|
||||||
|
matrix *= 2;
|
||||||
|
assert_eq!(matrix, matrix![2; 2, 4, 6, 8]);
|
||||||
|
assert_eq!(matrix * 0, matrix![2; 0, 0, 0, 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn div() {
|
||||||
|
let mut matrix = matrix![2; 2, 5, 8, 9];
|
||||||
|
matrix /= 2;
|
||||||
|
assert_eq!(matrix, matrix![2; 1, 2, 4, 4]);
|
||||||
|
assert_eq!(matrix / 4, matrix![2; 0, 0, 1, 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
112
src/math/matrix/iter.rs
Normal file
112
src/math/matrix/iter.rs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use num::Num;
|
||||||
|
|
||||||
|
impl<T: Num + Clone> Matrix<T> {
|
||||||
|
pub fn indices(&self) -> IterIndices {
|
||||||
|
IterIndices { i: 0, j: 0, width: self.width, height: self.height() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_iter(self) -> std::vec::IntoIter<T> {
|
||||||
|
self.data.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_iter_indexed(self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_iter_rows(self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<T> {
|
||||||
|
self.data.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_indexed(&self) -> IterIndexed<T> {
|
||||||
|
IterIndexed { indices: self.indices(), matrix_iter: self.iter() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_rows(&self) -> std::slice::Chunks<T> {
|
||||||
|
self.data.chunks(self.width)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_mut(&mut self) -> std::slice::IterMut<T> {
|
||||||
|
self.data.iter_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_indexed_mut(&mut self) -> IterIndexedMut<T> {
|
||||||
|
IterIndexedMut { indices: self.indices(), matrix_iter_mut: self.iter_mut() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_rows_mut(&mut self) -> std::slice::ChunksMut<T> {
|
||||||
|
self.data.chunks_mut(self.width)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IterIndexed<'a, T: Num> {
|
||||||
|
indices: IterIndices,
|
||||||
|
matrix_iter: std::slice::Iter<'a, T>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IterIndexedMut<'a, T: Num> {
|
||||||
|
indices: IterIndices,
|
||||||
|
matrix_iter_mut: std::slice::IterMut<'a, T>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IterIndices {
|
||||||
|
i: usize, j: usize, width: usize, height: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Num> Iterator for IterIndexed<'a, T> {
|
||||||
|
type Item = (usize, usize, &'a T);
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.indices.next()
|
||||||
|
.zip(self.matrix_iter.next())
|
||||||
|
.map(|((i, j), e)| (i, j, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Num> Iterator for IterIndexedMut<'a, T> {
|
||||||
|
type Item = (usize, usize, &'a mut T);
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.indices.next()
|
||||||
|
.zip(self.matrix_iter_mut.next())
|
||||||
|
.map(|((i, j), e)| (i, j, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for IterIndices {
|
||||||
|
type Item = (usize, usize);
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.j += 1;
|
||||||
|
if self.j > self.width {
|
||||||
|
self.i += 1;
|
||||||
|
if self.i >= self.height { return None; }
|
||||||
|
self.j = 1;
|
||||||
|
}
|
||||||
|
Some((self.i, self.j - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn iter() {
|
||||||
|
let data = vec![1,2,3,4,5,6,7,8,9];
|
||||||
|
let mut matrix = Matrix::new(data.clone(), 3);
|
||||||
|
for (i, e) in matrix.iter().enumerate() {
|
||||||
|
assert_eq!(data[i], *e);
|
||||||
|
}
|
||||||
|
for (i, e) in matrix.iter_mut().enumerate() {
|
||||||
|
*e += 2;
|
||||||
|
assert_eq!(data[i] + 2, *e);
|
||||||
|
}
|
||||||
|
for (i, e) in matrix.into_iter().enumerate() {
|
||||||
|
assert_eq!(data[i] + 2, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
99
src/math/matrix/ops.rs
Normal file
99
src/math/matrix/ops.rs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use num::Num;
|
||||||
|
|
||||||
|
impl<T: Num + Clone> Matrix<T> {
|
||||||
|
pub fn minor(&self, row_index: usize, column_index: usize) -> Self {
|
||||||
|
if self.width < 2 {
|
||||||
|
panic!("Matrix width must be greater than 1 to form its minor, but got {}", self.width)
|
||||||
|
}
|
||||||
|
let height = self.height();
|
||||||
|
if height < 2 {
|
||||||
|
panic!("Matrix height must be greater than 1 to form its minor, but got {}", height)
|
||||||
|
}
|
||||||
|
if self.width == 2 && height == 2 {
|
||||||
|
panic!("Unable to form minor of a 2x2 matrix");
|
||||||
|
}
|
||||||
|
let minor_width = self.width - 1;
|
||||||
|
let mut minor_data = Box::new(Vec::with_capacity(minor_width * (height - 1)));
|
||||||
|
for (i, j, e) in self.iter_indexed() {
|
||||||
|
if i == row_index || j == column_index { continue; }
|
||||||
|
minor_data.push(e.clone());
|
||||||
|
}
|
||||||
|
Self { width: minor_width, data: minor_data }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transposed(&self) -> Self {
|
||||||
|
let mut transposed_data = Box::new(Vec::with_capacity(self.data.len()));
|
||||||
|
let height = self.height();
|
||||||
|
for j in 0..self.width {
|
||||||
|
let mut row_start = 0usize;
|
||||||
|
for _ in 0..height {
|
||||||
|
transposed_data.push(self.data[row_start + j].clone());
|
||||||
|
row_start += self.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self { width: height, data: transposed_data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn minor() {
|
||||||
|
let matrix = matrix![4;
|
||||||
|
1, 2, 3, 4,
|
||||||
|
5, 6, 7, 8,
|
||||||
|
9, 10, 11, 12
|
||||||
|
];
|
||||||
|
assert_eq!(matrix.minor(0, 0), matrix![3;
|
||||||
|
6, 7, 8,
|
||||||
|
10, 11, 12
|
||||||
|
]);
|
||||||
|
assert_eq!(matrix.minor(1, 2), matrix![3;
|
||||||
|
1, 2, 4,
|
||||||
|
9, 10, 12
|
||||||
|
]);
|
||||||
|
assert_eq!(matrix.minor(0, 0).minor(0, 0), matrix![2;
|
||||||
|
11, 12
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "minor of a 2x2 matrix")]
|
||||||
|
fn minor_2x2_panic() {
|
||||||
|
matrix![2;
|
||||||
|
1, 2,
|
||||||
|
3, 4
|
||||||
|
].minor(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "width must be greater")]
|
||||||
|
fn minor_1xn_panic() {
|
||||||
|
matrix![1; 1, 2, 3, 4].minor(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "height must be greater")]
|
||||||
|
fn minor_nx1_panic() {
|
||||||
|
matrix![4; 1, 2, 3, 4].minor(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transposed() {
|
||||||
|
let matrix = matrix![4;
|
||||||
|
1, 2, 3, 4,
|
||||||
|
5, 6, 7, 8,
|
||||||
|
9, 10, 11, 12
|
||||||
|
];
|
||||||
|
assert_eq!(matrix.transposed(), matrix![3;
|
||||||
|
1, 5, 9,
|
||||||
|
2, 6, 10,
|
||||||
|
3, 7, 11,
|
||||||
|
4, 8, 12
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,8 @@ fn check_size(order: usize) -> usize {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! sq_matrix {
|
macro_rules! sq_matrix {
|
||||||
[ $o:expr; $( $x:expr ),+ ] => {
|
[ $o:expr; $( $x:expr ),+ ] => {
|
||||||
SquareMatrix::new(vec![$( $x, )+], $o)
|
$crate::math::SquareMatrix::new(vec![$( $x, )+], $o)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use sq_matrix;
|
||||||
|
|
Loading…
Reference in a new issue