From 25c1f55254f0104aceac8fe1b6b798d012185528 Mon Sep 17 00:00:00 2001 From: erius Date: Tue, 14 May 2024 14:24:54 +0300 Subject: [PATCH] Changed generic type T of matrix to only accept Num + Clone Derived some traits for Matrix Added panic when forming minor of a 2x2 matrix Added row iteration and indexed (i, j) element iteration Added more tests to Matrix --- src/math/matrix.rs | 170 ++++++++++++++++++++++++++++++++++++++---- src/math/sq_matrix.rs | 7 +- 2 files changed, 159 insertions(+), 18 deletions(-) diff --git a/src/math/matrix.rs b/src/math/matrix.rs index ad0a60f..c041bf6 100644 --- a/src/math/matrix.rs +++ b/src/math/matrix.rs @@ -2,12 +2,13 @@ use std::ops::{Index, IndexMut}; use num::Num; -pub struct Matrix { +#[derive(PartialEq, Eq, Debug)] +pub struct Matrix { width: usize, data: Box> } -impl Matrix { +impl Matrix { pub fn new_filled(val: T, width: usize, height: usize) -> Self { let Some(size) = width.checked_mul(height) else { @@ -23,9 +24,7 @@ impl Matrix { pub fn new_zeroes(width: usize, height: usize) -> Self { Self::new_filled(T::zero(), width, height) } -} -impl Matrix { pub fn new(mut data: Vec, width: usize) -> Self { if width <= 0 { panic!("Matrix width must be greater than 0, but got {}", width) @@ -63,12 +62,14 @@ impl Matrix { 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 = Vec::with_capacity(minor_width * (height - 1)); - for i in 0..row_index { - if i == row_index { continue; } - let row = &self[i]; - todo!() + 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: Box::new(minor_data) } } @@ -77,16 +78,80 @@ impl Matrix { 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 { self.data.iter() } + pub fn iter_indexed<'a>(&'a self) -> IterIndexed<'a, T> { + IterIndexed { i: 0, j: 0, width: self.width, matrix_iter: self.iter() } + } + + pub fn iter_rows(&self) -> std::slice::Chunks { + self.data.chunks(self.width) + } + pub fn iter_mut(&mut self) -> std::slice::IterMut { self.data.iter_mut() } + + pub fn iter_indexed_mut<'a>(&'a mut self) -> IterIndexedMut<'a, T> { + IterIndexedMut { i: 0, j: 0, width: self.width, matrix_iter_mut: self.iter_mut() } + } + + pub fn iter_mut_rows(&mut self) -> std::slice::ChunksMut { + self.data.chunks_mut(self.width) + } } -impl Index for Matrix { +pub struct IterIndexed<'a, T: Num + Clone> { + i: usize, j: usize, width: usize, + matrix_iter: std::slice::Iter<'a, T> +} + +pub struct IterIndexedMut<'a, T: Num + Clone> { + i: usize, j: usize, width: usize, + matrix_iter_mut: std::slice::IterMut<'a, T> +} + +impl<'a, T: Num + Clone> Iterator for IterIndexed<'a, T> { + type Item = (usize, usize, &'a T); + fn next(&mut self) -> Option { + self.matrix_iter.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<'a, T: Num + Clone> Iterator for IterIndexedMut<'a, T> { + type Item = (usize, usize, &'a mut T); + fn next(&mut self) -> Option { + 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 Index for Matrix { type Output = [T]; fn index(&self, index: usize) -> &Self::Output { let row_start = index * self.width; @@ -94,26 +159,27 @@ impl Index for Matrix { } } -impl IndexMut for Matrix { +impl IndexMut for Matrix { fn index_mut(&mut self, index: usize) -> &mut Self::Output { let row_start = index * self.width; &mut self.data[row_start..row_start + self.width] } } -impl Index<(usize, usize)> for Matrix { +impl Index<(usize, usize)> for Matrix { type Output = T; fn index(&self, index: (usize, usize)) -> &Self::Output { &self.data[index.0 * self.width + index.1] } } -impl IndexMut<(usize, usize)> for Matrix { +impl IndexMut<(usize, usize)> for Matrix { fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output { &mut self.data[index.0 * self.width + index.1] } } +#[macro_export] macro_rules! matrix { [ $w:expr; $( $x:expr ),+ ] => { Matrix::new(vec![$( $x, )+], $w) @@ -128,7 +194,6 @@ mod tests { #[should_panic] fn size_too_big() { Matrix::::new_zeroes(usize::MAX, 2); - let a = vec![0].into_iter(); } #[test] @@ -138,7 +203,7 @@ mod tests { } #[test] - fn new_test() { + fn new() { let matrix = matrix![3; 1, 2, 3, 4, 5, 6, @@ -147,4 +212,81 @@ mod tests { assert_eq!(matrix.width(), 3); assert_eq!(matrix.height(), 3); } + + #[test] + fn index() { + let mut matrix = matrix![3; + 1, 2, 3, + 4, 5, 6, + 7, 8, 9 + ]; + assert_eq!(matrix[(0, 0)], 1); + assert_eq!(matrix[(1, 2)], 6); + assert_eq!(matrix[(2, 2)], 9); + matrix[(1, 2)] = 10; + assert_eq!(matrix[(1, 2)], 10); + + assert_eq!(matrix[0][0], 1); + assert_eq!(matrix[2][1], 8); + assert_eq!(matrix[2][2], 9); + 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); + } } diff --git a/src/math/sq_matrix.rs b/src/math/sq_matrix.rs index d42e563..abb63a3 100644 --- a/src/math/sq_matrix.rs +++ b/src/math/sq_matrix.rs @@ -1,11 +1,11 @@ use num::Num; use super::matrix::Matrix; -pub struct SquareMatrix { +pub struct SquareMatrix { matrix: Matrix } -impl SquareMatrix { +impl SquareMatrix { pub fn new_filled(val: T, order: usize) -> Self { let size = check_size(order); let data = vec![val; size]; @@ -17,9 +17,7 @@ impl SquareMatrix { pub fn new_zeroes(order: usize) -> Self { Self::new_filled(T::zero(), order) } -} -impl SquareMatrix { pub fn new(mut data: Vec, order: usize) -> Self { let size = check_size(order); data.truncate(size); @@ -44,6 +42,7 @@ fn check_size(order: usize) -> usize { return size; } +#[macro_export] macro_rules! sq_matrix { [ $o:expr; $( $x:expr ),+ ] => { SquareMatrix::new(vec![$( $x, )+], $o)