use burn::prelude::*;
pub fn delta_update<B: Backend>(
x: Tensor<B, 3>, k: Tensor<B, 2>, v: Tensor<B, 2>, beta: Tensor<B, 2>, eps: f32,
) -> Tensor<B, 3> {
let k_squared = k.clone().powf_scalar(2.0);
let k_norm_val: Tensor<B, 2> = k_squared.sum_dim(1).sqrt().add_scalar(eps);
let k_normalized: Tensor<B, 2> = k.div(k_norm_val);
let k_t: Tensor<B, 3> = k_normalized.clone().unsqueeze_dim::<3>(1);
let proj: Tensor<B, 3> = k_t.matmul(x.clone());
let v_row: Tensor<B, 3> = v.unsqueeze_dim::<3>(1);
let delta_val = v_row.sub(proj);
let k_col: Tensor<B, 3> = k_normalized.unsqueeze_dim::<3>(2);
let rank1: Tensor<B, 3> = k_col.matmul(delta_val);
let beta_expanded: Tensor<B, 3> = beta.unsqueeze_dim::<3>(2);
let gated_update = rank1.mul(beta_expanded);
x.add(gated_update)
}
pub fn delta_update_vec<B: Backend>(
x: Tensor<B, 2>, k: Tensor<B, 2>, v: Tensor<B, 2>, beta: Tensor<B, 2>, eps: f32,
) -> Tensor<B, 2> {
let k_squared = k.clone().powf_scalar(2.0);
let k_norm_val: Tensor<B, 2> = k_squared.sum_dim(1).sqrt().add_scalar(eps);
let k_normalized: Tensor<B, 2> = k.div(k_norm_val);
let k_t_x: Tensor<B, 2> = (k_normalized.clone().mul(x.clone())).sum_dim(1);
let gamma: Tensor<B, 2> = v.sub(k_t_x);
let gated_gamma: Tensor<B, 2> = beta.mul(gamma);
let update: Tensor<B, 2> = k_normalized.mul(gated_gamma);
x.add(update)
}
pub fn delta_operator<B: Backend>(
k: Tensor<B, 2>, beta: Tensor<B, 2>, d: usize,
) -> Tensor<B, 3> {
let device = k.device();
let batch_size = k.dims()[0];
let identity: Tensor<B, 3> = Tensor::eye(d, &device)
.unsqueeze_dim::<3>(0)
.repeat_dim(0, batch_size);
let k_col: Tensor<B, 3> = k.clone().unsqueeze_dim::<3>(2);
let k_row: Tensor<B, 3> = k.unsqueeze_dim::<3>(1);
let k_outer = k_col.matmul(k_row);
let beta_expanded: Tensor<B, 3> = beta.unsqueeze_dim::<3>(2);
let scaled_outer = k_outer.mul(beta_expanded);
identity.sub(scaled_outer)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::backend::AutoBackend;
type TestBackend = AutoBackend;
#[test]
fn test_delta_update_identity_regime() {
let device = Default::default();
let x =
Tensor::<TestBackend, 3>::from_floats([[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]], &device);
let k = Tensor::<TestBackend, 2>::from_floats([[1.0, 0.0, 0.0]], &device);
let v = Tensor::<TestBackend, 2>::from_floats([[7.0, 8.0]], &device);
let beta = Tensor::<TestBackend, 2>::from_floats([[0.0001]], &device);
let result = delta_update(x.clone(), k, v, beta, 1e-8);
let diff = result.sub(x).abs().sum().into_scalar();
assert!(diff < 0.01);
}
#[test]
fn test_delta_update_vec_identity() {
let device = Default::default();
let x = Tensor::<TestBackend, 2>::from_floats([[1.0, 2.0, 3.0]], &device);
let k = Tensor::<TestBackend, 2>::from_floats([[1.0, 0.0, 0.0]], &device);
let v = Tensor::<TestBackend, 2>::from_floats([[5.0]], &device);
let beta = Tensor::<TestBackend, 2>::from_floats([[0.0]], &device);
let result = delta_update_vec(x.clone(), k, v, beta, 1e-8);
let diff = result.sub(x).abs().sum().into_scalar();
assert!(diff < 1e-6);
}
}