use candle_core::{Device, Result, Tensor};
pub(super) fn create_rope_table(
dim: usize,
max_len: usize,
device: &Device,
) -> Result<(Tensor, Tensor)> {
let base = 5_000f32;
let half_dim = dim / 2;
let inv_freq: Vec<f32> = (0..half_dim)
.map(|i| 1.0 / base.powf(2.0 * i as f32 / dim as f32))
.collect();
let inv_freq_t = Tensor::from_vec(inv_freq, half_dim, device)?;
let positions: Vec<f32> = (0..max_len).map(|i| i as f32).collect();
let positions_t = Tensor::from_vec(positions, max_len, device)?;
let freqs = positions_t
.unsqueeze(1)?
.matmul(&inv_freq_t.unsqueeze(0)?)?;
let emb = Tensor::cat(&[&freqs, &freqs], 1)?;
let cos = emb.cos()?;
let sin = emb.sin()?;
let cos = cos.unsqueeze(1)?.unsqueeze(1)?;
let sin = sin.unsqueeze(1)?.unsqueeze(1)?;
Ok((cos, sin))
}
pub(super) fn apply_rotary_pos_emb(
q: &Tensor,
k: &Tensor,
cos: &Tensor,
sin: &Tensor,
) -> Result<(Tensor, Tensor)> {
let q_rot = rotate_half(q)?;
let k_rot = rotate_half(k)?;
let q_embed = q.broadcast_mul(cos)?.add(&q_rot.broadcast_mul(sin)?)?;
let k_embed = k.broadcast_mul(cos)?.add(&k_rot.broadcast_mul(sin)?)?;
Ok((q_embed, k_embed))
}
fn rotate_half(x: &Tensor) -> Result<Tensor> {
let d = x.dim(candle_core::D::Minus1)?;
let half = d / 2;
let x1 = x.narrow(candle_core::D::Minus1, 0, half)?;
let x2 = x.narrow(candle_core::D::Minus1, half, half)?;
let neg_x2 = x2.neg()?;
Tensor::cat(&[&neg_x2, &x1], candle_core::D::Minus1)
}