use std::sync::Arc;
use std::ops::{
Add,
Sub,
Mul,
Div
};
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()
}
pub trait Rational: Clone + 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: T) -> Self {
Self { function: Arc::new(move |_x| value.clone())}
}
pub fn call(&self, x: T) -> T {
(self.function)(x)
}
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> {
pub fn find_zeroes(&self, range: (i32, i32)) -> Vec<T> {
let domain = make_domain(range.0, range.1, 0.001);
let mut zeroes: Vec<T> = vec![];
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,
"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> {
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;
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>;
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()
}).collect::<Vec<f64>>();
let b = b.into_iter().map(|x| {
x.round()
}).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
);
}
}