functional-closures 0.4.0

composable pure functions with the signature f(T) -> T
Documentation

//! This library allows you to do three things. It allows you to Create a function that
//! returns a constant f(x) -> 4, create a function that returns its input f(x) -> x, and
//! then do arithmatic with them and store the result f(x) -> x, g(x) -> 4, h = f*g => h ~= 4*x
//! then you can do whatever you want with the resulting Arc<Fn(T) -> T> where T is essentially
//! an f64 or other similar type


use std::sync::Arc;

use std::ops::{
	Add,
	Sub,
	Mul,
	Div
};


/// create a vector of all the values between
/// start and end with a factor of step
fn make_domain(start: i32, end: i32, step: f32) -> Vec<f64> {
	let start = (start as f32/step) as i64;
	let end = (end as f32/step) as i64;
	(start..=end).map(|x| {
		(x as f64)*step as f64
	}).collect()
}

/// This is the trait bounding what is necessary
/// to be the domain/range of any generic function
pub trait Rational: Clone + Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self>
 + From<f64> + PartialEq + std::fmt::Debug {
	/// raise self to the power of rhs of same type
	fn pow(self, rhs: Self) -> Self;
}

impl Rational for f64 {
	fn pow(self, rhs: Self) -> Self {
		self.powf(rhs)
	}
}

/// the main Function type of the library
#[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: T) -> Self {
		Self { function: Arc::new(move |_x| value.clone())}
	}
	
	/// return the current function at the given value
	pub fn call(&self, x: T) -> T {
		(self.function)(x)
	}
	
	/// calling this function with an empty vec of roots returns f(x) -> 0
	pub fn polynomial_from_roots(roots: Vec<T>) -> Function<T> {
		let function_roots = roots.into_iter().map(|root| {
			Function::default()-Function::new(root)
		}).collect::<Vec<Function<T>>>();
				
		match function_roots.len() > 0 {
			true => {
				let mut tmp: Function<T> = Function::new(T::from(1.));
				for func in function_roots.into_iter() {
					tmp = tmp*func;
				}
				tmp
			},
			false => {
				Function::new(T::from(0.))
			}
		}
		
	}
}

impl<T: Rational + std::cmp::PartialOrd + 'static> Function<T> {
	
	/// find the zeroes of the current function
	pub fn find_zeroes(&self, range: (i32, i32)) -> Vec<T> {
		// default run with a step size of 1/1000
		let domain = make_domain(range.0, range.1, 0.001);
		let mut zeroes: Vec<T> = vec![];
		
		// whether or not the previous call was greater than zero
		let mut g0 = self.call(domain[0].into())>T::from(0.);
		domain.into_iter().map(|x| {
			T::from(x)
		}).for_each(|x| {
			if g0 != (self.call(x.clone()) > T::from(0.)) {
				g0 = !g0;
				zeroes.push(x);
			}
		});
		
		zeroes
	}
}

impl<T: Rational + 'static> std::fmt::Debug for Function<T> {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		// write!("f(-5)->{}|f(-4)->{}|f(-3)->{}f(-2)->{}|f(-1)->{}\nf(0)->{}|f(1)->{}|f(2)->{}|f(3)->{}|f(4)->{}|f(5)->{}", )
		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 + 'static> From<T> for Function<T> {
	fn from(x: T) -> Self {
		Self { function: Arc::new(
			move |_x| x.clone()
		)}
	}
}

impl<T: Rational> From<i64> for Function<T> {
	fn from(x: i64) -> Self {
		Self {
			function: Arc::new(move |_x| (x as f64).into())
		}
	}
}

impl<T: Rational> Default for Function<T> {
	/// return the function f(x) -> x
	/// or y = x if you want to think of it that way
	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.clone())+(rhs.function)(x)) }
	}
}
impl<T: Rational + 'static> Add<T> for Function<T> {
	type Output = Self;
	fn add(self, rhs: T) -> Self {
		self+Function::from(rhs)
	}
}

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.clone())-(rhs.function)(x)) }
	}
}
impl<T: Rational + 'static> Sub<T> for Function<T> {
	type Output = Self;
	fn sub(self, rhs: T) -> Self {
		self-Function::from(rhs)
	}
}

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.clone())*(rhs.function)(x)) }
	}
}
impl<T: Rational + 'static> Mul<T> for Function<T> {
	type Output = Self;
	fn mul(self, rhs: T) -> Self {
		self*Function::from(rhs)
	}
}

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.clone())/(rhs.function)(x)) }
	}
}
impl<T: Rational + 'static> Div<T> for Function<T> {
	type Output = Self;
	fn div(self, rhs: T) -> Self {
		self/Function::from(rhs)
	}
}

