Added append_row, append_column, append_row_zeroes and append_column_zeroes methods to math::matrix::Matrix + some tests

Minor index.scss styles changes
Added prototype implementation for MatrixComponent in web crate
This commit is contained in:
Egor 2024-05-24 02:42:09 +03:00
parent 199805aafc
commit e4e17953e2
4 changed files with 186 additions and 2 deletions

View file

@ -36,6 +36,14 @@ impl<T: Num + Clone> Matrix<T> {
pub fn column(&self, j: usize) -> Vec<T> {
self.iter_column(j).cloned().collect()
}
pub fn append_row_zeroes(&mut self) {
self.append_row(vec![T::zero(); self.width])
}
pub fn append_column_zeroes(&mut self) {
self.append_column(vec![T::zero(); self.height()])
}
}
impl<T: Num> Matrix<T> {
@ -75,6 +83,25 @@ impl<T: Num> Matrix<T> {
pub fn can_mul(&self, other: &Self) -> bool {
self.width == other.height()
}
pub fn append_row(&mut self, mut row: Vec<T>) {
if row.len() != self.width {
panic!("Unable to append row with len {} to matrix with width {}", row.len(), self.width);
}
self.data.append(&mut row);
}
pub fn append_column(&mut self, column: Vec<T>) {
let height = self.height();
if column.len() != height {
panic!("Unable to append row with len {} to matrix with width {}", column.len(), height);
}
for (i, e) in column.into_iter().enumerate() {
let insert_at = (i + 1) * self.width + i;
self.data.insert(insert_at, e);
}
self.width += 1;
}
}
impl<T: Num> Index<usize> for Matrix<T> {
@ -175,4 +202,62 @@ mod tests {
assert_eq!(matrix.column(1), vec![2, 5, 8]);
assert_eq!(matrix.column(2), vec![3, 6, 9]);
}
#[test]
fn append_row_and_column() {
let mut matrix = matrix![2;
1, 2,
3, 4
];
matrix.append_row(vec![5, 6]);
assert_eq!(matrix, matrix![2;
1, 2,
3, 4,
5, 6
]);
matrix.append_column(vec![7, 8, 9]);
assert_eq!(matrix, matrix![3;
1, 2, 7,
3, 4, 8,
5, 6, 9
]);
}
#[test]
fn append_row_and_column_zeroes() {
let mut matrix = matrix![2;
1, 2,
3, 4
];
matrix.append_row_zeroes();
assert_eq!(matrix, matrix![2;
1, 2,
3, 4,
0, 0
]);
matrix.append_column_zeroes();
assert_eq!(matrix, matrix![3;
1, 2, 0,
3, 4, 0,
0, 0, 0
]);
}
#[test]
#[should_panic(expected = "Unable to append")]
fn append_row_wrong_width() {
matrix![2;
1, 2,
3, 4
].append_row(vec![1, 2, 3]);
}
#[test]
#[should_panic(expected = "Unable to append")]
fn append_column_wrong_height() {
matrix![2;
1, 2,
3, 4
].append_column(vec![1, 2, 3]);
}
}

View file

@ -1,5 +1,5 @@
<!doctype html>
<html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Mathematical</title>

View file

@ -1,5 +1,18 @@
$bg-color: #2b2927;
$text-color: #e2e19c;
$cell-color: #473b34;
html, 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;
}

View file

@ -1,9 +1,95 @@
use math::matrix::Matrix;
use yew::prelude::*;
pub struct MatrixComponent {
matrix: Matrix<f64>
}
pub enum MatrixMsg {
CellChange(Cell),
AddRow,
AddColumn
}
impl Component for MatrixComponent {
type Message = MatrixMsg;
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self { matrix: Matrix::new_zeroes(3, 3) }
}
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
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()
}
return true;
}
fn view(&self, ctx: &Context<Self>) -> Html {
let on_cell_change = ctx.link().callback(MatrixMsg::CellChange);
html! {
<table> {
self.matrix.iter_rows().enumerate().map(|(i, row)| html! {
<tr> {
row.iter().enumerate().map(|(j, e)| {
let cell = Cell { i, j, value: *e };
html! {
<td>
<MatrixCellComponent cell={cell} on_cell_change={on_cell_change.clone()} />
</td>
}
}).collect::<Html>()
}
</tr>
}).collect::<Html>()
}
</table>
}
}
}
pub struct MatrixCellComponent;
#[derive(PartialEq, Properties)]
pub struct MatrixCellProps {
pub cell: Cell,
pub on_cell_change: Callback<Cell>
}
#[derive(PartialEq, Clone, Copy)]
pub struct Cell {
i: usize, j: usize, value: f64
}
impl Component for MatrixCellComponent {
type Message = ();
type Properties = MatrixCellProps;
fn create(_ctx: &Context<Self>) -> Self {
Self
}
fn view(&self, ctx: &Context<Self>) -> Html {
let cell = ctx.props().cell.clone();
let oninput = ctx.props().on_cell_change
.reform(move |e: InputEvent|
Cell { i: cell.i, j: cell.j, value: e.as_f64().unwrap_or_default() }
);
html! {
<input class="matrix-cell" type="text" {oninput}/>
}
}
}
#[function_component]
fn App() -> Html {
html! {
<p>{"Hello World!"}</p>
<>
<MatrixComponent />
</>
}
}