use crate::arithmetic::Fx;
use crate::model::{Encoding, Tensor};
use super::arch::{m_svd, FxAdj};
use super::index::Adjacency;
pub fn embed(adj: &Adjacency, phi: &[Fx], d: usize) -> Tensor {
let g = FxAdj::from(adj);
let n = g.n;
let svd = m_svd(&g, phi, d, 120);
let rank = svd.sigma.len();
let sqrt_sigma: Vec<Fx> = svd.sigma.iter().map(|&s| s.sqrt()).collect();
let mut data = Vec::with_capacity(n * d);
for i in 0..n {
for c in 0..d {
let v = if c < rank {
svd.u[c][i] * sqrt_sigma[c]
} else {
Fx::ZERO
};
data.push(v);
}
}
Tensor {
name: "model.embed_tokens.weight".to_string(),
shape: vec![n as u64, d as u64],
encoding: Encoding::U16,
data,
}
}
#[cfg(test)]
mod tests {
use super::super::arch;
use super::super::index::build;
use super::*;
use crate::graph::Cyberlink;
fn hash(b: u8) -> [u8; 32] {
let mut h = [0u8; 32];
h[0] = b;
h
}
fn edge(from: u8, to: u8, amount: u128) -> Cyberlink {
Cyberlink {
neuron: hash(from),
from: hash(from),
to: hash(to),
token: 0,
amount,
valence: 1,
block: 0,
}
}
fn undirected_ring() -> (Adjacency, Vec<Fx>) {
let mut links = Vec::new();
for (a, b) in [(1u8, 2u8), (2, 3), (3, 4), (4, 1), (1, 3)] {
links.push(edge(a, b, 100));
links.push(edge(b, a, 100));
}
let (_v, _e, adj) = build(&[], &links);
let a = arch::compute(&adj, 1, 0);
(adj, a.phi)
}
#[test]
fn embedding_has_the_right_shape() {
let (adj, phi) = undirected_ring();
let d = 16;
let t = embed(&adj, &phi, d);
assert_eq!(t.name, "model.embed_tokens.weight");
assert_eq!(t.shape, vec![adj.n as u64, d as u64]);
assert_eq!(t.data.len(), adj.n * d);
}
#[test]
fn svd_reconstructs_m_within_tolerance() {
let (adj, phi) = undirected_ring();
let n = adj.n;
let g = FxAdj::from(&adj);
let svd = m_svd(&g, &phi, n, 200);
let ds: Vec<f64> = phi.iter().map(|x| x.to_f64().sqrt()).collect();
let maxw = adj.out.iter().flatten().map(|&(_, w)| w).max().unwrap_or(1) as f64;
let mut m = vec![vec![0.0; n]; n];
for i in 0..n {
for &(j, w) in &adj.out[i] {
m[i][j as usize] += ds[i] * (w as f64 / maxw) * ds[j as usize];
}
}
let mut err = 0.0;
let mut mag = 0.0;
for i in 0..n {
for j in 0..n {
let mut rec = 0.0;
for c in 0..svd.sigma.len() {
rec += svd.sigma[c].to_f64() * svd.u[c][i].to_f64() * svd.v[c][j].to_f64();
}
err += (rec - m[i][j]).powi(2);
mag += m[i][j].powi(2);
}
}
let rel = (err / mag).sqrt();
assert!(
rel <= 0.05,
"SVD reconstruction of M is {rel}, exceeds 0.05"
);
}
#[test]
fn embedding_is_deterministic() {
let (adj, phi) = undirected_ring();
let a = embed(&adj, &phi, 16);
let b = embed(&adj, &phi, 16);
assert!(
a.data.iter().zip(&b.data).all(|(x, y)| x.raw() == y.raw()),
"embedding bit-identical"
);
}
}