Skip to main content

qualia_core_db/q42/p64_weight/
compiler.rs

1//! GGUF -> P64 **compiler / builder**: `compile_gguf_to_p64*` (verbatim / f16-expand / Q4_K SoA),
2//! the FFN-quantized AWQ compilers (ternary / Q4_0), the legacy compiler, and their historical
3//! `_q42` aliases, plus the compile-time helpers (`p64_tensor_name`, f16 blob expansion).
4
5use super::*;
6use crate::container_10d::crc32c::crc32c;
7use crate::gguf_sharder::{GgufTensorIndex, GgufTensorInfo};
8
9fn p64_tensor_name(role: u16, layer: u16, source_name_hash: u64) -> String {
10    if layer == P64_LAYER_GLOBAL {
11        return match role {
12            P64_ROLE_TOKEN_EMBD => "token_embd.weight".to_string(),
13            P64_ROLE_OUTPUT => "output.weight".to_string(),
14            P64_ROLE_OUTPUT_NORM => "output_norm.weight".to_string(),
15            _ => format!("tensor.{source_name_hash:016x}"),
16        };
17    }
18    match p64_role_suffix(role) {
19        Some(suffix) => format!("blk.{layer}.{}", String::from_utf8_lossy(suffix)),
20        None => format!("tensor.{source_name_hash:016x}"),
21    }
22}
23
24/// Conversion-time weight layout policy for [`compile_gguf_to_p64_with_layout`].
25///
26/// The designed product path is: import GGUF once → store GPU-friendly bytes in `.p64`.
27/// [`P64ConvertLayout::Verbatim`] is the historical byte-preserving container swap
28/// (same kernels, same speed). [`P64ConvertLayout::F16Expand`] dequantizes 2-D weight
29/// matrices to IEEE f16 so decode can use the fast `unpack2x16float` path.
30/// [`P64ConvertLayout::Q4kSoa`] rewrites Q4_K matrices to a 160 B/superblock SoA with
31/// pre-expanded f16 sub-scales (decode GEMV skips scale unpack + header barriers).
32#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
33pub enum P64ConvertLayout {
34    /// Copy GGML quant blocks byte-for-byte (no speed change vs running the GGUF).
35    #[default]
36    Verbatim,
37    /// Expand 2-D matrices (attn/FFN/embd/output) to f16; leave 1-D norms as source.
38    /// Rejected if the result would exceed the 4 GiB u32-offset container limit.
39    F16Expand,
40    /// Convert 2-D Q4_K weight matrices to [`crate::ggml_quants::GGML_TYPE_Q4_K_SOA`].
41    /// Other tensors stay verbatim. ~11% larger than Q4_K; aimed at 3B-class decode.
42    Q4kSoa,
43}
44
45/// Compile a GGUF image into the cache-line-native P64 container (verbatim layout).
46///
47/// Every GGUF tensor is retained. Known inference tensors receive a semantic
48/// role/layer; unknown tensors receive [`P64_ROLE_UNKNOWN`] but retain their
49/// source name hash and source byte offset. Each tensor starts on a hardware
50/// page boundary and has an in-band CRC-32C. The metadata, tokenizer and 10D
51/// manifold table share a separate CRC, validated before any blob is exposed.
52pub fn compile_gguf_to_p64(input: &[u8], page_log2: u16) -> Result<Vec<u8>, String> {
53    compile_gguf_to_p64_with_layout(input, page_log2, P64ConvertLayout::Verbatim)
54}
55
56/// Like [`compile_gguf_to_p64`] but selects a conversion-time layout policy.
57pub fn compile_gguf_to_p64_with_layout(
58    input: &[u8],
59    page_log2: u16,
60    layout: P64ConvertLayout,
61) -> Result<Vec<u8>, String> {
62    let index = GgufTensorIndex::from_gguf(input);
63    if index.tensor_data_start == 0 || index.entries.is_empty() {
64        return Err("p64: GGUF parse yielded no tensors".to_string());
65    }
66    let page_log2 = if page_log2 == 0 {
67        P64_DEFAULT_PAGE_LOG2
68    } else {
69        page_log2
70    };
71    if !(8..=30).contains(&page_log2) {
72        return Err(format!("p64: page_log2 {page_log2} out of range"));
73    }
74    let page = 1usize << page_log2;
75    let tensor_data_start = index.tensor_data_start as usize;
76
77    // (role, layer, source-name hash, source tensor info)
78    let mut planned: Vec<(u16, u16, u64, GgufTensorInfo)> = Vec::with_capacity(index.entries.len());
79    let mut push_known = |role: u16, layer: u16, candidate: Option<GgufTensorInfo>| {
80        if let Some(info) = candidate {
81            if planned
82                .iter()
83                .any(|(_, _, _, existing)| existing.byte_offset == info.byte_offset)
84            {
85                return;
86            }
87            let name_hash = index
88                .entries
89                .iter()
90                .find(|(_, source)| source.byte_offset == info.byte_offset)
91                .map(|(hash, _)| *hash)
92                .unwrap_or(0);
93            planned.push((role, layer, name_hash, info));
94        }
95    };
96    for layer in 0..index.hyperparams.n_layer {
97        let tensors = index.get_layer_tensors(layer);
98        let layer = u16::try_from(layer).map_err(|_| "p64: layer index exceeds u16")?;
99        push_known(P64_ROLE_ATTN_NORM, layer, tensors.attn_norm);
100        push_known(P64_ROLE_ATTN_Q, layer, tensors.attn_q);
101        push_known(P64_ROLE_ATTN_K, layer, tensors.attn_k);
102        push_known(P64_ROLE_ATTN_V, layer, tensors.attn_v);
103        push_known(P64_ROLE_ATTN_OUTPUT, layer, tensors.attn_output);
104        push_known(P64_ROLE_FFN_NORM, layer, tensors.ffn_norm);
105        push_known(P64_ROLE_FFN_GATE, layer, tensors.ffn_gate);
106        push_known(P64_ROLE_FFN_UP, layer, tensors.ffn_up);
107        push_known(P64_ROLE_FFN_DOWN, layer, tensors.ffn_down);
108    }
109    push_known(
110        P64_ROLE_TOKEN_EMBD,
111        P64_LAYER_GLOBAL,
112        index.token_embd_info().copied(),
113    );
114    push_known(
115        P64_ROLE_OUTPUT,
116        P64_LAYER_GLOBAL,
117        index.output_weight_info().copied(),
118    );
119    push_known(
120        P64_ROLE_OUTPUT_NORM,
121        P64_LAYER_GLOBAL,
122        index.output_norm_info().copied(),
123    );
124    for (name_hash, info) in &index.entries {
125        if !planned
126            .iter()
127            .any(|(_, _, _, existing)| existing.byte_offset == info.byte_offset)
128        {
129            planned.push((P64_ROLE_UNKNOWN, P64_LAYER_GLOBAL, *name_hash, *info));
130        }
131    }
132    // Keep **layer-major** order for known roles (built above). Sorting by GGUF
133    // source offset used to destroy sequential layer packing and hurt residency.
134    // Unknown tensors trail, ordered by source offset for stable CRC layout only.
135    let mut unknowns: Vec<_> = planned
136        .iter()
137        .copied()
138        .filter(|(role, _, _, _)| *role == P64_ROLE_UNKNOWN)
139        .collect();
140    unknowns.sort_by_key(|(_, _, _, info)| info.byte_offset);
141    planned.retain(|(role, _, _, _)| *role != P64_ROLE_UNKNOWN);
142    planned.extend(unknowns);
143
144    let mut string_table = vec![0u8];
145    let mut name_offsets = Vec::with_capacity(planned.len());
146    for (role, layer, name_hash, _) in &planned {
147        let name_offset =
148            u32::try_from(string_table.len()).map_err(|_| "p64: string table exceeds 4 GiB")?;
149        name_offsets.push(name_offset);
150        let name = p64_tensor_name(*role, *layer, *name_hash);
151        string_table.extend_from_slice(name.as_bytes());
152        string_table.push(0);
153    }
154    let tokenizer = crate::gguf_sharder::GgufTokenizer::from_gguf(input).to_p64_section();
155    let manifold_count = index
156        .hyperparams
157        .n_layer
158        .checked_add(1)
159        .ok_or("p64: manifold count overflow")? as usize;
160
161    let hparams_offset = P64_WEIGHT_HEADER_BYTES;
162    let n_layer_u = index.hyperparams.n_layer as usize;
163    // Layer schedule sits immediately after hparams (pipeline residency map).
164    let schedule_offset = align_up(hparams_offset + 64, 64);
165    let schedule_bytes = n_layer_u
166        .checked_mul(core::mem::size_of::<P64LayerScheduleEntry>())
167        .ok_or("p64: schedule overflow")?;
168    let tensor_table_offset = align_up(schedule_offset + schedule_bytes, 64);
169    let tensor_table_bytes = planned
170        .len()
171        .checked_mul(P64_TENSOR_ENTRY_BYTES)
172        .ok_or("p64: tensor table overflow")?;
173    let string_table_offset = tensor_table_offset + tensor_table_bytes;
174    let manifold_table_offset = align_up(string_table_offset + string_table.len(), 64);
175    let manifold_bytes = manifold_count
176        .checked_mul(P64_MANIFOLD_ENTRY_BYTES)
177        .ok_or("p64: manifold table overflow")?;
178    let tokenizer_offset = align_up(manifold_table_offset + manifold_bytes, 64);
179    let checksum_offset = align_up(tokenizer_offset + tokenizer.len(), 64);
180    let checksum_bytes = planned
181        .len()
182        .checked_add(1)
183        .and_then(|count| count.checked_mul(4))
184        .ok_or("p64: checksum table overflow")?;
185    let blob_region_offset = align_up(checksum_offset + checksum_bytes, page);
186
187    let mut entries = Vec::with_capacity(planned.len());
188    // Parallel to `entries`: conversion kind for the blob write pass.
189    #[derive(Clone, Copy)]
190    enum BlobKind {
191        Copy,
192        F16Expand,
193        Q4kSoa,
194        Q4kSoaRequant,
195    }
196    let mut blob_kind: Vec<BlobKind> = Vec::with_capacity(planned.len());
197    let mut cursor = blob_region_offset;
198    for (position, (role, layer, name_hash, info)) in planned.iter().enumerate() {
199        let source_blob_size = crate::ggml_quants::tensor_byte_len(info)
200            .ok_or_else(|| format!("p64: unsupported GGML type {}", info.ggml_type))?;
201        let source_start = tensor_data_start
202            .checked_add(info.byte_offset as usize)
203            .ok_or("p64: source tensor offset overflow")?;
204        let source_end = source_start
205            .checked_add(source_blob_size)
206            .ok_or("p64: source tensor length overflow")?;
207        if source_end > input.len() {
208            return Err(format!("p64: source tensor {position} is out of bounds"));
209        }
210
211        let do_f16 = matches!(layout, P64ConvertLayout::F16Expand)
212            && p64_role_is_weight_matrix(*role)
213            && info.n_dims >= 2
214            && info.ggml_type != crate::ggml_quants::GGML_TYPE_F16
215            && info.ggml_type != crate::ggml_quants::GGML_TYPE_F32;
216        let do_soa = matches!(layout, P64ConvertLayout::Q4kSoa)
217            && p64_role_is_weight_matrix(*role)
218            && info.n_dims >= 2;
219        // Q4_K source → direct SoA expand (lossless layout transform).
220        // Non-Q4_K source → dequant to f32 then re-quantize to Q4_K_SOA.
221        let do_soa_requant = do_soa && info.ggml_type != crate::ggml_quants::GGML_TYPE_Q4_K;
222        let do_soa = do_soa && !do_soa_requant;
223        let (out_dtype, blob_size, kind) = if do_f16 {
224            let n0 = info.dims[0] as usize;
225            let n1 = info.dims[1] as usize;
226            let elems = n0
227                .checked_mul(n1)
228                .ok_or("p64: f16 expand element count overflow")?;
229            let bytes = elems
230                .checked_mul(2)
231                .ok_or("p64: f16 expand byte count overflow")?;
232            (
233                crate::ggml_quants::GGML_TYPE_F16 as u16,
234                bytes,
235                BlobKind::F16Expand,
236            )
237        } else if do_soa || do_soa_requant {
238            let n0 = info.dims[0] as usize;
239            let n1 = info.dims[1].max(1) as usize;
240            let bytes =
241                crate::ggml_quants::ggml_row_bytes(crate::ggml_quants::GGML_TYPE_Q4_K_SOA, n0)
242                    .and_then(|r| r.checked_mul(n1))
243                    .ok_or("p64: Q4_K SoA size overflow")?;
244            let kind = if do_soa_requant {
245                BlobKind::Q4kSoaRequant
246            } else {
247                BlobKind::Q4kSoa
248            };
249            (crate::ggml_quants::GGML_TYPE_Q4_K_SOA as u16, bytes, kind)
250        } else {
251            (
252                u16::try_from(info.ggml_type).map_err(|_| "p64: GGML type exceeds u16")?,
253                source_blob_size,
254                BlobKind::Copy,
255            )
256        };
257
258        // Pipeline packing: page-align only at **layer boundaries** (and first blob).
259        // Within a layer, 256-byte align — cuts ~page waste × tensors/layer (decode residency
260        // and CUDA multi-weight fill walk contiguous layer ranges).
261        let pack_align = if position == 0 {
262            page
263        } else {
264            let prev_layer = planned[position - 1].1;
265            if *layer != prev_layer {
266                page
267            } else {
268                256
269            }
270        };
271        cursor = align_up(cursor, pack_align);
272        let mut dimensions = [0u32; 4];
273        for (target, source) in dimensions.iter_mut().zip(info.dims) {
274            *target = u32::try_from(source).map_err(|_| "p64: tensor dimension exceeds u32")?;
275        }
276        let manifold_idx = if *layer == P64_LAYER_GLOBAL {
277            index.hyperparams.n_layer
278        } else {
279            *layer as u32
280        };
281        entries.push(P64TensorEntry {
282            name_offset: name_offsets[position],
283            role_id: *role,
284            dtype: out_dtype,
285            manifold_idx,
286            rank: info.n_dims,
287            dimensions,
288            blob_offset: u32::try_from(cursor).map_err(|_| "p64: container exceeds 4 GiB")?,
289            blob_size: u32::try_from(blob_size).map_err(|_| "p64: tensor exceeds 4 GiB")?,
290            source_offset: info.byte_offset,
291            source_name_hash: *name_hash,
292            alt_dtype: 0,
293            precision_views_mask: 0,
294            alt_blob_offset: 0,
295        });
296        blob_kind.push(kind);
297        cursor = cursor
298            .checked_add(blob_size)
299            .ok_or("p64: container size overflow")?;
300    }
301    let total_size = align_up(cursor, 64);
302    if total_size > u32::MAX as usize {
303        return Err("p64: 32-bit relative-offset container exceeds 4 GiB".to_string());
304    }
305
306    let mut flags = P64_FLAG_LITTLE_ENDIAN
307        | P64_FLAG_LAYER_MAJOR
308        | P64_FLAG_LAYER_PACK
309        | P64_FLAG_LAYER_SCHEDULE;
310    if matches!(layout, P64ConvertLayout::Q4kSoa)
311        && blob_kind
312            .iter()
313            .any(|k| matches!(k, BlobKind::Q4kSoa | BlobKind::Q4kSoaRequant))
314    {
315        flags |= P64_FLAG_Q4K_SOA;
316    }
317    // Build per-layer blob ranges for the schedule table (decode/CUDA residency).
318    let mut schedule = vec![P64LayerScheduleEntry::default(); n_layer_u];
319    for (i, s) in schedule.iter_mut().enumerate() {
320        s.layer = i as u32;
321        s.blob_begin = u32::MAX;
322        s.blob_end = 0;
323    }
324    for e in &entries {
325        let li = e.manifold_idx as usize;
326        if li >= n_layer_u {
327            continue; // globals
328        }
329        let s = &mut schedule[li];
330        s.blob_begin = s.blob_begin.min(e.blob_offset);
331        s.blob_end = s.blob_end.max(e.blob_offset.saturating_add(e.blob_size));
332        s.tensor_count = s.tensor_count.saturating_add(1);
333        if e.role_id < 16 {
334            s.roles_mask |= 1u16 << e.role_id;
335        }
336    }
337    for s in &mut schedule {
338        if s.blob_begin == u32::MAX {
339            s.blob_begin = 0;
340            s.blob_end = 0;
341        }
342    }
343    let header = P64WeightHeader {
344        magic: P64_MAGIC,
345        version: P64_VERSION,
346        flags,
347        role_table_offset: schedule_offset as u32, // layer schedule (not a role string table)
348        tensor_table_offset: tensor_table_offset as u32,
349        tokenizer_offset: tokenizer_offset as u32,
350        hparams_offset: hparams_offset as u32,
351        string_table_offset: string_table_offset as u32,
352        checksum_offset: checksum_offset as u32,
353        manifold_table_offset: manifold_table_offset as u32,
354        tensor_count: entries.len() as u32,
355        page_size: page as u32,
356        reserved: [0; 20],
357    };
358    let hp = P64HParams {
359        n_layer: index.hyperparams.n_layer,
360        n_embd: index.hyperparams.n_embd,
361        n_head: index.hyperparams.n_head,
362        n_kv_head: index.hyperparams.effective_n_kv_head(),
363        vocab_size: index.vocab_dim() as u32,
364        rope_freq_base: index.hyperparams.effective_rope_freq_base(),
365        rope_scale: index.hyperparams.effective_rope_scale(),
366        head_dim: index.hyperparams.head_dim,
367        head_dim_swa: index.hyperparams.head_dim_swa,
368        sliding_window: index.hyperparams.sliding_window,
369        shared_kv_layers: index.hyperparams.shared_kv_layers,
370        logit_softcap: index.hyperparams.logit_softcap,
371        architecture: index.hyperparams.architecture,
372        arch_flags: index.hyperparams.arch_flags,
373        reserved: [0; 8],
374    };
375
376    let mut output = vec![0u8; total_size];
377    header.write_le(&mut output[..P64_WEIGHT_HEADER_BYTES]);
378    hp.write_le(&mut output[hparams_offset..hparams_offset + 64]);
379    for (i, s) in schedule.iter().enumerate() {
380        let start = schedule_offset + i * core::mem::size_of::<P64LayerScheduleEntry>();
381        let dest = &mut output[start..start + 64];
382        dest.fill(0);
383        dest[0..4].copy_from_slice(&s.layer.to_le_bytes());
384        dest[4..8].copy_from_slice(&s.blob_begin.to_le_bytes());
385        dest[8..12].copy_from_slice(&s.blob_end.to_le_bytes());
386        dest[12..14].copy_from_slice(&s.tensor_count.to_le_bytes());
387        dest[14..16].copy_from_slice(&s.roles_mask.to_le_bytes());
388    }
389    for (position, entry) in entries.iter().enumerate() {
390        let start = tensor_table_offset + position * P64_TENSOR_ENTRY_BYTES;
391        write_tensor_entry(entry, &mut output[start..start + P64_TENSOR_ENTRY_BYTES]);
392    }
393    output[string_table_offset..string_table_offset + string_table.len()]
394        .copy_from_slice(&string_table);
395    for layer in 0..manifold_count {
396        let coordinate = crate::modalities::manifold::ManifoldCoordinate10D::from_sequential_layer(
397            layer.min(index.hyperparams.n_layer as usize) as u32,
398            index.hyperparams.n_layer.max(1),
399        );
400        let start = manifold_table_offset + layer * P64_MANIFOLD_ENTRY_BYTES;
401        write_manifold_coordinate(
402            &coordinate,
403            &mut output[start..start + P64_MANIFOLD_ENTRY_BYTES],
404        );
405    }
406    output[tokenizer_offset..tokenizer_offset + tokenizer.len()].copy_from_slice(&tokenizer);
407
408    for (position, entry) in entries.iter().enumerate() {
409        let target_start = entry.blob_offset as usize;
410        let target_end = target_start + entry.blob_size as usize;
411        match blob_kind[position] {
412            BlobKind::F16Expand => {
413                let info = &planned[position].3;
414                let source_blob_size = crate::ggml_quants::tensor_byte_len(info)
415                    .ok_or("p64: f16 expand missing source size")?;
416                let source_start = tensor_data_start + entry.source_offset as usize;
417                let source_end = source_start + source_blob_size;
418                let raw = &input[source_start..source_end];
419                expand_tensor_to_f16_blob(raw, info, &mut output[target_start..target_end])?;
420            }
421            BlobKind::Q4kSoa => {
422                let info = &planned[position].3;
423                let source_blob_size = crate::ggml_quants::tensor_byte_len(info)
424                    .ok_or("p64: Q4_K SoA missing source size")?;
425                let source_start = tensor_data_start + entry.source_offset as usize;
426                let source_end = source_start + source_blob_size;
427                let raw = &input[source_start..source_end];
428                let n0 = info.dims[0] as usize;
429                let n1 = info.dims[1].max(1) as usize;
430                crate::ggml_quants::expand_q4k_tensor_to_soa(
431                    raw,
432                    n0,
433                    n1,
434                    &mut output[target_start..target_end],
435                )
436                .map_err(|e| format!("p64: Q4_K SoA expand: {e:?}"))?;
437            }
438            BlobKind::Q4kSoaRequant => {
439                let info = &planned[position].3;
440                let source_blob_size = crate::ggml_quants::tensor_byte_len(info)
441                    .ok_or("p64: Q4_K SoA requant missing source size")?;
442                let source_start = tensor_data_start + entry.source_offset as usize;
443                let source_end = source_start + source_blob_size;
444                let raw = &input[source_start..source_end];
445                let n0 = info.dims[0] as usize;
446                let n1 = info.dims[1].max(1) as usize;
447                let total_elems = n0
448                    .checked_mul(n1)
449                    .ok_or("p64: Q4_K SoA requant element count overflow")?;
450                // Dequantize source → f32, then re-quantize f32 → Q4_K_SOA.
451                let mut f32_buf: Vec<f32> = vec![0.0f32; total_elems];
452                crate::ggml_quants::dequantize_row_into(
453                    raw,
454                    info.ggml_type,
455                    total_elems,
456                    &mut f32_buf,
457                )
458                .map_err(|e| format!("p64: Q4_K SoA requant dequant: {e:?}"))?;
459                crate::ggml_quants::quantize_f32_to_q4_k_soa_tensor(
460                    &f32_buf,
461                    n0,
462                    n1,
463                    &mut output[target_start..target_end],
464                )
465                .map_err(|e| format!("p64: Q4_K SoA requant: {e:?}"))?;
466            }
467            BlobKind::Copy => {
468                let source_start = tensor_data_start + entry.source_offset as usize;
469                let source_end = source_start + entry.blob_size as usize;
470                output[target_start..target_end].copy_from_slice(&input[source_start..source_end]);
471            }
472        }
473        let crc = crc32c(&output[target_start..target_end]);
474        let crc_start = checksum_offset + 4 + position * 4;
475        output[crc_start..crc_start + 4].copy_from_slice(&crc.to_le_bytes());
476    }
477    let metadata_crc = crc32c(&output[..checksum_offset]);
478    output[checksum_offset..checksum_offset + 4].copy_from_slice(&metadata_crc.to_le_bytes());
479    Ok(output)
480}
481
482/// Roles that are 2-D weight matrices (eligible for f16 expand). Norms stay source dtype.
483#[inline]
484fn p64_role_is_weight_matrix(role: u16) -> bool {
485    matches!(
486        role,
487        P64_ROLE_ATTN_K
488            | P64_ROLE_ATTN_V
489            | P64_ROLE_ATTN_Q
490            | P64_ROLE_ATTN_OUTPUT
491            | P64_ROLE_FFN_GATE
492            | P64_ROLE_FFN_UP
493            | P64_ROLE_FFN_DOWN
494            | P64_ROLE_TOKEN_EMBD
495            | P64_ROLE_OUTPUT
496    )
497}
498
499/// Dequantize a full 2-D GGUF tensor into a row-major f16 blob (`out` length = n0*n1*2).
500fn expand_tensor_to_f16_blob(
501    raw: &[u8],
502    info: &GgufTensorInfo,
503    out: &mut [u8],
504) -> Result<(), String> {
505    let n0 = info.dims[0] as usize; // cols (in)
506    let n1 = info.dims[1] as usize; // rows (out)
507    let need = n0
508        .checked_mul(n1)
509        .and_then(|e| e.checked_mul(2))
510        .ok_or("p64: f16 expand size overflow")?;
511    if out.len() < need {
512        return Err("p64: f16 expand output buffer too small".into());
513    }
514    let mut row_f32 = vec![0f32; n0];
515    for r in 0..n1 {
516        crate::ggml_quants::dequant_matrix_row_into(raw, info, r, &mut row_f32)
517            .map_err(|e| format!("p64: f16 expand dequant row {r}: {e:?}"))?;
518        let row_off = r * n0 * 2;
519        for (c, &v) in row_f32.iter().enumerate() {
520            let bits = half::f16::from_f32(v).to_le_bytes();
521            let o = row_off + c * 2;
522            out[o] = bits[0];
523            out[o + 1] = bits[1];
524        }
525    }
526    Ok(())
527}
528
529/// Compile a flat GGUF byte image into a P64 LLM-weight container.
530/// `page_log2 == 0` selects the default (16 KB). Returns the little-endian container bytes.
531#[allow(dead_code)]
532fn compile_gguf_to_p64_legacy(input: &[u8], page_log2: u16) -> Result<Vec<u8>, String> {
533    let idx = crate::gguf_sharder::GgufTensorIndex::from_gguf(input);
534    if idx.tensor_data_start == 0 && idx.hyperparams.n_layer == 0 {
535        return Err("GGUF parse failed or yielded no tensor metadata".to_string());
536    }
537    let page_log2 = if page_log2 == 0 {
538        12 // 4096 default
539    } else {
540        page_log2
541    };
542    if page_log2 < 8 || page_log2 > 30 {
543        return Err(format!("page_log2 {page_log2} out of range"));
544    }
545    let page = 1usize << page_log2;
546    let n_layer = idx.hyperparams.n_layer;
547    let tds = idx.tensor_data_start as usize;
548
549    let mut planned: Vec<(u16, u16, crate::gguf_sharder::GgufTensorInfo)> = Vec::new();
550    let mut push = |role_id: u16, layer: u16, t: Option<crate::gguf_sharder::GgufTensorInfo>| {
551        if let Some(info) = t {
552            planned.push((role_id, layer, info));
553        }
554    };
555    for layer in 0..n_layer {
556        let t = idx.get_layer_tensors(layer);
557        let l = layer as u16;
558        push(P64_ROLE_ATTN_NORM, l, t.attn_norm);
559        push(P64_ROLE_ATTN_Q, l, t.attn_q);
560        push(P64_ROLE_ATTN_K, l, t.attn_k);
561        push(P64_ROLE_ATTN_V, l, t.attn_v);
562        push(P64_ROLE_ATTN_OUTPUT, l, t.attn_output);
563        push(P64_ROLE_FFN_NORM, l, t.ffn_norm);
564        push(P64_ROLE_FFN_GATE, l, t.ffn_gate);
565        push(P64_ROLE_FFN_UP, l, t.ffn_up);
566        push(P64_ROLE_FFN_DOWN, l, t.ffn_down);
567    }
568    push(
569        P64_ROLE_TOKEN_EMBD,
570        P64_LAYER_GLOBAL,
571        idx.token_embd_info().copied(),
572    );
573    push(
574        P64_ROLE_OUTPUT_NORM,
575        P64_LAYER_GLOBAL,
576        idx.output_norm_info().copied(),
577    );
578    push(
579        P64_ROLE_OUTPUT,
580        P64_LAYER_GLOBAL,
581        idx.output_weight_info().copied(),
582    );
583
584    // Filter missing/invalid tensors
585    planned.retain(|(_, _, info)| info.dims[0] > 0);
586
587    // Build the string table
588    let mut string_table: Vec<u8> = Vec::new();
589    let mut name_offsets = std::collections::HashMap::new();
590
591    // Push a dummy null at start
592    string_table.push(0u8);
593
594    for (role, layer, info) in &planned {
595        let name = if let Some(suffix) = p64_role_suffix(*role) {
596            if *layer == P64_LAYER_GLOBAL {
597                String::from_utf8_lossy(suffix).to_string()
598            } else {
599                format!("blk.{}.{}", layer, String::from_utf8_lossy(suffix))
600            }
601        } else {
602            format!("tensor_{}", info.byte_offset)
603        };
604
605        if !name_offsets.contains_key(&name) {
606            let offset = string_table.len() as u32;
607            name_offsets.insert(name.clone(), offset);
608            string_table.extend_from_slice(name.as_bytes());
609            string_table.push(0u8);
610        }
611    }
612
613    // Now extract vocabulary from GGUF and append to string table.
614    let tokenizer_offset = string_table.len() as u32;
615    let tok = crate::gguf_sharder::GgufTokenizer::from_gguf(input);
616
617    let mut tok_bytes: Vec<u8> = Vec::new();
618    // Serialize vocabulary sizes and strings
619    tok_bytes.extend_from_slice(&(tok.vocab.len() as u32).to_le_bytes());
620    for v in &tok.vocab {
621        let v_bytes = v.as_bytes();
622        tok_bytes.extend_from_slice(&(v_bytes.len() as u32).to_le_bytes());
623        tok_bytes.extend_from_slice(v_bytes);
624    }
625    let tokenizer_size = tok_bytes.len() as u32;
626
627    string_table.extend_from_slice(&tok_bytes);
628
629    // Padding string table to 64 bytes
630    while string_table.len() % 64 != 0 {
631        string_table.push(0u8);
632    }
633
634    let string_table_size = string_table.len() as u32;
635    let tensor_count = planned.len() as u32;
636
637    // Build Manifold Table
638    let mut manifold_table: Vec<u8> = Vec::new();
639    let total_layers = idx.hyperparams.n_layer;
640    for l in 0..total_layers {
641        let coord = crate::modalities::manifold::ManifoldCoordinate10D::from_sequential_layer(
642            l,
643            total_layers,
644        );
645        // We do unsafe cast because bytemuck might not be derived for ManifoldCoordinate10D yet. Wait, we can just write the f32s.
646        manifold_table.extend_from_slice(&coord.scale.to_le_bytes());
647        manifold_table.extend_from_slice(&coord.attention_depth.to_le_bytes());
648        manifold_table.extend_from_slice(&coord.epistemic_weight.to_le_bytes());
649        manifold_table.extend_from_slice(&coord.topological_spin.to_le_bytes());
650        manifold_table.extend_from_slice(&coord.temporal_decay.to_le_bytes());
651        manifold_table.extend_from_slice(&coord.entropy_bias.to_le_bytes());
652        manifold_table.extend_from_slice(&coord.spatial_phase.to_le_bytes());
653        manifold_table.extend_from_slice(&coord.recurrence_frequency.to_le_bytes());
654        manifold_table.extend_from_slice(&coord.density_threshold.to_le_bytes());
655        manifold_table.extend_from_slice(&coord.manifold_curvature.to_le_bytes());
656    }
657    // Global layer
658    let global_coord =
659        crate::modalities::manifold::ManifoldCoordinate10D::from_sequential_layer(0, 1);
660    manifold_table.extend_from_slice(&global_coord.scale.to_le_bytes());
661    manifold_table.extend_from_slice(&global_coord.attention_depth.to_le_bytes());
662    manifold_table.extend_from_slice(&global_coord.epistemic_weight.to_le_bytes());
663    manifold_table.extend_from_slice(&global_coord.topological_spin.to_le_bytes());
664    manifold_table.extend_from_slice(&global_coord.temporal_decay.to_le_bytes());
665    manifold_table.extend_from_slice(&global_coord.entropy_bias.to_le_bytes());
666    manifold_table.extend_from_slice(&global_coord.spatial_phase.to_le_bytes());
667    manifold_table.extend_from_slice(&global_coord.recurrence_frequency.to_le_bytes());
668    manifold_table.extend_from_slice(&global_coord.density_threshold.to_le_bytes());
669    manifold_table.extend_from_slice(&global_coord.manifold_curvature.to_le_bytes());
670    let manifold_table_size = manifold_table.len() as u32;
671
672    // Layout
673    let hparams_offset = 64;
674    let entries_offset = 128;
675    let string_table_offset = entries_offset + (tensor_count * 64) as u32;
676    let manifold_table_offset = string_table_offset + string_table_size;
677    let end_of_manifold_table = manifold_table_offset + manifold_table_size;
678    let page_aligned_tensor_start =
679        (end_of_manifold_table + (page as u32) - 1) & !((page as u32) - 1);
680
681    let mut out = vec![0u8; page_aligned_tensor_start as usize];
682
683    // 1. Header
684    out[0..4].copy_from_slice(&P64_MAGIC);
685    out[4..6].copy_from_slice(&P64_VERSION.to_le_bytes());
686    out[6..8].copy_from_slice(&0u16.to_le_bytes()); // format flags
687
688    out[8..12].copy_from_slice(&0u32.to_le_bytes()); // role_table_offset
689    out[12..16].copy_from_slice(&(entries_offset as u32).to_le_bytes()); // tensor_table_offset
690    out[16..20].copy_from_slice(&(tokenizer_offset as u32).to_le_bytes()); // tokenizer_offset
691    out[20..24].copy_from_slice(&(hparams_offset as u32).to_le_bytes()); // hparams_offset
692    out[24..28].copy_from_slice(&string_table_offset.to_le_bytes()); // string_table_offset
693    out[28..32].copy_from_slice(&0u32.to_le_bytes()); // checksum_offset
694    out[32..36].copy_from_slice(&manifold_table_offset.to_le_bytes()); // manifold_table_offset
695
696    out[36..40].copy_from_slice(&tensor_count.to_le_bytes());
697    out[40..44].copy_from_slice(&(page as u32).to_le_bytes());
698    // reserved[0..4]: embedded tokenizer blob byte length
699    out[44..48].copy_from_slice(&tokenizer_size.to_le_bytes());
700
701    // 2. HParams
702    // Just mock for now or use the fields if they are pub. The DOD rewrite doesn't require a strict HParams struct unless defined.
703    // Actually we need to serialize idx.hyperparams into the 64 byte slot.
704    let hparams = &idx.hyperparams;
705    let h_off = hparams_offset as usize;
706    out[h_off..h_off + 4].copy_from_slice(&hparams.n_layer.to_le_bytes());
707    out[h_off + 4..h_off + 8].copy_from_slice(&hparams.n_embd.to_le_bytes());
708    out[h_off + 8..h_off + 12].copy_from_slice(&hparams.n_head.to_le_bytes());
709    out[h_off + 12..h_off + 16].copy_from_slice(&hparams.n_kv_head.to_le_bytes());
710    out[h_off + 16..h_off + 20].copy_from_slice(&0u32.to_le_bytes()); // vocab_size (filled later if known)
711    out[h_off + 20..h_off + 24].copy_from_slice(&hparams.rope_freq_base.to_le_bytes());
712    out[h_off + 24..h_off + 28].copy_from_slice(&hparams.rope_scale.to_le_bytes());
713    out[h_off + 28..h_off + 32].copy_from_slice(&hparams.head_dim.to_le_bytes());
714    out[h_off + 32..h_off + 36].copy_from_slice(&hparams.head_dim_swa.to_le_bytes());
715    out[h_off + 36..h_off + 40].copy_from_slice(&hparams.sliding_window.to_le_bytes());
716    out[h_off + 40..h_off + 44].copy_from_slice(&hparams.shared_kv_layers.to_le_bytes());
717    out[h_off + 44..h_off + 48].copy_from_slice(&hparams.logit_softcap.to_le_bytes());
718    out[h_off + 48..h_off + 52].copy_from_slice(&hparams.architecture.to_le_bytes());
719    out[h_off + 52..h_off + 56].copy_from_slice(&hparams.arch_flags.to_le_bytes());
720
721    // 2b. Manifold Table
722    let mt_off = manifold_table_offset as usize;
723    out[mt_off..mt_off + manifold_table.len()].copy_from_slice(&manifold_table);
724
725    // 3. Entries and Tensor Blobs
726    let mut cursor_blob = page_aligned_tensor_start as usize;
727    for (i, (role, layer, info)) in planned.iter().enumerate() {
728        let e_off = entries_offset as usize + i * 64;
729
730        let name = if let Some(suffix) = p64_role_suffix(*role) {
731            if *layer == P64_LAYER_GLOBAL {
732                String::from_utf8_lossy(suffix).to_string()
733            } else {
734                format!("blk.{}.{}", layer, String::from_utf8_lossy(suffix))
735            }
736        } else {
737            format!("tensor_{}", info.byte_offset)
738        };
739        let n_offset = *name_offsets.get(&name).unwrap();
740
741        // Align blob to its internal alignment requirement if needed, but P64 natively page aligns at start
742        // and blobs follow one another. Wait, ggml requires 32-byte alignment usually.
743        // Let's pad cursor_blob to 32 bytes
744        cursor_blob = (cursor_blob + 31) & !31;
745
746        let n_elements =
747            info.dims[0] * info.dims[1].max(1) * info.dims[2].max(1) * info.dims[3].max(1);
748        let byte_len = crate::ggml_quants::tensor_byte_len(info).unwrap_or(0);
749
750        // Copy the tensor blob
751        out.resize(cursor_blob + byte_len, 0);
752        let src_start = tds + info.byte_offset as usize;
753        if src_start + byte_len <= input.len() {
754            out[cursor_blob..cursor_blob + byte_len]
755                .copy_from_slice(&input[src_start..src_start + byte_len]);
756        }
757
758        // Write Entry
759        out[e_off..e_off + 4].copy_from_slice(&n_offset.to_le_bytes());
760        out[e_off + 4..e_off + 6].copy_from_slice(&role.to_le_bytes());
761        out[e_off + 6..e_off + 8].copy_from_slice(&(info.ggml_type as u16).to_le_bytes());
762
763        let m_idx = if *layer == P64_LAYER_GLOBAL {
764            total_layers
765        } else {
766            *layer as u32
767        };
768        out[e_off + 8..e_off + 12].copy_from_slice(&m_idx.to_le_bytes()); // manifold_idx
769
770        out[e_off + 12..e_off + 16].copy_from_slice(&info.n_dims.to_le_bytes());
771        out[e_off + 16..e_off + 20].copy_from_slice(&(info.dims[0] as u32).to_le_bytes());
772        out[e_off + 20..e_off + 24].copy_from_slice(&(info.dims[1] as u32).to_le_bytes());
773        out[e_off + 24..e_off + 28].copy_from_slice(&(info.dims[2] as u32).to_le_bytes());
774        out[e_off + 28..e_off + 32].copy_from_slice(&(info.dims[3] as u32).to_le_bytes());
775        out[e_off + 32..e_off + 36].copy_from_slice(&(cursor_blob as u32).to_le_bytes());
776        out[e_off + 36..e_off + 40].copy_from_slice(&(byte_len as u32).to_le_bytes());
777        out[e_off + 40..e_off + 44].copy_from_slice(&(n_elements as u32).to_le_bytes());
778
779        cursor_blob += byte_len;
780    }
781
782    // String table write
783    out[string_table_offset as usize..string_table_offset as usize + string_table.len()]
784        .copy_from_slice(&string_table);
785
786    Ok(out)
787}
788
789/// Compatibility alias for the historical pre-P64 API name.
790pub fn compile_gguf_to_q42(input: &[u8], page_log2: u16) -> Result<Vec<u8>, String> {
791    compile_gguf_to_p64(input, page_log2)
792}
793
794/// Task #12 / STELLAR §A — like [`compile_gguf_to_p64`] but **ternary-packs the FFN projections**
795/// (gate/up/down) during the compile, producing a **complete, runnable** P64: hyperparameters +
796/// tokenizer are preserved (so the live loader boots it and builds the KV cache), while the FFN
797/// tensors are BitNet-1.58b ternary blobs (`ternary::dequantize_blob` / the 2-bit GPU kernel).
798/// Attention / norms / embeddings stay verbatim at their source precision. This is the loadable
799/// container the live FFN-ternary dispatch path will run + measure against.
800pub fn compile_gguf_to_p64_ternary_ffn(input: &[u8], page_log2: u16) -> Result<Vec<u8>, String> {
801    compile_gguf_to_p64_ffn_quant_awq(input, page_log2, None, 0.0, FfnQuant::Ternary)
802}
803
804/// Compatibility alias for the historical pre-P64 API name.
805pub fn compile_gguf_to_q42_ternary_ffn(input: &[u8], page_log2: u16) -> Result<Vec<u8>, String> {
806    compile_gguf_to_p64_ternary_ffn(input, page_log2)
807}
808
809/// Target quantization for the FFN tensors in an AWQ P64 compile.
810#[derive(Clone, Copy, PartialEq, Eq, Debug)]
811pub enum FfnQuant {
812    /// BitNet 1.58b ternary (`GGML_TYPE_TERNARY_158`, resident 2-bit GPU path).
813    Ternary,
814    /// ggml Q4_0 4-bit (`GGML_TYPE_Q4_0`, the standard quantized GPU GEMM path) — AWQ's design regime.
815    Q4_0,
816}
817
818/// AWQ-aware ternary FFN compile.
819pub fn compile_gguf_to_p64_ternary_ffn_awq(
820    input: &[u8],
821    page_log2: u16,
822    awq_scales: Option<&[Vec<f32>]>,
823    alpha: f32,
824) -> Result<Vec<u8>, String> {
825    compile_gguf_to_p64_ffn_quant_awq(input, page_log2, awq_scales, alpha, FfnQuant::Ternary)
826}
827
828/// Compatibility alias for the historical pre-P64 API name.
829pub fn compile_gguf_to_q42_ternary_ffn_awq(
830    input: &[u8],
831    page_log2: u16,
832    awq_scales: Option<&[Vec<f32>]>,
833    alpha: f32,
834) -> Result<Vec<u8>, String> {
835    compile_gguf_to_p64_ternary_ffn_awq(input, page_log2, awq_scales, alpha)
836}
837
838/// AWQ-aware **Q4_0** FFN compile (Path A) — FFN packed to 4-bit Q4_0 (AWQ's design regime); all else
839/// verbatim from the source GGUF.
840pub fn compile_gguf_to_p64_q4_ffn_awq(
841    input: &[u8],
842    page_log2: u16,
843    awq_scales: Option<&[Vec<f32>]>,
844    alpha: f32,
845) -> Result<Vec<u8>, String> {
846    compile_gguf_to_p64_ffn_quant_awq(input, page_log2, awq_scales, alpha, FfnQuant::Q4_0)
847}
848
849/// Compatibility alias for the historical pre-P64 API name.
850pub fn compile_gguf_to_q42_q4_ffn_awq(
851    input: &[u8],
852    page_log2: u16,
853    awq_scales: Option<&[Vec<f32>]>,
854    alpha: f32,
855) -> Result<Vec<u8>, String> {
856    compile_gguf_to_p64_q4_ffn_awq(input, page_log2, awq_scales, alpha)
857}
858
859/// AWQ-aware FFN-quantized P64 compile. `quant` selects the FFN target (ternary or Q4_0). When
860/// `awq_scales` is `Some` (per-layer per-input-channel salience from [`crate::llm_awq::snapshot`]) the
861/// gate/up input channel `i` is scaled by `s_i^alpha` before packing and `ffn_norm` is divided by
862/// `s_i^alpha` — mathematically exact in f32 (`(X·norm/s^a)·(W·s^a)=(X·norm)·W`) — moving salient
863/// channels into a range the quant grid represents better. `awq_scales = None` / `alpha == 0.0`
864/// reproduces the plain (un-calibrated) compile. The down projection is left un-scaled (no clean fold
865/// site — a v2 item). Everything outside the FFN passes through verbatim from the source GGUF.
866pub fn compile_gguf_to_p64_ffn_quant_awq(
867    input: &[u8],
868    page_log2: u16,
869    awq_scales: Option<&[Vec<f32>]>,
870    alpha: f32,
871    quant: FfnQuant,
872) -> Result<Vec<u8>, String> {
873    use crate::ggml_quants::GGML_TYPE_Q4_0;
874    use crate::llm_kernel_parity::{q4_0_bytes, quantize_q4_0_from_f32};
875    use crate::ternary::{ternary_blob, ternary_blob_len, GGML_TYPE_TERNARY_158};
876
877    let base = compile_gguf_to_p64(input, page_log2)?;
878    let base_index = P64TensorIndex::from_p64(&base)?;
879    let mut header = base_index.header;
880    let hparams = base_index.hparams;
881    let mut entries = base_index.entries;
882    let string_region =
883        base[header.string_table_offset as usize..header.manifold_table_offset as usize].to_vec();
884    let manifold_region =
885        base[header.manifold_table_offset as usize..header.tokenizer_offset as usize].to_vec();
886    let tokenizer_region =
887        base[header.tokenizer_offset as usize..header.checksum_offset as usize].to_vec();
888    drop(base);
889
890    let page = header.page_size as usize;
891    let checksum_start = header.checksum_offset as usize;
892    let checksum_bytes = (entries.len() + 1)
893        .checked_mul(4)
894        .ok_or("p64: checksum table overflow")?;
895    let mut cursor = align_up(checksum_start + checksum_bytes, page);
896    let is_ffn = |role: u16| {
897        matches!(
898            role,
899            P64_ROLE_FFN_GATE | P64_ROLE_FFN_UP | P64_ROLE_FFN_DOWN
900        )
901    };
902    let element_count = |entry: &P64TensorEntry| -> Result<usize, String> {
903        entry.dimensions[..entry.rank as usize]
904            .iter()
905            .try_fold(1usize, |count, dimension| {
906                count.checked_mul((*dimension).max(1) as usize)
907            })
908            .ok_or_else(|| "p64: tensor element count overflow".to_string())
909    };
910
911    for entry in &mut entries {
912        let output_size = if is_ffn(entry.role_id) {
913            let count = element_count(entry)?;
914            match quant {
915                FfnQuant::Ternary => {
916                    entry.dtype = u16::try_from(GGML_TYPE_TERNARY_158)
917                        .map_err(|_| "p64: ternary type exceeds u16")?;
918                    ternary_blob_len(count)
919                }
920                FfnQuant::Q4_0 => {
921                    entry.dtype =
922                        u16::try_from(GGML_TYPE_Q4_0).map_err(|_| "p64: Q4_0 type exceeds u16")?;
923                    q4_0_bytes(count)
924                }
925            }
926        } else {
927            entry.blob_size as usize
928        };
929        cursor = align_up(cursor, page);
930        entry.blob_offset = u32::try_from(cursor).map_err(|_| "p64: container exceeds 4 GiB")?;
931        entry.blob_size = u32::try_from(output_size).map_err(|_| "p64: tensor exceeds 4 GiB")?;
932        cursor = cursor
933            .checked_add(output_size)
934            .ok_or("p64: output size overflow")?;
935    }
936    let total_size = align_up(cursor, 64);
937    if total_size > u32::MAX as usize {
938        return Err("p64: 32-bit relative-offset container exceeds 4 GiB".to_string());
939    }
940    if matches!(quant, FfnQuant::Ternary) {
941        header.flags |= FORMAT_FLAG_TERNARY;
942    } else {
943        header.flags &= !FORMAT_FLAG_TERNARY;
944    }
945
946    let mut output = vec![0u8; total_size];
947    header.write_le(&mut output[..P64_WEIGHT_HEADER_BYTES]);
948    let hparams_start = header.hparams_offset as usize;
949    hparams.write_le(&mut output[hparams_start..hparams_start + 64]);
950    let tensor_table_start = header.tensor_table_offset as usize;
951    for (position, entry) in entries.iter().enumerate() {
952        let start = tensor_table_start + position * P64_TENSOR_ENTRY_BYTES;
953        write_tensor_entry(entry, &mut output[start..start + P64_TENSOR_ENTRY_BYTES]);
954    }
955    let string_start = header.string_table_offset as usize;
956    output[string_start..string_start + string_region.len()].copy_from_slice(&string_region);
957    let manifold_start = header.manifold_table_offset as usize;
958    output[manifold_start..manifold_start + manifold_region.len()]
959        .copy_from_slice(&manifold_region);
960    let tokenizer_start = header.tokenizer_offset as usize;
961    output[tokenizer_start..tokenizer_start + tokenizer_region.len()]
962        .copy_from_slice(&tokenizer_region);
963
964    let source_index = GgufTensorIndex::from_gguf(input);
965    let source_data_start = source_index.tensor_data_start as usize;
966    let awq_enabled = awq_scales.is_some() && alpha != 0.0;
967    let awq_scale = |layer: u32, channel: usize| -> f32 {
968        awq_scales
969            .and_then(|layers| layers.get(layer as usize))
970            .and_then(|channels| channels.get(channel))
971            .copied()
972            .unwrap_or(1.0)
973            .max(1e-6)
974            .powf(alpha)
975    };
976    let mut scratch = Vec::<f32>::new();
977    for (position, entry) in entries.iter().enumerate() {
978        let source_entry = source_index
979            .entries
980            .iter()
981            .find(|(_, info)| info.byte_offset == entry.source_offset)
982            .map(|(_, info)| *info)
983            .ok_or_else(|| format!("p64: source tensor {position} disappeared"))?;
984        let source_size = crate::ggml_quants::tensor_byte_len(&source_entry)
985            .ok_or_else(|| format!("p64: source tensor {position} type is unsupported"))?;
986        let source_start = source_data_start + source_entry.byte_offset as usize;
987        let source_end = source_start + source_size;
988        if source_end > input.len() {
989            return Err(format!("p64: source tensor {position} is out of bounds"));
990        }
991        let target_start = entry.blob_offset as usize;
992        let target_end = target_start + entry.blob_size as usize;
993
994        if is_ffn(entry.role_id) {
995            let count = element_count(entry)?;
996            scratch.resize(count, 0.0);
997            crate::ggml_quants::dequantize_row_into(
998                &input[source_start..source_end],
999                source_entry.ggml_type,
1000                count,
1001                &mut scratch,
1002            )
1003            .map_err(|error| format!("p64: FFN dequantization failed: {error:?}"))?;
1004            if awq_enabled && matches!(entry.role_id, P64_ROLE_FFN_GATE | P64_ROLE_FFN_UP) {
1005                let n_in = entry.dimensions[0] as usize;
1006                let n_out = entry.dimensions[1] as usize;
1007                if n_in > 0 && n_in.saturating_mul(n_out) == count {
1008                    for output_channel in 0..n_out {
1009                        let row = output_channel * n_in;
1010                        for input_channel in 0..n_in {
1011                            scratch[row + input_channel] *=
1012                                awq_scale(entry.manifold_idx, input_channel);
1013                        }
1014                    }
1015                }
1016            }
1017            match quant {
1018                FfnQuant::Ternary => {
1019                    let blob = ternary_blob(&scratch);
1020                    if blob.len() != entry.blob_size as usize {
1021                        return Err("p64: ternary output length mismatch".to_string());
1022                    }
1023                    output[target_start..target_end].copy_from_slice(&blob);
1024                }
1025                FfnQuant::Q4_0 => {
1026                    if !quantize_q4_0_from_f32(&scratch, &mut output[target_start..target_end]) {
1027                        return Err(format!(
1028                            "p64: Q4_0 quantization failed for tensor {position}"
1029                        ));
1030                    }
1031                }
1032            }
1033        } else if awq_enabled && entry.role_id == P64_ROLE_FFN_NORM {
1034            let count = element_count(entry)?;
1035            match source_entry.ggml_type {
1036                crate::ggml_quants::GGML_TYPE_F32 if source_size >= count * 4 => {
1037                    for channel in 0..count {
1038                        let source = source_start + channel * 4;
1039                        let value =
1040                            f32::from_le_bytes(input[source..source + 4].try_into().unwrap())
1041                                / awq_scale(entry.manifold_idx, channel);
1042                        let target = target_start + channel * 4;
1043                        output[target..target + 4].copy_from_slice(&value.to_le_bytes());
1044                    }
1045                }
1046                crate::ggml_quants::GGML_TYPE_F16 if source_size >= count * 2 => {
1047                    for channel in 0..count {
1048                        let source = source_start + channel * 2;
1049                        let value =
1050                            half::f16::from_le_bytes(input[source..source + 2].try_into().unwrap())
1051                                .to_f32()
1052                                / awq_scale(entry.manifold_idx, channel);
1053                        let target = target_start + channel * 2;
1054                        output[target..target + 2]
1055                            .copy_from_slice(&half::f16::from_f32(value).to_le_bytes());
1056                    }
1057                }
1058                _ => {
1059                    return Err(format!(
1060                        "p64: AWQ cannot fold FFN norm type {} at manifold {}",
1061                        source_entry.ggml_type, entry.manifold_idx
1062                    ));
1063                }
1064            }
1065        } else {
1066            if source_size != entry.blob_size as usize {
1067                return Err(format!(
1068                    "p64: verbatim tensor {position} changed byte length"
1069                ));
1070            }
1071            output[target_start..target_end].copy_from_slice(&input[source_start..source_end]);
1072        }
1073        let crc = crc32c(&output[target_start..target_end]);
1074        let crc_start = checksum_start + 4 + position * 4;
1075        output[crc_start..crc_start + 4].copy_from_slice(&crc.to_le_bytes());
1076    }
1077    let metadata_crc = crc32c(&output[..checksum_start]);
1078    output[checksum_start..checksum_start + 4].copy_from_slice(&metadata_crc.to_le_bytes());
1079    P64TensorIndex::from_p64(&output)?;
1080    Ok(output)
1081}
1082
1083/// Compatibility alias for the historical pre-P64 API name.
1084pub fn compile_gguf_to_q42_ffn_quant_awq(
1085    input: &[u8],
1086    page_log2: u16,
1087    awq_scales: Option<&[Vec<f32>]>,
1088    alpha: f32,
1089    quant: FfnQuant,
1090) -> Result<Vec<u8>, String> {
1091    compile_gguf_to_p64_ffn_quant_awq(input, page_log2, awq_scales, alpha, quant)
1092}