Skip to main content

num_dual/
lib.rs

1//! Generalized, recursive, scalar and vector (hyper) dual numbers for the automatic and exact calculation of (partial) derivatives.
2//!
3//! # Example
4//! This example defines a generic scalar and a generic vector function that can be called using any (hyper-) dual number and automatically calculates derivatives.
5//! ```
6//! # #[cfg(feature = "nalgebra")]
7//! # {
8//! use num_dual::*;
9//! use nalgebra::SVector;
10//!
11//! fn foo<D: DualNum>(x: D) -> D {
12//!     x.powi(3)
13//! }
14//!
15//! fn bar<D: DualNum, const N: usize>(x: SVector<D, N>) -> D {
16//!     x.dot(&x).sqrt()
17//! }
18//!
19//! fn main() {
20//!     // Calculate a simple derivative
21//!     let (f, df) = first_derivative(foo, 5.0);
22//!     assert_eq!(f, 125.0);
23//!     assert_eq!(df, 75.0);
24//!
25//!     // Manually construct the dual number
26//!     let x = Dual64::new(5.0, 1.0);
27//!     println!("{}", foo(x));                     // 125 + 75ε
28//!
29//!     // Calculate a gradient
30//!     let (f, g) = gradient(bar, &SVector::from([4.0, 3.0]));
31//!     assert_eq!(f, 5.0);
32//!     assert_eq!(g[0], 0.8);
33//!
34//!     // Calculate a Hessian
35//!     let (f, g, h) = hessian(bar, &SVector::from([4.0, 3.0]));
36//!     println!("{h}");                            // [[0.072, -0.096], [-0.096, 0.128]]
37//!
38//!     // for x=cos(t) calculate the third derivative of foo w.r.t. t
39//!     let (f0, f1, f2, f3) = third_derivative(|t| foo(t.cos()), 1.0);
40//!     println!("{f3}");                           // 1.5836632930100278
41//! }
42//! # }
43//! ```
44//!
45//! # Usage
46//! There are two ways to use the data structures and functions provided in this crate:
47//! 1. (recommended) Using the provided functions for explicit ([`first_derivative`], [`gradient`], ...) and
48//!    implicit ([`implicit_derivative`], [`implicit_derivative_binary`], [`implicit_derivative_vec`]) functions.
49//! 2. (for experienced users) Using the different dual number types ([`Dual`], [`HyperDual`], [`DualVec`], ...) directly.
50//!
51//! The following examples and explanations focus on the first way.
52//!
53//! # Derivatives of explicit functions
54//! To be able to calculate the derivative of a function, it needs to be generic over the type of dual number used.
55//! Most commonly this would look like this:
56//! ```compile_fail
57//! fn foo<D: DualNum + Copy>(x: X) -> O {...}
58//! ```
59//! Of course, the function could also use single precision ([`f32`]) or be generic over the precision (`F:` [`DualNumFloat`]).
60//! For now, [`Copy`] is not a supertrait of [`DualNum`] to enable the calculation of derivatives with respect
61//! to a dynamic number of variables. However, in practice, using the [`Copy`] trait bound leads to an
62//! implementation that is more similar to one not using AD and there could be severe performance ramifications
63//! when using dynamically allocated dual numbers.
64//!
65//! The type `X` above is `D` for univariate functions, [`&OVector`](nalgebra::OVector) for multivariate
66//! functions, and `(D, D)` or `(&OVector, &OVector)` for partial derivatives. In the simplest case, the output
67//! `O` is a scalar `D`. However, it is generalized using the [`Mappable`] trait to also include types like
68//! [`Option<D>`] or [`Result<D, E>`], collections like [`Vec<D>`] or [`HashMap<K, D>`], or custom structs that
69//! implement the [`Mappable`] trait. Therefore, it is, e.g., possible to calculate the derivative of a fallible
70//! function:
71//!
72//! ```no_run
73//! # use num_dual::{DualNum, first_derivative};
74//! # type E = ();
75//! fn foo<D: DualNum + Copy>(x: D) -> Result<D, E> { todo!() }
76//!
77//! fn main() -> Result<(), E> {
78//!     let (val, deriv) = first_derivative(foo, 2.0)?;
79//!     // ...
80//!     Ok(())
81//! }
82//! ```
83//! All dual number types can contain other dual numbers as inner types. Therefore, it is also possible to
84//! use the different derivative functions inside of each other.
85//!
86//! ## Extra arguments
87//! The [`partial`] and [`partial2`] functions are used to pass additional arguments to the function, e.g.:
88//! ```no_run
89//! # use num_dual::{DualNum, first_derivative, partial};
90//! fn foo<D: DualNum + Copy>(x: D, args: &(D, D)) -> D { todo!() }
91//!
92//! fn main() {
93//!     let (val, deriv) = first_derivative(partial(foo, &(3.0, 4.0)), 5.0);
94//! }
95//! ```
96//! All types that implement the [`DualStruct`] trait can be used as additional function arguments. The
97//! only difference between using the [`partial`] and [`partial2`] functions compared to passing the extra
98//! arguments via a closure, is that the type of the extra arguments is automatically adjusted to the correct
99//! dual number type used for the automatic differentiation. Note that the following code would not compile:
100//! ```compile_fail
101//! # use num_dual::{DualNum, first_derivative};
102//! # fn foo<D: DualNum + Copy>(x: D, args: &(D, D)) -> D { todo!() }
103//! fn main() {
104//!     let (val, deriv) = first_derivative(|x| foo(x, &(3.0, 4.0)), 5.0);
105//! }
106//! ```
107//! The code created by [`partial`] essentially translates to:
108//! ```no_run
109//! # use num_dual::{DualNum, first_derivative, Dual, DualStruct};
110//! # fn foo<D: DualNum + Copy>(x: D, args: &(D, D)) -> D { todo!() }
111//! fn main() {
112//!     let (val, deriv) = first_derivative(|x| foo(x, &(Dual::from_re(3.0), Dual::from_re(4.0))), 5.0);
113//! }
114//! ```
115//!
116//! ## The [`Gradients`] trait
117//! The functions [`gradient`], [`hessian`], [`partial_hessian`] and [`jacobian`] are generic over the dimensionality
118//! of the variable vector. However, to use the functions in a generic context requires not using the [`Copy`] trait
119//! bound on the dual number type, because the dynamically sized dual numbers can by construction not implement
120//! [`Copy`]. Also, due to frequent heap allocations, the performance of the automatic differentiation could
121//! suffer significantly for dynamically sized dual numbers compared to statically sized dual numbers. The
122//! [`Gradients`] trait is introduced to overcome these limitations.
123//! ```
124//! # #[cfg(feature = "nalgebra")]
125//! # {
126//! # use num_dual::{DualNum, Gradients};
127//! # use nalgebra::{OVector, DefaultAllocator, allocator::Allocator, vector, dvector};
128//! # use approx::assert_relative_eq;
129//! fn foo<D: DualNum + Copy, N: Gradients>(x: OVector<D, N>, n: &D) -> D where DefaultAllocator: Allocator<N> {
130//!     x.dot(&x).sqrt() - n
131//! }
132//!
133//! fn main() {
134//!     let x = vector![1.0, 5.0, 5.0, 7.0];
135//!     let (f, grad) = Gradients::gradient(foo, &x, &10.0);
136//!     assert_eq!(f, 0.0);
137//!     assert_relative_eq!(grad, vector![0.1, 0.5, 0.5, 0.7]);
138//!
139//!     let x = dvector![1.0, 5.0, 5.0, 7.0];
140//!     let (f, grad) = Gradients::gradient(foo, &x, &10.0);
141//!     assert_eq!(f, 0.0);
142//!     assert_relative_eq!(grad, dvector![0.1, 0.5, 0.5, 0.7]);
143//! }
144//! # }
145//! ```
146//! For dynamically sized input arrays, the [`Gradients`] trait evaluates gradients or higher-order derivatives
147//! by iteratively evaluating scalar derivatives. For functions that do not rely on the [`Copy`] trait bound,
148//! only benchmarking can reveal Whether the increased performance through the avoidance of heap allocations
149//! can overcome the overhead of repeated function evaluations, i.e., if [`Gradients`] outperforms directly
150//! calling [`gradient`], [`hessian`], [`partial_hessian`] or [`jacobian`].
151//!
152//! # Derivatives of implicit functions
153//! Implicit differentiation is used to determine the derivative `dy/dx` where the output `y` is only related
154//! implicitly to the input `x` via the equation `f(x,y)=0`. Automatic implicit differentiation generalizes the
155//! idea to determining the output `y` with full derivative information. Note that the first step in calculating
156//! an implicit derivative is always determining the "real" part (i.e., neglecting all derivatives) of the equation
157//! `f(x,y)=0`. The `num-dual` library is focused on automatic differentiation and not nonlinear equation
158//! solving. Therefore, this first step needs to be done with your own custom solutions, or Rust crates for
159//! nonlinear equation solving and optimization like, e.g., [argmin](https://argmin-rs.org/).
160//!
161//! The following example implements a square root for generic dual numbers using implicit differentiation. Of
162//! course, the derivatives of the square root can also be determined explicitly using the chain rule, so the
163//! example serves mostly as illustration. `x.re()` provides the "real" part of the dual number which is a [`f64`]
164//! and therefore, we can use all the functionalities from the std library (including the square root).
165//! ```
166//! # use num_dual::{DualNum, implicit_derivative, first_derivative};
167//! fn implicit_sqrt<D: DualNum + Copy>(x: D) -> D {
168//!     implicit_derivative(|s, x| s * s - x, x.re().sqrt(), &x)
169//! }
170//!
171//! fn main() {
172//!     // sanity check, not actually calculating any derivative
173//!     assert_eq!(implicit_sqrt(25.0), 5.0);
174//!     
175//!     let (sq, deriv) = first_derivative(implicit_sqrt, 25.0);
176//!     assert_eq!(sq, 5.0);
177//!     // The derivative of sqrt(x) is 1/(2*sqrt(x)) which should evaluate to 0.1
178//!     assert_eq!(deriv, 0.1);
179//! }
180//! ```
181//! The `implicit_sqrt` or any likewise defined function is generic over the dual type `D`
182//! and can, therefore, be used anywhere as a part of an arbitrary complex computation. The functions
183//! [`implicit_derivative_binary`] and [`implicit_derivative_vec`] can be used for implicit functions
184//! with more than one variable.
185//!
186//! For implicit functions that contain complex models and a large number of parameters, the [`ImplicitDerivative`]
187//! interface might come in handy. The idea is to define the implicit function using the [`ImplicitFunction`] trait
188//! and feeding it into the [`ImplicitDerivative`] struct, which internally stores the parameters as dual numbers
189//! and their real parts. The [`ImplicitDerivative`] then provides methods for the evaluation of the real part
190//! of the residual (which can be passed to a nonlinear solver) and the implicit derivative which can be called
191//! after solving for the real part of the solution to reconstruct all the derivatives.
192//! ```
193//! # use num_dual::{ImplicitFunction, DualNum, Dual, ImplicitDerivative};
194//! struct ImplicitSqrt;
195//! impl ImplicitFunction for ImplicitSqrt {
196//!     type Parameters<D> = D;
197//!     type Variable<D> = D;
198//!     fn residual<D: DualNum + Copy>(x: D, square: &D) -> D {
199//!         *square - x * x
200//!     }
201//! }
202//!
203//! fn main() {
204//!     let x = Dual::from_re(25.0).derivative();
205//!     let func = ImplicitDerivative::new(ImplicitSqrt, x);
206//!     assert_eq!(func.residual(5.0), 0.0);
207//!     assert_eq!(x.sqrt(), func.implicit_derivative(5.0));
208//! }
209//! ```
210//!
211//! ## Combination with nonlinear solver libraries
212//! As mentioned previously, this crate does not contain any algorithms for nonlinear optimization or root finding.
213//! However, combining the capabilities of automatic differentiation with nonlinear solving can be very fruitful.
214//! Most importantly, the calculation of Jacobians or Hessians can be completely automated, if the model can be
215//! expressed within the functionalities of the [`DualNum`] trait. On top of that implicit derivatives can be of
216//! interest, if derivatives of the result of the optimization itself are relevant (e.g., in a bilevel
217//! optimization). The synergy is exploited in the [`ipopt-ad`](https://github.com/prehner/ipopt-ad) crate that
218//! turns the NLP solver [IPOPT](https://github.com/coin-or/Ipopt) into a black-box optimization algorithm (i.e.,
219//! it only requires a function that returns the values of the optimization variable and constraints), without
220//! any repercussions regarding the robustness or speed of convergence of the solver.
221//!
222//! If you are developing nonlinear optimization algorithms in Rust, feel free to reach out to us. We are happy to
223//! discuss how to enhance your algorithms with the automatic differentiation capabilities of this crate.
224
225#![warn(clippy::all)]
226#![warn(clippy::allow_attributes)]
227
228#[cfg(feature = "nalgebra")]
229use nalgebra::{DefaultAllocator, Dim, OMatrix, Scalar, allocator::Allocator};
230#[cfg(feature = "ndarray")]
231use ndarray::ScalarOperand;
232use num_traits::{Float, FloatConst, FromPrimitive, Inv, NumAssignOps, NumOps, Signed};
233use std::collections::HashMap;
234use std::fmt;
235use std::hash::Hash;
236use std::iter::{Product, Sum};
237
238#[macro_use]
239mod macros;
240#[macro_use]
241#[cfg(feature = "nalgebra")]
242mod nalgebra_macros;
243#[macro_use]
244mod impl_derivatives;
245
246mod bessel;
247mod datatypes;
248mod explicit;
249mod implicit;
250pub use bessel::BesselDual;
251#[cfg(feature = "nalgebra")]
252pub use datatypes::derivative::Derivative;
253pub use datatypes::dual::{Dual, Dual32, Dual64};
254#[cfg(feature = "nalgebra")]
255pub use datatypes::dual_vec::{
256    DualDVec32, DualDVec64, DualSVec, DualSVec32, DualSVec64, DualVec, DualVec32, DualVec64,
257};
258pub use datatypes::dual2::{Dual2, Dual2_32, Dual2_64};
259#[cfg(feature = "nalgebra")]
260pub use datatypes::dual2_vec::{
261    Dual2DVec, Dual2DVec32, Dual2DVec64, Dual2SVec, Dual2SVec32, Dual2SVec64, Dual2Vec, Dual2Vec32,
262    Dual2Vec64,
263};
264pub use datatypes::dual3::{Dual3, Dual3_32, Dual3_64};
265pub use datatypes::hyperdual::{HyperDual, HyperDual32, HyperDual64};
266#[cfg(feature = "nalgebra")]
267pub use datatypes::hyperdual_vec::{
268    HyperDualDVec32, HyperDualDVec64, HyperDualSVec32, HyperDualSVec64, HyperDualVec,
269    HyperDualVec32, HyperDualVec64,
270};
271pub use datatypes::hyperhyperdual::{HyperHyperDual, HyperHyperDual32, HyperHyperDual64};
272pub use datatypes::real::Real;
273#[cfg(feature = "nalgebra")]
274pub use explicit::{Gradients, gradient, hessian, jacobian, partial_hessian};
275pub use explicit::{
276    first_derivative, partial, partial2, partial3, second_derivative, second_partial_derivative,
277    third_derivative, third_partial_derivative, third_partial_derivative_vec, zeroth_derivative,
278};
279pub use implicit::{ImplicitDerivative, ImplicitFunction, implicit_derivative};
280#[cfg(feature = "nalgebra")]
281pub use implicit::{implicit_derivative_binary, implicit_derivative_sp, implicit_derivative_vec};
282
283#[cfg(feature = "nalgebra")]
284pub mod linalg;
285
286#[cfg(feature = "python")]
287pub mod python;
288
289#[cfg(feature = "python_macro")]
290mod python_macro;
291
292/// A generalized (hyper) dual number.
293#[cfg(feature = "ndarray")]
294pub trait DualNum:
295    NumOps
296    + for<'r> NumOps<&'r Self>
297    + Signed
298    + NumOps<Self::Primitive>
299    + NumAssignOps
300    + NumAssignOps<Self::Primitive>
301    + Clone
302    + Inv<Output = Self>
303    + Sum
304    + Product
305    + FromPrimitive
306    + From<Self::Primitive>
307    + DualStruct<Real = Self::Primitive>
308    + Mappable<Self>
309    + fmt::Display
310    + PartialOrd
311    + PartialOrd<Self::Primitive>
312    + fmt::Debug
313    + ScalarOperand
314    + 'static
315{
316    /// The underlying primitive data type (mostly f64 or f32)
317    type Primitive: DualNumFloat;
318
319    /// Highest derivative that can be calculated with this struct
320    const NDERIV: usize;
321
322    /// The type of the individual elements of this dual number
323    type InnerDual: DualNum;
324
325    /// Build a dual number from its real part, setting all other values to 0
326    fn from_re(re: Self::InnerDual) -> Self;
327
328    /// Reciprocal (inverse) of a number `1/x`
329    fn recip(&self) -> Self;
330
331    /// Power with integer exponent `x^n`
332    fn powi(&self, n: i32) -> Self;
333
334    /// Power with real exponent `x^n`
335    fn powf(&self, n: Self::Primitive) -> Self;
336
337    /// Square root
338    fn sqrt(&self) -> Self;
339
340    /// Cubic root
341    fn cbrt(&self) -> Self;
342
343    /// Exponential `e^x`
344    fn exp(&self) -> Self;
345
346    /// Exponential with base 2 `2^x`
347    fn exp2(&self) -> Self;
348
349    /// Exponential minus 1 `e^x-1`
350    fn exp_m1(&self) -> Self;
351
352    /// Natural logarithm
353    fn ln(&self) -> Self;
354
355    /// Logarithm with arbitrary base
356    fn log(&self, base: Self::Primitive) -> Self;
357
358    /// Logarithm with base 2
359    fn log2(&self) -> Self;
360
361    /// Logarithm with base 10
362    fn log10(&self) -> Self;
363
364    /// Logarithm on x plus one `ln(1+x)`
365    fn ln_1p(&self) -> Self;
366
367    /// Sine
368    fn sin(&self) -> Self;
369
370    /// Cosine
371    fn cos(&self) -> Self;
372
373    /// Tangent
374    fn tan(&self) -> Self;
375
376    /// Calculate sine and cosine simultaneously
377    fn sin_cos(&self) -> (Self, Self);
378
379    /// Arcsine
380    fn asin(&self) -> Self;
381
382    /// Arccosine
383    fn acos(&self) -> Self;
384
385    /// Arctangent
386    fn atan(&self) -> Self;
387
388    /// Arctangent
389    fn atan2(&self, other: Self) -> Self;
390
391    /// Hyperbolic sine
392    fn sinh(&self) -> Self;
393
394    /// Hyperbolic cosine
395    fn cosh(&self) -> Self;
396
397    /// Hyperbolic tangent
398    fn tanh(&self) -> Self;
399
400    /// Area hyperbolic sine
401    fn asinh(&self) -> Self;
402
403    /// Area hyperbolic cosine
404    fn acosh(&self) -> Self;
405
406    /// Area hyperbolic tangent
407    fn atanh(&self) -> Self;
408
409    /// 0th order spherical Bessel function of the first kind
410    fn sph_j0(&self) -> Self;
411
412    /// 1st order spherical Bessel function of the first kind
413    fn sph_j1(&self) -> Self;
414
415    /// 2nd order spherical Bessel function of the first kind
416    fn sph_j2(&self) -> Self;
417
418    /// Fused multiply-add
419    #[inline]
420    fn mul_add(&self, a: Self, b: Self) -> Self {
421        self.clone() * a + b
422    }
423
424    /// Power with dual exponent `x^n`
425    #[inline]
426    fn powd(&self, exp: Self) -> Self {
427        (self.ln() * exp).exp()
428    }
429}
430
431/// A generalized (hyper) dual number.
432#[cfg(not(feature = "ndarray"))]
433pub trait DualNum:
434    NumOps
435    + for<'r> NumOps<&'r Self>
436    + Signed
437    + NumOps<Self::Primitive>
438    + NumAssignOps
439    + NumAssignOps<Self::Primitive>
440    + Clone
441    + Inv<Output = Self>
442    + Sum
443    + Product
444    + FromPrimitive
445    + From<Self::Primitive>
446    + DualStruct<Real = Self::Primitive>
447    + Mappable<Self>
448    + fmt::Display
449    + PartialOrd
450    + PartialOrd<Self::Primitive>
451    + fmt::Debug
452    + 'static
453{
454    /// The underlying primitive data type (mostly f64 or f32)
455    type Primitive: DualNumFloat;
456
457    /// Highest derivative that can be calculated with this struct
458    const NDERIV: usize;
459
460    /// The type of the individual elements of this dual number
461    type InnerDual: DualNum;
462
463    /// Build a dual number from its real part, setting all other values to 0
464    fn from_re(re: Self::InnerDual) -> Self;
465
466    /// Reciprocal (inverse) of a number `1/x`
467    fn recip(&self) -> Self;
468
469    /// Power with integer exponent `x^n`
470    fn powi(&self, n: i32) -> Self;
471
472    /// Power with real exponent `x^n`
473    fn powf(&self, n: Self::Primitive) -> Self;
474
475    /// Square root
476    fn sqrt(&self) -> Self;
477
478    /// Cubic root
479    fn cbrt(&self) -> Self;
480
481    /// Exponential `e^x`
482    fn exp(&self) -> Self;
483
484    /// Exponential with base 2 `2^x`
485    fn exp2(&self) -> Self;
486
487    /// Exponential minus 1 `e^x-1`
488    fn exp_m1(&self) -> Self;
489
490    /// Natural logarithm
491    fn ln(&self) -> Self;
492
493    /// Logarithm with arbitrary base
494    fn log(&self, base: Self::Primitive) -> Self;
495
496    /// Logarithm with base 2
497    fn log2(&self) -> Self;
498
499    /// Logarithm with base 10
500    fn log10(&self) -> Self;
501
502    /// Logarithm on x plus one `ln(1+x)`
503    fn ln_1p(&self) -> Self;
504
505    /// Sine
506    fn sin(&self) -> Self;
507
508    /// Cosine
509    fn cos(&self) -> Self;
510
511    /// Tangent
512    fn tan(&self) -> Self;
513
514    /// Calculate sine and cosine simultaneously
515    fn sin_cos(&self) -> (Self, Self);
516
517    /// Arcsine
518    fn asin(&self) -> Self;
519
520    /// Arccosine
521    fn acos(&self) -> Self;
522
523    /// Arctangent
524    fn atan(&self) -> Self;
525
526    /// Arctangent
527    fn atan2(&self, other: Self) -> Self;
528
529    /// Hyperbolic sine
530    fn sinh(&self) -> Self;
531
532    /// Hyperbolic cosine
533    fn cosh(&self) -> Self;
534
535    /// Hyperbolic tangent
536    fn tanh(&self) -> Self;
537
538    /// Area hyperbolic sine
539    fn asinh(&self) -> Self;
540
541    /// Area hyperbolic cosine
542    fn acosh(&self) -> Self;
543
544    /// Area hyperbolic tangent
545    fn atanh(&self) -> Self;
546
547    /// 0th order spherical Bessel function of the first kind
548    fn sph_j0(&self) -> Self;
549
550    /// 1st order spherical Bessel function of the first kind
551    fn sph_j1(&self) -> Self;
552
553    /// 2nd order spherical Bessel function of the first kind
554    fn sph_j2(&self) -> Self;
555
556    /// Fused multiply-add
557    #[inline]
558    fn mul_add(&self, a: Self, b: Self) -> Self {
559        self.clone() * a + b
560    }
561
562    /// Power with dual exponent `x^n`
563    #[inline]
564    fn powd(&self, exp: Self) -> Self {
565        (self.ln() * exp).exp()
566    }
567}
568
569/// A generalized (hyper) dual number that has a static size.
570pub trait DualNumCopy: DualNum + Copy + Send + Sync {}
571impl<T: DualNum + Copy + Send + Sync> DualNumCopy for T {}
572
573/// The underlying data type of individual derivatives. Implemented for f32 or f64.
574pub trait DualNumFloat: DualNumCopy + Float + FloatConst {
575    const THIRD: Self;
576    const HALF: Self;
577    const TWO: Self;
578    const THREE: Self;
579    const FOUR: Self;
580    const SIX: Self;
581    const TEN: Self;
582    const FIFTEEN: Self;
583}
584
585macro_rules! impl_dual_num_float {
586    ($float:ty) => {
587        impl DualNum for $float {
588            type Primitive = $float;
589
590            const NDERIV: usize = 0;
591
592            type InnerDual = $float;
593            fn from_re(re: $float) -> Self {
594                re
595            }
596
597            fn mul_add(&self, a: Self, b: Self) -> Self {
598                <$float>::mul_add(*self, a, b)
599            }
600            fn recip(&self) -> Self {
601                <$float>::recip(*self)
602            }
603            fn powi(&self, n: i32) -> Self {
604                <$float>::powi(*self, n)
605            }
606            fn powf(&self, n: Self) -> Self {
607                <$float>::powf(*self, n)
608            }
609            fn powd(&self, n: Self) -> Self {
610                <$float>::powf(*self, n)
611            }
612            fn sqrt(&self) -> Self {
613                <$float>::sqrt(*self)
614            }
615            fn exp(&self) -> Self {
616                <$float>::exp(*self)
617            }
618            fn exp2(&self) -> Self {
619                <$float>::exp2(*self)
620            }
621            fn ln(&self) -> Self {
622                <$float>::ln(*self)
623            }
624            fn log(&self, base: Self) -> Self {
625                <$float>::log(*self, base)
626            }
627            fn log2(&self) -> Self {
628                <$float>::log2(*self)
629            }
630            fn log10(&self) -> Self {
631                <$float>::log10(*self)
632            }
633            fn cbrt(&self) -> Self {
634                <$float>::cbrt(*self)
635            }
636            fn sin(&self) -> Self {
637                <$float>::sin(*self)
638            }
639            fn cos(&self) -> Self {
640                <$float>::cos(*self)
641            }
642            fn tan(&self) -> Self {
643                <$float>::tan(*self)
644            }
645            fn asin(&self) -> Self {
646                <$float>::asin(*self)
647            }
648            fn acos(&self) -> Self {
649                <$float>::acos(*self)
650            }
651            fn atan(&self) -> Self {
652                <$float>::atan(*self)
653            }
654            fn atan2(&self, other: $float) -> Self {
655                <$float>::atan2(*self, other)
656            }
657            fn sin_cos(&self) -> (Self, Self) {
658                <$float>::sin_cos(*self)
659            }
660            fn exp_m1(&self) -> Self {
661                <$float>::exp_m1(*self)
662            }
663            fn ln_1p(&self) -> Self {
664                <$float>::ln_1p(*self)
665            }
666            fn sinh(&self) -> Self {
667                <$float>::sinh(*self)
668            }
669            fn cosh(&self) -> Self {
670                <$float>::cosh(*self)
671            }
672            fn tanh(&self) -> Self {
673                <$float>::tanh(*self)
674            }
675            fn asinh(&self) -> Self {
676                <$float>::asinh(*self)
677            }
678            fn acosh(&self) -> Self {
679                <$float>::acosh(*self)
680            }
681            fn atanh(&self) -> Self {
682                <$float>::atanh(*self)
683            }
684            fn sph_j0(&self) -> Self {
685                if self.abs() < <$float>::EPSILON {
686                    1.0 - self * self / 6.0
687                } else {
688                    self.sin() / self
689                }
690            }
691            fn sph_j1(&self) -> Self {
692                if self.abs() < <$float>::EPSILON {
693                    self / 3.0
694                } else {
695                    let sc = self.sin_cos();
696                    let rec = self.recip();
697                    (sc.0 * rec - sc.1) * rec
698                }
699            }
700            fn sph_j2(&self) -> Self {
701                if self.abs() < <$float>::EPSILON {
702                    self * self / 15.0
703                } else {
704                    let sc = self.sin_cos();
705                    let s2 = self * self;
706                    ((3.0 - s2) * sc.0 - 3.0 * self * sc.1) / (self * s2)
707                }
708            }
709        }
710
711        impl DualNumFloat for $float {
712            const THIRD: Self = 1.0 / 3.0;
713            const HALF: Self = 0.5;
714            const TWO: Self = 2.0;
715            const THREE: Self = 3.0;
716            const FOUR: Self = 4.0;
717            const SIX: Self = 6.0;
718            const TEN: Self = 10.0;
719            const FIFTEEN: Self = 15.0;
720        }
721    };
722}
723
724impl_dual_num_float!(f32);
725impl_dual_num_float!(f64);
726
727/// A struct that contains dual numbers. Needed for arbitrary arguments in [ImplicitFunction].
728///
729/// The trait is implemented for all dual types themselves, and common data types (tuple, vec,
730/// array, ...) and can be implemented for custom data types to achieve full flexibility.
731pub trait DualStruct {
732    type Real;
733    type Inner: DualStruct;
734    fn re(&self) -> Self::Real;
735    fn from_inner(inner: &Self::Inner) -> Self;
736}
737
738/// Trait for structs used as an output of functions for which derivatives are calculated.
739///
740/// The main intention is to generalize the calculation of derivatives to fallible functions, but
741/// other use cases might also appear in the future.
742pub trait Mappable<D> {
743    type Output<O>;
744    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O>;
745}
746
747impl DualStruct for () {
748    type Real = ();
749    type Inner = ();
750    fn re(&self) {}
751    fn from_inner(_: &Self::Inner) -> Self {}
752}
753
754impl<D> Mappable<D> for () {
755    type Output<O> = ();
756    fn map_dual<M: FnOnce(D) -> O, O>(self, _: M) {}
757}
758
759impl DualStruct for f32 {
760    type Real = f32;
761    type Inner = f32;
762    fn re(&self) -> f32 {
763        *self
764    }
765    fn from_inner(inner: &Self::Inner) -> Self {
766        *inner
767    }
768}
769
770impl Mappable<f32> for f32 {
771    type Output<O> = O;
772    fn map_dual<M: FnOnce(f32) -> O, O>(self, f: M) -> Self::Output<O> {
773        f(self)
774    }
775}
776
777impl DualStruct for f64 {
778    type Real = f64;
779    type Inner = f64;
780    fn re(&self) -> f64 {
781        *self
782    }
783    fn from_inner(inner: &Self::Inner) -> Self {
784        *inner
785    }
786}
787
788impl Mappable<f64> for f64 {
789    type Output<O> = O;
790    fn map_dual<M: FnOnce(f64) -> O, O>(self, f: M) -> Self::Output<O> {
791        f(self)
792    }
793}
794
795impl<T1: DualStruct, T2: DualStruct> DualStruct for (T1, T2) {
796    type Real = (T1::Real, T2::Real);
797    type Inner = (T1::Inner, T2::Inner);
798    fn re(&self) -> Self::Real {
799        let (s1, s2) = self;
800        (s1.re(), s2.re())
801    }
802    fn from_inner(re: &Self::Inner) -> Self {
803        let (r1, r2) = re;
804        (T1::from_inner(r1), T2::from_inner(r2))
805    }
806}
807
808impl<D, T1: Mappable<D>, T2: Mappable<D>> Mappable<D> for (T1, T2) {
809    type Output<O> = (T1::Output<O>, T2::Output<O>);
810    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O> {
811        let (s1, s2) = self;
812        (s1.map_dual(&f), s2.map_dual(&f))
813    }
814}
815
816impl<T1: DualStruct, T2: DualStruct, T3: DualStruct> DualStruct for (T1, T2, T3) {
817    type Real = (T1::Real, T2::Real, T3::Real);
818    type Inner = (T1::Inner, T2::Inner, T3::Inner);
819    fn re(&self) -> Self::Real {
820        let (s1, s2, s3) = self;
821        (s1.re(), s2.re(), s3.re())
822    }
823    fn from_inner(inner: &Self::Inner) -> Self {
824        let (r1, r2, r3) = inner;
825        (T1::from_inner(r1), T2::from_inner(r2), T3::from_inner(r3))
826    }
827}
828
829impl<D, T1: Mappable<D>, T2: Mappable<D>, T3: Mappable<D>> Mappable<D> for (T1, T2, T3) {
830    type Output<O> = (T1::Output<O>, T2::Output<O>, T3::Output<O>);
831    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O> {
832        let (s1, s2, s3) = self;
833        (s1.map_dual(&f), s2.map_dual(&f), s3.map_dual(&f))
834    }
835}
836
837impl<T1: DualStruct, T2: DualStruct, T3: DualStruct, T4: DualStruct> DualStruct
838    for (T1, T2, T3, T4)
839{
840    type Real = (T1::Real, T2::Real, T3::Real, T4::Real);
841    type Inner = (T1::Inner, T2::Inner, T3::Inner, T4::Inner);
842    fn re(&self) -> Self::Real {
843        let (s1, s2, s3, s4) = self;
844        (s1.re(), s2.re(), s3.re(), s4.re())
845    }
846    fn from_inner(inner: &Self::Inner) -> Self {
847        let (r1, r2, r3, r4) = inner;
848        (
849            T1::from_inner(r1),
850            T2::from_inner(r2),
851            T3::from_inner(r3),
852            T4::from_inner(r4),
853        )
854    }
855}
856
857impl<D, T1: Mappable<D>, T2: Mappable<D>, T3: Mappable<D>, T4: Mappable<D>> Mappable<D>
858    for (T1, T2, T3, T4)
859{
860    type Output<O> = (T1::Output<O>, T2::Output<O>, T3::Output<O>, T4::Output<O>);
861    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O> {
862        let (s1, s2, s3, s4) = self;
863        (
864            s1.map_dual(&f),
865            s2.map_dual(&f),
866            s3.map_dual(&f),
867            s4.map_dual(&f),
868        )
869    }
870}
871
872impl<T1: DualStruct, T2: DualStruct, T3: DualStruct, T4: DualStruct, T5: DualStruct> DualStruct
873    for (T1, T2, T3, T4, T5)
874{
875    type Real = (T1::Real, T2::Real, T3::Real, T4::Real, T5::Real);
876    type Inner = (T1::Inner, T2::Inner, T3::Inner, T4::Inner, T5::Inner);
877    fn re(&self) -> Self::Real {
878        let (s1, s2, s3, s4, s5) = self;
879        (s1.re(), s2.re(), s3.re(), s4.re(), s5.re())
880    }
881    fn from_inner(inner: &Self::Inner) -> Self {
882        let (r1, r2, r3, r4, r5) = inner;
883        (
884            T1::from_inner(r1),
885            T2::from_inner(r2),
886            T3::from_inner(r3),
887            T4::from_inner(r4),
888            T5::from_inner(r5),
889        )
890    }
891}
892
893impl<D, T1: Mappable<D>, T2: Mappable<D>, T3: Mappable<D>, T4: Mappable<D>, T5: Mappable<D>>
894    Mappable<D> for (T1, T2, T3, T4, T5)
895{
896    type Output<O> = (
897        T1::Output<O>,
898        T2::Output<O>,
899        T3::Output<O>,
900        T4::Output<O>,
901        T5::Output<O>,
902    );
903    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O> {
904        let (s1, s2, s3, s4, s5) = self;
905        (
906            s1.map_dual(&f),
907            s2.map_dual(&f),
908            s3.map_dual(&f),
909            s4.map_dual(&f),
910            s5.map_dual(&f),
911        )
912    }
913}
914
915impl<T: DualStruct, const N: usize> DualStruct for [T; N] {
916    type Real = [T::Real; N];
917    type Inner = [T::Inner; N];
918    fn re(&self) -> Self::Real {
919        self.each_ref().map(|x| x.re())
920    }
921    fn from_inner(re: &Self::Inner) -> Self {
922        re.each_ref().map(T::from_inner)
923    }
924}
925
926impl<D, T: Mappable<D>, const N: usize> Mappable<D> for [T; N] {
927    type Output<O> = [T::Output<O>; N];
928    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O> {
929        self.map(|x| x.map_dual(&f))
930    }
931}
932
933impl<T: DualStruct> DualStruct for Option<T> {
934    type Real = Option<T::Real>;
935    type Inner = Option<T::Inner>;
936    fn re(&self) -> Self::Real {
937        self.as_ref().map(|x| x.re())
938    }
939    fn from_inner(inner: &Self::Inner) -> Self {
940        inner.as_ref().map(|x| T::from_inner(x))
941    }
942}
943
944impl<D, T: Mappable<D>> Mappable<D> for Option<T> {
945    type Output<O> = Option<T::Output<O>>;
946    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O> {
947        self.map(|x| x.map_dual(f))
948    }
949}
950
951impl<D, T: Mappable<D>, E> Mappable<D> for Result<T, E> {
952    type Output<O> = Result<T::Output<O>, E>;
953    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O> {
954        self.map(|x| x.map_dual(f))
955    }
956}
957
958impl<T: DualStruct> DualStruct for Vec<T> {
959    type Real = Vec<T::Real>;
960    type Inner = Vec<T::Inner>;
961    fn re(&self) -> Self::Real {
962        self.iter().map(|x| x.re()).collect()
963    }
964    fn from_inner(inner: &Self::Inner) -> Self {
965        inner.iter().map(|x| T::from_inner(x)).collect()
966    }
967}
968
969impl<D, T: Mappable<D>> Mappable<D> for Vec<T> {
970    type Output<O> = Vec<T::Output<O>>;
971    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O> {
972        self.into_iter().map(|x| x.map_dual(&f)).collect()
973    }
974}
975
976impl<T: DualStruct, K: Clone + Eq + Hash> DualStruct for HashMap<K, T> {
977    type Real = HashMap<K, T::Real>;
978    type Inner = HashMap<K, T::Inner>;
979    fn re(&self) -> Self::Real {
980        self.iter().map(|(k, x)| (k.clone(), x.re())).collect()
981    }
982    fn from_inner(inner: &Self::Inner) -> Self {
983        inner
984            .iter()
985            .map(|(k, x)| (k.clone(), T::from_inner(x)))
986            .collect()
987    }
988}
989
990impl<D, T: Mappable<D>, K: Eq + Hash> Mappable<D> for HashMap<K, T> {
991    type Output<O> = HashMap<K, T::Output<O>>;
992    fn map_dual<M: Fn(D) -> O, O>(self, f: M) -> Self::Output<O> {
993        self.into_iter().map(|(k, x)| (k, x.map_dual(&f))).collect()
994    }
995}
996
997#[cfg(feature = "nalgebra")]
998impl<D: DualNum, R: Dim, C: Dim> DualStruct for OMatrix<D, R, C>
999where
1000    DefaultAllocator: Allocator<R, C>,
1001{
1002    type Real = OMatrix<D::Real, R, C>;
1003    type Inner = OMatrix<D::InnerDual, R, C>;
1004    fn re(&self) -> Self::Real {
1005        self.map(|x| x.re())
1006    }
1007    fn from_inner(inner: &Self::Inner) -> Self {
1008        inner.map(|x| DualNum::from_re(x))
1009    }
1010}
1011
1012#[cfg(feature = "nalgebra")]
1013impl<D: Scalar, R: Dim, C: Dim> Mappable<Self> for OMatrix<D, R, C>
1014where
1015    DefaultAllocator: Allocator<R, C>,
1016{
1017    type Output<O> = O;
1018    fn map_dual<M: Fn(Self) -> O, O>(self, f: M) -> O {
1019        f(self)
1020    }
1021}