pub trait RealPrimalMathWithPolicy: RealSpecialMathWithPolicy + PrimalMathWithPolicy {
// Required methods
fn spherical_harmonics_d_p<P: Policy, 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_p<P: Policy, 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_p<P: Policy, 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_p<P: Policy>(self, k: Self, rcp_k: Self) -> (Self, Self);
fn gelu_d_p<P: Policy>(self, alpha: Self) -> (Self, Self);
fn swish_d_p<P: Policy>(self, beta: Self) -> (Self, Self);
fn algebraic_sigmoid_d_n_p<P: Policy, const N: usize>(self) -> (Self, Self);
fn algebraic_sigmoid_d_p<P: Policy>(self, n: u32) -> (Self, Self);
fn algebraic_swish_d_p<P: Policy>(self) -> (Self, Self);
fn langevin_d_p<P: Policy>(self) -> (Self, Self);
}Expand description
RealPrimal math functions for floating-point vectors with customizable policies.
Each function carries a leading P: Policy generic controlling the
precision/performance trade-off. For convenience, RealPrimalMath provides the same
set of operations under DefaultPolicy. Every floating-point vector type
implementing specialized::SpecializedRealPrimalMath implements both
automatically.
“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.
Required Methods§
Sourcefn spherical_harmonics_d_p<P: Policy, 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_p<P: Policy, 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_p<P: Policy, 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_p<P: Policy, 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_p<P: Policy, 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_p<P: Policy, 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_p<P: Policy>(self, k: Self, rcp_k: Self) -> (Self, Self)
fn softplus_d_p<P: Policy>(self, k: Self, rcp_k: Self) -> (Self, Self)
softplus together with its derivative w.r.t. x
(the logistic sigmoid $\sigma(kx)$).
Sourcefn gelu_d_p<P: Policy>(self, alpha: Self) -> (Self, Self)
fn gelu_d_p<P: Policy>(self, alpha: Self) -> (Self, Self)
gelu together with its derivative w.r.t. x.
Sourcefn swish_d_p<P: Policy>(self, beta: Self) -> (Self, Self)
fn swish_d_p<P: Policy>(self, beta: Self) -> (Self, Self)
swish together with its derivative w.r.t. x.
Sourcefn algebraic_sigmoid_d_n_p<P: Policy, const N: usize>(self) -> (Self, Self)
fn algebraic_sigmoid_d_n_p<P: Policy, const N: usize>(self) -> (Self, Self)
algebraic_sigmoid together with its derivative w.r.t. x.
Sourcefn algebraic_sigmoid_d_p<P: Policy>(self, n: u32) -> (Self, Self)
fn algebraic_sigmoid_d_p<P: Policy>(self, n: u32) -> (Self, Self)
algebraic_sigmoid_d_n for a degree known
only at runtime.
Sourcefn algebraic_swish_d_p<P: Policy>(self) -> (Self, Self)
fn algebraic_swish_d_p<P: Policy>(self) -> (Self, Self)
algebraic_swish together with its derivative w.r.t. x.
Sourcefn langevin_d_p<P: Policy>(self) -> (Self, Self)
fn langevin_d_p<P: Policy>(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".