get_vderivative

Macro get_vderivative 

Source
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);