Source code for mercurial.branches.formation

"""Branch formation via symmetry breaking and bifurcation (MERCURIAL B)."""

from dataclasses import dataclass
from typing import List, Tuple

import numpy as np

from mercurial.branches.branch import RealityBranch
from mercurial.branches.decoherence import DecoherenceMeasure
from mercurial.core.state_space import HilbertSpace, StateVector


[docs] @dataclass class BifurcationPoint: """Parameters at which a branch splits.""" time: float critical_state: StateVector symmetry_parameter: float new_branch_seed: StateVector
[docs] class SymmetryBreaking: """ Simulates branch formation via spontaneous symmetry breaking. Key concept: When a control parameter crosses a critical threshold, the symmetric state becomes unstable, and two (or more) new stable branches emerge. """ def __init__( self, space: HilbertSpace, critical_parameter: float = 1.0, bifurcation_strength: float = 0.1, ): self.space = space self.theta_crit = critical_parameter self.strength = bifurcation_strength self.decoherence = DecoherenceMeasure()
[docs] def compute_order_parameter(self, state: StateVector) -> float: """ Order parameter that breaks symmetry (e.g., magnetization, phase difference). Simplified: variance of components. """ return np.var(state.components.real) + np.var(state.components.imag)
[docs] def is_instability_condition(self, state: StateVector, parameter: float) -> bool: """ Check if system is at a bifurcation point. """ return parameter >= self.theta_crit
[docs] def generate_new_branch_states( self, parent_state: StateVector, n_branches: int = 2 ) -> List[StateVector]: """ Generate n_branches new branch states from the parent state. Uses random orthogonal perturbations. """ new_states = [] dim = len(parent_state.components) for _ in range(n_branches): # Generate random orthogonal perturbation perturbation = np.random.normal(0, self.strength, size=dim) + 1j * np.random.normal( 0, self.strength, size=dim ) # Project onto orthogonal subspace of parent state parent_norm = parent_state.components / np.linalg.norm(parent_state.components) perturbation = perturbation - np.dot(perturbation, parent_norm) * parent_norm new_components = parent_state.components + perturbation # Normalize new_components = new_components / np.linalg.norm(new_components) new_states.append(StateVector(parent_state.space, new_components, parent_state.time)) return new_states
[docs] def evolve_to_bifurcation( self, initial_state: StateVector, parameter_evolution: List[Tuple[float, float]], dt: float = 0.01, ) -> List[BifurcationPoint]: """ Simulate the evolution of a branch as a control parameter changes. parameter_evolution: list of (time, parameter_value) Returns list of bifurcation points. """ bifurcations = [] state = initial_state current_time = 0.0 param_idx = 0 param_value = parameter_evolution[0][1] if parameter_evolution else 0.0 while ( current_time < parameter_evolution[-1][0] and param_idx < len(parameter_evolution) - 1 ): # Update parameter next_time, next_param = parameter_evolution[param_idx + 1] param_value = next_param current_time = next_time param_idx += 1 # Check for bifurcation if self.is_instability_condition(state, param_value): # Generate new branches new_states = self.generate_new_branch_states(state) for new_state in new_states: bifurcations.append( BifurcationPoint( time=current_time, critical_state=state, symmetry_parameter=param_value, new_branch_seed=new_state, ) ) # For simplicity, continue with the first new branch state = new_states[0] return bifurcations
[docs] class BranchFormationSimulator: """ Simulates the emergence of a multiverse from a single initial branch. """ def __init__(self, space: HilbertSpace): self.space = space self.branches: List[RealityBranch] = [] self.symmetry = SymmetryBreaking(space)
[docs] def create_initial_branch(self, label: str = "Initial") -> RealityBranch: """Create the primordial branch.""" # Start with a random state vector components = np.random.normal(0, 1, size=self.space.dimension) + 1j * np.random.normal( 0, 1, size=self.space.dimension ) components = components / np.linalg.norm(components) state = StateVector(self.space, components, t=0.0) branch = RealityBranch(len(self.branches), label) branch.set_state_vector(state) self.branches.append(branch) return branch
[docs] def simulate_branching( self, parameter_evolution: List[Tuple[float, float]], max_branches: int = 10 ) -> List[RealityBranch]: """ Simulate branching over time. Returns list of all branches formed. """ if not self.branches: self.create_initial_branch() all_bifurcations = [] # For simplicity, we track only the first branch's bifurcations current_branch = self.branches[0] if current_branch.state_vector is None: return self.branches # Evolve the current branch and collect bifurcations bifurcations = self.symmetry.evolve_to_bifurcation( current_branch.state_vector, parameter_evolution ) all_bifurcations.extend(bifurcations) # Create new branches from each bifurcation point for bf in bifurcations[:max_branches]: new_branch = RealityBranch(len(self.branches), f"Branch_{len(self.branches)}") new_branch.set_state_vector(bf.new_branch_seed) self.branches.append(new_branch) return self.branches