init
This commit is contained in:
211
src/main.rs
Normal file
211
src/main.rs
Normal file
@@ -0,0 +1,211 @@
|
||||
extern crate derive_more;
|
||||
use derive_more::Display;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::iter::successors;
|
||||
#[derive(Clone)]
|
||||
struct Context {
|
||||
vars: HashMap<String, f64>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
fn get(&self, name: &str) -> Option<f64> {
|
||||
return self.vars.get(name).cloned();
|
||||
}
|
||||
|
||||
fn with(&self, name: String, value: f64) -> Context {
|
||||
let mut n = self.clone();
|
||||
n.vars.insert(name, value);
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
trait Eval: Derive + fmt::Display {
|
||||
fn eval(&self, ctx: &Context) -> f64;
|
||||
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 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: &Context) -> f64 {
|
||||
match self {
|
||||
Self::Const(c) => *c,
|
||||
Self::Eval(e) => e.eval(&ctx),
|
||||
}
|
||||
}
|
||||
fn boxed_clone(&self) -> Box<dyn Eval> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Display)]
|
||||
#[display(fmt = "`{}`", _0)]
|
||||
struct Var(String);
|
||||
|
||||
impl Eval for Var {
|
||||
fn eval(&self, ctx: &Context) -> f64 {
|
||||
ctx.get(&self.0).unwrap()
|
||||
}
|
||||
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),
|
||||
}
|
||||
|
||||
impl Eval for Op {
|
||||
fn eval(&self, ctx: &Context) -> f64 {
|
||||
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)),
|
||||
}
|
||||
}
|
||||
fn boxed_clone(&self) -> Box<dyn Eval> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
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()).into(),
|
||||
Op::Mul(a.clone(), b.derive()).into(),
|
||||
)
|
||||
.into(),
|
||||
Op::Pow(b.clone(), Value::Const(2.0)).into(),
|
||||
),
|
||||
Self::Add(a, b) => Op::Add(a.derive(), b.derive()),
|
||||
Self::Sub(a, b) => Op::Sub(a.derive(), b.derive()),
|
||||
Self::Pow(a, b) => Op::Pow(
|
||||
Op::Mul(a.clone(), b.clone()).into(),
|
||||
Op::Sub(b.clone(), Value::Const(1.0)).into(),
|
||||
),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Value> for Op {
|
||||
fn into(self) -> Value {
|
||||
Value::Eval(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
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 = Context {
|
||||
vars: vec![("x".to_string(), *xp)].into_iter().collect(),
|
||||
};
|
||||
let calc = Op::Sub(
|
||||
Var::val("x"),
|
||||
Op::Div(Value::Eval(eq.boxed_clone()), d.clone()).into(),
|
||||
);
|
||||
println!("( {}.) {} -> {}\n", &i, &calc, &xp);
|
||||
i += 1;
|
||||
Some(calc.eval(&ctx)).filter(|x| (x - xp).abs() > (10.0f64).powf(-8.0))
|
||||
})
|
||||
}
|
||||
|
||||
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();
|
||||
newton_raphson(&eq, 1.0).last()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let ctx = Context {
|
||||
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();
|
||||
let res = n_root(9.0, 2.0);
|
||||
println!("1.0 - {}/{} ==> {}", &eq, eq.derive(), res.unwrap());
|
||||
}
|
Reference in New Issue
Block a user