457 lines
16 KiB
Python
457 lines
16 KiB
Python
# Golden-Weave Memory System for Khra'gixx Lattice Observer
|
|
# Version 1.0 - API Extensions and Hysteresis Implementation
|
|
# Author: CTO Agent
|
|
# Date: 2026-03-22
|
|
|
|
"""
|
|
This module extends the lattice_observer.py with:
|
|
1. Local property queries (density, stress, vorticity at specific coordinates)
|
|
2. Attractor storage and recall system
|
|
3. Hysteresis buffer for stress tensor memory
|
|
4. Persistent attractor library in JSON format
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import numpy as np
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Dict, List, Tuple, Optional
|
|
from dataclasses import dataclass, asdict
|
|
from collections import deque
|
|
|
|
# Golden ratio constants
|
|
PHI = (1 + np.sqrt(5)) / 2 # 1.6180339887...
|
|
PHI_SQUARED = PHI ** 2 # 2.618...
|
|
INV_PHI_SQUARED = 1 / PHI_SQUARED # ~0.382 (decay factor)
|
|
|
|
@dataclass
|
|
class LocalFieldState:
|
|
"""Represents the field state at a specific location."""
|
|
x: int
|
|
y: int
|
|
density: float
|
|
stress_xx: float
|
|
stress_yy: float
|
|
stress_xy: float
|
|
vorticity: float
|
|
velocity_x: float
|
|
velocity_y: float
|
|
timestamp: str
|
|
cycle: int
|
|
|
|
@property
|
|
def stress_divergence(self) -> float:
|
|
"""Compute stress divergence (charge analog)."""
|
|
# Approximate divergence from stress components
|
|
return self.stress_xx + self.stress_yy
|
|
|
|
@property
|
|
def stress_magnitude(self) -> float:
|
|
"""Compute total stress magnitude."""
|
|
return np.sqrt(self.stress_xx**2 + self.stress_yy**2 + 2*self.stress_xy**2)
|
|
|
|
|
|
@dataclass
|
|
class AttractorDefinition:
|
|
"""Defines a stored attractor with its properties."""
|
|
name: str
|
|
center_x: int
|
|
center_y: int
|
|
radius: int
|
|
creation_time: str
|
|
cycle_created: int
|
|
|
|
# Field properties at center
|
|
center_density: float
|
|
center_stress_div: float
|
|
center_vorticity: float
|
|
center_coherence: float
|
|
|
|
# Injection parameters used to create it
|
|
injection_amplitude: float
|
|
injection_radius: int
|
|
num_injections: int
|
|
omega_at_creation: float
|
|
|
|
# Full field snapshot (optional, for precise recall)
|
|
density_snapshot: Optional[List[float]] = None
|
|
|
|
@property
|
|
def atomic_number_analog(self) -> int:
|
|
"""Derive atomic number analog from vorticity."""
|
|
# Map vorticity to Z: low |ω| → low Z, high |ω| → high Z
|
|
return int(self.center_vorticity * 1000)
|
|
|
|
@property
|
|
def charge_analog(self) -> str:
|
|
"""Derive charge from stress divergence sign."""
|
|
if self.center_stress_div < -0.0001:
|
|
return "negative"
|
|
elif self.center_stress_div > 0.0001:
|
|
return "positive"
|
|
else:
|
|
return "neutral"
|
|
|
|
|
|
class HysteresisBuffer:
|
|
"""
|
|
Sliding window buffer for stress tensor history.
|
|
Provides memory of past states that influences current dynamics.
|
|
"""
|
|
|
|
def __init__(self, window_size: int = 15, decay_factor: float = INV_PHI_SQUARED):
|
|
self.window_size = window_size
|
|
self.decay_factor = decay_factor
|
|
|
|
# Circular buffers for stress components
|
|
self.stress_xx_buffer = deque(maxlen=window_size)
|
|
self.stress_yy_buffer = deque(maxlen=window_size)
|
|
self.stress_xy_buffer = deque(maxlen=window_size)
|
|
|
|
# Weighted moving average
|
|
self.current_weight = 1.0
|
|
|
|
def update(self, stress_xx: float, stress_yy: float, stress_xy: float):
|
|
"""Add new stress tensor to buffer."""
|
|
self.stress_xx_buffer.append(stress_xx)
|
|
self.stress_yy_buffer.append(stress_yy)
|
|
self.stress_xy_buffer.append(stress_xy)
|
|
|
|
def get_effective_stress(self) -> Tuple[float, float, float]:
|
|
"""
|
|
Compute effective stress with phi-decay weighting.
|
|
Recent stresses have higher weight, older stresses decay by φ⁻².
|
|
"""
|
|
if not self.stress_xx_buffer:
|
|
return 0.0, 0.0, 0.0
|
|
|
|
# Apply decay weights: most recent = 1, older = φ⁻², φ⁻⁴, ...
|
|
weights = [self.decay_factor ** i for i in range(len(self.stress_xx_buffer))]
|
|
weights = weights[::-1] # Reverse so most recent has highest weight
|
|
weight_sum = sum(weights)
|
|
|
|
# Weighted averages
|
|
eff_xx = sum(w * s for w, s in zip(weights, self.stress_xx_buffer)) / weight_sum
|
|
eff_yy = sum(w * s for w, s in zip(weights, self.stress_yy_buffer)) / weight_sum
|
|
eff_xy = sum(w * s for w, s in zip(weights, self.stress_xy_buffer)) / weight_sum
|
|
|
|
return eff_xx, eff_yy, eff_xy
|
|
|
|
def compute_omega_modulation(self, base_omega: float) -> float:
|
|
"""
|
|
Modulate omega based on hysteresis stress magnitude.
|
|
High accumulated stress → higher effective viscosity.
|
|
"""
|
|
eff_xx, eff_yy, eff_xy = self.get_effective_stress()
|
|
stress_mag = np.sqrt(eff_xx**2 + eff_yy**2 + 2*eff_xy**2)
|
|
|
|
# Modulate: base + stress-dependent term (bounded)
|
|
modulation = 0.1 * stress_mag * PHI # Golden-scaled modulation
|
|
return min(base_omega + modulation, 2.15) # Cap at 2.15
|
|
|
|
|
|
class GoldenWeaveMemorySystem:
|
|
"""
|
|
Main memory system integrating attractor storage and hysteresis.
|
|
"""
|
|
|
|
def __init__(self, attractor_dir: str = "attractors", grid_size: int = 1024):
|
|
self.attractor_dir = Path(attractor_dir)
|
|
self.attractor_dir.mkdir(exist_ok=True)
|
|
self.grid_size = grid_size
|
|
|
|
# Initialize hysteresis buffer
|
|
self.hysteresis = HysteresisBuffer(window_size=15)
|
|
|
|
# Cache of loaded attractors
|
|
self.attractor_cache: Dict[str, AttractorDefinition] = {}
|
|
|
|
# Load existing attractors
|
|
self._load_attractors()
|
|
|
|
def _load_attractors(self):
|
|
"""Load all stored attractors from disk."""
|
|
for attractor_file in self.attractor_dir.glob("*.json"):
|
|
with open(attractor_file, 'r') as f:
|
|
data = json.load(f)
|
|
attractor = AttractorDefinition(**data)
|
|
self.attractor_cache[attractor.name] = attractor
|
|
|
|
def query_local_field(self, x: int, y: int,
|
|
density_field: np.ndarray,
|
|
stress_xx: np.ndarray,
|
|
stress_yy: np.ndarray,
|
|
stress_xy: np.ndarray,
|
|
vorticity_field: np.ndarray,
|
|
velocity_field: np.ndarray,
|
|
current_cycle: int) -> LocalFieldState:
|
|
"""
|
|
Query the field state at a specific (x, y) coordinate.
|
|
|
|
Args:
|
|
x, y: Grid coordinates (0 to grid_size-1)
|
|
Various field arrays from the lattice daemon
|
|
current_cycle: Current simulation cycle
|
|
|
|
Returns:
|
|
LocalFieldState with all properties at that location
|
|
"""
|
|
# Bounds check
|
|
x = max(0, min(x, self.grid_size - 1))
|
|
y = max(0, min(y, self.grid_size - 1))
|
|
|
|
return LocalFieldState(
|
|
x=x,
|
|
y=y,
|
|
density=float(density_field[y, x]),
|
|
stress_xx=float(stress_xx[y, x]),
|
|
stress_yy=float(stress_yy[y, x]),
|
|
stress_xy=float(stress_xy[y, x]),
|
|
vorticity=float(vorticity_field[y, x]),
|
|
velocity_x=float(velocity_field[y, x, 0]),
|
|
velocity_y=float(velocity_field[y, x, 1]),
|
|
timestamp=datetime.now().isoformat(),
|
|
cycle=current_cycle
|
|
)
|
|
|
|
def store_attractor(self, name: str, center_x: int, center_y: int, radius: int,
|
|
local_state: LocalFieldState,
|
|
injection_params: Dict,
|
|
density_snapshot: Optional[np.ndarray] = None) -> AttractorDefinition:
|
|
"""
|
|
Store a new attractor definition.
|
|
|
|
Args:
|
|
name: Unique identifier for this attractor
|
|
center_x, center_y: Center coordinates
|
|
radius: Radius of the attractor region
|
|
local_state: LocalFieldState at center
|
|
injection_params: Dict with 'amplitude', 'radius', 'num_injections', 'omega'
|
|
density_snapshot: Optional full density field snapshot
|
|
|
|
Returns:
|
|
Stored AttractorDefinition
|
|
"""
|
|
attractor = AttractorDefinition(
|
|
name=name,
|
|
center_x=center_x,
|
|
center_y=center_y,
|
|
radius=radius,
|
|
creation_time=datetime.now().isoformat(),
|
|
cycle_created=local_state.cycle,
|
|
center_density=local_state.density,
|
|
center_stress_div=local_state.stress_divergence,
|
|
center_vorticity=local_state.vorticity,
|
|
center_coherence=0.0, # To be filled from global state
|
|
injection_amplitude=injection_params.get('amplitude', 0.05),
|
|
injection_radius=injection_params.get('radius', 20),
|
|
num_injections=injection_params.get('num_injections', 5),
|
|
omega_at_creation=injection_params.get('omega', 1.97),
|
|
density_snapshot=density_snapshot.flatten().tolist() if density_snapshot is not None else None
|
|
)
|
|
|
|
# Save to disk
|
|
attractor_file = self.attractor_dir / f"{name}.json"
|
|
with open(attractor_file, 'w') as f:
|
|
json.dump(asdict(attractor), f, indent=2)
|
|
|
|
# Cache
|
|
self.attractor_cache[name] = attractor
|
|
|
|
return attractor
|
|
|
|
def recall_attractor(self, name: str) -> Optional[AttractorDefinition]:
|
|
"""
|
|
Retrieve an attractor definition for reinjection.
|
|
|
|
Args:
|
|
name: Attractor identifier
|
|
|
|
Returns:
|
|
AttractorDefinition or None if not found
|
|
"""
|
|
return self.attractor_cache.get(name)
|
|
|
|
def list_attractors(self) -> List[str]:
|
|
"""Return list of all stored attractor names."""
|
|
return list(self.attractor_cache.keys())
|
|
|
|
def get_attractor_properties(self, name: str) -> Optional[Dict]:
|
|
"""Get human-readable properties of an attractor."""
|
|
attractor = self.recall_attractor(name)
|
|
if attractor is None:
|
|
return None
|
|
|
|
return {
|
|
"name": attractor.name,
|
|
"location": f"({attractor.center_x}, {attractor.center_y})",
|
|
"atomic_number_analog": attractor.atomic_number_analog,
|
|
"charge_analog": attractor.charge_analog,
|
|
"density": attractor.center_density,
|
|
"stress_divergence": attractor.center_stress_div,
|
|
"vorticity": attractor.center_vorticity,
|
|
"created": attractor.creation_time,
|
|
"injections": attractor.num_injections
|
|
}
|
|
|
|
def update_hysteresis(self, stress_xx: float, stress_yy: float, stress_xy: float):
|
|
"""Update the hysteresis buffer with current stress state."""
|
|
self.hysteresis.update(stress_xx, stress_yy, stress_xy)
|
|
|
|
def get_effective_omega(self, base_omega: float) -> float:
|
|
"""Get omega modulated by hysteresis memory."""
|
|
return self.hysteresis.compute_omega_modulation(base_omega)
|
|
|
|
|
|
# Integration with lattice_observer.py
|
|
# Add these methods to the LatticeObserver class:
|
|
|
|
class LatticeObserverExtensions:
|
|
"""
|
|
Mixin class to extend LatticeObserver with Golden-Weave memory system.
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.memory_system = GoldenWeaveMemorySystem()
|
|
|
|
def handle_query_local(self, x: int, y: int) -> Dict:
|
|
"""Handle CMD: query_local x y"""
|
|
# Access current field state from daemon telemetry
|
|
local_state = self.memory_system.query_local_field(
|
|
x=x, y=y,
|
|
density_field=self.current_density,
|
|
stress_xx=self.current_stress_xx,
|
|
stress_yy=self.current_stress_yy,
|
|
stress_xy=self.current_stress_xy,
|
|
vorticity_field=self.current_vorticity,
|
|
velocity_field=self.current_velocity,
|
|
current_cycle=self.cycle
|
|
)
|
|
|
|
return {
|
|
"command": "query_local",
|
|
"x": x,
|
|
"y": y,
|
|
"density": local_state.density,
|
|
"stress_divergence": local_state.stress_divergence,
|
|
"stress_magnitude": local_state.stress_magnitude,
|
|
"vorticity": local_state.vorticity,
|
|
"velocity": [local_state.velocity_x, local_state.velocity_y],
|
|
"cycle": local_state.cycle
|
|
}
|
|
|
|
def handle_store_attractor(self, name: str, x: int, y: int, radius: int) -> Dict:
|
|
"""Handle CMD: store_attractor name x y radius"""
|
|
# Query current state at location
|
|
local_state = self.memory_system.query_local_field(
|
|
x=x, y=y,
|
|
density_field=self.current_density,
|
|
stress_xx=self.current_stress_xx,
|
|
stress_yy=self.current_stress_yy,
|
|
stress_xy=self.current_stress_xy,
|
|
vorticity_field=self.current_vorticity,
|
|
velocity_field=self.current_velocity,
|
|
current_cycle=self.cycle
|
|
)
|
|
|
|
# Get injection params from recent history (simplified)
|
|
injection_params = {
|
|
'amplitude': self.last_injection_amplitude if hasattr(self, 'last_injection_amplitude') else 0.05,
|
|
'radius': self.last_injection_radius if hasattr(self, 'last_injection_radius') else 20,
|
|
'num_injections': self.last_num_injections if hasattr(self, 'last_num_injections') else 5,
|
|
'omega': self.current_omega
|
|
}
|
|
|
|
attractor = self.memory_system.store_attractor(
|
|
name=name,
|
|
center_x=x,
|
|
center_y=y,
|
|
radius=radius,
|
|
local_state=local_state,
|
|
injection_params=injection_params,
|
|
density_snapshot=self.current_density if radius > 50 else None
|
|
)
|
|
|
|
return {
|
|
"command": "store_attractor",
|
|
"name": name,
|
|
"properties": self.memory_system.get_attractor_properties(name),
|
|
"status": "stored"
|
|
}
|
|
|
|
def handle_recall_attractor(self, name: str) -> Dict:
|
|
"""Handle CMD: recall_attractor name"""
|
|
attractor = self.memory_system.recall_attractor(name)
|
|
if attractor is None:
|
|
return {"command": "recall_attractor", "name": name, "error": "not found"}
|
|
|
|
# Return parameters for reinjection
|
|
return {
|
|
"command": "recall_attractor",
|
|
"name": name,
|
|
"center": [attractor.center_x, attractor.center_y],
|
|
"injection_amplitude": attractor.injection_amplitude,
|
|
"injection_radius": attractor.injection_radius,
|
|
"num_injections": attractor.num_injections,
|
|
"omega": attractor.omega_at_creation,
|
|
"status": "ready_for_injection"
|
|
}
|
|
|
|
def handle_list_attractors(self) -> Dict:
|
|
"""Handle CMD: list_attractors"""
|
|
attractors = self.memory_system.list_attractors()
|
|
properties = [self.memory_system.get_attractor_properties(name) for name in attractors]
|
|
|
|
return {
|
|
"command": "list_attractors",
|
|
"count": len(attractors),
|
|
"attractors": properties
|
|
}
|
|
|
|
|
|
# Example usage script (for testing):
|
|
"""
|
|
# Test the memory system
|
|
|
|
from golden_weave_memory import GoldenWeaveMemorySystem, LocalFieldState
|
|
|
|
# Initialize
|
|
memory = GoldenWeaveMemorySystem(attractor_dir="attractors", grid_size=1024)
|
|
|
|
# Simulate querying local field (would use actual daemon data)
|
|
local_state = LocalFieldState(
|
|
x=512, y=512,
|
|
density=0.984,
|
|
stress_xx=-0.0005,
|
|
stress_yy=0.0003,
|
|
stress_xy=-0.0001,
|
|
vorticity=0.021,
|
|
velocity_x=0.1, velocity_y=0.05,
|
|
timestamp="2026-03-22T12:00:00",
|
|
cycle=100000
|
|
)
|
|
|
|
# Store an attractor
|
|
attractor = memory.store_attractor(
|
|
name="proton_analog",
|
|
center_x=512, center_y=512, radius=20,
|
|
local_state=local_state,
|
|
injection_params={'amplitude': 0.05, 'radius': 20, 'num_injections': 5, 'omega': 1.97}
|
|
)
|
|
|
|
print(f"Stored attractor: {attractor.name}")
|
|
print(f"Z analog: {attractor.atomic_number_analog}")
|
|
print(f"Charge: {attractor.charge_analog}")
|
|
|
|
# List all attractors
|
|
print(f"All attractors: {memory.list_attractors()}")
|
|
|
|
# Recall
|
|
recalled = memory.recall_attractor("proton_analog")
|
|
print(f"Recalled: {recalled}")
|
|
"""
|
|
|
|
# End of golden_weave_memory.py
|