check if pval == val and abort subsequently
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
shimun 2019-12-20 23:23:03 +01:00
parent c4fd3c459d
commit a15fb494c2
Signed by: shimun
GPG Key ID: E81D8382DC2F971B

View File

@ -14,11 +14,17 @@ trait Context {
/// Simple Context will return it's value for any variable name /// Simple Context will return it's value for any variable name
impl Context for f64 { impl Context for f64 {
fn get(&self, name: &str) -> Option<f64> { fn get(&self, _: &str) -> Option<f64> {
Some(*self) Some(*self)
} }
} }
impl Context for () {
fn get(&self, _: &str) -> Option<f64> {
None
}
}
impl Context for MultiContext { impl Context for MultiContext {
fn get(&self, name: &str) -> Option<f64> { fn get(&self, name: &str) -> Option<f64> {
return self.vars.get(name).cloned(); return self.vars.get(name).cloned();
@ -34,7 +40,7 @@ impl MultiContext {
} }
trait Eval: Derive + fmt::Display { trait Eval: Derive + fmt::Display {
fn eval(&self, ctx: &dyn Context) -> f64; fn eval(&self, ctx: &dyn Context) -> Value;
fn boxed_clone(&self) -> Box<dyn Eval>; fn boxed_clone(&self) -> Box<dyn Eval>;
} }
@ -75,9 +81,9 @@ impl Derive for Value {
} }
impl Eval for Value { impl Eval for Value {
fn eval(&self, ctx: &dyn Context) -> f64 { fn eval(&self, ctx: &dyn Context) -> Value {
match self { match self {
Self::Const(c) => *c, Self::Const(c) => self.clone(),
Self::Eval(e) => e.eval(ctx), Self::Eval(e) => e.eval(ctx),
} }
} }
@ -86,13 +92,26 @@ impl Eval for Value {
} }
} }
impl Value {
fn result(&self) -> Option<f64> {
match self {
Self::Const(c) => Some(*c),
_ => None,
}
}
}
#[derive(Clone, Display)] #[derive(Clone, Display)]
#[display(fmt = "`{}`", _0)] #[display(fmt = "`{}`", _0)]
struct Var(String); struct Var(String);
impl Eval for Var { impl Eval for Var {
fn eval(&self, ctx: &dyn Context) -> f64 { fn eval(&self, ctx: &dyn Context) -> Value {
ctx.get(&self.0).unwrap() if let Some(c) = ctx.get(&self.0) {
Value::Const(c)
} else {
self.clone().into()
}
} }
fn boxed_clone(&self) -> Box<dyn Eval> { fn boxed_clone(&self) -> Box<dyn Eval> {
Box::new(self.clone()) Box::new(self.clone())
@ -138,15 +157,36 @@ enum Op {
} }
impl Eval for Op { impl Eval for Op {
fn eval(&self, ctx: &dyn Context) -> f64 { fn eval(&self, ctx: &dyn Context) -> Value {
match self { match self {
Self::Mul(a, b) => a.eval(ctx) * b.eval(ctx), Self::Mul(a, b) => match (a.eval(ctx), b.eval(ctx)) {
Self::Div(a, b) => a.eval(ctx) / b.eval(ctx), (Value::Const(a), Value::Const(b)) => Value::Const(a * b),
Self::Add(a, b) => a.eval(ctx) + b.eval(ctx), (a, b) => Self::mul(a, b).into(),
Self::Sub(a, b) => a.eval(ctx) - b.eval(ctx), },
Self::Pow(a, b) => a.eval(ctx).powf(b.eval(ctx)), Self::Div(a, b) => match (a.eval(ctx), b.eval(ctx)) {
Self::Ln(x) => x.eval(ctx).ln(), (Value::Const(a), Value::Const(b)) => Value::Const(a / b),
Self::Exp(x) => x.eval(ctx).exp(), (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<dyn Eval> { fn boxed_clone(&self) -> Box<dyn Eval> {
@ -214,12 +254,28 @@ impl Into<Value> for Op {
} }
} }
fn newton_raphson<'a>(eq: &'a dyn Eval, x0: f64, precision: i32) -> impl Iterator<Item = f64> + 'a { fn take_while_unprecsise<'a>(
precision: i32,
it: impl Iterator<Item = f64> + 'a,
) -> impl Iterator<Item = f64> + 'a {
let mut prev: Option<f64> = 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<Item = f64> + 'a {
//xp - f(x)/f'(x) //xp - f(x)/f'(x)
let d = eq.derive(); let d = eq.derive();
let eq = eq.clone(); let eq = eq.clone();
let mut i = 0; let mut i = 0;
let mut same_counter = 0usize;
successors(Some(x0), move |xp: &f64| -> Option<f64> { successors(Some(x0), move |xp: &f64| -> Option<f64> {
let ctx = xp; let ctx = xp;
let calc = Op::Sub( 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); println!("( {}.) {} -> {}\n", &i, &calc, &xp);
i += 1; i += 1;
let x = calc.eval(ctx); let x = calc.eval(ctx).result().unwrap();
let equal = (x - xp).abs() < (10.0f64).powi(-1 * precision as i32); Some(x)
if equal { })
dbg!(("Reached precision after ", i)); .take(10usize.pow(4))
.scan(None, |state: &mut Option<f64>, 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<f64> {
Value::Const(number), Value::Const(number),
) )
.into(); .into();
newton_raphson(&eq, 1.0, 10).last() take_while_unprecsise(1, newton_raphson(&eq, 1.0)).last()
} }
fn main() { fn main() {
@ -267,11 +323,22 @@ fn main() {
Value::Const(9.0), Value::Const(9.0),
) )
.into(); .into();
println!("{}", eq.eval(&ctx));
fn pow_to_x(b: f64) -> Value { fn pow_to_x(b: f64) -> Value {
Op::Pow(Value::Const(b), Var::val("x")).into() 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 = n_root(9.4, 2.0);
let res = newton_raphson(&eq, 1.0, 8).last(); //let res = newton_raphson(&eq, 1.0).last();
println!("1.0 - {}/{} ==> {}", &eq, "", res.unwrap()); println!(
"{}\n1.0 - {}/{} ==> {}",
&eq,
&eq.eval(&()),
"",
res.unwrap()
);
} }