Expand description
In-crate forward-mode automatic differentiation (AD) substrate.
This module provides the numeric substrate for forward-mode automatic
differentiation used by the differentiable FDA subset. It defines a
Scalar trait bounding the arithmetic and transcendental operations a
differentiable computation needs, a forward-mode Dual number carrying a
value (primal) and a tangent (directional derivative), and a
zero-cost Scalar implementation for f64.
§Design invariants
- No external dependency. The
Scalartrait is defined entirely in-crate. Thenum-traitscrate is a transitive-only dependency offdars-coreand cannot beused without aCargo.tomlchange, which would violate the no-new-dependency constraint. This module therefore never imports it. - Additive / non-breaking.
Scalaris implemented forf64as a zero-cost passthrough to the inherentf64methods, so generic code instantiated atf64is numerically identical to plainf64code. - Value-only ordering for
Dual.Dual’sPartialOrdcompares thevalue(primal) field ONLY. This is the correct forward-mode branching semantics: control-flow decisions are made on the primal while tangents propagate through the selected branch. DerivingPartialOrdwould use the tangent as a lexicographic tiebreaker and corrupt those semantics.
§Forward-mode in one line
Seed an input’s tangent to 1.0 (via Dual::seed), run a computation
written against Scalar, and extract the
(value, derivative) pair. The diff helper wraps this pattern.
use fdars_core::autodiff::{diff, Dual, Scalar};
// f(x) = x^2, f'(x) = 2x. At x = 3: f = 9, f' = 6.
let (value, deriv) = diff(|x| x * x, 3.0);
assert!((value - 9.0).abs() < 1e-12);
assert!((deriv - 6.0).abs() < 1e-12);§Composing differentiable ops
grad flows a gradient through a composition of the crate’s
Scalar-generic differentiable ops. Here one scalar objective composes a
soft-DTW distance and an FPCA-score projection, then grad returns the
objective value and its full gradient w.r.t. the input curve’s samples.
use fdars_core::prelude::*;
use fdars_core::regression::fdata_to_pc;
// Small trained FPCA model (mirrors regression::fdata_to_pc usage).
let m = 10usize;
let n = 12usize;
let argvals: Vec<f64> = (0..m).map(|j| 0.1 + 0.8 * j as f64 / (m - 1) as f64).collect();
let mut raw = vec![0.0f64; n * m];
for i in 0..n {
for (j, &t) in argvals.iter().enumerate() {
let phase = i as f64 * 0.3;
raw[i + j * n] = (std::f64::consts::PI * t + phase).sin()
+ 0.5 * (2.0 * std::f64::consts::PI * t).cos();
}
}
let data = FdMatrix::from_column_major(raw, n, m).unwrap();
let fpca = fdata_to_pc(&data, 2, &argvals).unwrap();
// Objective: soft-DTW(curve, reference) + sum of squared FPCA scores.
let reference: Vec<Dual> = argvals
.iter()
.map(|&t| Dual::constant((std::f64::consts::PI * t).sin()))
.collect();
let curve: Vec<f64> = argvals
.iter()
.map(|&t| (std::f64::consts::PI * t).cos())
.collect();
let objective = |c: &[Dual]| -> Dual {
let sdtw = soft_dtw_distance_generic(c, &reference, 0.1);
let scores = project_scores_generic(c, &fpca.mean, &fpca.rotation, &fpca.weights, 2);
let mut acc = Dual::constant(0.0);
for s in &scores {
acc += *s * *s;
}
sdtw + acc
};
let (value, gradient) = grad(objective, &curve);
assert_eq!(gradient.len(), m);
assert!(value.is_finite());Structs§
- Dual
- A forward-mode dual number: a value (primal) paired with a tangent (directional derivative).
Traits§
- Scalar
- Numeric substrate for forward-mode automatic differentiation.
Functions§
- diff
- Compute
f(x)andf'(x)in one forward-mode pass. - directional_
derivative - Compute a scalar objective’s value and its directional derivative along a
supplied
direction, in a SINGLE forward-mode pass. - grad
- Compute a scalar objective’s value and its full gradient over an
m-vector input, inmforward-mode passes (one per input). - jacobian
- Compute a vector-valued map’s values and its full Jacobian over an
m-vector input, inmforward-mode passes (one per input).