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
This commit is contained in:
Egor 2024-05-14 14:24:54 +03:00
parent 883df942ea
commit 25c1f55254
2 changed files with 159 additions and 18 deletions

View file

@ -2,12 +2,13 @@ use std::ops::{Index, IndexMut};
use num::Num;
pub struct Matrix<T: Num> {
#[derive(PartialEq, Eq, Debug)]
pub struct Matrix<T: Num + Clone> {
width: usize,
data: Box<Vec<T>>
}
impl<T: Num + Copy> Matrix<T> {
impl<T: Num + Clone> Matrix<T> {
pub fn new_filled(val: T, width: usize, height: usize) -> Self {
let Some(size) = width.checked_mul(height)
else {
@ -23,9 +24,7 @@ impl<T: Num + Copy> Matrix<T> {
pub fn new_zeroes(width: usize, height: usize) -> Self {
Self::new_filled(T::zero(), width, height)
}
}
impl<T: Num> Matrix<T> {
pub fn new(mut data: Vec<T>, width: usize) -> Self {
if width <= 0 {
panic!("Matrix width must be greater than 0, but got {}", width)
@ -63,12 +62,14 @@ impl<T: Num> Matrix<T> {
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<T: Num> Matrix<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<'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<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<'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<T> {
self.data.chunks_mut(self.width)
}
}
impl<T: Num> Index<usize> for Matrix<T> {
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::Item> {
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::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<T: Num + Clone> Index<usize> for Matrix<T> {
type Output = [T];
fn index(&self, index: usize) -> &Self::Output {
let row_start = index * self.width;
@ -94,26 +159,27 @@ impl<T: Num> Index<usize> for Matrix<T> {
}
}
impl<T: Num> IndexMut<usize> for Matrix<T> {
impl<T: Num + Clone> IndexMut<usize> for Matrix<T> {
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<T: Num> Index<(usize, usize)> for Matrix<T> {
impl<T: Num + Clone> Index<(usize, usize)> for Matrix<T> {
type Output = T;
fn index(&self, index: (usize, usize)) -> &Self::Output {
&self.data[index.0 * self.width + index.1]
}
}
impl<T: Num> IndexMut<(usize, usize)> for Matrix<T> {
impl<T: Num + Clone> IndexMut<(usize, usize)> for Matrix<T> {
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::<i32>::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);
}
}

View file

@ -1,11 +1,11 @@
use num::Num;
use super::matrix::Matrix;
pub struct SquareMatrix<T: Num> {
pub struct SquareMatrix<T: Num + Clone> {
matrix: Matrix<T>
}
impl<T: Num + Copy> SquareMatrix<T> {
impl<T: Num + Clone> SquareMatrix<T> {
pub fn new_filled(val: T, order: usize) -> Self {
let size = check_size(order);
let data = vec![val; size];
@ -17,9 +17,7 @@ impl<T: Num + Copy> SquareMatrix<T> {
pub fn new_zeroes(order: usize) -> Self {
Self::new_filled(T::zero(), order)
}
}
impl<T: Num> SquareMatrix<T> {
pub fn new(mut data: Vec<T>, 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)