"""Top‑down biasing operator (MERCURIAL A.4, Definition 4.5)."""
from typing import Optional, Tuple
import numpy as np
from mercurial.core.patterns import Pattern
from mercurial.core.wilson_cowan import WilsonCowanPopulation
[docs]
class TopDownBiasing:
"""
Implements organizational causation: consciousness biases reality patterns.
The biasing strength κ_bias determines how strongly conscious patterns
influence the evolution of local reality patterns.
"""
[docs]
def __init__(self, kappa_bias: float = 0.1):
"""
Parameters
----------
kappa_bias : float
Biasing strength (κ_bias). Typical range 0.01–0.5.
"""
self.kappa_bias = kappa_bias
[docs]
def compute_biasing_field(
self,
consciousness_pattern: Pattern,
reality_pattern: Pattern,
target_level: int,
projection_dim: Optional[int] = None,
) -> np.ndarray:
"""
Compute the biasing term B[reality] from consciousness.
"""
from mercurial.core.dynamics import free_energy_gradient
# Project consciousness onto reality's state space
v_conscious = consciousness_pattern.V.flatten()
v_reality = reality_pattern.V.flatten()
min_dim = min(len(v_conscious), len(v_reality))
v_projected = v_conscious[:min_dim]
# Compute gradient of reality's free energy (returns tuple)
grad_F, _ = free_energy_gradient(reality_pattern)
grad_flat = grad_F.flatten()[:min_dim]
# Biasing term: consciousness pulls reality toward its own configuration
bias = -self.kappa_bias * (v_projected - grad_flat)
# Apply range enforcement penalty
penalty = self.enforce_range(consciousness_level=9, target_level=target_level)
bias *= penalty
# Reshape to match reality's pattern shape
if bias.shape != reality_pattern.V.shape:
bias = bias.reshape(reality_pattern.V.shape)
return bias
[docs]
def apply_biasing(
self, reality_pattern: Pattern, consciousness_pattern: Pattern, dt: float, target_level: int
) -> Pattern:
"""
Apply biasing to reality pattern for one time step.
"""
bias = self.compute_biasing_field(consciousness_pattern, reality_pattern, target_level)
new_V = reality_pattern.V + bias * dt
return Pattern(
new_V, reality_pattern.C, reality_pattern.R, label=f"{reality_pattern.label}_biased"
)
[docs]
def enforce_range(self, consciousness_level: int, target_level: int) -> float:
"""
Return a multiplicative penalty (0-1) for biasing outside allowed range.
Consciousness can only bias Levels 7-10 effectively.
"""
allowed_min = 7
allowed_max = 10
if allowed_min <= target_level <= allowed_max:
return 1.0 # no penalty
# Distance outside allowed range
if target_level < allowed_min:
distance = allowed_min - target_level
else:
distance = target_level - allowed_max
# Exponential decay penalty: halved every level outside range
return np.exp(-distance) # distance=1 → 0.368, distance=2 → 0.135
# ========================================================================
# Biasing for Wilson‑Cowan neural populations (appended)
# ========================================================================
[docs]
def compute_neural_bias(
self, consciousness_pattern, target_neural_pattern, target_level: int
) -> Tuple[float, float]:
"""
Compute external input bias (P_ext, Q_ext) for a Wilson‑Cowan population.
"""
penalty = self.enforce_range(consciousness_level=9, target_level=target_level)
# Use the consciousness pattern's mean activity as bias strength
if (
hasattr(consciousness_pattern, "E_history")
and consciousness_pattern.E_history is not None
):
bias_val = np.mean(consciousness_pattern.E_history[-100:])
else:
bias_val = 0.5 # default
bias = self.kappa_bias * penalty * bias_val
# Add to both excitatory and inhibitory inputs
return bias, bias
def _compute_gradient(self, pattern: Pattern) -> np.ndarray:
"""Compute gradient of free energy with respect to pattern state."""
from mercurial.core.dynamics import free_energy_gradient
grad, _ = free_energy_gradient(pattern)
return grad.flatten()