Research-Stack/4-Infrastructure/shim/chaos_game_16d.py
allaun 475f6319ea chore(repo): push local 768-commit branch state onto clean remote baseline
This squashes all local history (768 commits) onto the scrubbed PR #90
baseline. Individual commits were lost during filter-repo corruption;
the working tree content is preserved intact.

Build: N/A (working tree state only)
2026-06-15 22:46:50 -05:00

247 lines
8.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
16D Chaos Game via QR Braid Crossings.
The 16D manifold V₁₆ = (q_void, q_orbit, q_braid, q_observer) is encoded
as an 8×8 matrix where each row is a 2×4 block (8 strands × 2 quadrants).
Householder reflections (braid crossings) are randomly applied — the
accumulated trajectory is the shock front of the 16D chaos game.
The attractor structure reveals the "folded prime" geometry of the
16D search manifold.
Reference:
- VCN QR pipeline (vcn_dsp_pipeline.py) — Householder = braid crossing
- BraidShock 16D (braid_shock_16d.py) — 16D shock propagation
- 16D Manifold Adjustment doc — V₁₆ decomposition
"""
import hashlib
import json
import math
import random
from collections import Counter
from datetime import datetime, timezone
Q16 = 65536
EPSILON = 1e-14
def sidon(k):
return 1 << k
def random_householder(n):
"""Generate a random Householder reflector H = I - τ·v·vᵀ."""
v = [random.uniform(-1, 1) for _ in range(n)]
norm = math.sqrt(sum(xi * xi for xi in v))
if norm < EPSILON:
return [float(i == j) for i in range(n)], 0.0
v = [xi / norm for xi in v]
tau = 2.0 # full reflection for normalized v
return v, tau
def apply_reflector(A, k, v, tau):
"""Apply Householder reflector at column k of matrix A."""
m = len(A)
n = len(A[0])
for j in range(k, n):
dot = sum(v[i] * A[i][j] for i in range(m))
for i in range(m):
A[i][j] -= tau * v[i] * dot
class ChaosGame16D:
"""16D chaos game driven by random Householder braid crossings."""
def __init__(self, size=8):
self.size = size # 8×8 matrix encodes 16D state
self.history = []
self.quadrant_map = {
"q_void": (0, 3), # rows 0-3, cols 0-1 (4D)
"q_orbit": (0, 3), # rows 0-3, cols 2-3 (4D)
"q_braid": (4, 7), # rows 4-7, cols 0-1 (4D)
"q_observer": (4, 7), # rows 4-7, cols 2-3 (4D)
}
def init_state(self, mode="random"):
"""Initialize the 8×8 state matrix for the chaos game."""
A = [[0.0] * self.size for _ in range(self.size)]
if mode == "identity":
for i in range(self.size):
A[i][i] = 1.0
elif mode == "sidon":
# Sidon-labeled diagonal: powers of 2
for i in range(self.size):
A[i][i] = sidon(i)
elif mode == "random":
for i in range(self.size):
for j in range(self.size):
A[i][j] = random.uniform(-1, 1)
elif mode == "unit":
# All-ones matrix (uniform energy)
for i in range(self.size):
for j in range(self.size):
A[i][j] = 1.0
return A
def step(self, A, target_strand=None):
"""One chaos game step: apply a random Householder reflector.
If target_strand is None, picks a random strand (0..7).
Returns the reflector info and the new matrix."""
k = target_strand if target_strand is not None else random.randint(0, self.size - 1)
v, tau = random_householder(self.size - k)
# Pad v to full size
v_full = [0.0] * k + v
apply_reflector(A, k, v_full, tau)
return {
"strand": k,
"sidon": sidon(k),
"tau": round(tau, 4),
"nz": sum(1 for vi in v if abs(vi) > EPSILON),
}
def run(self, steps=1000, record_every=10):
"""Run the chaos game for `steps` iterations."""
A = self.init_state("random")
self.history = []
trace = []
for s in range(steps):
ref = self.step(A)
if s % record_every == 0:
# Compute quadrant energies
energy = self.quadrant_energy(A)
trace.append({
"step": s,
"last_strand": ref["strand"],
"sidon": ref["sidon"],
"energy": energy,
})
self.history = trace
return A
def quadrant_energy(self, A):
"""Compute energy in each 4D quadrant of the 16D manifold."""
qe = {}
for name, (r_start, r_end) in self.quadrant_map.items():
e = 0.0
for i in range(r_start, r_end + 1):
for j in range(self.size):
e += A[i][j] * A[i][j]
qe[name] = round(math.sqrt(e), 6)
qe["total"] = round(sum(qe.values()), 6)
return qe
def energy_ratio(self, A):
"""Compute q_braid / q_void energy ratio = braid tension."""
qe = self.quadrant_energy(A)
v = qe["q_void"]
return qe["q_braid"] / v if v > 0 else float("inf")
def sidon_sumset(self):
"""Compute the Sidon sumset of all visited strand pairs."""
pairs = set()
for t in self.history:
s = t["sidon"]
for other_s in [sidon(i) for i in range(self.size)]:
if other_s != s:
pairs.add(s + other_s)
return sorted(pairs)
def main():
random.seed(42)
print("=" * 60)
print("16D Chaos Game — QR Braid Crossing Model")
print("=" * 60)
game = ChaosGame16D()
# ─── Run multiple trajectories ───────────────────────────────────────
trajectories = []
for trial in range(5):
A = game.run(steps=500, record_every=25)
final_energy = game.quadrant_energy(A)
braid_tension = game.energy_ratio(A)
sumset = game.sidon_sumset()
print(f"\nTrial {trial + 1}:")
print(f" Final energy: {final_energy['total']:.4f}")
print(f" Braid tension: {braid_tension:.4f} (q_braid/q_void)")
print(f" Sidon sumset: {len(sumset)} unique sums")
print(f" Strand usage: {Counter(t['last_strand'] for t in game.history).most_common(3)}")
trajectories.append({
"trial": trial + 1,
"final_energy": final_energy,
"braid_tension": round(braid_tension, 4),
"sidon_sumset_size": len(sumset),
"sidon_sumset": sumset[:20], # first 20
"energy_evolution": game.history[::4],
})
# ─── Run with fixed Sidon sequence ───────────────────────────────────
print(f"\n{'' * 60}")
print("Sidon-ordered chaos: cycling strands 0..7 repeatedly")
A = game.init_state("sidon")
sidon_trace = []
for cycle in range(10):
for strand in range(8):
ref = game.step(A, target_strand=strand)
if cycle % 2 == 0:
sidon_trace.append({
"cycle": cycle,
"strand": strand,
"sidon": ref["sidon"],
"energy": game.quadrant_energy(A),
})
final = game.quadrant_energy(A)
print(f" Final energy: {final['total']:.4f}")
print(f" Quadrants: { {k: round(v, 4) for k, v in final.items()} }")
# ─── Receipt ─────────────────────────────────────────────────────────
receipt = {
"schema": "rrc_chaos_game_16d_v1",
"claim_boundary": "random_householder_braid_crossings_on_8x8;sidon_mapped_quadrants",
"description": (
"The 16D chaos game applies random Householder reflections "
"(braid crossings) to an 8×8 state matrix. The 16D manifold "
"quadrants (q_void, q_orbit, q_braid, q_observer) are 4×8 "
"blocks of the matrix. Sidon addresses {1..128} label the "
"8 strands. The attractor is the shock front ensemble."
),
"v16_structure": {
"encoding": "8×8 matrix split into 4 quadrant blocks",
"q_void": "rows 0-3, cols 0-1",
"q_orbit": "rows 0-3, cols 2-3",
"q_braid": "rows 4-7, cols 0-1",
"q_observer": "rows 4-7, cols 2-3",
},
"sidon_addresses": [sidon(k) for k in range(8)],
"trajectories": trajectories,
"sidon_ordered": sidon_trace,
"summary": {
"total_trials": len(trajectories),
"avg_braid_tension": round(sum(t["braid_tension"] for t in trajectories) / len(trajectories), 4),
"avg_energy": round(sum(t["final_energy"]["total"] for t in trajectories) / len(trajectories), 4),
},
"computed_at": datetime.now(timezone.utc).isoformat(),
}
canonical = json.dumps(receipt, sort_keys=True, separators=(",", ":"))
receipt["receipt_sha256"] = hashlib.sha256(canonical.encode()).hexdigest()
path = "chaos_game_16d_receipt.json"
with open(path, "w") as f:
json.dump(receipt, f, indent=2)
print(f"\n{'=' * 60}")
print(f"Receipt: {path}")
print(f"SHA256: {receipt['receipt_sha256']}")
if __name__ == "__main__":
main()