From 378334a1f111bbb98e6b77d1f01242d21fa19ed3 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Thu, 13 Jun 2024 16:25:45 +0100 Subject: [PATCH 01/55] Add initial Rust ports. --- Cargo.lock | 402 ++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 24 +++ src/expression.rs | 36 +++++ src/lib.rs | 41 +++++ src/libs.rs | 16 ++ src/main.rs | 10 ++ src/symbols.rs | 45 ++++++ 7 files changed, 574 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/expression.rs create mode 100644 src/lib.rs create mode 100644 src/libs.rs create mode 100644 src/main.rs create mode 100644 src/symbols.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..0f84cea --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,402 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pyo3" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "parking_lot", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + +[[package]] +name = "qadence2-expressions" +version = "0.1.0" +dependencies = [ + "num", + "pyo3", + "strum", + "strum_macros", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" + +[[package]] +name = "strum_macros" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7993a8e3a9e88a00351486baae9522c91b123a088f76469e5bd5cc17198ea87" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unindent" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b50763b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "qadence2-expressions" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +# The name of the native library. This is the name which will be used in Python to import the +# library (i.e. `import string_sum`). If you change this, you must also change the name of the +# `#[pymodule]` in `src/lib.rs`. +name = "pyexpression" +# "cdylib" is necessary to produce a shared library for Python to import from. +# +# Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able +# to `use string_sum;` unless the "rlib" or "lib" crate type is also included, e.g.: +# crate-type = ["cdylib", "rlib"] +crate-type = ["cdylib"] + +[dependencies] +num = "0.4.3" +pyo3 = "0.21.2" +strum = "0.26.2" +strum_macros = "0.26.3" diff --git a/src/expression.rs b/src/expression.rs new file mode 100644 index 0000000..edbca16 --- /dev/null +++ b/src/expression.rs @@ -0,0 +1,36 @@ +pub enum Operator { + ADD, + MUL, + NONCOMMUTE, + POWER, + CALL, +} + + +impl Operator { + pub fn as_str(&self) -> &'static str { + match self { + Operator::ADD => "+", + Operator::MUL => "*", + Operator::NONCOMMUTE => "@", + Operator::POWER => "^", + Operator::CALL => "call", + } + } +} + + +#[cfg(test)] +mod tests { + // Note this useful idiom: importing names from outer (for mod tests) scope. + use super::*; + + #[test] + fn test_operator_as_str() { + assert_eq!(Operator::ADD.as_str(), "+"); + assert_eq!(Operator::MUL.as_str(), "*"); + assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); + assert_eq!(Operator::POWER.as_str(), "^"); + assert_eq!(Operator::CALL.as_str(), "call"); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..12190bf --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,41 @@ +use pyo3::prelude::*; + +mod expression; +// use expression::Operator; + +#[pyclass] +pub enum Operator { + ADD, + MUL, + NONCOMMUTE, + POWER, + CALL, +} + +impl Operator { + pub fn as_str(&self) -> &'static str { + match self { + Operator::ADD => "+", + Operator::MUL => "*", + Operator::NONCOMMUTE => "@", + Operator::POWER => "^", + Operator::CALL => "call", + } + } +} + + +/// Formats the sum of two numbers as string. +#[pyfunction] +fn operator() -> PyResult<&'static str> { + Ok(Operator::ADD.as_str()) +} + +/// A Python module implemented in Rust. The name of this function must match +/// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to +/// import the module. +#[pymodule] +fn pyexpression(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(wrap_pyfunction!(operator, m)?)?; + Ok(()) +} diff --git a/src/libs.rs b/src/libs.rs new file mode 100644 index 0000000..ce1206a --- /dev/null +++ b/src/libs.rs @@ -0,0 +1,16 @@ +use pyo3::prelude::*; + +/// Formats the sum of two numbers as string. +#[pyfunction] +fn sum_as_string(a: usize, b: usize) -> PyResult { + Ok((a + b).to_string()) +} + +/// A Python module implemented in Rust. The name of this function must match +/// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to +/// import the module. +#[pymodule] +fn qadence2_expressions(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; + Ok(()) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..740f963 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,10 @@ +mod expression; +use expression::Operator; +mod symbols; +use symbols::Numeric; + + +fn main() { + println!("Hello, world!"); + println!("{}", Operator::ADD.as_str()); +} diff --git a/src/symbols.rs b/src/symbols.rs new file mode 100644 index 0000000..b708cac --- /dev/null +++ b/src/symbols.rs @@ -0,0 +1,45 @@ +use num::Complex; +use std::ops; + +pub enum Numerical { + Int(i64), + Float(f64), + Complex(Complex), +} + +pub enum Numeric { + Int(i64), + Float(f64), + Complex(Complex), +} + +impl ops::Add for Numeric { + // type Output = FooBar; + + fn add(self, _rhs: Numeric) -> Numeric { + println!("> Foo.add(Bar) was called"); + self + _rhs + } +} + + + +pub struct Symbol { + name: &'static str +} + + +#[cfg(test)] +mod tests { + // Note this useful idiom: importing names from outer (for mod tests) scope. + use super::*; + + #[test] + fn test_numeric() { + assert_eq!(Operator::ADD.as_str(), "+"); + // assert_eq!(Operator::MUL.as_str(), "*"); + // assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); + // assert_eq!(Operator::POWER.as_str(), "^"); + // assert_eq!(Operator::CALL.as_str(), "call"); + } +} From 94583274fc493cf21c194f95b13d96de3ac3a92a Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Thu, 13 Jun 2024 16:26:01 +0100 Subject: [PATCH 02/55] Update gitignore. --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index b6f2e35..cb73f1e 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,9 @@ runs/ # Mkdocs site/ + + +# Added by cargo + +/target +*.so \ No newline at end of file From 4567d50a22a37cac31cbd3300f7e682a9ea86074 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Thu, 13 Jun 2024 17:54:23 +0100 Subject: [PATCH 03/55] Attempt to define a Numeric type. --- src/symbols.rs | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index b708cac..ea4b0d2 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -1,27 +1,38 @@ use num::Complex; -use std::ops; +use std::ops::Add; -pub enum Numerical { - Int(i64), - Float(f64), - Complex(Complex), -} +#[derive(Debug)] pub enum Numeric { Int(i64), Float(f64), Complex(Complex), } -impl ops::Add for Numeric { - // type Output = FooBar; - - fn add(self, _rhs: Numeric) -> Numeric { - println!("> Foo.add(Bar) was called"); - self + _rhs +impl Add for Numeric { + type Output = Numeric; + + fn add(self, rhs: Self) -> Self { + match (self, rhs) { + (Numeric::Int(i1), Numeric::Int(i2)) => Numeric::Int(i1 + i2), + (Numeric::Int(i1), Numeric::Float(f2)) => Numeric::Float(i1 as f64 + f2), + (Numeric::Int(i1), Numeric::Complex(c2)) => Numeric::Complex(Complex::new(i1 as f64, 0.) + c2), + (Numeric::Float(f1), Numeric::Int(i2)) => Numeric::Float(f1 + i2 as f64), + (Numeric::Float(f1), Numeric::Float(f2)) => Numeric::Float(f1 + f2), + (Numeric::Float(f1), Numeric::Complex(c2)) => Numeric::Complex(Complex::new(f1,0.) + c2), + (Numeric::Complex(c1), Numeric::Int(i2)) => Numeric::Complex(c1 + Complex::new(i2 as f64,0.)), + (Numeric::Complex(c1), Numeric::Float(f2)) => Numeric::Complex(c1 + Complex::new(f2, 0.)), + (Numeric::Complex(c1), Numeric::Complex(c2)) => Numeric::Complex(c1+c2), + + } } } +impl PartialEq for Numeric { + fn eq(&self, other: &Numeric) -> bool { + self == other + } +} pub struct Symbol { @@ -36,7 +47,7 @@ mod tests { #[test] fn test_numeric() { - assert_eq!(Operator::ADD.as_str(), "+"); + // assert_eq!(Numeric::Int(1)+Numeric::Int(2), Numeric::Int(2)); // assert_eq!(Operator::MUL.as_str(), "*"); // assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); // assert_eq!(Operator::POWER.as_str(), "^"); From 36d767686741921ebfdf4f2d5cc7c3f7283a9c64 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 09:13:00 +0100 Subject: [PATCH 04/55] Add PartialEq trait for equality checking. --- src/symbols.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/symbols.rs b/src/symbols.rs index ea4b0d2..4ad47d8 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -2,7 +2,7 @@ use num::Complex; use std::ops::Add; -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Numeric { Int(i64), Float(f64), From 595f04545fae22065052ad8015692f1d24e90c0f Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 09:13:37 +0100 Subject: [PATCH 05/55] Remove obsolete code and refactor Symbol struct. --- src/symbols.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 4ad47d8..893070b 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -28,16 +28,8 @@ impl Add for Numeric { } } -impl PartialEq for Numeric { - fn eq(&self, other: &Numeric) -> bool { - self == other - } -} - - -pub struct Symbol { - name: &'static str -} +#[derive(Debug, PartialEq)] +pub struct Symbol (&'static str); #[cfg(test)] From 53a5c9cc6aab7dffd4b87a78e2538e28bbec57af Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 09:45:51 +0100 Subject: [PATCH 06/55] Convenience functions to construct enum variants. --- src/symbols.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/symbols.rs b/src/symbols.rs index 893070b..4a6d3ec 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -9,6 +9,22 @@ pub enum Numeric { Complex(Complex), } +impl Numeric { + /// Convenience method to create a Numeric::Int + pub fn int(value: i64) -> Self { + Numeric::Int(value) + } + + /// Convenience method to create a Numeric::Float + pub fn float(value: f64) -> Self { + Numeric::Float(value) + } + + /// Convenience method to create a Numeric::Complex + pub fn complex(re: f64, im: f64) -> Self { + Numeric::Complex(Complex::new(re, im)) + } +} impl Add for Numeric { type Output = Numeric; From 2f3dc7307e36d6def932a0c83ce1128002a2a1a6 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 09:46:24 +0100 Subject: [PATCH 07/55] Complete tests for add op. --- src/symbols.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 6 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 4a6d3ec..e3635db 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -25,6 +25,7 @@ impl Numeric { Numeric::Complex(Complex::new(re, im)) } } + impl Add for Numeric { type Output = Numeric; @@ -54,11 +55,89 @@ mod tests { use super::*; #[test] - fn test_numeric() { - // assert_eq!(Numeric::Int(1)+Numeric::Int(2), Numeric::Int(2)); - // assert_eq!(Operator::MUL.as_str(), "*"); - // assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); - // assert_eq!(Operator::POWER.as_str(), "^"); - // assert_eq!(Operator::CALL.as_str(), "call"); + fn test_add_int_to_int() { + let n1 = Numeric::int(5); + let n2 = Numeric::int(10); + assert_eq!(n1 + n2, Numeric::int(15)); + } + + #[test] + fn test_add_int_to_float() { + let n1 = Numeric::int(5); + let n2 = Numeric::float(10.5); + assert_eq!(n1 + n2, Numeric::float(15.5)); + } + + #[test] + fn test_add_int_to_complex() { + let n1 = Numeric::int(5); + let n2 = Numeric::complex(10.0, 5.0); + assert_eq!(n1 + n2, Numeric::complex(15.0, 5.0)); + } + + #[test] + fn test_add_float_to_int() { + let n1 = Numeric::float(5.0); + let n2 = Numeric::int(10); + assert_eq!(n1 + n2, Numeric::float(15.0)); + } + + #[test] + fn test_add_float_to_float() { + let n1 = Numeric::float(5.0); + let n2 = Numeric::float(10.0); + assert_eq!(n1 + n2, Numeric::float(15.0)); } + + #[test] + fn test_add_float_to_complex() { + let n1 = Numeric::float(5.0); + let n2 = Numeric::complex(3.0, 4.0); + assert_eq!(n1 + n2, Numeric::complex(8.0, 4.0)); + } + + #[test] + fn test_add_complex_to_int() { + let n1 = Numeric::complex(5.0, 4.0); + let n2 = Numeric::int(3); + assert_eq!(n1 + n2, Numeric::complex(8.0, 4.0)); + } + + #[test] + fn test_add_complex_to_float() { + let n1 = Numeric::complex(5.0, 4.0); + let n2 = Numeric::float(3.0); + assert_eq!(n1 + n2, Numeric::complex(8.0, 4.0)); + } + + #[test] + fn test_add_complex_to_complex() { + let n1 = Numeric::complex(5.0, 4.0); + let n2 = Numeric::complex(3.0, 2.0); + assert_eq!(n1 + n2, Numeric::complex(8.0, 6.0)); + } + + // #[test] + // fn test_eq_int_and_float() { + // let n1 = Numeric::Int(5); + // let n2 = Numeric::Float(5.0); + // assert_eq!(n1, n2); + // } + + // #[test] + // fn test_eq_complex_and_int() { + // let n1 = Numeric::Complex(Complex::new(5.0, 0.0)); + // let n2 = Numeric::Int(5); + // assert_eq!(n1, n2); + // } + + + // #[test] + // fn test_numeric() { + // // assert_eq!(Numeric::Int(1)+Numeric::Int(2), Numeric::Int(2)); + // // assert_eq!(Operator::MUL.as_str(), "*"); + // // assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); + // // assert_eq!(Operator::POWER.as_str(), "^"); + // // assert_eq!(Operator::CALL.as_str(), "call"); + // } } From 490bccfe80ba479e1d8f0f67bedfb46fc8ed948a Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:19:27 +0100 Subject: [PATCH 08/55] To implement the Display trait. --- src/symbols.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/symbols.rs b/src/symbols.rs index e3635db..04734c1 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -1,5 +1,6 @@ use num::Complex; use std::ops::Add; +use std::fmt; #[derive(Debug, PartialEq)] From 428ae91acf90e9f1f2f56c98cc21fd492e44338a Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:20:06 +0100 Subject: [PATCH 09/55] Correct name. --- src/symbols.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 04734c1..30e34ac 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -4,26 +4,26 @@ use std::fmt; #[derive(Debug, PartialEq)] -pub enum Numeric { +pub enum Numerical { Int(i64), Float(f64), Complex(Complex), } -impl Numeric { - /// Convenience method to create a Numeric::Int +impl Numerical { + /// Convenience method to create a Numerical::Int pub fn int(value: i64) -> Self { - Numeric::Int(value) + Numerical::Int(value) } - /// Convenience method to create a Numeric::Float + /// Convenience method to create a Numerical::Float pub fn float(value: f64) -> Self { - Numeric::Float(value) + Numerical::Float(value) } - /// Convenience method to create a Numeric::Complex + /// Convenience method to create a Numerical::Complex pub fn complex(re: f64, im: f64) -> Self { - Numeric::Complex(Complex::new(re, im)) + Numerical::Complex(Complex::new(re, im)) } } From a0d733c1b72ae13164f148448d0c40308e2ad813 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:21:35 +0100 Subject: [PATCH 10/55] Implement Display trait for Numerical. --- src/symbols.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 30e34ac..b471786 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -27,8 +27,16 @@ impl Numerical { } } -impl Add for Numeric { - type Output = Numeric; +impl fmt::Display for Numerical { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Numerical::Int(value) => write!(f, "{}", value), + Numerical::Float(value) => write!(f, "{}", value), + Numerical::Complex(value) => write!(f, "{} + {}i", value.re, value.im), + } + } +} + fn add(self, rhs: Self) -> Self { match (self, rhs) { From 352447b3376cf74c8615bca941ac469d1f515181 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:22:04 +0100 Subject: [PATCH 11/55] Correct name. --- src/symbols.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index b471786..38da8d6 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -37,19 +37,20 @@ impl fmt::Display for Numerical { } } +impl Add for Numerical { + type Output = Numerical; fn add(self, rhs: Self) -> Self { match (self, rhs) { - (Numeric::Int(i1), Numeric::Int(i2)) => Numeric::Int(i1 + i2), - (Numeric::Int(i1), Numeric::Float(f2)) => Numeric::Float(i1 as f64 + f2), - (Numeric::Int(i1), Numeric::Complex(c2)) => Numeric::Complex(Complex::new(i1 as f64, 0.) + c2), - (Numeric::Float(f1), Numeric::Int(i2)) => Numeric::Float(f1 + i2 as f64), - (Numeric::Float(f1), Numeric::Float(f2)) => Numeric::Float(f1 + f2), - (Numeric::Float(f1), Numeric::Complex(c2)) => Numeric::Complex(Complex::new(f1,0.) + c2), - (Numeric::Complex(c1), Numeric::Int(i2)) => Numeric::Complex(c1 + Complex::new(i2 as f64,0.)), - (Numeric::Complex(c1), Numeric::Float(f2)) => Numeric::Complex(c1 + Complex::new(f2, 0.)), - (Numeric::Complex(c1), Numeric::Complex(c2)) => Numeric::Complex(c1+c2), - + (Numerical::Int(i1), Numerical::Int(i2)) => Numerical::Int(i1 + i2), + (Numerical::Int(i1), Numerical::Float(f2)) => Numerical::Float(i1 as f64 + f2), + (Numerical::Int(i1), Numerical::Complex(c2)) => Numerical::Complex(Complex::new(i1 as f64, 0.) + c2), + (Numerical::Float(f1), Numerical::Int(i2)) => Numerical::Float(f1 + i2 as f64), + (Numerical::Float(f1), Numerical::Float(f2)) => Numerical::Float(f1 + f2), + (Numerical::Float(f1), Numerical::Complex(c2)) => Numerical::Complex(Complex::new(f1, 0.) + c2), + (Numerical::Complex(c1), Numerical::Int(i2)) => Numerical::Complex(c1 + Complex::new(i2 as f64,0.)), + (Numerical::Complex(c1), Numerical::Float(f2)) => Numerical::Complex(c1 + Complex::new(f2, 0.)), + (Numerical::Complex(c1), Numerical::Complex(c2)) => Numerical::Complex(c1+c2), } } } From fd30713d9d103d1a4e911ca21de3aa3d1baf7e69 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:23:09 +0100 Subject: [PATCH 12/55] Correct name for tests. --- src/symbols.rs | 82 +++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 38da8d6..84aff13 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -65,86 +65,86 @@ mod tests { use super::*; #[test] - fn test_add_int_to_int() { - let n1 = Numeric::int(5); - let n2 = Numeric::int(10); - assert_eq!(n1 + n2, Numeric::int(15)); + fn test_numerical_add_int_to_int() { + let n1 = Numerical::int(5); + let n2 = Numerical::int(10); + assert_eq!(n1 + n2, Numerical::int(15)); } #[test] - fn test_add_int_to_float() { - let n1 = Numeric::int(5); - let n2 = Numeric::float(10.5); - assert_eq!(n1 + n2, Numeric::float(15.5)); + fn test_numerical_add_int_to_float() { + let n1 = Numerical::int(5); + let n2 = Numerical::float(10.5); + assert_eq!(n1 + n2, Numerical::float(15.5)); } #[test] - fn test_add_int_to_complex() { - let n1 = Numeric::int(5); - let n2 = Numeric::complex(10.0, 5.0); - assert_eq!(n1 + n2, Numeric::complex(15.0, 5.0)); + fn test_numerical_add_int_to_complex() { + let n1 = Numerical::int(5); + let n2 = Numerical::complex(10.0, 5.0); + assert_eq!(n1 + n2, Numerical::complex(15.0, 5.0)); } #[test] - fn test_add_float_to_int() { - let n1 = Numeric::float(5.0); - let n2 = Numeric::int(10); - assert_eq!(n1 + n2, Numeric::float(15.0)); + fn test_numerical_add_float_to_int() { + let n1 = Numerical::float(5.0); + let n2 = Numerical::int(10); + assert_eq!(n1 + n2, Numerical::float(15.0)); } #[test] - fn test_add_float_to_float() { - let n1 = Numeric::float(5.0); - let n2 = Numeric::float(10.0); - assert_eq!(n1 + n2, Numeric::float(15.0)); + fn test_numerical_add_float_to_float() { + let n1 = Numerical::float(5.0); + let n2 = Numerical::float(10.0); + assert_eq!(n1 + n2, Numerical::float(15.0)); } #[test] - fn test_add_float_to_complex() { - let n1 = Numeric::float(5.0); - let n2 = Numeric::complex(3.0, 4.0); - assert_eq!(n1 + n2, Numeric::complex(8.0, 4.0)); + fn test_numerical_add_float_to_complex() { + let n1 = Numerical::float(5.0); + let n2 = Numerical::complex(3.0, 4.0); + assert_eq!(n1 + n2, Numerical::complex(8.0, 4.0)); } #[test] - fn test_add_complex_to_int() { - let n1 = Numeric::complex(5.0, 4.0); - let n2 = Numeric::int(3); - assert_eq!(n1 + n2, Numeric::complex(8.0, 4.0)); + fn test_numerical_add_complex_to_int() { + let n1 = Numerical::complex(5.0, 4.0); + let n2 = Numerical::int(3); + assert_eq!(n1 + n2, Numerical::complex(8.0, 4.0)); } #[test] - fn test_add_complex_to_float() { - let n1 = Numeric::complex(5.0, 4.0); - let n2 = Numeric::float(3.0); - assert_eq!(n1 + n2, Numeric::complex(8.0, 4.0)); + fn test_numerical_add_complex_to_float() { + let n1 = Numerical::complex(5.0, 4.0); + let n2 = Numerical::float(3.0); + assert_eq!(n1 + n2, Numerical::complex(8.0, 4.0)); } #[test] - fn test_add_complex_to_complex() { - let n1 = Numeric::complex(5.0, 4.0); - let n2 = Numeric::complex(3.0, 2.0); - assert_eq!(n1 + n2, Numeric::complex(8.0, 6.0)); + fn test_numerical_add_complex_to_complex() { + let n1 = Numerical::complex(5.0, 4.0); + let n2 = Numerical::complex(3.0, 2.0); + assert_eq!(n1 + n2, Numerical::complex(8.0, 6.0)); } // #[test] // fn test_eq_int_and_float() { - // let n1 = Numeric::Int(5); - // let n2 = Numeric::Float(5.0); + // let n1 = Numerical::Int(5); + // let n2 = Numerical::Float(5.0); // assert_eq!(n1, n2); // } // #[test] // fn test_eq_complex_and_int() { - // let n1 = Numeric::Complex(Complex::new(5.0, 0.0)); - // let n2 = Numeric::Int(5); + // let n1 = Numerical::Complex(Complex::new(5.0, 0.0)); + // let n2 = Numerical::Int(5); // assert_eq!(n1, n2); // } // #[test] // fn test_numeric() { - // // assert_eq!(Numeric::Int(1)+Numeric::Int(2), Numeric::Int(2)); + // // assert_eq!(Numerical::Int(1)+Numerical::Int(2), Numerical::Int(2)); // // assert_eq!(Operator::MUL.as_str(), "*"); // // assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); // // assert_eq!(Operator::POWER.as_str(), "^"); From 6f2785bd5a20c7e689a0f8f78a9985b4a9bcc58d Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:23:34 +0100 Subject: [PATCH 13/55] Update package name. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f84cea..9e9595e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -244,7 +244,7 @@ dependencies = [ ] [[package]] -name = "qadence2-expressions" +name = "qadence2_expressions" version = "0.1.0" dependencies = [ "num", diff --git a/Cargo.toml b/Cargo.toml index b50763b..14e8413 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "qadence2-expressions" +name = "qadence2_expressions" version = "0.1.0" edition = "2021" From 73b558a18597cfe43345f3d8315a76c940ebae43 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:23:57 +0100 Subject: [PATCH 14/55] Export modules for access throughout the package. --- src/lib.rs | 71 +++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 12190bf..28af4aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,41 +1,42 @@ -use pyo3::prelude::*; +// use pyo3::prelude::*; -mod expression; -// use expression::Operator; +pub mod operator; +pub mod symbols; +pub mod expression; -#[pyclass] -pub enum Operator { - ADD, - MUL, - NONCOMMUTE, - POWER, - CALL, -} +// #[pyclass] +// pub enum Operator { +// ADD, +// MUL, +// NONCOMMUTE, +// POWER, +// CALL, +// } -impl Operator { - pub fn as_str(&self) -> &'static str { - match self { - Operator::ADD => "+", - Operator::MUL => "*", - Operator::NONCOMMUTE => "@", - Operator::POWER => "^", - Operator::CALL => "call", - } - } -} +// impl Operator { +// pub fn as_str(&self) -> &'static str { +// match self { +// Operator::ADD => "+", +// Operator::MUL => "*", +// Operator::NONCOMMUTE => "@", +// Operator::POWER => "^", +// Operator::CALL => "call", +// } +// } +// } -/// Formats the sum of two numbers as string. -#[pyfunction] -fn operator() -> PyResult<&'static str> { - Ok(Operator::ADD.as_str()) -} +// /// Formats the sum of two numbers as string. +// #[pyfunction] +// fn operator() -> PyResult<&'static str> { +// Ok(Operator::ADD.as_str()) +// } -/// A Python module implemented in Rust. The name of this function must match -/// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to -/// import the module. -#[pymodule] -fn pyexpression(m: &Bound<'_, PyModule>) -> PyResult<()> { - m.add_function(wrap_pyfunction!(operator, m)?)?; - Ok(()) -} +// /// A Python module implemented in Rust. The name of this function must match +// /// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to +// /// import the module. +// #[pymodule] +// fn pyexpression(m: &Bound<'_, PyModule>) -> PyResult<()> { +// m.add_function(wrap_pyfunction!(operator, m)?)?; +// Ok(()) +// } From cfdd2f7651f9931e2cdbb9c8486bcb2f47e918f2 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:26:05 +0100 Subject: [PATCH 15/55] Add new module. --- src/operator.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/operator.rs diff --git a/src/operator.rs b/src/operator.rs new file mode 100644 index 0000000..e2c849e --- /dev/null +++ b/src/operator.rs @@ -0,0 +1,36 @@ +#[derive(Debug, PartialEq)] +pub enum Operator { + ADD, + MUL, + NONCOMMUTE, + POWER, + CALL, +} + +impl Operator { + pub fn as_str(&self) -> &'static str { + match self { + Operator::ADD => "+", + Operator::MUL => "*", + Operator::NONCOMMUTE => "@", + Operator::POWER => "^", + Operator::CALL => "call", + } + } +} + + +#[cfg(test)] +mod tests { + // Note this useful idiom: importing names from outer (for mod tests) scope. + use super::*; + + #[test] + fn test_operator_as_str() { + assert_eq!(Operator::ADD.as_str(), "+"); + assert_eq!(Operator::MUL.as_str(), "*"); + assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); + assert_eq!(Operator::POWER.as_str(), "^"); + assert_eq!(Operator::CALL.as_str(), "call"); + } +} From 5aee7c9721a52af62c040d0b7ddc03b6685ed1df Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:26:40 +0100 Subject: [PATCH 16/55] Implement Expression with Add and tests. --- src/expression.rs | 187 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 164 insertions(+), 23 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index edbca16..e5361cc 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -1,36 +1,177 @@ -pub enum Operator { - ADD, - MUL, - NONCOMMUTE, - POWER, - CALL, +use crate::operator::Operator; +use crate::symbols::{Numerical,Symbol}; + +use std::ops::Add; +use num::Complex; + + +#[derive(Debug, PartialEq)] +pub enum Expression { + Symbol(&'static str), + Value(Numerical), + Expr { head: Operator, args: Vec> }, } +// Implement helper functions to create different types of Expressions. +impl Expression { + pub fn symbol(name: &'static str) -> Self { + Expression::Symbol(name) + } + + pub fn int(value: i64) -> Self { + Expression::Value(Numerical::int(value)) + } -impl Operator { - pub fn as_str(&self) -> &'static str { - match self { - Operator::ADD => "+", - Operator::MUL => "*", - Operator::NONCOMMUTE => "@", - Operator::POWER => "^", - Operator::CALL => "call", - } + pub fn float(value: f64) -> Self { + Expression::Value(Numerical::float(value)) + } + + pub fn complex(real: f64, imag: f64) -> Self { + Expression::Value(Numerical::complex(real, imag)) } } +impl Add for Expression { + type Output = Expression; + + fn add(self, rhs: Self) -> Self::Output { + // If both sides are Numerical, add them directly + match (self, rhs) { + (Expression::Value(lhs), Expression::Value(rhs)) => { + Expression::Value(lhs + rhs) + } + // For other cases, create an Expression::Expr with Operator::Add + (lhs, rhs) => Expression::Expr { + head: Operator::ADD, + args: vec![Box::new(lhs), Box::new(rhs)], + }, + } + } +} #[cfg(test)] mod tests { - // Note this useful idiom: importing names from outer (for mod tests) scope. - use super::*; + use super::*; // This imports everything from the parent module + + #[test] + fn test_symbol_expression() { + let symbol_expr = Expression::symbol("x"); + assert_eq!(symbol_expr, Expression::Symbol("x")); + } + + #[test] + fn test_int_expression() { + let int_expr = Expression::int(42); + assert_eq!(int_expr, Expression::Value(Numerical::Int(42))); + } + + #[test] + fn test_float_expression() { + let float_expr = Expression::float(3.14); + assert_eq!(float_expr, Expression::Value(Numerical::Float(3.14))); + } + + #[test] + fn test_complex_expression() { + let complex_expr = Expression::complex(1.0, 2.0); + assert_eq!(complex_expr, Expression::Value(Numerical::Complex(Complex::new(1.0, 2.0)))); + } + + #[test] + fn test_expression_add_int_to_int() { + let expr1 = Expression::int(1); + let expr2 = Expression::int(2); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Int(3))); + } + + #[test] + fn test_expression_add_int_to_float() { + let expr1 = Expression::int(1); + let expr2 = Expression::float(2.0); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + } + + #[test] + fn test_expression_add_int_to_complex() { + let expr1 = Expression::int(1); + let expr2 = Expression::complex(2.0, 4.0); + let result = expr1 + expr2; + assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); + } + + #[test] + fn test_expression_add_float_to_int() { + let expr1 = Expression::float(1.0); + let expr2 = Expression::int(2); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + } + #[test] - fn test_operator_as_str() { - assert_eq!(Operator::ADD.as_str(), "+"); - assert_eq!(Operator::MUL.as_str(), "*"); - assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); - assert_eq!(Operator::POWER.as_str(), "^"); - assert_eq!(Operator::CALL.as_str(), "call"); + fn test_expression_add_float_to_float() { + let expr1 = Expression::float(1.0); + let expr2 = Expression::float(2.0); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + } + + #[test] + fn test_expression_add_float_to_complex() { + let expr1 = Expression::float(1.0); + let expr2 = Expression::complex(2.0, 4.0); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); + } + + #[test] + fn test_expression_add_complex_to_int() { + let expr1 = Expression::complex(1.0, 2.0); + let expr2 = Expression::int(2); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); + } + + #[test] + fn test_expression_add_complex_to_float() { + let expr1 = Expression::complex(1.0, 2.0); + let expr2 = Expression::float(2.0); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); + } + + #[test] + fn test_expression_add_complex_to_complex() { + let expr1 = Expression::complex(1.0, 2.0); + let expr2 = Expression::complex(3.0, 4.0); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(4.0, 6.0)))); + } + + #[test] + fn test_expression_add_symbol_to_int() { + let symbol_expr = Expression::symbol("x"); + let expr2 = Expression::int(1); + let result = symbol_expr + expr2; + + match result { + Expression::Expr { head, args } => { + assert_eq!(head, Operator::ADD); + assert_eq!(*args[0], Expression::Symbol("x")); + assert_eq!(*args[1], Expression::Value(Numerical::Int(1))); + } + _ => panic!("Expected an Expression::Expr with Operator::ADD"), + } + } } From 6bd9c9f828d4be9f8795079d5b8da945737d488f Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Fri, 14 Jun 2024 17:27:26 +0100 Subject: [PATCH 17/55] Comment obsolete code. --- src/main.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 740f963..63cf1fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,6 @@ -mod expression; -use expression::Operator; -mod symbols; -use symbols::Numeric; - +// use crate::operator::Operator; fn main() { println!("Hello, world!"); - println!("{}", Operator::ADD.as_str()); + // println!("{}", Operator::ADD.as_str()); } From cdcf38f91b142b2ac887e28ab965eb891718ccc0 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Sun, 16 Jun 2024 17:21:49 +0100 Subject: [PATCH 18/55] Implement arithmetic ops for Numerical using a macro. --- src/symbols.rs | 54 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 84aff13..fa058ad 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -1,5 +1,5 @@ use num::Complex; -use std::ops::Add; +use std::ops::{Add, Div, Mul, Sub}; use std::fmt; @@ -37,24 +37,44 @@ impl fmt::Display for Numerical { } } -impl Add for Numerical { - type Output = Numerical; - - fn add(self, rhs: Self) -> Self { - match (self, rhs) { - (Numerical::Int(i1), Numerical::Int(i2)) => Numerical::Int(i1 + i2), - (Numerical::Int(i1), Numerical::Float(f2)) => Numerical::Float(i1 as f64 + f2), - (Numerical::Int(i1), Numerical::Complex(c2)) => Numerical::Complex(Complex::new(i1 as f64, 0.) + c2), - (Numerical::Float(f1), Numerical::Int(i2)) => Numerical::Float(f1 + i2 as f64), - (Numerical::Float(f1), Numerical::Float(f2)) => Numerical::Float(f1 + f2), - (Numerical::Float(f1), Numerical::Complex(c2)) => Numerical::Complex(Complex::new(f1, 0.) + c2), - (Numerical::Complex(c1), Numerical::Int(i2)) => Numerical::Complex(c1 + Complex::new(i2 as f64,0.)), - (Numerical::Complex(c1), Numerical::Float(f2)) => Numerical::Complex(c1 + Complex::new(f2, 0.)), - (Numerical::Complex(c1), Numerical::Complex(c2)) => Numerical::Complex(c1+c2), - } - } +macro_rules! impl_binary_operator { + ($binop:ident, $method:ident) => { + impl $binop for Numerical { + type Output = Self; + + fn $method(self, other: Self) -> Self { + use Numerical::*; + use num::Complex as complex; + + match (self, other) { + // Complex and Complex + (Complex(a), Complex(b)) => Complex(a.$method(b)), + + // Complex with Float or Int + (Complex(a), Float(b)) | (Float(b), Complex(a)) => Complex(a.$method(complex::from(b))), + (Complex(a), Int(b)) | (Int(b), Complex(a)) => Complex(a.$method(complex::from(b as f64))), + + // Float and Float + (Float(a), Float(b)) => Float(a.$method(b)), + + // Float with Int + (Float(a), Int(b)) => Float(a.$method(b as f64)), + (Int(a), Float(b)) => Float((a as f64).$method(b)), + + // Int and Int + (Int(a), Int(b)) => Int(a.$method(b)), + } + } + } + }; } +// Implement the binary operators for Numerical using the macro +impl_binary_operator!(Add, add); +impl_binary_operator!(Sub, sub); +impl_binary_operator!(Mul, mul); +impl_binary_operator!(Div, div); + #[derive(Debug, PartialEq)] pub struct Symbol (&'static str); From a354f0657d90b6c94a80dd7cc71a64a1b8052480 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Mon, 17 Jun 2024 15:10:03 +0100 Subject: [PATCH 19/55] Implement macro for binary operators in expressions. --- src/expression.rs | 77 ++++++++++++++++++++++++++++++++++++++--------- src/operator.rs | 1 + src/symbols.rs | 10 +++--- 3 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index e5361cc..4e9ca6c 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -31,24 +31,73 @@ impl Expression { } } -impl Add for Expression { - type Output = Expression; - - fn add(self, rhs: Self) -> Self::Output { - // If both sides are Numerical, add them directly - match (self, rhs) { - (Expression::Value(lhs), Expression::Value(rhs)) => { - Expression::Value(lhs + rhs) +// impl Add for Expression { +// type Output = Expression; + +// fn add(self, rhs: Self) -> Self::Output { +// // If both sides are Numerical, add them directly +// match (self, rhs) { +// (Expression::Value(lhs), Expression::Value(rhs)) => { +// Expression::Value(lhs + rhs) +// } +// // For other cases, create an Expression::Expr with Operator::Add +// (lhs, rhs) => Expression::Expr { +// head: Operator::ADD, +// args: vec![Box::new(lhs), Box::new(rhs)], +// }, +// } +// } +// } + +// Macro to implement binary operators for the Expression enum +macro_rules! impl_binary_operator_for_expression { + ($trait:ident, $method:ident, $operator:expr) => { + impl $trait for Expression { + type Output = Self; + + fn $method(self, other: Self) -> Self::Output { + use Expression::*; + let operator = $operator; + + match (self, other) { + // Numerical values are operated directly. + (Value(lhs), Value(rhs)) => Value(lhs.$method(rhs)), + + // Both are Expressions with the same operator, merge their arguments. + (Expr { head: op_lhs, args: args_lhs }, Expr { head: op_rhs, args: args_rhs }) if op_lhs == operator && op_rhs == operator => { + let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect(); + Expr { head: operator, args } + }, + + // Left side is an Expression with the same operator, append the right side. + (Expr { head: op_lhs, mut args: args_lhs }, rhs) if op_lhs == operator => { + args_lhs.push(Box::new(rhs)); + Expr { head: operator, args: args_lhs } + }, + + // Right side is an Expression with the same operator, prepend the left side. + (lhs, Expr { head: op_rhs, mut args: args_rhs }) if op_rhs == operator => { + args_rhs.insert(0, Box::new(lhs)); + Expr { head: operator, args: args_rhs } + }, + + // Otherwise, create a new Expression::Expr with the given operator. + (lhs, rhs) => Expr { head: operator, args: vec![Box::new(lhs), Box::new(rhs)] }, + } } - // For other cases, create an Expression::Expr with Operator::Add - (lhs, rhs) => Expression::Expr { - head: Operator::ADD, - args: vec![Box::new(lhs), Box::new(rhs)], - }, } - } + }; } +// Applying the macro to implement Add, Sub, Mul, and Div for Expression +impl_expression_operator!(Add, add, Operator::ADD); +impl_expression_operator!(Sub, sub, Operator::SUB); +impl_expression_operator!(Mul, mul, Operator::MUL); +impl_expression_operator!(Div, div, Operator::DIV); + + + + #[cfg(test)] mod tests { use super::*; // This imports everything from the parent module diff --git a/src/operator.rs b/src/operator.rs index e2c849e..4d774e4 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -11,6 +11,7 @@ impl Operator { pub fn as_str(&self) -> &'static str { match self { Operator::ADD => "+", + Operator::MUL => "*", Operator::NONCOMMUTE => "@", Operator::POWER => "^", diff --git a/src/symbols.rs b/src/symbols.rs index fa058ad..cb21f20 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -37,7 +37,7 @@ impl fmt::Display for Numerical { } } -macro_rules! impl_binary_operator { +macro_rules! impl_binary_operator_for_numerical { ($binop:ident, $method:ident) => { impl $binop for Numerical { type Output = Self; @@ -70,10 +70,10 @@ macro_rules! impl_binary_operator { } // Implement the binary operators for Numerical using the macro -impl_binary_operator!(Add, add); -impl_binary_operator!(Sub, sub); -impl_binary_operator!(Mul, mul); -impl_binary_operator!(Div, div); +impl_binary_operator_for_numerical!(Add, add); +impl_binary_operator_for_numerical!(Sub, sub); +impl_binary_operator_for_numerical!(Mul, mul); +impl_binary_operator_for_numerical!(Div, div); #[derive(Debug, PartialEq)] pub struct Symbol (&'static str); From c4bbeccc1c9c52218533990ae79095663a818ae5 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Mon, 17 Jun 2024 17:30:51 +0100 Subject: [PATCH 20/55] More traits to Numerical. --- src/symbols.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/symbols.rs b/src/symbols.rs index cb21f20..928797a 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -3,7 +3,7 @@ use std::ops::{Add, Div, Mul, Sub}; use std::fmt; -#[derive(Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum Numerical { Int(i64), Float(f64), From a2fae8edfb9906f220c7b3410a57f67330f8f556 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Mon, 17 Jun 2024 17:31:10 +0100 Subject: [PATCH 21/55] Better naming. --- src/symbols.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 928797a..49fb253 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -38,8 +38,8 @@ impl fmt::Display for Numerical { } macro_rules! impl_binary_operator_for_numerical { - ($binop:ident, $method:ident) => { - impl $binop for Numerical { + ($trait:ident, $method:ident) => { + impl $trait for Numerical { type Output = Self; fn $method(self, other: Self) -> Self { From d8010b924cba28e1a107b2191a3878da70fc8571 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Mon, 17 Jun 2024 17:31:38 +0100 Subject: [PATCH 22/55] Discriminate binary ops complex <-> int. --- src/symbols.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 49fb253..077737c 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -50,9 +50,12 @@ macro_rules! impl_binary_operator_for_numerical { // Complex and Complex (Complex(a), Complex(b)) => Complex(a.$method(b)), - // Complex with Float or Int + // Complex with Float (Complex(a), Float(b)) | (Float(b), Complex(a)) => Complex(a.$method(complex::from(b))), - (Complex(a), Int(b)) | (Int(b), Complex(a)) => Complex(a.$method(complex::from(b as f64))), + + // Complex with Int + (Complex(a), Int(b)) => Complex(a.$method(complex::from(b as f64))), + (Int(a), Complex(b)) => Complex(complex::from(a as f64).$method(b)), // Float and Float (Float(a), Float(b)) => Float(a.$method(b)), From 0e722b957182c350561ea5ead72f99a2e144c878 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Mon, 17 Jun 2024 17:32:26 +0100 Subject: [PATCH 23/55] More tests to mixed types binary ops. --- src/symbols.rs | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 077737c..53062c1 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -88,31 +88,43 @@ mod tests { use super::*; #[test] - fn test_numerical_add_int_to_int() { - let n1 = Numerical::int(5); - let n2 = Numerical::int(10); - assert_eq!(n1 + n2, Numerical::int(15)); + fn test_numerical_binary_ops_int_to_int() { + let n1 = Numerical::Int(5); + let n2 = Numerical::Int(10); + assert_eq!(n1 + n2, Numerical::Int(15)); + assert_eq!(n1 - n2, Numerical::Int(-5)); + assert_eq!(n1 * n2, Numerical::Int(50)); + assert_eq!(n1 / n2, Numerical::Int(0)); // integer division } #[test] - fn test_numerical_add_int_to_float() { - let n1 = Numerical::int(5); - let n2 = Numerical::float(10.5); - assert_eq!(n1 + n2, Numerical::float(15.5)); + fn test_numerical_binary_ops_int_to_float() { + let n1 = Numerical::Int(5); + let n2 = Numerical::Float(10.5); + assert_eq!(n1 + n2, Numerical::Float(15.5)); + assert_eq!(n1 - n2, Numerical::Float(-5.5)); + assert_eq!(n1 * n2, Numerical::Float(52.5)); + assert_eq!(n1 / n2, Numerical::Float(5.0 / 10.5)); } #[test] - fn test_numerical_add_int_to_complex() { + fn test_numerical_binary_ops_int_to_complex() { let n1 = Numerical::int(5); let n2 = Numerical::complex(10.0, 5.0); - assert_eq!(n1 + n2, Numerical::complex(15.0, 5.0)); + assert_eq!(n1 + n2, Numerical::Complex(Complex::new(15.0, 5.0))); + assert_eq!(n1 - n2, Numerical::Complex(Complex::new(-5.0, -5.0))); + assert_eq!(n1 * n2, Numerical::Complex(Complex::new(50.0, 25.0))); + assert_eq!(n1 / n2, Numerical::Complex(Complex::new(0.4, -0.2))); } #[test] fn test_numerical_add_float_to_int() { let n1 = Numerical::float(5.0); let n2 = Numerical::int(10); - assert_eq!(n1 + n2, Numerical::float(15.0)); + assert_eq!(n1 + n2, Numerical::Float(15.0)); + assert_eq!(n1 - n2, Numerical::Float(-5.0)); + assert_eq!(n1 * n2, Numerical::Float(50.0)); + assert_eq!(n1 / n2, Numerical::Float(0.5)); } #[test] From a78b3a7e5c434d7b41284e55f5280dd6229d418d Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Mon, 17 Jun 2024 17:32:59 +0100 Subject: [PATCH 24/55] More binary op imports. --- src/expression.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expression.rs b/src/expression.rs index 4e9ca6c..84becdd 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -1,7 +1,7 @@ use crate::operator::Operator; use crate::symbols::{Numerical,Symbol}; -use std::ops::Add; +use std::ops::{Add,Div,Mul,Sub}; use num::Complex; From 8a805722e50df6122a20a1329aa021a61b36d878 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Mon, 17 Jun 2024 17:34:07 +0100 Subject: [PATCH 25/55] Correct qualifier. --- src/expression.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index 84becdd..9d25cf9 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -70,13 +70,13 @@ macro_rules! impl_binary_operator_for_expression { }, // Left side is an Expression with the same operator, append the right side. - (Expr { head: op_lhs, mut args: args_lhs }, rhs) if op_lhs == operator => { + (Expr { head: op_lhs, args: mut args_lhs }, rhs) if op_lhs == operator => { args_lhs.push(Box::new(rhs)); Expr { head: operator, args: args_lhs } }, // Right side is an Expression with the same operator, prepend the left side. - (lhs, Expr { head: op_rhs, mut args: args_rhs }) if op_rhs == operator => { + (lhs, Expr { head: op_rhs, args: mut args_rhs }) if op_rhs == operator => { args_rhs.insert(0, Box::new(lhs)); Expr { head: operator, args: args_rhs } }, From a0105546e676aa76d854a4c894b02fcf2f915a7d Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Mon, 17 Jun 2024 17:34:28 +0100 Subject: [PATCH 26/55] Sub and div request specific handling. --- src/expression.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index 9d25cf9..af8279e 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -90,10 +90,10 @@ macro_rules! impl_binary_operator_for_expression { } // Applying the macro to implement Add, Sub, Mul, and Div for Expression -impl_expression_operator!(Add, add, Operator::ADD); -impl_expression_operator!(Sub, sub, Operator::SUB); -impl_expression_operator!(Mul, mul, Operator::MUL); -impl_expression_operator!(Div, div, Operator::DIV); +impl_binary_operator_for_expression!(Add, add, Operator::ADD); +// impl_binary_operator_for_expression!(Sub, sub, Operator::SUB); +impl_binary_operator_for_expression!(Mul, mul, Operator::MUL); +// impl_binary_operator_for_expression!(Div, div, Operator::DIV); From 57936d3aad6093f41ad977d74d4b3675e1241d1d Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Mon, 17 Jun 2024 17:34:53 +0100 Subject: [PATCH 27/55] Better layout and div/sub request specific handling. --- src/operator.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 4d774e4..3961bef 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,21 +1,22 @@ #[derive(Debug, PartialEq)] pub enum Operator { ADD, + CALL, + // DIV, MUL, NONCOMMUTE, POWER, - CALL, + // SUB, } impl Operator { pub fn as_str(&self) -> &'static str { match self { Operator::ADD => "+", - + Operator::CALL => "call", Operator::MUL => "*", Operator::NONCOMMUTE => "@", Operator::POWER => "^", - Operator::CALL => "call", } } } From 0a46ae1e8fa1923dac55459b990104714ad49c88 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 18 Jun 2024 14:16:59 +0100 Subject: [PATCH 28/55] Use push instead of insert. --- src/expression.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expression.rs b/src/expression.rs index af8279e..28e99db 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -77,7 +77,7 @@ macro_rules! impl_binary_operator_for_expression { // Right side is an Expression with the same operator, prepend the left side. (lhs, Expr { head: op_rhs, args: mut args_rhs }) if op_rhs == operator => { - args_rhs.insert(0, Box::new(lhs)); + args_rhs.push(Box::new(lhs)); Expr { head: operator, args: args_rhs } }, From 56b4bd775bf6f8c96a2d6894c35d774d8746efec Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 18 Jun 2024 15:21:38 +0100 Subject: [PATCH 29/55] Correct op for mixed tyeps and finalise tests. --- src/symbols.rs | 61 ++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 53062c1..5eb3f86 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -51,7 +51,8 @@ macro_rules! impl_binary_operator_for_numerical { (Complex(a), Complex(b)) => Complex(a.$method(b)), // Complex with Float - (Complex(a), Float(b)) | (Float(b), Complex(a)) => Complex(a.$method(complex::from(b))), + (Complex(a), Float(b)) => Complex(a.$method(complex::from(b))), + (Float(a), Complex(b)) => Complex(complex::from(a).$method(b)), // Complex with Int (Complex(a), Int(b)) => Complex(a.$method(complex::from(b as f64))), @@ -128,61 +129,53 @@ mod tests { } #[test] - fn test_numerical_add_float_to_float() { + fn test_numerical_binary_ops_float_to_float() { let n1 = Numerical::float(5.0); let n2 = Numerical::float(10.0); - assert_eq!(n1 + n2, Numerical::float(15.0)); + assert_eq!(n1 + n2, Numerical::Float(15.0)); + assert_eq!(n1 - n2, Numerical::Float(-5.0)); + assert_eq!(n1 * n2, Numerical::Float(50.0)); + assert_eq!(n1 / n2, Numerical::Float(0.5)); } #[test] - fn test_numerical_add_float_to_complex() { + fn test_numerical_binary_ops_float_to_complex() { let n1 = Numerical::float(5.0); let n2 = Numerical::complex(3.0, 4.0); - assert_eq!(n1 + n2, Numerical::complex(8.0, 4.0)); + assert_eq!(n1 + n2, Numerical::Complex(Complex::new(8.0, 4.0))); + assert_eq!(n1 - n2, Numerical::Complex(Complex::new(2.0, -4.0))); + assert_eq!(n1 * n2, Numerical::Complex(Complex::new(15.0, 20.0))); + assert_eq!(n1 / n2, Numerical::Complex(Complex::new(15.0 / 25.0, -20.0 / 25.0))); } #[test] - fn test_numerical_add_complex_to_int() { + fn test_numerical_binary_ops_complex_to_int() { let n1 = Numerical::complex(5.0, 4.0); let n2 = Numerical::int(3); - assert_eq!(n1 + n2, Numerical::complex(8.0, 4.0)); + assert_eq!(n1 + n2, Numerical::Complex(Complex::new(8.0, 4.0))); + assert_eq!(n1 - n2, Numerical::Complex(Complex::new(2.0, 4.0))); + assert_eq!(n1 * n2, Numerical::Complex(Complex::new(15.0, 12.0))); + assert_eq!(n1 / n2, Numerical::Complex(Complex::new(5.0 / 3.0, 4.0 / 3.0))); } #[test] - fn test_numerical_add_complex_to_float() { + fn test_numerical_binary_ops_complex_to_float() { let n1 = Numerical::complex(5.0, 4.0); let n2 = Numerical::float(3.0); - assert_eq!(n1 + n2, Numerical::complex(8.0, 4.0)); + assert_eq!(n1 + n2, Numerical::Complex(Complex::new(8.0, 4.0))); + assert_eq!(n1 - n2, Numerical::Complex(Complex::new(2.0, 4.0))); + assert_eq!(n1 * n2, Numerical::Complex(Complex::new(15.0, 12.0))); + assert_eq!(n1 / n2, Numerical::Complex(Complex::new(5.0 / 3.0, 4.0 / 3.0))); } #[test] - fn test_numerical_add_complex_to_complex() { + fn test_numerical_binary_ops_complex_to_complex() { let n1 = Numerical::complex(5.0, 4.0); let n2 = Numerical::complex(3.0, 2.0); - assert_eq!(n1 + n2, Numerical::complex(8.0, 6.0)); + assert_eq!(n1 + n2, Numerical::Complex(Complex::new(8.0, 6.0))); + assert_eq!(n1 - n2, Numerical::Complex(Complex::new(2.0, 2.0))); + assert_eq!(n1 * n2, Numerical::Complex(Complex::new(7.0, 22.0))); + assert_eq!(n1 / n2, Numerical::Complex(Complex::new(23.0 / 13.0, 2.0 / 13.0))); } - // #[test] - // fn test_eq_int_and_float() { - // let n1 = Numerical::Int(5); - // let n2 = Numerical::Float(5.0); - // assert_eq!(n1, n2); - // } - - // #[test] - // fn test_eq_complex_and_int() { - // let n1 = Numerical::Complex(Complex::new(5.0, 0.0)); - // let n2 = Numerical::Int(5); - // assert_eq!(n1, n2); - // } - - - // #[test] - // fn test_numeric() { - // // assert_eq!(Numerical::Int(1)+Numerical::Int(2), Numerical::Int(2)); - // // assert_eq!(Operator::MUL.as_str(), "*"); - // // assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); - // // assert_eq!(Operator::POWER.as_str(), "^"); - // // assert_eq!(Operator::CALL.as_str(), "call"); - // } } From 88f6e448e3b88c4ac8be010af955e15998581eab Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 18 Jun 2024 17:56:42 +0100 Subject: [PATCH 30/55] Add Clone trait to Expression. --- src/expression.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expression.rs b/src/expression.rs index 28e99db..d547dda 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -5,7 +5,7 @@ use std::ops::{Add,Div,Mul,Sub}; use num::Complex; -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Expression { Symbol(&'static str), Value(Numerical), From df2b4d8e5d67d47504c2e26e25641eb6272d20e8 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 18 Jun 2024 17:57:31 +0100 Subject: [PATCH 31/55] Implement arithmetic ops for Expression. --- src/expression.rs | 218 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 162 insertions(+), 56 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index d547dda..5c12b15 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -31,68 +31,174 @@ impl Expression { } } -// impl Add for Expression { -// type Output = Expression; - -// fn add(self, rhs: Self) -> Self::Output { -// // If both sides are Numerical, add them directly -// match (self, rhs) { -// (Expression::Value(lhs), Expression::Value(rhs)) => { -// Expression::Value(lhs + rhs) -// } -// // For other cases, create an Expression::Expr with Operator::Add -// (lhs, rhs) => Expression::Expr { -// head: Operator::ADD, -// args: vec![Box::new(lhs), Box::new(rhs)], -// }, -// } -// } -// } +impl Add for Expression { + type Output = Expression; + + fn add(self, rhs: Self) -> Self::Output { + use Expression::{Expr, Value}; + use Operator::ADD; + + match (self, rhs) { + // Numerical values are operated directly. + (Value(lhs), Value(rhs)) => Value(lhs + rhs), + + // Both are Expressions with the same Operator::ADD, merge their arguments. + (Expr { head: ADD, args: args_lhs }, Expr { head: ADD, args: args_rhs }) => { + let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect(); + Expr { head: ADD, args } + }, + + // Left side is an Expression with Operator::ADD, append the right side. + (Expr { head: ADD, args: mut args_lhs }, rhs) => { + args_lhs.push(Box::new(rhs)); + Expr { head: ADD, args: args_lhs } + }, + + // Right side is an Expression with Operator::ADD, prepend the left side. + (lhs, Expr { head: ADD, args: mut args_rhs }) => { + args_rhs.push(Box::new(lhs)); + Expr { head: ADD, args: args_rhs } + }, + + // Otherwise, create a new Expression::Expr with Operator::ADD. + (lhs, rhs) => Expr { head: ADD, args: vec![Box::new(lhs), Box::new(rhs)] }, + } + } +} -// Macro to implement binary operators for the Expression enum -macro_rules! impl_binary_operator_for_expression { - ($trait:ident, $method:ident, $operator:expr) => { - impl $trait for Expression { - type Output = Self; - - fn $method(self, other: Self) -> Self::Output { - use Expression::*; - let operator = $operator; - - match (self, other) { - // Numerical values are operated directly. - (Value(lhs), Value(rhs)) => Value(lhs.$method(rhs)), - - // Both are Expressions with the same operator, merge their arguments. - (Expr { head: op_lhs, args: args_lhs }, Expr { head: op_rhs, args: args_rhs }) if op_lhs == operator && op_rhs == operator => { - let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect(); - Expr { head: operator, args } - }, - - // Left side is an Expression with the same operator, append the right side. - (Expr { head: op_lhs, args: mut args_lhs }, rhs) if op_lhs == operator => { - args_lhs.push(Box::new(rhs)); - Expr { head: operator, args: args_lhs } - }, - - // Right side is an Expression with the same operator, prepend the left side. - (lhs, Expr { head: op_rhs, args: mut args_rhs }) if op_rhs == operator => { - args_rhs.push(Box::new(lhs)); - Expr { head: operator, args: args_rhs } - }, - - // Otherwise, create a new Expression::Expr with the given operator. - (lhs, rhs) => Expr { head: operator, args: vec![Box::new(lhs), Box::new(rhs)] }, - } - } +impl Sub for Expression { + type Output = Expression; + + fn sub(self, rhs: Self) -> Self::Output { + use Expression::{Expr, Value}; + use Operator::{ADD, MUL}; + + match (self, rhs) { + // Numerical values are operated directly. + (Value(lhs), Value(rhs)) => Value(lhs - rhs), + + // Transform x - y into Expr(Add, [x, Expr(Mul, [-1, y])]) + (lhs, rhs) => Expr { + head: ADD, + args: vec![ + Box::new(lhs), + Box::new(Expr { + head: MUL, + args: vec![Box::new(Expression::int(-1)), Box::new(rhs)], + }), + ], + }, } - }; + } } +impl Mul for Expression { + type Output = Expression; + + fn mul(self, rhs: Self) -> Self::Output { + use Expression::{Expr, Value}; + use Operator::MUL; + + match (self, rhs) { + // Numerical values are operated directly. + (Value(lhs), Value(rhs)) => Value(lhs * rhs), + + // Both are Expressions with the same Operator::MUL, merge their arguments. + (Expr { head: MUL, args: args_lhs }, Expr { head: MUL, args: args_rhs }) => { + let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect(); + Expr { head: MUL, args } + }, + + // Left side is an Expression with Operator::MUL, append the right side. + (Expr { head: MUL, args: mut args_lhs }, rhs) => { + args_lhs.push(Box::new(rhs)); + Expr { head: MUL, args: args_lhs } + }, + + // Right side is an Expression with Operator::MUL, prepend the left side. + (lhs, Expr { head: MUL, args: mut args_rhs }) => { + args_rhs.push(Box::new(lhs)); + Expr { head: MUL, args: args_rhs } + }, + + // Otherwise, create a new Expression::Expr with Operator::MUL. + (lhs, rhs) => Expr { head: MUL, args: vec![Box::new(lhs), Box::new(rhs)] }, + } + } +} + + + +impl Div for Expression { + type Output = Expression; + + fn div(self, rhs: Self) -> Self::Output { + use Expression::{Expr, Value}; + use Operator::{MUL, POWER}; + + match (self, rhs) { + // Numerical values are operated directly. + (Value(lhs), Value(rhs)) => Value(lhs / rhs), + + // Transform x / y into Expr(MUL, [x, Expr(POWER, [y, -1])]) + (lhs, rhs) => Expr { + head: MUL, + args: vec![ + Box::new(lhs), + Box::new(Expr { + head: POWER, + args: vec![Box::new(rhs), Box::new(Expression::int(-1))], + }), + ], + }, + } + } +} + +// Macro to implement binary operators for the Expression enum +// macro_rules! impl_binary_operator_for_expression { +// ($trait:ident, $method:ident, $operator:expr) => { +// impl $trait for Expression { +// type Output = Self; + +// fn $method(self, other: Self) -> Self::Output { +// use Expression::*; +// let operator = $operator; + +// match (self, other) { +// // Numerical values are operated directly. +// (Value(lhs), Value(rhs)) => Value(lhs.$method(rhs)), + +// // Both are Expressions with the same Operator::ADD, merge their arguments. +// (Expr { head: Operator::ADD, args: args_lhs }, Expr { head: Operator::ADD, args: args_rhs }) => { +// let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect(); +// Expr { head: Operator::ADD, args } +// }, + +// // Left side is an Expression with Operator::ADD, append the right side. +// (Expr { head: Operator::ADD, args: mut args_lhs }, rhs) => { +// args_lhs.push(Box::new(rhs)); +// Expr { head: Operator::ADD, args: args_lhs } +// }, + +// // Right side is an Expression with Operator::ADD, prepend the left side. +// (lhs, Expr { head: Operator::ADD, args: mut args_rhs }) => { +// args_rhs.push(Box::new(lhs)); +// Expr { head: Operator::ADD, args: args_rhs } +// }, + +// // Otherwise, create a new Expression::Expr with the given operator. +// (lhs, rhs) => Expr { head: operator, args: vec![Box::new(lhs), Box::new(rhs)] }, +// } +// } +// } +// }; +// } + // Applying the macro to implement Add, Sub, Mul, and Div for Expression -impl_binary_operator_for_expression!(Add, add, Operator::ADD); +// impl_binary_operator_for_expression!(Add, add, Operator::ADD); // impl_binary_operator_for_expression!(Sub, sub, Operator::SUB); -impl_binary_operator_for_expression!(Mul, mul, Operator::MUL); +// impl_binary_operator_for_expression!(Mul, mul, Operator::MUL); // impl_binary_operator_for_expression!(Div, div, Operator::DIV); From a59d74608a29e05df84c6901a8e9acc62a2197bd Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 18 Jun 2024 17:57:55 +0100 Subject: [PATCH 32/55] Test arithmetic ops for Expressions. --- src/expression.rs | 220 ++++++++++++++++++++++++++++------------------ 1 file changed, 135 insertions(+), 85 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index 5c12b15..a620225 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -231,102 +231,152 @@ mod tests { let complex_expr = Expression::complex(1.0, 2.0); assert_eq!(complex_expr, Expression::Value(Numerical::Complex(Complex::new(1.0, 2.0)))); } - - #[test] - fn test_expression_add_int_to_int() { - let expr1 = Expression::int(1); - let expr2 = Expression::int(2); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Int(3))); - } - - #[test] - fn test_expression_add_int_to_float() { - let expr1 = Expression::int(1); - let expr2 = Expression::float(2.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Float(3.0))); - } - - #[test] - fn test_expression_add_int_to_complex() { - let expr1 = Expression::int(1); - let expr2 = Expression::complex(2.0, 4.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); - } #[test] - fn test_expression_add_float_to_int() { - let expr1 = Expression::float(1.0); - let expr2 = Expression::int(2); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + fn test_mixed_types_expression_add() { + let symbol_expr = Expression::symbol("x"); + let mixed_expr = Expression::int(1) + symbol_expr; + assert_eq!( + mixed_expr, + Expression::Expr { + head: Operator::ADD, + args: vec![ + Box::new(Expression::int(1)), + Box::new(Expression::symbol("x")), + ] + } + ); } #[test] - fn test_expression_add_float_to_float() { - let expr1 = Expression::float(1.0); - let expr2 = Expression::float(2.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + fn test_mixed_types_expression_sub() { + let symbol_expr = Expression::symbol("x"); + let mixed_expr = Expression::complex(1.0, 2.0) - symbol_expr; + assert_eq!( + mixed_expr, + Expression::Expr { + head: Operator::ADD, + args: vec![ + Box::new(Expression::complex(1.0, 2.0)), + Box::new( + Expression::Expr { + head: Operator::MUL, + args: vec![ + Box::new(Expression::int(-1)), + Box::new(Expression::symbol("x")), + ] + } + ), + ] + } + ); } #[test] - fn test_expression_add_float_to_complex() { - let expr1 = Expression::float(1.0); - let expr2 = Expression::complex(2.0, 4.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); + fn test_numerical_binary_ops() { + let n1 = Expression::int(10); + let n2 = Expression::int(3); + assert_eq!(n1.clone() + n2.clone(), Expression::int(13)); + assert_eq!(n1.clone() - n2.clone(), Expression::int(7)); + assert_eq!(n1.clone() * n2.clone(), Expression::int(30)); + assert_eq!(n1 / n2, Expression::int(3)); } - #[test] - fn test_expression_add_complex_to_int() { - let expr1 = Expression::complex(1.0, 2.0); - let expr2 = Expression::int(2); - let result = expr1 + expr2; + // #[test] + // fn test_expression_add_int_to_int() { + // let expr1 = Expression::int(1); + // let expr2 = Expression::int(2); + // let result = expr1 + expr2; - assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); - } + // assert_eq!(result, Expression::Value(Numerical::Int(3))); + // } - #[test] - fn test_expression_add_complex_to_float() { - let expr1 = Expression::complex(1.0, 2.0); - let expr2 = Expression::float(2.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); - } + // #[test] + // fn test_expression_add_int_to_float() { + // let expr1 = Expression::int(1); + // let expr2 = Expression::float(2.0); + // let result = expr1 + expr2; + + // assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + // } + + // #[test] + // fn test_expression_add_int_to_complex() { + // let expr1 = Expression::int(1); + // let expr2 = Expression::complex(2.0, 4.0); + // let result = expr1 + expr2; + + // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); + // } - #[test] - fn test_expression_add_complex_to_complex() { - let expr1 = Expression::complex(1.0, 2.0); - let expr2 = Expression::complex(3.0, 4.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(4.0, 6.0)))); - } - - #[test] - fn test_expression_add_symbol_to_int() { - let symbol_expr = Expression::symbol("x"); - let expr2 = Expression::int(1); - let result = symbol_expr + expr2; - - match result { - Expression::Expr { head, args } => { - assert_eq!(head, Operator::ADD); - assert_eq!(*args[0], Expression::Symbol("x")); - assert_eq!(*args[1], Expression::Value(Numerical::Int(1))); - } - _ => panic!("Expected an Expression::Expr with Operator::ADD"), - } - - } + // #[test] + // fn test_expression_add_float_to_int() { + // let expr1 = Expression::float(1.0); + // let expr2 = Expression::int(2); + // let result = expr1 + expr2; + + // assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + // } + + // #[test] + // fn test_expression_add_float_to_float() { + // let expr1 = Expression::float(1.0); + // let expr2 = Expression::float(2.0); + // let result = expr1 + expr2; + + // assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + // } + + // #[test] + // fn test_expression_add_float_to_complex() { + // let expr1 = Expression::float(1.0); + // let expr2 = Expression::complex(2.0, 4.0); + // let result = expr1 + expr2; + + // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); + // } + + // #[test] + // fn test_expression_add_complex_to_int() { + // let expr1 = Expression::complex(1.0, 2.0); + // let expr2 = Expression::int(2); + // let result = expr1 + expr2; + + // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); + // } + + // #[test] + // fn test_expression_add_complex_to_float() { + // let expr1 = Expression::complex(1.0, 2.0); + // let expr2 = Expression::float(2.0); + // let result = expr1 + expr2; + + // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); + // } + + // #[test] + // fn test_expression_add_complex_to_complex() { + // let expr1 = Expression::complex(1.0, 2.0); + // let expr2 = Expression::complex(3.0, 4.0); + // let result = expr1 + expr2; + + // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(4.0, 6.0)))); + // } + + // #[test] + // fn test_expression_add_symbol_to_int() { + // let symbol_expr = Expression::symbol("x"); + // let expr2 = Expression::int(1); + // let result = symbol_expr + expr2; + + // match result { + // Expression::Expr { head, args } => { + // assert_eq!(head, Operator::ADD); + // assert_eq!(*args[0], Expression::Symbol("x")); + // assert_eq!(*args[1], Expression::Value(Numerical::Int(1))); + // } + // _ => panic!("Expected an Expression::Expr with Operator::ADD"), + // } + + // } } From 1c965a5b5c889487bfc552c46fbfb4063ad4e166 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 18 Jun 2024 18:00:14 +0100 Subject: [PATCH 33/55] Remove obsolete variants and add Clone trait. --- src/operator.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 3961bef..284e5ac 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,12 +1,10 @@ -#[derive(Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum Operator { ADD, CALL, - // DIV, MUL, NONCOMMUTE, POWER, - // SUB, } impl Operator { From 1efb6d2d95ce60e90e81ae4bbc5696fc06f26ddf Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 18 Jun 2024 18:00:41 +0100 Subject: [PATCH 34/55] Better comment. --- src/symbols.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/symbols.rs b/src/symbols.rs index 5eb3f86..98b3fa2 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -44,6 +44,7 @@ macro_rules! impl_binary_operator_for_numerical { fn $method(self, other: Self) -> Self { use Numerical::*; + // To disambiguate with the enum variant. use num::Complex as complex; match (self, other) { From 903fc20813476840b5a4575054ee637092d9044a Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 18 Jun 2024 18:07:00 +0100 Subject: [PATCH 35/55] Remove and move imports. --- src/expression.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index a620225..ceba992 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -1,8 +1,7 @@ use crate::operator::Operator; -use crate::symbols::{Numerical,Symbol}; +use crate::symbols::Numerical; use std::ops::{Add,Div,Mul,Sub}; -use num::Complex; #[derive(Clone, Debug, PartialEq)] @@ -207,6 +206,7 @@ impl Div for Expression { #[cfg(test)] mod tests { use super::*; // This imports everything from the parent module + use num::Complex; #[test] fn test_symbol_expression() { From c9975741ec826277e34b1507dee716cad70b149b Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 18 Jun 2024 18:07:19 +0100 Subject: [PATCH 36/55] Fix lint removing unnecessary iterator calls. --- src/expression.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index ceba992..a5e2e79 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -43,7 +43,7 @@ impl Add for Expression { // Both are Expressions with the same Operator::ADD, merge their arguments. (Expr { head: ADD, args: args_lhs }, Expr { head: ADD, args: args_rhs }) => { - let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect(); + let args = args_lhs.into_iter().chain(args_rhs).collect(); Expr { head: ADD, args } }, @@ -104,7 +104,7 @@ impl Mul for Expression { // Both are Expressions with the same Operator::MUL, merge their arguments. (Expr { head: MUL, args: args_lhs }, Expr { head: MUL, args: args_rhs }) => { - let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect(); + let args = args_lhs.into_iter().chain(args_rhs).collect(); Expr { head: MUL, args } }, From 8d4340e23cafb41ee407746013bd3240b94bfb2b Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:29:33 +0100 Subject: [PATCH 37/55] More traits to be implemented for Expressions. --- src/expression.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/expression.rs b/src/expression.rs index a5e2e79..eef9bae 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -1,7 +1,9 @@ +use num_traits::pow::Pow; + use crate::operator::Operator; use crate::symbols::Numerical; -use std::ops::{Add,Div,Mul,Sub}; +use std::ops::{Add, Div, Mul, Sub, Neg}; #[derive(Clone, Debug, PartialEq)] From a100364ebd6a7765f9aff6601e47bb4273919731 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:29:59 +0100 Subject: [PATCH 38/55] A macro to help boxing expressions. --- src/expression.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/expression.rs b/src/expression.rs index eef9bae..ad5a52b 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -5,6 +5,10 @@ use crate::symbols::Numerical; use std::ops::{Add, Div, Mul, Sub, Neg}; +macro_rules! vbox { + () => { vec![] }; + ($($x:expr),+ $(,)?) => { vec![$(Box::new($x)),*] }; +} #[derive(Clone, Debug, PartialEq)] pub enum Expression { From 0e552f413224face8dd2e64045a95932ba269eea Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:30:43 +0100 Subject: [PATCH 39/55] Implement negation operator for Expression. --- src/expression.rs | 112 +++++++++++----------------------------------- 1 file changed, 27 insertions(+), 85 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index ad5a52b..c7c2492 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -36,98 +36,40 @@ impl Expression { } } -impl Add for Expression { +impl Neg for Expression { type Output = Expression; - - fn add(self, rhs: Self) -> Self::Output { - use Expression::{Expr, Value}; - use Operator::ADD; - - match (self, rhs) { - // Numerical values are operated directly. - (Value(lhs), Value(rhs)) => Value(lhs + rhs), - - // Both are Expressions with the same Operator::ADD, merge their arguments. - (Expr { head: ADD, args: args_lhs }, Expr { head: ADD, args: args_rhs }) => { - let args = args_lhs.into_iter().chain(args_rhs).collect(); - Expr { head: ADD, args } - }, - - // Left side is an Expression with Operator::ADD, append the right side. - (Expr { head: ADD, args: mut args_lhs }, rhs) => { - args_lhs.push(Box::new(rhs)); - Expr { head: ADD, args: args_lhs } - }, - - // Right side is an Expression with Operator::ADD, prepend the left side. - (lhs, Expr { head: ADD, args: mut args_rhs }) => { - args_rhs.push(Box::new(lhs)); - Expr { head: ADD, args: args_rhs } - }, - - // Otherwise, create a new Expression::Expr with Operator::ADD. - (lhs, rhs) => Expr { head: ADD, args: vec![Box::new(lhs), Box::new(rhs)] }, - } - } -} - -impl Sub for Expression { - type Output = Expression; - - fn sub(self, rhs: Self) -> Self::Output { - use Expression::{Expr, Value}; - use Operator::{ADD, MUL}; - - match (self, rhs) { - // Numerical values are operated directly. - (Value(lhs), Value(rhs)) => Value(lhs - rhs), - // Transform x - y into Expr(Add, [x, Expr(Mul, [-1, y])]) - (lhs, rhs) => Expr { - head: ADD, - args: vec![ - Box::new(lhs), - Box::new(Expr { - head: MUL, - args: vec![Box::new(Expression::int(-1)), Box::new(rhs)], - }), - ], - }, - } - } -} - -impl Mul for Expression { - type Output = Expression; - - fn mul(self, rhs: Self) -> Self::Output { - use Expression::{Expr, Value}; + fn neg(self) -> Self::Output { + use Expression::{Expr, Value, Symbol}; use Operator::MUL; - match (self, rhs) { - // Numerical values are operated directly. - (Value(lhs), Value(rhs)) => Value(lhs * rhs), - - // Both are Expressions with the same Operator::MUL, merge their arguments. - (Expr { head: MUL, args: args_lhs }, Expr { head: MUL, args: args_rhs }) => { - let args = args_lhs.into_iter().chain(args_rhs).collect(); - Expr { head: MUL, args } + match self { + // Negating a symbol directly isn't well-defined, but for the sake of + // completeness, we could wrap it in an Expr with multiplication by -1. + Symbol(s) => Expr { + head: MUL, + args: vbox![ + Expression::int(-1), + Expression::symbol(s), + ] }, - - // Left side is an Expression with Operator::MUL, append the right side. - (Expr { head: MUL, args: mut args_lhs }, rhs) => { - args_lhs.push(Box::new(rhs)); - Expr { head: MUL, args: args_lhs } + + // Negate the numerical value. + Value(v) => { + Value(-v) }, - - // Right side is an Expression with Operator::MUL, prepend the left side. - (lhs, Expr { head: MUL, args: mut args_rhs }) => { - args_rhs.push(Box::new(lhs)); - Expr { head: MUL, args: args_rhs } + + // Negate the entire expression by multiplying by -1 + Expr { head, args } => Expr { + head: MUL, + args: vbox![ + Expression::int(-1), + Expr { + head, + args, + } + ] }, - - // Otherwise, create a new Expression::Expr with Operator::MUL. - (lhs, rhs) => Expr { head: MUL, args: vec![Box::new(lhs), Box::new(rhs)] }, } } } From 4c35b2ee2ee6f879ac2bb47385b17867d76d9312 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:31:49 +0100 Subject: [PATCH 40/55] Implement power operator for Expressions. --- src/expression.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index c7c2492..164088e 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -74,30 +74,28 @@ impl Neg for Expression { } } - - -impl Div for Expression { +impl Pow for Expression { type Output = Expression; - - fn div(self, rhs: Self) -> Self::Output { + + fn pow(self, rhs: Self) -> Self::Output { use Expression::{Expr, Value}; - use Operator::{MUL, POWER}; + use Operator::POW; match (self, rhs) { // Numerical values are operated directly. - (Value(lhs), Value(rhs)) => Value(lhs / rhs), + (Value(lhs), Value(rhs)) => Value(lhs.pow(rhs)), - // Transform x / y into Expr(MUL, [x, Expr(POWER, [y, -1])]) - (lhs, rhs) => Expr { - head: MUL, - args: vec![ - Box::new(lhs), - Box::new(Expr { - head: POWER, - args: vec![Box::new(rhs), Box::new(Expression::int(-1))], - }), - ], + // If the left side is already a power expression, chain the exponent. + (Expr { head: POW, args: mut args_lhs }, rhs) => { + args_lhs.push(Box::new(rhs)); + Expr { head: POW, args: args_lhs } }, + + // Otherwise, create a new power expression. + (lhs, rhs) => Expr { + head: POW, + args: vbox![lhs, rhs], + } } } } From 08af28ec7f1a3b478d067a1ec0ceea8376b616e5 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:32:34 +0100 Subject: [PATCH 41/55] A macro to implement binray ops for Expression. --- src/expression.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/expression.rs b/src/expression.rs index 164088e..1067906 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -145,8 +145,61 @@ impl Pow for Expression { // impl_binary_operator_for_expression!(Sub, sub, Operator::SUB); // impl_binary_operator_for_expression!(Mul, mul, Operator::MUL); // impl_binary_operator_for_expression!(Div, div, Operator::DIV); +macro_rules! impl_binary_operator_for_expression { + ($trait:ident, $method:ident, $operator:path) => { + impl $trait for Expression { + type Output = Self; + + fn $method(self, other: Self) -> Self { + use Expression::*; + + match (self, other) { + (Value(x), Value(y)) => Value(x.$method(y)), + + (Expr {head: $operator, args: args_lhs}, Expr {head: $operator, args: args_rhs}) => { + let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect(); + Expr{head: $operator, args} + }, + + (Expr {head: $operator, args: mut args_lhs}, rhs) => { + args_lhs.push(Box::new(rhs)); + Expr {head: $operator, args: args_lhs} + }, + + (lhs, Expr {head: $operator, args: mut args_rhs}) => { + args_rhs.push(Box::new(lhs)); + Expr {head: $operator, args: args_rhs} + }, + + (lhs, rhs) => Expr{head: $operator, args: vbox![lhs, rhs]}, + } + } + } + }; + + ($trait:ident, $method:ident, $operator:path, $inv:expr) => { + impl $trait for Expression { + type Output = Self; + + fn $method(self, other: Self) -> Self { + use Expression::*; + + match (self, other) { + (Value(x), Value(y)) => Value(x.$method(y)), + (lhs, rhs) => Expr { + head: $operator, + args: vbox![lhs, $inv(rhs)] + }, + } + } + } + } +} - +impl_binary_operator_for_expression!(Add, add, Operator::ADD); +impl_binary_operator_for_expression!(Mul, mul, Operator::MUL); +impl_binary_operator_for_expression!(Sub, sub, Operator:: ADD, |x: Expression| { x.neg() }); +impl_binary_operator_for_expression!(Div, div, Operator:: MUL, |x: Expression| { x.pow(Expression::float(-1.0)) }); #[cfg(test)] From 8f0ebc8811e8f6dfcba399d48c161e0338790ebc Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:33:15 +0100 Subject: [PATCH 42/55] Remove useless code. --- src/expression.rs | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index 1067906..53b0b0e 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -100,51 +100,6 @@ impl Pow for Expression { } } -// Macro to implement binary operators for the Expression enum -// macro_rules! impl_binary_operator_for_expression { -// ($trait:ident, $method:ident, $operator:expr) => { -// impl $trait for Expression { -// type Output = Self; - -// fn $method(self, other: Self) -> Self::Output { -// use Expression::*; -// let operator = $operator; - -// match (self, other) { -// // Numerical values are operated directly. -// (Value(lhs), Value(rhs)) => Value(lhs.$method(rhs)), - -// // Both are Expressions with the same Operator::ADD, merge their arguments. -// (Expr { head: Operator::ADD, args: args_lhs }, Expr { head: Operator::ADD, args: args_rhs }) => { -// let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect(); -// Expr { head: Operator::ADD, args } -// }, - -// // Left side is an Expression with Operator::ADD, append the right side. -// (Expr { head: Operator::ADD, args: mut args_lhs }, rhs) => { -// args_lhs.push(Box::new(rhs)); -// Expr { head: Operator::ADD, args: args_lhs } -// }, - -// // Right side is an Expression with Operator::ADD, prepend the left side. -// (lhs, Expr { head: Operator::ADD, args: mut args_rhs }) => { -// args_rhs.push(Box::new(lhs)); -// Expr { head: Operator::ADD, args: args_rhs } -// }, - -// // Otherwise, create a new Expression::Expr with the given operator. -// (lhs, rhs) => Expr { head: operator, args: vec![Box::new(lhs), Box::new(rhs)] }, -// } -// } -// } -// }; -// } - -// Applying the macro to implement Add, Sub, Mul, and Div for Expression -// impl_binary_operator_for_expression!(Add, add, Operator::ADD); -// impl_binary_operator_for_expression!(Sub, sub, Operator::SUB); -// impl_binary_operator_for_expression!(Mul, mul, Operator::MUL); -// impl_binary_operator_for_expression!(Div, div, Operator::DIV); macro_rules! impl_binary_operator_for_expression { ($trait:ident, $method:ident, $operator:path) => { impl $trait for Expression { From d3ac64a0192f923d49e9ed988ecc0c732cf65ac0 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:33:44 +0100 Subject: [PATCH 43/55] Better naming. --- src/operator.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 284e5ac..6c56dad 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -4,7 +4,7 @@ pub enum Operator { CALL, MUL, NONCOMMUTE, - POWER, + POW, } impl Operator { @@ -14,7 +14,7 @@ impl Operator { Operator::CALL => "call", Operator::MUL => "*", Operator::NONCOMMUTE => "@", - Operator::POWER => "^", + Operator::POW => "^", } } } @@ -30,7 +30,7 @@ mod tests { assert_eq!(Operator::ADD.as_str(), "+"); assert_eq!(Operator::MUL.as_str(), "*"); assert_eq!(Operator::NONCOMMUTE.as_str(), "@"); - assert_eq!(Operator::POWER.as_str(), "^"); + assert_eq!(Operator::POW.as_str(), "^"); assert_eq!(Operator::CALL.as_str(), "call"); } } From 27de3752b50e82c323ea5c8ce8c197d9b23d891d Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:34:09 +0100 Subject: [PATCH 44/55] Implement pow and neg ops for Numerical. --- src/symbols.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/symbols.rs b/src/symbols.rs index 98b3fa2..201d253 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -1,5 +1,6 @@ use num::Complex; -use std::ops::{Add, Div, Mul, Sub}; +use num_traits::pow::Pow; +use std::ops::{Add, Div, Mul, Sub, Neg}; use std::fmt; @@ -37,12 +38,46 @@ impl fmt::Display for Numerical { } } +impl Neg for Numerical { + type Output = Numerical; + + fn neg(self) -> Self::Output { + use Numerical::*; + + match self { + Int(i) => Numerical::int(-i), + Float(f) => Numerical::float(-f), + Complex(c) => Numerical::complex(-c.re, -c.im), + } + } +} + +impl Pow for Numerical { + type Output = Numerical; + + fn pow(self, rhs: Numerical) -> Self::Output { + use Numerical::*; + + match (self, rhs) { + (Int(base), Int(exp)) => Int((base as f64).powi(exp as i32) as i64), + (Float(base), Int(exp)) => Float(base.powi(exp as i32)), + (Complex(base), Int(exp)) => Complex(base.powi(exp as i32)), + (Float(base), Float(exp)) => Float(base.powf(exp)), + (Complex(base), Float(exp)) => Complex(base.powf(exp)), + (Int(base), Float(exp)) => Float((base as f64).powf(exp)), + (Complex(base), Complex(exp)) => Complex(base.powc(exp)), + (Float(base), Complex(exp)) => Complex((num::Complex::new(base, 0.0)).powc(exp)), + (Int(base), Complex(exp)) => Complex((num::Complex::new(base as f64, 0.0)).powc(exp)), + } + } +} + macro_rules! impl_binary_operator_for_numerical { ($trait:ident, $method:ident) => { impl $trait for Numerical { type Output = Self; - fn $method(self, other: Self) -> Self { + fn $method(self, other: Self) -> Self::Output { use Numerical::*; // To disambiguate with the enum variant. use num::Complex as complex; From 6692319db0ac042826462f53e40333fc991b8111 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:34:40 +0100 Subject: [PATCH 45/55] Update tests for new ops. --- src/symbols.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/symbols.rs b/src/symbols.rs index 201d253..9fb5a88 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -123,6 +123,57 @@ pub struct Symbol (&'static str); mod tests { // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; + + // Approximate equality check for Complex numbers + fn approx_eq_complex(c1: &num::Complex, c2: &num::Complex, epsilon: f64) -> bool { + (c1.re - c2.re).abs() < epsilon && (c1.im - c2.im).abs() < epsilon + } + + #[test] + fn test_negation_int() { + let num_int = Numerical::Int(10); + assert_eq!(-num_int, Numerical::Int(-10)); + + let num_int_neg = Numerical::Int(-10); + assert_eq!(-num_int_neg, Numerical::Int(10)); + } + + #[test] + fn test_negation_float() { + let num_float = Numerical::Float(5.5); + assert_eq!(-num_float, Numerical::Float(-5.5)); + + let num_float_neg = Numerical::Float(-5.5); + assert_eq!(-num_float_neg, Numerical::Float(5.5)); + } + + #[test] + fn test_negation_complex() { + let num_complex = Numerical::Complex(Complex::new(3.0, 4.0)); + assert_eq!(-num_complex, Numerical::Complex(Complex::new(-3.0, -4.0))); + + let num_complex_neg = Numerical::Complex(Complex::new(-3.0, -4.0)); + assert_eq!(-num_complex_neg, Numerical::Complex(Complex::new(3.0, 4.0))); + } + + #[test] + fn test_numerical_pow() { + let n1 = Numerical::Int(2); + let n2 = Numerical::Int(3); + assert_eq!(n1.pow(n2), Numerical::Int(8)); + + let n3 = Numerical::Float(2.0); + let n4 = Numerical::Float(3.0); + assert_eq!(n3.pow(n4), Numerical::Float(8.0)); + + let n5 = Numerical::Complex(num::Complex::new(2.0, 0.0)); + let n6 = Numerical::Complex(num::Complex::new(3.0, 0.0)); + if let Numerical::Complex(c) = n5.pow(n6) { + assert!(approx_eq_complex(&c, &Complex::new(8.0, 0.0), 1e-9)); + } else { + panic!("Expected complex result"); + } + } #[test] fn test_numerical_binary_ops_int_to_int() { From 68490b896d1ecbafa89763bded24d3332d434589 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Wed, 19 Jun 2024 14:34:52 +0100 Subject: [PATCH 46/55] Update cargo files with new crates. --- Cargo.lock | 1 + Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 9e9595e..b905b04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,6 +248,7 @@ name = "qadence2_expressions" version = "0.1.0" dependencies = [ "num", + "num-traits", "pyo3", "strum", "strum_macros", diff --git a/Cargo.toml b/Cargo.toml index 14e8413..994e4d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ crate-type = ["cdylib"] [dependencies] num = "0.4.3" +num-traits = "0.2.19" pyo3 = "0.21.2" strum = "0.26.2" strum_macros = "0.26.3" From 489d1b0b00a1011cd5be592d30ae4a6ebd57c686 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 2 Jul 2024 11:14:29 +0100 Subject: [PATCH 47/55] Export the macro to be usable elsewhere. --- src/expression.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/expression.rs b/src/expression.rs index 53b0b0e..345dc3c 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -5,6 +5,7 @@ use crate::symbols::Numerical; use std::ops::{Add, Div, Mul, Sub, Neg}; +#[macro_export] macro_rules! vbox { () => { vec![] }; ($($x:expr),+ $(,)?) => { vec![$(Box::new($x)),*] }; From e470ef22bf73c6d60e1ba7d613ce3363e1e45585 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 2 Jul 2024 11:15:51 +0100 Subject: [PATCH 48/55] Update expressions. --- src/expression.rs | 53 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index 345dc3c..847e9b7 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -52,8 +52,8 @@ impl Neg for Expression { args: vbox![ Expression::int(-1), Expression::symbol(s), - ] - }, + ], + }, // Negate the numerical value. Value(v) => { @@ -162,6 +162,8 @@ impl_binary_operator_for_expression!(Div, div, Operator:: MUL, |x: Expression| { mod tests { use super::*; // This imports everything from the parent module use num::Complex; + use Expression::Expr; + use Operator::{ADD, MUL}; #[test] fn test_symbol_expression() { @@ -169,23 +171,60 @@ mod tests { assert_eq!(symbol_expr, Expression::Symbol("x")); } + #[test] + fn test_neg_expression() { + let expr = Expression::symbol("y"); + let neg_expr = -expr; + assert_eq!( + neg_expr, + Expr { + head: MUL, + args: vec![ + Box::new(Expression::int(-1)), + Box::new(Expression::symbol("y")), + ] + } + ); + } + #[test] fn test_int_expression() { let int_expr = Expression::int(42); assert_eq!(int_expr, Expression::Value(Numerical::Int(42))); } + #[test] + fn test_neg_int_expr() { + let value = Expression::int(10); + let neg_value = -value; + assert_eq!(neg_value, Expression::int(-10)); + } + #[test] fn test_float_expression() { let float_expr = Expression::float(3.14); assert_eq!(float_expr, Expression::Value(Numerical::Float(3.14))); } + #[test] + fn test_neg_float_expr() { + let value = Expression::float(10.); + let neg_value = -value; + assert_eq!(neg_value, Expression::float(-10.)); + } + #[test] fn test_complex_expression() { let complex_expr = Expression::complex(1.0, 2.0); assert_eq!(complex_expr, Expression::Value(Numerical::Complex(Complex::new(1.0, 2.0)))); } + + #[test] + fn test_neg_complex_expr() { + let value = Expression::complex(1., 2.); + let neg_value = -value; + assert_eq!(neg_value, Expression::complex(-1., -2.)); + } #[test] fn test_mixed_types_expression_add() { @@ -193,8 +232,8 @@ mod tests { let mixed_expr = Expression::int(1) + symbol_expr; assert_eq!( mixed_expr, - Expression::Expr { - head: Operator::ADD, + Expr { + head: ADD, args: vec![ Box::new(Expression::int(1)), Box::new(Expression::symbol("x")), @@ -209,13 +248,13 @@ mod tests { let mixed_expr = Expression::complex(1.0, 2.0) - symbol_expr; assert_eq!( mixed_expr, - Expression::Expr { - head: Operator::ADD, + Expr { + head: ADD, args: vec![ Box::new(Expression::complex(1.0, 2.0)), Box::new( Expression::Expr { - head: Operator::MUL, + head: MUL, args: vec![ Box::new(Expression::int(-1)), Box::new(Expression::symbol("x")), From 70080cf820f91bafa17a2186c57edd2db8691f12 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 2 Jul 2024 11:16:09 +0100 Subject: [PATCH 49/55] Format. --- src/symbols.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/symbols.rs b/src/symbols.rs index 9fb5a88..25ada66 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -4,6 +4,7 @@ use std::ops::{Add, Div, Mul, Sub, Neg}; use std::fmt; + #[derive(Copy, Clone, Debug, PartialEq)] pub enum Numerical { Int(i64), @@ -118,7 +119,6 @@ impl_binary_operator_for_numerical!(Div, div); #[derive(Debug, PartialEq)] pub struct Symbol (&'static str); - #[cfg(test)] mod tests { // Note this useful idiom: importing names from outer (for mod tests) scope. @@ -264,5 +264,6 @@ mod tests { assert_eq!(n1 * n2, Numerical::Complex(Complex::new(7.0, 22.0))); assert_eq!(n1 / n2, Numerical::Complex(Complex::new(23.0 / 13.0, 2.0 / 13.0))); } + } From e38c7b1ae39da053f4aed97ca3dd9488d7ad2fda Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 2 Jul 2024 11:22:40 +0100 Subject: [PATCH 50/55] Add CI tests. --- .github/workflows/rust-tests.yml | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/rust-tests.yml diff --git a/.github/workflows/rust-tests.yml b/.github/workflows/rust-tests.yml new file mode 100644 index 0000000..c26a562 --- /dev/null +++ b/.github/workflows/rust-tests.yml @@ -0,0 +1,41 @@ +name: Rust Tests + +on: + push: + branches: main + pull_request: + branches: main + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Cache Cargo registry + uses: actions/cache@v3 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-registry- + + - name: Cache Cargo build + uses: actions/cache@v3 + with: + path: target + key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-build- + + - name: Run tests + run: cargo test --all From 3ffbcbf8c24edbad45f05d98f4d90a98fb2a7d42 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 2 Jul 2024 11:30:57 +0100 Subject: [PATCH 51/55] Add linter. --- .github/workflows/rust-tests.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/rust-tests.yml b/.github/workflows/rust-tests.yml index c26a562..5f2217e 100644 --- a/.github/workflows/rust-tests.yml +++ b/.github/workflows/rust-tests.yml @@ -37,5 +37,11 @@ jobs: restore-keys: | ${{ runner.os }}-cargo-build- + - name: Install dependencies + run: cargo fetch + + - name: Run `clippy` linter + run: cargo clippy --all-targets -- -D warnings + - name: Run tests run: cargo test --all From 92da1c8d9e63b001bea356722c3f6bfce65c16ac Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 2 Jul 2024 11:31:11 +0100 Subject: [PATCH 52/55] Remove support for int type. --- src/expression.rs | 155 ++++++++++++---------------------------------- src/symbols.rs | 89 -------------------------- 2 files changed, 38 insertions(+), 206 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index 847e9b7..ada457c 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -24,10 +24,6 @@ impl Expression { Expression::Symbol(name) } - pub fn int(value: i64) -> Self { - Expression::Value(Numerical::int(value)) - } - pub fn float(value: f64) -> Self { Expression::Value(Numerical::float(value)) } @@ -50,7 +46,7 @@ impl Neg for Expression { Symbol(s) => Expr { head: MUL, args: vbox![ - Expression::int(-1), + Expression::float(-1.), Expression::symbol(s), ], }, @@ -64,7 +60,7 @@ impl Neg for Expression { Expr { head, args } => Expr { head: MUL, args: vbox![ - Expression::int(-1), + Expression::float(-1.), Expr { head, args, @@ -187,19 +183,6 @@ mod tests { ); } - #[test] - fn test_int_expression() { - let int_expr = Expression::int(42); - assert_eq!(int_expr, Expression::Value(Numerical::Int(42))); - } - - #[test] - fn test_neg_int_expr() { - let value = Expression::int(10); - let neg_value = -value; - assert_eq!(neg_value, Expression::int(-10)); - } - #[test] fn test_float_expression() { let float_expr = Expression::float(3.14); @@ -229,13 +212,13 @@ mod tests { #[test] fn test_mixed_types_expression_add() { let symbol_expr = Expression::symbol("x"); - let mixed_expr = Expression::int(1) + symbol_expr; + let mixed_expr = Expression::float(1.) + symbol_expr; assert_eq!( mixed_expr, Expr { head: ADD, args: vec![ - Box::new(Expression::int(1)), + Box::new(Expression::float(1.)), Box::new(Expression::symbol("x")), ] } @@ -256,7 +239,7 @@ mod tests { Expression::Expr { head: MUL, args: vec![ - Box::new(Expression::int(-1)), + Box::new(Expression::float(-1.)), Box::new(Expression::symbol("x")), ] } @@ -276,101 +259,39 @@ mod tests { assert_eq!(n1 / n2, Expression::int(3)); } - // #[test] - // fn test_expression_add_int_to_int() { - // let expr1 = Expression::int(1); - // let expr2 = Expression::int(2); - // let result = expr1 + expr2; + #[test] + fn test_expression_add_float_to_float() { + let expr1 = Expression::float(1.0); + let expr2 = Expression::float(2.0); + let result = expr1 + expr2; - // assert_eq!(result, Expression::Value(Numerical::Int(3))); - // } - - // #[test] - // fn test_expression_add_int_to_float() { - // let expr1 = Expression::int(1); - // let expr2 = Expression::float(2.0); - // let result = expr1 + expr2; - - // assert_eq!(result, Expression::Value(Numerical::Float(3.0))); - // } - - // #[test] - // fn test_expression_add_int_to_complex() { - // let expr1 = Expression::int(1); - // let expr2 = Expression::complex(2.0, 4.0); - // let result = expr1 + expr2; - - // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); - // } - - // #[test] - // fn test_expression_add_float_to_int() { - // let expr1 = Expression::float(1.0); - // let expr2 = Expression::int(2); - // let result = expr1 + expr2; - - // assert_eq!(result, Expression::Value(Numerical::Float(3.0))); - // } - - // #[test] - // fn test_expression_add_float_to_float() { - // let expr1 = Expression::float(1.0); - // let expr2 = Expression::float(2.0); - // let result = expr1 + expr2; - - // assert_eq!(result, Expression::Value(Numerical::Float(3.0))); - // } - - // #[test] - // fn test_expression_add_float_to_complex() { - // let expr1 = Expression::float(1.0); - // let expr2 = Expression::complex(2.0, 4.0); - // let result = expr1 + expr2; - - // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); - // } - - // #[test] - // fn test_expression_add_complex_to_int() { - // let expr1 = Expression::complex(1.0, 2.0); - // let expr2 = Expression::int(2); - // let result = expr1 + expr2; - - // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); - // } - - // #[test] - // fn test_expression_add_complex_to_float() { - // let expr1 = Expression::complex(1.0, 2.0); - // let expr2 = Expression::float(2.0); - // let result = expr1 + expr2; - - // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); - // } + assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + } + + #[test] + fn test_expression_add_float_to_complex() { + let expr1 = Expression::float(1.0); + let expr2 = Expression::complex(2.0, 4.0); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); + } + + + fn test_expression_add_complex_to_float() { + let expr1 = Expression::complex(1.0, 2.0); + let expr2 = Expression::float(2.0); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); + } - // #[test] - // fn test_expression_add_complex_to_complex() { - // let expr1 = Expression::complex(1.0, 2.0); - // let expr2 = Expression::complex(3.0, 4.0); - // let result = expr1 + expr2; - - // assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(4.0, 6.0)))); - // } - - // #[test] - // fn test_expression_add_symbol_to_int() { - // let symbol_expr = Expression::symbol("x"); - // let expr2 = Expression::int(1); - // let result = symbol_expr + expr2; - - // match result { - // Expression::Expr { head, args } => { - // assert_eq!(head, Operator::ADD); - // assert_eq!(*args[0], Expression::Symbol("x")); - // assert_eq!(*args[1], Expression::Value(Numerical::Int(1))); - // } - // _ => panic!("Expected an Expression::Expr with Operator::ADD"), - // } - - // } + #[test] + fn test_expression_add_complex_to_complex() { + let expr1 = Expression::complex(1.0, 2.0); + let expr2 = Expression::complex(3.0, 4.0); + let result = expr1 + expr2; + + assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(4.0, 6.0)))); + } } diff --git a/src/symbols.rs b/src/symbols.rs index 25ada66..6288a60 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -7,17 +7,11 @@ use std::fmt; #[derive(Copy, Clone, Debug, PartialEq)] pub enum Numerical { - Int(i64), Float(f64), Complex(Complex), } impl Numerical { - /// Convenience method to create a Numerical::Int - pub fn int(value: i64) -> Self { - Numerical::Int(value) - } - /// Convenience method to create a Numerical::Float pub fn float(value: f64) -> Self { Numerical::Float(value) @@ -32,7 +26,6 @@ impl Numerical { impl fmt::Display for Numerical { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Numerical::Int(value) => write!(f, "{}", value), Numerical::Float(value) => write!(f, "{}", value), Numerical::Complex(value) => write!(f, "{} + {}i", value.re, value.im), } @@ -46,7 +39,6 @@ impl Neg for Numerical { use Numerical::*; match self { - Int(i) => Numerical::int(-i), Float(f) => Numerical::float(-f), Complex(c) => Numerical::complex(-c.re, -c.im), } @@ -60,15 +52,10 @@ impl Pow for Numerical { use Numerical::*; match (self, rhs) { - (Int(base), Int(exp)) => Int((base as f64).powi(exp as i32) as i64), - (Float(base), Int(exp)) => Float(base.powi(exp as i32)), - (Complex(base), Int(exp)) => Complex(base.powi(exp as i32)), (Float(base), Float(exp)) => Float(base.powf(exp)), (Complex(base), Float(exp)) => Complex(base.powf(exp)), - (Int(base), Float(exp)) => Float((base as f64).powf(exp)), (Complex(base), Complex(exp)) => Complex(base.powc(exp)), (Float(base), Complex(exp)) => Complex((num::Complex::new(base, 0.0)).powc(exp)), - (Int(base), Complex(exp)) => Complex((num::Complex::new(base as f64, 0.0)).powc(exp)), } } } @@ -91,19 +78,8 @@ macro_rules! impl_binary_operator_for_numerical { (Complex(a), Float(b)) => Complex(a.$method(complex::from(b))), (Float(a), Complex(b)) => Complex(complex::from(a).$method(b)), - // Complex with Int - (Complex(a), Int(b)) => Complex(a.$method(complex::from(b as f64))), - (Int(a), Complex(b)) => Complex(complex::from(a as f64).$method(b)), - // Float and Float (Float(a), Float(b)) => Float(a.$method(b)), - - // Float with Int - (Float(a), Int(b)) => Float(a.$method(b as f64)), - (Int(a), Float(b)) => Float((a as f64).$method(b)), - - // Int and Int - (Int(a), Int(b)) => Int(a.$method(b)), } } } @@ -129,15 +105,6 @@ mod tests { (c1.re - c2.re).abs() < epsilon && (c1.im - c2.im).abs() < epsilon } - #[test] - fn test_negation_int() { - let num_int = Numerical::Int(10); - assert_eq!(-num_int, Numerical::Int(-10)); - - let num_int_neg = Numerical::Int(-10); - assert_eq!(-num_int_neg, Numerical::Int(10)); - } - #[test] fn test_negation_float() { let num_float = Numerical::Float(5.5); @@ -158,10 +125,6 @@ mod tests { #[test] fn test_numerical_pow() { - let n1 = Numerical::Int(2); - let n2 = Numerical::Int(3); - assert_eq!(n1.pow(n2), Numerical::Int(8)); - let n3 = Numerical::Float(2.0); let n4 = Numerical::Float(3.0); assert_eq!(n3.pow(n4), Numerical::Float(8.0)); @@ -175,46 +138,6 @@ mod tests { } } - #[test] - fn test_numerical_binary_ops_int_to_int() { - let n1 = Numerical::Int(5); - let n2 = Numerical::Int(10); - assert_eq!(n1 + n2, Numerical::Int(15)); - assert_eq!(n1 - n2, Numerical::Int(-5)); - assert_eq!(n1 * n2, Numerical::Int(50)); - assert_eq!(n1 / n2, Numerical::Int(0)); // integer division - } - - #[test] - fn test_numerical_binary_ops_int_to_float() { - let n1 = Numerical::Int(5); - let n2 = Numerical::Float(10.5); - assert_eq!(n1 + n2, Numerical::Float(15.5)); - assert_eq!(n1 - n2, Numerical::Float(-5.5)); - assert_eq!(n1 * n2, Numerical::Float(52.5)); - assert_eq!(n1 / n2, Numerical::Float(5.0 / 10.5)); - } - - #[test] - fn test_numerical_binary_ops_int_to_complex() { - let n1 = Numerical::int(5); - let n2 = Numerical::complex(10.0, 5.0); - assert_eq!(n1 + n2, Numerical::Complex(Complex::new(15.0, 5.0))); - assert_eq!(n1 - n2, Numerical::Complex(Complex::new(-5.0, -5.0))); - assert_eq!(n1 * n2, Numerical::Complex(Complex::new(50.0, 25.0))); - assert_eq!(n1 / n2, Numerical::Complex(Complex::new(0.4, -0.2))); - } - - #[test] - fn test_numerical_add_float_to_int() { - let n1 = Numerical::float(5.0); - let n2 = Numerical::int(10); - assert_eq!(n1 + n2, Numerical::Float(15.0)); - assert_eq!(n1 - n2, Numerical::Float(-5.0)); - assert_eq!(n1 * n2, Numerical::Float(50.0)); - assert_eq!(n1 / n2, Numerical::Float(0.5)); - } - #[test] fn test_numerical_binary_ops_float_to_float() { let n1 = Numerical::float(5.0); @@ -235,16 +158,6 @@ mod tests { assert_eq!(n1 / n2, Numerical::Complex(Complex::new(15.0 / 25.0, -20.0 / 25.0))); } - #[test] - fn test_numerical_binary_ops_complex_to_int() { - let n1 = Numerical::complex(5.0, 4.0); - let n2 = Numerical::int(3); - assert_eq!(n1 + n2, Numerical::Complex(Complex::new(8.0, 4.0))); - assert_eq!(n1 - n2, Numerical::Complex(Complex::new(2.0, 4.0))); - assert_eq!(n1 * n2, Numerical::Complex(Complex::new(15.0, 12.0))); - assert_eq!(n1 / n2, Numerical::Complex(Complex::new(5.0 / 3.0, 4.0 / 3.0))); - } - #[test] fn test_numerical_binary_ops_complex_to_float() { let n1 = Numerical::complex(5.0, 4.0); @@ -264,6 +177,4 @@ mod tests { assert_eq!(n1 * n2, Numerical::Complex(Complex::new(7.0, 22.0))); assert_eq!(n1 / n2, Numerical::Complex(Complex::new(23.0 / 13.0, 2.0 / 13.0))); } - - } From 461904685f2974be70feafc3fa836ae0d4e88da6 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 2 Jul 2024 12:12:36 +0100 Subject: [PATCH 53/55] Update expression and test to remove vboxing. --- src/expression.rs | 115 ++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index ada457c..ca863a9 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -5,17 +5,12 @@ use crate::symbols::Numerical; use std::ops::{Add, Div, Mul, Sub, Neg}; -#[macro_export] -macro_rules! vbox { - () => { vec![] }; - ($($x:expr),+ $(,)?) => { vec![$(Box::new($x)),*] }; -} #[derive(Clone, Debug, PartialEq)] pub enum Expression { Symbol(&'static str), Value(Numerical), - Expr { head: Operator, args: Vec> }, + Expr { head: Operator, args: Vec }, } // Implement helper functions to create different types of Expressions. @@ -45,7 +40,7 @@ impl Neg for Expression { // completeness, we could wrap it in an Expr with multiplication by -1. Symbol(s) => Expr { head: MUL, - args: vbox![ + args: vec![ Expression::float(-1.), Expression::symbol(s), ], @@ -59,7 +54,7 @@ impl Neg for Expression { // Negate the entire expression by multiplying by -1 Expr { head, args } => Expr { head: MUL, - args: vbox![ + args: vec![ Expression::float(-1.), Expr { head, @@ -84,14 +79,14 @@ impl Pow for Expression { // If the left side is already a power expression, chain the exponent. (Expr { head: POW, args: mut args_lhs }, rhs) => { - args_lhs.push(Box::new(rhs)); + args_lhs.push(rhs); Expr { head: POW, args: args_lhs } }, // Otherwise, create a new power expression. (lhs, rhs) => Expr { head: POW, - args: vbox![lhs, rhs], + args: vec![lhs, rhs], } } } @@ -114,16 +109,16 @@ macro_rules! impl_binary_operator_for_expression { }, (Expr {head: $operator, args: mut args_lhs}, rhs) => { - args_lhs.push(Box::new(rhs)); + args_lhs.push(rhs); Expr {head: $operator, args: args_lhs} }, (lhs, Expr {head: $operator, args: mut args_rhs}) => { - args_rhs.push(Box::new(lhs)); + args_rhs.push(lhs); Expr {head: $operator, args: args_rhs} }, - (lhs, rhs) => Expr{head: $operator, args: vbox![lhs, rhs]}, + (lhs, rhs) => Expr{head: $operator, args: vec![lhs, rhs]}, } } } @@ -140,7 +135,7 @@ macro_rules! impl_binary_operator_for_expression { (Value(x), Value(y)) => Value(x.$method(y)), (lhs, rhs) => Expr { head: $operator, - args: vbox![lhs, $inv(rhs)] + args: vec![lhs, $inv(rhs)] }, } } @@ -176,8 +171,8 @@ mod tests { Expr { head: MUL, args: vec![ - Box::new(Expression::int(-1)), - Box::new(Expression::symbol("y")), + Expression::float(-1.), + Expression::symbol("y"), ] } ); @@ -218,8 +213,8 @@ mod tests { Expr { head: ADD, args: vec![ - Box::new(Expression::float(1.)), - Box::new(Expression::symbol("x")), + Expression::float(1.), + Expression::symbol("x"), ] } ); @@ -234,64 +229,76 @@ mod tests { Expr { head: ADD, args: vec![ - Box::new(Expression::complex(1.0, 2.0)), - Box::new( - Expression::Expr { - head: MUL, - args: vec![ - Box::new(Expression::float(-1.)), - Box::new(Expression::symbol("x")), - ] - } - ), + Expression::complex(1.0, 2.0), + Expression::Expr { + head: MUL, + args: vec![ + Expression::float(-1.), + Expression::symbol("x"), + ] + } ] } ); } #[test] - fn test_numerical_binary_ops() { - let n1 = Expression::int(10); - let n2 = Expression::int(3); - assert_eq!(n1.clone() + n2.clone(), Expression::int(13)); - assert_eq!(n1.clone() - n2.clone(), Expression::int(7)); - assert_eq!(n1.clone() * n2.clone(), Expression::int(30)); - assert_eq!(n1 / n2, Expression::int(3)); - } - - #[test] - fn test_expression_add_float_to_float() { + fn test_expression_binary_ops_float_to_float() { let expr1 = Expression::float(1.0); let expr2 = Expression::float(2.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Float(3.0))); + let n1 = expr1.clone() + expr2.clone(); + let n2 = expr1.clone() - expr2.clone(); + let n3 = expr1.clone() * expr2.clone(); + let n4 = expr1.clone() / expr2.clone(); + + assert_eq!(n1, Expression::Value(Numerical::Float(3.0))); + assert_eq!(n2, Expression::Value(Numerical::Float(-1.0))); + assert_eq!(n3, Expression::Value(Numerical::Float(2.0))); + assert_eq!(n4, Expression::Value(Numerical::Float(0.5))); } #[test] - fn test_expression_add_float_to_complex() { + fn test_expression_binary_ops_float_to_complex() { let expr1 = Expression::float(1.0); let expr2 = Expression::complex(2.0, 4.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); + let n1 = expr1.clone() + expr2.clone(); + let n2 = expr1.clone() - expr2.clone(); + let n3 = expr1.clone() * expr2.clone(); + let n4 = expr1.clone() / expr2.clone(); + + assert_eq!(n1, Expression::Value(Numerical::Complex(Complex::new(3.0, 4.0)))); + assert_eq!(n2, Expression::Value(Numerical::Complex(Complex::new(-1.0, -4.0)))); + assert_eq!(n3, Expression::Value(Numerical::Complex(Complex::new(2.0, 4.0)))); + assert_eq!(n4, Expression::Value(Numerical::Complex(Complex::new(0.1, -0.2)))); } - - fn test_expression_add_complex_to_float() { + #[test] + fn test_expression_binary_ops_complex_to_float() { let expr1 = Expression::complex(1.0, 2.0); let expr2 = Expression::float(2.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); + let n1 = expr1.clone() + expr2.clone(); + let n2 = expr1.clone() - expr2.clone(); + let n3 = expr1.clone() * expr2.clone(); + let n4 = expr1.clone() / expr2.clone(); + + assert_eq!(n1, Expression::Value(Numerical::Complex(Complex::new(3.0, 2.0)))); + assert_eq!(n2, Expression::Value(Numerical::Complex(Complex::new(-1.0, 2.0)))); + assert_eq!(n3, Expression::Value(Numerical::Complex(Complex::new(2.0, 4.0)))); + assert_eq!(n4, Expression::Value(Numerical::Complex(Complex::new(0.5, 1.0)))); } #[test] fn test_expression_add_complex_to_complex() { let expr1 = Expression::complex(1.0, 2.0); let expr2 = Expression::complex(3.0, 4.0); - let result = expr1 + expr2; - - assert_eq!(result, Expression::Value(Numerical::Complex(Complex::new(4.0, 6.0)))); + let n1 = expr1.clone() + expr2.clone(); + let n2 = expr1.clone() - expr2.clone(); + let n3 = expr1.clone() * expr2.clone(); + let n4 = expr1.clone() / expr2.clone(); + + assert_eq!(n1, Expression::Value(Numerical::Complex(Complex::new(4.0, 6.0)))); + assert_eq!(n2, Expression::Value(Numerical::Complex(Complex::new(-2.0, -2.0)))); + assert_eq!(n3, Expression::Value(Numerical::Complex(Complex::new(-5.0, 10.0)))); + assert_eq!(n4, Expression::Value(Numerical::Complex(Complex::new(0.44, 0.08)))); } } From 8f78deb16b1f4aee1f329a7e5223aa03a9c1a659 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 2 Jul 2024 12:16:43 +0100 Subject: [PATCH 54/55] Use pi approx form std. --- src/expression.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index ca863a9..bc14ef2 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -180,8 +180,8 @@ mod tests { #[test] fn test_float_expression() { - let float_expr = Expression::float(3.14); - assert_eq!(float_expr, Expression::Value(Numerical::Float(3.14))); + let float_expr = Expression::float(std::f64::consts::FRAC_1_PI); + assert_eq!(float_expr, Expression::Value(Numerical::Float(std::f64::consts::FRAC_1_PI))); } #[test] From 5360beb2971e3fcd5f8e05a87b36012fad820703 Mon Sep 17 00:00:00 2001 From: Roland Guichard Date: Tue, 2 Jul 2024 12:23:12 +0100 Subject: [PATCH 55/55] Remove useless convenience function. --- src/expression.rs | 2 +- src/symbols.rs | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/expression.rs b/src/expression.rs index bc14ef2..4f5861b 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -20,7 +20,7 @@ impl Expression { } pub fn float(value: f64) -> Self { - Expression::Value(Numerical::float(value)) + Expression::Value(Numerical::Float(value)) } pub fn complex(real: f64, imag: f64) -> Self { diff --git a/src/symbols.rs b/src/symbols.rs index 6288a60..4280393 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -12,11 +12,6 @@ pub enum Numerical { } impl Numerical { - /// Convenience method to create a Numerical::Float - pub fn float(value: f64) -> Self { - Numerical::Float(value) - } - /// Convenience method to create a Numerical::Complex pub fn complex(re: f64, im: f64) -> Self { Numerical::Complex(Complex::new(re, im)) @@ -39,7 +34,7 @@ impl Neg for Numerical { use Numerical::*; match self { - Float(f) => Numerical::float(-f), + Float(f) => Numerical::Float(-f), Complex(c) => Numerical::complex(-c.re, -c.im), } } @@ -140,8 +135,8 @@ mod tests { #[test] fn test_numerical_binary_ops_float_to_float() { - let n1 = Numerical::float(5.0); - let n2 = Numerical::float(10.0); + let n1 = Numerical::Float(5.0); + let n2 = Numerical::Float(10.0); assert_eq!(n1 + n2, Numerical::Float(15.0)); assert_eq!(n1 - n2, Numerical::Float(-5.0)); assert_eq!(n1 * n2, Numerical::Float(50.0)); @@ -150,7 +145,7 @@ mod tests { #[test] fn test_numerical_binary_ops_float_to_complex() { - let n1 = Numerical::float(5.0); + let n1 = Numerical::Float(5.0); let n2 = Numerical::complex(3.0, 4.0); assert_eq!(n1 + n2, Numerical::Complex(Complex::new(8.0, 4.0))); assert_eq!(n1 - n2, Numerical::Complex(Complex::new(2.0, -4.0))); @@ -161,7 +156,7 @@ mod tests { #[test] fn test_numerical_binary_ops_complex_to_float() { let n1 = Numerical::complex(5.0, 4.0); - let n2 = Numerical::float(3.0); + let n2 = Numerical::Float(3.0); assert_eq!(n1 + n2, Numerical::Complex(Complex::new(8.0, 4.0))); assert_eq!(n1 - n2, Numerical::Complex(Complex::new(2.0, 4.0))); assert_eq!(n1 * n2, Numerical::Complex(Complex::new(15.0, 12.0)));