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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use crateFOURTH_ROOT_EPS;
use Vector;
/// Second-order partial derivative of a multivariate, scalar-valued function using the central
/// difference approximation.
///
/// # Arguments
///
/// * `f` - Multivariate, scalar-valued function, $f:\mathbb{R}^{n}\to\mathbb{R}$.
/// * `x0` - Evaluation point, $\mathbf{x}_{0}\in\mathbb{R}^{n}$.
/// * `k` - Element of $\mathbf{x}$ to differentiate with respect to twice. Note that this uses
/// 0-based indexing (e.g. $\mathbf{x}=\left(x_{0},...,x_{k},...,x_{n-1}\right)^{T}$).
/// * `h` - Relative step size, $h\in\mathbb{R}$. Defaults to [`FOURTH_ROOT_EPS`].
///
/// # Returns
///
/// Second-order partial derivative of $f$ with respect to $x_{k}$, evaluated at
/// $\mathbf{x}=\mathbf{x}_{0}$.
///
/// $$\frac{\partial^{2}f}{\partial x_{k}^{2}}\bigg\rvert_{\mathbf{x}=\mathbf{x}_{0}}\in\mathbb{R}$$
///
/// # Note
///
/// This function performs 3 evaluations of $f(\mathbf{x})$.
///
/// # Examples
///
/// ## Basic Example
///
/// Approximate the second-order partial derivative of
///
/// $$f(x,y)=x^{4}+2x^{2}y+y^{3}$$
///
/// with respect to $x$ at $(x,y)=(2,1)$, and compare the result to the true result of
///
/// $$\frac{\partial^{2}f}{\partial x^{2}}\bigg\rvert_{(x,y)=(2,1)}=12x^{2}+4y\bigg\rvert_{(x,y)=(2,1)}=52$$
///
/// ```
/// use numtest::*;
///
/// use numdiff::central_difference::spartial_derivative2;
///
/// // Define the function, f(x).
/// let f = |x: &Vec<f64>| x[0].powi(4) + 2.0 * x[0].powi(2) * x[1] + x[1].powi(3);
///
/// // Define the evaluation point.
/// let x0 = vec![2.0, 1.0];
///
/// // Define the element of the vector (using 0-based indexing) we are differentiating with
/// // respect to.
/// let k = 0;
///
/// // Approximate the second-order partial derivative of f(x) with respect to x₀.
/// let d2f: f64 = spartial_derivative2(&f, &x0, k, None);
///
/// // Check the accuracy of the second-order partial derivative approximation.
/// assert_equal_to_decimal!(d2f, 52.0, 4);
/// ```
///
/// ## Example Passing Runtime Parameters
///
/// Approximate the second-order partial derivative of a parameterized function
///
/// $$f(\mathbf{x})=ax_{0}^{2}+bx_{1}^{2}+cx_{0}x_{1}$$
///
/// where $a$, $b$, and $c$ are runtime parameters. Compare the result against the true second-order
/// partial derivative of $\dfrac{\partial^{2}f}{\partial x_{0}^{2}}=2a$.
///
/// ```
/// use numtest::*;
///
/// use numdiff::central_difference::spartial_derivative2;
///
/// // Runtime parameters.
/// let a = 1.5;
/// let b = 2.0;
/// let c = 0.8;
///
/// // Define the parameterized function.
/// fn f_param(x: &Vec<f64>, a: f64, b: f64, c: f64) -> f64 {
/// a * x[0].powi(2) + b * x[1].powi(2) + c * x[0] * x[1]
/// }
///
/// // Wrap the parameterized function with a closure that captures the parameters.
/// let f = |x: &Vec<f64>| f_param(x, a, b, c);
///
/// // Evaluation point.
/// let x0 = vec![1.0, -0.5];
///
/// // Approximate ∂²f/∂x₀² at x₀ and compare with the true result.
/// let d2f_dx0dx0: f64 = spartial_derivative2(&f, &x0, 0, None);
/// assert_equal_to_decimal!(d2f_dx0dx0, 2.0 * a, 4);
/// ```