Skip to main content

ClikaRT::ops::gated_delta_update

function

gated_delta_update()

Tensor gated_delta_update(
    Tensor q,
    Tensor k,
    Tensor v,
    Tensor beta,
    Tensor g,
    Tensor state,
    OptionalTensor seq_lens = {},
    OptionalTensor slot_ids = {},
    std::optional<double> scale = std::nullopt,
    OptionalTensor gate_bias = {},
    OptionalTensor gate_scale = {}
)

Gated delta-rule recurrence step: per token, the [B, HV, K, V] Float32 state decays by exp(g), takes the delta-rule rank-1 update (beta·k) ⊗ (v − Sᵀk), and emits o = (scale·q)ᵀ S, updated IN PLACE. The gate's RANK picks the family: [B, T, HV] = one scalar per value head; [B, T, HV, K] = per key dim. q/k [B, T, H, K] (HV % H == 0, grouped heads), v [B, T, HV, V], beta [B, T, HV]; scale defaults to K^-1/2; seq_lens ([B] Int32) bounds ragged prefill rows. slot_ids ([B] Int32, device-resident) addresses state as a SLAB [num_slots, HV, K, V]: batch row b reads/updates slab row slot_ids[b] in place (ids in range and DISTINCT per call, the caller's contract); absent keeps state row b. TWO gate forms, told apart by which inputs are bound: with gate_bias and gate_scale absent, g IS the log-space decay (Float32 or the activations' dtype); with both bound (Float32 gate_bias [HV] beside a [B, T, HV] gate or [HV, K] beside a [B, T, HV, K] one, the checkpoint's dt_bias; Float32 gate_scale [HV], the once-folded -exp(A_log)), g is the RAW gate projection slice at the activations' dtype and the kernel forms the decay gate_scale * softplus(g + gate_bias) in fp32 registers, so no add / softplus / mul pass and no fp32 transient precede the call. One without the other rejects; a backend without the raw-gate arm declines it typed.

Declared in ClikaRT/compute/ops.h, line 3773