Macro get_spartial_derivative

Source
macro_rules! get_spartial_derivative {
    ($f:ident, $func_name:ident) => { ... };
}
Expand description

Get a function that returns the partial derivative of the provided multivariate, scalar-valued function.

The partial derivative is computed using forward-mode automatic differentiation.

§Arguments

  • f - Multivariate, scalar-valued function, $f:\mathbb{R}^{n}\to\mathbb{R}$.
  • func_name - Name of the function that will return the partial derivative of $f(\mathbf{x})$ with respect to $x_{k}$ at any point $\mathbf{x}\in\mathbb{R}^{n}$.

§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 $f(\mathbf{x})$ to evaluate its partial derivative with respect to $x_{k}$.

§Example

Compute the partial derivative of

$$f(x)=x^{3}\sin{y}$$

with respect to $y$ at $(x,y)=(5,1)$, and compare the result to the true result of

$$\frac{\partial f}{\partial y}\bigg\rvert_{(x,y)=(5,1)}=5^{3}\cos{(1)}$$

First, note that we can rewrite this function as

$$f(\mathbf{x})=x_{0}^{3}\sin{x_{1}}$$

where $\mathbf{x}=(x_{0},x_{1})^{T}$ (note that we use 0-based indexing to aid with the computational implementation). We are then trying to find

$$\frac{\partial f}{\partial x_{1}}\bigg\rvert_{\mathbf{x}=\mathbf{x}_{0}}$$

where $\mathbf{x}_{0}=(5,1)^{T}$.

§Using standard vectors
use linalg_traits::{Scalar, Vector};

use numdiff::{get_spartial_derivative, Dual, DualVector};

// Define the function, f(x).
fn f<S: Scalar, V: Vector<S>>(x: &V) -> S {
    x.vget(0).powi(3) * x.vget(1).sin()
}

// Define the evaluation point.
let x0 = vec![5.0, 1.0];

// Define the element of the vector (using 0-based indexing) we are differentiating with respect
// to.
let k = 1;

// 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_spartial_derivative!(f, dfk);

// Verify that the partial derivative function obtained using get_spartial_derivative! computes
// the partial derivative correctly.
assert_eq!(dfk(&x0, k), 5.0_f64.powi(3) * 1.0_f64.cos());
§Using other vector types

The function produced by get_spartial_derivative! 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 numdiff::{get_spartial_derivative, Dual, DualVector};

// Define the function, f(x).
fn f<S: Scalar, V: Vector<S>>(x: &V) -> S {
    x.vget(0).powi(3) * x.vget(1).sin()
}

// Define the element of the vector (using 0-based indexing) we are differentiating with respect
// to.
let k = 1;

// 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_spartial_derivative!(f, dfk);

// nalgebra::DVector
let x0: DVector<f64> = dvector![5.0, 1.0];
let dfk_eval: f64 = dfk(&x0, k);

// nalgebra::SVector
let x0: SVector<f64, 2> = SVector::from_slice(&[5.0, 1.0]);
let dfk_eval: f64 = dfk(&x0, k);

// ndarray::Array1
let x0: Array1<f64> = array![5.0, 1.0];
let dfk_eval: f64 = dfk(&x0, k);

// faer::Mat
let x0: Mat<f64> = Mat::from_slice(&[5.0, 1.0]);
let dfk_eval: f64 = dfk(&x0, k);