macro_rules! get_vpartial_derivative {
($f:ident, $func_name:ident) => { ... };
}Expand description
Get a function that returns the partial derivative of the provided multivariate, vector-valued function.
The partial derivative is computed using forward-mode automatic differentiation.
§Arguments
f- Multivariate, vector-valued function, $\mathbf{f}:\mathbb{R}^{n}\to\mathbb{R}^{m}$.func_name- Name of the function that will return the partial derivative of $\mathbf{f}(\mathbf{x})$ with respect to $x_{k}$ at any point $\mathbf{x}\in\mathbb{R}^{n}$.
§Defining f
The multivariate, vector-valued function f must have the following function signature:
fn f<S: Scalar, V: Vector<S>>(x: &V) -> V::DVectorT<S> {
// place function contents here
}For the automatic differentiation to work, f must be fully generic over the types of scalars
and vectors used. Additionally, the function must return an instance of V::DVector (a
dynamically-sized vector type that is compatible with V, see the
linalg-traits docs
for more information) since we did not want to burden the user with having to specify the size
of the output vector (i.e. $m$, where $\mathbf{f}:\mathbb{R}^{n}\to\mathbb{R}^{m}$) at compile
time, especially since users may be using this crate exclusively with dynamically-sized types.
§Warning
f cannot be defined as closure. It must be defined as a function.
§Note
The function produced by this macro will perform 1 evaluation of $\mathbf{f}(\mathbf{x})$ to evaluate its partial derivative with respect to $x_{k}$.
§Example
Compute the partial derivative of
$$\mathbf{f}(\mathbf{x})=\begin{bmatrix}\sin{x_{0}}\sin{x_{1}}\\\cos{x_{0}}\cos{x_{1}}\end{bmatrix}$$
with respect to $x_{0}$ at $\mathbf{x}=(1,2)^{T}$, and compare the result to the true result of
$$ \frac{\partial\mathbf{f}}{\partial x_{0}}\bigg\rvert_{\mathbf{x}=(1,2)^{T}}= \begin{bmatrix} \cos{(1)}\sin{(2)} \\ -\sin{(1)}\cos{(2)} \end{bmatrix} $$
§Using standard vectors
use linalg_traits::{Scalar, Vector};
use numdiff::{get_vpartial_derivative, Dual, DualVector};
// Define the function, f(x).
fn f<S: Scalar, V: Vector<S>>(x: &V) -> V::DVectorT<S> {
V::DVectorT::from_slice(&[x[0].sin() * x[1].sin(), x[0].cos() * x[1].cos()])
}
// Define the evaluation point.
let x0 = vec![1.0, 2.0];
// Define the element of the vector (using 0-based indexing) we are differentiating with respect
// to.
let k = 0;
// Autogenerate the function "dfk" that can be used to compute the partial derivative of f(x)
// with respect to xₖ at any point x.
get_vpartial_derivative!(f, dfk);
// Verify that the partial derivative function obtained using get_vpartial_derivative! computes
// the partial derivative correctly.
assert_eq!(
dfk(&x0, k),
vec![1.0_f64.cos() * 2.0_f64.sin(), -1.0_f64.sin() * 2.0_f64.cos()]
);§Using other vector types
The function produced by get_vpartial_derivative! can accept any type for x0, as long as
it implements the linalg_traits::Vector trait.
use linalg_traits::{Scalar, Vector};
use nalgebra::{dvector, DVector, SVector};
use ndarray::{array, Array1};
use numdiff::{get_vpartial_derivative, Dual, DualVector};
// Define the function, f(x).
fn f<S: Scalar, V: Vector<S>>(x: &V) -> V::DVectorT<S> {
V::DVectorT::from_slice(&[x[0].sin() * x[1].sin(), x[0].cos() * x[1].cos()])
}
// Define the element of the vector (using 0-based indexing) we are differentiating with respect
// to.
let k = 0;
// Autogenerate the function "dfk" that can be used to compute the partial derivative of f(x)
// with respect to xₖ at any point x.
get_vpartial_derivative!(f, dfk);
// nalgebra::DVector
let x0: DVector<f64> = dvector![5.0, 1.0];
let dfk_eval: DVector<f64> = dfk(&x0, k);
// nalgebra::SVector
let x0: SVector<f64, 2> = SVector::from_slice(&[5.0, 1.0]);
let dfk_eval: DVector<f64> = dfk(&x0, k);
// ndarray::Array1
let x0: Array1<f64> = array![5.0, 1.0];
let dfk_eval: Array1<f64> = dfk(&x0, k);