Start work on Matrix
This commit is contained in:
parent
7ee77f4c4c
commit
3b10aaf06f
75
Cargo.lock
generated
75
Cargo.lock
generated
@ -12,12 +12,6 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -27,12 +21,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "confy"
|
name = "confy"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/rust-cli/confy/#6ae700bb0e6e2f9f7138d0c1871f604013c8f59f"
|
||||||
checksum = "2913470204e9e8498a0f31f17f90a0de801ae92c8c5ac18c49af4819e6786697"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"directories",
|
"directories-next",
|
||||||
"serde",
|
"serde",
|
||||||
"toml",
|
"serde_yaml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -61,33 +54,39 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "directories"
|
name = "directories-next"
|
||||||
version = "2.0.2"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c"
|
checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
"dirs-sys",
|
"dirs-sys-next",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs-sys"
|
name = "dirs-sys-next"
|
||||||
version = "0.3.6"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
|
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"redox_users",
|
"redox_users",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dtoa"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
|
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
@ -98,7 +97,7 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
|
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -113,6 +112,12 @@ version = "0.2.94"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
@ -128,7 +133,7 @@ version = "0.4.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -179,7 +184,7 @@ version = "0.8.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
"instant",
|
"instant",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
@ -231,6 +236,7 @@ dependencies = [
|
|||||||
"confy",
|
"confy",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"serde",
|
"serde",
|
||||||
|
"toml",
|
||||||
"tui",
|
"tui",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -260,6 +266,18 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_yaml"
|
||||||
|
version = "0.8.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
|
||||||
|
dependencies = [
|
||||||
|
"dtoa",
|
||||||
|
"linked-hash-map",
|
||||||
|
"serde",
|
||||||
|
"yaml-rust",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.1.17"
|
version = "0.1.17"
|
||||||
@ -299,9 +317,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.5.8"
|
version = "0.4.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -364,3 +382,12 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaml-rust"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
||||||
|
10
Cargo.toml
10
Cargo.toml
@ -15,4 +15,12 @@ categories = ["command-line-utilities"]
|
|||||||
crossterm = "0.18"
|
crossterm = "0.18"
|
||||||
tui = { version = "0.14", default-features = false, features = ['crossterm'] }
|
tui = { version = "0.14", default-features = false, features = ['crossterm'] }
|
||||||
serde = {version = "1.0", features = ["derive"]}
|
serde = {version = "1.0", features = ["derive"]}
|
||||||
confy = "0.4.0"
|
# confy = "0.4.0"
|
||||||
|
toml = "0.4.2"
|
||||||
|
|
||||||
|
[dependencies.confy]
|
||||||
|
# TODO: Update this to v0.5.0 when it finally comes out -- for now, use latest git master
|
||||||
|
# version = "0.4.0"
|
||||||
|
git = "https://github.com/rust-cli/confy/"
|
||||||
|
features = ["yaml_conf"]
|
||||||
|
default-features = false
|
||||||
|
59
src/calc.rs
59
src/calc.rs
@ -5,7 +5,7 @@ pub mod types;
|
|||||||
use crate::calc::entries::CalculatorEntry;
|
use crate::calc::entries::CalculatorEntry;
|
||||||
|
|
||||||
use confy::{load, store};
|
use confy::{load, store};
|
||||||
use entries::{Entry, Number, Vector, VectorDirection};
|
use entries::{Entry, Matrix, Number, Vector};
|
||||||
use errors::{CalculatorError, CalculatorResult};
|
use errors::{CalculatorError, CalculatorResult};
|
||||||
use operations::{
|
use operations::{
|
||||||
ArithmeticOperation, CalculatorOperation, CalculatorStateChange, MacroState, OpArgs,
|
ArithmeticOperation, CalculatorOperation, CalculatorStateChange, MacroState, OpArgs,
|
||||||
@ -115,6 +115,13 @@ impl Default for Calculator {
|
|||||||
value: String::from("RcRbRarbnrb2^4rarc**-v+2ra*/rbnrb2^4rarc**-v-2ra*/"),
|
value: String::from("RcRbRarbnrb2^4rarc**-v+2ra*/rbnrb2^4rarc**-v-2ra*/"),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
't',
|
||||||
|
CalculatorMacro {
|
||||||
|
help: String::from("Testing"),
|
||||||
|
value: String::from("1 V1 "),
|
||||||
|
},
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -168,10 +175,10 @@ impl Calculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_config() -> CalculatorResult<Self> {
|
pub fn load_config() -> CalculatorResult<Self> {
|
||||||
load(APP_NAME).map_err(|e| CalculatorError::LoadError(Some(e)))
|
load(APP_NAME, None).map_err(|e| CalculatorError::LoadError(Some(e)))
|
||||||
}
|
}
|
||||||
pub fn save_config(&self) -> CalculatorResult<()> {
|
pub fn save_config(&self) -> CalculatorResult<()> {
|
||||||
store(APP_NAME, self).map_err(|e| CalculatorError::SaveError(Some(e)))
|
store(APP_NAME, None, self).map_err(|e| CalculatorError::SaveError(Some(e)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_input(&mut self, c: char) -> CalculatorResult<()> {
|
pub fn take_input(&mut self, c: char) -> CalculatorResult<()> {
|
||||||
@ -271,6 +278,7 @@ impl Calculator {
|
|||||||
)),
|
)),
|
||||||
// Temporary
|
// Temporary
|
||||||
'V' => self.op(CalculatorOperation::BuildVector),
|
'V' => self.op(CalculatorOperation::BuildVector),
|
||||||
|
'M' => self.op(CalculatorOperation::BuildMatrix),
|
||||||
// Special
|
// Special
|
||||||
'\\' => self.op(CalculatorOperation::Drop),
|
'\\' => self.op(CalculatorOperation::Drop),
|
||||||
' ' => self.op(CalculatorOperation::Dup),
|
' ' => self.op(CalculatorOperation::Dup),
|
||||||
@ -508,8 +516,9 @@ 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::Number(Number { value }) => value,
|
Entry::Matrix(_) => return Err(CalculatorError::TypeMismatch),
|
||||||
Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
|
Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Number(Number { value }) => value,
|
||||||
};
|
};
|
||||||
// Ensure this can be cast to a usize
|
// Ensure this can be cast to a usize
|
||||||
if !f.is_finite() || f.is_sign_negative() {
|
if !f.is_finite() || f.is_sign_negative() {
|
||||||
@ -537,27 +546,30 @@ 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, values): (VecDeque<Entry>, Vec<Number>) = (1..=count)
|
let mut entries: Vec<Entry> = (1..=count)
|
||||||
.map(|i| {
|
.map(|i| self.peek(i))
|
||||||
let e = self.peek(i)?;
|
.collect::<CalculatorResult<Vec<Entry>>>()?;
|
||||||
match e {
|
|
||||||
// TODO: For now, vectors only contain numbers
|
let new_entry = Vector::from(&entries)?;
|
||||||
Entry::Number(number) => Ok((e, number)),
|
|
||||||
Entry::Vector(_vector) => Err(CalculatorError::TypeMismatch),
|
entries.splice(1..1, vec![count_entry]);
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<CalculatorResult<Vec<(Entry, Number)>>>()?
|
|
||||||
// TODO: Do I have to iter again?
|
|
||||||
.into_iter()
|
|
||||||
.unzip();
|
|
||||||
let entry = Entry::Vector(Vector {
|
|
||||||
values,
|
|
||||||
direction: VectorDirection::Row,
|
|
||||||
});
|
|
||||||
entries.push_front(count_entry);
|
|
||||||
Ok(CalculatorStateChange {
|
Ok(CalculatorStateChange {
|
||||||
pop: OpArgs::Variable(Vec::from(entries)),
|
pop: OpArgs::Variable(Vec::from(entries)),
|
||||||
push: OpArgs::Unary(entry),
|
push: OpArgs::Unary(new_entry),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn build_matrix(&mut self) -> CalculatorResult<CalculatorStateChange> {
|
||||||
|
let (count, count_entry) = self.peek_usize()?;
|
||||||
|
let mut entries: Vec<Entry> = (1..=count)
|
||||||
|
.map(|i| self.peek(i))
|
||||||
|
.collect::<CalculatorResult<Vec<Entry>>>()?;
|
||||||
|
|
||||||
|
let new_entry = Matrix::from(&entries)?;
|
||||||
|
|
||||||
|
entries.splice(1..1, vec![count_entry]);
|
||||||
|
Ok(CalculatorStateChange {
|
||||||
|
pop: OpArgs::Variable(Vec::from(entries)),
|
||||||
|
push: OpArgs::Unary(new_entry),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,6 +646,7 @@ impl Calculator {
|
|||||||
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(&a)?)))
|
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(&a)?)))
|
||||||
}
|
}
|
||||||
CalculatorOperation::BuildVector => self.build_vector(),
|
CalculatorOperation::BuildVector => self.build_vector(),
|
||||||
|
CalculatorOperation::BuildMatrix => self.build_matrix(),
|
||||||
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]))),
|
||||||
|
@ -58,18 +58,19 @@ pub struct Vector {
|
|||||||
pub direction: VectorDirection,
|
pub direction: VectorDirection,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
// pub struct Matrix {
|
pub struct Matrix {
|
||||||
// pub values: Vec<Vector>,
|
pub vectors: Vec<Vector>,
|
||||||
// pub direction: VectorDirection,
|
pub dimensions: (usize, usize),
|
||||||
// }
|
pub direction: VectorDirection,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum Entry {
|
pub enum Entry {
|
||||||
Number(Number),
|
Number(Number),
|
||||||
Vector(Vector),
|
Vector(Vector),
|
||||||
// Matrix(Matrix),
|
Matrix(Matrix),
|
||||||
}
|
}
|
||||||
|
|
||||||
// macro_rules! op_child_call {
|
// macro_rules! op_child_call {
|
||||||
@ -92,90 +93,105 @@ impl CalculatorEntry for Entry {
|
|||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.to_editable_string(),
|
Self::Number(number) => number.to_editable_string(),
|
||||||
Self::Vector(vector) => vector.to_editable_string(),
|
Self::Vector(vector) => vector.to_editable_string(),
|
||||||
|
Self::Matrix(matrix) => matrix.to_editable_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.format_entry(display_mode),
|
Self::Number(number) => number.format_entry(display_mode),
|
||||||
Self::Vector(vector) => vector.format_entry(display_mode),
|
Self::Vector(vector) => vector.format_entry(display_mode),
|
||||||
|
Self::Matrix(matrix) => matrix.format_entry(display_mode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn is_valid(&self) -> bool {
|
fn is_valid(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.is_valid(),
|
Self::Number(number) => number.is_valid(),
|
||||||
Self::Vector(vector) => vector.is_valid(),
|
Self::Vector(vector) => vector.is_valid(),
|
||||||
|
Self::Matrix(matrix) => matrix.is_valid(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn negate(&self) -> CalculatorResult<Self> {
|
fn negate(&self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.negate(),
|
Self::Number(number) => number.negate(),
|
||||||
Self::Vector(vector) => vector.negate(),
|
Self::Vector(vector) => vector.negate(),
|
||||||
|
Self::Matrix(matrix) => matrix.negate(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn abs(&self) -> CalculatorResult<Self> {
|
fn abs(&self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.abs(),
|
Self::Number(number) => number.abs(),
|
||||||
Self::Vector(vector) => vector.abs(),
|
Self::Vector(vector) => vector.abs(),
|
||||||
|
Self::Matrix(matrix) => matrix.abs(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn inverse(&self) -> CalculatorResult<Self> {
|
fn inverse(&self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.inverse(),
|
Self::Number(number) => number.inverse(),
|
||||||
Self::Vector(vector) => vector.inverse(),
|
Self::Vector(vector) => vector.inverse(),
|
||||||
|
Self::Matrix(matrix) => matrix.inverse(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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),
|
||||||
Self::Vector(vector) => vector.sin(angle_mode),
|
Self::Vector(vector) => vector.sin(angle_mode),
|
||||||
|
Self::Matrix(matrix) => matrix.sin(angle_mode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.cos(angle_mode),
|
Self::Number(number) => number.cos(angle_mode),
|
||||||
Self::Vector(vector) => vector.cos(angle_mode),
|
Self::Vector(vector) => vector.cos(angle_mode),
|
||||||
|
Self::Matrix(matrix) => matrix.cos(angle_mode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.tan(angle_mode),
|
Self::Number(number) => number.tan(angle_mode),
|
||||||
Self::Vector(vector) => vector.tan(angle_mode),
|
Self::Vector(vector) => vector.tan(angle_mode),
|
||||||
|
Self::Matrix(matrix) => matrix.tan(angle_mode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.asin(angle_mode),
|
Self::Number(number) => number.asin(angle_mode),
|
||||||
Self::Vector(vector) => vector.asin(angle_mode),
|
Self::Vector(vector) => vector.asin(angle_mode),
|
||||||
|
Self::Matrix(matrix) => matrix.asin(angle_mode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.acos(angle_mode),
|
Self::Number(number) => number.acos(angle_mode),
|
||||||
Self::Vector(vector) => vector.acos(angle_mode),
|
Self::Vector(vector) => vector.acos(angle_mode),
|
||||||
|
Self::Matrix(matrix) => matrix.acos(angle_mode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.atan(angle_mode),
|
Self::Number(number) => number.atan(angle_mode),
|
||||||
Self::Vector(vector) => vector.atan(angle_mode),
|
Self::Vector(vector) => vector.atan(angle_mode),
|
||||||
|
Self::Matrix(matrix) => matrix.atan(angle_mode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn sqrt(&self) -> CalculatorResult<Self> {
|
fn sqrt(&self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.sqrt(),
|
Self::Number(number) => number.sqrt(),
|
||||||
Self::Vector(vector) => vector.sqrt(),
|
Self::Vector(vector) => vector.sqrt(),
|
||||||
|
Self::Matrix(matrix) => matrix.sqrt(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn log(&self) -> CalculatorResult<Self> {
|
fn log(&self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.log(),
|
Self::Number(number) => number.log(),
|
||||||
Self::Vector(vector) => vector.log(),
|
Self::Vector(vector) => vector.log(),
|
||||||
|
Self::Matrix(matrix) => matrix.log(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn ln(&self) -> CalculatorResult<Self> {
|
fn ln(&self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.ln(),
|
Self::Number(number) => number.ln(),
|
||||||
Self::Vector(vector) => vector.ln(),
|
Self::Vector(vector) => vector.ln(),
|
||||||
|
Self::Matrix(matrix) => matrix.ln(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,46 +199,291 @@ impl CalculatorEntry for Entry {
|
|||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.add(arg),
|
Self::Number(number) => number.add(arg),
|
||||||
Self::Vector(vector) => vector.add(arg),
|
Self::Vector(vector) => vector.add(arg),
|
||||||
|
Self::Matrix(matrix) => matrix.add(arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn sub(&self, arg: &Self) -> CalculatorResult<Self> {
|
fn sub(&self, arg: &Self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.sub(arg),
|
Self::Number(number) => number.sub(arg),
|
||||||
Self::Vector(vector) => vector.sub(arg),
|
Self::Vector(vector) => vector.sub(arg),
|
||||||
|
Self::Matrix(matrix) => matrix.sub(arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn mul(&self, arg: &Self) -> CalculatorResult<Self> {
|
fn mul(&self, arg: &Self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.mul(arg),
|
Self::Number(number) => number.mul(arg),
|
||||||
Self::Vector(vector) => vector.mul(arg),
|
Self::Vector(vector) => vector.mul(arg),
|
||||||
|
Self::Matrix(matrix) => matrix.mul(arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn div(&self, arg: &Self) -> CalculatorResult<Self> {
|
fn div(&self, arg: &Self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.div(arg),
|
Self::Number(number) => number.div(arg),
|
||||||
Self::Vector(vector) => vector.div(arg),
|
Self::Vector(vector) => vector.div(arg),
|
||||||
|
Self::Matrix(matrix) => matrix.div(arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn int_divide(&self, arg: &Self) -> CalculatorResult<Self> {
|
fn int_divide(&self, arg: &Self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.int_divide(arg),
|
Self::Number(number) => number.int_divide(arg),
|
||||||
Self::Vector(vector) => vector.int_divide(arg),
|
Self::Vector(vector) => vector.int_divide(arg),
|
||||||
|
Self::Matrix(matrix) => matrix.int_divide(arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn modulo(&self, arg: &Self) -> CalculatorResult<Self> {
|
fn modulo(&self, arg: &Self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.modulo(arg),
|
Self::Number(number) => number.modulo(arg),
|
||||||
Self::Vector(vector) => vector.modulo(arg),
|
Self::Vector(vector) => vector.modulo(arg),
|
||||||
|
Self::Matrix(matrix) => matrix.modulo(arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn pow(&self, arg: &Self) -> CalculatorResult<Self> {
|
fn pow(&self, arg: &Self) -> CalculatorResult<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.pow(arg),
|
Self::Number(number) => number.pow(arg),
|
||||||
Self::Vector(vector) => vector.pow(arg),
|
Self::Vector(vector) => vector.pow(arg),
|
||||||
|
Self::Matrix(matrix) => matrix.pow(arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CalculatorEntry for Matrix {
|
||||||
|
fn to_editable_string(&self) -> CalculatorResult<String> {
|
||||||
|
// TODO: Eventualy we can parse and edit a matrix as a string
|
||||||
|
Err(CalculatorError::TypeMismatch)
|
||||||
|
}
|
||||||
|
fn is_valid(&self) -> bool {
|
||||||
|
self.vectors.len() == self.dimensions.0
|
||||||
|
&& self
|
||||||
|
.vectors
|
||||||
|
.iter()
|
||||||
|
.all(|v| v.values.len() == self.dimensions.1 && v.is_valid())
|
||||||
|
}
|
||||||
|
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||||
|
format!(
|
||||||
|
"[ {} ]",
|
||||||
|
self.vectors
|
||||||
|
.iter()
|
||||||
|
.map(|vector| vector.format_entry(display_mode))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(self.direction.get_separator())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mathematical operations
|
||||||
|
fn negate(&self) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(Vector::negate)
|
||||||
|
}
|
||||||
|
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(),
|
||||||
|
// direction: self.direction.swap(),
|
||||||
|
// }))
|
||||||
|
self.iterated_unary(Vector::inverse)
|
||||||
|
}
|
||||||
|
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(|v| v.sin(angle_mode))
|
||||||
|
}
|
||||||
|
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(|v| v.cos(angle_mode))
|
||||||
|
}
|
||||||
|
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(|v| v.tan(angle_mode))
|
||||||
|
}
|
||||||
|
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(|v| v.asin(angle_mode))
|
||||||
|
}
|
||||||
|
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(|v| v.acos(angle_mode))
|
||||||
|
}
|
||||||
|
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(|v| v.atan(angle_mode))
|
||||||
|
}
|
||||||
|
fn sqrt(&self) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(Vector::sqrt)
|
||||||
|
}
|
||||||
|
fn log(&self) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(Vector::log)
|
||||||
|
}
|
||||||
|
fn ln(&self) -> CalculatorResult<Entry> {
|
||||||
|
self.iterated_unary(Vector::ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary
|
||||||
|
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
|
match arg {
|
||||||
|
Entry::Matrix(m2) => self.iterated_binary_mat(m2, Vector::add),
|
||||||
|
Entry::Vector(vector) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Number(number) => self.iterated_binary_num(number, Vector::add),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
|
match arg {
|
||||||
|
Entry::Matrix(m2) => self.iterated_binary_mat(m2, Vector::sub),
|
||||||
|
Entry::Vector(vector) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Number(number) => self.iterated_binary_num(number, Vector::sub),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
|
// TODO: Correct implementation
|
||||||
|
match arg {
|
||||||
|
Entry::Matrix(m2) => self.iterated_binary_mat(m2, Vector::mul),
|
||||||
|
Entry::Vector(vector) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Number(number) => self.iterated_binary_num(number, Vector::mul),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
|
match arg {
|
||||||
|
Entry::Matrix(m2) => self.iterated_binary_mat(m2, Vector::div),
|
||||||
|
Entry::Vector(vector) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Number(number) => self.iterated_binary_num(number, Vector::div),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
|
match arg {
|
||||||
|
Entry::Matrix(m2) => self.iterated_binary_mat(m2, Vector::int_divide),
|
||||||
|
Entry::Vector(vector) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Number(number) => self.iterated_binary_num(number, Vector::int_divide),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
|
match arg {
|
||||||
|
Entry::Matrix(m2) => self.iterated_binary_mat(m2, Vector::modulo),
|
||||||
|
Entry::Vector(vector) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Number(number) => self.iterated_binary_num(number, Vector::modulo),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
|
match arg {
|
||||||
|
Entry::Matrix(m2) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Vector(vector) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Number(number) => self.iterated_binary_num(number, Vector::pow),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Matrix {
|
||||||
|
pub fn from(entries: &Vec<Entry>) -> CalculatorResult<Entry> {
|
||||||
|
if entries.len() == 0 {
|
||||||
|
return Err(CalculatorError::NotEnoughStackEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
let vectors = entries
|
||||||
|
.iter()
|
||||||
|
.map(|e| match e {
|
||||||
|
Entry::Matrix(_) | Entry::Number(_) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Vector(vector) => Ok(vector.clone()),
|
||||||
|
})
|
||||||
|
.collect::<CalculatorResult<Vec<Vector>>>()?;
|
||||||
|
|
||||||
|
// Get the depth of the matrix
|
||||||
|
let depth = vectors
|
||||||
|
.get(0)
|
||||||
|
.ok_or(CalculatorError::NotEnoughStackEntries)?
|
||||||
|
.values
|
||||||
|
.len();
|
||||||
|
|
||||||
|
if vectors.iter().any(|v| v.values.len() != depth) {
|
||||||
|
// One vector has a different length than another
|
||||||
|
return Err(CalculatorError::DimensionMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dimensions: (usize, usize) = (vectors.len(), depth);
|
||||||
|
Self {
|
||||||
|
vectors,
|
||||||
|
dimensions,
|
||||||
|
direction: VectorDirection::Row,
|
||||||
|
}
|
||||||
|
.validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Should validate be put in the trait?
|
||||||
|
pub fn validate(self) -> CalculatorResult<Entry> {
|
||||||
|
if self.is_valid() {
|
||||||
|
Ok(Entry::Matrix(self))
|
||||||
|
} else {
|
||||||
|
Err(CalculatorError::ArithmeticError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iterated_unary(
|
||||||
|
&self,
|
||||||
|
op: impl Fn(&Vector) -> CalculatorResult<Entry>,
|
||||||
|
) -> CalculatorResult<Entry> {
|
||||||
|
Self {
|
||||||
|
vectors: self
|
||||||
|
.vectors
|
||||||
|
.iter()
|
||||||
|
.map(|v| op(v))
|
||||||
|
.map(|e| match e {
|
||||||
|
Ok(Entry::Vector(vector)) => Ok(vector),
|
||||||
|
_ => Err(CalculatorError::ArithmeticError),
|
||||||
|
})
|
||||||
|
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
||||||
|
direction: self.direction,
|
||||||
|
dimensions: self.dimensions,
|
||||||
|
}
|
||||||
|
.validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iterated_binary_num(
|
||||||
|
&self,
|
||||||
|
number: &Number,
|
||||||
|
op: impl Fn(&Vector, &Entry) -> CalculatorResult<Entry>,
|
||||||
|
) -> CalculatorResult<Entry> {
|
||||||
|
Self {
|
||||||
|
vectors: self
|
||||||
|
.vectors
|
||||||
|
.iter()
|
||||||
|
.map(|v| op(v, &Entry::Number(*number)))
|
||||||
|
.map(|e| match e {
|
||||||
|
Ok(Entry::Vector(vector)) => Ok(vector),
|
||||||
|
_ => Err(CalculatorError::ArithmeticError),
|
||||||
|
})
|
||||||
|
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
||||||
|
direction: self.direction,
|
||||||
|
dimensions: self.dimensions,
|
||||||
|
}
|
||||||
|
.validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iterated_binary_mat(
|
||||||
|
&self,
|
||||||
|
m2: &Self,
|
||||||
|
op: impl Fn(&Vector, &Entry) -> CalculatorResult<Entry>,
|
||||||
|
) -> CalculatorResult<Entry> {
|
||||||
|
if self.dimensions != m2.dimensions && self.direction != m2.direction {
|
||||||
|
return Err(CalculatorError::DimensionMismatch);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
vectors: self
|
||||||
|
.vectors
|
||||||
|
.iter()
|
||||||
|
.zip(m2.vectors.iter())
|
||||||
|
.map(|(v1, v2)| op(v1, &Entry::Vector(v2.clone())))
|
||||||
|
.map(|e| match e {
|
||||||
|
Ok(Entry::Vector(vector)) => Ok(vector),
|
||||||
|
_ => Err(CalculatorError::ArithmeticError),
|
||||||
|
})
|
||||||
|
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
||||||
|
direction: self.direction,
|
||||||
|
dimensions: self.dimensions,
|
||||||
|
}
|
||||||
|
.validate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CalculatorEntry for Vector {
|
impl CalculatorEntry for Vector {
|
||||||
// Misc
|
// Misc
|
||||||
fn to_editable_string(&self) -> CalculatorResult<String> {
|
fn to_editable_string(&self) -> CalculatorResult<String> {
|
||||||
@ -291,18 +552,22 @@ impl CalculatorEntry for Vector {
|
|||||||
|
|
||||||
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
|
Entry::Matrix(_) => Err(CalculatorError::TypeMismatch),
|
||||||
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::add),
|
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::add),
|
||||||
Entry::Number(number) => self.iterated_binary_num(number, Number::add),
|
Entry::Number(number) => self.iterated_binary_num(number, Number::add),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
|
Entry::Matrix(_) => Err(CalculatorError::TypeMismatch),
|
||||||
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::sub),
|
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::sub),
|
||||||
Entry::Number(number) => self.iterated_binary_num(number, Number::sub),
|
Entry::Number(number) => self.iterated_binary_num(number, Number::sub),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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(_) => 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);
|
||||||
@ -331,24 +596,28 @@ impl CalculatorEntry for Vector {
|
|||||||
}
|
}
|
||||||
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
|
Entry::Matrix(_) => Err(CalculatorError::TypeMismatch),
|
||||||
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::div),
|
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::div),
|
||||||
Entry::Number(number) => self.iterated_binary_num(number, Number::div),
|
Entry::Number(number) => self.iterated_binary_num(number, Number::div),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
|
Entry::Matrix(_) => Err(CalculatorError::TypeMismatch),
|
||||||
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::int_divide),
|
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::int_divide),
|
||||||
Entry::Number(number) => self.iterated_binary_num(number, Number::int_divide),
|
Entry::Number(number) => self.iterated_binary_num(number, Number::int_divide),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
|
Entry::Matrix(_) => Err(CalculatorError::TypeMismatch),
|
||||||
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::modulo),
|
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::modulo),
|
||||||
Entry::Number(number) => self.iterated_binary_num(number, Number::modulo),
|
Entry::Number(number) => self.iterated_binary_num(number, Number::modulo),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
|
Entry::Matrix(_) => Err(CalculatorError::TypeMismatch),
|
||||||
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::pow),
|
Entry::Vector(v2) => self.iterated_binary_vec(v2, Number::pow),
|
||||||
Entry::Number(number) => self.iterated_binary_num(number, Number::pow),
|
Entry::Number(number) => self.iterated_binary_num(number, Number::pow),
|
||||||
}
|
}
|
||||||
@ -356,6 +625,23 @@ impl CalculatorEntry for Vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Vector {
|
impl Vector {
|
||||||
|
pub fn from(entries: &Vec<Entry>) -> CalculatorResult<Entry> {
|
||||||
|
if entries.len() == 0 {
|
||||||
|
return Err(CalculatorError::NotEnoughStackEntries);
|
||||||
|
}
|
||||||
|
Ok(Entry::Vector(Self {
|
||||||
|
values: entries
|
||||||
|
.iter()
|
||||||
|
.map(|e| match e {
|
||||||
|
Entry::Matrix(_) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Vector(_) => Err(CalculatorError::TypeMismatch),
|
||||||
|
Entry::Number(number) => Ok(number.clone()),
|
||||||
|
})
|
||||||
|
.collect::<CalculatorResult<Vec<Number>>>()?,
|
||||||
|
direction: VectorDirection::Row,
|
||||||
|
})) //.validate() <- TODO
|
||||||
|
}
|
||||||
|
|
||||||
fn iterated_unary(
|
fn iterated_unary(
|
||||||
&self,
|
&self,
|
||||||
op: impl Fn(&Number) -> CalculatorResult<Entry>,
|
op: impl Fn(&Number) -> CalculatorResult<Entry>,
|
||||||
@ -525,7 +811,8 @@ impl CalculatorEntry for Number {
|
|||||||
|
|
||||||
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
Entry::Vector(vector) => self.iterated_binary(vector, Self::add),
|
Entry::Matrix(matrix) => self.iterated_binary_mat(matrix, Self::add),
|
||||||
|
Entry::Vector(vector) => self.iterated_binary_vec(vector, Self::add),
|
||||||
Entry::Number(number) => Self {
|
Entry::Number(number) => Self {
|
||||||
value: self.value + number.value,
|
value: self.value + number.value,
|
||||||
}
|
}
|
||||||
@ -534,7 +821,8 @@ impl CalculatorEntry for Number {
|
|||||||
}
|
}
|
||||||
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
Entry::Vector(vector) => self.iterated_binary(vector, Self::sub),
|
Entry::Matrix(matrix) => self.iterated_binary_mat(matrix, Self::sub),
|
||||||
|
Entry::Vector(vector) => self.iterated_binary_vec(vector, Self::sub),
|
||||||
Entry::Number(number) => Self {
|
Entry::Number(number) => Self {
|
||||||
value: self.value - number.value,
|
value: self.value - number.value,
|
||||||
}
|
}
|
||||||
@ -543,7 +831,8 @@ impl CalculatorEntry for Number {
|
|||||||
}
|
}
|
||||||
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
Entry::Vector(vector) => self.iterated_binary(vector, Self::mul),
|
Entry::Matrix(matrix) => self.iterated_binary_mat(matrix, Self::mul),
|
||||||
|
Entry::Vector(vector) => self.iterated_binary_vec(vector, Self::mul),
|
||||||
Entry::Number(number) => Self {
|
Entry::Number(number) => Self {
|
||||||
value: self.value * number.value,
|
value: self.value * number.value,
|
||||||
}
|
}
|
||||||
@ -552,7 +841,8 @@ impl CalculatorEntry for Number {
|
|||||||
}
|
}
|
||||||
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
Entry::Vector(vector) => self.iterated_binary(vector, Self::div),
|
Entry::Matrix(matrix) => self.iterated_binary_mat(matrix, Self::div),
|
||||||
|
Entry::Vector(vector) => self.iterated_binary_vec(vector, Self::div),
|
||||||
Entry::Number(number) => Self {
|
Entry::Number(number) => Self {
|
||||||
value: self.value / number.value,
|
value: self.value / number.value,
|
||||||
}
|
}
|
||||||
@ -561,7 +851,8 @@ impl CalculatorEntry for Number {
|
|||||||
}
|
}
|
||||||
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
Entry::Vector(vector) => self.iterated_binary(vector, Self::int_divide),
|
Entry::Matrix(matrix) => self.iterated_binary_mat(matrix, Self::int_divide),
|
||||||
|
Entry::Vector(vector) => self.iterated_binary_vec(vector, Self::int_divide),
|
||||||
Entry::Number(number) => Self {
|
Entry::Number(number) => Self {
|
||||||
value: self.value.div_euclid(number.value),
|
value: self.value.div_euclid(number.value),
|
||||||
}
|
}
|
||||||
@ -570,7 +861,8 @@ impl CalculatorEntry for Number {
|
|||||||
}
|
}
|
||||||
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
Entry::Vector(vector) => self.iterated_binary(vector, Self::modulo),
|
Entry::Matrix(matrix) => self.iterated_binary_mat(matrix, Self::modulo),
|
||||||
|
Entry::Vector(vector) => self.iterated_binary_vec(vector, Self::modulo),
|
||||||
Entry::Number(number) => Self {
|
Entry::Number(number) => Self {
|
||||||
value: self.value % number.value,
|
value: self.value % number.value,
|
||||||
}
|
}
|
||||||
@ -579,7 +871,8 @@ impl CalculatorEntry for Number {
|
|||||||
}
|
}
|
||||||
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||||
match arg {
|
match arg {
|
||||||
Entry::Vector(vector) => self.iterated_binary(vector, Self::pow),
|
Entry::Matrix(matrix) => self.iterated_binary_mat(matrix, Self::pow),
|
||||||
|
Entry::Vector(vector) => self.iterated_binary_vec(vector, Self::pow),
|
||||||
Entry::Number(number) => Self {
|
Entry::Number(number) => Self {
|
||||||
value: self.value.powf(number.value),
|
value: self.value.powf(number.value),
|
||||||
}
|
}
|
||||||
@ -599,7 +892,7 @@ impl Number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iterated_binary(
|
fn iterated_binary_vec(
|
||||||
self,
|
self,
|
||||||
vector: &Vector,
|
vector: &Vector,
|
||||||
op: impl Fn(&Self, &Entry) -> CalculatorResult<Entry>,
|
op: impl Fn(&Self, &Entry) -> CalculatorResult<Entry>,
|
||||||
@ -618,6 +911,28 @@ impl Number {
|
|||||||
direction: vector.direction,
|
direction: vector.direction,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iterated_binary_mat(
|
||||||
|
self,
|
||||||
|
matrix: &Matrix,
|
||||||
|
op: impl Fn(&Self, &Entry) -> CalculatorResult<Entry>,
|
||||||
|
) -> CalculatorResult<Entry> {
|
||||||
|
Matrix {
|
||||||
|
vectors: matrix
|
||||||
|
.vectors
|
||||||
|
.iter()
|
||||||
|
.map(|v| op(&self, &Entry::Vector(v.clone()))) // TODO: Do I need to clone?
|
||||||
|
.map(|e| match e {
|
||||||
|
// Only numbers are valid in a vector
|
||||||
|
Ok(Entry::Vector(vector)) => Ok(vector),
|
||||||
|
_ => Err(CalculatorError::ArithmeticError),
|
||||||
|
})
|
||||||
|
.collect::<CalculatorResult<Vec<Vector>>>()?,
|
||||||
|
direction: matrix.direction,
|
||||||
|
dimensions: matrix.dimensions,
|
||||||
|
}
|
||||||
|
.validate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CalculatorEntry
|
pub trait CalculatorEntry
|
||||||
@ -629,15 +944,6 @@ where
|
|||||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String;
|
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String;
|
||||||
fn to_editable_string(&self) -> CalculatorResult<String>;
|
fn to_editable_string(&self) -> CalculatorResult<String>;
|
||||||
// Mathematical operations
|
// Mathematical operations
|
||||||
// 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>;
|
|
||||||
|
|
||||||
// Unary
|
// Unary
|
||||||
fn negate(&self) -> CalculatorResult<Entry>;
|
fn negate(&self) -> CalculatorResult<Entry>;
|
||||||
fn abs(&self) -> CalculatorResult<Entry>;
|
fn abs(&self) -> CalculatorResult<Entry>;
|
||||||
@ -651,20 +957,38 @@ where
|
|||||||
fn sqrt(&self) -> CalculatorResult<Entry>;
|
fn sqrt(&self) -> CalculatorResult<Entry>;
|
||||||
fn log(&self) -> CalculatorResult<Entry>;
|
fn log(&self) -> CalculatorResult<Entry>;
|
||||||
fn ln(&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 {
|
||||||
Self::Number(number) => write!(f, "{}", number),
|
Self::Matrix(matrix) => write!(f, "{}", matrix),
|
||||||
Self::Vector(vector) => write!(f, "{}", vector),
|
Self::Vector(vector) => write!(f, "{}", vector),
|
||||||
|
Self::Number(number) => write!(f, "{}", number),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Number {
|
impl fmt::Display for Matrix {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.value)
|
write!(
|
||||||
|
f,
|
||||||
|
"[ {} ]",
|
||||||
|
self.vectors
|
||||||
|
.iter()
|
||||||
|
.map(|vector| format!("{}", vector))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("; ")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,6 +1006,12 @@ impl fmt::Display for Vector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Number {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Based on https://stackoverflow.com/a/65266882
|
// Based on https://stackoverflow.com/a/65266882
|
||||||
fn scientific(f: f64, precision: usize) -> String {
|
fn scientific(f: f64, precision: usize) -> String {
|
||||||
let mut ret = format!("{:.precision$E}", f, precision = precision);
|
let mut ret = format!("{:.precision$E}", f, precision = precision);
|
||||||
|
@ -66,12 +66,12 @@ impl fmt::Display for CalculatorError {
|
|||||||
Self::ParseError => write!(f, "Parse error"),
|
Self::ParseError => write!(f, "Parse error"),
|
||||||
Self::PrecisionTooHigh => write!(f, "Precision too high"),
|
Self::PrecisionTooHigh => write!(f, "Precision too high"),
|
||||||
Self::SaveError(None) => write!(f, "Could not save"),
|
Self::SaveError(None) => write!(f, "Could not save"),
|
||||||
Self::SaveError(Some(ConfyError::SerializeTomlError(e))) => {
|
Self::SaveError(Some(ConfyError::SerializeYamlError(e))) => {
|
||||||
write!(f, "Save serialization error: {}", e)
|
write!(f, "Save serialization error: {}", e)
|
||||||
}
|
}
|
||||||
Self::SaveError(Some(e)) => write!(f, "Could not save: {}", e),
|
Self::SaveError(Some(e)) => write!(f, "Could not save: {}", e),
|
||||||
Self::LoadError(None) => write!(f, "Could not load"),
|
Self::LoadError(None) => write!(f, "Could not load"),
|
||||||
Self::LoadError(Some(ConfyError::SerializeTomlError(e))) => {
|
Self::LoadError(Some(ConfyError::SerializeYamlError(e))) => {
|
||||||
write!(f, "Load serialization error: {}", e)
|
write!(f, "Load serialization error: {}", e)
|
||||||
}
|
}
|
||||||
Self::LoadError(Some(e)) => write!(f, "Could not load: {}", e),
|
Self::LoadError(Some(e)) => write!(f, "Could not load: {}", e),
|
||||||
|
@ -28,6 +28,7 @@ pub enum ArithmeticOperation {
|
|||||||
pub enum CalculatorOperation {
|
pub enum CalculatorOperation {
|
||||||
ArithmeticOperation(ArithmeticOperation),
|
ArithmeticOperation(ArithmeticOperation),
|
||||||
BuildVector,
|
BuildVector,
|
||||||
|
BuildMatrix,
|
||||||
Undo,
|
Undo,
|
||||||
Redo,
|
Redo,
|
||||||
Drop,
|
Drop,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user