From f8a8727fdd56f6e7b69acd270891c3a08fd2fa12 Mon Sep 17 00:00:00 2001 From: shimun Date: Wed, 20 Nov 2019 20:39:52 +0100 Subject: [PATCH] init --- Cargo.lock | 56 ++++++++++++++ Cargo.toml | 10 +++ src/main.rs | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..20874c3 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,56 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "derive_more" +version = "0.99.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "eq" +version = "0.1.0" +dependencies = [ + "derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2159be042979966de68315bce7034bb000c775f22e3e834e1c52ff78f041cae8" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1c4a4ef --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "eq" +version = "0.1.0" +authors = ["shimun "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +derive_more = "0.99.2" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..64abc33 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,211 @@ +extern crate derive_more; +use derive_more::Display; +use std::collections::HashMap; +use std::fmt; +use std::iter::successors; +#[derive(Clone)] +struct Context { + vars: HashMap, +} + +impl Context { + fn get(&self, name: &str) -> Option { + return self.vars.get(name).cloned(); + } + + fn with(&self, name: String, value: f64) -> Context { + let mut n = self.clone(); + n.vars.insert(name, value); + n + } +} + +trait Eval: Derive + fmt::Display { + fn eval(&self, ctx: &Context) -> f64; + fn boxed_clone(&self) -> Box; +} + +trait Derive { + fn derive(&self) -> Value; +} + +#[derive(Display)] +enum Value { + #[display(fmt = "{}", _0)] + Const(f64), + #[display(fmt = "{}", _0)] + Eval(Box), +} + +impl Clone for Value { + fn clone(&self) -> Self { + match self { + Self::Const(c) => Self::Const(*c), + Self::Eval(e) => Self::Eval(e.boxed_clone()), + } + } +} + +impl Derive for Value { + fn derive(&self) -> Value { + match self { + Self::Const(_) => Value::Const(0.0), + Self::Eval(e) => e.derive(), + } + } +} + +impl Eval for Value { + fn eval(&self, ctx: &Context) -> f64 { + match self { + Self::Const(c) => *c, + Self::Eval(e) => e.eval(&ctx), + } + } + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } +} + +#[derive(Clone, Display)] +#[display(fmt = "`{}`", _0)] +struct Var(String); + +impl Eval for Var { + fn eval(&self, ctx: &Context) -> f64 { + ctx.get(&self.0).unwrap() + } + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } +} + +impl Derive for Var { + fn derive(&self) -> Value { + Value::Const(1.0) + } +} + +impl Into for Var { + fn into(self) -> Value { + Value::Eval(Box::new(self)) + } +} + +impl Var { + fn new>(name: T) -> Self { + Var(name.into()) + } + fn val>(name: T) -> Value { + Self::new(name).into() + } +} +#[derive(Clone, Display)] +enum Op { + #[display(fmt = "{} * {}", _0, _1)] + Mul(Value, Value), + #[display(fmt = "{} /({})", _0, _1)] + Div(Value, Value), + #[display(fmt = "{} + {}", _0, _1)] + Add(Value, Value), + #[display(fmt = "{} - {}", _0, _1)] + Sub(Value, Value), + #[display(fmt = "{}**({})", _0, _1)] + Pow(Value, Value), +} + +impl Eval for Op { + fn eval(&self, ctx: &Context) -> f64 { + match self { + Self::Mul(a, b) => a.eval(ctx) * b.eval(ctx), + Self::Div(a, b) => a.eval(ctx) / b.eval(ctx), + Self::Add(a, b) => a.eval(ctx) + b.eval(ctx), + Self::Sub(a, b) => a.eval(ctx) - b.eval(ctx), + Self::Pow(a, b) => a.eval(ctx).powf(b.eval(ctx)), + } + } + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } +} + +impl Derive for Op { + fn derive(&self) -> Value { + match self { + Self::Mul(a, b) => Op::Add( + Op::Mul(a.derive(), b.clone()).into(), + Op::Mul(a.clone(), b.derive()).into(), + ), + Self::Div(a, b) => Op::Div( + Op::Sub( + Op::Mul(a.derive(), b.clone()).into(), + Op::Mul(a.clone(), b.derive()).into(), + ) + .into(), + Op::Pow(b.clone(), Value::Const(2.0)).into(), + ), + Self::Add(a, b) => Op::Add(a.derive(), b.derive()), + Self::Sub(a, b) => Op::Sub(a.derive(), b.derive()), + Self::Pow(a, b) => Op::Pow( + Op::Mul(a.clone(), b.clone()).into(), + Op::Sub(b.clone(), Value::Const(1.0)).into(), + ), + } + .into() + } +} + +impl Into for Op { + fn into(self) -> Value { + Value::Eval(Box::new(self)) + } +} + +fn newton_raphson<'a>(eq: &'a dyn Eval, x0: f64) -> impl Iterator + 'a { + //xp - f(x)/f'(x) + let d = eq.derive(); + let eq = eq.clone(); + let mut i = 0; + successors(Some(x0), move |xp: &f64| -> Option { + let ctx = Context { + vars: vec![("x".to_string(), *xp)].into_iter().collect(), + }; + let calc = Op::Sub( + Var::val("x"), + Op::Div(Value::Eval(eq.boxed_clone()), d.clone()).into(), + ); + println!("( {}.) {} -> {}\n", &i, &calc, &xp); + i += 1; + Some(calc.eval(&ctx)).filter(|x| (x - xp).abs() > (10.0f64).powf(-8.0)) + }) +} + +fn n_root(number: f64, n: f64) -> Option { + let eq: Value = Op::Sub( + Op::Pow(Var::val("x"), Value::Const(n).into()).into(), + Value::Const(number), + ) + .into(); + newton_raphson(&eq, 1.0).last() +} + +fn main() { + let ctx = Context { + vars: vec![("x".to_string(), 5.0)].into_iter().collect(), + }; + let eq = Op::Sub( + Op::Add( + Op::Pow(Value::Const(3.0), Var::val("x")).into(), + Op::Pow(Value::Const(9.0), Var::val("x")).into(), + ) + .into(), + Op::Pow(Value::Const(4.0), Var::val("x")).into(), + ); + let eq: Value = Op::Sub( + Op::Pow(Var::val("x"), Value::Const(2.0).into()).into(), + Value::Const(9.0), + ) + .into(); + let res = n_root(9.0, 2.0); + println!("1.0 - {}/{} ==> {}", &eq, eq.derive(), res.unwrap()); +}