import numpy as np from datetime import datetime from .emma_mdp import EmmaAction class MorphicMemory: """ Morphic Resonance pattern cache (in-memory). Resonansvekt: w = sim(s,s') * ln(1+n) * decay^d * R """ def __init__(self, decay_rate: float = 0.95): self.patterns: list[dict] = [] self.decay = decay_rate def store(self, state_embedding: np.ndarray, action: EmmaAction, reward_val: float): for p in self.patterns: if _cosine(state_embedding, p["embedding"]) > 0.92: p["count"] += 1 p["reward"] = 0.7 * p["reward"] + 0.3 * reward_val p["lastseen"] = datetime.now() return self.patterns.append({ "embedding": state_embedding, "action": action, "reward": reward_val, "count": 1, "lastseen": datetime.now(), }) def recall(self, state_embedding: np.ndarray, top_k: int = 3) -> list[dict]: scored = [] now = datetime.now() for p in self.patterns: sim = _cosine(state_embedding, p["embedding"]) age_days = (now - p["lastseen"]).days recency = self.decay ** age_days resonance = sim * np.log1p(p["count"]) * recency * p["reward"] scored.append((resonance, p)) return [p for _, p in sorted(scored, reverse=True)[:top_k]] def __len__(self): return len(self.patterns) def _cosine(a: np.ndarray, b: np.ndarray) -> float: return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-9))