Source code for mercurial.branches.decoherence

"""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), )