TNFR Structural Coherence Cache System
Implements a specialized caching layer for structural computations that emerge from the nodal equation's mathematical properties:
∂EPI/∂t = νf · ΔNFR(t)
Key optimizations:
Status: CANONICAL STRUCTURAL CACHE
"""
TNFR Structural Coherence Cache System
Implements a specialized caching layer for structural computations
that emerge from the nodal equation's mathematical properties:
∂EPI/∂t = νf · ΔNFR(t)
Key optimizations:
1. Structural Field Memoization: Cache Φ_s, |∇φ|, K_φ, ξ_C computations
2. Phase Gradient Interpolation: Spatial interpolation of phase fields
3. Coherence Metric Batching: Batch computation of coherence across time windows
4. Resonance Pattern Recognition: Cache and reuse resonant frequency patterns
Status: CANONICAL STRUCTURAL CACHE
"""
import hashlib
from dataclasses import dataclass, field
from functools import wraps
from typing import Any
from ..alias import get_attr
from ..constants.aliases import ALIAS_EPI, ALIAS_THETA, ALIAS_VF
from ..constants.operational import (
STRUCT_CACHE_EVICTION_CANONICAL,
STRUCT_CACHE_INTERPOLATE_CANONICAL,
)
from ..mathematics.unified_numerical import np
try:
import networkx as nx
HAS_NETWORKX = True
except ImportError:
HAS_NETWORKX = False
nx = None
# Import TNFR Cache Infrastructure
try:
from ..utils.cache import get_global_cache
_CACHE_AVAILABLE = True
except ImportError:
_CACHE_AVAILABLE = False
# Import Physics Fields
try:
from ..physics.fields import (
compute_phase_curvature,
compute_phase_gradient,
compute_structural_potential,
estimate_coherence_length,
)
HAS_PHYSICS = True
except ImportError:
HAS_PHYSICS = False
@dataclass
class StructuralCacheEntry:
"""Cache entry for structural field computations."""
phi_s: dict[Any, float] = field(default_factory=dict)
grad_phi: dict[Any, float] = field(default_factory=dict)
k_phi: dict[Any, float] = field(default_factory=dict)
xi_c: float = 0.0
coherence: float = 0.0
timestamp: float = 0.0
topology_hash: str = ""
spectral_basis_signature: str = ""
eigenvalues: np.ndarray | None = None
eigenvectors: np.ndarray | None = None
coordination_nodes: list[Any] = field(default_factory=list)
@dataclass
class ResonancePattern:
"""Cached resonance pattern for frequency optimization."""
frequencies: np.ndarray
amplitudes: np.ndarray
phases: np.ndarray
pattern_hash: str
usage_count: int = 0
class StructuralCoherenceCache:
"""
Specialized cache for TNFR structural computations.
Leverages the mathematical structure of structural fields to
provide intelligent caching with dependency tracking.
"""
def __init__(self, max_entries: int = 500, enable_interpolation: bool = True):
self.max_entries = max_entries
self.enable_interpolation = enable_interpolation
self._structural_cache: dict[str, StructuralCacheEntry] = {}
self._resonance_cache: dict[str, ResonancePattern] = {}
# Performance counters
self.hits = 0
self.misses = 0
self.interpolations = 0
# Global cache integration
if _CACHE_AVAILABLE:
self._global_cache = get_global_cache()
else:
self._global_cache = None
self._fft_cache = None
self._fft_cache_checked = False
def get_topology_hash(self, G: Any) -> str:
"""Generate topology hash for cache keying."""
if not HAS_NETWORKX or G is None:
return "empty"
# Create deterministic topology fingerprint
nodes = sorted(G.nodes())
edges = sorted(G.edges())
# Include node properties in hash
node_props = []
for node in nodes:
props = G.nodes[node]
epi_v = get_attr(props, ALIAS_EPI, 0.0)
vf_v = get_attr(props, ALIAS_VF, 1.0)
ph_v = get_attr(props, ALIAS_THETA, 0.0)
prop_str = f"{epi_v:.3f}_{vf_v:.3f}_{ph_v:.3f}"
node_props.append(prop_str)
combined = f"n{len(nodes)}_e{len(edges)}_props{'_'.join(node_props)}"
return hashlib.md5(combined.encode(), usedforsecurity=False).hexdigest()[:16]
def get_structural_fields(
self,
G: Any,
force_recompute: bool = False,
interpolate_threshold: float = STRUCT_CACHE_INTERPOLATE_CANONICAL, # = 0.1 (operational)
spectral_basis: Any | None = None,
) -> StructuralCacheEntry:
"""
Get structural fields with intelligent caching and interpolation.
Returns cached results if topology is unchanged, or interpolates
if changes are small (< interpolate_threshold).
"""
if not HAS_NETWORKX or not HAS_PHYSICS or G is None:
return StructuralCacheEntry()
topology_hash = self.get_topology_hash(G)
spectral_basis = spectral_basis or self._maybe_fetch_spectral_basis(G)
# Check direct cache hit
if not force_recompute and topology_hash in self._structural_cache:
self.hits += 1
entry = self._structural_cache[topology_hash]
self._attach_spectral_basis(entry, spectral_basis)
return entry
# Check for interpolation opportunities
if self.enable_interpolation and not force_recompute:
interpolated = self._try_interpolate_fields(
G, topology_hash, interpolate_threshold
)
if interpolated is not None:
self.interpolations += 1
self._attach_spectral_basis(interpolated, spectral_basis)
return interpolated
# Compute from scratch
self.misses += 1
entry = self._compute_structural_fields(G, topology_hash, spectral_basis)
# Cache with LRU eviction
self._cache_with_eviction(topology_hash, entry)
return entry
def _compute_structural_fields(
self, G: Any, topology_hash: str, spectral_basis: Any | None = None
) -> StructuralCacheEntry:
"""Compute all structural fields for the graph."""
if not HAS_PHYSICS:
return StructuralCacheEntry(topology_hash=topology_hash)
try:
# Compute canonical structural fields
phi_s = compute_structural_potential(G, alpha=2.0)
grad_phi = compute_phase_gradient(G)
k_phi = compute_phase_curvature(G)
xi_c = estimate_coherence_length(G)
# Compute global coherence
coherence = self._compute_global_coherence(G)
entry = StructuralCacheEntry(
phi_s=phi_s,
grad_phi=grad_phi,
k_phi=k_phi,
xi_c=xi_c,
coherence=coherence,
timestamp=0.0, # Could integrate with time if available
topology_hash=topology_hash,
)
self._attach_spectral_basis(entry, spectral_basis)
return entry
except Exception:
# Fallback to empty entry if computation fails
return StructuralCacheEntry(topology_hash=topology_hash)
def register_coordination_nodes(
self, G: Any, coordination_nodes: list[Any], spectral_basis: Any | None = None
) -> None:
"""Register nodes that coordinate cache distribution."""
if not HAS_NETWORKX or G is None:
return
topology_hash = self.get_topology_hash(G)
entry = self._structural_cache.get(topology_hash)
if entry is None:
entry = self.get_structural_fields(
G, force_recompute=False, spectral_basis=spectral_basis
)
entry.coordination_nodes = list(coordination_nodes)
self._attach_spectral_basis(entry, spectral_basis)
def _maybe_fetch_spectral_basis(self, G: Any) -> Any | None:
"""Fetch spectral basis from FFT cache if available."""
if G is None:
return None
fft_cache = self._get_fft_cache()
if fft_cache is None:
return None
try:
return fft_cache.get_spectral_basis(G)
except Exception:
return None
def _get_fft_cache(self) -> Any | None:
"""Lazily instantiate FFT cache coordinator."""
if self._fft_cache_checked:
return self._fft_cache
try:
from .fft_cache_coordinator import get_fft_cache_coordinator
self._fft_cache = get_fft_cache_coordinator()
except ImportError:
self._fft_cache = None
self._fft_cache_checked = True
return self._fft_cache
def _attach_spectral_basis(
self, entry: StructuralCacheEntry | None, spectral_basis: Any | None
) -> None:
"""Attach spectral metadata to cache entry."""
if entry is None or spectral_basis is None:
return
entry.spectral_basis_signature = getattr(spectral_basis, "signature", "")
entry.eigenvalues = getattr(spectral_basis, "eigenvalues", None)
entry.eigenvectors = getattr(spectral_basis, "eigenvectors", None)
def _compute_global_coherence(self, G: Any) -> float:
"""Compute global coherence measure."""
if not HAS_NETWORKX or G is None:
return 0.0
# Simple coherence proxy: phase synchronization
phases = []
for node in G.nodes():
phase = get_attr(G.nodes[node], ALIAS_THETA, 0.0)
phases.append(phase)
if not phases:
return 0.0
# Kuramoto order parameter
phases = np.array(phases)
z = np.mean(np.exp(1j * phases))
return float(np.abs(z))
def _try_interpolate_fields(
self, G: Any, new_hash: str, threshold: float
) -> StructuralCacheEntry | None:
"""
Try to interpolate structural fields from similar cached entries.
Uses topology similarity and field continuity assumptions.
"""
if not self._structural_cache:
return None
# Find most similar cached topology
best_match = None
best_similarity = 0.0
current_nodes = set(G.nodes()) if HAS_NETWORKX and G else set()
current_edges = set(G.edges()) if HAS_NETWORKX and G else set()
for cached_hash, entry in self._structural_cache.items():
# Simple similarity based on hash prefix matching
common_prefix = 0
for i in range(min(len(cached_hash), len(new_hash))):
if cached_hash[i] == new_hash[i]:
common_prefix += 1
else:
break
similarity = common_prefix / max(len(cached_hash), len(new_hash))
if similarity > best_similarity and similarity > threshold:
best_similarity = similarity
best_match = entry
if best_match is None or best_similarity < threshold:
return None
# Create interpolated entry (simple copy for now - could implement actual interpolation)
interpolated = StructuralCacheEntry(
phi_s=best_match.phi_s.copy(),
grad_phi=best_match.grad_phi.copy(),
k_phi=best_match.k_phi.copy(),
xi_c=best_match.xi_c,
coherence=best_match.coherence,
timestamp=best_match.timestamp,
topology_hash=new_hash,
)
# Cache the interpolated result
self._cache_with_eviction(new_hash, interpolated)
return interpolated
def cache_resonance_pattern(
self, frequencies: np.ndarray, amplitudes: np.ndarray, phases: np.ndarray
) -> str:
"""
Cache a resonance pattern for frequency-domain optimizations.
Returns pattern hash for later retrieval.
"""
# Generate pattern fingerprint
freq_hash = hashlib.md5(
frequencies.tobytes(), usedforsecurity=False
).hexdigest()[:8]
amp_hash = hashlib.md5(amplitudes.tobytes(), usedforsecurity=False).hexdigest()[
:8
]
phase_hash = hashlib.md5(phases.tobytes(), usedforsecurity=False).hexdigest()[
:8
]
pattern_hash = f"{freq_hash}_{amp_hash}_{phase_hash}"
# Store pattern
pattern = ResonancePattern(
frequencies=frequencies.copy(),
amplitudes=amplitudes.copy(),
phases=phases.copy(),
pattern_hash=pattern_hash,
usage_count=1,
)
self._resonance_cache[pattern_hash] = pattern
# Evict old patterns if needed
if len(self._resonance_cache) > self.max_entries // 2:
self._evict_resonance_patterns()
return pattern_hash
def get_resonance_pattern(self, pattern_hash: str) -> ResonancePattern | None:
"""Retrieve cached resonance pattern."""
pattern = self._resonance_cache.get(pattern_hash)
if pattern is not None:
pattern.usage_count += 1
return pattern
def _cache_with_eviction(self, key: str, entry: StructuralCacheEntry) -> None:
"""Cache entry with LRU eviction."""
self._structural_cache[key] = entry
# Simple eviction: remove oldest entries
if len(self._structural_cache) > self.max_entries:
# Remove 20% of oldest entries
to_remove = len(self._structural_cache) - int(
STRUCT_CACHE_EVICTION_CANONICAL * self.max_entries
) # = 0.74 (operational)
keys_to_remove = list(self._structural_cache.keys())[:to_remove]
for k in keys_to_remove:
del self._structural_cache[k]
def _evict_resonance_patterns(self) -> None:
"""Evict least-used resonance patterns."""
if not self._resonance_cache:
return
# Sort by usage count and keep top 50%
patterns = sorted(
self._resonance_cache.items(), key=lambda x: x[1].usage_count, reverse=True
)
keep_count = len(patterns) // 2
new_cache = {}
for i in range(keep_count):
key, pattern = patterns[i]
new_cache[key] = pattern
self._resonance_cache = new_cache
def get_cache_stats(self) -> dict[str, Any]:
"""Get caching performance statistics."""
total_requests = self.hits + self.misses
hit_rate = self.hits / max(1, total_requests)
return {
"hits": self.hits,
"misses": self.misses,
"interpolations": self.interpolations,
"hit_rate": hit_rate,
"structural_entries": len(self._structural_cache),
"resonance_patterns": len(self._resonance_cache),
"cache_enabled": _CACHE_AVAILABLE,
}
def clear_cache(self) -> None:
"""Clear all caches."""
self._structural_cache.clear()
self._resonance_cache.clear()
self.hits = 0
self.misses = 0
self.interpolations = 0
# Global cache instance
_global_structural_cache = None
def get_structural_cache() -> StructuralCoherenceCache:
"""Get or create the global structural cache."""
global _global_structural_cache
if _global_structural_cache is None:
_global_structural_cache = StructuralCoherenceCache()
return _global_structural_cache
def cached_structural_fields(G: Any, **kwargs) -> StructuralCacheEntry:
"""Convenience function for cached structural field computation."""
cache = get_structural_cache()
return cache.get_structural_fields(G, **kwargs)
# Decorator for automatic structural field caching
def cache_structural_computation(func):
"""Decorator to automatically cache structural computations."""
@wraps(func)
def wrapper(*args, **kwargs):
# Extract graph from arguments (assume first argument)
if args:
G = args[0]
cache = get_structural_cache()
# Try to use cached fields if the function needs them
if hasattr(func, "_uses_structural_fields"):
cached_entry = cache.get_structural_fields(G)
kwargs["_cached_fields"] = cached_entry
return func(*args, **kwargs)
return wrapper