Source code for mercurial.spectral.modalities

"""Sensory modality definitions and energy hierarchy (SPECTRAL A.1.1)."""

from dataclasses import dataclass
from enum import Enum

import numpy as np

from mercurial.spectral.quantum_fields import ModalityField, UnifiedField


[docs] class Modality(Enum): """All sensory modalities recognized in SPECTRAL.""" DPR = "dpr" AFFECTIVE = "affective" AUDITORY = "auditory" TACTILE = "tactile" VISUAL = "visual" OLFACTORY = "olfactory" GUSTATORY = "gustatory" PROPRIOCEPTIVE = "proprioceptive" VESTIBULAR = "vestibular" INTEROCEPTIVE = "interoceptive" NOCICEPTIVE = "nociceptive" THERMOCEPTIVE = "thermoceptive" CHRONOCEPTIVE = "chronoceptive" AGENCY = "agency" MAGNETOCEPTIVE = "magnetoceptive" ELECTROCEPTIVE = "electroceptive"
[docs] @dataclass class ModalitySpec: name: Modality log_energy_threshold: float # log10(E_thresh) [log10(J)] baseline_latency: float # τ_act0 [s] coupling_coefficient: float # sensitivity
# Energy thresholds from SPECTRAL A.1.1 (in log10 Joules) MODALITY_SPECS = { Modality.DPR: ModalitySpec(Modality.DPR, -23.0, 0.001, 1.0), Modality.AFFECTIVE: ModalitySpec(Modality.AFFECTIVE, -21.0, 0.0, 0.9), Modality.AUDITORY: ModalitySpec(Modality.AUDITORY, -18.0, 0.05, 0.8), Modality.TACTILE: ModalitySpec(Modality.TACTILE, -17.0, 0.1, 0.7), Modality.VISUAL: ModalitySpec(Modality.VISUAL, -16.0, 0.2, 0.6), Modality.OLFACTORY: ModalitySpec(Modality.OLFACTORY, -15.0, 0.5, 0.5), Modality.GUSTATORY: ModalitySpec(Modality.GUSTATORY, -13.0, 1.0, 0.4), Modality.PROPRIOCEPTIVE: ModalitySpec(Modality.PROPRIOCEPTIVE, -18.0, 0.01, 0.7), Modality.VESTIBULAR: ModalitySpec(Modality.VESTIBULAR, -18.0, 0.01, 0.7), Modality.INTEROCEPTIVE: ModalitySpec(Modality.INTEROCEPTIVE, -19.0, 0.5, 0.6), Modality.NOCICEPTIVE: ModalitySpec(Modality.NOCICEPTIVE, -17.0, 0.05, 0.8), Modality.THERMOCEPTIVE: ModalitySpec(Modality.THERMOCEPTIVE, -18.0, 0.1, 0.7), Modality.CHRONOCEPTIVE: ModalitySpec(Modality.CHRONOCEPTIVE, -20.0, 0.0, 0.5), Modality.AGENCY: ModalitySpec(Modality.AGENCY, -19.0, 0.05, 0.6), Modality.MAGNETOCEPTIVE: ModalitySpec(Modality.MAGNETOCEPTIVE, -21.0, 0.5, 0.3), Modality.ELECTROCEPTIVE: ModalitySpec(Modality.ELECTROCEPTIVE, -20.0, 0.3, 0.4), }
[docs] class ModalityEnergyHierarchy: """Manages energy thresholds and manifestation probabilities."""
[docs] def __init__(self, steepness: float = 5.0, spatial_points: int = 10): """ steepness: logistic slope factor (higher = sharper transition) """ self.steepness = steepness self.unified_field = UnifiedField(spatial_points) self.specs = MODALITY_SPECS
def manifestation_probability( self, modality: Modality, pattern_energy: float, pattern_entropy: float ) -> float: """ p_manif = sigmoid(steepness * (log10(E_pattern) - log10(E_thresh))) * max(0, 1 - entropy/10) """ spec = self.specs[modality] logE_pattern = np.log10(max(pattern_energy, 1e-30)) logE_thresh = spec.log_energy_threshold # Logistic function centered at threshold energy_factor = 1.0 / (1.0 + np.exp(-self.steepness * (logE_pattern - logE_thresh))) # Entropy factor: lower entropy → higher probability entropy_factor = max(0.0, 1.0 - pattern_entropy / 10.0) # Coupling coefficient modulates overall sensitivity return energy_factor * entropy_factor * spec.coupling_coefficient
[docs] def activation_time(self, modality: Modality, pattern_power: float) -> float: """ τ_act = τ_0 + ΔE / P_bias Using log-energy difference as proxy for ΔE. """ spec = self.specs[modality] logE_pattern = np.log10(max(pattern_power, 1e-30)) logE_thresh = spec.log_energy_threshold delta_logE = max(0.0, logE_thresh - logE_pattern) # Convert log difference to a time penalty time_penalty = delta_logE * 0.1 # 0.1 s per order of magnitude deficit return spec.baseline_latency + time_penalty
[docs] def dominant_modality(self, pattern_energy: float, pattern_entropy: float) -> Modality: best_mod = None best_prob = -1.0 for mod in Modality: prob = self.manifestation_probability(mod, pattern_energy, pattern_entropy) if prob > best_prob: best_prob = prob best_mod = mod return best_mod
[docs] def update_field_evolution(self, dt: float, pattern_energy: float, pattern_coherence: float): """Call this each simulation step to evolve quantum fields.""" self.unified_field.evolve_all(dt, pattern_energy, pattern_coherence)
[docs] def manifestation_probability( self, modality: Modality, pattern_energy: float, pattern_entropy: float ) -> float: # Use field-based probability if available, else fallback try: mod_field = getattr(ModalityField, modality.name) return self.unified_field.manifestation_probability(mod_field) except (AttributeError, KeyError): # Fallback to energy-based spec = self.specs[modality] logE_pattern = np.log10(max(pattern_energy, 1e-30)) logE_thresh = spec.log_energy_threshold energy_factor = 1.0 / (1.0 + np.exp(-self.steepness * (logE_pattern - logE_thresh))) entropy_factor = max(0.0, 1.0 - pattern_entropy / 10.0) return energy_factor * entropy_factor * spec.coupling_coefficient