Compare commits
1 Commits
master
...
partial_ev
Author | SHA1 | Date | |
---|---|---|---|
a15fb494c2 |
125
src/main.rs
125
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<f64> {
|
||||
fn get(&self, _: &str) -> Option<f64> {
|
||||
Some(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for () {
|
||||
fn get(&self, _: &str) -> Option<f64> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for MultiContext {
|
||||
fn get(&self, name: &str) -> Option<f64> {
|
||||
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<dyn Eval>;
|
||||
}
|
||||
|
||||
@ -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<f64> {
|
||||
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<dyn Eval> {
|
||||
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<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)
|
||||
let d = eq.derive();
|
||||
let eq = eq.clone();
|
||||
let mut i = 0;
|
||||
let mut same_counter = 0usize;
|
||||
successors(Some(x0), move |xp: &f64| -> Option<f64> {
|
||||
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<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),
|
||||
)
|
||||
.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()
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user