use crate::{gamma_function, polygamma_function, Elementary::*, Factorial};
use std::{f64::consts::E, sync::Arc};
use crate::{Error, Func};
use super::series_expansions::SeriesExpansion;
fn f() -> Func {
Box::new(move |x| x)
}
#[derive(Debug, Clone, PartialEq)]
pub enum Elementary {
Sin(Arc<Elementary>), Cos(Arc<Elementary>), Tan(Arc<Elementary>),
Sec(Arc<Elementary>), Csc(Arc<Elementary>), Cot(Arc<Elementary>),
Asin(Arc<Elementary>), Acos(Arc<Elementary>), Atan(Arc<Elementary>),
Sinh(Arc<Elementary>), Cosh(Arc<Elementary>), Tanh(Arc<Elementary>),
Add(Arc<Elementary>, Arc<Elementary>), Sub(Arc<Elementary>, Arc<Elementary>), Mul(Arc<Elementary>, Arc<Elementary>), Div(Arc<Elementary>, Arc<Elementary>), Pow(Arc<Elementary>, Arc<Elementary>), Log(Arc<Elementary>, Arc<Elementary>),
Factorial(Arc<Elementary>),
Gamma(Arc<Elementary>), Polygamma(Arc<Elementary>, usize),
Abs(Arc<Elementary>),
Con(f64),
X, }
impl Elementary {
pub fn call(self) -> Func {
Box::new(move |x| match self.clone() {
Sin(func) => (*func).clone().call()(x).sin(),
Cos(func) => (*func).clone().call()(x).cos(),
Tan(func) => (*func).clone().call()(x).tan(),
Sec(func) => 1. / (*func).clone().call()(x).cos(),
Csc(func) => 1. / (*func).clone().call()(x).sin(),
Cot(func) => 1. / (*func).clone().call()(x).tan(),
Asin(func) => (*func).clone().call()(x).asin(),
Acos(func) => (*func).clone().call()(x).acos(),
Atan(func) => (*func).clone().call()(x).atan(),
Sinh(func) => {
(E.powf((*func).clone().call()(x)) - E.powf(-(*func).clone().call()(x))) / 2.
}
Cosh(func) => {
(E.powf((*func).clone().call()(x)) + E.powf(-(*func).clone().call()(x))) / 2.
}
Tanh(func) => Sinh(func.clone()).call()(x) / Cosh(func).call()(x),
Add(func1, func2) => (*func1).clone().call()(x) + (*func2).clone().call()(x),
Sub(func1, func2) => (*func1).clone().call()(x) - (*func2).clone().call()(x),
Mul(func1, func2) => (*func1).clone().call()(x) * (*func2).clone().call()(x),
Div(func1, func2) => (*func1).clone().call()(x) / (*func2).clone().call()(x),
Pow(func1, func2) => (*func1).clone().call()(x).powf((*func2).clone().call()(x)),
Log(func1, func2) => (*func2).clone().call()(x).log((*func1).clone().call()(x)),
Factorial(func) => (*func).clone().call()(x).factorial(),
Gamma(func) => gamma_function((*func).clone().call()(x)),
Polygamma(func, order) => polygamma_function((*func).clone().call()(x), order),
Abs(func) => (*func).clone().call()(x).abs(),
Con(numb) => numb,
X => f()(x),
})
}
}
pub fn force_unwrap(element: &Arc<Elementary>) -> Elementary {
if let Ok(inner) = Arc::try_unwrap(element.clone()) {
inner
} else {
(**element).clone()
}
}
pub fn sin(func: Function) -> Function {
let new_function = Sin(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn cos(func: Function) -> Function {
let new_function = Cos(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn tan(func: Function) -> Function {
let new_function = Tan(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn sec(func: Function) -> Function {
let new_function = Sec(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn csc(func: Function) -> Function {
let new_function = Csc(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn cot(func: Function) -> Function {
let new_function = Cot(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn asin(func: Function) -> Function {
let new_function = Asin(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn acos(func: Function) -> Function {
let new_function = Acos(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn atan(func: Function) -> Function {
let new_function = Atan(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn sinh(func: Function) -> Function {
let new_function = Sinh(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn cosh(func: Function) -> Function {
let new_function = Cosh(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn tanh(func: Function) -> Function {
let new_function = Tanh(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn abs(func: Function) -> Function {
let new_function = Abs(Arc::new(func.elementary()));
Function::from(new_function)
}
pub fn ln(func: Function) -> Function {
let new_function = Log(Con(E).into(), func.elementary().into());
Function::from(new_function)
}
pub fn sqrt(func: Function) -> Function {
let new_function = Pow(Arc::new(func.elementary()), Arc::new(Con(0.5)));
Function::from(new_function)
}
pub fn factorial(func: Function) -> Function {
let new_function = Factorial(func.elementary().into());
Function::from(new_function)
}
pub fn nth_root(func: Function, n: f64) -> Function {
let new_function = Pow(Arc::new(func.elementary()), Arc::new(Con(1.) / n));
Function::from(new_function)
}
pub struct Function {
func: Elementary,
}
impl Function {
pub fn elementary(&self) -> Elementary {
self.func.clone()
}
pub fn set_function(&mut self, element: Elementary) {
self.func = element;
}
pub fn differentiate(&mut self) {
self.func = self.elementary().to_owned().derivative_unsimplified();
}
pub fn as_taylor_expansion(&mut self, order: u8, a: f64) -> Result<(), Error> {
self.func = self.func.expand_taylor(order, a)?.get_elementary();
Ok(())
}
pub fn get_taylor_expansion(&self, order: u8, a: f64) -> Result<SeriesExpansion, Error> {
self.func.expand_taylor(order, a)
}
pub fn get_maclaurin_expansion(&self, order: u8) -> Result<SeriesExpansion, Error> {
self.func.expand_maclaurin(order)
}
}
impl Default for Function {
fn default() -> Self {
Self { func: X }
}
}
impl<'a> From<&'a str> for Function {
fn from(value: &'a str) -> Self {
let func = Elementary::from(value);
Self { func }
}
}
impl From<String> for Function {
fn from(value: String) -> Self {
let func = Elementary::from(&value[..]);
Self { func }
}
}
impl<'a> From<&'a String> for Function {
fn from(value: &'a String) -> Self {
let func = Elementary::from(&value[..]);
Self { func }
}
}
impl From<Elementary> for Function {
fn from(value: Elementary) -> Self {
Self { func: value }
}
}
impl From<SeriesExpansion> for Function {
fn from(value: SeriesExpansion) -> Self {
value.get_function()
}
}
impl From<&SeriesExpansion> for Function {
fn from(value: &SeriesExpansion) -> Self {
(*value).clone().get_function()
}
}