This commit is contained in:
shimun 2019-11-20 20:39:52 +01:00
commit f8a8727fdd
Signed by: shimun
GPG Key ID: E81D8382DC2F971B
3 changed files with 277 additions and 0 deletions

56
Cargo.lock generated Normal file
View File

@ -0,0 +1,56 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "derive_more"
version = "0.99.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "eq"
version = "0.1.0"
dependencies = [
"derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2159be042979966de68315bce7034bb000c775f22e3e834e1c52ff78f041cae8"
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"

10
Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "eq"
version = "0.1.0"
authors = ["shimun <shimun@shimun.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
derive_more = "0.99.2"

211
src/main.rs Normal file
View 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());
}