Skip to main content

get_sderivative2

Macro get_sderivative2 

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

Get a function that returns the second derivative of the provided univariate, scalar-valued function.

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

§Arguments

  • f - Univariate, scalar-valued function, $f:\mathbb{R}\to\mathbb{R}$.
  • func_name - Name of the function that will return the second derivative of $f(x)$ at any point $x\in\mathbb{R}$.
  • param_type (optional) - Type of the extra runtime parameter p that is passed to f. Defaults to [f64] (implying that f accepts p: &[f64]).

§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(x)$ to evaluate its second derivative.

§Examples

§Basic Example

Compute the second derivative of

$$f(x)=x^{3}$$

at $x=2$, and compare the result to the true result of $f’’(2)=12$.

use linalg_traits::Scalar;
use numtest::*;

use numdiff::{get_sderivative2, HyperDual};

// Define the function, f(x).
fn f<S: Scalar>(x: S, _p: &[f64]) -> S {
    x.powi(3)
}

// Parameter vector (empty for this example).
let p = [];

// Autogenerate the function "d2f" that can be used to compute the second derivative of f(x) at
// any point x.
get_sderivative2!(f, d2f);

// Compute the second derivative of f(x) at the evaluation point, x = 2.
let d2f_at_2: f64 = d2f(2.0, &p);

// Check the accuracy of the second derivative.
assert_equal_to_decimal!(d2f_at_2, 12.0, 16);

§Example Passing Runtime Parameters

Compute the second derivative of a parameterized function

$$f(x)=ax^{2}+bx+c$$

where $a$, $b$, and $c$ are runtime parameters. Compare the result against the true second derivative of

$$f’’(x)=2a$$

use linalg_traits::Scalar;
use numtest::*;

use numdiff::{get_sderivative2, HyperDual};

// Define the function, f(x).
fn f<S: Scalar>(x: S, p: &[f64]) -> S {
    let a = S::new(p[0]);
    let b = S::new(p[1]);
    let c = S::new(p[2]);
    a * x.powi(2) + b * x + c
}

// Parameter vector.
let a = 2.5;
let b = -1.3;
let c = 4.7;
let p = [a, b, c];

// Autogenerate the second derivative function.
get_sderivative2!(f, d2f);

// True second derivative function.
let d2f_true = |_x: f64| 2.0 * a;

// Compute the second derivative at x = 1.0 using both the automatically generated second
// derivative function and the true second derivative function, and compare the results.
let d2f_at_1: f64 = d2f(1.0, &p);
let d2f_at_1_true: f64 = d2f_true(1.0);
assert_eq!(d2f_at_1, d2f_at_1_true);

§Example Passing Custom Parameter Types

Use a custom parameter struct instead of f64 values.

use linalg_traits::Scalar;
use numtest::*;

use numdiff::{get_sderivative2, HyperDual};

struct Data {
    a: f64,
    b: f64,
    c: f64,
}

// Define the function, f(x).
fn f<S: Scalar>(x: S, p: &Data) -> S {
    let a = S::new(p.a);
    let b = S::new(p.b);
    let c = S::new(p.c);
    a * x.powi(2) + b * x + c
}

// Runtime parameter struct.
let p = Data {
    a: 2.5,
    b: -1.3,
    c: 4.7,
};

// Autogenerate the second derivative function, telling the macro to expect a runtime parameter
// of type `&Data`.
get_sderivative2!(f, d2f, Data);

// True second derivative function.
let d2f_true = |_x: f64| 2.0 * p.a;

// Compute the second derivative at x = 1.0 using both the automatically generated second
// derivative function and the true second derivative function, and compare the results.
let x0 = 1.0;
let d2f_eval: f64 = d2f(x0, &p);
let d2f_eval_true: f64 = d2f_true(x0);
assert_equal_to_decimal!(d2f_eval, d2f_eval_true, 15);