Skip to main content

RealPrimalMath

Trait RealPrimalMath 

Source
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§

Source

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.

Source

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.

Source

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.

Source

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)$).

Source

fn gelu_d(self, alpha: Self) -> (Self, Self)

gelu together with its derivative w.r.t. x.

Source

fn swish_d(self, beta: Self) -> (Self, Self)

swish together with its derivative w.r.t. x.

Source

fn algebraic_sigmoid_d_n<const N: usize>(self) -> (Self, Self)

algebraic_sigmoid together with its derivative w.r.t. x.

Source

fn algebraic_sigmoid_d(self, n: u32) -> (Self, Self)

algebraic_sigmoid_d_n for a degree known only at runtime.

Source

fn algebraic_swish_d(self) -> (Self, Self)

algebraic_swish together with its derivative w.r.t. x.

Source

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".

Implementors§

Last built: 2026-09-08 21:35:55 UTC