"""Cross-branch alignment dynamics with level coupling (MERCURIAL C)."""
from dataclasses import dataclass
from typing import List, Optional
import numpy as np
from mercurial.hierarchy.coupling import LevelCoupling
[docs]
@dataclass
class AlignmentEvent:
branch_a: int
branch_b: int
position: np.ndarray
time: float
coupling_strength: float
duration: float
[docs]
def coupling_envelope(self, t: float) -> float:
dt = t - self.time
if dt < 0 or dt > self.duration:
return 0.0
decay = np.exp(-dt / (self.duration / 3))
return self.coupling_strength * decay
[docs]
class BranchAlignment:
"""
Implements alignment probability with cross‑level adjacency optimization.
"""
[docs]
def __init__(
self,
branch_levels: List[int],
base_coupling: float = 0.1,
alignment_threshold: float = 0.7,
decay_length: float = 1.0,
k_align: float = 1.0,
S_crit: float = 10.0,
tau_align: float = 1.0,
):
"""
Parameters
----------
branch_levels : List[int]
LADDER level for each branch.
base_coupling : float
K_0 for same-level coupling.
alignment_threshold : float
Minimum similarity to consider alignment.
decay_length : float
ℓ_adj for cross-level decay.
k_align : float
Boltzmann constant for entropy factor.
S_crit : float
Critical entropy threshold.
tau_align : float
Alignment decay time constant.
"""
self.branch_levels = branch_levels
self.base_coupling = base_coupling
self.theta_align = alignment_threshold
self.decay_length = decay_length
self.k_align = k_align
self.S_crit = S_crit
self.tau_align = tau_align
self.level_coupling = LevelCoupling(base_coupling, decay_length)
self._precompute_coupling_matrix()
def _precompute_coupling_matrix(self):
"""Precompute K_ij for all branch pairs."""
n = len(self.branch_levels)
self.K_matrix = np.zeros((n, n))
for i in range(n):
for j in range(n):
self.K_matrix[i, j] = self.level_coupling.coupling_strength(
self.branch_levels[i], self.branch_levels[j]
)
[docs]
def alignment_probability(
self,
branch_i: int,
branch_j: int,
entropy_i: float,
entropy_j: float,
base_similarity: float = 1.0,
) -> float:
"""
p_align = K_ij * base_similarity * exp(-(S_i+S_j)/k_align)
No hard threshold – allows low probabilities for cross‑level.
"""
K_ij = self.K_matrix[branch_i, branch_j]
S_total = entropy_i + entropy_j
entropy_factor = np.exp(-S_total / self.k_align)
p = K_ij * base_similarity * entropy_factor
# Optional: apply a soft threshold (sigmoid) if needed, but not zero
return p
[docs]
def compute_transfer(
self,
pattern_source: np.ndarray,
coupling: float,
mapping: Optional[np.ndarray] = None,
use_isomorphism: bool = True,
) -> np.ndarray:
if use_isomorphism and mapping is None:
from mercurial.branches.isomorphism import IsomorphismMapper
IsomorphismMapper()
# For demonstration, we'd need target pattern; here just identity
# In real use, mapping would be precomputed between branch patterns
mapping = np.eye(len(pattern_source))
if mapping is None:
mapping = np.eye(len(pattern_source))
transformed = mapping @ pattern_source
return coupling * transformed
[docs]
def alignment_dynamics(self, lambda0: float, t: float) -> float:
return lambda0 * np.exp(-t / self.tau_align)