pub trait RealPrimalMath: RealPrimalMathWithPolicy {
// Provided methods
fn spherical_harmonics_d<const L: usize, const N: usize, const CS: bool>(
x: Self,
y: Self,
z: Self,
out: &mut [Self; N],
ddx: &mut [Self; N],
ddy: &mut [Self; N],
ddz: &mut [Self; N],
) { ... }
fn zernike_basis_d<const L: usize, const NORM: u8, const N: usize>(
x: Self,
y: Self,
out: &mut [Self; N],
ddx: &mut [Self; N],
ddy: &mut [Self; N],
) { ... }
fn spherical_harmonics_d_with<const L: usize, const N: usize>(
table: &ShTable<Self, N>,
x: Self,
y: Self,
z: Self,
out: &mut [Self; N],
ddx: &mut [Self; N],
ddy: &mut [Self; N],
ddz: &mut [Self; N],
) { ... }
fn softplus_d(self, k: Self, rcp_k: Self) -> (Self, Self) { ... }
fn gelu_d(self, alpha: Self) -> (Self, Self) { ... }
fn swish_d(self, beta: Self) -> (Self, Self) { ... }
fn algebraic_sigmoid_d_n<const N: usize>(self) -> (Self, Self) { ... }
fn algebraic_sigmoid_d(self, n: u32) -> (Self, Self) { ... }
fn algebraic_swish_d(self) -> (Self, Self) { ... }
fn langevin_d(self) -> (Self, Self) { ... }
}Expand description
RealPrimal math functions for floating-point vectors using the default policy.
The same operations as RealPrimalMathWithPolicy, with every method’s leading policy
fixed to DefaultPolicy. Implementors of RealPrimalMathWithPolicy automatically
implement this trait; each method here has a _p-suffixed counterpart there.
“Primal” special functions: the value-and-derivative (_d) forms of the activation
functions, returning (value, derivative) together.
These exist for single-value real numbers (f32, f64, Compensated, …) where the
analytic derivative is a useful, cheaply-shared byproduct of the value. They are not
implemented for derivative-carrying numbers such as Dual: an automatic-differentiation
type already produces the derivative from the plain value form (e.g. gelu),
so the bundled _d derivative would be redundant work at the wrong level of abstraction.
Each *_d method mirrors the like-named value-only function in SpecialMath /
RealSpecialMath, returning that same value as the first tuple element.
Provided Methods§
Sourcefn spherical_harmonics_d<const L: usize, const N: usize, const CS: bool>(
x: Self,
y: Self,
z: Self,
out: &mut [Self; N],
ddx: &mut [Self; N],
ddy: &mut [Self; N],
ddz: &mut [Self; N],
)
fn spherical_harmonics_d<const L: usize, const N: usize, const CS: bool>( x: Self, y: Self, z: Self, out: &mut [Self; N], ddx: &mut [Self; N], ddy: &mut [Self; N], ddz: &mut [Self; N], )
spherical_harmonics plus the
ambient Cartesian gradient of every harmonic, into ddx/ddy/ddz.
Lives on RealPrimalMath rather than RealSpecialMath, so Dual does
not get it, and should not want it. If you need $\partial/\partial(x,y,z)$,
call this directly rather than evaluating
spherical_harmonics on a
Dual<V, 3> seeded with an identity Jacobian: this shares the recurrence
between the value and all three gradients, whereas dual arithmetic carries a
derivative through every operation and costs roughly twice as much.
Dual earns its keep on the value form instead, where (x, y, z) are
themselves functions of upstream parameters and the chain rule has real work
to do. Even there, going the other way (contracting these three gradients
against an upstream Jacobian) loses: spherical harmonics cost about two
operations per harmonic to evaluate but three per harmonic per parameter to
contract, because one recurrence produces the whole basis.
The derivatives are those of the polynomial form at the given (unit)
input. Project out the radial component (g - (g . n) n) for the
tangential gradient. Shares all recurrence work with the value pass, since
the gradients come from tabulated norm ratios, not new recurrences.
Sourcefn zernike_basis_d<const L: usize, const NORM: u8, const N: usize>(
x: Self,
y: Self,
out: &mut [Self; N],
ddx: &mut [Self; N],
ddy: &mut [Self; N],
)
fn zernike_basis_d<const L: usize, const NORM: u8, const N: usize>( x: Self, y: Self, out: &mut [Self; N], ddx: &mut [Self; N], ddy: &mut [Self; N], )
zernike_basis plus $\partial Z_n^m/\partial x$
and $\partial Z_n^m/\partial y$ for every mode, in the same ANSI layout.
This is what a Shack-Hartmann wavefront reconstruction integrates against. The sensor measures local wavefront slopes, not the wavefront itself, so the fit matrix is built from the gradient basis and the value basis never appears in it.
Lives on RealPrimalMath rather than SpecialMath for the same reason
spherical_harmonics_d does: Dual
should not get it and should not want it. Seeding a Dual<V, 2> and calling the
value form carries two derivative components through every operation of the whole
ladder, where this differentiates only the two factors that depend on the point
and shares the radial recurrence between the value and both gradients.
The gradient is finite everywhere, including the pupil centre. That is the
practical dividend of the Cartesian formulation: the polar
$\partial_\theta Z/\rho$ is singular there, and hand-rolled polar
implementations guard the origin with a special case.
N must equal (L+1)(L+2)/2, and NORM is as on
zernike_basis. All three output buffers are
written in full.
Sourcefn spherical_harmonics_d_with<const L: usize, const N: usize>(
table: &ShTable<Self, N>,
x: Self,
y: Self,
z: Self,
out: &mut [Self; N],
ddx: &mut [Self; N],
ddy: &mut [Self; N],
ddz: &mut [Self; N],
)
fn spherical_harmonics_d_with<const L: usize, const N: usize>( table: &ShTable<Self, N>, x: Self, y: Self, z: Self, out: &mut [Self; N], ddx: &mut [Self; N], ddy: &mut [Self; N], ddz: &mut [Self; N], )
spherical_harmonics_with plus
the ambient Cartesian gradients, from a prebuilt table.
Sourcefn softplus_d(self, k: Self, rcp_k: Self) -> (Self, Self)
fn softplus_d(self, k: Self, rcp_k: Self) -> (Self, Self)
softplus together with its derivative w.r.t. x
(the logistic sigmoid $\sigma(kx)$).
Sourcefn algebraic_sigmoid_d_n<const N: usize>(self) -> (Self, Self)
fn algebraic_sigmoid_d_n<const N: usize>(self) -> (Self, Self)
algebraic_sigmoid together with its derivative w.r.t. x.
Sourcefn algebraic_sigmoid_d(self, n: u32) -> (Self, Self)
fn algebraic_sigmoid_d(self, n: u32) -> (Self, Self)
algebraic_sigmoid_d_n for a degree known
only at runtime.
Sourcefn algebraic_swish_d(self) -> (Self, Self)
fn algebraic_swish_d(self) -> (Self, Self)
algebraic_swish together with its derivative w.r.t. x.
Sourcefn langevin_d(self) -> (Self, Self)
fn langevin_d(self) -> (Self, Self)
langevin together with its derivative
$L'(x) = \frac{1}{x^2} - \operatorname{csch}^2 x$.
The derivative shares every intermediate with the value, so this costs a
handful of arithmetic ops over langevin alone.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".