345 lines
8.9 KiB
Rust
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()
|
|
);
|
|
}
|