Files
rusty_num/src/main.rs
shimun a15fb494c2
Some checks failed
continuous-integration/drone/push Build is failing
check if pval == val and abort subsequently
2019-12-20 23:23:03 +01:00

345 lines
8.9 KiB
Rust

extern crate derive_more;
use derive_more::Display;
use std::collections::HashMap;
use std::fmt;
use std::iter::successors;
#[derive(Clone)]
struct MultiContext {
vars: HashMap<String, f64>,
}
trait Context {
fn get(&self, name: &str) -> Option<f64>;
}
/// Simple Context will return it's value for any variable name
impl Context for 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();
}
}
impl MultiContext {
fn with(&self, name: String, value: f64) -> Self {
let mut n = self.clone();
n.vars.insert(name, value);
n
}
}
trait Eval: Derive + fmt::Display {
fn eval(&self, ctx: &dyn Context) -> Value;
fn boxed_clone(&self) -> Box<dyn Eval>;
}
trait Derive {
fn derive(&self) -> Value;
}
#[derive(Display)]
enum Value {
#[display(fmt = "{}", _0)]
Const(f64),
#[display(fmt = "{}", _0)]
Eval(Box<dyn Eval>),
}
impl From<f64> for Value {
fn from(f: f64) -> Self {
Self::Const(f)
}
}
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: &dyn Context) -> Value {
match self {
Self::Const(c) => self.clone(),
Self::Eval(e) => e.eval(ctx),
}
}
fn boxed_clone(&self) -> Box<dyn Eval> {
Box::new(self.clone())
}
}
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) -> 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())
}
}
impl Derive for Var {
fn derive(&self) -> Value {
Value::Const(1.0)
}
}
impl Into<Value> for Var {
fn into(self) -> Value {
Value::Eval(Box::new(self))
}
}
impl Var {
fn new<T: Into<String>>(name: T) -> Self {
Var(name.into())
}
fn val<T: Into<String>>(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),
#[display(fmt = "ln({})", _0)]
Ln(Value),
#[display(fmt = "exp({})", _0)]
Exp(Value),
}
impl Eval for Op {
fn eval(&self, ctx: &dyn Context) -> Value {
match self {
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> {
Box::new(self.clone())
}
}
impl Op {
fn exp<T: Into<Value>>(x: T) -> Self {
Self::Exp(x.into())
}
fn ln<T: Into<Value>>(x: T) -> Self {
Self::Ln(x.into())
}
fn sub<T: Into<Value>, U: Into<Value>>(a: T, b: U) -> Self {
Self::Sub(a.into(), b.into())
}
fn add<T: Into<Value>, U: Into<Value>>(a: T, b: U) -> Self {
Self::Add(a.into(), b.into())
}
fn mul<T: Into<Value>, U: Into<Value>>(a: T, b: U) -> Self {
Self::Mul(a.into(), b.into())
}
fn div<T: Into<Value>, U: Into<Value>>(a: T, b: U) -> Self {
Self::Div(a.into(), b.into())
}
fn pow<T: Into<Value>, U: Into<Value>>(a: T, b: U) -> Self {
Self::Pow(a.into(), b.into())
}
}
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()),
Op::Mul(a.clone(), b.derive()),
),
Op::pow(b.clone(), 2.0),
),
Self::Add(a, b) => Op::add(a.derive(), b.derive()),
Self::Sub(a, b) => Op::sub(a.derive(), b.derive()),
Self::Pow(a, b) => match b {
Value::Eval(e) => Op::mul(Op::ln(a.clone()), Op::pow(a.clone(), b.clone())),
b => Op::pow(Op::mul(a.clone(), b.clone()), Op::sub(b.clone(), 1.0)),
},
Self::Ln(x) => Op::div(1.0, x.clone()),
Self::Exp(x) => Op::mul(x.derive(), Op::exp(x.clone())),
}
.into()
}
}
impl Into<Value> for Op {
fn into(self) -> Value {
Value::Eval(Box::new(self))
}
}
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;
successors(Some(x0), move |xp: &f64| -> Option<f64> {
let ctx = xp;
let calc = Op::Sub(
Var::val("x"),
Op::Div(Value::Eval(eq.boxed_clone()), d.clone()).into(),
);
println!("( {}.) {} -> {}\n", &i, &calc, &xp);
i += 1;
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)
}
})
}
fn n_root(number: f64, n: f64) -> Option<f64> {
let eq: Value = Op::Sub(
Op::Pow(Var::val("x"), Value::Const(n).into()).into(),
Value::Const(number),
)
.into();
take_while_unprecsise(1, newton_raphson(&eq, 1.0)).last()
}
fn main() {
let ctx = MultiContext {
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();
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)),
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).last();
println!(
"{}\n1.0 - {}/{} ==> {}",
&eq,
&eq.eval(&()),
"",
res.unwrap()
);
}