mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
Pipeline: - q16_lut_vcn.py: Q16_16 LUT generation + VCN frame encoding (8 ops) - braid_vcn_encoder.py: Delta+RLE → RS ECC → ChaCha20 → VCN → MKV - braid_search.py: Sidon set slots, soliton search, QUBO optimization - test_braid_pipeline.py: 67 tests covering full round-trip WebGPU/Scripts: - braid_fft.wgsl: Cooley-Tukey radix-2 FFT on phase vectors - reed_solomon_vcn.py: Reed-Solomon ECC for VCN frame data - chacha20_braid.py: ChaCha20 encryption + key derivation - polynomial_commitment.py: KZG scheme for receipt verification Lean: - BraidBitwiseODE.lean: XOR crossing, O(1) integration, 2 proved theorems FPGA (Tang Nano 9K): - q16_lut_core.v: 8-op arithmetic, 2-stage pipeline, BRAM reciprocal - braid_crossing_core.v: 4-stage crossing residual, 7 Q16 instances - Testbenches with edge cases + VCD dumps
256 lines
8.6 KiB
Python
256 lines
8.6 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Q16_16 Lookup Table VCN Encoder
|
||
|
||
Generates Q16_16 lookup tables for arithmetic operations (add/sub/mul/div/
|
||
max/min/neg/abs), encodes each LUT as a VCN YUV420 frame via the existing
|
||
vcn_compute_substrate infrastructure, and provides round-trip decode.
|
||
|
||
The full Q16_16 range is 2^32 values, but we discretize into 65536 entries
|
||
per operation (sampling every 65536-th input or using a 256×256 grid for
|
||
two-operand ops) so the LUT fits a single VCN frame.
|
||
|
||
Usage:
|
||
python3 q16_lut_vcn.py gen_add 1080p -> writes add_lut.mkv
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import struct
|
||
import math
|
||
import hashlib
|
||
from pathlib import Path
|
||
from typing import Dict, List, Tuple, Optional
|
||
|
||
# Local imports – same directory
|
||
import sys as _sys
|
||
_sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||
from vcn_compute_substrate import (
|
||
VCNComputeFrameSpec, VCN_RESOLUTIONS, SIGNATURE_HEADER, SIGNATURE_SIZE,
|
||
compute_frame_size, create_frame_dynamic, encode_frames_hardware,
|
||
)
|
||
|
||
# ── Constants ────────────────────────────────────────────────────────────────
|
||
|
||
Q16_ONE = 0x00010000 # 1.0 in Q16_16
|
||
Q16_MASK = 0xFFFFFFFF
|
||
LUT_ENTRIES = 65536 # 256 × 256 grid for two-operand ops
|
||
GRID_SIDE = 256 # sample every 256-th value along each axis
|
||
SAMPLE_STRIDE = Q16_ONE // GRID_SIDE # 256
|
||
|
||
SUPPORTED_OPS = ("add", "sub", "mul", "div", "max", "min", "neg", "abs")
|
||
|
||
|
||
# ── Q16_16 arithmetic (integer-only, no float in compute paths) ─────────────
|
||
|
||
def _q16_add(a: int, b: int) -> int:
|
||
return (a + b) & Q16_MASK
|
||
|
||
def _q16_sub(a: int, b: int) -> int:
|
||
return (a - b) & Q16_MASK
|
||
|
||
def _q16_mul(a: int, b: int) -> int:
|
||
"""Saturating Q16_16 multiply."""
|
||
sa = a if a < 0x80000000 else a - 0x100000000
|
||
sb = b if b < 0x80000000 else b - 0x100000000
|
||
result = (sa * sb) >> 16
|
||
# Clamp to Q16_16 range
|
||
if result > 0x7FFFFFFF:
|
||
return 0x7FFFFFFF
|
||
if result < -0x80000000:
|
||
return 0x80000000
|
||
return result & Q16_MASK
|
||
|
||
def _q16_div(a: int, b: int) -> int:
|
||
"""Saturating Q16_16 divide."""
|
||
if b == 0:
|
||
return 0x7FFFFFFF # saturate
|
||
sa = a if a < 0x80000000 else a - 0x100000000
|
||
sb = b if b < 0x80000000 else b - 0x100000000
|
||
result = (sa << 16) // sb
|
||
if result > 0x7FFFFFFF:
|
||
return 0x7FFFFFFF
|
||
if result < -0x80000000:
|
||
return 0x80000000
|
||
return result & Q16_MASK
|
||
|
||
def _q16_max(a: int, b: int) -> int:
|
||
sa = a if a < 0x80000000 else a - 0x100000000
|
||
sb = b if b < 0x80000000 else b - 0x100000000
|
||
return (sa if sa >= sb else sb) & Q16_MASK
|
||
|
||
def _q16_min(a: int, b: int) -> int:
|
||
sa = a if a < 0x80000000 else a - 0x100000000
|
||
sb = b if b < 0x80000000 else b - 0x100000000
|
||
return (sa if sa <= sb else sb) & Q16_MASK
|
||
|
||
def _q16_neg(a: int) -> int:
|
||
return (-a) & Q16_MASK
|
||
|
||
def _q16_abs(a: int) -> int:
|
||
sa = a if a < 0x80000000 else a - 0x100000000
|
||
return (sa if sa >= 0 else -sa) & Q16_MASK
|
||
|
||
|
||
# Two-operand dispatch table
|
||
_TWO_OP = {
|
||
"add": _q16_add,
|
||
"sub": _q16_sub,
|
||
"mul": _q16_mul,
|
||
"div": _q16_div,
|
||
"max": _q16_max,
|
||
"min": _q16_min,
|
||
}
|
||
|
||
# Single-operand dispatch table
|
||
_ONE_OP = {
|
||
"neg": _q16_neg,
|
||
"abs": _q16_abs,
|
||
}
|
||
|
||
|
||
# ── LUT generation ───────────────────────────────────────────────────────────
|
||
|
||
def generate_lut(operation: str) -> List[int]:
|
||
"""Generate 65536-entry LUT for *operation*.
|
||
|
||
For two-operand ops we build a 256×256 grid: entry[i*256+j] = op(i*stride, j*stride).
|
||
For single-operand ops we store op(i*stride) for i in 0..65535.
|
||
|
||
Returns a list of 65536 unsigned 32-bit Q16_16 results.
|
||
"""
|
||
if operation not in SUPPORTED_OPS:
|
||
raise ValueError(f"Unsupported operation '{operation}'. Choose from {SUPPORTED_OPS}")
|
||
|
||
table: List[int] = [0] * LUT_ENTRIES
|
||
|
||
if operation in _TWO_OP:
|
||
fn = _TWO_OP[operation]
|
||
for i in range(GRID_SIDE):
|
||
a = (i * SAMPLE_STRIDE) & Q16_MASK
|
||
for j in range(GRID_SIDE):
|
||
b = (j * SAMPLE_STRIDE) & Q16_MASK
|
||
table[i * GRID_SIDE + j] = fn(a, b)
|
||
else:
|
||
fn = _ONE_OP[operation]
|
||
for i in range(LUT_ENTRIES):
|
||
val = (i * (Q16_ONE // LUT_ENTRIES * LUT_ENTRIES if LUT_ENTRIES < Q16_ONE else 1)) & Q16_MASK
|
||
# For single-operand, map index to Q16 value
|
||
val = (i * (Q16_MASK // LUT_ENTRIES + 1)) & Q16_MASK
|
||
table[i] = fn(val)
|
||
|
||
return table
|
||
|
||
|
||
def serialize_lut(table: List[int]) -> bytes:
|
||
"""Serialize LUT to bytes (65536 × 4 = 256 KiB)."""
|
||
return struct.pack(f"<{LUT_ENTRIES}I", *table)
|
||
|
||
|
||
def deserialize_lut(data: bytes) -> List[int]:
|
||
"""Deserialize bytes back to LUT."""
|
||
return list(struct.unpack(f"<{LUT_ENTRIES}I", data[:LUT_ENTRIES * 4]))
|
||
|
||
|
||
def lut_checksum(table: List[int]) -> str:
|
||
"""SHA-256 hex digest of the serialized LUT."""
|
||
return hashlib.sha256(serialize_lut(table)).hexdigest()
|
||
|
||
|
||
# ── VCN frame encode / decode ───────────────────────────────────────────────
|
||
|
||
def encode_q16_lut_frame(operation: str, resolution: str = "1080p") -> bytes:
|
||
"""Generate a Q16_16 LUT for *operation* and encode it as a VCN YUV420 frame.
|
||
|
||
The frame payload is: [4-byte op tag][32-byte SHA-256][256 KiB LUT data]
|
||
|
||
Returns raw YUV420 frame bytes.
|
||
"""
|
||
table = generate_lut(operation)
|
||
payload = serialize_lut(table)
|
||
|
||
# Prepend operation tag + checksum for validation on decode
|
||
op_tag = operation.encode("ascii").ljust(4, b"\x00")[:4]
|
||
checksum = hashlib.sha256(payload).digest() # 32 bytes
|
||
frame_data = op_tag + checksum + payload # 4 + 32 + 262144 = 262180 bytes
|
||
|
||
w, h = VCN_RESOLUTIONS.get(resolution, VCN_RESOLUTIONS["1080p"])
|
||
spec = VCNComputeFrameSpec(
|
||
width=w, height=h,
|
||
bytes_per_frame=compute_frame_size(w, h, "yuv420p"),
|
||
encoder="libx264",
|
||
)
|
||
return create_frame_dynamic(frame_data, seq=0, spec=spec)
|
||
|
||
|
||
def decode_q16_lut_frame(frame_bytes: bytes, operation: str) -> Dict:
|
||
"""Decode a VCN YUV420 frame back to a Q16_16 LUT.
|
||
|
||
Parses the frame payload, validates the SHA-256 checksum, and returns:
|
||
{
|
||
"operation": str,
|
||
"entries": List[int], # 65536 Q16_16 values
|
||
"checksum_valid": bool,
|
||
"checksum": str, # hex
|
||
}
|
||
"""
|
||
# Strip signature header (first SIGNATURE_SIZE bytes)
|
||
payload = frame_bytes[SIGNATURE_SIZE:]
|
||
|
||
# Parse header
|
||
op_tag = payload[:4].rstrip(b"\x00").decode("ascii")
|
||
stored_checksum = payload[4:36] # 32 bytes
|
||
lut_data = payload[36:36 + LUT_ENTRIES * 4]
|
||
|
||
table = deserialize_lut(lut_data)
|
||
computed_checksum = hashlib.sha256(lut_data).digest()
|
||
valid = computed_checksum == stored_checksum
|
||
|
||
return {
|
||
"operation": op_tag if op_tag else operation,
|
||
"entries": table,
|
||
"checksum_valid": valid,
|
||
"checksum": computed_checksum.hex(),
|
||
}
|
||
|
||
|
||
def encode_q16_lut_to_mkv(operation: str, output_path: str | Path,
|
||
resolution: str = "1080p") -> Path:
|
||
"""Full pipeline: generate LUT → VCN frame → hardware encode to MKV."""
|
||
output_path = Path(output_path)
|
||
frame = encode_q16_lut_frame(operation, resolution)
|
||
w, h = VCN_RESOLUTIONS.get(resolution, VCN_RESOLUTIONS["1080p"])
|
||
spec = VCNComputeFrameSpec(
|
||
width=w, height=h,
|
||
bytes_per_frame=compute_frame_size(w, h, "yuv420p"),
|
||
encoder="libx264",
|
||
)
|
||
result = encode_frames_hardware([frame], output_path, spec)
|
||
if result.returncode != 0:
|
||
raise RuntimeError(f"VCN encode failed: {result.stderr}")
|
||
return output_path
|
||
|
||
|
||
# ── CLI entry-point ──────────────────────────────────────────────────────────
|
||
|
||
def main():
|
||
import sys
|
||
if len(sys.argv) < 3:
|
||
print("Usage: q16_lut_vcn.py <operation> <resolution>")
|
||
print(f" operations: {SUPPORTED_OPS}")
|
||
print(" resolution: 240p .. 16K")
|
||
sys.exit(1)
|
||
|
||
op = sys.argv[1]
|
||
res = sys.argv[2] if len(sys.argv) > 2 else "1080p"
|
||
|
||
print(f"Generating Q16_16 LUT for '{op}' ...")
|
||
table = generate_lut(op)
|
||
print(f" LUT size: {len(table)} entries, checksum: {lut_checksum(table)}")
|
||
|
||
out = encode_q16_lut_to_mkv(op, Path(f"{op}_lut.mkv"), res)
|
||
print(f" Written to {out}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|