Instantly share code, notes, and snippets.

Embed
What would you like to do?
use std::env;
use std::fmt;
use std::ops::{Add, Mul};
use std::rc::Rc;
thread_local! {
static MINUS_ONE_EXPR: Expr = Expr::int(-1);
static ONE_EXPR: Expr = Expr::int(1);
static ZERO_EXPR: Expr = Expr::int(0);
}
#[derive(Clone, Debug)]
enum _Expr {
Int(i64),
Var(String),
Add(Expr, Expr),
Mul(Expr, Expr),
Pow(Expr, Expr),
Ln(Expr),
}
#[derive(Clone, Debug)]
pub struct Expr(Rc<_Expr>);
impl From<_Expr> for Expr {
fn from(e: _Expr) -> Self {
Expr(e.into())
}
}
fn pown(base: i64, expt: i64) -> i64 {
match expt {
0 => 1,
1 => base,
_ => {
let b = pown(base, expt / 2);
b * b * if expt % 2 == 0 { 1 } else { base }
}
}
}
fn decompose_add(_expr: &Expr) -> (i64, Option<&Expr>) {
match &*_expr.0 {
_Expr::Int(n) => (*n, None),
_Expr::Add(f, g) => match *f.0 {
_Expr::Int(n) => (n, Some(g)),
_ => (0, Some(_expr)),
},
_ => (0, Some(_expr)),
}
}
fn decompose_mul(_expr: &Expr) -> (i64, Option<&Expr>) {
match &*_expr.0 {
_Expr::Int(n) => (*n, None),
_Expr::Mul(f, g) => match *f.0 {
_Expr::Int(n) => (n, Some(g)),
_ => (1, Some(_expr)),
},
_ => (1, Some(_expr)),
}
}
impl Add<&Expr> for &Expr {
type Output = Expr;
fn add(self, other: &Expr) -> Expr {
use crate::_Expr::*;
let (m, fo) = decompose_add(self);
let (n, go) = decompose_add(other);
let mn = m + n;
let fg = match (fo, go) {
(None, None) => return Int(mn).into(),
(Some(f), None) => f.clone(),
(None, Some(g)) => g.clone(),
(Some(f), Some(g)) => Add(f.clone(), g.clone()).into(),
};
if mn == 0 {
fg
} else {
Add(Int(mn).into(), fg).into()
}
}
}
impl Mul<&Expr> for &Expr {
type Output = Expr;
fn mul(self, other: &Expr) -> Expr {
use crate::_Expr::*;
let (m, fo) = decompose_mul(self);
let (n, go) = decompose_mul(other);
let mn = m * n;
if mn == 0 {
return ZERO_EXPR.with(Clone::clone);
}
let fg = match (fo, go) {
(None, None) => return Int(mn).into(),
(Some(f), None) => f.clone(),
(None, Some(g)) => g.clone(),
(Some(f), Some(g)) => Mul(f.clone(), g.clone()).into(),
};
if mn == 1 {
fg
} else {
Mul(Int(mn).into(), fg).into()
}
}
}
impl Expr {
pub fn int(i: i64) -> Self {
Expr(_Expr::Int(i).into())
}
pub fn var(s: &str) -> Self {
Expr(_Expr::Var(s.to_owned()).into())
}
pub fn pow(&self, other: &Expr) -> Expr {
use crate::_Expr::*;
match (&*self.0, &*other.0) {
(Int(m), Int(n)) => Int(pown(*m, *n)).into(),
(_, Int(0)) => ONE_EXPR.with(Clone::clone),
(_a, Int(1)) => self.clone(),
(Int(0), _) => ZERO_EXPR.with(Clone::clone),
(_a, _b) => Pow(self.clone(), other.clone()).into(),
}
}
pub fn ln(&self) -> Expr {
use crate::_Expr::*;
match &*self.0 {
Int(1) => ZERO_EXPR.with(Clone::clone),
_a => Ln(self.clone()).into(),
}
}
pub fn d(&self, x: &str) -> Expr {
use crate::_Expr::*;
match &*self.0 {
Var(y) => {
if *x == **y {
ONE_EXPR.with(Clone::clone)
} else {
ZERO_EXPR.with(Clone::clone)
}
}
Int(_) => ZERO_EXPR.with(Clone::clone),
Add(f, g) => &f.d(x) + &g.d(x),
Mul(f, g) => &(f * &g.d(x)) + &(g * &f.d(x)),
Pow(f, g) => {
&(self * &(g * &(&f.d(x) * &MINUS_ONE_EXPR.with(|minus_one| f.pow(minus_one)))))
+ &(&f.ln() * &g.d(x))
}
Ln(f) => &f.d(x) * &MINUS_ONE_EXPR.with(|minus_one| f.pow(minus_one)),
}
}
pub fn count(&self) -> usize {
use crate::_Expr::*;
match &*self.0 {
Var(_) => 1,
Int(_) => 1,
Add(f, g) => f.count() + g.count(),
Mul(f, g) => f.count() + g.count(),
Pow(f, g) => f.count() + g.count(),
Ln(f) => f.count(),
}
}
fn format(&self, f: &mut fmt::Formatter, old_prec: usize) -> fmt::Result {
use crate::_Expr::*;
fn bracket<F>(
f: &mut fmt::Formatter,
old_prec: usize,
new_prec: usize,
body: F,
) -> fmt::Result
where
F: FnOnce(&mut fmt::Formatter) -> fmt::Result,
{
if new_prec < old_prec {
f.write_str("(")?;
}
body(f)?;
if new_prec < old_prec {
f.write_str(")")?;
}
Ok(())
}
match &*self.0 {
Var(name) => f.write_str(&*name),
Int(n) => write!(f, "{}", n),
Add(g, h) => bracket(f, old_prec, 1, |f| {
g.format(f, 1)?;
f.write_str(" + ")?;
h.format(f, 1)
}),
Mul(g, h) => bracket(f, old_prec, 2, |f| {
g.format(f, 2)?;
f.write_str("*")?;
h.format(f, 2)
}),
Pow(g, h) => bracket(f, old_prec, 3, |f| {
g.format(f, 2)?;
f.write_str("^")?;
h.format(f, 3)
}),
Ln(g) => {
f.write_str("ln(")?;
g.format(f, 1)?;
f.write_str(")")
}
}
}
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let n = self.count();
if n > 100 {
write!(f, "<<{}>>", n)
} else {
self.format(f, 1)
}
}
}
fn nest<A, F: Fn(A) -> A>(n: usize, f: F, mut x: A) -> A {
for _ in 0..n {
x = f(x);
}
x
}
fn deriv(f: Expr) -> Expr {
let d = f.d("x");
println!("D({}) = {}", f, d);
d
}
fn main() {
let x: Expr = _Expr::Var("x".into()).into();
let f = x.clone().pow(&x);
let n = env::args().nth(1).expect("n").parse().unwrap();
nest(n, deriv, f);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment