use std::ops::{
Add,
Sub,
Mul,
Div
};
use std::sync::Arc;
pub trait Rational: Clone + Copy + Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + From<f64> + PartialEq {
fn pow(self, rhs: Self) -> Self;
}
impl Rational for f64 {
fn pow(self, rhs: Self) -> Self {
self.powf(rhs)
}
}
#[derive(Clone)]
pub struct Function<T = f64> where T: Rational, {
function: Arc<dyn Fn(T) -> T>
}
unsafe impl<T: Rational> Send for Function<T> {}
impl<T: Rational + 'static> Function<T> {
pub fn new(value: f64) -> Self {
Self {
function: Arc::new(move |_x| value.into())
}
}
pub fn pow(self, rhs: Self) -> Self {
Self { function: Arc::new(move |x| (self.function)(x).pow((rhs.function)(x))) }
}
}
impl<T: Rational> std::fmt::Debug for Function<T> {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
impl<T: Rational> From<f64> for Function<T> {
fn from(x: f64) -> Self {
Self {
function: Arc::new(move |_x| x.into())
}
}
}
impl<T: Rational> Default for Function<T> {
fn default() -> Self {
Self {
function: Arc::new(|x| x)
}
}
}
impl<T: Rational + 'static> Add for Function<T> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self { function: Arc::new(move |x| (self.function)(x)+(rhs.function)(x)) }
}
}
impl<T: Rational + 'static> Sub for Function<T> {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self { function: Arc::new(move |x| (self.function)(x)-(rhs.function)(x)) }
}
}
impl<T: Rational + 'static> Mul for Function<T> {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Self { function: Arc::new(move |x| (self.function)(x)*(rhs.function)(x)) }
}
}
impl<T: Rational + 'static> Div for Function<T> {
type Output = Self;
fn div(self, rhs: Self) -> Self {
Self { function: Arc::new(move |x| (self.function)(x)*(rhs.function)(x)) }
}
}
impl<T: Rational> PartialEq for Function<T> {
fn eq(&self, rhs: &Self) -> bool {
let mut roughly_equal = true;
for iter in -10..=10 {
if (self.function)((iter as f64).into()) != (rhs.function)((iter as f64).into()) {roughly_equal = false;}
}
roughly_equal
}
}
#[cfg(test)]
mod tests {
use super::*;
fn define_shit() -> (Function, Function, Function, Function) {
return (Function::default(), Function::new(3.), Function::new(5.), Function::from(3.))
}
#[test]
fn test_equality() {
let (y, f ,g , h) = define_shit();
assert_eq!(
f,
h
);
assert_eq!(
Function::from(4.),
Function::<f64>::new(4.),
);
}
#[test]
fn test_add() {
let (y, f ,g , h) = define_shit();
assert_eq!(
g+Function::new(4.),
f+Function::new(6.),
);
let (y, f ,g , h) = define_shit();
assert_eq!(
f+g.clone(),
g+h
);
}
#[test]
fn test_sub() {
let (y, f ,g , h) = define_shit();
assert_eq!(
g-h,
Function::new(2.)
);
let (y, f ,g , h) = define_shit();
assert_eq!(
f-g,
Function::new(-2.)
);
}
#[test]
fn test_mul() {
let (y, f ,g , h) = define_shit();
assert_eq!(
g.clone()*h,
f*g
);
let (y, f ,g , h) = define_shit();
assert_eq!(
f*g,
Function::new(15.)
);
}
fn test_div() {
let (y, f ,g , h) = define_shit();
assert_eq!(
f/g,
Function::new(5./3.),
);
assert_eq!(
y/Function::new(1.),
Function::new(1.)
);
}
}