Fix vector building
This commit is contained in:
parent
d92a6fbdb0
commit
677444b7ff
19
src/calc.rs
19
src/calc.rs
@ -548,14 +548,15 @@ impl Calculator {
|
|||||||
pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> {
|
pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> {
|
||||||
let (count, count_entry) = self.peek_usize()?;
|
let (count, count_entry) = self.peek_usize()?;
|
||||||
let mut entries: Vec<Entry> = (1..=count)
|
let mut entries: Vec<Entry> = (1..=count)
|
||||||
|
.rev()
|
||||||
.map(|i| self.peek(i))
|
.map(|i| self.peek(i))
|
||||||
.collect::<CalculatorResult<Vec<Entry>>>()?;
|
.collect::<CalculatorResult<Vec<Entry>>>()?;
|
||||||
|
|
||||||
let new_entry = Vector::from(&entries)?;
|
let new_entry = Vector::from(&entries)?;
|
||||||
|
|
||||||
entries.splice(1..1, vec![count_entry]);
|
entries.push(count_entry);
|
||||||
Ok(CalculatorStateChange {
|
Ok(CalculatorStateChange {
|
||||||
pop: OpArgs::Variable(Vec::from(entries)),
|
pop: OpArgs::Variable(entries.into_iter().rev().collect::<Vec<Entry>>()),
|
||||||
push: OpArgs::Unary(new_entry),
|
push: OpArgs::Unary(new_entry),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -801,14 +802,10 @@ impl Calculator {
|
|||||||
self.stack.pop_front();
|
self.stack.pop_front();
|
||||||
}
|
}
|
||||||
OpArgs::Variable(entries) => {
|
OpArgs::Variable(entries) => {
|
||||||
if entries
|
entries
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.any(|(i, e)| self.stack_eq(i, e).is_err())
|
.try_for_each(|(i, e)| self.stack_eq(i, e))?;
|
||||||
{
|
|
||||||
// TODO: Return an error if there is one
|
|
||||||
return Err(CalculatorError::ArithmeticError);
|
|
||||||
}
|
|
||||||
|
|
||||||
for _ in 0..entries.len() {
|
for _ in 0..entries.len() {
|
||||||
self.stack.pop_front();
|
self.stack.pop_front();
|
||||||
@ -819,11 +816,11 @@ impl Calculator {
|
|||||||
|
|
||||||
match to_push {
|
match to_push {
|
||||||
OpArgs::Unary(a) => {
|
OpArgs::Unary(a) => {
|
||||||
self.stack.push_front(a.clone()); // TODO: Remove the clones
|
self.stack.push_front(a.clone());
|
||||||
}
|
}
|
||||||
OpArgs::Binary([a, b]) => {
|
OpArgs::Binary([a, b]) => {
|
||||||
self.stack.push_front(b.clone()); // TODO: Remove the clones
|
self.stack.push_front(b.clone());
|
||||||
self.stack.push_front(a.clone()); // TODO: Remove the clones
|
self.stack.push_front(a.clone());
|
||||||
}
|
}
|
||||||
OpArgs::Variable(entries) => {
|
OpArgs::Variable(entries) => {
|
||||||
for e in entries.iter().rev() {
|
for e in entries.iter().rev() {
|
||||||
|
@ -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)]
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
pub struct Vector {
|
pub struct Vector {
|
||||||
pub values: Vec<Number>,
|
pub values: Vec<Number>,
|
||||||
pub direction: VectorDirection,
|
pub direction: VectorDirection,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct MatrixDimensions {
|
||||||
|
rows: usize,
|
||||||
|
columns: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
pub struct Matrix {
|
pub struct Matrix {
|
||||||
pub vectors: Vec<Vector>,
|
pub vectors: Vec<Vector>,
|
||||||
pub dimensions: (usize, usize),
|
pub dimensions: MatrixDimensions,
|
||||||
pub direction: VectorDirection,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
@ -252,11 +264,15 @@ impl CalculatorEntry for Matrix {
|
|||||||
Err(CalculatorError::TypeMismatch)
|
Err(CalculatorError::TypeMismatch)
|
||||||
}
|
}
|
||||||
fn is_valid(&self) -> bool {
|
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
|
&& self
|
||||||
.vectors
|
.vectors
|
||||||
.iter()
|
.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 {
|
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||||
format!(
|
format!(
|
||||||
@ -265,7 +281,7 @@ impl CalculatorEntry for Matrix {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|vector| vector.format_entry(display_mode))
|
.map(|vector| vector.format_entry(display_mode))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join(self.direction.get_separator())
|
.join(" ")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,22 +291,25 @@ impl CalculatorEntry for Matrix {
|
|||||||
}
|
}
|
||||||
fn abs(&self) -> CalculatorResult<Entry> {
|
fn abs(&self) -> CalculatorResult<Entry> {
|
||||||
// TODO: Compute determinant
|
// 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)
|
Err(CalculatorError::NotYetImplemented)
|
||||||
}
|
}
|
||||||
fn inverse(&self) -> CalculatorResult<Entry> {
|
fn inverse(&self) -> CalculatorResult<Entry> {
|
||||||
// TODO: Matrix inverse
|
Err(CalculatorError::NotYetImplemented)
|
||||||
// Ok(Entry::Vector(Self {
|
// TODO: Figure out where to put transpose function.
|
||||||
// vectors: self.vectors.clone(),
|
// 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(),
|
// direction: self.direction.swap(),
|
||||||
// }))
|
// dimensions: self.dimensions,
|
||||||
self.iterated_unary(Vector::inverse)
|
// }
|
||||||
|
// .validate()
|
||||||
}
|
}
|
||||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
self.iterated_unary(|v| v.sin(angle_mode))
|
self.iterated_unary(|v| v.sin(angle_mode))
|
||||||
@ -338,7 +357,32 @@ impl CalculatorEntry for Matrix {
|
|||||||
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
// TODO: Correct implementation
|
// TODO: Correct implementation
|
||||||
match arg {
|
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::Vector(_vector) => Err(CalculatorError::TypeMismatch),
|
||||||
Entry::Number(number) => self.iterated_binary_num(number, Vector::mul),
|
Entry::Number(number) => self.iterated_binary_num(number, Vector::mul),
|
||||||
}
|
}
|
||||||
@ -387,23 +431,30 @@ impl Matrix {
|
|||||||
})
|
})
|
||||||
.collect::<CalculatorResult<Vec<Vector>>>()?;
|
.collect::<CalculatorResult<Vec<Vector>>>()?;
|
||||||
|
|
||||||
// Get the depth of the matrix
|
// Get the num_rows and dimension of the matrix
|
||||||
let depth = vectors
|
let first_vector = vectors
|
||||||
.get(0)
|
.get(0)
|
||||||
.ok_or(CalculatorError::NotEnoughStackEntries)?
|
.ok_or(CalculatorError::NotEnoughStackEntries)?;
|
||||||
.values
|
let num_rows = first_vector.values.len();
|
||||||
.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
|
// One vector has a different length than another
|
||||||
return Err(CalculatorError::DimensionMismatch);
|
return Err(CalculatorError::DimensionMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dimensions: (usize, usize) = (vectors.len(), depth);
|
let dimensions = MatrixDimensions {
|
||||||
|
rows: num_rows,
|
||||||
|
columns: vectors.len(),
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
vectors,
|
vectors,
|
||||||
dimensions,
|
dimensions,
|
||||||
direction: VectorDirection::Row,
|
|
||||||
}
|
}
|
||||||
.validate()
|
.validate()
|
||||||
}
|
}
|
||||||
@ -431,8 +482,7 @@ impl Matrix {
|
|||||||
_ => Err(CalculatorError::ArithmeticError),
|
_ => Err(CalculatorError::ArithmeticError),
|
||||||
})
|
})
|
||||||
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
||||||
direction: self.direction,
|
dimensions: self.dimensions.clone(),
|
||||||
dimensions: self.dimensions,
|
|
||||||
}
|
}
|
||||||
.validate()
|
.validate()
|
||||||
}
|
}
|
||||||
@ -452,8 +502,7 @@ impl Matrix {
|
|||||||
_ => Err(CalculatorError::ArithmeticError),
|
_ => Err(CalculatorError::ArithmeticError),
|
||||||
})
|
})
|
||||||
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
||||||
direction: self.direction,
|
dimensions: self.dimensions.clone(),
|
||||||
dimensions: self.dimensions,
|
|
||||||
}
|
}
|
||||||
.validate()
|
.validate()
|
||||||
}
|
}
|
||||||
@ -463,7 +512,7 @@ impl Matrix {
|
|||||||
m2: &Self,
|
m2: &Self,
|
||||||
op: impl Fn(&Vector, &Entry) -> CalculatorResult<Entry>,
|
op: impl Fn(&Vector, &Entry) -> CalculatorResult<Entry>,
|
||||||
) -> CalculatorResult<Entry> {
|
) -> CalculatorResult<Entry> {
|
||||||
if self.dimensions != m2.dimensions && self.direction != m2.direction {
|
if self.dimensions != m2.dimensions {
|
||||||
return Err(CalculatorError::DimensionMismatch);
|
return Err(CalculatorError::DimensionMismatch);
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
@ -477,8 +526,7 @@ impl Matrix {
|
|||||||
_ => Err(CalculatorError::ArithmeticError),
|
_ => Err(CalculatorError::ArithmeticError),
|
||||||
})
|
})
|
||||||
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
||||||
direction: self.direction,
|
dimensions: self.dimensions.clone(),
|
||||||
dimensions: self.dimensions,
|
|
||||||
}
|
}
|
||||||
.validate()
|
.validate()
|
||||||
}
|
}
|
||||||
@ -517,6 +565,7 @@ impl CalculatorEntry for Vector {
|
|||||||
value.sqrt()
|
value.sqrt()
|
||||||
}
|
}
|
||||||
fn inverse(&self) -> CalculatorResult<Entry> {
|
fn inverse(&self) -> CalculatorResult<Entry> {
|
||||||
|
// TODO: Correct implementation of this. This is the transpose
|
||||||
Ok(Entry::Vector(Self {
|
Ok(Entry::Vector(Self {
|
||||||
values: self.values.clone(),
|
values: self.values.clone(),
|
||||||
direction: self.direction.swap(),
|
direction: self.direction.swap(),
|
||||||
@ -629,17 +678,25 @@ impl Vector {
|
|||||||
if entries.len() == 0 {
|
if entries.len() == 0 {
|
||||||
return Err(CalculatorError::NotEnoughStackEntries);
|
return Err(CalculatorError::NotEnoughStackEntries);
|
||||||
}
|
}
|
||||||
Ok(Entry::Vector(Self {
|
Self {
|
||||||
values: entries
|
values: entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| match e {
|
.map(|e| match e {
|
||||||
Entry::Matrix(_) => Err(CalculatorError::TypeMismatch),
|
Entry::Matrix(_) | Entry::Vector(_) => Err(CalculatorError::TypeMismatch),
|
||||||
Entry::Vector(_) => Err(CalculatorError::TypeMismatch),
|
|
||||||
Entry::Number(number) => Ok(number.clone()),
|
Entry::Number(number) => Ok(number.clone()),
|
||||||
})
|
})
|
||||||
.collect::<CalculatorResult<Vec<Number>>>()?,
|
.collect::<CalculatorResult<Vec<Number>>>()?,
|
||||||
direction: VectorDirection::Row,
|
direction: VectorDirection::default(),
|
||||||
})) //.validate() <- TODO
|
}
|
||||||
|
.validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(self) -> CalculatorResult<Entry> {
|
||||||
|
if self.is_valid() {
|
||||||
|
Ok(Entry::Vector(self))
|
||||||
|
} else {
|
||||||
|
Err(CalculatorError::ArithmeticError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iterated_unary(
|
fn iterated_unary(
|
||||||
@ -928,8 +985,7 @@ impl Number {
|
|||||||
_ => Err(CalculatorError::ArithmeticError),
|
_ => Err(CalculatorError::ArithmeticError),
|
||||||
})
|
})
|
||||||
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
||||||
direction: matrix.direction,
|
dimensions: matrix.dimensions.clone(),
|
||||||
dimensions: matrix.dimensions,
|
|
||||||
}
|
}
|
||||||
.validate()
|
.validate()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user