Fix vector building

This commit is contained in:
Austen Adler 2021-06-03 22:26:28 -04:00
parent d92a6fbdb0
commit 677444b7ff
2 changed files with 104 additions and 51 deletions

View File

@ -548,14 +548,15 @@ impl Calculator {
pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> {
let (count, count_entry) = self.peek_usize()?;
let mut entries: Vec<Entry> = (1..=count)
.rev()
.map(|i| self.peek(i))
.collect::<CalculatorResult<Vec<Entry>>>()?;
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::<Vec<Entry>>()),
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() {

View File

@ -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<Number>,
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<Vector>,
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::<Vec<String>>()
.join(self.direction.get_separator())
.join(" ")
)
}
@ -275,22 +291,25 @@ impl CalculatorEntry for Matrix {
}
fn abs(&self) -> CalculatorResult<Entry> {
// 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<Entry> {
// 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::<CalculatorResult<Vec<Vector>>>()?,
// direction: self.direction.swap(),
// }))
self.iterated_unary(Vector::inverse)
// dimensions: self.dimensions,
// }
// .validate()
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
self.iterated_unary(|v| v.sin(angle_mode))
@ -338,7 +357,32 @@ impl CalculatorEntry for Matrix {
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
// 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::<CalculatorResult<Vec<Vector>>>()?;
// 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::<CalculatorResult<Vec<Vector>>>()?,
direction: self.direction,
dimensions: self.dimensions,
dimensions: self.dimensions.clone(),
}
.validate()
}
@ -452,8 +502,7 @@ impl Matrix {
_ => Err(CalculatorError::ArithmeticError),
})
.collect::<CalculatorResult<Vec<Vector>>>()?,
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<Entry>,
) -> CalculatorResult<Entry> {
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::<CalculatorResult<Vec<Vector>>>()?,
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<Entry> {
// 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::<CalculatorResult<Vec<Number>>>()?,
direction: VectorDirection::Row,
})) //.validate() <- TODO
direction: VectorDirection::default(),
}
.validate()
}
fn validate(self) -> CalculatorResult<Entry> {
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::<CalculatorResult<Vec<Vector>>>()?,
direction: matrix.direction,
dimensions: matrix.dimensions,
dimensions: matrix.dimensions.clone(),
}
.validate()
}