pub const EMBEDDING_DIM: usize = 768;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Width<const N: usize>(());
pub trait Matryoshka: sealed::Sealed {}
mod sealed {
pub trait Sealed {}
}
macro_rules! matryoshka_widths {
($($n:literal),+) => {$(
impl sealed::Sealed for Width<$n> {}
impl Matryoshka for Width<$n> {}
)+};
}
matryoshka_widths!(768, 512, 256, 128);
#[derive(Clone)]
pub struct Embedding<const N: usize = EMBEDDING_DIM> {
inner: [f32; N],
}
impl<const N: usize> Embedding<N>
where
Width<N>: Matryoshka,
{
#[inline]
pub const fn dim(&self) -> usize {
N
}
#[inline]
pub const fn as_slice(&self) -> &[f32] {
&self.inner
}
#[inline]
pub fn to_vec(&self) -> Vec<f32> {
self.inner.to_vec()
}
pub fn dot(&self, other: &Self) -> f32 {
self
.inner
.iter()
.zip(&other.inner)
.map(|(a, b)| f64::from(*a) * f64::from(*b))
.sum::<f64>() as f32
}
#[inline]
pub fn cosine(&self, other: &Self) -> f32 {
self.dot(other)
}
fn from_wide(wide: &[f64; N]) -> Option<Self> {
let norm = wide.iter().map(|v| v * v).sum::<f64>().sqrt();
if !(norm.is_finite() && norm > 0.0) {
return None;
}
Some(Self {
inner: core::array::from_fn(|i| (wide[i] / norm) as f32),
})
}
}
impl Embedding<EMBEDDING_DIM> {
pub(crate) fn from_output(row: &[f32; EMBEDDING_DIM]) -> Option<Self> {
if !row.iter().all(|v| v.is_finite()) {
return None;
}
let wide: [f64; EMBEDDING_DIM] = core::array::from_fn(|i| f64::from(row[i]));
Self::from_wide(&wide)
}
pub fn truncate<const M: usize>(&self) -> Embedding<M>
where
Width<M>: Matryoshka,
{
let wide: [f64; M] = core::array::from_fn(|i| f64::from(self.inner[i]));
Embedding::from_wide(&wide).unwrap_or(Embedding { inner: [0.0; M] })
}
}
impl<const N: usize> AsRef<[f32]> for Embedding<N>
where
Width<N>: Matryoshka,
{
#[inline]
fn as_ref(&self) -> &[f32] {
self.as_slice()
}
}
impl<const N: usize> core::fmt::Debug for Embedding<N>
where
Width<N>: Matryoshka,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"Embedding {{ dim: {N}, head: [{:.4}, {:.4}, {:.4}, ..] }}",
self.inner[0], self.inner[1], self.inner[2],
)
}
}
impl<const N: usize> windit::windowed::Vector for Embedding<N>
where
Width<N>: Matryoshka,
{
type Scalar = f32;
fn as_slice(&self) -> &[f32] {
&self.inner
}
fn from_unnormalized(v: &[f64]) -> Result<Self, windit::WinditError> {
let wide: &[f64; N] = v.try_into().map_err(|_| windit::WinditError::DimMismatch {
got: v.len(),
expected: N,
})?;
Self::from_wide(wide).ok_or(windit::WinditError::NonFinite)
}
}
#[cfg(test)]
mod tests;