| This module provides support for automatic differentiation. For precise information on | |
| differences between the `autodiff_forward` and `autodiff_reverse` macros and how to | |
| use them, see their respective documentation. | |
| ## General usage | |
| Autodiff macros can be applied to almost all function definitions, see below for examples. | |
| They can be applied to functions accepting structs, arrays, slices, vectors, tuples, and more. | |
| It is possible to apply multiple autodiff macros to the same function. As an example, this can | |
| be helpful to compute the partial derivatives with respect to `x` and `y` independently: | |
| ```rust,ignore (optional component) | |
| #[autodiff_forward(dsquare1, Dual, Const, Dual)] | |
| #[autodiff_forward(dsquare2, Const, Dual, Dual)] | |
| #[autodiff_forward(dsquare3, Active, Active, Active)] | |
| fn square(x: f64, y: f64) -> f64 { | |
| x * x + 2.0 * y | |
| } | |
| ``` | |
| We also support autodiff on functions with generic parameters: | |
| ```rust,ignore (optional component) | |
| #[autodiff_forward(generic_derivative, Duplicated, Active)] | |
| fn generic_f<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T { | |
| x * x | |
| } | |
| ``` | |
| or applying autodiff to nested functions: | |
| ```rust,ignore (optional component) | |
| fn outer(x: f64) -> f64 { | |
| #[autodiff_forward(inner_derivative, Dual, Const)] | |
| fn inner(y: f64) -> f64 { | |
| y * y | |
| } | |
| inner_derivative(x, 1.0) | |
| } | |
| fn main() { | |
| assert_eq!(outer(3.14), 6.28); | |
| } | |
| ``` | |
| The generated function will be available in the same scope as the function differentiated, and | |
| have the same private/pub usability. | |
| ## Traits and impls | |
| Autodiff macros can be used in multiple ways in combination with traits: | |
| ```rust,ignore (optional component) | |
| struct Foo { | |
| a: f64, | |
| } | |
| trait MyTrait { | |
| #[autodiff_reverse(df, Const, Active, Active)] | |
| fn f(&self, x: f64) -> f64; | |
| } | |
| impl MyTrait for Foo { | |
| fn f(&self, x: f64) -> f64 { | |
| x.sin() | |
| } | |
| } | |
| fn main() { | |
| let foo = Foo { a: 3.0f64 }; | |
| assert_eq!(foo.f(2.0), 2.0_f64.sin()); | |
| assert_eq!(foo.df(2.0, 1.0).1, 2.0_f64.cos()); | |
| } | |
| ``` | |
| In this case `df` will be the default implementation provided by the library who provided the | |
| trait. A user implementing `MyTrait` could then decide to use the default implementation of | |
| `df`, or overwrite it with a custom implementation as a form of "custom derivatives". | |
| On the other hand, a function generated by either autodiff macro can also be used to implement a | |
| trait: | |
| ```rust,ignore (optional component) | |
| struct Foo { | |
| a: f64, | |
| } | |
| trait MyTrait { | |
| fn f(&self, x: f64) -> f64; | |
| fn df(&self, x: f64, seed: f64) -> (f64, f64); | |
| } | |
| impl MyTrait for Foo { | |
| #[autodiff_reverse(df, Const, Active, Active)] | |
| fn f(&self, x: f64) -> f64 { | |
| self.a * 0.25 * (x * x - 1.0 - 2.0 * x.ln()) | |
| } | |
| } | |
| ``` | |
| Simple `impl` blocks without traits are also supported. Differentiating with respect to the | |
| implemented struct will then require the use of a "shadow struct" to hold the derivatives of the | |
| struct fields: | |
| ```rust,ignore (optional component) | |
| struct OptProblem { | |
| a: f64, | |
| b: f64, | |
| } | |
| impl OptProblem { | |
| #[autodiff_reverse(d_objective, Duplicated, Duplicated, Duplicated)] | |
| fn objective(&self, x: &[f64], out: &mut f64) { | |
| *out = self.a + x[0].sqrt() * self.b | |
| } | |
| } | |
| fn main() { | |
| let p = OptProblem { a: 1., b: 2. }; | |
| let mut p_shadow = OptProblem { a: 0., b: 0. }; | |
| let mut dx = [0.0]; | |
| let mut out = 0.0; | |
| let mut dout = 1.0; | |
| p.d_objective(&mut p_shadow, &x, &mut dx, &mut out, &mut dout); | |
| } | |
| ``` | |
| ## Higher-order derivatives | |
| Finally, it is possible to generate higher-order derivatives (e.g. Hessian) by applying an | |
| autodiff macro to a function that is already generated by an autodiff macro, via a thin wrapper. | |
| The following example uses Forward mode over Reverse mode | |
| ```rust,ignore (optional component) | |
| #[autodiff_reverse(df, Duplicated, Duplicated)] | |
| fn f(x: &[f64;2], y: &mut f64) { | |
| *y = x[0] * x[0] + x[1] * x[0] | |
| } | |
| #[autodiff_forward(h, Dual, Dual, Dual, Dual)] | |
| fn wrapper(x: &[f64;2], dx: &mut [f64;2], y: &mut f64, dy: &mut f64) { | |
| df(x, dx, y, dy); | |
| } | |
| fn main() { | |
| let mut y = 0.0; | |
| let x = [2.0, 2.0]; | |
| let mut dy = 0.0; | |
| let mut dx = [1.0, 0.0]; | |
| let mut bx = [0.0, 0.0]; | |
| let mut by = 1.0; | |
| let mut dbx = [0.0, 0.0]; | |
| let mut dby = 0.0; | |
| h(&x, &mut dx, &mut bx, &mut dbx, &mut y, &mut dy, &mut by, &mut dby); | |
| assert_eq!(&dbx, [2.0, 1.0]); | |
| } | |
| ``` | |
| ## Current limitations: | |
| - Differentiating a function which accepts a `dyn Trait` is currently not supported. | |
| - Builds without `lto="fat"` are not yet supported. | |
| - Builds in debug mode are currently more likely to fail compilation. |