Separated Num and Num + Clone implementations
Implemented iterator over every matrix element index pair (i, j) in method Matrix::indices Removed redundat lifetime specifiers in some iterator methods Implemented Add, AddAssign, Sub, SubAssign and Neg traits for Matrix Added some tests for new functionality
This commit is contained in:
parent
25c1f55254
commit
a2e311f295
1 changed files with 175 additions and 44 deletions
|
@ -1,9 +1,9 @@
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Add, AddAssign, Index, IndexMut, Neg, Sub, SubAssign};
|
||||||
|
|
||||||
use num::Num;
|
use num::{traits::NumAssign, Num, Signed};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
pub struct Matrix<T: Num + Clone> {
|
pub struct Matrix<T: Num> {
|
||||||
width: usize,
|
width: usize,
|
||||||
data: Box<Vec<T>>
|
data: Box<Vec<T>>
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,41 @@ impl<T: Num + Clone> Matrix<T> {
|
||||||
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> {
|
||||||
pub fn new(mut data: Vec<T>, width: usize) -> Self {
|
pub fn new(mut data: Vec<T>, width: usize) -> Self {
|
||||||
if width <= 0 {
|
if width <= 0 {
|
||||||
panic!("Matrix width must be greater than 0, but got {}", width)
|
panic!("Matrix width must be greater than 0, but got {}", width)
|
||||||
|
@ -54,24 +89,8 @@ impl<T: Num + Clone> Matrix<T> {
|
||||||
self.data.len()
|
self.data.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn minor(&self, row_index: usize, column_index: usize) -> Self {
|
pub fn indices(&self) -> IterIndices {
|
||||||
if self.width < 2 {
|
IterIndices { i: 0, j: 0, width: self.width, height: self.height() }
|
||||||
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 = 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: Box::new(minor_data) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_iter(self) -> std::vec::IntoIter<T> {
|
pub fn into_iter(self) -> std::vec::IntoIter<T> {
|
||||||
|
@ -90,8 +109,8 @@ impl<T: Num + Clone> Matrix<T> {
|
||||||
self.data.iter()
|
self.data.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_indexed<'a>(&'a self) -> IterIndexed<'a, T> {
|
pub fn iter_indexed(&self) -> IterIndexed<T> {
|
||||||
IterIndexed { i: 0, j: 0, width: self.width, matrix_iter: self.iter() }
|
IterIndexed { indices: self.indices(), matrix_iter: self.iter() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_rows(&self) -> std::slice::Chunks<T> {
|
pub fn iter_rows(&self) -> std::slice::Chunks<T> {
|
||||||
|
@ -102,41 +121,39 @@ impl<T: Num + Clone> Matrix<T> {
|
||||||
self.data.iter_mut()
|
self.data.iter_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_indexed_mut<'a>(&'a mut self) -> IterIndexedMut<'a, T> {
|
pub fn iter_indexed_mut(&mut self) -> IterIndexedMut<T> {
|
||||||
IterIndexedMut { i: 0, j: 0, width: self.width, matrix_iter_mut: self.iter_mut() }
|
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> {
|
pub fn iter_rows_mut(&mut self) -> std::slice::ChunksMut<T> {
|
||||||
self.data.chunks_mut(self.width)
|
self.data.chunks_mut(self.width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IterIndexed<'a, T: Num + Clone> {
|
pub struct IterIndexed<'a, T: Num> {
|
||||||
i: usize, j: usize, width: usize,
|
indices: IterIndices,
|
||||||
matrix_iter: std::slice::Iter<'a, T>
|
matrix_iter: std::slice::Iter<'a, T>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IterIndexedMut<'a, T: Num + Clone> {
|
pub struct IterIndexedMut<'a, T: Num> {
|
||||||
i: usize, j: usize, width: usize,
|
i: usize, j: usize, width: usize,
|
||||||
matrix_iter_mut: std::slice::IterMut<'a, T>
|
matrix_iter_mut: std::slice::IterMut<'a, T>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Num + Clone> Iterator for IterIndexed<'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);
|
type Item = (usize, usize, &'a T);
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.matrix_iter.next().map(|e| {
|
self.indices.next()
|
||||||
let next = (self.i, self.j, e);
|
.zip(self.matrix_iter.next())
|
||||||
self.j += 1;
|
.map(|((i, j), e)| (i, j, e))
|
||||||
if self.j >= self.width {
|
|
||||||
self.i += 1;
|
|
||||||
self.j = 0;
|
|
||||||
}
|
|
||||||
next
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Num + Clone> Iterator for IterIndexedMut<'a, T> {
|
impl<'a, T: Num> Iterator for IterIndexedMut<'a, T> {
|
||||||
type Item = (usize, usize, &'a mut T);
|
type Item = (usize, usize, &'a mut T);
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.matrix_iter_mut.next().map(|e| {
|
self.matrix_iter_mut.next().map(|e| {
|
||||||
|
@ -151,7 +168,20 @@ impl<'a, T: Num + Clone> Iterator for IterIndexedMut<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Num + Clone> Index<usize> for Matrix<T> {
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Num> Index<usize> for Matrix<T> {
|
||||||
type Output = [T];
|
type Output = [T];
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
let row_start = index * self.width;
|
let row_start = index * self.width;
|
||||||
|
@ -159,26 +189,84 @@ impl<T: Num + Clone> Index<usize> for Matrix<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Num + Clone> IndexMut<usize> for Matrix<T> {
|
impl<T: Num> IndexMut<usize> for Matrix<T> {
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
let row_start = index * self.width;
|
let row_start = index * self.width;
|
||||||
&mut self.data[row_start..row_start + self.width]
|
&mut self.data[row_start..row_start + self.width]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Num + Clone> Index<(usize, usize)> for Matrix<T> {
|
impl<T: Num> Index<(usize, usize)> for Matrix<T> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
fn index(&self, index: (usize, usize)) -> &Self::Output {
|
fn index(&self, index: (usize, usize)) -> &Self::Output {
|
||||||
&self.data[index.0 * self.width + index.1]
|
&self.data[index.0 * self.width + index.1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Num + Clone> IndexMut<(usize, usize)> for Matrix<T> {
|
impl<T: Num> IndexMut<(usize, usize)> for Matrix<T> {
|
||||||
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
|
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
|
||||||
&mut self.data[index.0 * self.width + index.1]
|
&mut self.data[index.0 * self.width + index.1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 ),+ ] => {
|
||||||
|
@ -289,4 +377,47 @@ mod tests {
|
||||||
fn minor_nx1_panic() {
|
fn minor_nx1_panic() {
|
||||||
matrix![4; 1, 2, 3, 4].minor(0, 0);
|
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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue