diff --git a/math/src/matrix.rs b/math/src/matrix.rs index 5f677bb..097e235 100644 --- a/math/src/matrix.rs +++ b/math/src/matrix.rs @@ -12,7 +12,7 @@ pub struct Matrix { 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 { @@ -34,7 +34,7 @@ impl Matrix { } pub fn column(&self, j: usize) -> Vec { - self.iter_column(j).cloned().collect() + self.iter_column(j).copied().collect() } pub fn append_row_zeroes(&mut self) { @@ -44,6 +44,19 @@ impl Matrix { pub fn append_column_zeroes(&mut self) { self.append_column(vec![T::zero(); self.height()]) } + + pub fn remove_row(&mut self, i: usize) { + if self.height() <= 2 { + panic!("Unable to remove row of a matrix with height {}", self.height()); + } + let row_start = i * self.width; + self.data.copy_within(row_start+self.width.., row_start); + self.data.truncate(self.data.len() - self.width); + } + + pub fn remove_last_row(&mut self) { + self.remove_row(self.height() - 1); + } } impl Matrix { @@ -102,6 +115,21 @@ impl Matrix { } self.width += 1; } + + pub fn remove_column(&mut self, j: usize) { + if self.width <= 2 { + panic!("Unable to remove column of a matrix with height {}", self.width); + } + for i in 0..self.height() { + let remove_at = i * (self.width - 1) + j; + self.data.remove(remove_at); + } + self.width -= 1; + } + + pub fn remove_last_column(&mut self) { + self.remove_column(self.width - 1); + } } impl Index for Matrix { @@ -260,4 +288,60 @@ mod tests { 3, 4 ].append_column(vec![1, 2, 3]); } + + #[test] + fn remove_row_and_column() { + let mut matrix = matrix![3; + 1, 2, 3, + 4, 5, 6, + 7, 8, 9 + ]; + matrix.remove_row(1); + assert_eq!(matrix, matrix![3; + 1, 2, 3, + 7, 8, 9 + ]); + matrix.remove_column(1); + assert_eq!(matrix, matrix![2; + 1, 3, + 7, 9 + ]); + } + + #[test] + #[should_panic(expected = "Unable to remove")] + fn remove_row_wrong_height() { + matrix![2; + 1, 2, + 3, 4 + ].remove_row(1); + } + + #[test] + #[should_panic(expected = "Unable to remove")] + fn remove_column_wrong_height() { + matrix![2; + 1, 2, + 3, 4 + ].remove_column(1); + } + + #[test] + fn remove_last_row_and_column() { + let mut matrix = matrix![3; + 1, 2, 3, + 4, 5, 6, + 7, 8, 9 + ]; + matrix.remove_last_row(); + assert_eq!(matrix, matrix![3; + 1, 2, 3, + 4, 5, 6 + ]); + matrix.remove_last_column(); + assert_eq!(matrix, matrix![2; + 1, 2, + 4, 5 + ]); + } } diff --git a/math/src/matrix/arithemtic.rs b/math/src/matrix/arithemtic.rs index d393a5d..fa92df4 100644 --- a/math/src/matrix/arithemtic.rs +++ b/math/src/matrix/arithemtic.rs @@ -4,7 +4,7 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi use num::{traits::NumAssign, Num, Signed}; -impl Matrix { +impl Matrix { pub fn multiply(&self, rhs: &Self) -> Self { if !self.can_mul(&rhs) { panic!("Unable to multiply matrices with sizes {}x{} and {}x{}", @@ -22,109 +22,109 @@ impl Matrix { } } -impl Add for Matrix { +impl Add for Matrix { 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()); + let width = self.width; + let mut data = Box::new(Vec::with_capacity(self.size())); + for (e1, e2) in self.into_iter().zip(rhs.into_iter()) { + data.push(e1 + e2); } - Self { width: self.width, data: new_data } + Self { width, data } } } -impl AddAssign for Matrix { +impl AddAssign for Matrix { 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(); + for (e1, e2) in self.iter_mut().zip(rhs.into_iter()) { + *e1 += e2; } } } -impl Neg for Matrix { +impl Neg for Matrix { type Output = Self; fn neg(mut self) -> Self::Output { for e in self.iter_mut() { - *e = -e.clone(); + *e = -*e; } return self; } } -impl Sub for Matrix { +impl Sub for Matrix { 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()); + let width = self.width; + let mut data = Box::new(Vec::with_capacity(self.size())); + for (e1, e2) in self.into_iter().zip(rhs.into_iter()) { + data.push(e1 - e2); } - Self { width: self.width, data: new_data } + Self { width, data } } } -impl SubAssign for Matrix { +impl SubAssign for Matrix { 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(); + for (e1, e2) in self.iter_mut().zip(rhs.into_iter()) { + *e1 -= e2; } } } -impl Mul for Matrix { +impl Mul for Matrix { 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()); + fn mul(mut self, rhs: T) -> Self::Output { + for e in self.iter_mut() { + *e = *e * rhs; } - Self { width: self.width, data: new_data } + return self; } } -impl MulAssign for Matrix { +impl MulAssign for Matrix { fn mul_assign(&mut self, rhs: T) { for e in self.iter_mut() { - *e *= rhs.clone(); + *e *= rhs; } } } -impl Div for Matrix { +impl Div for Matrix { 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()); + fn div(mut self, rhs: T) -> Self::Output { + for e in self.iter_mut() { + *e = *e / rhs; } - Self { width: self.width, data: new_data } + return self; } } -impl DivAssign for Matrix { +impl DivAssign for Matrix { fn div_assign(&mut self, rhs: T) { for e in self.iter_mut() { - *e /= rhs.clone(); + *e /= rhs; } } } -impl Mul for Matrix { +impl Mul for Matrix { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { self.multiply(&rhs) diff --git a/math/src/matrix/iter.rs b/math/src/matrix/iter.rs index 5e10d0b..715b766 100644 --- a/math/src/matrix/iter.rs +++ b/math/src/matrix/iter.rs @@ -4,7 +4,7 @@ use std::{slice::{Chunks, ChunksMut, Iter, IterMut}, vec::IntoIter}; use num::Num; -impl Matrix { +impl Matrix { pub fn indices(&self) -> IterIndices { IterIndices { i: 0, j: 0, width: self.width, height: self.height() } } diff --git a/math/src/matrix/ops.rs b/math/src/matrix/ops.rs index d449db8..3cbfc32 100644 --- a/math/src/matrix/ops.rs +++ b/math/src/matrix/ops.rs @@ -2,7 +2,7 @@ use super::*; use num::Num; -impl Matrix { +impl Matrix { 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) @@ -18,7 +18,7 @@ impl Matrix { 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()); + minor_data.push(*e); } Self { width: minor_width, data: minor_data } } @@ -29,7 +29,7 @@ impl Matrix { for j in 0..self.width { let mut row_start = 0usize; for _ in 0..height { - transposed_data.push(self.data[row_start + j].clone()); + transposed_data.push(self.data[row_start + j]); row_start += self.width; } } diff --git a/math/src/sq_matrix.rs b/math/src/sq_matrix.rs index b259b70..6a684f4 100644 --- a/math/src/sq_matrix.rs +++ b/math/src/sq_matrix.rs @@ -1,21 +1,13 @@ use num::Num; use super::matrix::Matrix; -pub struct SquareMatrix { +pub struct SquareMatrix { matrix: Matrix } -impl SquareMatrix { - pub fn new_filled(val: T, order: usize) -> Self { - let size = check_size(order); - let data = vec![val; size]; - Self { - matrix: Matrix::new_unchecked(data, order) - } - } - - pub fn new_zeroes(order: usize) -> Self { - Self::new_filled(T::zero(), order) +impl SquareMatrix { + pub fn order(&self) -> usize { + self.matrix.width() } pub fn new(mut data: Vec, order: usize) -> Self { @@ -25,9 +17,15 @@ impl SquareMatrix { matrix: Matrix::new_unchecked(data, order) } } +} - pub fn order(&self) -> usize { - self.matrix.width() +impl SquareMatrix { + pub fn new_filled(val: T, order: usize) -> Self { + let size = check_size(order); + let data = vec![val; size]; + Self { + matrix: Matrix::new_unchecked(data, order) + } } } diff --git a/web/index.scss b/web/index.scss index 0e50fa8..20c0552 100644 --- a/web/index.scss +++ b/web/index.scss @@ -2,17 +2,28 @@ $bg-color: #2b2927; $text-color: #e2e19c; $cell-color: #473b34; -html, body { +body { background-color: $bg-color; color: $text-color; - position: absolute; - top: 50%; - left: 50%; } -.matrix-cell { - background-color: $cell-color; - color: $text-color; - border: solid 1px black; - width: 30pt; +.matrix { + display: grid; + gap: 50px; + grid-template-columns: auto 100px; + grid-template-rows: auto 100px; + justify-content: start; + + input { + background-color: $cell-color; + color: $text-color; + border: solid 1px black; + width: 30pt; + } + + button { + background-color: $cell-color; + color: $text-color; + border: solid 1px black; + } } diff --git a/web/src/main.rs b/web/src/main.rs index 914006f..31d1253 100644 --- a/web/src/main.rs +++ b/web/src/main.rs @@ -8,7 +8,9 @@ pub struct MatrixComponent { pub enum MatrixMsg { CellChange(Cell), AddRow, - AddColumn + AddColumn, + RemoveRow, + RemoveColumn } impl Component for MatrixComponent { @@ -23,30 +25,38 @@ impl Component for MatrixComponent { match msg { MatrixMsg::CellChange(cell) => self.matrix[cell.i][cell.j] = cell.value, MatrixMsg::AddRow => self.matrix.append_row_zeroes(), - MatrixMsg::AddColumn => self.matrix.append_column_zeroes() + MatrixMsg::AddColumn => self.matrix.append_column_zeroes(), + MatrixMsg::RemoveRow => (), + MatrixMsg::RemoveColumn => () } return true; } fn view(&self, ctx: &Context) -> Html { let on_cell_change = ctx.link().callback(MatrixMsg::CellChange); + let on_click_add_row = ctx.link().callback(|_| MatrixMsg::AddRow); + let on_click_add_column = ctx.link().callback(|_| MatrixMsg::AddColumn); html! { - { - self.matrix.iter_rows().enumerate().map(|(i, row)| html! { - { - row.iter().enumerate().map(|(j, e)| { - let cell = Cell { i, j, value: *e }; - html! { - +
+
- -
{ + self.matrix.iter_rows().enumerate().map(|(i, row)| html! { + { + row.iter().enumerate().map(|(j, e)| { + let cell = Cell { i, j, value: *e }; + html! { + + } + }).collect::() } + }).collect::() } - - }).collect::() - } -
+ +
+ + + + } } } @@ -79,7 +89,7 @@ impl Component for MatrixCellComponent { Cell { i: cell.i, j: cell.j, value: e.as_f64().unwrap_or_default() } ); html! { - + } } }