From b5e944e82ca96c742c357084fd3e291862ef7419 Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Fri, 4 Jun 2021 22:54:32 -0400 Subject: [PATCH] Fix more bugs --- src/calc.rs | 2 +- src/calc/entries.rs | 120 ++++++++++++++++++++++++++------------------ src/calc/errors.rs | 5 ++ 3 files changed, 77 insertions(+), 50 deletions(-) diff --git a/src/calc.rs b/src/calc.rs index 3e8aa39..444de3a 100644 --- a/src/calc.rs +++ b/src/calc.rs @@ -570,7 +570,7 @@ impl Calculator { .map(|i| self.peek(i)) .collect::>>()?; - let new_entry = Matrix::from(&entries)?; + let new_entry = Matrix::from(&entries[..])?; entries.push(count_entry); Ok(CalculatorStateChange { diff --git a/src/calc/entries.rs b/src/calc/entries.rs index 5c0d9ca..3bf97d2 100644 --- a/src/calc/entries.rs +++ b/src/calc/entries.rs @@ -7,6 +7,42 @@ use serde::{Deserialize, Serialize}; use std::cmp::PartialEq; use std::fmt; +pub trait CalculatorEntry +where + Self: Sized, +{ + // Misc + fn is_valid(&self) -> bool; + /// Turns self into a valid entry + fn validate(self) -> CalculatorResult; + fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String; + fn to_editable_string(&self) -> CalculatorResult; + // Mathematical operations + // Unary + fn negate(&self) -> CalculatorResult; + fn abs(&self) -> CalculatorResult; + fn inverse(&self) -> CalculatorResult; + fn transpose(&self) -> CalculatorResult; + fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; + fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; + fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; + fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; + fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; + fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; + fn sqrt(&self) -> CalculatorResult; + fn log(&self) -> CalculatorResult; + fn ln(&self) -> CalculatorResult; + + // Binary + fn add(&self, arg: &Entry) -> CalculatorResult; + fn sub(&self, arg: &Entry) -> CalculatorResult; + fn mul(&self, arg: &Entry) -> CalculatorResult; + fn div(&self, arg: &Entry) -> CalculatorResult; + fn int_divide(&self, arg: &Entry) -> CalculatorResult; + fn modulo(&self, arg: &Entry) -> CalculatorResult; + fn pow(&self, arg: &Entry) -> CalculatorResult; +} + #[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub struct Number { pub value: f64, @@ -397,7 +433,6 @@ impl CalculatorEntry for Matrix { } } fn mul(&self, arg: &Entry) -> CalculatorResult { - // TODO: Correct implementation match arg { Entry::Matrix(m2) => { if self.dimensions.columns != m2.dimensions.rows { @@ -409,15 +444,35 @@ impl CalculatorEntry for Matrix { }; // 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] + let transposed_self: Self = match self.transpose()? { + Entry::Matrix(t) => t, + _ => { + return Err(CalculatorError::InternalError(String::from( + "Matrix transpose produced wrong type", + ))) + } + }; - // TODO - let vectors = vec![]; + let mut vectors: Vec = vec![]; + + for c in &m2.vectors { + let mut vector: Vector = Vector { + values: vec![], + direction: VectorDirection::Column, + }; + for r in &transposed_self.vectors { + if let Entry::Number(number) = + c.transpose()?.mul(&Entry::Vector(r.clone()))? + { + vector.values.push(number); + } else { + return Err(CalculatorError::InternalError(String::from( + "Vector multiplication did not produce a number", + ))); + } + } + vectors.push(vector); + } Self { vectors, @@ -425,7 +480,9 @@ impl CalculatorEntry for Matrix { } .validate() } - Entry::Vector(_vector) => Err(CalculatorError::TypeMismatch), + Entry::Vector(vector) => self.mul(&Self::from( + &[Entry::Vector(vector.clone())], // Treat a vector as a 1D matrix + )?), Entry::Number(number) => self.iterated_binary_num(number, Vector::mul), } } @@ -669,8 +726,7 @@ impl CalculatorEntry for Vector { } fn mul(&self, arg: &Entry) -> CalculatorResult { match arg { - // TODO: Matrix multiplication should be allowed - Entry::Matrix(_) => Err(CalculatorError::TypeMismatch), + Entry::Matrix(_matrix) => Matrix::from(&[Entry::Vector(self.clone())])?.mul(arg), Entry::Vector(v2) => { if self.values.len() != v2.values.len() { return Err(CalculatorError::DimensionMismatch); @@ -686,7 +742,9 @@ impl CalculatorEntry for Vector { }) } (VectorDirection::Column, VectorDirection::Row) => { - Err(CalculatorError::NotYetImplemented) + // TODO: Do we need to clone? + Matrix::from(&[Entry::Vector(self.clone())])? + .mul(&Matrix::from(&[arg.clone()])?) } (VectorDirection::Row, VectorDirection::Row) | (VectorDirection::Column, VectorDirection::Column) => { @@ -1041,42 +1099,6 @@ impl Number { } } -pub trait CalculatorEntry -where - Self: Sized, -{ - // Misc - fn is_valid(&self) -> bool; - /// Turns self into a valid entry - fn validate(self) -> CalculatorResult; - fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String; - fn to_editable_string(&self) -> CalculatorResult; - // Mathematical operations - // Unary - fn negate(&self) -> CalculatorResult; - fn abs(&self) -> CalculatorResult; - fn inverse(&self) -> CalculatorResult; - fn transpose(&self) -> CalculatorResult; - fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; - fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; - fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; - fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; - fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; - fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult; - fn sqrt(&self) -> CalculatorResult; - fn log(&self) -> CalculatorResult; - fn ln(&self) -> CalculatorResult; - - // Binary - fn add(&self, arg: &Entry) -> CalculatorResult; - fn sub(&self, arg: &Entry) -> CalculatorResult; - fn mul(&self, arg: &Entry) -> CalculatorResult; - fn div(&self, arg: &Entry) -> CalculatorResult; - fn int_divide(&self, arg: &Entry) -> CalculatorResult; - fn modulo(&self, arg: &Entry) -> CalculatorResult; - fn pow(&self, arg: &Entry) -> CalculatorResult; -} - impl fmt::Display for Entry { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { diff --git a/src/calc/errors.rs b/src/calc/errors.rs index 9a07c5e..0414074 100644 --- a/src/calc/errors.rs +++ b/src/calc/errors.rs @@ -17,6 +17,8 @@ pub enum CalculatorError { DimensionMismatch, /// Plans are in place to implement, but we are not there yet NotYetImplemented, + /// Internal computation error + InternalError(String), /// Thrown when an undo or redo cannot be performed CorruptStateChange(String), /// Cannot undo or redo @@ -53,6 +55,9 @@ impl fmt::Display for CalculatorError { Self::TypeMismatch => write!(f, "Type mismatch"), Self::DimensionMismatch => write!(f, "Dimension mismatch"), Self::NotYetImplemented => write!(f, "Not yet implemented"), + Self::InternalError(msg) => { + write!(f, "Internal error: {}", msg) + } Self::CorruptStateChange(msg) => { write!(f, "Corrupt state change: {}", msg) }