mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
1037 lines
39 KiB
Python
1037 lines
39 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
connectome_lut_shim.py — Python shim for parallel biophysical LUT evaluation.
|
||
|
||
Loads OpenWorm C. elegans connectome data from Parquet, quantizes each dataset
|
||
into the 18-bit address space defined in CooperativeLUT.lean (6D × 8 bins = 262,144
|
||
entries), precomputes the biophysical constraint surface, and performs parallel
|
||
lawful-state lookups for mutation proposals.
|
||
|
||
Branch prediction is treated as a SIMD interface: each misprediction is a coarse-
|
||
grain stochastic computation that shrinks possibility space.
|
||
|
||
Now supports 8-way and 16-way speculative bundles, plus BTB pattern detection
|
||
with streak-based short-circuiting.
|
||
|
||
Per AGENTS.md §6.1: This is a shim. All logic lives in Lean.
|
||
This file only: JSON serialization, Parquet I/O, LUT precomputation,
|
||
parallel lookup, quantum walk simulation, Verilog generation, and result wrapping.
|
||
"""
|
||
|
||
import json
|
||
import sys
|
||
from pathlib import Path
|
||
from dataclasses import dataclass, asdict
|
||
from typing import List, Dict, Optional, Tuple
|
||
from concurrent.futures import ThreadPoolExecutor
|
||
|
||
import pandas as pd
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# §0 Q16_16 utilities (mirror Lean FixedPoint.lean)
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
Q16_ONE = 0x00010000
|
||
|
||
|
||
def q16_to_float(q: int) -> float:
|
||
"""Convert Q16.16 UInt32 to float."""
|
||
if q >= 0x80000000:
|
||
return (q - 0x100000000) / 65536.0
|
||
return q / 65536.0
|
||
|
||
|
||
def q16_mul(a: int, b: int) -> int:
|
||
return ((a * b) >> 16) & 0xFFFFFFFF
|
||
|
||
|
||
def q16_div(a: int, b: int) -> int:
|
||
if b == 0:
|
||
return 0xFFFFFFFF
|
||
return ((a << 16) // b) & 0xFFFFFFFF
|
||
|
||
|
||
def q16_sub(a: int, b: int) -> int:
|
||
return ((a - b) & 0xFFFFFFFF)
|
||
|
||
|
||
def q16_le(a: int, b: int) -> bool:
|
||
a_s = a if a < 0x80000000 else a - 0x100000000
|
||
b_s = b if b < 0x80000000 else b - 0x100000000
|
||
return a_s <= b_s
|
||
|
||
|
||
def q16_ge(a: int, b: int) -> bool:
|
||
a_s = a if a < 0x80000000 else a - 0x100000000
|
||
b_s = b if b < 0x80000000 else b - 0x100000000
|
||
return a_s >= b_s
|
||
|
||
|
||
def q16_lt(a: int, b: int) -> bool:
|
||
a_s = a if a < 0x80000000 else a - 0x100000000
|
||
b_s = b if b < 0x80000000 else b - 0x100000000
|
||
return a_s < b_s
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# §1 Biophysical constants (mirror CooperativeLUT.lean)
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
DRAKE_CONSTANT = 0x000000C5
|
||
DRIFT_BARRIER_CONSTANT = 0x00000042
|
||
U_BASE = 0x00000041
|
||
NE_BASE = 0x00008000
|
||
SIGMA_BASE = 0x00004000
|
||
CONNECTANCE_BASE = 0x00002000
|
||
MODULARITY_BASE = 0x00002000
|
||
|
||
ADDR_SPACE = 262144
|
||
STREAK_THRESHOLD = 4
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# §2 Quantized genome encoding (6D × 8 bins = 18 bits)
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
@dataclass(frozen=True)
|
||
class QuantizedGenome:
|
||
g_bin: int
|
||
ne_bin: int
|
||
u_bin: int
|
||
sigma_bin: int
|
||
connectance_bin: int
|
||
modularity_bin: int
|
||
|
||
def to_address(self) -> int:
|
||
return (
|
||
self.g_bin * 32768 +
|
||
self.ne_bin * 4096 +
|
||
self.u_bin * 512 +
|
||
self.sigma_bin * 64 +
|
||
self.connectance_bin * 8 +
|
||
self.modularity_bin
|
||
)
|
||
|
||
@staticmethod
|
||
def from_address(addr: int) -> "QuantizedGenome":
|
||
return QuantizedGenome(
|
||
g_bin=addr // 32768,
|
||
ne_bin=(addr // 4096) % 8,
|
||
u_bin=(addr // 512) % 8,
|
||
sigma_bin=(addr // 64) % 8,
|
||
connectance_bin=(addr // 8) % 8,
|
||
modularity_bin=addr % 8,
|
||
)
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class ConstraintEntry:
|
||
lawful: bool
|
||
cost: int
|
||
drake_ok: bool
|
||
drift_ok: bool
|
||
error_ok: bool
|
||
|
||
|
||
def compute_constraint_entry(q: QuantizedGenome) -> ConstraintEntry:
|
||
"""Mirror of CooperativeLUT.computeConstraintEntry.
|
||
Connectance tightens Drake budget; modularity relaxes drift barrier."""
|
||
u_q = U_BASE * (q.u_bin + 1)
|
||
ne_q = NE_BASE * (q.ne_bin + 1)
|
||
sigma_q = Q16_ONE + SIGMA_BASE * (q.sigma_bin + 1)
|
||
connectance_factor = CONNECTANCE_BASE * (q.connectance_bin + 1)
|
||
modularity_factor = MODULARITY_BASE * (q.modularity_bin + 1)
|
||
|
||
adjusted_drake = q16_div(DRAKE_CONSTANT, connectance_factor)
|
||
drake_ok = q16_le(u_q, adjusted_drake)
|
||
|
||
adjusted_drift = q16_div(DRIFT_BARRIER_CONSTANT, modularity_factor)
|
||
un_product = q16_mul(u_q, ne_q)
|
||
drift_ok = q16_ge(un_product, adjusted_drift)
|
||
|
||
ln_sigma = q16_sub(sigma_q, Q16_ONE)
|
||
error_ok = q16_lt(u_q, ln_sigma)
|
||
|
||
cost = 0
|
||
if not drake_ok:
|
||
cost += q16_sub(u_q, adjusted_drake) & 0xFFFFFFFF
|
||
if not drift_ok:
|
||
cost += q16_sub(adjusted_drift, un_product) & 0xFFFFFFFF
|
||
if not error_ok:
|
||
cost += 0x00FF0000
|
||
|
||
return ConstraintEntry(
|
||
lawful=drake_ok and drift_ok and error_ok,
|
||
cost=cost,
|
||
drake_ok=drake_ok,
|
||
drift_ok=drift_ok,
|
||
error_ok=error_ok,
|
||
)
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# §3 Precomputed biophysical LUT (262,144 entries)
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
class BiophysicalLUT:
|
||
"""Precomputed 262,144-entry constraint surface.
|
||
In hardware, this is a BRAM block. In Python, a list."""
|
||
|
||
def __init__(self):
|
||
print("[INFO] Precomputing biophysical LUT (262,144 entries)...")
|
||
self.entries = [
|
||
compute_constraint_entry(QuantizedGenome.from_address(addr))
|
||
for addr in range(ADDR_SPACE)
|
||
]
|
||
lawful_count = sum(1 for e in self.entries if e.lawful)
|
||
print(f"[INFO] LUT ready: {lawful_count} lawful states ({100*lawful_count/ADDR_SPACE:.1f}%)")
|
||
|
||
def lookup(self, addr: int) -> ConstraintEntry:
|
||
if not (0 <= addr < ADDR_SPACE):
|
||
return ConstraintEntry(lawful=False, cost=0xFFFFFFFF,
|
||
drake_ok=False, drift_ok=False, error_ok=False)
|
||
return self.entries[addr]
|
||
|
||
|
||
# Global singleton (precomputed once)
|
||
BIOPHYSICAL_LUT = BiophysicalLUT()
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# §4 Connectome state quantization from OpenWorm Parquet
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
@dataclass
|
||
class ConnectomeState:
|
||
dataset_name: str
|
||
edge_count: int
|
||
cell_count: int
|
||
quantized: QuantizedGenome
|
||
|
||
def to_address(self) -> int:
|
||
return self.quantized.to_address()
|
||
|
||
def lookup(self) -> ConstraintEntry:
|
||
return BIOPHYSICAL_LUT.lookup(self.to_address())
|
||
|
||
|
||
def quantize_edge_count(n_edges: int) -> int:
|
||
return max(0, min(7, (n_edges // 1000) - 1))
|
||
|
||
|
||
def quantize_ne(ne: float) -> int:
|
||
return max(0, min(7, int(ne / 0.5) - 1))
|
||
|
||
|
||
def quantize_u(u: float) -> int:
|
||
return max(0, min(7, int(u / 0.001) - 1))
|
||
|
||
|
||
def quantize_sigma(sigma: float) -> int:
|
||
return max(0, min(7, int((sigma - 1.0) / 0.25) - 1))
|
||
|
||
|
||
def quantize_connectance(n_edges: int, n_cells: int) -> int:
|
||
"""Edge density: E / (N*(N-1)) for directed graphs, binned 0-7."""
|
||
if n_cells <= 1:
|
||
return 0
|
||
max_edges = n_cells * (n_cells - 1)
|
||
density = n_edges / max_edges
|
||
return max(0, min(7, int(density * 8)))
|
||
|
||
|
||
def quantize_modularity(_n_edges: int, _n_cells: int) -> int:
|
||
"""Placeholder: modularity would require community detection.
|
||
For now, default to middle bin (3)."""
|
||
return 3
|
||
|
||
|
||
def load_openworm_dataset(parquet_dir: Path, dataset_name: str) -> Optional[ConnectomeState]:
|
||
conn_file = parquet_dir / f"{dataset_name}_connections.parquet"
|
||
if not conn_file.exists():
|
||
return None
|
||
|
||
df = pd.read_parquet(conn_file)
|
||
n_edges = len(df)
|
||
|
||
ne_default = 2.5
|
||
u_default = 0.003
|
||
sigma_default = 1.5
|
||
|
||
cells_file = parquet_dir / f"{dataset_name}_cells.parquet"
|
||
n_cells = 0
|
||
if cells_file.exists():
|
||
cells_df = pd.read_parquet(cells_file)
|
||
n_cells = len(cells_df)
|
||
|
||
q = QuantizedGenome(
|
||
g_bin=quantize_edge_count(n_edges),
|
||
ne_bin=quantize_ne(ne_default),
|
||
u_bin=quantize_u(u_default),
|
||
sigma_bin=quantize_sigma(sigma_default),
|
||
connectance_bin=quantize_connectance(n_edges, n_cells),
|
||
modularity_bin=quantize_modularity(n_edges, n_cells),
|
||
)
|
||
|
||
return ConnectomeState(
|
||
dataset_name=dataset_name,
|
||
edge_count=n_edges,
|
||
cell_count=n_cells,
|
||
quantized=q,
|
||
)
|
||
|
||
|
||
def load_all_openworm_states(parquet_dir: Path) -> List[ConnectomeState]:
|
||
conn_files = sorted(parquet_dir.glob("*_connections.parquet"))
|
||
states = []
|
||
for conn_file in conn_files:
|
||
name = conn_file.stem.replace("_connections", "")
|
||
state = load_openworm_dataset(parquet_dir, name)
|
||
if state:
|
||
states.append(state)
|
||
return states
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# §5 Quantum Walk: Stochastic Traversal via Speculative Evaluation
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
@dataclass
|
||
class BTBEntry:
|
||
source: int
|
||
target: int
|
||
confidence: int # 0-3
|
||
streak: int = 0 # consecutive correct predictions
|
||
|
||
|
||
class BranchTargetBuffer:
|
||
"""Simple BTB with up to 16 entries and streak tracking."""
|
||
|
||
def __init__(self):
|
||
self.entries: Dict[int, BTBEntry] = {}
|
||
|
||
def lookup(self, addr: int) -> Optional[BTBEntry]:
|
||
return self.entries.get(addr)
|
||
|
||
def update_hit(self, addr: int):
|
||
if addr in self.entries:
|
||
e = self.entries[addr]
|
||
e.confidence = min(3, e.confidence + 1)
|
||
e.streak = e.streak + 1
|
||
|
||
def update_miss(self, source: int, target: int):
|
||
if source not in self.entries:
|
||
if len(self.entries) >= 16:
|
||
# Evict lowest-confidence entry
|
||
min_addr = min(self.entries, key=lambda k: self.entries[k].confidence)
|
||
del self.entries[min_addr]
|
||
self.entries[source] = BTBEntry(source=source, target=target, confidence=1, streak=0)
|
||
|
||
def is_stable(self, addr: int) -> bool:
|
||
e = self.entries.get(addr)
|
||
return e is not None and e.streak >= STREAK_THRESHOLD
|
||
|
||
|
||
@dataclass
|
||
class SpeculativeBundle:
|
||
primary: int
|
||
alt1: int
|
||
alt2: int
|
||
alt3: int
|
||
mask1: bool = True
|
||
mask2: bool = True
|
||
mask3: bool = True
|
||
|
||
|
||
@dataclass
|
||
class SpeculativeBundle8:
|
||
primary: int
|
||
alt1: int
|
||
alt2: int
|
||
alt3: int
|
||
alt4: int
|
||
alt5: int
|
||
alt6: int
|
||
alt7: int
|
||
mask1: bool = True
|
||
mask2: bool = True
|
||
mask3: bool = True
|
||
mask4: bool = True
|
||
mask5: bool = True
|
||
mask6: bool = True
|
||
mask7: bool = True
|
||
|
||
|
||
@dataclass
|
||
class SpeculativeBundle16:
|
||
primary: int
|
||
alt1: int
|
||
alt2: int
|
||
alt3: int
|
||
alt4: int
|
||
alt5: int
|
||
alt6: int
|
||
alt7: int
|
||
alt8: int
|
||
alt9: int
|
||
alt10: int
|
||
alt11: int
|
||
alt12: int
|
||
alt13: int
|
||
alt14: int
|
||
alt15: int
|
||
mask1: bool = True
|
||
mask2: bool = True
|
||
mask3: bool = True
|
||
mask4: bool = True
|
||
mask5: bool = True
|
||
mask6: bool = True
|
||
mask7: bool = True
|
||
mask8: bool = True
|
||
mask9: bool = True
|
||
mask10: bool = True
|
||
mask11: bool = True
|
||
mask12: bool = True
|
||
mask13: bool = True
|
||
mask14: bool = True
|
||
mask15: bool = True
|
||
|
||
|
||
def evaluate_bundle(bundle: SpeculativeBundle) -> List[Tuple[int, ConstraintEntry]]:
|
||
candidates = [
|
||
(True, bundle.primary),
|
||
(bundle.mask1, bundle.alt1),
|
||
(bundle.mask2, bundle.alt2),
|
||
(bundle.mask3, bundle.alt3),
|
||
]
|
||
results = []
|
||
for active, addr in candidates:
|
||
if active:
|
||
entry = BIOPHYSICAL_LUT.lookup(addr)
|
||
if entry.lawful:
|
||
results.append((addr, entry))
|
||
return results
|
||
|
||
|
||
def evaluate_bundle8(bundle: SpeculativeBundle8) -> List[Tuple[int, ConstraintEntry]]:
|
||
candidates = [
|
||
(True, bundle.primary),
|
||
(bundle.mask1, bundle.alt1),
|
||
(bundle.mask2, bundle.alt2),
|
||
(bundle.mask3, bundle.alt3),
|
||
(bundle.mask4, bundle.alt4),
|
||
(bundle.mask5, bundle.alt5),
|
||
(bundle.mask6, bundle.alt6),
|
||
(bundle.mask7, bundle.alt7),
|
||
]
|
||
results = []
|
||
for active, addr in candidates:
|
||
if active:
|
||
entry = BIOPHYSICAL_LUT.lookup(addr)
|
||
if entry.lawful:
|
||
results.append((addr, entry))
|
||
return results
|
||
|
||
|
||
def evaluate_bundle16(bundle: SpeculativeBundle16) -> List[Tuple[int, ConstraintEntry]]:
|
||
candidates = [
|
||
(True, bundle.primary),
|
||
(bundle.mask1, bundle.alt1),
|
||
(bundle.mask2, bundle.alt2),
|
||
(bundle.mask3, bundle.alt3),
|
||
(bundle.mask4, bundle.alt4),
|
||
(bundle.mask5, bundle.alt5),
|
||
(bundle.mask6, bundle.alt6),
|
||
(bundle.mask7, bundle.alt7),
|
||
(bundle.mask8, bundle.alt8),
|
||
(bundle.mask9, bundle.alt9),
|
||
(bundle.mask10, bundle.alt10),
|
||
(bundle.mask11, bundle.alt11),
|
||
(bundle.mask12, bundle.alt12),
|
||
(bundle.mask13, bundle.alt13),
|
||
(bundle.mask14, bundle.alt14),
|
||
(bundle.mask15, bundle.alt15),
|
||
]
|
||
results = []
|
||
for active, addr in candidates:
|
||
if active:
|
||
entry = BIOPHYSICAL_LUT.lookup(addr)
|
||
if entry.lawful:
|
||
results.append((addr, entry))
|
||
return results
|
||
|
||
|
||
def quantum_walk_step(current: int, btb: BranchTargetBuffer) -> Tuple[int, BranchTargetBuffer, ConstraintEntry]:
|
||
"""One step of the quantum walk (4-way bundle)."""
|
||
entry = btb.lookup(current)
|
||
if entry:
|
||
prediction = entry.target
|
||
else:
|
||
prediction = (current + 1) % ADDR_SPACE
|
||
|
||
bundle = SpeculativeBundle(
|
||
primary=prediction,
|
||
alt1=(current + 1) % ADDR_SPACE,
|
||
alt2=(current + 8) % ADDR_SPACE,
|
||
alt3=(current + 64) % ADDR_SPACE,
|
||
)
|
||
|
||
results = evaluate_bundle(bundle)
|
||
if not results:
|
||
btb.update_miss(current, current)
|
||
return current, btb, BIOPHYSICAL_LUT.lookup(current)
|
||
|
||
best_addr, best_entry = min(results, key=lambda x: x[1].cost)
|
||
if best_addr == prediction:
|
||
btb.update_hit(current)
|
||
else:
|
||
btb.update_miss(current, best_addr)
|
||
|
||
return best_addr, btb, best_entry
|
||
|
||
|
||
def quantum_walk_step8(current: int, btb: BranchTargetBuffer) -> Tuple[int, BranchTargetBuffer, ConstraintEntry]:
|
||
"""One step of the quantum walk (8-way bundle)."""
|
||
entry = btb.lookup(current)
|
||
if entry:
|
||
prediction = entry.target
|
||
else:
|
||
prediction = (current + 1) % ADDR_SPACE
|
||
|
||
bundle = SpeculativeBundle8(
|
||
primary=prediction,
|
||
alt1=(current + 1) % ADDR_SPACE, # modularity
|
||
alt2=(current + 8) % ADDR_SPACE, # connectance
|
||
alt3=(current + 64) % ADDR_SPACE, # sigma
|
||
alt4=(current + 512) % ADDR_SPACE, # u
|
||
alt5=(current + 4096) % ADDR_SPACE, # Ne
|
||
alt6=(current + 32768) % ADDR_SPACE, # g
|
||
alt7=(current + 2) % ADDR_SPACE, # fine modularity
|
||
)
|
||
|
||
results = evaluate_bundle8(bundle)
|
||
if not results:
|
||
btb.update_miss(current, current)
|
||
return current, btb, BIOPHYSICAL_LUT.lookup(current)
|
||
|
||
best_addr, best_entry = min(results, key=lambda x: x[1].cost)
|
||
if best_addr == prediction:
|
||
btb.update_hit(current)
|
||
else:
|
||
btb.update_miss(current, best_addr)
|
||
|
||
return best_addr, btb, best_entry
|
||
|
||
|
||
def quantum_walk_step16(current: int, btb: BranchTargetBuffer) -> Tuple[int, BranchTargetBuffer, ConstraintEntry]:
|
||
"""One step of the quantum walk (16-way bundle)."""
|
||
entry = btb.lookup(current)
|
||
if entry:
|
||
prediction = entry.target
|
||
else:
|
||
prediction = (current + 1) % ADDR_SPACE
|
||
|
||
bundle = SpeculativeBundle16(
|
||
primary=prediction,
|
||
alt1=(current + 1) % ADDR_SPACE,
|
||
alt2=(current + 2) % ADDR_SPACE,
|
||
alt3=(current + 4) % ADDR_SPACE,
|
||
alt4=(current + 8) % ADDR_SPACE,
|
||
alt5=(current + 16) % ADDR_SPACE,
|
||
alt6=(current + 32) % ADDR_SPACE,
|
||
alt7=(current + 64) % ADDR_SPACE,
|
||
alt8=(current + 128) % ADDR_SPACE,
|
||
alt9=(current + 256) % ADDR_SPACE,
|
||
alt10=(current + 512) % ADDR_SPACE,
|
||
alt11=(current + 1024) % ADDR_SPACE,
|
||
alt12=(current + 2048) % ADDR_SPACE,
|
||
alt13=(current + 4096) % ADDR_SPACE,
|
||
alt14=(current + 8192) % ADDR_SPACE,
|
||
alt15=(current + 16384) % ADDR_SPACE,
|
||
)
|
||
|
||
results = evaluate_bundle16(bundle)
|
||
if not results:
|
||
btb.update_miss(current, current)
|
||
return current, btb, BIOPHYSICAL_LUT.lookup(current)
|
||
|
||
best_addr, best_entry = min(results, key=lambda x: x[1].cost)
|
||
if best_addr == prediction:
|
||
btb.update_hit(current)
|
||
else:
|
||
btb.update_miss(current, best_addr)
|
||
|
||
return best_addr, btb, best_entry
|
||
|
||
|
||
def quantum_walk_step_pattern(current: int, btb: BranchTargetBuffer) -> Tuple[int, BranchTargetBuffer, ConstraintEntry]:
|
||
"""Pattern-aware quantum walk step with BTB short-circuit.
|
||
If the BTB entry has a stable streak (≥ threshold), skip bundle
|
||
evaluation and follow the BTB target directly."""
|
||
entry = btb.lookup(current)
|
||
if entry and btb.is_stable(current):
|
||
# Stable pattern: short-circuit
|
||
btb.update_hit(current)
|
||
return entry.target, btb, BIOPHYSICAL_LUT.lookup(entry.target)
|
||
|
||
# Unstable or no BTB entry: fall back to 8-way speculative evaluation
|
||
return quantum_walk_step8(current, btb)
|
||
|
||
|
||
def run_quantum_walk(seed_addr: int, steps: int = 100, mode: str = "pattern") -> List[Tuple[int, ConstraintEntry]]:
|
||
"""Run a quantum walk for N steps from a seed address.
|
||
mode: "4way", "8way", "16way", or "pattern" (default)."""
|
||
btb = BranchTargetBuffer()
|
||
trajectory = []
|
||
current = seed_addr
|
||
short_circuits = 0
|
||
|
||
step_fn = {
|
||
"4way": quantum_walk_step,
|
||
"8way": quantum_walk_step8,
|
||
"16way": quantum_walk_step16,
|
||
"pattern": quantum_walk_step_pattern,
|
||
}.get(mode, quantum_walk_step_pattern)
|
||
|
||
for _ in range(steps):
|
||
prev = current
|
||
current, btb, entry = step_fn(current, btb)
|
||
if mode == "pattern" and prev != current and btb.is_stable(prev):
|
||
short_circuits += 1
|
||
trajectory.append((current, entry))
|
||
|
||
return trajectory, short_circuits
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# §6 JSON serialization for swarm consumption
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
def state_to_json(state: ConnectomeState) -> dict:
|
||
entry = state.lookup()
|
||
return {
|
||
"dataset": state.dataset_name,
|
||
"edge_count": state.edge_count,
|
||
"cell_count": state.cell_count,
|
||
"address": state.to_address(),
|
||
"quantized": {
|
||
"g_bin": state.quantized.g_bin,
|
||
"ne_bin": state.quantized.ne_bin,
|
||
"u_bin": state.quantized.u_bin,
|
||
"sigma_bin": state.quantized.sigma_bin,
|
||
"connectance_bin": state.quantized.connectance_bin,
|
||
"modularity_bin": state.quantized.modularity_bin,
|
||
},
|
||
"lawful": entry.lawful,
|
||
"cost": entry.cost,
|
||
"drake_ok": entry.drake_ok,
|
||
"drift_ok": entry.drift_ok,
|
||
"error_ok": entry.error_ok,
|
||
}
|
||
|
||
|
||
def trajectory_to_json(trajectory: List[Tuple[int, ConstraintEntry]]) -> List[dict]:
|
||
return [
|
||
{
|
||
"step": i,
|
||
"address": addr,
|
||
"lawful": entry.lawful,
|
||
"cost": entry.cost,
|
||
"drake_ok": entry.drake_ok,
|
||
"drift_ok": entry.drift_ok,
|
||
"error_ok": entry.error_ok,
|
||
}
|
||
for i, (addr, entry) in enumerate(trajectory)
|
||
]
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# §7 Verilog generation (hardware extraction)
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
def generate_verilog_lut(output_path: Path):
|
||
"""Generate Verilog modules for the biophysical LUT and speculative evaluators.
|
||
Includes 4-way, 8-way, and 16-way speculative evaluator modules."""
|
||
lines = []
|
||
lines.append("// Auto-generated from connectome_lut_shim.py")
|
||
lines.append("// Biophysical Constraint LUT: 262,144 entries, 18-bit address")
|
||
lines.append("// Each entry: {lawful(1), cost(32), drake_ok(1), drift_ok(1), error_ok(1)}")
|
||
lines.append("")
|
||
lines.append("module BiophysicalLUT (")
|
||
lines.append(" input [17:0] addr,")
|
||
lines.append(" output lawful,")
|
||
lines.append(" output [31:0] cost,")
|
||
lines.append(" output drake_ok,")
|
||
lines.append(" output drift_ok,")
|
||
lines.append(" output error_ok")
|
||
lines.append(");")
|
||
lines.append("")
|
||
lines.append(" // Entry encoding: {cost[31:0], lawful, drake_ok, drift_ok, error_ok}")
|
||
lines.append(" // For 262K entries, use external BRAM initialization.")
|
||
lines.append(" // This module declares the interface; initialization is via $readmemh.")
|
||
lines.append("")
|
||
lines.append(" reg [35:0] lut_mem [0:262143]; // 36-bit word: 32b cost + 4b flags")
|
||
lines.append("")
|
||
lines.append(" initial begin")
|
||
lines.append(' $display("Loading biophysical LUT from biophysical_lut.hex...");')
|
||
lines.append(' $readmemh("biophysical_lut.hex", lut_mem);')
|
||
lines.append(" end")
|
||
lines.append("")
|
||
lines.append(" wire [35:0] entry = lut_mem[addr];")
|
||
lines.append(" assign cost = entry[35:4];")
|
||
lines.append(" assign lawful = entry[3];")
|
||
lines.append(" assign drake_ok = entry[2];")
|
||
lines.append(" assign drift_ok = entry[1];")
|
||
lines.append(" assign error_ok = entry[0];")
|
||
lines.append("")
|
||
lines.append("endmodule")
|
||
lines.append("")
|
||
|
||
# 4-way evaluator
|
||
lines.append("// Speculative evaluation unit: 4-way bundle")
|
||
lines.append("module SpeculativeEvaluator (")
|
||
lines.append(" input [17:0] primary,")
|
||
lines.append(" input [17:0] alt1,")
|
||
lines.append(" input [17:0] alt2,")
|
||
lines.append(" input [17:0] alt3,")
|
||
lines.append(" input mask1,")
|
||
lines.append(" input mask2,")
|
||
lines.append(" input mask3,")
|
||
lines.append(" output [17:0] best_addr,")
|
||
lines.append(" output [31:0] best_cost,")
|
||
lines.append(" output best_lawful")
|
||
lines.append(");")
|
||
lines.append("")
|
||
lines.append(" wire [31:0] cost_p, cost_1, cost_2, cost_3;")
|
||
lines.append(" wire law_p, law_1, law_2, law_3;")
|
||
lines.append("")
|
||
lines.append(" BiophysicalLUT lut_p (.addr(primary), .cost(cost_p), .lawful(law_p), .drake_ok(), .drift_ok(), .error_ok());")
|
||
lines.append(" BiophysicalLUT lut_1 (.addr(alt1), .cost(cost_1), .lawful(law_1), .drake_ok(), .drift_ok(), .error_ok());")
|
||
lines.append(" BiophysicalLUT lut_2 (.addr(alt2), .cost(cost_2), .lawful(law_2), .drake_ok(), .drift_ok(), .error_ok());")
|
||
lines.append(" BiophysicalLUT lut_3 (.addr(alt3), .cost(cost_3), .lawful(law_3), .drake_ok(), .drift_ok(), .error_ok());")
|
||
lines.append("")
|
||
lines.append(" // Priority encoder: select lowest-cost lawful address")
|
||
lines.append(" assign best_addr = law_p ? primary : (law_1 & mask1) ? alt1 : (law_2 & mask2) ? alt2 : (law_3 & mask3) ? alt3 : primary;")
|
||
lines.append(" assign best_cost = law_p ? cost_p : (law_1 & mask1) ? cost_1 : (law_2 & mask2) ? cost_2 : (law_3 & mask3) ? cost_3 : 32'hFFFFFFFF;")
|
||
lines.append(" assign best_lawful = law_p | (law_1 & mask1) | (law_2 & mask2) | (law_3 & mask3);")
|
||
lines.append("")
|
||
lines.append("endmodule")
|
||
lines.append("")
|
||
|
||
# 8-way evaluator
|
||
lines.append("// Speculative evaluation unit: 8-way bundle")
|
||
lines.append("module SpeculativeEvaluator8 (")
|
||
for i in range(8):
|
||
lines.append(f" input [17:0] {'primary' if i == 0 else f'alt{i}'},")
|
||
for i in range(1, 8):
|
||
lines.append(f" input mask{i},")
|
||
lines.append(" output [17:0] best_addr,")
|
||
lines.append(" output [31:0] best_cost,")
|
||
lines.append(" output best_lawful")
|
||
lines.append(");")
|
||
lines.append("")
|
||
lines.append(" wire [31:0] cost_p, cost_1, cost_2, cost_3, cost_4, cost_5, cost_6, cost_7;")
|
||
lines.append(" wire law_p, law_1, law_2, law_3, law_4, law_5, law_6, law_7;")
|
||
lines.append("")
|
||
for i, name in enumerate(["p", "1", "2", "3", "4", "5", "6", "7"]):
|
||
addr = "primary" if i == 0 else f"alt{i}"
|
||
lines.append(f" BiophysicalLUT lut_{name} (.addr({addr}), .cost(cost_{name}), .lawful(law_{name}), .drake_ok(), .drift_ok(), .error_ok());")
|
||
lines.append("")
|
||
lines.append(" // Priority encoder: select lowest-cost lawful address (primary highest priority)")
|
||
sel = "law_p ? primary : "
|
||
for i in range(1, 8):
|
||
sel += f"(law_{i} & mask{i}) ? alt{i} : "
|
||
sel += "primary;"
|
||
lines.append(f" assign best_addr = {sel}")
|
||
sel_cost = "law_p ? cost_p : "
|
||
for i in range(1, 8):
|
||
sel_cost += f"(law_{i} & mask{i}) ? cost_{i} : "
|
||
sel_cost += "32'hFFFFFFFF;"
|
||
lines.append(f" assign best_cost = {sel_cost}")
|
||
sel_law = "law_p"
|
||
for i in range(1, 8):
|
||
sel_law += f" | (law_{i} & mask{i})"
|
||
sel_law += ";"
|
||
lines.append(f" assign best_lawful = {sel_law}")
|
||
lines.append("")
|
||
lines.append("endmodule")
|
||
lines.append("")
|
||
|
||
# 16-way evaluator
|
||
lines.append("// Speculative evaluation unit: 16-way bundle")
|
||
lines.append("module SpeculativeEvaluator16 (")
|
||
for i in range(16):
|
||
lines.append(f" input [17:0] {'primary' if i == 0 else f'alt{i}'},")
|
||
for i in range(1, 16):
|
||
lines.append(f" input mask{i},")
|
||
lines.append(" output [17:0] best_addr,")
|
||
lines.append(" output [31:0] best_cost,")
|
||
lines.append(" output best_lawful")
|
||
lines.append(");")
|
||
lines.append("")
|
||
lines.append(" wire [31:0] cost_p, " + ", ".join([f"cost_{i}" for i in range(1, 16)]) + ";")
|
||
lines.append(" wire law_p, " + ", ".join([f"law_{i}" for i in range(1, 16)]) + ";")
|
||
lines.append("")
|
||
for i, name in enumerate(["p"] + [str(j) for j in range(1, 16)]):
|
||
addr = "primary" if i == 0 else f"alt{i}"
|
||
lines.append(f" BiophysicalLUT lut_{name} (.addr({addr}), .cost(cost_{name}), .lawful(law_{name}), .drake_ok(), .drift_ok(), .error_ok());")
|
||
lines.append("")
|
||
lines.append(" // Priority encoder: select lowest-cost lawful address (primary highest priority)")
|
||
sel = "law_p ? primary : "
|
||
for i in range(1, 16):
|
||
sel += f"(law_{i} & mask{i}) ? alt{i} : "
|
||
sel += "primary;"
|
||
lines.append(f" assign best_addr = {sel}")
|
||
sel_cost = "law_p ? cost_p : "
|
||
for i in range(1, 16):
|
||
sel_cost += f"(law_{i} & mask{i}) ? cost_{i} : "
|
||
sel_cost += "32'hFFFFFFFF;"
|
||
lines.append(f" assign best_cost = {sel_cost}")
|
||
sel_law = "law_p"
|
||
for i in range(1, 16):
|
||
sel_law += f" | (law_{i} & mask{i})"
|
||
sel_law += ";"
|
||
lines.append(f" assign best_lawful = {sel_law}")
|
||
lines.append("")
|
||
lines.append("endmodule")
|
||
lines.append("")
|
||
|
||
# BTB pattern detector module
|
||
lines.append("// BTB Pattern Detector with streak-based short-circuit")
|
||
lines.append("module PatternDetector (")
|
||
lines.append(" input clk,")
|
||
lines.append(" input rst,")
|
||
lines.append(" input [17:0] current_addr,")
|
||
lines.append(" input [17:0] predicted_target,")
|
||
lines.append(" input hit,")
|
||
lines.append(" output stable,")
|
||
lines.append(" output [17:0] stable_target")
|
||
lines.append(");")
|
||
lines.append("")
|
||
lines.append(" // Simple direct-mapped BTB with streak counter (4 entries for demo)")
|
||
lines.append(" reg [17:0] btb_source [0:3];")
|
||
lines.append(" reg [17:0] btb_target [0:3];")
|
||
lines.append(" reg [1:0] btb_conf [0:3];")
|
||
lines.append(" reg [2:0] btb_streak [0:3];")
|
||
lines.append(" reg btb_valid [0:3];")
|
||
lines.append("")
|
||
lines.append(" wire [1:0] idx = current_addr[1:0]; // 2-bit index (demo: 4 entries)")
|
||
lines.append(" wire match_found = btb_valid[idx] && (btb_source[idx] == current_addr);")
|
||
lines.append(" wire is_stable = match_found && (btb_streak[idx] >= 3'd4);")
|
||
lines.append("")
|
||
lines.append(" assign stable = is_stable;")
|
||
lines.append(" assign stable_target = btb_target[idx];")
|
||
lines.append("")
|
||
lines.append(" integer i;")
|
||
lines.append(" always @(posedge clk or posedge rst) begin")
|
||
lines.append(" if (rst) begin")
|
||
lines.append(" for (i = 0; i < 4; i = i + 1) begin")
|
||
lines.append(" btb_valid[i] <= 1'b0;")
|
||
lines.append(" btb_streak[i] <= 3'd0;")
|
||
lines.append(" btb_conf[i] <= 2'd0;")
|
||
lines.append(" end")
|
||
lines.append(" end else begin")
|
||
lines.append(" if (hit && match_found) begin")
|
||
lines.append(" // Increment confidence and streak on hit")
|
||
lines.append(" btb_conf[idx] <= (btb_conf[idx] < 2'd3) ? btb_conf[idx] + 1 : 2'd3;")
|
||
lines.append(" btb_streak[idx] <= btb_streak[idx] + 1;")
|
||
lines.append(" end else if (!hit && match_found) begin")
|
||
lines.append(" // Reset streak on miss")
|
||
lines.append(" btb_streak[idx] <= 3'd0;")
|
||
lines.append(" end else if (!match_found) begin")
|
||
lines.append(" // Insert new entry")
|
||
lines.append(" btb_valid[idx] <= 1'b1;")
|
||
lines.append(" btb_source[idx] <= current_addr;")
|
||
lines.append(" btb_target[idx] <= predicted_target;")
|
||
lines.append(" btb_conf[idx] <= 2'd1;")
|
||
lines.append(" btb_streak[idx] <= 3'd0;")
|
||
lines.append(" end")
|
||
lines.append(" end")
|
||
lines.append(" end")
|
||
lines.append("")
|
||
lines.append("endmodule")
|
||
|
||
with open(output_path, "w") as f:
|
||
f.write("\n".join(lines))
|
||
print(f"[OK] Verilog module written to {output_path}")
|
||
|
||
|
||
def generate_lut_hex(output_path: Path):
|
||
"""Generate hex initialization file for the LUT BRAM.
|
||
Format: 36-bit hex words (8 hex digits + 1 nibble for flags)."""
|
||
lines = []
|
||
for addr in range(ADDR_SPACE):
|
||
entry = BIOPHYSICAL_LUT.lookup(addr)
|
||
# Pack: cost[31:0] | lawful | drake_ok | drift_ok | error_ok
|
||
flags = (int(entry.lawful) << 3) | (int(entry.drake_ok) << 2) | (int(entry.drift_ok) << 1) | int(entry.error_ok)
|
||
word = (entry.cost << 4) | flags
|
||
lines.append(f"{word:09X}")
|
||
|
||
with open(output_path, "w") as f:
|
||
f.write("\n".join(lines))
|
||
print(f"[OK] LUT hex file written to {output_path}")
|
||
|
||
|
||
def generate_yosys_script(output_dir: Path):
|
||
"""Generate Yosys synthesis script for iCE40 target.
|
||
Synthesizes the 8-way speculative evaluator and reports resource usage."""
|
||
script = """# Yosys synthesis script for CooperativeLUT iCE40 target
|
||
# Generated by connectome_lut_shim.py
|
||
|
||
# Read design
|
||
read_verilog biophysical_lut.v
|
||
|
||
# Generic synthesis (technology-independent optimization)
|
||
synth -top SpeculativeEvaluator8
|
||
|
||
# Technology mapping for iCE40
|
||
# Note: The full 262K LUT won't fit in iCE40 SPRAM (max ~128KB).
|
||
# For a real build, external SRAM or a larger FPGA (ECP5, Xilinx) is needed.
|
||
# This script targets a parameterized small-LUT version for iCE40UP5K.
|
||
synth_ice40 -top SpeculativeEvaluator8 -json speculative_evaluator8.json
|
||
|
||
# Resource report
|
||
stat
|
||
|
||
# Write BLIF for nextpnr-ice40
|
||
write_blif speculative_evaluator8.blif
|
||
"""
|
||
script_path = output_dir / "synth_ice40.ys"
|
||
with open(script_path, "w") as f:
|
||
f.write(script)
|
||
print(f"[OK] Yosys synthesis script written to {script_path}")
|
||
return script_path
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# §8 CLI / main execution
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
def main():
|
||
parquet_dir = Path("shared-data/data/connectomes/openworm_parquet")
|
||
if not parquet_dir.exists():
|
||
print(f"[ERROR] Parquet directory not found: {parquet_dir}", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
print("[INFO] Loading OpenWorm connectome datasets...")
|
||
states = load_all_openworm_states(parquet_dir)
|
||
print(f"[INFO] Loaded {len(states)} datasets")
|
||
|
||
# Seed states
|
||
seed_json = [state_to_json(s) for s in states]
|
||
print("\n=== SEED STATES (sample) ===")
|
||
print(json.dumps(seed_json[:5], indent=2))
|
||
|
||
trajectory = []
|
||
short_circuits = 0
|
||
mode_summary = {}
|
||
|
||
# Quantum walks from first dataset
|
||
if states:
|
||
seed_state = states[0]
|
||
seed_addr = seed_state.to_address()
|
||
|
||
for mode in ["4way", "8way", "16way", "pattern"]:
|
||
print(f"\n[INFO] Running quantum walk ({mode}) from {seed_state.dataset_name} (addr={seed_addr})...")
|
||
traj, sc = run_quantum_walk(seed_addr, steps=50, mode=mode)
|
||
lawful_steps = sum(1 for _, e in traj if e.lawful)
|
||
mode_summary[mode] = {
|
||
"lawful_steps": lawful_steps,
|
||
"short_circuits": sc,
|
||
}
|
||
print(f"[INFO] {mode} complete: {lawful_steps}/50 lawful steps, {sc} short-circuits")
|
||
|
||
if mode == "pattern":
|
||
trajectory = traj
|
||
short_circuits = sc
|
||
|
||
print("\n=== QUANTUM WALK TRAJECTORY (pattern, first 10 steps) ===")
|
||
print(json.dumps(trajectory_to_json(trajectory[:10]), indent=2))
|
||
|
||
# Generate Verilog
|
||
verilog_dir = Path("5-Applications/out/verilog")
|
||
verilog_dir.mkdir(parents=True, exist_ok=True)
|
||
generate_verilog_lut(verilog_dir / "biophysical_lut.v")
|
||
generate_lut_hex(verilog_dir / "biophysical_lut.hex")
|
||
generate_yosys_script(verilog_dir)
|
||
|
||
# Run Yosys synthesis if available
|
||
yosys_bin = Path("/usr/bin/yosys")
|
||
if yosys_bin.exists():
|
||
print("\n[INFO] Running Yosys synthesis for resource estimation...")
|
||
import subprocess
|
||
try:
|
||
result = subprocess.run(
|
||
[str(yosys_bin), "-s", "synth_ice40.ys"],
|
||
cwd=verilog_dir,
|
||
capture_output=True,
|
||
text=True,
|
||
timeout=60,
|
||
)
|
||
# Extract resource stats from the 'stat' section
|
||
# Yosys prints stats multiple times; we want the one with SB_LUT4 counts
|
||
stats_blocks = []
|
||
current_block = []
|
||
in_block = False
|
||
for line in result.stdout.splitlines():
|
||
if "=== SpeculativeEvaluator8 ===" in line:
|
||
if in_block and current_block:
|
||
stats_blocks.append(current_block)
|
||
in_block = True
|
||
current_block = [line]
|
||
elif in_block:
|
||
if line.startswith("=== ") and "SpeculativeEvaluator8" not in line:
|
||
in_block = False
|
||
stats_blocks.append(current_block)
|
||
current_block = []
|
||
else:
|
||
current_block.append(line)
|
||
if current_block and in_block:
|
||
stats_blocks.append(current_block)
|
||
|
||
# Find the block that contains SB_LUT4
|
||
best_block = []
|
||
for block in stats_blocks:
|
||
if any("SB_LUT4" in line for line in block):
|
||
best_block = block
|
||
break
|
||
|
||
if best_block:
|
||
print("\n=== YOSYS RESOURCE ESTIMATE (SpeculativeEvaluator8, iCE40) ===")
|
||
for line in best_block[:25]:
|
||
print(line)
|
||
else:
|
||
print("\n=== YOSYS OUTPUT (tail) ===")
|
||
for line in result.stdout.splitlines()[-40:]:
|
||
print(line)
|
||
|
||
# Save full log
|
||
with open(verilog_dir / "yosys.log", "w") as f:
|
||
f.write(result.stdout)
|
||
f.write(result.stderr)
|
||
print(f"\n[OK] Yosys log saved to {verilog_dir / 'yosys.log'}")
|
||
except Exception as e:
|
||
print(f"[WARN] Yosys synthesis failed: {e}")
|
||
else:
|
||
print("[INFO] Yosys not found; skipping synthesis.")
|
||
|
||
# Save full results
|
||
out_file = Path("5-Applications/out/connectome_lut_results.json")
|
||
out_file.parent.mkdir(parents=True, exist_ok=True)
|
||
with open(out_file, "w") as f:
|
||
json.dump({
|
||
"seed_states": seed_json,
|
||
"quantum_walk": trajectory_to_json(trajectory),
|
||
"summary": {
|
||
"total_datasets": len(states),
|
||
"lut_entries": ADDR_SPACE,
|
||
"lawful_lut_fraction": sum(1 for e in BIOPHYSICAL_LUT.entries if e.lawful) / ADDR_SPACE,
|
||
"mode_comparison": mode_summary,
|
||
"short_circuits": short_circuits,
|
||
}
|
||
}, f, indent=2)
|
||
print(f"\n[OK] Full results saved to {out_file}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|