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 + std::fmt::Debug {
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))) }
}
pub fn call(&self, x: T) -> T {
(self.function)(x)
}
}
impl<T: Rational + 'static> std::fmt::Debug for Function<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"f(-2) {:?}|f(-1) {:?}|f(0) {:?}|f(1) {:?}|f(2) {:?}",
self.call((-2.).into()),
self.call((-1.).into()),
self.call((0.).into()),
self.call((1.).into()),
self.call((2.).into()),
)
}
}
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.),
);
let (y, f ,g , h) = define_shit();
assert_eq!(
Function::from(1.)/y.clone(),
(f/h)/y,
);
}
#[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.)
);
}
#[test]
fn test_div() {
let (y, f ,g , h) = define_shit();
assert_eq!(
f/g,
Function::new(3./5.),
);
assert_eq!(
y/Function::new(1.),
Function::default()
);
}
#[test]
fn test_call() {
let (y, f, g, h) = define_shit();
assert_eq!(
g.call(2.),
5.
);
assert_eq!(
h.call(10000.47654),
3.
);
assert_eq!(
y.call(536.5),
536.5
);
}
}