macro_rules! get_vderivative {
($f:ident, $func_name:ident) => { ... };
}Expand description
Get a function that returns the derivative of the provided univariate, vector-valued function.
The derivative is computed using forward-mode automatic differentiation.
§Arguments
f- Univariate, vector-valued function, $\mathbb{f}:\mathbb{R}\to\mathbb{R}^{m}$.func_name- Name of the function that will return the derivative of $\mathbf{f}(x)$ at any point $x\in\mathbb{R}$.
§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}(x)$ to evaluate its derivative.
§Examples
§Basic Example
Compute the derivative of
$$f(t)=\begin{bmatrix}\sin{t}\\\cos{t}\end{bmatrix}$$
at $t=1$, and compare the result to the true result of
$$\frac{d\mathbf{f}}{dt}\bigg\rvert_{t=1}=\begin{bmatrix}\cos{(1)}\\-\sin{(1)}\end{bmatrix}$$
§Using standard vectors
use linalg_traits::{Scalar, Vector};
use numtest::*;
use numdiff::{get_vderivative, Dual};
// Define the function, f(t).
fn f<S: Scalar, V: Vector<S>>(t: S, _p: &[f64]) -> V {
V::from_slice(&[t.sin(), t.cos()])
}
// Autogenerate the function "df" that can be used to compute the derivative of f(t) at any
// point t.
get_vderivative!(f, df);
// Compute the derivative of f(t) at the evaluation point, t = 1.
let df_at_1 = df::<f64, Vec<f64>>(1.0, &[]);
// True derivative of f(t) at the evaluation point.
let df_at_1_true: Vec<f64> = vec![1.0_f64.cos(), -1.0_f64.sin()];
// Check the accuracy of the derivative.
assert_arrays_equal_to_decimal!(df_at_1, df_at_1_true, 16);§Using other vector types
The function produced by get_vderivative! can accept any type for x0, as long as it
implements the linalg_traits::Vector trait.
use faer::Mat;
use linalg_traits::{Scalar, Vector};
use nalgebra::{dvector, DVector, SVector};
use ndarray::{array, Array1};
use numtest::*;
use numdiff::{get_vderivative, Dual};
// Define the function, f(t).
fn f<S: Scalar, V: Vector<S>>(t: S, _p: &[f64]) -> V {
V::from_slice(&[t.sin(), t.cos()])
}
// Autogenerate the function "df" that can be used to compute the derivative of f(t) at any
// point t.
get_vderivative!(f, df);
// True derivative of f(t) at the evaluation point.
let df_at_1_true: Vec<f64> = vec![1.0_f64.cos(), -1.0_f64.sin()];
// nalgebra::DVector
let df_at_1_dvector: DVector<f64> = df::<f64, DVector<f64>>(1.0, &[]);
assert_arrays_equal_to_decimal!(df_at_1_dvector, df_at_1_true, 16);
// nalgebra::SVector
let df_at_1_svector: SVector<f64, 2> = df::<f64, SVector<f64, 2>>(1.0, &[]);
assert_arrays_equal_to_decimal!(df_at_1_svector, df_at_1_true, 16);
// ndarray::Array1
let df_at_1_array1: Array1<f64> = df::<f64, Array1<f64>>(1.0, &[]);
assert_arrays_equal_to_decimal!(df_at_1_array1, df_at_1_true, 16);
// faer::Mat
let df_at_1_mat: Mat<f64> = df::<f64, Mat<f64>>(1.0, &[]);
assert_arrays_equal_to_decimal!(df_at_1_mat.as_slice(), df_at_1_true, 16);§Example Passing Runtime Parameters
Compute the derivative of a parameterized vector function
$$f(t)=\begin{bmatrix}at^{2}+b\\ce^{t}+d\end{bmatrix}$$
where $a$, $b$, $c$, and $d$ are runtime parameters. Compare the result against the true derivative of
$$f’(t)=\begin{bmatrix}2at\\ce^{t}\end{bmatrix}$$
use linalg_traits::{Scalar, Vector};
use numtest::*;
use numdiff::{get_vderivative, Dual};
// Define the function, f(x).
fn f<S: Scalar, V: Vector<S>>(t: S, p: &[f64]) -> V {
let a = S::new(p[0]);
let b = S::new(p[1]);
let c = S::new(p[2]);
let d = S::new(p[3]);
V::from_slice(&[a * t.powi(2) + b, c * t.exp() + d])
}
// Parameter vector.
let a = 1.5;
let b = -2.0;
let c = 0.8;
let d = 3.0;
let p = [a, b, c, d];
// Autogenerate the derivative function.
get_vderivative!(f, df);
// True derivative function.
let df_true = |t: f64| vec![2.0 * a * t, c * t.exp()];
// Compute the derivative at t = 1.0 using both the automatically generated derivative function
// and the true derivative function, and compare the results.
let df_at_1: Vec<f64> = df::<f64, Vec<f64>>(1.0, &p);
let df_at_1_true: Vec<f64> = df_true(1.0);
assert_arrays_equal_to_decimal!(df_at_1, df_at_1_true, 15);