"""Bayesian perception as pattern completion (MERCURIAL D)."""
from typing import Optional
import numpy as np
from mercurial.spectral.modalities import ModalityEnergyHierarchy
[docs]
class BayesianPerception:
"""
Implements perceptual inference via variational free energy minimization.
"""
[docs]
def __init__(
self,
hierarchy: ModalityEnergyHierarchy,
prior_strength: float = 1.0,
learning_rate: float = 0.1,
):
"""
Parameters
----------
hierarchy : ModalityEnergyHierarchy
Energy hierarchy for modality thresholds.
prior_strength : float
β_prior for prior influence.
learning_rate : float
Step size for gradient descent.
"""
self.hierarchy = hierarchy
self.prior_strength = prior_strength
self.lr = learning_rate
# Import DPR pathway optimizer here to avoid circular import
from mercurial.spectral.dpr_pathways import DPRPathwayOptimizer
self.dpr_optimizer = DPRPathwayOptimizer()
[docs]
def free_energy(
self,
sensory_input: np.ndarray,
predicted_pattern: np.ndarray,
prior_pattern: Optional[np.ndarray] = None,
) -> float:
"""
F_perc = ||sensory - predicted||^2 + β_prior ||predicted - prior||^2
"""
likelihood_term = np.linalg.norm(sensory_input - predicted_pattern) ** 2
if prior_pattern is not None:
prior_term = (
self.prior_strength * np.linalg.norm(predicted_pattern - prior_pattern) ** 2
)
else:
prior_term = 0.0
return likelihood_term + prior_term
[docs]
def infer_hidden_state(
self, sensory_input: np.ndarray, prior: Optional[np.ndarray] = None, max_iter: int = 20
) -> np.ndarray:
"""
Find pattern that minimizes free energy (gradient descent).
"""
if prior is not None:
hidden = prior.copy()
else:
hidden = sensory_input.copy()
for _ in range(max_iter):
grad = 2 * (hidden - sensory_input)
if prior is not None:
grad += 2 * self.prior_strength * (hidden - prior)
hidden -= self.lr * grad
return hidden
[docs]
def detection_threshold(
self, pattern_intensity: float, observer_coherence: float, environmental_noise: float
) -> float:
"""
Θ_perc = Θ_0 * (1 + β_state ψ_obs) / (1 + γ_noise N_env) * (1 - S/S_crit)
"""
Theta0 = 0.1 # base threshold
beta_state = 0.5
gamma_noise = 0.1
S = 1.0 - observer_coherence # entropy proxy
S_crit = 10.0
numerator = 1.0 + beta_state * observer_coherence
denominator = 1.0 + gamma_noise * environmental_noise
entropy_factor = 1.0 - S / S_crit
return Theta0 * (numerator / denominator) * max(0.0, entropy_factor)
[docs]
def detect(
self, pattern_intensity: float, observer_coherence: float, environmental_noise: float
) -> bool:
"""Return True if pattern is consciously perceived."""
threshold = self.detection_threshold(
pattern_intensity, observer_coherence, environmental_noise
)
return pattern_intensity > threshold
[docs]
def dpr_perception(
self,
sensory_input: np.ndarray,
pattern_energy: float,
pattern_coherence: float,
environmental_noise: float,
branch_similarity: float = 1.0,
) -> np.ndarray:
"""
Use optimal DPR pathway for perception.
"""
pathway, eff = self.dpr_optimizer.select_optimal_pathway(
pattern_energy, pattern_coherence, environmental_noise, branch_similarity
)
if eff > 0.5:
# DPR is viable; use direct transfer
return self.dpr_optimizer.simulate_dpr_transfer(sensory_input, pathway, eff)
else:
# Fallback to variational inference
return self.infer_hidden_state(sensory_input)