1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/* This file is part of bacon.
 * Copyright (c) Wyatt Campbell.
 *
 * See repository LICENSE for information.
 */

use nalgebra::ComplexField;
use num_traits::FromPrimitive;

/// Numerically find the derivative of a function at a point.
///
/// Given a function of a real field to a complex field, an input point x, and a
/// step size h, calculate the derivative of f at x using the five-point method.
///
/// Making h too small will lead to round-off error.
pub fn derivative<N: ComplexField + FromPrimitive + Copy>(
    f: impl Fn(N::RealField) -> N,
    x: N::RealField,
    h: N::RealField,
) -> N
where
    <N as ComplexField>::RealField: FromPrimitive + Copy,
{
    (f(x - h - h) + N::from_f64(8.0).unwrap() * (f(x + h) - f(x - h)) - f(x + h + h))
        / (N::from_f64(12.0).unwrap() * N::from_real(h))
}

/// Numerically find the second derivative of a function at a point.
///
/// Given a function of a real field to a complex field, an input point x, and a
/// step size h, calculate the second derivative of f at x using the five-point
/// method.
///
/// Making h too small will lead to round-off error.
pub fn second_derivative<N: ComplexField + FromPrimitive + Copy>(
    f: impl Fn(N::RealField) -> N,
    x: N::RealField,
    h: N::RealField,
) -> N
where
    <N as ComplexField>::RealField: FromPrimitive + Copy,
{
    (f(x - h) - N::from_f64(2.0).unwrap() * f(x) + f(x + h)) / N::from_real(h.powi(2))
}