1#[derive(Clone)]
6pub struct Differentiable<F, DF>(pub F, pub DF);
7
8impl<Ret, F: FnOnce(f64) -> Ret, DF> FnOnce<(f64,)> for Differentiable<F, DF> {
9 type Output = Ret;
10
11 extern "rust-call" fn call_once(self, args: (f64,)) -> Self::Output {
12 (self.0)(args.0)
13 }
14}
15impl<Ret, F: FnMut(f64) -> Ret, DF> FnMut<(f64,)> for Differentiable<F, DF> {
16 extern "rust-call" fn call_mut(&mut self, args: (f64,)) -> Self::Output {
17 (self.0)(args.0)
18 }
19}
20impl<Ret, F: Fn(f64) -> Ret, DF> Fn<(f64,)> for Differentiable<F, DF> {
21 extern "rust-call" fn call(&self, args: (f64,)) -> Self::Output {
22 (self.0)(args.0)
23 }
24}
25
26impl<F, DF, Ret> Differentiable<F, DF>
27where
28 DF: Fn<(f64,), Output = Ret>,
29{
30 pub fn d(&self, t: f64) -> Ret {
32 (self.1)(t)
33 }
34}
35
36#[macro_export]
53macro_rules! polynomial_closure {
54 () => {
55 |_t: f64| { 0. }
56 };
57 ($($coef:expr),+ $(,)?) => {
58 |t: f64| {
59 [$($coef),+].into_iter().rev()
60 .reduce(|acc: f64, c: f64| c + t * acc).unwrap()
61 }
62 };
63}
64
65#[macro_export]
68macro_rules! polynomial_derivative_closure {
69 () => {
70 |_t: f64| { 0. }
71 };
72 ($coef:expr) => {
73 |_t: f64| { 0. }
74 };
75 ($($coef:expr),+ $(,)?) => {
76 |t: f64| {
77 let coef = [$($coef),+];
78 let last = *coef.last().unwrap();
79 coef.into_iter().enumerate().skip(1).rev().skip(1)
80 .fold(last * (coef.len()-1) as f64, |acc: f64, (n, c): (usize, f64)| n as f64 * c + t * acc)
81 }
82 };
83}
84
85#[macro_export]
127macro_rules! polynomial {
128 ($($coef:expr),* $(,)?) => {
129 $crate::polynomial::Differentiable(
130 $crate::polynomial_closure![$($coef),*],
131 $crate::polynomial_derivative_closure![$($coef),*]
132 )
133 };
134 ($t:ident => $($coef:expr),+) => {
135 [$($coef),+].into_iter().rev()
136 .reduce(|acc: f64, c: f64| c + $t * acc).unwrap()
137 };
138}
139
140#[cfg(test)]
141mod tests {
142 #[test]
144 fn empty_polynomial() {
145 let p = polynomial![];
146 assert_eq!(p(0.), 0.);
147 assert_eq!(p(1.), 0.);
148 assert_eq!(p.d(0.), 0.);
149 assert_eq!(p.d(1.), 0.);
150 }
151
152 #[test]
153 fn constant_polynomail_evauation() {
154 let p = polynomial_closure![42.];
155 assert_eq!(p(0.), 42.);
156 assert_eq!(p(1.), 42.);
157 }
158
159 #[test]
160 fn linear_polynomial_evaluation() {
161 let p = polynomial_closure![42., 2.];
162 assert_eq!(p(0.), 42.);
163 assert_eq!(p(69.), 42. + 2. * 69.);
164 }
165
166 #[test]
167 fn quadratic_polynomial_evaluation() {
168 let p = polynomial_closure![-1., 0., 1.];
169 assert_eq!(p(0.), -1.);
170 assert_eq!(p(-1.), 0.);
171 assert_eq!(p(1.), 0.);
172 }
173
174 #[test]
175 fn geometric_sum() {
176 let geometric_series = polynomial_closure![
177 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
178 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
179 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
180 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
181 ];
182
183 assert_eq!(geometric_series(1. / 2.), 1. / (1. - 1. / 2.));
184 assert_eq!(geometric_series(1. / 3.), 1.5);
185 assert_eq!(geometric_series(1. / 4.), 1. / (1. - 1. / 4.));
186 assert_eq!(geometric_series(1. / 5.), 1. / (1. - 1. / 5.));
187 assert_eq!(geometric_series(1. / 6.), 1. / (1. - 1. / 6.));
188 }
189
190 #[test]
191 fn constant_polynomail_derivative() {
192 let p = polynomial_derivative_closure![42.];
193 assert_eq!(p(0.), 0.);
194 assert_eq!(p(1.), 0.);
195 }
196
197 #[test]
198 fn linear_polynomial_derivative() {
199 let p = polynomial_derivative_closure![42., 2.];
200 assert_eq!(p(0.), 2.);
201 assert_eq!(p(69.), 2.);
202 }
203
204 #[test]
205 fn quadratic_polynomial_derivative() {
206 let p = polynomial_derivative_closure![-1., 0., 1.];
207 assert_eq!(p(0.), 2. * 0.);
208 assert_eq!(p(-1.), 2. * (-1.));
209 assert_eq!(p(1.), 2. * 1.);
210 }
211
212 #[test]
213 fn geometric_sum_derivative() {
214 let geometric_series = polynomial_derivative_closure![
215 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
216 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
217 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
218 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
219 ];
220
221 assert_eq!(geometric_series(1. / 2.), (1f64 / (1. - 1. / 2.)).powi(2));
222 assert_eq!(geometric_series(1. / 3.), 1.5f64.powi(2));
223 assert_eq!(geometric_series(1. / 4.), (1f64 / (1. - 1. / 4.)).powi(2));
224 assert_eq!(geometric_series(1. / 5.), (1f64 / (1. - 1. / 5.)).powi(2));
225 assert_eq!(geometric_series(1. / 6.), (1f64 / (1. - 1. / 6.)).powi(2));
226 }
227}