viva_math/scalar

Scalar mathematical functions.

This module provides pipeline-friendly scalar primitives that are either missing from gleam_community_maths or commonly needed for ML / scientific computing. Where the Erlang stdlib already exposes a fast BIF (such as :math.erf/1, :math.erfc/1 or :math.fmod/2), we delegate through FFI rather than reimplementing.

Design rules

Erlang BIFs used (OTP 22+, confirmed on OTP 28)

:math.erf/1, :math.erfc/1, :math.fmod/2, :math.expm1/1, :math.log1p/1, :math.tanh/1, :math.exp/1, :math.log/1, :math.sqrt/1, :math.pow/2.

Values

pub fn clamp(x: Float, min: Float, max: Float) -> Float

Clamp to range [min, max].

pub fn clamp_bipolar(x: Float) -> Float

Clamp to bipolar [-1, 1].

pub fn clamp_unit(x: Float) -> Float

Clamp to unit [0, 1].

pub fn deg_to_rad(deg: Float) -> Float

Convert degrees to radians.

pub fn elu(x: Float, alpha: Float) -> Float

ELU: x if x > 0 else α(e^x - 1).

pub fn erf(x: Float) -> Float

Error function erf(x) = (2/√π) · ∫₀ˣ e^(-t²) dt.

Delegates to :math.erf/1 (Erlang stdlib BIF).

pub fn erfc(x: Float) -> Float

Complementary error function erfc(x) = 1 - erf(x).

Computed by methods that avoid cancellation for large x. Delegates to :math.erfc/1.

pub fn exp(x: Float) -> Float

Natural exponential e^x. Delegates to :math.exp/1.

pub fn expm1(x: Float) -> Float

exp(x) - 1 accurate for small x.

Uses a 4-term Maclaurin series near zero (|x| < 1e-5) to avoid the catastrophic cancellation of exp(x) - 1.0. Falls back to the direct expression elsewhere. (Not all OTP builds ship :math.expm1/1, so we implement it portably.)

pub fn fmod(x: Float, y: Float) -> Float

Floating-point remainder x mod y (IEEE 754 fmod).

Delegates to :math.fmod/2.

pub fn gelu(x: Float) -> Float

GELU exact: x · Φ(x) using erf.

Φ(x) = ½ · (1 + erf(x / √2)). Used by BERT/GPT.

pub fn gelu_approx(x: Float) -> Float

GELU tanh approximation (Hendrycks & Gimpel).

Faster, used by GPT-2/PaLM. Accurate to ~4 decimals.

pub fn hard_sigmoid(x: Float) -> Float

Hard sigmoid: piecewise linear approximation of sigmoid.

Returns 0 for x ≤ -3, 1 for x ≥ 3, linear interpolation between.

pub fn hard_swish(x: Float) -> Float

Hard swish: x · hard_sigmoid(x). Used in MobileNetV3.

pub fn hard_tanh(x: Float) -> Float

Hard tanh: clamps to [-1, 1].

pub fn hypot(x: Float, y: Float) -> Float

Hypotenuse √(x² + y²) without intermediate overflow.

pub fn iglu(x: Float, sigma: Float) -> Float

IGLU (Integrated Gaussian Linear Unit): continuous mixture of GELU activations under a Gaussian dispersion of “decision hardness”.

IGLU(x; σ) = x · Z(x; σ) where Z uses arctan-based gating. Provides smoother gradients than GELU near zero and heavier tails.

Reference: Aragón et al. (2026) “IGLU: An Integrated Gaussian Linear Activation Function” (arXiv:2603.06861).

pub fn iglu_approx(x: Float, sigma: Float) -> Float

IGLU rational approximation — same qualitative behaviour as iglu without transcendental functions. Maximum deviation ~5 %.

Recommended when execution speed matters more than exact GELU shape (e.g. low-precision quantised inference).

pub fn lambda_gelu(x: Float, lambda: Float) -> Float

