functional_closures/
lib.rs

1
2//! This library allows you to do three things. It allows you to Create a function that
3//! returns a constant f(x) -> 4, create a function that returns its input f(x) -> x, and
4//! then do arithmatic with them and store the result f(x) -> x, g(x) -> 4, h = f*g => h ~= 4*x
5//! then you can do whatever you want with the resulting Arc<Fn(T) -> T> where T is essentially
6//! an f64 or other similar type
7
8
9use std::sync::Arc;
10
11use std::ops::{
12	Add,
13	Sub,
14	Mul,
15	Div
16};
17
18
19/// create a vector of all the values between
20/// start and end with a factor of step
21fn make_domain(start: i32, end: i32, step: f32) -> Vec<f64> {
22	let start = (start as f32/step) as i64;
23	let end = (end as f32/step) as i64;
24	(start..=end).map(|x| {
25		(x as f64)*step as f64
26	}).collect()
27}
28
29/// This is the trait bounding what is necessary
30/// to be the domain/range of any generic function
31pub trait Rational: Clone + Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self>
32 + From<f64> + PartialEq + std::fmt::Debug {
33	/// raise self to the power of rhs of same type
34	fn pow(self, rhs: Self) -> Self;
35}
36
37impl Rational for f64 {
38	fn pow(self, rhs: Self) -> Self {
39		self.powf(rhs)
40	}
41}
42
43/// the main Function type of the library
44#[derive(Clone)]
45pub struct Function<T = f64> where T: Rational, {
46	function: Arc<dyn Fn(T) -> T>
47}
48
49unsafe impl<T: Rational> Send for Function<T> {}
50
51
52impl<T: Rational + 'static> Function<T> {
53	pub fn new(value: T) -> Self {
54		Self { function: Arc::new(move |_x| value.clone())}
55	}
56	
57	/// return the current function at the given value
58	pub fn call(&self, x: T) -> T {
59		(self.function)(x)
60	}
61	
62	/// calling this function with an empty vec of roots returns f(x) -> 0
63	pub fn polynomial_from_roots(roots: Vec<T>) -> Function<T> {
64		let function_roots = roots.into_iter().map(|root| {
65			Function::default()-Function::new(root)
66		}).collect::<Vec<Function<T>>>();
67				
68		match function_roots.len() > 0 {
69			true => {
70				let mut tmp: Function<T> = Function::new(T::from(1.));
71				for func in function_roots.into_iter() {
72					tmp = tmp*func;
73				}
74				tmp
75			},
76			false => {
77				Function::new(T::from(0.))
78			}
79		}
80		
81	}
82}
83
84impl<T: Rational + std::cmp::PartialOrd + 'static> Function<T> {
85	
86	/// find the zeroes of the current function
87	pub fn find_zeroes(&self, range: (i32, i32)) -> Vec<T> {
88		// default run with a step size of 1/1000
89		let domain = make_domain(range.0, range.1, 0.001);
90		let mut zeroes: Vec<T> = vec![];
91		
92		// whether or not the previous call was greater than zero
93		let mut g0 = self.call(domain[0].into())>T::from(0.);
94		domain.into_iter().map(|x| {
95			T::from(x)
96		}).for_each(|x| {
97			if g0 != (self.call(x.clone()) > T::from(0.)) {
98				g0 = !g0;
99				zeroes.push(x);
100			}
101		});
102		
103		zeroes
104	}
105}
106
107impl<T: Rational + 'static> std::fmt::Debug for Function<T> {
108	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109		// write!("f(-5)->{}|f(-4)->{}|f(-3)->{}f(-2)->{}|f(-1)->{}\nf(0)->{}|f(1)->{}|f(2)->{}|f(3)->{}|f(4)->{}|f(5)->{}", )
110		write!(
111			f,
112			"f(-2) {:?}|f(-1) {:?}|f(0) {:?}|f(1) {:?}|f(2) {:?}",
113			self.call((-2.).into()),
114			self.call((-1.).into()),
115			self.call((0.).into()),
116			self.call((1.).into()),
117			self.call((2.).into()),
118		)
119	}
120}
121
122impl<T: Rational + 'static> From<T> for Function<T> {
123	fn from(x: T) -> Self {
124		Self { function: Arc::new(
125			move |_x| x.clone()
126		)}
127	}
128}
129
130impl<T: Rational> From<i64> for Function<T> {
131	fn from(x: i64) -> Self {
132		Self {
133			function: Arc::new(move |_x| (x as f64).into())
134		}
135	}
136}
137
138impl<T: Rational> Default for Function<T> {
139	/// return the function f(x) -> x
140	/// or y = x if you want to think of it that way
141	fn default() -> Self {
142		Self {
143			function: Arc::new(|x| x)
144		}
145	}
146}
147
148impl<T: Rational + 'static> Add for Function<T> {
149	type Output = Self;
150	fn add(self, rhs: Self) -> Self {
151		Self { function: Arc::new(move |x| (self.function)(x.clone())+(rhs.function)(x)) }
152	}
153}
154impl<T: Rational + 'static> Add<T> for Function<T> {
155	type Output = Self;
156	fn add(self, rhs: T) -> Self {
157		self+Function::from(rhs)
158	}
159}
160
161impl<T: Rational + 'static> Sub for Function<T> {
162	type Output = Self;
163	fn sub(self, rhs: Self) -> Self {
164		Self { function: Arc::new(move |x| (self.function)(x.clone())-(rhs.function)(x)) }
165	}
166}
167impl<T: Rational + 'static> Sub<T> for Function<T> {
168	type Output = Self;
169	fn sub(self, rhs: T) -> Self {
170		self-Function::from(rhs)
171	}
172}
173
174impl<T: Rational + 'static> Mul for Function<T> {
175	type Output = Self;
176	fn mul(self, rhs: Self) -> Self {
177		Self { function: Arc::new(move |x| (self.function)(x.clone())*(rhs.function)(x)) }
178	}
179}
180impl<T: Rational + 'static> Mul<T> for Function<T> {
181	type Output = Self;
182	fn mul(self, rhs: T) -> Self {
183		self*Function::from(rhs)
184	}
185}
186
187impl<T: Rational + 'static> Div for Function<T> {
188	type Output = Self;
189	fn div(self, rhs: Self) -> Self {
190		Self { function: Arc::new(move |x| (self.function)(x.clone())/(rhs.function)(x)) }
191	}
192}
193impl<T: Rational + 'static> Div<T> for Function<T> {
194	type Output = Self;
195	fn div(self, rhs: T) -> Self {
196		self/Function::from(rhs)
197	}
198}
199
200impl<T: Rational> PartialEq for Function<T> {
201	fn eq(&self, rhs: &Self) -> bool {
202		let mut roughly_equal = true;
203		// check for equality in the range of all integers between -10 and 10
204		// may not be the most rigerous but works
205		for iter in -10..=10 {
206			if (self.function)((iter as f64).into()) != (rhs.function)((iter as f64).into()) {roughly_equal = false;}
207		}
208		roughly_equal
209	}
210}
211
212impl<T: Rational + 'static> Rational for Function<T> where Function<T>: From<f64> {
213	fn pow(self, rhs: Self) -> Self {
214		Self { function: Arc::new(move |x| (self.function)(x.clone()).pow((rhs.function)(x))) }
215	}
216}
217
218
219#[cfg(test)]
220mod tests {
221    use super::*;
222    
223    type Func = Function<f64>;
224    
225    // because constant definitions are practically non-functional in rust
226    fn define_shit() -> (Func, Func, Func, Func) {
227    	return (Function::default(), Function::new(3.), Function::new(5.), Function::from(3.))
228    }
229    
230    fn rounded_eq(a: Vec<f64>, b: Vec<f64>) {
231    	let a = a.into_iter().map(|x| {
232    		x.round()
233    		// (x*1000.).round() / 1000.
234    	}).collect::<Vec<f64>>();
235    	let b = b.into_iter().map(|x| {
236    		x.round()
237    		// (x*1000.).round() / 1000.
238    	}).collect::<Vec<f64>>();
239    	
240    	assert_eq!(a, b);
241    }
242    
243    #[test]
244    fn polynomial() {
245    	assert_eq!(
246    		Function::polynomial_from_roots(vec![2., 3.]),
247    		(
248    			(Func::default()+Func::new(-2.))*
249    			(Func::default()+Func::new(-3.))
250    		)
251    	);
252    	assert_eq!(
253    		Function::polynomial_from_roots(vec![-2., -1., 3., 5.]),
254    		(
255    			(Func::default()+Func::new(2.))*
256    			(Func::default()+Func::new(1.))*
257    			(Func::default()+Func::new(-3.))*
258    			(Func::default()+Func::new(-5.))
259    		)
260    	);
261    	let x = Func::default();
262    	assert_eq!(
263    		Func::polynomial_from_roots(
264    			vec![-3.5, -3., 3., 3.5]
265    		),
266    		(x.clone()+3.5)*(x.clone()+3.)*(x.clone()-3.)*(x-3.5)
267    	)
268    }
269    
270    #[test]
271    fn test_find_zeroes() {
272    	rounded_eq(
273    		vec![-1., 1.],
274    		Func::polynomial_from_roots(vec![1., -1.]).find_zeroes((-10, 10))
275    	);
276    	rounded_eq(
277    		vec![-3., 2., 5.],
278    		Func::polynomial_from_roots(vec![-3., 2., 5.]).find_zeroes((-10, 10))
279    	)
280    }
281		
282		#[test]
283		fn test_equality() {
284			let (y, f ,g , h) = define_shit();
285			assert_eq!(
286				f,
287				h
288			);
289			assert_eq!(
290				Func::from(4.),
291				Func::new(4.),
292			);
293			let (y, f ,g , h) = define_shit();
294			assert_eq!(
295				Func::from(1.)/y.clone(),
296				(f/h)/y,
297			);
298		}
299		
300		#[test]
301		fn test_add() {
302			let (y, f ,g , h) = define_shit();
303			assert_eq!(
304				g+Func::new(4.),
305				f+Func::new(6.),
306			);
307			let (y, f ,g , h) = define_shit();
308			assert_eq!(
309				f+g.clone(),
310				g+h
311			);
312		}
313		
314		#[test]
315		fn test_sub() {
316			let (y, f ,g , h) = define_shit();
317			assert_eq!(
318				g-h,
319				Func::new(2.)
320			);
321			let (y, f ,g , h) = define_shit();
322			assert_eq!(
323				f-g,
324				Func::new(-2.)
325			);
326		}
327		
328		#[test]
329		fn test_mul() {
330			let (y, f ,g , h) = define_shit();
331			assert_eq!(
332				g.clone()*h,
333				f*g
334			);
335			let (y, f ,g , h) = define_shit();
336			assert_eq!(
337				f*g,
338				Func::new(15.)
339			);
340		}
341		
342		#[test]
343		fn test_div() {
344			let (y, f ,g , h) = define_shit();
345			assert_eq!(
346				f/g,
347				Func::new(3./5.),
348			);
349			assert_eq!(
350				y/Func::new(1.),
351				Func::default()
352			);
353		}
354		
355		#[test]
356		fn test_call() {
357			let (y, f, g, h) = define_shit();
358			assert_eq!(
359				g.call(2.),
360				5.
361			);
362			assert_eq!(
363				h.call(10000.47654),
364				3.
365			);
366			assert_eq!(
367				y.call(536.5),
368				536.5
369			);
370		}
371}
372
373
374