1 unstable release

0.1.0 Nov 12, 2023

#1629 in Algorithms

MIT license

22KB
651 lines

frechet

frechet implements the simple dual number types dual32 and dual64, thus providing basic auto-differentiation capabilities.

Example

use frechet::*;

fn p(x: dual32) -> dual32 { x.powf(2.5).atanh() + 1.0  }
fn p_derivative(x: f32) -> f32 { -2.5 * x.powf(1.5)/(x.powi(5) - 1.0) }

// using the `derivative` function
let z1 = derivative(p, 2.0);

// manually
let z2 = p(2.0.as_dual_variable()).d;

// exact derivative
let z3 = p_derivative(2.0);

assert!((z1 - z3).abs() < f32::EPSILON);
assert!((z2 - z3).abs() < f32::EPSILON);

lib.rs:

frechet is a library providing simple dual number types with interfaces similar to that of the standard floating point types. Additionally, provides a small interface to abstract the computation of derivatives.

Refresher on dual numbers

A dual number $z$ is represented as the sum of a "real part" $x$ and an "imaginary part" $y$, and written $z = x + yj$, where $j$ is purely symbolic and follows the rule $j^2 = 0$. As an example, evaluating the polynomial $P(X)=3X^2-X+1$ at the dual number $X + j$ yields $$P(X+j)=3X^2-X+1 + (6X-1)j = P(X) + P^\prime(X)j.$$ This motivates the following extension of any (differentiable) real function $f$ to dual numbers: $$f(x+yj) = f(x) + yf^\prime(x)j.$$

Example

use frechet::*;

fn p(x: dual32) -> dual32 { x.powf(2.5).atanh() + 1.0  }
fn p_derivative(x: f32) -> f32 { -2.5 * x.powf(1.5)/(x.powi(5) - 1.0) }

// using the `derivative` function
let z1 = derivative(p, 2.0);

// manually
let z2 = p(2.0.as_dual_variable()).d;

// exact derivative
let z3 = p_derivative(2.0);

assert!((z1 - z3).abs() < f32::EPSILON);
assert!((z2 - z3).abs() < f32::EPSILON);

No runtime deps