//! Symbolic differentiation with rational coefficents. use std::fmt; use std::ops::*; /// Rational number represented by two isize, numerator and denominator. /// /// Each Rational number should be normalized so that `demoninator` is nonnegative and `numerator` and `demoninator` are coprime. /// See `normalize` for examples. As a corner case, 0 is represented by Rational { numerator: 0, demoninator: 0 }. /// /// For "natural use", Rational also overloads standard arithmetic operations, i.e, `+`, `-`, `*`, `/`. /// /// See [here](https://doc.rust-lang.org/core/ops/index.html) for details. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Rational { numerator: isize, denominator: isize, } // Some useful constants. /// Zero pub const ZERO: Rational = Rational::new(0, 0); /// One pub const ONE: Rational = Rational::new(1, 1); /// Minus one pub const MINUS_ONE: Rational = Rational::new(-1, 1); impl Rational { /// Creates a new rational number. pub const fn new(numerator: isize, denominator: isize) -> Self { Self { numerator, denominator, } } } impl Add for Rational { type Output = Self; fn add(self, rhs: Self) -> Self::Output { todo!() } } impl Mul for Rational { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { todo!() } } impl Sub for Rational { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { todo!() } } impl Div for Rational { type Output = Self; fn div(self, rhs: Self) -> Self::Output { todo!() } } /// Differentiable functions. /// /// For simplicity, we only consider infinitely differentiable functions. pub trait Differentiable: Clone { /// Differentiate. /// /// Since the return type is `Self`, this trait can only be implemented /// for types that are closed under differentiation. fn diff(&self) -> Self; } impl Differentiable for Rational { /// HINT: Consult fn diff(&self) -> Self { todo!() } } /// Singleton polynomial. /// /// Unlike regular polynomials, this type only represents a single term. /// The `Const` variant is included to make `Polynomial` closed under differentiation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SingletonPolynomial { /// Constant polynomial. Const(Rational), /// Non-const polynomial. Polynomial { /// coefficent of polynomial. Must be non-zero. coeff: Rational, /// power of polynomial. Must be non-zero. power: Rational, }, } impl SingletonPolynomial { /// Creates a new const polynomial. pub fn new_c(r: Rational) -> Self { todo!() } /// Creates a new polynomial. pub fn new_poly(coeff: Rational, power: Rational) -> Self { todo!() } } impl Differentiable for SingletonPolynomial { /// HINT: Consult fn diff(&self) -> Self { todo!() } } /// Expoential function.(`e^x`) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Exp; impl Exp { /// Creates a new exponential function. pub fn new() -> Self { todo!() } } impl Default for Exp { fn default() -> Self { Self::new() } } impl Differentiable for Exp { /// HINT: Consult fn diff(&self) -> Self { todo!() } } /// Trigonometric functions. /// /// The trig fucntions carry their coefficents to be closed under differntiation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Trignometric { /// Sine function. Sine { /// Coefficent coeff: Rational, }, /// Sine function. Cosine { /// Coefficent coeff: Rational, }, } impl Trignometric { /// Creates a new sine function. pub fn new_sine(coeff: Rational) -> Self { todo!() } /// Creates a new cosine function. pub fn new_cosine(coeff: Rational) -> Self { todo!() } } impl Differentiable for Trignometric { /// HINT: Consult fn diff(&self) -> Self { todo!() } } /// Basic functions #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BaseFuncs { /// Constant Const(Rational), /// Polynomial Poly(SingletonPolynomial), /// Exponential Exp(Exp), /// Trignometirc Trig(Trignometric), } impl Differentiable for BaseFuncs { fn diff(&self) -> Self { todo!() } } /// Complex functions. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ComplexFuncs { /// Basic functions Func(F), /// Addition Add(Box>, Box>), /// Subtraction Sub(Box>, Box>), /// Multipliciation Mul(Box>, Box>), /// Division Div(Box>, Box>), /// Composition Comp(Box>, Box>), } impl Differentiable for Box { fn diff(&self) -> Self { todo!() } } impl Differentiable for ComplexFuncs { /// HINT: Consult fn diff(&self) -> Self { todo!() } } /// Evaluate functions. pub trait Evaluate { /// Evaluate `self` at `x`. fn evaluate(&self, x: f64) -> f64; } impl Evaluate for Rational { fn evaluate(&self, x: f64) -> f64 { todo!() } } impl Evaluate for SingletonPolynomial { fn evaluate(&self, x: f64) -> f64 { todo!() } } impl Evaluate for Exp { fn evaluate(&self, x: f64) -> f64 { todo!() } } impl Evaluate for Trignometric { fn evaluate(&self, x: f64) -> f64 { todo!() } } impl Evaluate for BaseFuncs { fn evaluate(&self, x: f64) -> f64 { todo!() } } impl Evaluate for ComplexFuncs { fn evaluate(&self, x: f64) -> f64 { todo!() } } impl fmt::Display for Rational { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if *self == ZERO { return write!(f, "0"); } else if self.denominator == 1 { return write!(f, "{}", self.numerator); } write!(f, "{}/{}", self.numerator, self.denominator) } } impl fmt::Display for SingletonPolynomial { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Const(r) => write!(f, "{r}"), Self::Polynomial { coeff, power } => { // coeff or power is zero if *coeff == ZERO { return write!(f, "0"); } else if *power == ZERO { return write!(f, "{coeff}"); } // Standard form of px^q let coeff = if *coeff == ONE { "".to_string() } else if *coeff == MINUS_ONE { "-".to_string() } else { format!("({coeff})") }; let var = if *power == ONE { "x".to_string() } else { format!("x^({power})") }; write!(f, "{coeff}{var}") } } } } impl fmt::Display for Exp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "exp(x)") } } impl fmt::Display for Trignometric { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (func, coeff) = match self { Trignometric::Sine { coeff } => ("sin(x)", coeff), Trignometric::Cosine { coeff } => ("cos(x)", coeff), }; if *coeff == ZERO { write!(f, "0") } else if *coeff == ONE { write!(f, "{func}") } else if *coeff == MINUS_ONE { write!(f, "-{func}") } else { write!(f, "({coeff}){func}") } } } impl fmt::Display for BaseFuncs { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Const(r) => write!(f, "{r}"), Self::Poly(p) => write!(f, "{p}"), Self::Exp(e) => write!(f, "{e}"), Self::Trig(t) => write!(f, "{t}"), } } } impl fmt::Display for ComplexFuncs { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ComplexFuncs::Func(func) => write!(f, "{func}"), ComplexFuncs::Add(l, r) => write!(f, "({l} + {r})"), ComplexFuncs::Sub(l, r) => write!(f, "({l} - {r})"), ComplexFuncs::Mul(l, r) => write!(f, "({l} * {r})"), ComplexFuncs::Div(l, r) => write!(f, "({l} / {r})"), ComplexFuncs::Comp(l, r) => write!(f, "({l} ∘ {r})"), } } }