#[cfg(test)]
mod tests {
use crate::quant::quarot::hadamard::{BlockHadamard, RandomizedHadamard, derive_block_seed};
use crate::quant::quarot::plan::{AbsorptionSide, OnlineRotationSpec};
const HIDDEN: usize = 32;
const NUM_Q_HEADS: usize = 8;
const NUM_KV_HEADS: usize = 2;
const HEAD_DIM: usize = 256;
const Q_DIM: usize = NUM_Q_HEADS * HEAD_DIM; const KV_DIM: usize = NUM_KV_HEADS * HEAD_DIM; const GROUPS: usize = NUM_Q_HEADS / NUM_KV_HEADS; const SEQ_LEN: usize = 3;
const R_V_SEED: u64 = 0xA1;
const R_O_SEED: u64 = 0xB2;
fn synthetic_vec(n: usize, seed: u64) -> Vec<f32> {
let mut state = seed;
(0..n)
.map(|_| {
state = state
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
let bits = (state >> 11) as u32;
(bits as f32 / u32::MAX as f32) - 0.5
})
.collect()
}
fn matvec(w: &[f32], rows: usize, cols: usize, x: &[f32]) -> Vec<f32> {
(0..rows)
.map(|r| (0..cols).map(|c| w[r * cols + c] * x[c]).sum())
.collect()
}
fn sigmoid(x: f32) -> f32 {
1.0 / (1.0 + (-x).exp())
}
fn max_abs_diff(a: &[f32], b: &[f32]) -> f32 {
a.iter()
.zip(b.iter())
.map(|(x, y)| (x - y).abs())
.fold(0.0, f32::max)
}
struct Fixture {
x: Vec<f32>, q_gate_proj: Vec<f32>, o_proj: Vec<f32>, k_cache: Vec<Vec<f32>>, v_cache: Vec<Vec<f32>>, }
fn build_fixture() -> Fixture {
Fixture {
x: synthetic_vec(HIDDEN, 1),
q_gate_proj: synthetic_vec(2 * Q_DIM * HIDDEN, 2),
o_proj: synthetic_vec(HIDDEN * Q_DIM, 3),
k_cache: vec![
synthetic_vec(KV_DIM, 10),
synthetic_vec(KV_DIM, 11),
synthetic_vec(KV_DIM, 12),
],
v_cache: vec![
synthetic_vec(KV_DIM, 20),
synthetic_vec(KV_DIM, 21),
synthetic_vec(KV_DIM, 22),
],
}
}
fn project_q_and_gate(fx: &Fixture) -> (Vec<f32>, Vec<f32>) {
let q_and_gate = matvec(&fx.q_gate_proj, 2 * Q_DIM, HIDDEN, &fx.x);
let mut q = vec![0.0f32; Q_DIM];
let mut gate = vec![0.0f32; Q_DIM];
for h in 0..NUM_Q_HEADS {
let src = h * HEAD_DIM * 2;
let dst = h * HEAD_DIM;
q[dst..dst + HEAD_DIM].copy_from_slice(&q_and_gate[src..src + HEAD_DIM]);
gate[dst..dst + HEAD_DIM]
.copy_from_slice(&q_and_gate[src + HEAD_DIM..src + HEAD_DIM * 2]);
}
(q, gate)
}
fn attention_context(fx: &Fixture, q: &[f32], v_cache: &[Vec<f32>]) -> Vec<f32> {
let scale = 1.0 / (HEAD_DIM as f32).sqrt();
let mut context = vec![0.0f32; Q_DIM];
for qh in 0..NUM_Q_HEADS {
let kvh = qh / GROUPS;
let q_off = qh * HEAD_DIM;
let qh_vec = &q[q_off..q_off + HEAD_DIM];
let mut scores = [0.0f32; SEQ_LEN];
for t in 0..SEQ_LEN {
let k_off = kvh * HEAD_DIM;
let dot: f32 = (0..HEAD_DIM)
.map(|d| qh_vec[d] * fx.k_cache[t][k_off + d])
.sum();
scores[t] = dot * scale;
}
let max_score = scores.iter().copied().fold(f32::NEG_INFINITY, f32::max);
let mut sum_exp = 0.0f32;
for s in scores.iter_mut() {
*s = (*s - max_score).exp();
sum_exp += *s;
}
for s in scores.iter_mut() {
*s /= sum_exp;
}
let ctx_off = qh * HEAD_DIM;
for d in 0..HEAD_DIM {
let v_off = kvh * HEAD_DIM;
let sum: f32 = (0..SEQ_LEN)
.map(|t| scores[t] * v_cache[t][v_off + d])
.sum();
context[ctx_off + d] = sum;
}
}
context
}
fn dense_forward(fx: &Fixture) -> Vec<f32> {
let (q, gate) = project_q_and_gate(fx);
let context = attention_context(fx, &q, &fx.v_cache);
let gated: Vec<f32> = context
.iter()
.zip(gate.iter())
.map(|(&c, &g)| c * sigmoid(g))
.collect();
matvec(&fx.o_proj, HIDDEN, Q_DIM, &gated)
}
fn apply_cross_head_rotation(
data: &mut [f32],
num_heads: usize,
head_dim: usize,
r: &RandomizedHadamard,
) {
assert_eq!(data.len(), num_heads * head_dim);
assert_eq!(r.dim(), num_heads);
let mut channel = vec![0.0f32; num_heads];
for d in 0..head_dim {
for h in 0..num_heads {
channel[h] = data[h * head_dim + d];
}
r.apply(&mut channel).unwrap();
for h in 0..num_heads {
data[h * head_dim + d] = channel[h];
}
}
}
fn absorb_input_cross_head_rotation(
weight: &mut [f32],
rows: usize,
cols: usize,
num_heads: usize,
head_dim: usize,
r: &RandomizedHadamard,
) {
assert_eq!(weight.len(), rows * cols);
assert_eq!(cols, num_heads * head_dim);
for row in 0..rows {
let slice = &mut weight[row * cols..(row + 1) * cols];
apply_cross_head_rotation(slice, num_heads, head_dim, r);
}
}
struct KvBroadcastRotation {
per_kv_head: Vec<RandomizedHadamard>,
}
impl KvBroadcastRotation {
fn matching(seed: u64) -> Self {
let per_kv_head = (0..NUM_KV_HEADS)
.map(|kvh| RandomizedHadamard::new(derive_block_seed(seed, kvh), HEAD_DIM).unwrap())
.collect();
Self { per_kv_head }
}
fn apply(&self, data: &mut [f32]) {
for qh in 0..NUM_Q_HEADS {
let kvh = qh / GROUPS;
let slice = &mut data[qh * HEAD_DIM..(qh + 1) * HEAD_DIM];
self.per_kv_head[kvh].apply(slice).unwrap();
}
}
fn apply_inverse(&self, data: &mut [f32]) {
for qh in 0..NUM_Q_HEADS {
let kvh = qh / GROUPS;
let slice = &mut data[qh * HEAD_DIM..(qh + 1) * HEAD_DIM];
self.per_kv_head[kvh].apply_inverse(slice).unwrap();
}
}
fn absorb_into_input_side(&self, weight: &mut [f32], rows: usize, cols: usize) {
assert_eq!(weight.len(), rows * cols);
assert_eq!(cols, Q_DIM);
for row in 0..rows {
let slice = &mut weight[row * cols..(row + 1) * cols];
self.apply(slice);
}
}
}
fn candidate_pre_gate_value_only(fx: &Fixture) -> Vec<f32> {
let r_v = BlockHadamard::new(R_V_SEED, KV_DIM, HEAD_DIM).unwrap();
let mut v_rotated = fx.v_cache.clone();
for v in v_rotated.iter_mut() {
r_v.apply(v).unwrap();
}
let (q, gate) = project_q_and_gate(fx);
let context_rot = attention_context(fx, &q, &v_rotated);
let gated: Vec<f32> = context_rot
.iter()
.zip(gate.iter())
.map(|(&c, &g)| c * sigmoid(g))
.collect();
let broadcast = KvBroadcastRotation::matching(R_V_SEED);
let mut o_rot = fx.o_proj.clone();
broadcast.absorb_into_input_side(&mut o_rot, HIDDEN, Q_DIM);
matvec(&o_rot, HIDDEN, Q_DIM, &gated)
}
fn candidate_post_gate_context(fx: &Fixture) -> Vec<f32> {
let (q, gate) = project_q_and_gate(fx);
let context = attention_context(fx, &q, &fx.v_cache);
let mut gated: Vec<f32> = context
.iter()
.zip(gate.iter())
.map(|(&c, &g)| c * sigmoid(g))
.collect();
let r = RandomizedHadamard::new(R_O_SEED, NUM_Q_HEADS).unwrap();
apply_cross_head_rotation(&mut gated, NUM_Q_HEADS, HEAD_DIM, &r);
let mut o_rot = fx.o_proj.clone();
absorb_input_cross_head_rotation(&mut o_rot, HIDDEN, Q_DIM, NUM_Q_HEADS, HEAD_DIM, &r);
matvec(&o_rot, HIDDEN, Q_DIM, &gated)
}
fn candidate_joint_pre_gate_through_sigmoid(fx: &Fixture) -> Vec<f32> {
let (q, gate) = project_q_and_gate(fx);
let context = attention_context(fx, &q, &fx.v_cache);
let r = RandomizedHadamard::new(0xC3, NUM_Q_HEADS).unwrap();
let mut context_rot = context.clone();
apply_cross_head_rotation(&mut context_rot, NUM_Q_HEADS, HEAD_DIM, &r);
let mut gate_rot = gate.clone();
apply_cross_head_rotation(&mut gate_rot, NUM_Q_HEADS, HEAD_DIM, &r);
let gated: Vec<f32> = context_rot
.iter()
.zip(gate_rot.iter())
.map(|(&c, &g)| c * sigmoid(g))
.collect();
let mut o_rot = fx.o_proj.clone();
absorb_input_cross_head_rotation(&mut o_rot, HIDDEN, Q_DIM, NUM_Q_HEADS, HEAD_DIM, &r);
matvec(&o_rot, HIDDEN, Q_DIM, &gated)
}
fn candidate_value_round_trip_then_post_gate(fx: &Fixture) -> Vec<f32> {
let r_v = BlockHadamard::new(R_V_SEED, KV_DIM, HEAD_DIM).unwrap();
let mut v_rotated = fx.v_cache.clone();
for v in v_rotated.iter_mut() {
r_v.apply(v).unwrap();
}
let (q, gate) = project_q_and_gate(fx);
let context_rot = attention_context(fx, &q, &v_rotated);
let broadcast = KvBroadcastRotation::matching(R_V_SEED);
let mut context_restored = context_rot.clone();
broadcast.apply_inverse(&mut context_restored);
let mut gated: Vec<f32> = context_restored
.iter()
.zip(gate.iter())
.map(|(&c, &g)| c * sigmoid(g))
.collect();
let r_o = RandomizedHadamard::new(R_O_SEED, NUM_Q_HEADS).unwrap();
apply_cross_head_rotation(&mut gated, NUM_Q_HEADS, HEAD_DIM, &r_o);
let mut o_rot = fx.o_proj.clone();
absorb_input_cross_head_rotation(&mut o_rot, HIDDEN, Q_DIM, NUM_Q_HEADS, HEAD_DIM, &r_o);
matvec(&o_rot, HIDDEN, Q_DIM, &gated)
}
#[test]
fn r3_orientation_enumeration_finds_exactly_one_reparameterization() {
let fx = build_fixture();
let dense = dense_forward(&fx);
const TOLERANCE: f32 = 1e-4;
let candidates: [(&str, Vec<f32>, bool); 4] = [
(
"pre_gate_value_only",
candidate_pre_gate_value_only(&fx),
false,
),
(
"post_gate_context (winning orientation)",
candidate_post_gate_context(&fx),
true,
),
(
"joint_pre_gate_through_sigmoid",
candidate_joint_pre_gate_through_sigmoid(&fx),
false,
),
(
"value_round_trip_then_post_gate",
candidate_value_round_trip_then_post_gate(&fx),
true,
),
];
let mut matched: usize = 0;
for (name, out, expected_match) in &candidates {
let delta = max_abs_diff(&dense, out);
let is_match = delta < TOLERANCE;
eprintln!(
"R3 orientation candidate {name:>45}: max_abs_diff={delta:.6} match={is_match}"
);
assert_eq!(
is_match, *expected_match,
"candidate {name}: expected match={expected_match}, got delta={delta}"
);
if is_match {
matched += 1;
}
}
assert_eq!(
matched, 2,
"expected exactly the two same-orientation candidates to match"
);
let cfg = crate::model::qwen35_config::Qwen35Config::qwen35_0_8b();
let spec = OnlineRotationSpec::r3_full_attention(&cfg, 1, NUM_Q_HEADS).unwrap();
assert_eq!(
spec.side,
AbsorptionSide::InputSide,
"OnlineRotationSpec::r3_full_attention must record the winning \
orientation proven by this enumeration"
);
}
fn cross_head_matrix(num_heads: usize, head_dim: usize) -> Vec<Vec<f32>> {
let n = num_heads * head_dim;
let mut matrix = vec![vec![0.0f32; n]; n];
for j in 0..n {
let mut e = vec![0.0f32; n];
e[j] = 1.0;
for d in 0..head_dim {
let mut channel: Vec<f32> = (0..num_heads).map(|h| e[h * head_dim + d]).collect();
crate::quant::quarot::hadamard::walsh_hadamard_orthonormal_in_place(&mut channel)
.unwrap();
for (h, &v) in channel.iter().enumerate() {
e[h * head_dim + d] = v;
}
}
for (i, &v) in e.iter().enumerate() {
matrix[i][j] = v;
}
}
matrix
}
fn intra_head_matrix(num_heads: usize, head_dim: usize) -> Vec<Vec<f32>> {
let n = num_heads * head_dim;
let mut matrix = vec![vec![0.0f32; n]; n];
for j in 0..n {
let mut e = vec![0.0f32; n];
e[j] = 1.0;
for h in 0..num_heads {
let slice = &mut e[h * head_dim..(h + 1) * head_dim];
crate::quant::quarot::hadamard::walsh_hadamard_orthonormal_in_place(slice).unwrap();
}
for (i, &v) in e.iter().enumerate() {
matrix[i][j] = v;
}
}
matrix
}
#[test]
fn r3_axis_discriminates_cross_head_from_intra_head() {
const NH: usize = 4;
const DH: usize = 4;
const N: usize = NH * DH;
let h4: [[f32; NH]; NH] = [
[0.5, 0.5, 0.5, 0.5],
[0.5, -0.5, 0.5, -0.5],
[0.5, 0.5, -0.5, -0.5],
[0.5, -0.5, -0.5, 0.5],
];
let mut hand_cross = vec![vec![0.0f32; N]; N];
for h_out in 0..NH {
for h_in in 0..NH {
for d in 0..DH {
hand_cross[h_out * DH + d][h_in * DH + d] = h4[h_out][h_in];
}
}
}
let built_cross = cross_head_matrix(NH, DH);
for i in 0..N {
for j in 0..N {
assert!(
(built_cross[i][j] - hand_cross[i][j]).abs() < 1e-6,
"cross-head matrix[{i}][{j}]: built={}, hand-computed H_4⊗I_4={}",
built_cross[i][j],
hand_cross[i][j]
);
}
}
assert!(
built_cross[0][DH].abs() > 1e-6,
"H_num_heads ⊗ I_head_dim must mix across heads at a fixed channel"
);
assert_eq!(
built_cross[0][DH + 1],
0.0,
"H_num_heads ⊗ I_head_dim must not mix different within-head channels"
);
let built_intra = intra_head_matrix(NH, DH);
assert_eq!(
built_intra[0][DH], 0.0,
"I_num_heads ⊗ H_head_dim (the pre-fix construction) must NOT mix \
across heads — confirms the discriminating assertion above would \
fail (mutation-sensitive) against the old construction"
);
let differing = (0..N)
.flat_map(|i| (0..N).map(move |j| (i, j)))
.filter(|&(i, j)| (built_cross[i][j] - built_intra[i][j]).abs() > 1e-6)
.count();
assert!(
differing > 0,
"cross-head and intra-head constructions must be genuinely different matrices"
);
}
}