λ-GELU: hardness-parameterised GELU x · Φ(λx) with λ ≥ 1.

λ = 1 recovers standard GELU; λ → ∞ approaches ReLU. Useful for learnable activation hardness, hardware quantisation-friendly fine-tuning, and gradual ReLU substitution during training.

Reference: Cantos & Aragón (2026) “λ-GELU: A Hardness-Parameterised GELU for Smooth ReLU Substitution” (arXiv:2603.21991).

pub fn leaky_relu(x: Float, negative_slope: Float) -> Float

Leaky ReLU: x if x > 0 else negative_slope · x.

pub fn lerp(a: Float, b: Float, t: Float) -> Float

Linear interpolation between a and b.

pub fn ln(x: Float) -> Float

Natural logarithm ln(x). Domain x > 0.

pub fn log1p(x: Float) -> Float

log(1 + x) accurate for small x.

Uses a Maclaurin series near zero to avoid cancellation in ln(1.0 + x). Falls back to direct logarithm elsewhere.

pub fn logaddexp(a: Float, b: Float) -> Float

log(exp(a) + exp(b)) without overflow.

Uses the identity log(e^a + e^b) = max(a,b) + log(1 + exp(-|a-b|)). When a == b (including ±∞) short-circuits to avoid ∞ - ∞ → NaN.

pub fn logit(p: Float) -> Float

Logit / inverse sigmoid: ln(p / (1 - p)). Domain p ∈ (0, 1).

pub fn logsumexp(xs: List(Float)) -> Float

log(Σ exp(xᵢ)) — log-sum-exp with max subtraction for stability.

Uses Neumaier compensated summation on the exp-shifted terms to retain precision when xᵢ values span many orders of magnitude.

pub fn mish(x: Float) -> Float

Mish: x · tanh(softplus(x)).

pub fn pow(x: Float, y: Float) -> Float

Power x^y.

pub fn rad_to_deg(rad: Float) -> Float

Convert radians to degrees.

pub fn relu(x: Float) -> Float

ReLU: max(0, x).

pub fn safe_div(a: Float, b: Float, default: Float) -> Float

Safe division.

pub fn safe_exp(x: Float) -> Float

Safe exp clamped to avoid overflow (exp(709) ≈ max_float).

pub fn safe_log(x: Float, default: Float) -> Float

Safe natural log: returns default for non-positive input.

pub fn safe_sqrt(x: Float) -> Float

Safe square root: returns 0 for negative input.

pub fn selu(x: Float) -> Float

SELU (self-normalizing). Scale and alpha from Klambauer et al. 2017.

pub fn sigmoid(x: Float) -> Float

Standard sigmoid σ(x) = 1 / (1 + e^(-x)).

pub fn sigmoid_k(x: Float, k: Float) -> Float

Generalized sigmoid with steepness k: σ(kx).

pub fn sign(x: Float) -> Float

Sign function: -1, 0, or 1.

pub fn silu(x: Float) -> Float

SiLU / Swish: x · σ(x).

pub fn smootherstep(
  edge0: Float,
  edge1: Float,
  x: Float,
) -> Float

Smootherstep: quintic version (zero first and second derivatives at edges).

pub fn smoothstep(edge0: Float, edge1: Float, x: Float) -> Float

Smoothstep: cubic Hermite interpolation between edge0 and edge1.

When the edges coincide, behaves as a step at edge0.

pub fn softplus(x: Float) -> Float

Softplus: ln(1 + e^x). Smooth ReLU.

Uses safe identity for large x to avoid overflow: softplus(x) = max(x, 0) + log1p(exp(-|x|)).

pub fn sqrt(x: Float) -> Float

Square root.

pub fn step(threshold: Float, x: Float) -> Float

Step function: 0 if x < threshold, 1 otherwise.

pub fn swish(x: Float) -> Float

Alias for silu. Used by Google’s original Swish paper.

pub fn tanh(x: Float) -> Float

Hyperbolic tangent. Delegates to :math.tanh/1.

Search Document