Vitalis_Devcore / src /cortex /predictive.py
FerrellSyntheticIntelligence
Add PinealGland, AttentionalGate, PredictiveCortex, ThalamicLoop, full quad-flow architecture
c99bf3c
"""
Predictive Cortex β€” Vitalis FSI
Implements predictive processing: the cortex maintains a model
of what it expects to see next, and only forwards the PREDICTION
ERROR to higher cognitive layers β€” not the raw input.
This is how biological cortex works. It predicts constantly.
What gets attention is what violates prediction.
Steps:
1. Maintain a running prediction of the next input
2. Compute prediction error = actual - predicted
3. Update prediction based on error
4. Forward error vector to cognitive core
5. Strong errors = surprise = attention = learning
"""
import numpy as np
from vitalis_ide.math_core.kernel import VitalisKernel
class PredictiveCortex:
LEARNING_RATE = 0.05
SURPRISE_THRESHOLD = 0.3
def __init__(self, dim: int = 10_000):
self.dim = dim
self.kernel = VitalisKernel()
self._prediction = np.zeros(dim, dtype=np.float32)
self._cycle = 0
self._surprise_history = []
def process(self, hv: np.ndarray) -> tuple:
"""
Feed an input hypervector through predictive processing.
Returns:
error_vec : prediction error as bipolar int8 vector
surprise : float [0,1] β€” how surprising was this input
is_novel : bool β€” above surprise threshold
"""
self._cycle += 1
hv_f = hv.astype(np.float32)
# Prediction error
error_f = hv_f - self._prediction
# Surprise = normalized magnitude of error
surprise = float(np.tanh(np.linalg.norm(error_f) / np.sqrt(self.dim)))
# Update prediction toward actual input
self._prediction += self.LEARNING_RATE * error_f
# Binarize error for downstream HDC processing
error_vec = np.sign(error_f).astype(np.int8)
error_vec[error_vec == 0] = 1
is_novel = surprise > self.SURPRISE_THRESHOLD
self._surprise_history.append(surprise)
if len(self._surprise_history) > 100:
self._surprise_history.pop(0)
return error_vec, surprise, is_novel
def reset_prediction(self):
"""Call after dream cycle β€” fresh prediction slate."""
self._prediction *= 0.5
def avg_surprise(self) -> float:
if not self._surprise_history:
return 0.0
return round(float(np.mean(self._surprise_history[-20:])), 4)
def report(self) -> dict:
return {
"cycles": self._cycle,
"avg_surprise": self.avg_surprise(),
"prediction_norm": round(float(np.linalg.norm(self._prediction)), 4),
}