Working vector and matrix; fix clippy warnings

This commit is contained in:
Austen Adler 2021-06-03 23:38:52 -04:00
parent f80011652b
commit 456dc6dcd4
4 changed files with 91 additions and 37 deletions

View File

@ -58,7 +58,7 @@ asciidoctor REAMDE.adoc
If you have not done this before, open the calculator and press `<ctrl+s>` to save the basic config. If you have not done this before, open the calculator and press `<ctrl+s>` to save the basic config.
Edit the config file (in Linux, edit `~/.config/rpn_rs/rpn_rs.toml` and add any constants or macros and press `<ctrl+l>` or reopen the calculator. Edit the config file (in Linux, edit `~/.config/rpn_rs/rpn_rs.yaml` and add any constants or macros and press `<ctrl+l>` or reopen the calculator.
Sample Macros: Sample Macros:

View File

@ -280,6 +280,7 @@ impl Calculator {
'V' => self.op(CalculatorOperation::BuildVector), 'V' => self.op(CalculatorOperation::BuildVector),
'M' => self.op(CalculatorOperation::BuildMatrix), 'M' => self.op(CalculatorOperation::BuildMatrix),
'_' => self.op(CalculatorOperation::Deconstruct), '_' => self.op(CalculatorOperation::Deconstruct),
')' => self.op(CalculatorOperation::Transpose),
// Special // Special
'\\' => self.op(CalculatorOperation::Drop), '\\' => self.op(CalculatorOperation::Drop),
' ' => self.op(CalculatorOperation::Dup), ' ' => self.op(CalculatorOperation::Dup),
@ -517,8 +518,7 @@ impl Calculator {
pub fn peek_usize(&mut self) -> CalculatorResult<(usize, Entry)> { pub fn peek_usize(&mut self) -> CalculatorResult<(usize, Entry)> {
let entry = self.peek(0)?; let entry = self.peek(0)?;
let f = match entry { let f = match entry {
Entry::Matrix(_) => return Err(CalculatorError::TypeMismatch), Entry::Matrix(_) | Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
Entry::Number(Number { value }) => value, Entry::Number(Number { value }) => value,
}; };
// Ensure this can be cast to a usize // Ensure this can be cast to a usize
@ -547,6 +547,7 @@ 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()?;
// The arguments need to be reversed since 1 2 3 3V should produce a vector [1;2;3], not [3;2;1]
let mut entries: Vec<Entry> = (1..=count) let mut entries: Vec<Entry> = (1..=count)
.rev() .rev()
.map(|i| self.peek(i)) .map(|i| self.peek(i))
@ -556,21 +557,25 @@ impl Calculator {
entries.push(count_entry); entries.push(count_entry);
Ok(CalculatorStateChange { Ok(CalculatorStateChange {
// Since we reversed the arguments once, we need to reverse again
pop: OpArgs::Variable(entries.into_iter().rev().collect::<Vec<Entry>>()), pop: OpArgs::Variable(entries.into_iter().rev().collect::<Vec<Entry>>()),
push: OpArgs::Unary(new_entry), push: OpArgs::Unary(new_entry),
}) })
} }
pub fn build_matrix(&mut self) -> CalculatorResult<CalculatorStateChange> { pub fn build_matrix(&mut self) -> CalculatorResult<CalculatorStateChange> {
let (count, count_entry) = self.peek_usize()?; let (count, count_entry) = self.peek_usize()?;
// The arguments need to be reversed, see build_vector
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 = Matrix::from(&entries)?; let new_entry = Matrix::from(&entries)?;
entries.splice(1..1, vec![count_entry]); entries.push(count_entry);
Ok(CalculatorStateChange { Ok(CalculatorStateChange {
pop: OpArgs::Variable(Vec::from(entries)), // Since we reversed the arguments once, we need to reverse again
pop: OpArgs::Variable(entries.into_iter().rev().collect::<Vec<Entry>>()),
push: OpArgs::Unary(new_entry), push: OpArgs::Unary(new_entry),
}) })
} }
@ -580,12 +585,14 @@ impl Calculator {
Entry::Matrix(matrix) => Ok(matrix Entry::Matrix(matrix) => Ok(matrix
.vectors .vectors
.iter() .iter()
.rev()
.map(|v| Entry::Vector(v.clone())) .map(|v| Entry::Vector(v.clone()))
.collect()), .collect()),
Entry::Vector(vector) => Ok(vector Entry::Vector(vector) => Ok(vector
.values .values
.iter() .iter()
.map(|n| Entry::Number(n.clone())) .rev()
.map(|n| Entry::Number(*n))
.collect()), .collect()),
Entry::Number(_number) => Err(CalculatorError::TypeMismatch), Entry::Number(_number) => Err(CalculatorError::TypeMismatch),
}?; }?;
@ -671,6 +678,7 @@ impl Calculator {
CalculatorOperation::BuildVector => self.build_vector(), CalculatorOperation::BuildVector => self.build_vector(),
CalculatorOperation::BuildMatrix => self.build_matrix(), CalculatorOperation::BuildMatrix => self.build_matrix(),
CalculatorOperation::Deconstruct => self.deconstruct(), CalculatorOperation::Deconstruct => self.deconstruct(),
CalculatorOperation::Transpose => self.unary_op(|a| Ok(OpArgs::Unary(a.transpose()?))),
CalculatorOperation::Dup => self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a]))), CalculatorOperation::Dup => self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a]))),
CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)), CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)),
CalculatorOperation::Swap => self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a]))), CalculatorOperation::Swap => self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a]))),

