Fix more bugs

This commit is contained in:
Austen Adler 2021-06-04 22:54:32 -04:00
parent 456dc6dcd4
commit b5e944e82c
3 changed files with 77 additions and 50 deletions

View File

@ -570,7 +570,7 @@ impl Calculator {
.map(|i| self.peek(i)) .map(|i| self.peek(i))
.collect::<CalculatorResult<Vec<Entry>>>()?; .collect::<CalculatorResult<Vec<Entry>>>()?;
let new_entry = Matrix::from(&entries)?; let new_entry = Matrix::from(&entries[..])?;
entries.push(count_entry); entries.push(count_entry);
Ok(CalculatorStateChange { Ok(CalculatorStateChange {

View File

@ -7,6 +7,42 @@ use serde::{Deserialize, Serialize};
use std::cmp::PartialEq; use std::cmp::PartialEq;
use std::fmt; 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<Entry>;
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String;
fn to_editable_string(&self) -> CalculatorResult<String>;
// Mathematical operations
// Unary
fn negate(&self) -> CalculatorResult<Entry>;
fn abs(&self) -> CalculatorResult<Entry>;
fn inverse(&self) -> CalculatorResult<Entry>;
fn transpose(&self) -> CalculatorResult<Entry>;
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn sqrt(&self) -> CalculatorResult<Entry>;
fn log(&self) -> CalculatorResult<Entry>;
fn ln(&self) -> CalculatorResult<Entry>;
// Binary
fn add(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn div(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry>;
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct Number { pub struct Number {
pub value: f64, pub value: f64,
@ -397,7 +433,6 @@ impl CalculatorEntry for Matrix {
} }
} }
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> { fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
// TODO: Correct implementation
match arg { match arg {
Entry::Matrix(m2) => { Entry::Matrix(m2) => {
if self.dimensions.columns != m2.dimensions.rows { 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 // A matrix is a list of column vectors, so transpose self and zip the columns
// let transposed_self = self.transpose()?; let transposed_self: Self = match self.transpose()? {
// for i in dimensions.rows { Entry::Matrix(t) => t,
// for j in dimensions.columns { _ => {
// } return Err(CalculatorError::InternalError(String::from(
// } "Matrix transpose produced wrong type",
// self.vectors[0] )))
}
};
// TODO let mut vectors: Vec<Vector> = vec![];
let vectors = 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 { Self {
vectors, vectors,
@ -425,7 +480,9 @@ impl CalculatorEntry for Matrix {
} }
.validate() .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), Entry::Number(number) => self.iterated_binary_num(number, Vector::mul),
} }
} }
@ -669,8 +726,7 @@ impl CalculatorEntry for Vector {
} }
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> { fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg { match arg {
// TODO: Matrix multiplication should be allowed Entry::Matrix(_matrix) => Matrix::from(&[Entry::Vector(self.clone())])?.mul(arg),
Entry::Matrix(_) => Err(CalculatorError::TypeMismatch),
Entry::Vector(v2) => { Entry::Vector(v2) => {
if self.values.len() != v2.values.len() { if self.values.len() != v2.values.len() {
return Err(CalculatorError::DimensionMismatch); return Err(CalculatorError::DimensionMismatch);
@ -686,7 +742,9 @@ impl CalculatorEntry for Vector {
}) })
} }
(VectorDirection::Column, VectorDirection::Row) => { (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::Row, VectorDirection::Row)
| (VectorDirection::Column, VectorDirection::Column) => { | (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<Entry>;
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String;
fn to_editable_string(&self) -> CalculatorResult<String>;
// Mathematical operations
// Unary
fn negate(&self) -> CalculatorResult<Entry>;
fn abs(&self) -> CalculatorResult<Entry>;
fn inverse(&self) -> CalculatorResult<Entry>;
fn transpose(&self) -> CalculatorResult<Entry>;
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn sqrt(&self) -> CalculatorResult<Entry>;
fn log(&self) -> CalculatorResult<Entry>;
fn ln(&self) -> CalculatorResult<Entry>;
// Binary
fn add(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn div(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry>;
}
impl fmt::Display for Entry { impl fmt::Display for Entry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {

View File

@ -17,6 +17,8 @@ pub enum CalculatorError {
DimensionMismatch, DimensionMismatch,
/// Plans are in place to implement, but we are not there yet /// Plans are in place to implement, but we are not there yet
NotYetImplemented, NotYetImplemented,
/// Internal computation error
InternalError(String),
/// Thrown when an undo or redo cannot be performed /// Thrown when an undo or redo cannot be performed
CorruptStateChange(String), CorruptStateChange(String),
/// Cannot undo or redo /// Cannot undo or redo
@ -53,6 +55,9 @@ impl fmt::Display for CalculatorError {
Self::TypeMismatch => write!(f, "Type mismatch"), Self::TypeMismatch => write!(f, "Type mismatch"),
Self::DimensionMismatch => write!(f, "Dimension mismatch"), Self::DimensionMismatch => write!(f, "Dimension mismatch"),
Self::NotYetImplemented => write!(f, "Not yet implemented"), Self::NotYetImplemented => write!(f, "Not yet implemented"),
Self::InternalError(msg) => {
write!(f, "Internal error: {}", msg)
}
Self::CorruptStateChange(msg) => { Self::CorruptStateChange(msg) => {
write!(f, "Corrupt state change: {}", msg) write!(f, "Corrupt state change: {}", msg)
} }