Working vector and matrix; fix clippy warnings
This commit is contained in:
parent
f80011652b
commit
456dc6dcd4
@ -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:
|
||||||
|
|
||||||
|
18
src/calc.rs
18
src/calc.rs
@ -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]))),
|
||||||
|
@ -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>;
|
||||||
|
@ -30,6 +30,7 @@ pub enum CalculatorOperation {
|
|||||||
BuildVector,
|
BuildVector,
|
||||||
BuildMatrix,
|
BuildMatrix,
|
||||||
Deconstruct,
|
Deconstruct,
|
||||||
|
Transpose,
|
||||||
Undo,
|
Undo,
|
||||||
Redo,
|
Redo,
|
||||||
Drop,
|
Drop,
|
||||||
|
Loading…
Reference in New Issue
Block a user