diff --git a/src/calc.rs b/src/calc.rs index 49847da..ad2d671 100644 --- a/src/calc.rs +++ b/src/calc.rs @@ -548,14 +548,15 @@ impl Calculator { pub fn build_vector(&mut self) -> CalculatorResult { let (count, count_entry) = self.peek_usize()?; let mut entries: Vec = (1..=count) + .rev() .map(|i| self.peek(i)) .collect::>>()?; let new_entry = Vector::from(&entries)?; - entries.splice(1..1, vec![count_entry]); + entries.push(count_entry); Ok(CalculatorStateChange { - pop: OpArgs::Variable(Vec::from(entries)), + pop: OpArgs::Variable(entries.into_iter().rev().collect::>()), push: OpArgs::Unary(new_entry), }) } @@ -801,14 +802,10 @@ impl Calculator { self.stack.pop_front(); } OpArgs::Variable(entries) => { - if entries + entries .iter() .enumerate() - .any(|(i, e)| self.stack_eq(i, e).is_err()) - { - // TODO: Return an error if there is one - return Err(CalculatorError::ArithmeticError); - } + .try_for_each(|(i, e)| self.stack_eq(i, e))?; for _ in 0..entries.len() { self.stack.pop_front(); @@ -819,11 +816,11 @@ impl Calculator { match to_push { OpArgs::Unary(a) => { - self.stack.push_front(a.clone()); // TODO: Remove the clones + self.stack.push_front(a.clone()); } OpArgs::Binary([a, b]) => { - self.stack.push_front(b.clone()); // TODO: Remove the clones - self.stack.push_front(a.clone()); // TODO: Remove the clones + self.stack.push_front(b.clone()); + self.stack.push_front(a.clone()); } OpArgs::Variable(entries) => { for e in entries.iter().rev() { diff --git a/src/calc/entries.rs b/src/calc/entries.rs index 88209cc..b6dbbb6 100644 --- a/src/calc/entries.rs +++ b/src/calc/entries.rs @@ -52,17 +52,29 @@ impl VectorDirection { } } +impl Default for VectorDirection { + fn default() -> Self { + // Column vectors are the default + Self::Column + } +} + #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct Vector { pub values: Vec, pub direction: VectorDirection, } +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct MatrixDimensions { + rows: usize, + columns: usize, +} + #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct Matrix { pub vectors: Vec, - pub dimensions: (usize, usize), - pub direction: VectorDirection, + pub dimensions: MatrixDimensions, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] @@ -252,11 +264,15 @@ impl CalculatorEntry for Matrix { Err(CalculatorError::TypeMismatch) } fn is_valid(&self) -> bool { - self.vectors.len() == self.dimensions.0 + // The the number of vectors is equal to the 0th dimension + self.vectors.len() == self.dimensions.columns + // The number of elements in all vectors are equal to the 1st dimension, and each is valid && self .vectors .iter() - .all(|v| v.values.len() == self.dimensions.1 && v.is_valid()) + .all(|v| v.values.len() == self.dimensions.rows && v.is_valid()) + // The dimensions are not zero + && self.dimensions.rows > 0 && self.dimensions.columns > 0 } fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String { format!( @@ -265,7 +281,7 @@ impl CalculatorEntry for Matrix { .iter() .map(|vector| vector.format_entry(display_mode)) .collect::>() - .join(self.direction.get_separator()) + .join(" ") ) } @@ -275,22 +291,25 @@ impl CalculatorEntry for Matrix { } fn abs(&self) -> CalculatorResult { // TODO: Compute determinant - // let value: Entry = self - // .vectors - // .iter() - // .try_fold(Entry::Number(Vector::ZERO), |acc, vector| { - // acc.add(&vector.abs()?) - // })?; - // value.sqrt() Err(CalculatorError::NotYetImplemented) } fn inverse(&self) -> CalculatorResult { - // TODO: Matrix inverse - // Ok(Entry::Vector(Self { - // vectors: self.vectors.clone(), + Err(CalculatorError::NotYetImplemented) + // TODO: Figure out where to put transpose function. + // Self { + // vectors: self + // .vectors + // .iter() + // .map(|v| v.inverse()) + // .map(|e| match e { + // Ok(Entry::Vector(vector)) => Ok(vector), + // _ => Err(CalculatorError::ArithmeticError), + // }) + // .collect::>>()?, // direction: self.direction.swap(), - // })) - self.iterated_unary(Vector::inverse) + // dimensions: self.dimensions, + // } + // .validate() } fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult { self.iterated_unary(|v| v.sin(angle_mode)) @@ -338,7 +357,32 @@ impl CalculatorEntry for Matrix { fn mul(&self, arg: &Entry) -> CalculatorResult { // TODO: Correct implementation match arg { - Entry::Matrix(m2) => self.iterated_binary_mat(m2, Vector::mul), + Entry::Matrix(m2) => { + if self.dimensions.columns != m2.dimensions.rows { + return Err(CalculatorError::DimensionMismatch); + } + let dimensions = MatrixDimensions { + rows: self.dimensions.rows, + columns: m2.dimensions.columns, + }; + + // A matrix is a list of column vectors, so transpose self and zip the columns + // let transposed_self = self.transpose()?; + // for i in dimensions.rows { + // for j in dimensions.columns { + // } + // } + // self.vectors[0] + + // TODO + let vectors = vec![]; + + Self { + vectors, + dimensions, + } + .validate() + } Entry::Vector(_vector) => Err(CalculatorError::TypeMismatch), Entry::Number(number) => self.iterated_binary_num(number, Vector::mul), } @@ -387,23 +431,30 @@ impl Matrix { }) .collect::>>()?; - // Get the depth of the matrix - let depth = vectors + // Get the num_rows and dimension of the matrix + let first_vector = vectors .get(0) - .ok_or(CalculatorError::NotEnoughStackEntries)? - .values - .len(); + .ok_or(CalculatorError::NotEnoughStackEntries)?; + let num_rows = first_vector.values.len(); + let vector_direction = first_vector.direction; - if vectors.iter().any(|v| v.values.len() != depth) { + // TODO: Only build a matrix for column vectors; transpose if they are row vectors + + if vectors + .iter() + .any(|v| v.values.len() != num_rows || v.direction != vector_direction) + { // One vector has a different length than another return Err(CalculatorError::DimensionMismatch); } - let dimensions: (usize, usize) = (vectors.len(), depth); + let dimensions = MatrixDimensions { + rows: num_rows, + columns: vectors.len(), + }; Self { vectors, dimensions, - direction: VectorDirection::Row, } .validate() } @@ -431,8 +482,7 @@ impl Matrix { _ => Err(CalculatorError::ArithmeticError), }) .collect::>>()?, - direction: self.direction, - dimensions: self.dimensions, + dimensions: self.dimensions.clone(), } .validate() } @@ -452,8 +502,7 @@ impl Matrix { _ => Err(CalculatorError::ArithmeticError), }) .collect::>>()?, - direction: self.direction, - dimensions: self.dimensions, + dimensions: self.dimensions.clone(), } .validate() } @@ -463,7 +512,7 @@ impl Matrix { m2: &Self, op: impl Fn(&Vector, &Entry) -> CalculatorResult, ) -> CalculatorResult { - if self.dimensions != m2.dimensions && self.direction != m2.direction { + if self.dimensions != m2.dimensions { return Err(CalculatorError::DimensionMismatch); } Self { @@ -477,8 +526,7 @@ impl Matrix { _ => Err(CalculatorError::ArithmeticError), }) .collect::>>()?, - direction: self.direction, - dimensions: self.dimensions, + dimensions: self.dimensions.clone(), } .validate() } @@ -517,6 +565,7 @@ impl CalculatorEntry for Vector { value.sqrt() } fn inverse(&self) -> CalculatorResult { + // TODO: Correct implementation of this. This is the transpose Ok(Entry::Vector(Self { values: self.values.clone(), direction: self.direction.swap(), @@ -629,17 +678,25 @@ impl Vector { if entries.len() == 0 { return Err(CalculatorError::NotEnoughStackEntries); } - Ok(Entry::Vector(Self { + Self { values: entries .iter() .map(|e| match e { - Entry::Matrix(_) => Err(CalculatorError::TypeMismatch), - Entry::Vector(_) => Err(CalculatorError::TypeMismatch), + Entry::Matrix(_) | Entry::Vector(_) => Err(CalculatorError::TypeMismatch), Entry::Number(number) => Ok(number.clone()), }) .collect::>>()?, - direction: VectorDirection::Row, - })) //.validate() <- TODO + direction: VectorDirection::default(), + } + .validate() + } + + fn validate(self) -> CalculatorResult { + if self.is_valid() { + Ok(Entry::Vector(self)) + } else { + Err(CalculatorError::ArithmeticError) + } } fn iterated_unary( @@ -928,8 +985,7 @@ impl Number { _ => Err(CalculatorError::ArithmeticError), }) .collect::>>()?, - direction: matrix.direction, - dimensions: matrix.dimensions, + dimensions: matrix.dimensions.clone(), } .validate() }