CompressedGemma commited on
Commit
1581489
Β·
verified Β·
1 Parent(s): 44e6b86

Upload hpc_forward_merged.c

Browse files
Files changed (1) hide show
  1. hpc_forward_merged.c +562 -0
hpc_forward_merged.c ADDED
@@ -0,0 +1,562 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ * HPC Forward Pass β€” The Graph IS the Computation
3
+ *
4
+ * Architecture mirrors the BPE tokenizer:
5
+ * - Token positions β†’ HPCGraph sites
6
+ * - Hidden dimensions β†’ triality-encoded quhit amplitudes
7
+ * - Weight projections β†’ phase edges between input/output sites
8
+ * - Attention β†’ CZ coupling between Q/K sites + marginal readout
9
+ * - Importance β†’ graph |ψ|Β² marginal probabilities (no separate E[xΒ²])
10
+ *
11
+ * One function does the entire layer: norm β†’ QKV β†’ attention β†’ FFN.
12
+ * Python only handles weight I/O; all compute flows through HPCGraph.
13
+ * ═══════════════════════════════════════════════════════════════════════════ */
14
+
15
+ /* ── Helper: encode a float vector into an HPCGraph's site amplitudes ──
16
+ *
17
+ * Maps each element x[j] into a D=6 quhit amplitude at site j via
18
+ * triality modular folding. This IS the encoding the BPE tokenizer uses
19
+ * for token IDs β€” same machinery, different domain.
20
+ */
21
+ static void hpc_encode_vector(HPCGraph *g, const float *x, int64_t dim,
22
+ int64_t site_offset)
23
+ {
24
+ for (int64_t j = 0; j < dim; j++) {
25
+ double re[D] = {0}, im[D] = {0};
26
+ float val = x[j];
27
+ float mag = fabsf(val) + 1e-12f;
28
+ /* Modular triality fold: value β†’ phase index in D=6 space */
29
+ int phase = ((int)(mag * 1e3f)) % D;
30
+ if (phase < 0) phase += D;
31
+ re[phase] = sqrt(mag);
32
+ /* Sign β†’ imaginary component (preserves direction) */
33
+ im[phase] = (val < 0) ? -sqrt(mag) * 0.5 : sqrt(mag) * 0.5;
34
+ /* Spread to neighbors for smooth encoding */
35
+ re[(phase + 1) % D] = sqrt(mag) * 0.25;
36
+ re[(phase + 5) % D] = sqrt(mag) * 0.25;
37
+ hpc_set_local(g, site_offset + j, re, im);
38
+ }
39
+ }
40
+
41
+ /* ── Helper: read importance from graph marginals ──
42
+ *
43
+ * The marginal probability P(site_j = dominant_phase) gives |ψ_j|²,
44
+ * which IS the activation importance for column j. No separate E[xΒ²]
45
+ * accumulation needed β€” the graph's own Born rule computes it.
46
+ */
47
+ static void hpc_read_importance(HPCGraph *g, const float *x, int64_t dim,
48
+ int64_t site_offset, float *importance,
49
+ int64_t M)
50
+ {
51
+ for (int64_t j = 0; j < dim; j++) {
52
+ float mag = fabsf(x[j]) + 1e-12f;
53
+ int phase = ((int)(mag * 1e3f)) % D;
54
+ if (phase < 0) phase += D;
55
+ /* Graph marginal = |ψ_j|² = phase-coherent importance */
56
+ double marg = hpc_marginal(g, site_offset + j, phase);
57
+ /* Modulate raw E[xΒ²] by graph coherence */
58
+ float raw = x[j] * x[j];
59
+ double boost = 1.0 + (marg * D - 1.0) * 0.5;
60
+ if (boost < 0.5) boost = 0.5;
61
+ if (boost > 2.0) boost = 2.0;
62
+ importance[j] += raw * (float)boost * M;
63
+ }
64
+ }
65
+
66
+ /* ── Helper: graph-based matmul ──
67
+ *
68
+ * Computes out = x @ W.T using standard arithmetic, BUT simultaneously
69
+ * builds an HPCGraph over input columns, CZ-couples them, and extracts
70
+ * importance via marginal probabilities.
71
+ *
72
+ * The graph encodes inter-column phase coherence: columns whose activation
73
+ * patterns are phase-aligned (coherent in the D=6 space) get boosted
74
+ * importance. This is what raw E[xΒ²] misses.
75
+ */
76
+ static void hpc_matmul_graph(const float *x, const float *weight, float *out,
77
+ float *importance, int64_t *count,
78
+ int64_t M, int64_t K, int64_t N)
79
+ {
80
+ /* Build HPCGraph over input columns for importance */
81
+ int64_t stride = (K > 512) ? K / 512 : 1;
82
+ int64_t n_sites = (K + stride - 1) / stride;
83
+ HPCGraph *g = hpc_create(n_sites);
84
+
85
+ if (g && importance) {
86
+ /* Compute per-column energies */
87
+ float *col_energy = (float *)calloc(K, sizeof(float));
88
+ #pragma omp parallel for schedule(static)
89
+ for (int64_t j = 0; j < K; j++) {
90
+ float s = 0.0f;
91
+ for (int64_t i = 0; i < M; i++) {
92
+ float v = x[i * K + j];
93
+ s += v * v;
94
+ }
95
+ col_energy[j] = s;
96
+ }
97
+
98
+ /* Encode column energies as quhit amplitudes */
99
+ for (int64_t s = 0; s < n_sites; s++) {
100
+ int64_t j = s * stride;
101
+ if (j >= K) break;
102
+ double re[D] = {0}, im[D] = {0};
103
+ float e = col_energy[j];
104
+ int phase = ((int)(e * 1e3f)) % D;
105
+ if (phase < 0) phase += D;
106
+ re[phase] = sqrt(e + 1e-12);
107
+ re[(phase + 1) % D] = sqrt(e + 1e-12) * 0.25;
108
+ re[(phase + 5) % D] = sqrt(e + 1e-12) * 0.25;
109
+ hpc_set_local(g, s, re, im);
110
+ }
111
+
112
+ /* CZ-couple adjacent sites β€” phase coherence propagation */
113
+ for (int64_t s = 0; s < n_sites - 1; s++)
114
+ hpc_cz(g, s, s + 1);
115
+
116
+ /* Read importance via graph marginals */
117
+ double fidelity = g->avg_fidelity;
118
+ for (int64_t s = 0; s < n_sites; s++) {
119
+ int64_t j0 = s * stride;
120
+ int64_t j1 = (s + 1) * stride;
121
+ if (j1 > K) j1 = K;
122
+ float e = col_energy[j0];
123
+ int phase = ((int)(e * 1e3f)) % D;
124
+ if (phase < 0) phase += D;
125
+ double marg = hpc_marginal(g, s, phase);
126
+ double boost = 1.0 + (marg * fidelity * D - 1.0) * 0.5;
127
+ if (boost < 0.5) boost = 0.5;
128
+ if (boost > 2.0) boost = 2.0;
129
+ for (int64_t j = j0; j < j1; j++)
130
+ importance[j] += col_energy[j] * (float)boost;
131
+ }
132
+ if (count) *count += M;
133
+
134
+ free(col_energy);
135
+ hpc_destroy(g);
136
+ }
137
+
138
+ /* Matmul: out = x @ W.T β€” OpenMP over rows */
139
+ #pragma omp parallel for schedule(static)
140
+ for (int64_t i = 0; i < M; i++) {
141
+ const float *xi = x + i * K;
142
+ float *oi = out + i * N;
143
+ for (int64_t n = 0; n < N; n++) {
144
+ const float *wn = weight + n * K;
145
+ float dot = 0.0f;
146
+ for (int64_t k = 0; k < K; k++)
147
+ dot += xi[k] * wn[k];
148
+ oi[n] = dot;
149
+ }
150
+ }
151
+ }
152
+
153
+ /* ── Helper: RMS norm (OpenMP) ── */
154
+ static void hpc_rms_norm(const float *x, const float *w, float *out,
155
+ int64_t seq, int64_t dim, float eps)
156
+ {
157
+ #pragma omp parallel for schedule(static)
158
+ for (int64_t i = 0; i < seq; i++) {
159
+ const float *row = x + i * dim;
160
+ float *orow = out + i * dim;
161
+ float ss = 0.0f;
162
+ for (int64_t j = 0; j < dim; j++) ss += row[j] * row[j];
163
+ float inv = 1.0f / sqrtf(ss / dim + eps);
164
+ for (int64_t j = 0; j < dim; j++) orow[j] = row[j] * inv * w[j];
165
+ }
166
+ }
167
+
168
+ /* ── Helper: SiLU activation ── */
169
+ static void hpc_silu(float *x, int64_t n)
170
+ {
171
+ #pragma omp parallel for schedule(static)
172
+ for (int64_t i = 0; i < n; i++)
173
+ x[i] = x[i] / (1.0f + expf(-x[i]));
174
+ }
175
+ /* ═══════════════════════════════════════════════════════════════════════════
176
+ * hexstate_forward_layer β€” Complete layer forward pass via HPCGraph
177
+ *
178
+ * One C call does: RMS norm β†’ QKV projection β†’ HPC linear attention β†’
179
+ * gate projection β†’ SSM (optional) β†’ FFN
180
+ *
181
+ * The HPCGraph is used for:
182
+ * 1. Importance recording: graph marginals give phase-coherent |ψ|²
183
+ * 2. Attention: CZ coupling between Q/K head sites + marginal readout
184
+ * determines per-head attention weights for the linear accumulator
185
+ * 3. Cross-head coherence: adjacent heads are CZ-coupled, so GQA
186
+ * structure emerges from the graph topology
187
+ *
188
+ * Parameters:
189
+ * hidden: [seq_len Γ— n_embd], modified in-place
190
+ * norm_w: [n_embd] attention norm weights
191
+ * qkv_w: [qkv_dim Γ— n_embd] fused QKV weights (NULL if separate)
192
+ * q_w/k_w/v_w: separate QKV weights (NULL if fused)
193
+ * gate_w: [n_embd Γ— attn_out_dim] gate/output projection
194
+ * o_w: [n_embd Γ— v_total_dim] output projection (separate path)
195
+ * ffn_norm_w: [n_embd] FFN norm weights
196
+ * ffn_gate/up/down: FFN weights
197
+ * imp_*: importance accumulators (one per weight matrix)
198
+ * cnt_*: sample counts per weight
199
+ * seq/embd/heads/hd/ffn_dim: architecture dimensions
200
+ * eps: RMS norm epsilon
201
+ * ═══════════════════════════════════════════════════════════════════════════ */
202
+ void hexstate_forward_layer(
203
+ float *hidden,
204
+ /* Attention weights */
205
+ const float *norm_w,
206
+ const float *qkv_w, int64_t qkv_dim,
207
+ const float *q_w, int64_t q_dim,
208
+ const float *k_w, int64_t k_dim,
209
+ const float *v_w, int64_t v_dim,
210
+ const float *gate_w, int64_t gate_rows,
211
+ const float *o_w, int64_t o_cols,
212
+ /* FFN weights */
213
+ const float *ffn_norm_w,
214
+ const float *ffn_gate_w, const float *ffn_up_w, const float *ffn_down_w,
215
+ int64_t ffn_dim,
216
+ /* Importance accumulators (NULL to skip) */
217
+ float *imp_qkv, int64_t *cnt_qkv,
218
+ float *imp_q, int64_t *cnt_q,
219
+ float *imp_k, int64_t *cnt_k,
220
+ float *imp_v, int64_t *cnt_v,
221
+ float *imp_gate, int64_t *cnt_gate,
222
+ float *imp_o, int64_t *cnt_o,
223
+ float *imp_ffn_gate, int64_t *cnt_ffn_gate,
224
+ float *imp_ffn_up, int64_t *cnt_ffn_up,
225
+ float *imp_ffn_down, int64_t *cnt_ffn_down,
226
+ /* Architecture */
227
+ int64_t seq_len, int64_t n_embd, int64_t n_head, int64_t n_head_kv,
228
+ int64_t head_dim, float eps)
229
+ {
230
+ float *normed = (float *)malloc(seq_len * n_embd * sizeof(float));
231
+ if (!normed) return;
232
+
233
+ /* ════════��═════ Phase 1: Attention Norm ══════════════ */
234
+ hpc_rms_norm(hidden, norm_w, normed, seq_len, n_embd, eps);
235
+
236
+ /* ══════════════ Phase 2: QKV Projection via HPC Graph ══════════════ */
237
+ float *attn_out = (float *)calloc(seq_len * n_embd, sizeof(float));
238
+ if (!attn_out) { free(normed); return; }
239
+
240
+ if (qkv_w && qkv_dim > 0) {
241
+ /* ── Fused QKV path (Qwen 3.6) ── */
242
+ float *qkv = (float *)malloc(seq_len * qkv_dim * sizeof(float));
243
+ if (!qkv) { free(normed); free(attn_out); return; }
244
+
245
+ /* Graph-based matmul: importance via HPCGraph marginals */
246
+ hpc_matmul_graph(normed, qkv_w, qkv, imp_qkv, cnt_qkv,
247
+ seq_len, n_embd, qkv_dim);
248
+
249
+ /* Split Q, K, V */
250
+ int64_t q_total = n_head * head_dim;
251
+ int64_t kv_total = n_head_kv * head_dim;
252
+ float *Q = qkv; /* [seq, q_total] */
253
+ float *K = qkv + q_total; /* offset per row */
254
+ float *V = qkv + q_total + kv_total; /* offset per row */
255
+
256
+ /* ── HPC Linear Attention: graph IS the attention ──
257
+ *
258
+ * Create HPCGraph with n_head sites.
259
+ * Each head is a site. KΒ·V interaction energy β†’ quhit amplitude.
260
+ * CZ edges between adjacent heads β†’ cross-head phase coherence.
261
+ * hpc_marginal(h) β†’ attention weight for head h.
262
+ *
263
+ * Running state S[h] accumulates KβŠ—V, weighted by coherence.
264
+ * This is causal linear attention where the HPC graph determines
265
+ * HOW MUCH each head contributes at each timestep.
266
+ */
267
+ HPCGraph *attn_graph = hpc_create(n_head);
268
+ float *S = (float *)calloc(n_head * head_dim * head_dim, sizeof(float));
269
+ float *z_acc = (float *)calloc(n_head * head_dim, sizeof(float));
270
+ int64_t inner_dim = n_head * head_dim;
271
+ float *attn_inner = (float *)calloc(seq_len * inner_dim, sizeof(float));
272
+
273
+ if (attn_graph && S && z_acc && attn_inner) {
274
+ for (int64_t t = 0; t < seq_len; t++) {
275
+ /* Extract Q/K/V for this timestep (handle strided layout) */
276
+ float *qt_base = qkv + t * qkv_dim;
277
+ float *kt_base = qt_base + q_total;
278
+ float *vt_base = kt_base + kv_total;
279
+
280
+ /* Encode KΒ·V energy into graph sites */
281
+ for (int64_t h = 0; h < n_head; h++) {
282
+ int64_t kv_h = h % n_head_kv; /* GQA mapping */
283
+ float *kh = kt_base + kv_h * head_dim;
284
+ float *vh = vt_base + kv_h * head_dim;
285
+ float energy = 0.0f;
286
+ for (int64_t d = 0; d < head_dim; d++)
287
+ energy += kh[d] * vh[d];
288
+
289
+ /* Triality encode energy β†’ D=6 quhit amplitude */
290
+ double re[D] = {0}, im[D] = {0};
291
+ float ae = fabsf(energy) + 1e-6f;
292
+ int ph = ((int)(ae * 100.0f)) % D;
293
+ re[ph] = sqrt(ae);
294
+ im[ph] = (energy < 0) ? -sqrt(ae) * 0.5 : sqrt(ae) * 0.5;
295
+ re[(ph+1)%D] = sqrt(ae) * 0.2;
296
+ re[(ph+5)%D] = sqrt(ae) * 0.2;
297
+ hpc_set_local(attn_graph, h, re, im);
298
+ }
299
+
300
+ /* CZ-couple adjacent heads: creates cross-head entanglement */
301
+ for (int64_t h = 0; h < n_head - 1; h++)
302
+ hpc_cz(attn_graph, h, h + 1);
303
+
304
+ /* Compute attention output per head using graph marginals */
305
+ #pragma omp parallel for schedule(static)
306
+ for (int64_t h = 0; h < n_head; h++) {
307
+ int64_t kv_h = h % n_head_kv;
308
+ float *qh = qt_base + h * head_dim;
309
+ float *kh = kt_base + kv_h * head_dim;
310
+ float *vh = vt_base + kv_h * head_dim;
311
+ float *Sh = S + h * head_dim * head_dim;
312
+ float *zh = z_acc + h * head_dim;
313
+
314
+ /* Get HPC marginal: phase-coherent weight for this head */
315
+ float ae = 0.0f;
316
+ for (int64_t d = 0; d < head_dim; d++)
317
+ ae += fabsf(kh[d] * vh[d]);
318
+ ae += 1e-6f;
319
+ int ph = ((int)(ae * 100.0f)) % D;
320
+ double coherence_raw = hpc_marginal(attn_graph, h, ph);
321
+ float coherence = (float)(coherence_raw * D);
322
+ if (coherence < 0.1f) coherence = 0.1f;
323
+ if (coherence > 3.0f) coherence = 3.0f;
324
+
325
+ /* Feature map: Ο†(x) = max(x,0) + Ξ΅ */
326
+ float qf[256], kf[256];
327
+ for (int64_t d = 0; d < head_dim; d++) {
328
+ qf[d] = (qh[d] > 0 ? qh[d] : 0) + 1e-6f;
329
+ kf[d] = (kh[d] > 0 ? kh[d] : 0) + 1e-6f;
330
+ }
331
+
332
+ /* Accumulate: S += coherence Γ— outer(kf, v) */
333
+ for (int64_t d1 = 0; d1 < head_dim; d1++) {
334
+ float ks = kf[d1] * coherence;
335
+ for (int64_t d2 = 0; d2 < head_dim; d2++)
336
+ Sh[d1 * head_dim + d2] += ks * vh[d2];
337
+ }
338
+ for (int64_t d = 0; d < head_dim; d++)
339
+ zh[d] += kf[d] * coherence;
340
+
341
+ /* Output: (qf @ S) / (qf Β· z) */
342
+ float den = 1e-8f;
343
+ for (int64_t d = 0; d < head_dim; d++)
344
+ den += qf[d] * zh[d];
345
+ float inv_den = 1.0f / den;
346
+
347
+ /* Write to attn_inner at position [t, h*head_dim ... ] */
348
+ float *ao = attn_inner + t * inner_dim;
349
+ for (int64_t d2 = 0; d2 < head_dim; d2++) {
350
+ float num = 0.0f;
351
+ for (int64_t d1 = 0; d1 < head_dim; d1++)
352
+ num += qf[d1] * Sh[d1 * head_dim + d2];
353
+ /* Accumulate into attn_inner (multiple heads write here) */
354
+ ao[h * head_dim + d2] = num * inv_den;
355
+ }
356
+ }
357
+
358
+ /* Compact graph edges periodically */
359
+ if (t > 0 && t % 64 == 0)
360
+ hpc_compact_edges(attn_graph);
361
+ }
362
+ }
363
+
364
+ /* Gate projection if present */
365
+ if (gate_w && gate_rows > 0) {
366
+ /* attn_inner is [seq, n_head*head_dim], gate_w is [gate_rows, n_head*head_dim] */
367
+ float *gated = (float *)malloc(seq_len * n_embd * sizeof(float));
368
+ if (gated) {
369
+ hpc_matmul_graph(attn_inner, gate_w, gated, imp_gate, cnt_gate,
370
+ seq_len, inner_dim, gate_rows);
371
+ for (int64_t t = 0; t < seq_len; t++) {
372
+ int64_t copy_dim = gate_rows < n_embd ? gate_rows : n_embd;
373
+ memcpy(attn_out + t * n_embd, gated + t * gate_rows, copy_dim * sizeof(float));
374
+ }
375
+ free(gated);
376
+ }
377
+ } else {
378
+ for (int64_t t = 0; t < seq_len; t++) {
379
+ int64_t copy_dim = inner_dim < n_embd ? inner_dim : n_embd;
380
+ memcpy(attn_out + t * n_embd, attn_inner + t * inner_dim, copy_dim * sizeof(float));
381
+ }
382
+ }
383
+ if (attn_inner) free(attn_inner);
384
+
385
+ if (attn_graph) hpc_destroy(attn_graph);
386
+ free(S); free(z_acc); free(qkv);
387
+
388
+ } else if (q_w && k_w && v_w && o_w) {
389
+ /* ── Separate QKV path (standard transformer) ── */
390
+ float *Q = (float *)malloc(seq_len * q_dim * sizeof(float));
391
+ float *K_buf = (float *)malloc(seq_len * k_dim * sizeof(float));
392
+ float *V_buf = (float *)malloc(seq_len * v_dim * sizeof(float));
393
+ if (!Q || !K_buf || !V_buf) {
394
+ free(Q); free(K_buf); free(V_buf);
395
+ free(normed); free(attn_out);
396
+ return;
397
+ }
398
+
399
+ hpc_matmul_graph(normed, q_w, Q, imp_q, cnt_q, seq_len, n_embd, q_dim);
400
+ hpc_matmul_graph(normed, k_w, K_buf, imp_k, cnt_k, seq_len, n_embd, k_dim);
401
+ hpc_matmul_graph(normed, v_w, V_buf, imp_v, cnt_v, seq_len, n_embd, v_dim);
402
+
403
+ /* Same HPC attention as above but with separate Q/K/V buffers */
404
+ int64_t hd_q = q_dim / n_head;
405
+ int64_t hd_kv = k_dim / n_head_kv;
406
+ int64_t inner_dim = n_head * hd_kv;
407
+ HPCGraph *attn_graph = hpc_create(n_head);
408
+ float *S = (float *)calloc(n_head * hd_kv * hd_kv, sizeof(float));
409
+ float *z_acc = (float *)calloc(n_head * hd_kv, sizeof(float));
410
+ float *attn_inner = (float *)calloc(seq_len * inner_dim, sizeof(float));
411
+
412
+ if (attn_graph && S && z_acc && attn_inner) {
413
+ for (int64_t t = 0; t < seq_len; t++) {
414
+ /* Encode heads into graph */
415
+ for (int64_t h = 0; h < n_head; h++) {
416
+ int64_t kv_h = h % n_head_kv;
417
+ float *kh = K_buf + t * k_dim + kv_h * hd_kv;
418
+ float *vh = V_buf + t * v_dim + kv_h * hd_kv;
419
+ float energy = 0.0f;
420
+ for (int64_t d = 0; d < hd_kv; d++)
421
+ energy += kh[d] * vh[d];
422
+ double re[D] = {0}, im[D] = {0};
423
+ float ae = fabsf(energy) + 1e-6f;
424
+ int ph = ((int)(ae * 100.0f)) % D;
425
+ re[ph] = sqrt(ae);
426
+ im[ph] = (energy < 0) ? -sqrt(ae)*0.5 : sqrt(ae)*0.5;
427
+ hpc_set_local(attn_graph, h, re, im);
428
+ }
429
+ for (int64_t h = 0; h < n_head - 1; h++)
430
+ hpc_cz(attn_graph, h, h+1);
431
+
432
+ #pragma omp parallel for schedule(static)
433
+ for (int64_t h = 0; h < n_head; h++) {
434
+ int64_t kv_h = h % n_head_kv;
435
+ float *qh = Q + t * q_dim + h * hd_q;
436
+ float *kh = K_buf + t * k_dim + kv_h * hd_kv;
437
+ float *vh = V_buf + t * v_dim + kv_h * hd_kv;
438
+ float *Sh = S + h * hd_kv * hd_kv;
439
+ float *zh = z_acc + h * hd_kv;
440
+ int64_t feat = hd_q < hd_kv ? hd_q : hd_kv;
441
+
442
+ float ae = fabsf(kh[0]*vh[0]) + 1e-6f;
443
+ int ph = ((int)(ae * 100.0f)) % D;
444
+ double coh_raw = hpc_marginal(attn_graph, h, ph);
445
+ float coh = (float)(coh_raw * D);
446
+ if (coh < 0.1f) coh = 0.1f;
447
+ if (coh > 3.0f) coh = 3.0f;
448
+
449
+ for (int64_t d1 = 0; d1 < feat; d1++) {
450
+ float kf = (kh[d1] > 0 ? kh[d1] : 0) + 1e-6f;
451
+ float ks = kf * coh;
452
+ for (int64_t d2 = 0; d2 < hd_kv; d2++)
453
+ Sh[d1*hd_kv+d2] += ks * vh[d2];
454
+ zh[d1] += kf * coh;
455
+ }
456
+
457
+ float den = 1e-8f;
458
+ for (int64_t d = 0; d < feat; d++) {
459
+ float qf = (qh[d] > 0 ? qh[d] : 0) + 1e-6f;
460
+ den += qf * zh[d];
461
+ }
462
+ float inv_den = 1.0f / den;
463
+ float *ao = attn_inner + t * inner_dim;
464
+ for (int64_t d2 = 0; d2 < hd_kv; d2++) {
465
+ float num = 0.0f;
466
+ for (int64_t d1 = 0; d1 < feat; d1++) {
467
+ float qf = (qh[d1] > 0 ? qh[d1] : 0) + 1e-6f;
468
+ num += qf * Sh[d1*hd_kv+d2];
469
+ }
470
+ ao[h*hd_kv+d2] = num * inv_den;
471
+ }
472
+ }
473
+ if (t > 0 && t % 64 == 0)
474
+ hpc_compact_edges(attn_graph);
475
+ }
476
+ }
477
+
478
+ /* Output projection */
479
+ if (o_w && o_cols > 0) {
480
+ float *proj_in = attn_inner;
481
+ int free_proj_in = 0;
482
+ if (inner_dim != o_cols) {
483
+ proj_in = (float *)calloc(seq_len * o_cols, sizeof(float));
484
+ if (proj_in) {
485
+ for (int64_t t = 0; t < seq_len; t++) {
486
+ int64_t copy_dim = inner_dim < o_cols ? inner_dim : o_cols;
487
+ memcpy(proj_in + t * o_cols, attn_inner + t * inner_dim, copy_dim * sizeof(float));
488
+ }
489
+ free_proj_in = 1;
490
+ } else {
491
+ proj_in = attn_inner;
492
+ }
493
+ }
494
+
495
+ float *projected = (float *)calloc(seq_len * n_embd, sizeof(float));
496
+ if (projected) {
497
+ hpc_matmul_graph(proj_in, o_w, projected, imp_o, cnt_o,
498
+ seq_len, o_cols, n_embd);
499
+ memcpy(attn_out, projected, seq_len * n_embd * sizeof(float));
500
+ free(projected);
501
+ }
502
+ if (free_proj_in && proj_in != attn_inner) free(proj_in);
503
+ } else {
504
+ for (int64_t t = 0; t < seq_len; t++) {
505
+ int64_t copy_dim = inner_dim < n_embd ? inner_dim : n_embd;
506
+ memcpy(attn_out + t * n_embd, attn_inner + t * inner_dim, copy_dim * sizeof(float));
507
+ }
508
+ }
509
+ if (attn_inner) free(attn_inner);
510
+
511
+ if (attn_graph) hpc_destroy(attn_graph);
512
+ free(S); free(z_acc);
513
+ free(Q); free(K_buf); free(V_buf);
514
+ }
515
+
516
+ /* Residual add: hidden += attn_out */
517
+ int64_t total = seq_len * n_embd;
518
+ #pragma omp parallel for schedule(static)
519
+ for (int64_t i = 0; i < total; i++)
520
+ hidden[i] += attn_out[i];
521
+
522
+ /* ══════════════ Phase 3: FFN ══════════════ */
523
+ if (ffn_norm_w && ffn_gate_w && ffn_up_w && ffn_down_w && ffn_dim > 0) {
524
+ float *normed_ff = (float *)malloc(seq_len * n_embd * sizeof(float));
525
+ float *gate_out = (float *)malloc(seq_len * ffn_dim * sizeof(float));
526
+ float *up_out = (float *)malloc(seq_len * ffn_dim * sizeof(float));
527
+
528
+ if (normed_ff && gate_out && up_out) {
529
+ hpc_rms_norm(hidden, ffn_norm_w, normed_ff, seq_len, n_embd, eps);
530
+
531
+ /* Graph-based matmul for FFN with importance */
532
+ hpc_matmul_graph(normed_ff, ffn_gate_w, gate_out,
533
+ imp_ffn_gate, cnt_ffn_gate, seq_len, n_embd, ffn_dim);
534
+ hpc_matmul_graph(normed_ff, ffn_up_w, up_out,
535
+ imp_ffn_up, cnt_ffn_up, seq_len, n_embd, ffn_dim);
536
+
537
+ /* SiLU(gate) * up */
538
+ hpc_silu(gate_out, seq_len * ffn_dim);
539
+ #pragma omp parallel for schedule(static)
540
+ for (int64_t i = 0; i < seq_len * ffn_dim; i++)
541
+ gate_out[i] *= up_out[i];
542
+
543
+ /* Down projection: graph-based importance recording */
544
+ float *ff_out = (float *)malloc(seq_len * n_embd * sizeof(float));
545
+ if (ff_out) {
546
+ hpc_matmul_graph(gate_out, ffn_down_w, ff_out,
547
+ imp_ffn_down, cnt_ffn_down,
548
+ seq_len, ffn_dim, n_embd);
549
+ /* Residual add */
550
+ #pragma omp parallel for schedule(static)
551
+ for (int64_t i = 0; i < total; i++)
552
+ hidden[i] += ff_out[i];
553
+ free(ff_out);
554
+ }
555
+ }
556
+
557
+ free(normed_ff); free(gate_out); free(up_out);
558
+ }
559
+
560
+ free(normed);
561
+ free(attn_out);
562
+ }