#!/usr/bin/env python3 """ chaos_game.py — Deterministic Chaos Game Engine Deterministic chaos game using IFS contraction on 8×8 state matrix. 4 basins: q_void (rows 0-1), q_orbit (rows 2-3), q_braid (rows 4-5), q_observer (rows 6-7). """ import hashlib import json import math from typing import Dict, List, Optional from sidon_address import ( SIDON_ADDRESSES, _ADDRESS_TO_STRAND, address_to_strand, compute_full_address, structural_hash, verify_sidon_property, ) from spectral_profile import compute_spectral_profile EPSILON = 1e-14 N = 8 IFS_ALPHA = 0.75 # Strong contraction for fast convergence BASIN_ROWS = { "q_void": (0, 1), "q_orbit": (2, 3), "q_braid": (4, 5), "q_observer": (6, 7), } LCG_A = 1664525 LCG_C = 1013904223 LCG_M = 2**32 DEFAULT_CONVERGENCE_THRESHOLD = 0.95 DEFAULT_MAX_STEPS = 10000 DEFAULT_CONVERGENCE_WINDOW = 10 class LCG: def __init__(self, seed: int): self.state = seed & 0xFFFFFFFF def next(self) -> int: self.state = (LCG_A * self.state + LCG_C) % LCG_M return self.state def next_float(self) -> float: return self.next() / LCG_M def init_state_matrix(seed: int) -> List[List[float]]: """Initialize 8×8 state matrix deterministically from seed.""" lcg = LCG(seed) A = [[0.0] * N for _ in range(N)] for i in range(N): for j in range(N): if i == j: A[i][j] = SIDON_ADDRESSES[i] / 128.0 + 0.5 elif abs(i - j) == 1: A[i][j] = -0.1 + 0.04 * (lcg.next_float() - 0.5) else: A[i][j] = 0.05 * (lcg.next_float() - 0.5) return A def mat_copy(A): return [row[:] for row in A] def mat_diff_norm(A, B): return math.sqrt(sum((A[i][j] - B[i][j])**2 for i in range(N) for j in range(N))) def mat_norm(A): return math.sqrt(sum(A[i][j]**2 for i in range(N) for j in range(N))) def strand_to_basin(strand: int) -> str: if strand < 2: return "q_void" elif strand < 4: return "q_orbit" elif strand < 6: return "q_braid" else: return "q_observer" def get_basin_rows(strand: int): return BASIN_ROWS[strand_to_basin(strand)] def ifs_contract(A, strand, step, eq_hash): """Apply IFS contraction toward a strand's quadrant. Pure IFS contraction: A <- (1-alpha)*A + alpha*T where T is the target matrix with strong energy in the target strand's basin and suppressed energy elsewhere. No post-step modifications. """ alpha = IFS_ALPHA r0, r1 = get_basin_rows(strand) lcg = LCG((eq_hash + step * 104729 + strand * 7919) & 0xFFFFFFFF) for i in range(N): for j in range(N): in_basin = (r0 <= i <= r1) on_diag = (i == j) is_strand = (i == strand) if is_strand and on_diag: target = 10.0 # maximum energy at strand diagonal elif is_strand: target = 3.0 + 0.5 * lcg.next_float() elif in_basin and on_diag: target = 4.0 + 0.5 * lcg.next_float() elif in_basin: target = 1.5 + 0.3 * lcg.next_float() elif on_diag: target = 0.02 + 0.01 * lcg.next_float() else: target = 0.005 * lcg.next_float() A[i][j] = (1 - alpha) * A[i][j] + alpha * target def quadrant_energy(A): """Compute Frobenius energy in each basin (2-row block).""" energy = {} for basin, (r0, r1) in BASIN_ROWS.items(): e = sum(A[i][j]**2 for i in range(r0, r1 + 1) for j in range(N)) energy[basin] = math.sqrt(e) energy["total"] = sum(v for k, v in energy.items()) return energy def energy_ratio(A): """Ratio of dominant basin energy to total energy.""" qe = quadrant_energy(A) total = qe["total"] if total < EPSILON: return 0.0 basin_energies = {k: v for k, v in qe.items() if k != "total"} return max(basin_energies.values()) / total def dominant_basin(A): qe = quadrant_energy(A) del qe["total"] return max(qe, key=qe.get) def detect_quarantine(equation): if not equation or not equation.strip(): return "empty_equation" eq = equation.strip() normalized = eq.replace(" ", "").replace("\t", "") contradictions = {"0=1", "1=0", "false=true", "true=false", "False=True", "True=False", "⊥=⊤", "⊤=⊥"} if normalized in contradictions: return "explicit_contradiction" if eq in {"0 = 1", "1 = 0", "False = True", "True = False", "⊥ = ⊤", "⊤ = ⊥"}: return "explicit_contradiction" return None def sidon_guided_chaos_game( target_address: list, max_steps: int = DEFAULT_MAX_STEPS, convergence_threshold: float = DEFAULT_CONVERGENCE_THRESHOLD, convergence_window: int = DEFAULT_CONVERGENCE_WINDOW, equation: str = "", ): """Deterministic chaos game guided by Sidon address.""" # Quarantine check quarantine = detect_quarantine(equation) if equation else None if quarantine: return { "converged": False, "basin": "QUARANTINE", "steps": -1, "energy_ratio": 0.0, "address": target_address, "hash": hex(structural_hash(equation))[2:18] if equation else "", "target_strand": -1, "quarantine": quarantine, } primary = target_address[0] if target_address else SIDON_ADDRESSES[0] primary_strand = address_to_strand(primary) eq_hash = structural_hash(equation) if equation else 42 A = init_state_matrix(eq_hash & 0xFFFFFFFF) converged = False basin_history = [] trajectory = [] for step in range(max_steps): # Adaptive: emphasize target strand more over time progress = min(step / max(max_steps // 3, 1), 1.0) target_prob = 0.5 + 0.45 * progress lcg = LCG((eq_hash + step * 104729) & 0xFFFFFFFF) if lcg.next_float() < target_prob: chosen = primary_strand else: others = [s for s in range(N) if s != primary_strand] chosen = others[step % len(others)] ifs_contract(A, chosen, step, eq_hash) trajectory.append(chosen) # Check convergence every 4 steps if step % 4 == 0 and step > 0: ratio = energy_ratio(A) current_basin = dominant_basin(A) basin_history.append(current_basin) if ratio >= convergence_threshold: if len(basin_history) >= convergence_window: recent = basin_history[-convergence_window:] if len(set(recent)) == 1: converged = True break steps = step + 1 if converged else max_steps final_ratio = energy_ratio(A) final_basin = dominant_basin(A) if not converged and final_ratio >= convergence_threshold: converged = True qe = quadrant_energy(A) profile = energy_to_profile(qe) from sidon_address import spectral_to_sidon_address achieved = spectral_to_sidon_address(profile, eq_hash) return { "converged": converged, "basin": final_basin, "steps": steps, "energy_ratio": round(final_ratio, 6), "address": achieved, "hash": hex(eq_hash)[2:18], "target_strand": primary_strand, "quarantine": None, "trajectory": trajectory[:100], } def energy_to_profile(energy): """Convert quadrant energies to 8D profile.""" total = energy.get("total", 1.0) if total < EPSILON: total = 1.0 v = energy.get("q_void", 0.0) / total o = energy.get("q_orbit", 0.0) / total b = energy.get("q_braid", 0.0) / total ob = energy.get("q_observer", 0.0) / total profile = [v, v*v, o, o*o, b, b*b, ob, ob*ob] s = sum(profile) if s > 0: profile = [p / s for p in profile] else: profile = [0.125] * 8 return profile def generate_receipt(results, schema_version="stage3_v1"): import datetime converged = sum(1 for r in results if r.get("converged")) quarantined = sum(1 for r in results if r.get("quarantine")) basin_counts = {"q_void": 0, "q_orbit": 0, "q_braid": 0, "q_observer": 0} for r in results: b = r.get("basin", "") if b in basin_counts: basin_counts[b] += 1 receipt = { "schema": f"rrc_chaos_game_search_{schema_version}", "sidon_property_verified": verify_sidon_property(), "total_searches": len(results), "converged": converged, "quarantined": quarantined, "failed": len(results) - converged - quarantined, "basin_distribution": basin_counts, "convergence_rate": round(converged / len(results), 4) if results else 0.0, "parameters": { "matrix_size": N, "ifs_alpha": IFS_ALPHA, "convergence_threshold": DEFAULT_CONVERGENCE_THRESHOLD, "max_steps": DEFAULT_MAX_STEPS, "convergence_window": DEFAULT_CONVERGENCE_WINDOW, }, "results": results, "computed_at": datetime.datetime.now(datetime.timezone.utc).isoformat(), } canonical = json.dumps(receipt, sort_keys=True, separators=(",", ":")) receipt["receipt_sha256"] = hashlib.sha256(canonical.encode()).hexdigest() return receipt def search_equation(equation: str, **kwargs): """Full pipeline: equation → profile → address → chaos game → result.""" profile = compute_spectral_profile(equation) address = compute_full_address(equation) result = sidon_guided_chaos_game( target_address=address, equation=equation, **kwargs, ) result["spectral_profile"] = [round(x, 6) for x in profile] return result