View File

@ -71,6 +71,15 @@ pub struct MatrixDimensions {
columns: usize, columns: usize,
} }
impl MatrixDimensions {
pub const fn transpose(&self) -> Self {
Self {
rows: self.columns,
columns: self.rows,
}
}
}
#[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>,
@ -150,6 +159,13 @@ impl CalculatorEntry for Entry {
Self::Matrix(matrix) => matrix.inverse(), Self::Matrix(matrix) => matrix.inverse(),
} }
} }
fn transpose(&self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.transpose(),
Self::Vector(vector) => vector.transpose(),
Self::Matrix(matrix) => matrix.transpose(),
}
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> { fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
match self { match self {
Self::Number(number) => number.sin(angle_mode), Self::Number(number) => number.sin(angle_mode),
@ -309,22 +325,33 @@ impl CalculatorEntry for Matrix {
Err(CalculatorError::NotYetImplemented) Err(CalculatorError::NotYetImplemented)
} }
fn inverse(&self) -> CalculatorResult<Entry> { fn inverse(&self) -> CalculatorResult<Entry> {
// TODO: Inverse
Err(CalculatorError::NotYetImplemented) Err(CalculatorError::NotYetImplemented)
// TODO: Figure out where to put transpose function. }
// Self { fn transpose(&self) -> CalculatorResult<Entry> {
// vectors: self // Iterate over all rows
// .vectors let mut vectors: Vec<Vector> = vec![];
// .iter() for r in 0..self.dimensions.rows {
// .map(|v| v.inverse()) vectors.push(Vector {
// .map(|e| match e { values: self
// Ok(Entry::Vector(vector)) => Ok(vector), .vectors
// _ => Err(CalculatorError::ArithmeticError), .iter()
// }) .map(|v| {
// .collect::<CalculatorResult<Vec<Vector>>>()?, // For each row, get the r'th element to build a new vector
// direction: self.direction.swap(), v.values
// dimensions: self.dimensions, .get(r)
// } .map_or_else(|| Err(CalculatorError::DimensionMismatch), |n| Ok(*n))
// .validate() })
.collect::<CalculatorResult<Vec<Number>>>()?,
direction: VectorDirection::Column,
});
}
Self {
vectors,
dimensions: self.dimensions.transpose(),
}
.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))
@ -433,8 +460,8 @@ impl CalculatorEntry for Matrix {
} }
impl Matrix { impl Matrix {
pub fn from(entries: &Vec<Entry>) -> CalculatorResult<Entry> { pub fn from(entries: &[Entry]) -> CalculatorResult<Entry> {
if entries.len() == 0 { if entries.is_empty() {
return Err(CalculatorError::NotEnoughStackEntries); return Err(CalculatorError::NotEnoughStackEntries);
} }
@ -450,16 +477,16 @@ impl Matrix {
let first_vector = vectors let first_vector = vectors
.get(0) .get(0)
.ok_or(CalculatorError::NotEnoughStackEntries)?; .ok_or(CalculatorError::NotEnoughStackEntries)?;
// The number of rows in this column-based matrix
let num_rows = first_vector.values.len(); let num_rows = first_vector.values.len();
// The direction all vectors must face
let vector_direction = first_vector.direction; let vector_direction = first_vector.direction;
// TODO: Only build a matrix for column vectors; transpose if they are row vectors // Either the dimension lengths mismatch, or the vectors are facing different directions (and are longer than 1, since a 1-length vector orientation does not matter
if vectors.iter().any(|v| v.values.len() != num_rows)
if vectors || (num_rows > 1 && vectors.iter().any(|v| v.direction != vector_direction))
.iter()
.any(|v| v.values.len() != num_rows || v.direction != vector_direction)
{ {
// One vector has a different length than another
return Err(CalculatorError::DimensionMismatch); return Err(CalculatorError::DimensionMismatch);
} }
@ -467,11 +494,18 @@ impl Matrix {
rows: num_rows, rows: num_rows,
columns: vectors.len(), columns: vectors.len(),
}; };
Self {
let ret = Self {
vectors, vectors,
dimensions, dimensions,
};
// If the user tried making a matrix out of row vectors, we need to transpose it, which forces column vectors
if vector_direction == VectorDirection::Row && num_rows > 1 {
ret.transpose()
} else {
ret.validate()
} }
.validate()
} }
fn iterated_unary( fn iterated_unary(
@ -585,6 +619,12 @@ impl CalculatorEntry for Vector {
direction: self.direction.swap(), direction: self.direction.swap(),
})) }))
} }
fn transpose(&self) -> CalculatorResult<Entry> {
Ok(Entry::Vector(Self {
values: self.values.clone(),
direction: self.direction.swap(),
}))
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
self.iterated_unary(|n| n.sin(angle_mode)) self.iterated_unary(|n| n.sin(angle_mode))
} }
@ -688,8 +728,8 @@ impl CalculatorEntry for Vector {
} }
impl Vector { impl Vector {
pub fn from(entries: &Vec<Entry>) -> CalculatorResult<Entry> { pub fn from(entries: &[Entry]) -> CalculatorResult<Entry> {
if entries.len() == 0 { if entries.is_empty() {
return Err(CalculatorError::NotEnoughStackEntries); return Err(CalculatorError::NotEnoughStackEntries);
} }
Self { Self {
@ -697,7 +737,7 @@ impl Vector {
.iter() .iter()
.map(|e| match e { .map(|e| match e {
Entry::Matrix(_) | Entry::Vector(_) => Err(CalculatorError::TypeMismatch), Entry::Matrix(_) | Entry::Vector(_) => Err(CalculatorError::TypeMismatch),
Entry::Number(number) => Ok(number.clone()), Entry::Number(number) => Ok(*number),
}) })
.collect::<CalculatorResult<Vec<Number>>>()?, .collect::<CalculatorResult<Vec<Number>>>()?,
direction: VectorDirection::default(), direction: VectorDirection::default(),
@ -806,9 +846,13 @@ impl CalculatorEntry for Number {
})) }))
} }
fn inverse(&self) -> CalculatorResult<Entry> { fn inverse(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self { Self {
value: self.value.recip(), value: self.value.recip(),
})) }
.validate()
}
fn transpose(&self) -> CalculatorResult<Entry> {
Err(CalculatorError::TypeMismatch)
} }
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self { Ok(Entry::Number(Self {
@ -984,7 +1028,7 @@ impl Number {
vectors: matrix vectors: matrix
.vectors .vectors
.iter() .iter()
.map(|v| op(&self, &Entry::Vector(v.clone()))) // TODO: Do I need to clone? .map(|v| op(&self, &Entry::Vector(v.clone())))
.map(|e| match e { .map(|e| match e {
// Only numbers are valid in a vector // Only numbers are valid in a vector
Ok(Entry::Vector(vector)) => Ok(vector), Ok(Entry::Vector(vector)) => Ok(vector),
@ -1012,6 +1056,7 @@ where
fn negate(&self) -> CalculatorResult<Entry>; fn negate(&self) -> CalculatorResult<Entry>;
fn abs(&self) -> CalculatorResult<Entry>; fn abs(&self) -> CalculatorResult<Entry>;
fn inverse(&self) -> CalculatorResult<Entry>; fn inverse(&self) -> CalculatorResult<Entry>;
fn transpose(&self) -> CalculatorResult<Entry>;
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>; fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>; fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>; fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;

View File

@ -30,6 +30,7 @@ pub enum CalculatorOperation {
BuildVector, BuildVector,
BuildMatrix, BuildMatrix,
Deconstruct, Deconstruct,
Transpose,
Undo, Undo,
Redo, Redo,
Drop, Drop,