"""Branch decoherence: orthogonality and decoherence rate (Definition 5.1)."""
from typing import Tuple
import numpy as np
from mercurial.core.state_space import StateVector
[docs]
class DecoherenceMeasure:
"""
Computes decoherence between branches and the rate of decoherence.
Key concepts:
- Orthogonality: |⟨x_a, x_b⟩| ≈ 0
- Decoherence rate: γ_dec = γ_0 * (1 - |⟨x_a, x_b⟩|²)
"""
[docs]
def __init__(self, base_rate: float = 0.1, environment_coupling: float = 0.01):
"""
Parameters
----------
base_rate : float
γ_0 – maximum decoherence rate (per second).
environment_coupling : float
Coupling to environmental degrees of freedom that drive decoherence.
"""
self.gamma_0 = base_rate
self.env_coupling = environment_coupling
[docs]
def overlap(self, state_a: StateVector, state_b: StateVector) -> float:
"""
Compute |⟨x_a, x_b⟩|, the absolute value of the inner product.
"""
return abs(state_a.space.inner_product(state_a.components, state_b.components))
[docs]
def orthogonality(self, state_a: StateVector, state_b: StateVector) -> float:
"""
Orthogonality measure: 1 - |⟨x_a, x_b⟩|.
Fully orthogonal = 1, identical = 0.
"""
return 1.0 - self.overlap(state_a, state_b)
[docs]
def decoherence_rate(
self, state_a: StateVector, state_b: StateVector, entropy_a: float, entropy_b: float
) -> float:
"""
γ_dec = γ_0 * (1 - |⟨x_a, x_b⟩|²) * f(S_a, S_b)
where f(S) = exp(-(S_a + S_b)/S_crit) – higher entropy increases decoherence.
"""
overlap_sq = self.overlap(state_a, state_b) ** 2
# Entropy factor: higher entropy → faster decoherence
S_crit = 10.0
entropy_factor = np.exp(-(entropy_a + entropy_b) / S_crit)
return self.gamma_0 * (1 - overlap_sq) * entropy_factor
[docs]
def is_decohered(
self, state_a: StateVector, state_b: StateVector, threshold: float = 0.99
) -> bool:
"""
Return True if branches are effectively decohered.
threshold = 0.99 means 99% orthogonal.
"""
return self.orthogonality(state_a, state_b) >= threshold
[docs]
def decoherence_time(
self, state_a: StateVector, state_b: StateVector, entropy_a: float, entropy_b: float
) -> float:
"""
Characteristic time for decoherence: τ_dec = 1/γ_dec.
"""
gamma = self.decoherence_rate(state_a, state_b, entropy_a, entropy_b)
return 1.0 / gamma if gamma > 0 else np.inf
[docs]
class BranchDecoherenceDynamics:
"""
Simulates the time evolution of branch state vectors under decoherence.
"""
def __init__(self, decoherence_measure: DecoherenceMeasure):
self.dm = decoherence_measure
[docs]
def evolve_branch_state(
self, state: StateVector, dt: float, environment_noise: float = 0.01
) -> StateVector:
"""
Simplified evolution: state loses coherence with environment.
d|ψ>/dt = -γ_env |ψ> + noise
"""
# Decoherence from environment (not cross-branch)
gamma_env = self.dm.env_coupling
new_components = state.components * (1 - gamma_env * dt)
# Add Gaussian noise (environmental fluctuations)
noise = np.random.normal(0, np.sqrt(environment_noise * dt), size=len(new_components))
new_components += noise
return StateVector(state.space, new_components, state.time + dt)
[docs]
def evolve_pair(
self,
state_a: StateVector,
state_b: StateVector,
dt: float,
entropy_a: float,
entropy_b: float,
) -> Tuple[StateVector, StateVector]:
"""
Evolve two branch states with mutual decoherence.
The decoherence rate between them drives them apart.
"""
gamma = self.dm.decoherence_rate(state_a, state_b, entropy_a, entropy_b)
# Repulsion term: states are pushed toward orthogonality
overlap = self.dm.overlap(state_a, state_b)
# Project onto the orthogonal component
ortho_component_a = state_a.components - overlap * state_b.components
ortho_component_b = state_b.components - overlap * state_a.components
# Apply repulsion
new_a = state_a.components + gamma * dt * ortho_component_a
new_b = state_b.components + gamma * dt * ortho_component_b
# Normalize (preserve norm)
new_a = new_a / (np.linalg.norm(new_a) + 1e-12)
new_b = new_b / (np.linalg.norm(new_b) + 1e-12)
return (
StateVector(state_a.space, new_a, state_a.time + dt),
StateVector(state_b.space, new_b, state_b.time + dt),
)