impl<T: Rational> PartialEq for Function<T> {
	fn eq(&self, rhs: &Self) -> bool {
		let mut roughly_equal = true;
		// check for equality in the range of all integers between -10 and 10
		// may not be the most rigerous but works
		for iter in -10..=10 {
			if (self.function)((iter as f64).into()) != (rhs.function)((iter as f64).into()) {roughly_equal = false;}
		}
		roughly_equal
	}
}

impl<T: Rational + 'static> Rational for Function<T> where Function<T>: From<f64> {
	fn pow(self, rhs: Self) -> Self {
		Self { function: Arc::new(move |x| (self.function)(x.clone()).pow((rhs.function)(x))) }
	}
}


#[cfg(test)]
mod tests {
    use super::*;
    
    type Func = Function<f64>;
    
    // because constant definitions are practically non-functional in rust
    fn define_shit() -> (Func, Func, Func, Func) {
    	return (Function::default(), Function::new(3.), Function::new(5.), Function::from(3.))
    }
    
    fn rounded_eq(a: Vec<f64>, b: Vec<f64>) {
    	let a = a.into_iter().map(|x| {
    		x.round()
    		// (x*1000.).round() / 1000.
    	}).collect::<Vec<f64>>();
    	let b = b.into_iter().map(|x| {
    		x.round()
    		// (x*1000.).round() / 1000.
    	}).collect::<Vec<f64>>();
    	
    	assert_eq!(a, b);
    }
    
    #[test]
    fn polynomial() {
    	assert_eq!(
    		Function::polynomial_from_roots(vec![2., 3.]),
    		(
    			(Func::default()+Func::new(-2.))*
    			(Func::default()+Func::new(-3.))
    		)
    	);
    	assert_eq!(
    		Function::polynomial_from_roots(vec![-2., -1., 3., 5.]),
    		(
    			(Func::default()+Func::new(2.))*
    			(Func::default()+Func::new(1.))*
    			(Func::default()+Func::new(-3.))*
    			(Func::default()+Func::new(-5.))
    		)
    	);
    	let x = Func::default();
    	assert_eq!(
    		Func::polynomial_from_roots(
    			vec![-3.5, -3., 3., 3.5]
    		),
    		(x.clone()+3.5)*(x.clone()+3.)*(x.clone()-3.)*(x-3.5)
    	)
    }
    
    #[test]
    fn test_find_zeroes() {
    	rounded_eq(
    		vec![-1., 1.],
    		Func::polynomial_from_roots(vec![1., -1.]).find_zeroes((-10, 10))
    	);
    	rounded_eq(
    		vec![-3., 2., 5.],
    		Func::polynomial_from_roots(vec![-3., 2., 5.]).find_zeroes((-10, 10))
    	)
    }
		
		#[test]
		fn test_equality() {
			let (y, f ,g , h) = define_shit();
			assert_eq!(
				f,
				h
			);
			assert_eq!(
				Func::from(4.),
				Func::new(4.),
			);
			let (y, f ,g , h) = define_shit();
			assert_eq!(
				Func::from(1.)/y.clone(),
				(f/h)/y,
			);
		}
		
		#[test]
		fn test_add() {
			let (y, f ,g , h) = define_shit();
			assert_eq!(
				g+Func::new(4.),
				f+Func::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,
				Func::new(2.)
			);
			let (y, f ,g , h) = define_shit();
			assert_eq!(
				f-g,
				Func::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,
				Func::new(15.)
			);
		}
		
		#[test]
		fn test_div() {
			let (y, f ,g , h) = define_shit();
			assert_eq!(
				f/g,
				Func::new(3./5.),
			);
			assert_eq!(
				y/Func::new(1.),
				Func::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
			);
		}
}