48 lines
1.6 KiB
Python
48 lines
1.6 KiB
Python
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))
|