Research-Stack/4-Infrastructure/hardware/noise_stability_sim.py
2026-05-11 22:18:31 -05:00

449 lines
18 KiB
Python

#!/usr/bin/env python3
"""
Eigenvector Stability of Braided Field in Noisy Environment
This script computes the eigenvector decomposition of the braided field
transfer matrix and analyzes stability under various noise conditions.
This is relevant for compression - if information is encoded in transfer
characteristics, we need to know if those characteristics are stable.
"""
import numpy as np
import cmath
import hashlib
import json
import zlib
from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path
from typing import List, Tuple
import matplotlib.pyplot as plt
ROOT = Path(__file__).resolve().parents[2]
RECEIPT_PATH = ROOT / "4-Infrastructure" / "hardware" / "noise_stability_sim_receipt.json"
PLOT_PATH = ROOT / "4-Infrastructure" / "hardware" / "eigenvalue_trajectory.png"
@dataclass
class NoiseEnvironment:
"""Parameters for the noisy environment."""
thermal_noise: float # Temperature-dependent noise
quantum_noise: float # Quantum fluctuations
disorder_strength: float # Structural disorder
correlation_length: float # Noise correlation length
class BraidedFieldMatrix:
"""Linear system representation of braided field for eigenvector analysis."""
def __init__(self, num_particles: int = 4):
self.num_particles = num_particles
# Transfer matrix representing the system
self.matrix = np.eye(num_particles, dtype=complex)
self.eigenvalues = None
self.eigenvectors = None
def apply_hamiltonian_component(self, component_type: str, weight: float):
"""Apply a Hamiltonian component to the transfer matrix."""
# Component-specific matrix modifications
if component_type == 'photon':
# Photon: diagonal phase shifts
for i in range(self.num_particles):
self.matrix[i, i] *= cmath.exp(1j * weight * 0.1)
elif component_type == 'electron':
# Electron: off-diagonal coupling
for i in range(self.num_particles - 1):
self.matrix[i, i+1] += weight * 0.05 * cmath.exp(1j * np.pi/4)
self.matrix[i+1, i] += weight * 0.05 * cmath.exp(-1j * np.pi/4)
elif component_type == 'phonon':
# Phonon: stronger coupling with phase
for i in range(self.num_particles - 1):
self.matrix[i, i+1] += weight * 0.1 * cmath.exp(1j * np.pi/2)
self.matrix[i+1, i] += weight * 0.1 * cmath.exp(-1j * np.pi/2)
elif component_type == 'interaction':
# Interaction: global coupling
for i in range(self.num_particles):
for j in range(self.num_particles):
if i != j:
self.matrix[i, j] += weight * 0.02 * cmath.exp(1j * np.pi)
def add_noise(self, noise_env: NoiseEnvironment, gain: float = 0.01):
"""Add noise to the transfer matrix."""
n = self.num_particles
# Thermal noise: random perturbations
thermal_perturbation = np.random.normal(0, noise_env.thermal_noise, (n, n)) + \
1j * np.random.normal(0, noise_env.thermal_noise, (n, n))
# Quantum noise: coherent perturbations
quantum_perturbation = np.random.normal(0, noise_env.quantum_noise, (n, n)) * \
np.exp(1j * np.random.uniform(0, 2*np.pi, (n, n)))
# Disorder: diagonal variations
disorder = np.random.normal(0, noise_env.disorder_strength, n)
disorder_matrix = np.diag(disorder)
# Combine noise sources
total_noise = thermal_perturbation + quantum_perturbation + disorder_matrix
self.matrix += total_noise * gain
def compute_eigendecomposition(self):
"""Compute eigenvalues and eigenvectors."""
self.eigenvalues, self.eigenvectors = np.linalg.eig(self.matrix)
return self.eigenvalues, self.eigenvectors
def spectral_radius(self) -> float:
"""Compute spectral radius (max eigenvalue magnitude)."""
if self.eigenvalues is None:
self.compute_eigendecomposition()
return max(abs(ev) for ev in self.eigenvalues)
def condition_number(self) -> float:
"""Compute condition number (stability metric)."""
if self.eigenvalues is None:
self.compute_eigendecomposition()
magnitudes = [abs(ev) for ev in self.eigenvalues]
return max(magnitudes) / (min(magnitudes) + 1e-10)
def stability_margin(self) -> float:
"""Compute stability margin (distance to instability)."""
if self.eigenvalues is None:
self.compute_eigendecomposition()
# Stability margin = minimum distance of eigenvalues from unit circle
margin = min(abs(abs(ev) - 1.0) for ev in self.eigenvalues)
return margin
def dominant_eigenvector(self) -> np.ndarray:
"""Get the eigenvector corresponding to the dominant eigenvalue."""
if self.eigenvalues is None:
self.compute_eigendecomposition()
idx = np.argmax(abs(self.eigenvalues))
return self.eigenvectors[:, idx]
def noise_stability_analysis(gain: float = 0.01, label: str = "micro"):
"""Analyze eigenvector stability under various noise conditions."""
print(f"=== Eigenvector Stability Analysis in Noisy Environment ({label}, gain={gain}) ===\n")
# Test different noise levels
noise_levels = [
("Low noise", NoiseEnvironment(0.01, 0.01, 0.01, 1.0)),
("Medium noise", NoiseEnvironment(0.05, 0.05, 0.05, 1.0)),
("High noise", NoiseEnvironment(0.1, 0.1, 0.1, 1.0)),
("Extreme noise", NoiseEnvironment(0.2, 0.2, 0.2, 1.0)),
]
print("Stability metrics vs noise level:")
print("-" * 70)
print(f"{'Noise Level':<15} {'Spectral Radius':<15} {'Condition #':<12} {'Stability Margin':<15}")
print("-" * 70)
results = []
for name, noise_env in noise_levels:
# Create braided field with Hamiltonian components
bf = BraidedFieldMatrix(num_particles=4)
# Apply standard Hamiltonian components
bf.apply_hamiltonian_component('photon', weight=1.0)
bf.apply_hamiltonian_component('electron', weight=1.0)
bf.apply_hamiltonian_component('phonon', weight=1.0)
bf.apply_hamiltonian_component('interaction', weight=1.0)
# Add noise
bf.add_noise(noise_env, gain=gain)
# Compute stability metrics
spectral_radius = bf.spectral_radius()
condition_num = bf.condition_number()
stability_margin = bf.stability_margin()
print(f"{name:<15} {spectral_radius:<15.4f} {condition_num:<12.4f} {stability_margin:<15.4f}")
results.append({
"name": name,
"gain": gain,
"spectral_radius": float(spectral_radius),
"condition_number": float(condition_num),
"stability_margin": float(stability_margin),
"eigenvalues": [
{
"real": float(ev.real),
"imag": float(ev.imag),
"magnitude": float(abs(ev)),
"phase": float(cmath.phase(ev)),
}
for ev in bf.eigenvalues
],
})
print()
# Analyze eigenvalue distribution
print("Eigenvalue distribution (high noise case):")
high_noise_eigenvalues = [
complex(row["real"], row["imag"]) for row in results[-1]["eigenvalues"]
]
for i, ev in enumerate(high_noise_eigenvalues):
print(f" λ_{i}: {ev:.4f} (magnitude: {abs(ev):.4f}, phase: {cmath.phase(ev):.4f} rad)")
return {
"label": label,
"gain": gain,
"rows": results,
}
def eigenvector_persistence(gain: float = 0.01, label: str = "micro"):
"""Test if eigenvectors persist under repeated noise."""
print(f"\n=== Eigenvector Persistence Under Repeated Noise ({label}, gain={gain}) ===\n")
bf = BraidedFieldMatrix(num_particles=4)
# Apply standard Hamiltonian components
bf.apply_hamiltonian_component('photon', weight=1.0)
bf.apply_hamiltonian_component('electron', weight=1.0)
bf.apply_hamiltonian_component('phonon', weight=1.0)
bf.apply_hamiltonian_component('interaction', weight=1.0)
# Get initial eigenvector
bf.compute_eigendecomposition()
initial_eigenvector = bf.dominant_eigenvector()
print(f"Initial dominant eigenvector: {initial_eigenvector}")
noise_env = NoiseEnvironment(0.05, 0.05, 0.05, 1.0)
# Apply noise multiple times and track eigenvector similarity
similarities = []
for i in range(10):
bf.add_noise(noise_env, gain=gain)
bf.compute_eigendecomposition()
current_eigenvector = bf.dominant_eigenvector()
# Compute similarity (cosine of angle between vectors)
similarity = abs(np.vdot(initial_eigenvector, current_eigenvector)) / \
(np.linalg.norm(initial_eigenvector) * np.linalg.norm(current_eigenvector))
similarities.append(similarity)
print(f" Noise iteration {i}: similarity = {similarity:.4f}")
print(f"\nAverage similarity: {np.mean(similarities):.4f}")
print(f"Similarity degradation: {similarities[0] - similarities[-1]:.4f}")
return {
"label": label,
"gain": gain,
"similarities": [float(x) for x in similarities],
"average_similarity": float(np.mean(similarities)),
"similarity_degradation": float(similarities[0] - similarities[-1]),
}
def information_capacity_analysis(gain: float = 0.01, label: str = "micro"):
"""Analyze information capacity under noise using eigenvalue spectrum."""
print(f"\n=== Information Capacity Analysis ({label}, gain={gain}) ===\n")
bf = BraidedFieldMatrix(num_particles=4)
# Apply standard Hamiltonian components
bf.apply_hamiltonian_component('photon', weight=1.0)
bf.apply_hamiltonian_component('electron', weight=1.0)
bf.apply_hamiltonian_component('phonon', weight=1.0)
bf.apply_hamiltonian_component('interaction', weight=1.0)
print("Information capacity vs noise level:")
print("-" * 60)
print(f"{'Noise Level':<15} {'Spectral Entropy':<20} {'Effective Rank':<15}")
print("-" * 60)
noise_levels = [0.0, 0.02, 0.05, 0.1, 0.2]
rows = []
for noise_level in noise_levels:
bf_temp = BraidedFieldMatrix(num_particles=4)
bf_temp.matrix = bf.matrix.copy()
if noise_level > 0:
noise_env = NoiseEnvironment(noise_level, noise_level, noise_level, 1.0)
bf_temp.add_noise(noise_env, gain=gain)
bf_temp.compute_eigendecomposition()
# Compute spectral entropy (information measure)
eigenvalue_mags = np.array([abs(ev) for ev in bf_temp.eigenvalues])
eigenvalue_mags = eigenvalue_mags / np.sum(eigenvalue_mags) # Normalize
spectral_entropy = -np.sum(eigenvalue_mags * np.log(eigenvalue_mags + 1e-10))
# Compute effective rank (number of significant eigenvalues)
effective_rank = np.sum(eigenvalue_mags > 0.1)
print(f"{noise_level:<15.2f} {spectral_entropy:<20.4f} {effective_rank:<15.0f}")
rows.append({
"noise_level": float(noise_level),
"spectral_entropy": float(spectral_entropy),
"effective_rank": int(effective_rank),
})
return {
"label": label,
"gain": gain,
"rows": rows,
}
def stochastic_crc_lane(stability: dict, persistence: dict, capacity: dict) -> dict:
"""Derive a deterministic CRC witness from the seeded stochastic micro-noise lane.
This is not an error-correcting code by itself. It is a compact witness over
the sampled noise response, suitable for detecting drift in a replayed probe.
"""
payload = {
"stability_rows": [
{
"name": row["name"],
"spectral_radius_q": round(row["spectral_radius"], 8),
"condition_number_q": round(row["condition_number"], 8),
"stability_margin_q": round(row["stability_margin"], 8),
"eigenvalue_magnitudes_q": [
round(ev["magnitude"], 8) for ev in row["eigenvalues"]
],
"eigenvalue_phases_q": [
round(ev["phase"], 8) for ev in row["eigenvalues"]
],
}
for row in stability["rows"]
],
"persistence_q": [round(x, 8) for x in persistence["similarities"]],
"capacity_rows": [
{
"noise_level": row["noise_level"],
"spectral_entropy_q": round(row["spectral_entropy"], 8),
"effective_rank": row["effective_rank"],
}
for row in capacity["rows"]
],
}
encoded = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
crc = zlib.crc32(encoded) & 0xFFFFFFFF
return {
"schema": "stochastic_crc_lane_v1",
"source": "seeded micro-gain eigen/noise lane",
"quantization": "round floating metrics to 8 decimal places before CRC32",
"byte_length": len(encoded),
"crc32_hex": f"{crc:08x}",
"payload_sha256": hashlib.sha256(encoded).hexdigest(),
"claim_boundary": "CRC witnesses replay drift in this seeded toy noise lane; it is not a proof of physical noise immunity or cryptographic integrity.",
}
def plot_eigenvalue_trajectory(gain: float = 0.01, label: str = "micro"):
"""Plot eigenvalue trajectory under increasing noise."""
print(f"\n=== Eigenvalue Trajectory Visualization ({label}, gain={gain}) ===\n")
bf = BraidedFieldMatrix(num_particles=4)
# Apply standard Hamiltonian components
bf.apply_hamiltonian_component('photon', weight=1.0)
bf.apply_hamiltonian_component('electron', weight=1.0)
bf.apply_hamiltonian_component('phonon', weight=1.0)
bf.apply_hamiltonian_component('interaction', weight=1.0)
# Track eigenvalues under increasing noise
noise_levels = np.linspace(0, 0.3, 30)
eigenvalue_trajectories = [[] for _ in range(4)]
for noise_level in noise_levels:
bf_temp = BraidedFieldMatrix(num_particles=4)
bf_temp.matrix = bf.matrix.copy()
if noise_level > 0:
noise_env = NoiseEnvironment(noise_level, noise_level, noise_level, 1.0)
bf_temp.add_noise(noise_env, gain=gain)
bf_temp.compute_eigendecomposition()
for i, ev in enumerate(bf_temp.eigenvalues):
eigenvalue_trajectories[i].append(ev)
# Plot trajectories
fig, ax = plt.subplots(figsize=(10, 8))
colors = ['red', 'blue', 'green', 'orange']
for i, trajectory in enumerate(eigenvalue_trajectories):
real_parts = [ev.real for ev in trajectory]
imag_parts = [ev.imag for ev in trajectory]
ax.plot(real_parts, imag_parts, color=colors[i], linewidth=2,
marker='o', markersize=3, label=f'λ_{i}')
# Mark initial and final points
ax.plot(real_parts[0], imag_parts[0], 's', color=colors[i], markersize=8)
ax.plot(real_parts[-1], imag_parts[-1], '^', color=colors[i], markersize=8)
# Draw unit circle
theta = np.linspace(0, 2*np.pi, 100)
ax.plot(np.cos(theta), np.sin(theta), 'k--', alpha=0.3, label='Unit circle')
ax.set_xlabel('Re(λ)')
ax.set_ylabel('Im(λ)')
ax.set_title('Eigenvalue Trajectories Under Increasing Noise')
ax.axhline(y=0, color='k', linestyle='-', alpha=0.1)
ax.axvline(x=0, color='k', linestyle='-', alpha=0.1)
ax.grid(True, alpha=0.3)
ax.legend()
ax.axis('equal')
plt.tight_layout()
plt.savefig(PLOT_PATH, dpi=150)
print(f"Eigenvalue trajectory plot saved to {PLOT_PATH}")
return {
"label": label,
"gain": gain,
"plot_path": str(PLOT_PATH),
"noise_levels": [float(x) for x in noise_levels],
}
if __name__ == "__main__":
# Set random seed for reproducibility
np.random.seed(42)
micro_stability = noise_stability_analysis(gain=0.01, label="micro")
micro_persistence = eigenvector_persistence(gain=0.01, label="micro")
micro_capacity = information_capacity_analysis(gain=0.01, label="micro")
micro_stochastic_crc = stochastic_crc_lane(
micro_stability,
micro_persistence,
micro_capacity,
)
trajectory = plot_eigenvalue_trajectory(gain=0.01, label="micro")
direct_stability = noise_stability_analysis(gain=1.0, label="direct")
direct_persistence = eigenvector_persistence(gain=1.0, label="direct")
direct_capacity = information_capacity_analysis(gain=1.0, label="direct")
receipt = {
"generated_utc": datetime.now(timezone.utc).isoformat(),
"lawful": True,
"mode": "virtual_only",
"source_note": "No hardware programming, RF emission, JTAG, serial flashing, board access, or material claim. Python eigenvector stability simulation only.",
"noise_gain_boundary": "The original micro lane uses gain=0.01, so nominal extreme noise is intentionally small. Direct lane uses gain=1.0 to expose degradation.",
"micro_gain": {
"stability": micro_stability,
"persistence": micro_persistence,
"capacity": micro_capacity,
"stochastic_crc": micro_stochastic_crc,
},
"direct_gain": {
"stability": direct_stability,
"persistence": direct_persistence,
"capacity": direct_capacity,
},
"trajectory": trajectory,
"claim_boundary": "This simulation records transfer-matrix eigen stability in a toy braided-field model. It does not prove topological protection, local-noise immunity, device feasibility, material existence, compression advantage, or Hutter Prize relevance.",
}
encoded = json.dumps(receipt, indent=2, sort_keys=True).encode("utf-8")
receipt["receipt_hash_preimage_sha256"] = hashlib.sha256(encoded).hexdigest()
RECEIPT_PATH.write_text(json.dumps(receipt, indent=2, sort_keys=True) + "\n", encoding="utf-8")
print("\n=== Analysis Complete ===")
print("The eigenvector analysis shows:")
print("1. Micro-gain noise can look almost invariant because gain=0.01")
print("2. Direct-gain noise exposes actual degradation and mode drift")
print("3. Eigenvectors should be treated as transfer-characteristic candidates")
print("4. Eigenvalue trajectories show how the toy system evolves under noise")
print("\nFor compression applications, this suggests that transfer characteristic")
print("encoding is worth testing, but no compression advantage is claimed.")
print(f"Receipt written to {RECEIPT_PATH}")