pub struct MultiDual<T, const N: usize> {
pub value: T,
pub derivs: [T; N],
}Expand description
A multi-component dual number representing a value and N partial derivatives.
MultiDual<T, N> represents a value along with its gradient
[∂f/∂x₁, …, ∂f/∂xₙ] for forward-mode automatic differentiation
of multivariable functions.
§Type Parameters
T: The numeric type (typicallyf64orf32)N: The number of input variables (compile-time constant)
§Examples
§Creating Variables
use autodiff::MultiDual;
// Create the first variable x with value 3.0 (∂/∂x = 1, ∂/∂y = 0)
let x = MultiDual::<f64, 2>::variable(3.0, 0);
assert_eq!(x.value, 3.0);
assert_eq!(x.derivs, [1.0, 0.0]);
// Create the second variable y with value 4.0 (∂/∂x = 0, ∂/∂y = 1)
let y = MultiDual::<f64, 2>::variable(4.0, 1);
assert_eq!(y.value, 4.0);
assert_eq!(y.derivs, [0.0, 1.0]);
// Create a constant (∂/∂x = 0, ∂/∂y = 0)
let c = MultiDual::<f64, 2>::constant(2.0);
assert_eq!(c.value, 2.0);
assert_eq!(c.derivs, [0.0, 0.0]);§Computing Gradients
use autodiff::MultiDual;
// f(x, y) = x² + y²
let x = MultiDual::<f64, 2>::variable(3.0, 0);
let y = MultiDual::<f64, 2>::variable(4.0, 1);
let f = x * x + y * y;
assert_eq!(f.value, 25.0); // 3² + 4² = 25
assert_eq!(f.derivs[0], 6.0); // ∂f/∂x = 2x = 6
assert_eq!(f.derivs[1], 8.0); // ∂f/∂y = 2y = 8Fields§
§value: TThe primal value (function output)
derivs: [T; N]The partial derivatives [∂f/∂x₁, ∂f/∂x₂, …, ∂f/∂xₙ]
Implementations§
Source§impl<T, const N: usize> MultiDual<T, N>where
T: Copy,
impl<T, const N: usize> MultiDual<T, N>where
T: Copy,
Sourcepub fn new(value: T, derivs: [T; N]) -> Self
pub fn new(value: T, derivs: [T; N]) -> Self
Create a dual number with explicit value and derivatives.
§Examples
use autodiff::MultiDual;
let d = MultiDual::new(5.0, [1.0, 2.0, 3.0]);
assert_eq!(d.value, 5.0);
assert_eq!(d.derivs, [1.0, 2.0, 3.0]);Sourcepub fn constant(value: T) -> Selfwhere
T: Zero,
pub fn constant(value: T) -> Selfwhere
T: Zero,
Create a constant (all partial derivatives are zero).
§Examples
use autodiff::MultiDual;
let c = MultiDual::<f64, 3>::constant(42.0);
assert_eq!(c.value, 42.0);
assert_eq!(c.derivs, [0.0, 0.0, 0.0]);Sourcepub fn variable(value: T, index: usize) -> Self
pub fn variable(value: T, index: usize) -> Self
Create the i-th input variable.
Sets derivs[index] = 1 and all other derivatives to zero,
representing ∂xᵢ/∂xⱼ = δᵢⱼ (Kronecker delta).
§Panics
Panics if index >= N.
§Examples
use autodiff::MultiDual;
// Create x (first variable)
let x = MultiDual::<f64, 2>::variable(3.0, 0);
assert_eq!(x.value, 3.0);
assert_eq!(x.derivs, [1.0, 0.0]);
// Create y (second variable)
let y = MultiDual::<f64, 2>::variable(4.0, 1);
assert_eq!(y.value, 4.0);
assert_eq!(y.derivs, [0.0, 1.0]);Source§impl<T, const N: usize> MultiDual<T, N>where
T: Float,
impl<T, const N: usize> MultiDual<T, N>where
T: Float,
Sourcepub fn recip(self) -> Self
pub fn recip(self) -> Self
Reciprocal: 1/(b + ∇b) = (1/b) + (-∇b/b²)
Implements the rule: (1/g)′ = -g′/g² (note: g ≠ 0)
§Examples
use autodiff::MultiDual;
// f(x, y) = 1/x at (2, 3)
let x = MultiDual::<f64, 2>::variable(2.0, 0);
let recip_x = x.recip();
assert_eq!(recip_x.value, 0.5); // 1/2
assert!((recip_x.derivs[0] + 0.25).abs() < 1e-10); // -1/4
assert_eq!(recip_x.derivs[1], 0.0); // ∂(1/x)/∂y = 0Sourcepub fn exp(self) -> Self
pub fn exp(self) -> Self
Exponential function: exp(a + ∇a) = exp(a) + (exp(a) · ∇a)
Implements the chain rule: ∂/∂xᵢ(exp(f)) = exp(f) · ∂f/∂xᵢ
§Examples
use autodiff::MultiDual;
// f(x, y) = exp(x) at (0, 1)
let x = MultiDual::<f64, 2>::variable(0.0, 0);
let f = x.exp();
assert_eq!(f.value, 1.0); // exp(0) = 1
assert_eq!(f.derivs[0], 1.0); // ∂exp(x)/∂x at x=0 is exp(0) = 1
assert_eq!(f.derivs[1], 0.0); // ∂exp(x)/∂y = 0Sourcepub fn ln(self) -> Self
pub fn ln(self) -> Self
Natural logarithm: ln(a + ∇a) = ln(a) + (∇a / a)
Implements the chain rule: ∂/∂xᵢ(ln(f)) = (∂f/∂xᵢ) / f
§Examples
use autodiff::MultiDual;
// f(x, y) = ln(x) at (1, 2)
let x = MultiDual::<f64, 2>::variable(1.0, 0);
let f = x.ln();
assert!((f.value - 0.0_f64).abs() < 1e-12); // ln(1) = 0
assert!((f.derivs[0] - 1.0_f64).abs() < 1e-12); // ∂ln(x)/∂x at x=1 is 1/1 = 1
assert_eq!(f.derivs[1], 0.0); // ∂ln(x)/∂y = 0Sourcepub fn sin(self) -> Self
pub fn sin(self) -> Self
Sine function: sin(a + ∇a) = sin(a) + (cos(a) · ∇a)
Implements the chain rule: ∂/∂xᵢ(sin(f)) = cos(f) · ∂f/∂xᵢ
§Examples
use autodiff::MultiDual;
// f(x, y) = sin(x) at (0, 1)
let x = MultiDual::<f64, 2>::variable(0.0, 0);
let f = x.sin();
assert!((f.value - 0.0_f64).abs() < 1e-12); // sin(0) = 0
assert!((f.derivs[0] - 1.0_f64).abs() < 1e-12); // ∂sin(x)/∂x at x=0 is cos(0) = 1
assert_eq!(f.derivs[1], 0.0); // ∂sin(x)/∂y = 0Sourcepub fn cos(self) -> Self
pub fn cos(self) -> Self
Cosine function: cos(a + ∇a) = cos(a) + (-sin(a) · ∇a)
Implements the chain rule: ∂/∂xᵢ(cos(f)) = -sin(f) · ∂f/∂xᵢ
§Examples
use autodiff::MultiDual;
// f(x, y) = cos(x) at (0, 1)
let x = MultiDual::<f64, 2>::variable(0.0, 0);
let f = x.cos();
assert!((f.value - 1.0_f64).abs() < 1e-12); // cos(0) = 1
assert!((f.derivs[0] - 0.0_f64).abs() < 1e-12); // ∂cos(x)/∂x at x=0 is -sin(0) = 0
assert_eq!(f.derivs[1], 0.0); // ∂cos(x)/∂y = 0Sourcepub fn sqrt(self) -> Self
pub fn sqrt(self) -> Self
Square root: sqrt(a + ∇a) = sqrt(a) + (∇a / (2·sqrt(a)))
Implements the chain rule: ∂/∂xᵢ(√f) = (∂f/∂xᵢ) / (2√f)
§Examples
use autodiff::MultiDual;
// f(x, y) = √x at (4, 1)
let x = MultiDual::<f64, 2>::variable(4.0, 0);
let f = x.sqrt();
assert_eq!(f.value, 2.0); // √4 = 2
assert_eq!(f.derivs[0], 0.25); // ∂√x/∂x at x=4 is 1/(2·2) = 0.25
assert_eq!(f.derivs[1], 0.0); // ∂√x/∂y = 0Trait Implementations§
Source§impl<T, const N: usize> Add for MultiDual<T, N>
Addition: (a + ∇a) + (b + ∇b) = (a+b) + (∇a+∇b)
impl<T, const N: usize> Add for MultiDual<T, N>
Addition: (a + ∇a) + (b + ∇b) = (a+b) + (∇a+∇b)
§Examples
use autodiff::MultiDual;
let x = MultiDual::new(3.0, [1.0, 0.0]);
let y = MultiDual::new(4.0, [0.0, 1.0]);
let sum = x + y;
assert_eq!(sum.value, 7.0);
assert_eq!(sum.derivs, [1.0, 1.0]);Source§impl<T, const N: usize> Div for MultiDual<T, N>where
T: Float,
Division: (a + ∇a) / (b + ∇b) = (a + ∇a) * (1/(b + ∇b))
impl<T, const N: usize> Div for MultiDual<T, N>where
T: Float,
Division: (a + ∇a) / (b + ∇b) = (a + ∇a) * (1/(b + ∇b))
Implements division via reciprocal (composition of operations).
§Examples
use autodiff::MultiDual;
// f(x, y) = x / y at (6, 2)
let x = MultiDual::<f64, 2>::variable(6.0, 0);
let y = MultiDual::<f64, 2>::variable(2.0, 1);
let quotient = x / y;
assert_eq!(quotient.value, 3.0); // 6/2
assert_eq!(quotient.derivs[0], 0.5); // ∂(x/y)/∂x = 1/y = 0.5
assert_eq!(quotient.derivs[1], -1.5); // ∂(x/y)/∂y = -x/y² = -1.5Source§impl<T, const N: usize> Mul for MultiDual<T, N>
Multiplication: (a + ∇a) * (b + ∇b) = ab + (b∇a + a∇b)
impl<T, const N: usize> Mul for MultiDual<T, N>
Multiplication: (a + ∇a) * (b + ∇b) = ab + (b∇a + a∇b)
This implements the product rule automatically.
§Examples
use autodiff::MultiDual;
// f(x, y) = x * y at (3, 4)
let x = MultiDual::<f64, 2>::variable(3.0, 0);
let y = MultiDual::<f64, 2>::variable(4.0, 1);
let product = x * y;
assert_eq!(product.value, 12.0); // 3 * 4
assert_eq!(product.derivs[0], 4.0); // ∂(xy)/∂x = y = 4
assert_eq!(product.derivs[1], 3.0); // ∂(xy)/∂y = x = 3Source§impl<T, const N: usize> Neg for MultiDual<T, N>
Negation: -(a + ∇a) = -a + (-∇a)
impl<T, const N: usize> Neg for MultiDual<T, N>
Negation: -(a + ∇a) = -a + (-∇a)
§Examples
use autodiff::MultiDual;
let x = MultiDual::new(3.0, [1.0, 2.0]);
let neg_x = -x;
assert_eq!(neg_x.value, -3.0);
assert_eq!(neg_x.derivs, [-1.0, -2.0]);Source§impl<T, const N: usize> Sub for MultiDual<T, N>
Subtraction: (a + ∇a) - (b + ∇b) = (a-b) + (∇a-∇b)
impl<T, const N: usize> Sub for MultiDual<T, N>
Subtraction: (a + ∇a) - (b + ∇b) = (a-b) + (∇a-∇b)
§Examples
use autodiff::MultiDual;
let x = MultiDual::new(7.0, [2.0, 3.0]);
let y = MultiDual::new(4.0, [1.0, 2.0]);
let diff = x - y;
assert_eq!(diff.value, 3.0);
assert_eq!(diff.derivs, [1.0, 1.0]);