From a15fb494c2a3b4b03dcf6fb40f7ca3b702113833 Mon Sep 17 00:00:00 2001 From: shimun Date: Fri, 20 Dec 2019 23:23:03 +0100 Subject: [PATCH] check if pval == val and abort subsequently --- src/main.rs | 125 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 29 deletions(-) diff --git a/src/main.rs b/src/main.rs index e602629..4e1c3b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,11 +14,17 @@ trait Context { /// Simple Context will return it's value for any variable name impl Context for f64 { - fn get(&self, name: &str) -> Option { + fn get(&self, _: &str) -> Option { Some(*self) } } +impl Context for () { + fn get(&self, _: &str) -> Option { + None + } +} + impl Context for MultiContext { fn get(&self, name: &str) -> Option { return self.vars.get(name).cloned(); @@ -34,7 +40,7 @@ impl MultiContext { } trait Eval: Derive + fmt::Display { - fn eval(&self, ctx: &dyn Context) -> f64; + fn eval(&self, ctx: &dyn Context) -> Value; fn boxed_clone(&self) -> Box; } @@ -75,9 +81,9 @@ impl Derive for Value { } impl Eval for Value { - fn eval(&self, ctx: &dyn Context) -> f64 { + fn eval(&self, ctx: &dyn Context) -> Value { match self { - Self::Const(c) => *c, + Self::Const(c) => self.clone(), Self::Eval(e) => e.eval(ctx), } } @@ -86,13 +92,26 @@ impl Eval for Value { } } +impl Value { + fn result(&self) -> Option { + match self { + Self::Const(c) => Some(*c), + _ => None, + } + } +} + #[derive(Clone, Display)] #[display(fmt = "`{}`", _0)] struct Var(String); impl Eval for Var { - fn eval(&self, ctx: &dyn Context) -> f64 { - ctx.get(&self.0).unwrap() + fn eval(&self, ctx: &dyn Context) -> Value { + if let Some(c) = ctx.get(&self.0) { + Value::Const(c) + } else { + self.clone().into() + } } fn boxed_clone(&self) -> Box { Box::new(self.clone()) @@ -138,15 +157,36 @@ enum Op { } impl Eval for Op { - fn eval(&self, ctx: &dyn Context) -> f64 { + fn eval(&self, ctx: &dyn Context) -> Value { 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)), - Self::Ln(x) => x.eval(ctx).ln(), - Self::Exp(x) => x.eval(ctx).exp(), + Self::Mul(a, b) => match (a.eval(ctx), b.eval(ctx)) { + (Value::Const(a), Value::Const(b)) => Value::Const(a * b), + (a, b) => Self::mul(a, b).into(), + }, + Self::Div(a, b) => match (a.eval(ctx), b.eval(ctx)) { + (Value::Const(a), Value::Const(b)) => Value::Const(a / b), + (a, b) => Self::div(a, b).into(), + }, + Self::Add(a, b) => match (a.eval(ctx), b.eval(ctx)) { + (Value::Const(a), Value::Const(b)) => Value::Const(a + b), + (a, b) => Self::add(a, b).into(), + }, + Self::Sub(a, b) => match (a.eval(ctx), b.eval(ctx)) { + (Value::Const(a), Value::Const(b)) => Value::Const(a - b), + (a, b) => Self::sub(a, b).into(), + }, + Self::Pow(a, b) => match (a.eval(ctx), b.eval(ctx)) { + (Value::Const(a), Value::Const(b)) => Value::Const(a.powf(b)), + (a, b) => Self::pow(a, b).into(), + }, + Self::Ln(x) => match x.eval(ctx) { + Value::Const(x) => Value::Const(x.ln()), + x => Self::ln(x).into(), + }, + Self::Exp(x) => match x.eval(ctx) { + Value::Const(x) => Value::Const(x.exp()), + x => Self::exp(x).into(), + }, } } fn boxed_clone(&self) -> Box { @@ -214,12 +254,28 @@ impl Into for Op { } } -fn newton_raphson<'a>(eq: &'a dyn Eval, x0: f64, precision: i32) -> impl Iterator + 'a { +fn take_while_unprecsise<'a>( + precision: i32, + it: impl Iterator + 'a, +) -> impl Iterator + 'a { + let mut prev: Option = None; + it.filter(move |v| { + let prd = prev + .map(|prev| { + let d = dbg!((prev - v).abs()); + d != 0.0 && d > dbg!(10.0f64.powi(-1 * precision)) + }) + .unwrap_or(true); + prev = Some(*v); + prd && false + }) +} + +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; - let mut same_counter = 0usize; successors(Some(x0), move |xp: &f64| -> Option { let ctx = xp; let calc = Op::Sub( @@ -228,16 +284,16 @@ fn newton_raphson<'a>(eq: &'a dyn Eval, x0: f64, precision: i32) -> impl Iterato ); println!("( {}.) {} -> {}\n", &i, &calc, &xp); i += 1; - let x = calc.eval(ctx); - let equal = (x - xp).abs() < (10.0f64).powi(-1 * precision as i32); - if equal { - dbg!(("Reached precision after ", i)); + let x = calc.eval(ctx).result().unwrap(); + Some(x) + }) + .take(10usize.pow(4)) + .scan(None, |state: &mut Option, val| match state { + Some(pval) if pval.to_bits() == val.to_bits() => None, + _ => { + *state = Some(val); + Some(val) } - if same_counter > 3 { - dbg!(("Aborted after", i)); - } - same_counter = (same_counter + equal as usize) * (equal as usize); - Some(x).filter(|_| !equal && same_counter < 3 && !x.is_nan()) }) } @@ -247,7 +303,7 @@ fn n_root(number: f64, n: f64) -> Option { Value::Const(number), ) .into(); - newton_raphson(&eq, 1.0, 10).last() + take_while_unprecsise(1, newton_raphson(&eq, 1.0)).last() } fn main() { @@ -267,11 +323,22 @@ fn main() { Value::Const(9.0), ) .into(); + println!("{}", eq.eval(&ctx)); fn pow_to_x(b: f64) -> Value { Op::Pow(Value::Const(b), Var::val("x")).into() } - let eq: Value = Op::Sub(Op::Add(pow_to_x(4.0), pow_to_x(6.0)).into(), pow_to_x(9.0)).into(); + let eq: Value = Op::sub( + Op::add(pow_to_x(4.0), pow_to_x(6.0)), + Op::pow(Op::add(5.0, 4.0), Op::mul(Var::val("x"), 1.0)), + ) + .into(); let res = n_root(9.4, 2.0); - let res = newton_raphson(&eq, 1.0, 8).last(); - println!("1.0 - {}/{} ==> {}", &eq, "", res.unwrap()); + //let res = newton_raphson(&eq, 1.0).last(); + println!( + "{}\n1.0 - {}/{} ==> {}", + &eq, + &eq.eval(&()), + "", + res.unwrap() + ); }