1extern crate alloc;
16use alloc::vec;
17use alloc::vec::Vec;
18
19use crate::math::exp;
20use crate::ops::silu;
21
22pub fn hada_blocks(n: usize) -> (usize, usize) {
27 debug_assert!(
28 n.is_power_of_two(),
29 "transform width must be a power of two"
30 );
31 let bits = usize::BITS - (n - 1).leading_zeros();
32 let ba = 1usize << (bits / 2);
33 (ba, n / ba)
34}
35
36pub fn kron_apply(z: &[f32], a: &[f32], b: &[f32], ba: usize, bb: usize, out: &mut [f32]) {
42 debug_assert_eq!(z.len(), ba * bb);
43 debug_assert_eq!(a.len(), ba * ba);
44 debug_assert_eq!(b.len(), bb * bb);
45 debug_assert_eq!(out.len(), ba * bb);
46
47 let mut t = vec![0.0f32; ba * bb];
50 for i in 0..ba {
51 let zi = &z[i * bb..(i + 1) * bb];
52 let ai = &a[i * ba..(i + 1) * ba];
53 for (k, &aik) in ai.iter().enumerate() {
54 if aik == 0.0 {
55 continue;
56 }
57 let tk = &mut t[k * bb..(k + 1) * bb];
58 for (tkj, &zij) in tk.iter_mut().zip(zi) {
59 *tkj += zij * aik;
60 }
61 }
62 }
63
64 for k in 0..ba {
66 let tk = &t[k * bb..(k + 1) * bb];
67 let ok = &mut out[k * bb..(k + 1) * bb];
68 ok.fill(0.0);
69 for (j, &tkj) in tk.iter().enumerate() {
70 if tkj == 0.0 {
71 continue;
72 }
73 let bj = &b[j * bb..(j + 1) * bb];
74 for (okl, &bjl) in ok.iter_mut().zip(bj) {
75 *okl += tkj * bjl;
76 }
77 }
78 }
79}
80
81#[derive(Debug, Clone)]
83pub struct HadaMlp {
84 pub d1: Vec<f32>,
86 pub d2: Vec<f32>,
87 pub b2: Vec<f32>,
88 pub d3: Vec<f32>,
89 pub d4: Vec<f32>,
90 pub w1: (Vec<f32>, Vec<f32>),
92 pub w2: (Vec<f32>, Vec<f32>),
93 pub w3: (Vec<f32>, Vec<f32>),
94 pub cond_v: Vec<f32>,
96 pub cond_u: Vec<f32>,
97 pub cond_rank: usize,
98}
99
100#[derive(Debug, Clone)]
104pub struct HadaPerms {
105 pub p1: Vec<u32>,
106 pub p2: Vec<u32>,
107}
108
109pub fn hadamard_mlp(x: &[f32], w: &HadaMlp, perms: &HadaPerms, hada_n: usize, out: &mut [f32]) {
120 let d_model = x.len();
121 debug_assert_eq!(out.len(), d_model);
122 let (ba, bb) = hada_blocks(hada_n);
123
124 let r = w.cond_rank;
126 let mut proj = vec![0.0f32; r];
127 for (j, p) in proj.iter_mut().enumerate() {
128 let mut acc = 0.0f32;
129 for (i, &xi) in x.iter().enumerate() {
130 acc += xi * w.cond_v[i * r + j];
131 }
132 *p = acc;
133 }
134 let max = proj.iter().copied().fold(f32::NEG_INFINITY, f32::max);
135 let mut sum = 0.0f32;
136 for p in proj.iter_mut() {
137 *p = exp(*p - max);
138 sum += *p;
139 }
140 for p in proj.iter_mut() {
141 *p /= sum;
142 }
143 let mut cond = vec![1.0f32; hada_n];
144 for (j, &pj) in proj.iter().enumerate() {
145 if pj == 0.0 {
146 continue;
147 }
148 let row = &w.cond_u[j * hada_n..(j + 1) * hada_n];
149 for (c, &u) in cond.iter_mut().zip(row) {
150 *c += pj * u;
151 }
152 }
153
154 let mut z = vec![0.0f32; hada_n];
156 z[..d_model].copy_from_slice(x);
157
158 let mut buf = vec![0.0f32; hada_n];
159
160 for (zi, &d) in z.iter_mut().zip(&w.d1) {
161 *zi *= d;
162 }
163 kron_apply(&z, &w.w1.0, &w.w1.1, ba, bb, &mut buf);
164 permute(&buf, &perms.p1, &mut z);
165
166 for i in 0..hada_n {
167 z[i] = silu(w.d2[i] * cond[i] * z[i] + w.b2[i]);
168 }
169 kron_apply(&z, &w.w2.0, &w.w2.1, ba, bb, &mut buf);
170 permute(&buf, &perms.p2, &mut z);
171
172 for (zi, &d) in z.iter_mut().zip(&w.d3) {
173 *zi *= d;
174 }
175 kron_apply(&z, &w.w3.0, &w.w3.1, ba, bb, &mut buf);
176
177 for (o, (&b, &d)) in out.iter_mut().zip(buf.iter().zip(&w.d4)) {
178 *o = b * d;
179 }
180}
181
182fn permute(src: &[f32], perm: &[u32], out: &mut [f32]) {
184 debug_assert_eq!(src.len(), perm.len());
185 for (o, &p) in out.iter_mut().zip(perm) {
186 *o = src[p as usize];
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn block_sizes_match_upstream() {
196 assert_eq!(hada_blocks(1024), (32, 32));
197 assert_eq!(hada_blocks(512), (16, 32));
198 assert_eq!(hada_blocks(256), (16, 16));
199 }
200
201 #[test]
202 fn kron_matches_a_transpose_z_b() {
203 let (ba, bb) = (2usize, 2usize);
205 let z = [1.0f32, 2.0, 3.0, 4.0]; let a = [1.0f32, 2.0, 3.0, 4.0]; let b = [0.0f32, 1.0, 1.0, 0.0]; let mut out = [0.0f32; 4];
209 kron_apply(&z, &a, &b, ba, bb, &mut out);
210 assert_eq!(out, [14.0, 10.0, 20.0, 14.0]);
216 }
217
218 #[test]
219 fn permute_gathers() {
220 let src = [10.0f32, 20.0, 30.0];
221 let perm = [2u32, 0, 1];
222 let mut out = [0.0f32; 3];
223 permute(&src, &perm, &mut out);
224 assert_eq!(out, [30.0, 10.0, 20.0]);
225 }
226}