From 7df06cd720a498be2be14061ba5bbd7774896153 Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 06:52:25 +0100 Subject: [PATCH 01/15] This updated implementation introduces several non-linear elements to the field state update --- requirements.txt | 2 +- src/nfs_story_waves.py | 192 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/nfs_story_waves.py diff --git a/requirements.txt b/requirements.txt index 51159cc..12f6443 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,4 @@ torch pytest pytest-asyncio pytest-mock -pytest-cov +transformers diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py new file mode 100644 index 0000000..fed3d35 --- /dev/null +++ b/src/nfs_story_waves.py @@ -0,0 +1,192 @@ +import numpy as np +from dataclasses import dataclass +import torch +import torch.autograd +from typing import List, Dict, Tuple +from transformers import AutoTokenizer, AutoModel +import logging + +logging.basicConfig(level=logging.DEBUG) +logger = logging.getLogger(__name__) + + +@dataclass +class NarrativeWave: + """Represents a story as a quantum wave function""" + + content: str + embedding: torch.Tensor # Semantic embedding as quantum state + amplitude: float # Story strength/influence + phase: float # Story's phase in narrative space + coherence: float # Measure of story stability + entanglement: Dict[str, float] # Connections to other stories + + def __post_init__(self): + assert self.embedding.dim() == 1, f"Embedding must be 1D, got shape {self.embedding.shape}" + assert self.embedding.shape[0] == 768, f"Embedding must have 768 elements, got {self.embedding.shape[0]}" + + +class NarrativeFieldSimulator: + def __init__(self): + # Initialize quantum semantic space + self.tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") + self.encoder = AutoModel.from_pretrained("bert-base-uncased") + self.quantum_dim = 768 # Embedding dimension + self.stories: Dict[str, NarrativeWave] = {} + self.field_state = torch.zeros(self.quantum_dim) + + def create_wave_function(self, content: str) -> NarrativeWave: + """Convert story to quantum wave function""" + # Create semantic embedding + tokens = self.tokenizer(content, return_tensors="pt", padding=True, truncation=True, max_length=512) + with torch.no_grad(): + embedding = self.encoder(**tokens).last_hidden_state.mean(dim=1).squeeze(0) + + # Initialize quantum properties + return NarrativeWave( + content=content, + embedding=embedding, # Now guaranteed to be 1D + amplitude=1.0, + phase=np.random.random() * 2 * np.pi, + coherence=1.0, + entanglement={}, + ) + + def quantum_interference(self, wave1: NarrativeWave, wave2: NarrativeWave) -> float: + """Calculate interference between two narrative waves""" + # Compute quantum interference using cosine similarity and phase + similarity = torch.cosine_similarity(wave1.embedding.unsqueeze(0), wave2.embedding.unsqueeze(0)) + phase_factor = np.cos(wave1.phase - wave2.phase) + return float(similarity * phase_factor) + + def apply_field_effects(self, wave: NarrativeWave, dt: float): + """Apply quantum field effects to a narrative wave""" + # Simulate quantum evolution + wave.phase += dt * wave.amplitude + wave.coherence *= np.exp(-dt / 10.0) # Gradual decoherence + + # Apply field interactions + field_interaction = torch.cosine_similarity( + wave.embedding, self.field_state.unsqueeze(0) + ) + wave.amplitude *= 1.0 + field_interaction * dt + + def update_field_state(self): + """Update the overall field state based on all stories with non-linear effects""" + new_field = torch.zeros(self.quantum_dim, requires_grad=True) + + for story in self.stories.values(): + # Combine wave functions with phase and amplitude + contribution = story.embedding * story.amplitude * torch.exp(1j * story.phase) + new_field += contribution.real + + # Apply non-linear transformation + field_potential = torch.tanh(new_field) + + # Calculate field gradient + field_gradient = torch.autograd.grad(field_potential.sum(), new_field, create_graph=True)[0] + + # Combine linear and non-linear effects + alpha = 0.7 # Adjustable parameter for balance between linear and non-linear effects + self.field_state = alpha * new_field + (1 - alpha) * field_gradient + + # Normalize field state + self.field_state = self.field_state / torch.norm(self.field_state) + + def detect_emergence(self) -> List[Dict]: + """Detect emergent patterns in the narrative field""" + logger.debug(f"Detecting emergence with {len(self.stories)} stories") + patterns = [] + if len(self.stories) < 3: + logger.debug("Not enough stories for meaningful patterns") + return patterns + + story_keys = list(self.stories.keys()) + embeddings = torch.stack([self.stories[key].embedding for key in story_keys]) + + similarity_matrix = torch.cosine_similarity( + embeddings.unsqueeze(1), embeddings.unsqueeze(0) + ) + + threshold = 0.8 + for i in range(len(similarity_matrix)): + connected = (similarity_matrix[i] > threshold).nonzero().squeeze(1) + if len(connected) > 2: + pattern = { + "stories": [story_keys[j.item()] for j in connected if j.item() < len(story_keys)], + "coherence": float(similarity_matrix[i, connected].mean()), + "field_strength": float( + self.stories[story_keys[i]].amplitude + ), + } + patterns.append(pattern) + logger.debug(f"Found pattern: {pattern}") + + logger.debug(f"Detected {len(patterns)} patterns") + return patterns + + def simulate_timestep(self, dt: float): + """Simulate one timestep of field evolution""" + # Update all wave functions + for story in self.stories.values(): + self.apply_field_effects(story, dt) + + # Calculate interference effects + story_ids = list(self.stories.keys()) + for i in range(len(story_ids)): + for j in range(i + 1, len(story_ids)): + interference = self.quantum_interference( + self.stories[story_ids[i]], self.stories[story_ids[j]] + ) + + # Apply interference effects + self.stories[story_ids[i]].amplitude *= 1.0 + interference * dt + self.stories[story_ids[j]].amplitude *= 1.0 + interference * dt + + # Update entanglement + self.stories[story_ids[i]].entanglement[story_ids[j]] = interference + self.stories[story_ids[j]].entanglement[story_ids[i]] = interference + + # Update field state + self.update_field_state() + + # Remove fully decohered stories + self.stories = {k: v for k, v in self.stories.items() if v.coherence > 0.1} + + +# Example usage +simulator = NarrativeFieldSimulator() + +# Add some initial stories +stories = [ + "The lab's funding was unexpectedly cut", + "Dr. Patel's experiment showed promising results", + "The department is considering a new research direction", +] + +for i, content in enumerate(stories): + wave = simulator.create_wave_function(content) + simulator.stories[f"story_{i}"] = wave + +# Run simulation +for t in range(100): + simulator.simulate_timestep(0.1) + + # Check for emergent patterns + if t % 10 == 0: + patterns = simulator.detect_emergence() + if patterns: + print(f"Timestep {t}: Detected {len(patterns)} emergent patterns") + for i, pattern in enumerate(patterns): + print(f" Pattern {i + 1}:") + print(f" Stories: {', '.join(pattern['stories'])}") + print(f" Coherence: {pattern['coherence']:.2f}") + print(f" Field Strength: {pattern['field_strength']:.2f}") + else: + print(f"Timestep {t}: No emergent patterns detected") + + # Analyze pattern effects on field + field_energy = torch.norm(simulator.field_state) + print(f"Field energy: {field_energy:.2f}") + + print(f"Number of active stories: {len(simulator.stories)}") From 26cd6e7aa2e4afe0172485c2a36972b44a3b9963 Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 06:56:09 +0100 Subject: [PATCH 02/15] Key changes: In NarrativeWave, we now use view(1) to ensure that amplitude, phase, and coherence are 1D tensors with a single element. In create_wave_function, we initialize amplitude, phase, and coherence as 1D tensors. In apply_field_effects, we use torch.exp and torch.tensor to ensure all operations are performed on tensors. --- src/nfs_story_waves.py | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index fed3d35..a941fa1 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -16,14 +16,17 @@ class NarrativeWave: content: str embedding: torch.Tensor # Semantic embedding as quantum state - amplitude: float # Story strength/influence - phase: float # Story's phase in narrative space - coherence: float # Measure of story stability + amplitude: torch.Tensor # Story strength/influence + phase: torch.Tensor # Story's phase in narrative space + coherence: torch.Tensor # Measure of story stability entanglement: Dict[str, float] # Connections to other stories def __post_init__(self): assert self.embedding.dim() == 1, f"Embedding must be 1D, got shape {self.embedding.shape}" assert self.embedding.shape[0] == 768, f"Embedding must have 768 elements, got {self.embedding.shape[0]}" + self.amplitude = torch.tensor(self.amplitude, dtype=torch.float32).view(1) + self.phase = torch.tensor(self.phase, dtype=torch.float32).view(1) + self.coherence = torch.tensor(self.coherence, dtype=torch.float32).view(1) class NarrativeFieldSimulator: @@ -46,9 +49,9 @@ def create_wave_function(self, content: str) -> NarrativeWave: return NarrativeWave( content=content, embedding=embedding, # Now guaranteed to be 1D - amplitude=1.0, - phase=np.random.random() * 2 * np.pi, - coherence=1.0, + amplitude=torch.tensor([1.0]), + phase=torch.tensor([np.random.random() * 2 * np.pi]), + coherence=torch.tensor([1.0]), entanglement={}, ) @@ -56,39 +59,43 @@ def quantum_interference(self, wave1: NarrativeWave, wave2: NarrativeWave) -> fl """Calculate interference between two narrative waves""" # Compute quantum interference using cosine similarity and phase similarity = torch.cosine_similarity(wave1.embedding.unsqueeze(0), wave2.embedding.unsqueeze(0)) - phase_factor = np.cos(wave1.phase - wave2.phase) + phase_factor = torch.cos(torch.tensor(wave1.phase - wave2.phase)) return float(similarity * phase_factor) def apply_field_effects(self, wave: NarrativeWave, dt: float): """Apply quantum field effects to a narrative wave""" # Simulate quantum evolution wave.phase += dt * wave.amplitude - wave.coherence *= np.exp(-dt / 10.0) # Gradual decoherence + wave.coherence *= torch.exp(torch.tensor(-dt / 10.0)) # Gradual decoherence # Apply field interactions field_interaction = torch.cosine_similarity( - wave.embedding, self.field_state.unsqueeze(0) + wave.embedding.unsqueeze(0), self.field_state.unsqueeze(0) ) wave.amplitude *= 1.0 + field_interaction * dt def update_field_state(self): """Update the overall field state based on all stories with non-linear effects""" - new_field = torch.zeros(self.quantum_dim, requires_grad=True) + contributions = torch.zeros(self.quantum_dim, dtype=torch.complex64) for story in self.stories.values(): - # Combine wave functions with phase and amplitude - contribution = story.embedding * story.amplitude * torch.exp(1j * story.phase) - new_field += contribution.real + # Convert phase to tensor and combine wave functions with phase and amplitude + phase_tensor = torch.tensor(story.phase, dtype=torch.float32) + phase_factor = torch.complex(torch.cos(phase_tensor), torch.sin(phase_tensor)) + contribution = story.embedding * story.amplitude * phase_factor + contributions += contribution + + new_field = contributions.requires_grad_() # Apply non-linear transformation - field_potential = torch.tanh(new_field) + field_potential = torch.tanh(new_field.real) # Calculate field gradient field_gradient = torch.autograd.grad(field_potential.sum(), new_field, create_graph=True)[0] # Combine linear and non-linear effects alpha = 0.7 # Adjustable parameter for balance between linear and non-linear effects - self.field_state = alpha * new_field + (1 - alpha) * field_gradient + self.field_state = alpha * new_field.real + (1 - alpha) * field_gradient.real # Normalize field state self.field_state = self.field_state / torch.norm(self.field_state) From 6fe23af5736296795fd4e49ade53b6746a70e12a Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 07:02:58 +0100 Subject: [PATCH 03/15] a summary of the modifications: 1. In NarrativeWave.__post_init__, we now use .clone().detach() instead of torch.tensor() to create new tensors from existing ones. In apply_environmental_effects, we convert the environment_coupling to a tensor to ensure compatibility with PyTorch operations. In create_wave_function, we explicitly create tensors for amplitude, phase, and coherence to ensure they're of the correct type from the start. --- src/nfs_story_waves.py | 124 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 14 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index a941fa1..df38415 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -1,8 +1,8 @@ import numpy as np -from dataclasses import dataclass +from dataclasses import dataclass, field import torch import torch.autograd -from typing import List, Dict, Tuple +from typing import List, Dict, Any from transformers import AutoTokenizer, AutoModel import logging @@ -20,13 +20,50 @@ class NarrativeWave: phase: torch.Tensor # Story's phase in narrative space coherence: torch.Tensor # Measure of story stability entanglement: Dict[str, float] # Connections to other stories + uncertainty: torch.Tensor = field(init=False) def __post_init__(self): assert self.embedding.dim() == 1, f"Embedding must be 1D, got shape {self.embedding.shape}" assert self.embedding.shape[0] == 768, f"Embedding must have 768 elements, got {self.embedding.shape[0]}" - self.amplitude = torch.tensor(self.amplitude, dtype=torch.float32).view(1) - self.phase = torch.tensor(self.phase, dtype=torch.float32).view(1) - self.coherence = torch.tensor(self.coherence, dtype=torch.float32).view(1) + self.amplitude = self.amplitude.clone().detach().view(1) + self.phase = self.phase.clone().detach().view(1) + self.coherence = self.coherence.clone().detach().view(1) + self.uncertainty = torch.tensor(np.random.random(), dtype=torch.float32).view(1) + + +class PatternMemory: + def __init__(self): + self.patterns = [] + self.pattern_strengths = torch.tensor([]) + + def update_patterns(self, new_pattern, field_state): + """Track and evolve observed patterns""" + pattern_embedding = self.encode_pattern(new_pattern) + + if len(self.patterns) > 0: + similarities = torch.cosine_similarity( + pattern_embedding.unsqueeze(0), + torch.stack(self.patterns) + ) + + if torch.any(similarities > 0.9): + idx = torch.argmax(similarities) + self.patterns[idx] = 0.9 * self.patterns[idx] + 0.1 * pattern_embedding + else: + self.patterns.append(pattern_embedding) + else: + self.patterns.append(pattern_embedding) + + # Update pattern strengths based on field state + self.pattern_strengths = torch.tensor([ + torch.cosine_similarity(p.unsqueeze(0), field_state.unsqueeze(0)) + for p in self.patterns + ]) + + def encode_pattern(self, pattern: Dict) -> torch.Tensor: + # Implement pattern encoding logic here + # This is a placeholder implementation + return torch.randn(768) # Same dimension as story embeddings class NarrativeFieldSimulator: @@ -37,6 +74,9 @@ def __init__(self): self.quantum_dim = 768 # Embedding dimension self.stories: Dict[str, NarrativeWave] = {} self.field_state = torch.zeros(self.quantum_dim) + self.total_energy = 1.0 # System's total energy + self.energy_threshold = 2.0 # Maximum allowed energy + self.pattern_memory = PatternMemory() def create_wave_function(self, content: str) -> NarrativeWave: """Convert story to quantum wave function""" @@ -48,19 +88,27 @@ def create_wave_function(self, content: str) -> NarrativeWave: # Initialize quantum properties return NarrativeWave( content=content, - embedding=embedding, # Now guaranteed to be 1D - amplitude=torch.tensor([1.0]), - phase=torch.tensor([np.random.random() * 2 * np.pi]), - coherence=torch.tensor([1.0]), + embedding=embedding, + amplitude=torch.tensor([1.0], dtype=torch.float32), + phase=torch.tensor([np.random.random() * 2 * np.pi], dtype=torch.float32), + coherence=torch.tensor([1.0], dtype=torch.float32), entanglement={}, ) def quantum_interference(self, wave1: NarrativeWave, wave2: NarrativeWave) -> float: - """Calculate interference between two narrative waves""" - # Compute quantum interference using cosine similarity and phase - similarity = torch.cosine_similarity(wave1.embedding.unsqueeze(0), wave2.embedding.unsqueeze(0)) - phase_factor = torch.cos(torch.tensor(wave1.phase - wave2.phase)) - return float(similarity * phase_factor) + """Enhanced quantum interference with uncertainty""" + position_uncertainty = torch.std(wave1.embedding) + momentum_uncertainty = torch.std(wave2.embedding) + uncertainty_factor = 1.0 / (position_uncertainty * momentum_uncertainty) + + semantic_distance = torch.norm(wave1.embedding - wave2.embedding) + tunnel_probability = torch.exp(-semantic_distance) + + similarity = torch.cosine_similarity(wave1.embedding.unsqueeze(0), + wave2.embedding.unsqueeze(0)) + phase_factor = torch.cos(wave1.phase - wave2.phase) + + return float(similarity * phase_factor * uncertainty_factor * tunnel_probability) def apply_field_effects(self, wave: NarrativeWave, dt: float): """Apply quantum field effects to a narrative wave""" @@ -74,6 +122,32 @@ def apply_field_effects(self, wave: NarrativeWave, dt: float): ) wave.amplitude *= 1.0 + field_interaction * dt + # Apply environmental effects + env_embedding, vacuum_fluctuation = self.apply_environmental_effects(wave, dt) + wave.embedding = 0.9 * wave.embedding + 0.1 * env_embedding + self.field_state += vacuum_fluctuation + + def apply_environmental_effects(self, wave: NarrativeWave, dt: float): + """Simulate interaction with environment""" + noise = torch.randn_like(wave.embedding) * 0.01 + + environment_coupling = torch.tensor(0.1, dtype=torch.float32) + wave.coherence *= torch.exp(-environment_coupling * dt) + + vacuum_energy = 0.01 + vacuum_fluctuation = torch.randn_like(self.field_state) * vacuum_energy + + return wave.embedding + noise, vacuum_fluctuation + + def enforce_energy_conservation(self): + """Enforce energy conservation in the field""" + current_energy = torch.norm(self.field_state) + if current_energy > self.energy_threshold: + self.field_state = self.field_state * (self.total_energy / current_energy) + scale_factor = torch.sqrt(self.total_energy / current_energy) + for story in self.stories.values(): + story.amplitude *= scale_factor + def update_field_state(self): """Update the overall field state based on all stories with non-linear effects""" contributions = torch.zeros(self.quantum_dim, dtype=torch.complex64) @@ -129,6 +203,20 @@ def detect_emergence(self) -> List[Dict]: patterns.append(pattern) logger.debug(f"Found pattern: {pattern}") + # Consider pattern memory in emergence detection + for i, pattern_embedding in enumerate(self.pattern_memory.patterns): + similarity = torch.cosine_similarity( + pattern_embedding.unsqueeze(0), + embeddings + ) + if torch.any(similarity > threshold): + pattern = { + "stories": [story_keys[j] for j in (similarity > threshold).nonzero().squeeze(1)], + "coherence": float(similarity[similarity > threshold].mean()), + "field_strength": float(self.pattern_memory.pattern_strengths[i]), + } + patterns.append(pattern) + logger.debug(f"Detected {len(patterns)} patterns") return patterns @@ -160,6 +248,14 @@ def simulate_timestep(self, dt: float): # Remove fully decohered stories self.stories = {k: v for k, v in self.stories.items() if v.coherence > 0.1} + # Enforce energy conservation + self.enforce_energy_conservation() + + # Update pattern memory + patterns = self.detect_emergence() + for pattern in patterns: + self.pattern_memory.update_patterns(pattern, self.field_state) + # Example usage simulator = NarrativeFieldSimulator() From 928e11249768830647c9f5bfd3f2364afe4db6ef Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 07:08:20 +0100 Subject: [PATCH 04/15] Explanation of changes: Added type hints to improve code readability and maintainability, following PEP 484. Enhanced the update_patterns method: Improved temporal dynamics by introducing a decay rate for pattern strengths. Added a pattern history to track the temporal evolution of patterns. Implemented a more sophisticated pattern merging algorithm that considers the age of patterns. Improved the encode_pattern method: Added semantic structure to the pattern encoding by combining story embeddings. Introduced modulation based on pattern metadata (coherence and field strength). Ensured the returned embedding is normalized. Added comments to explain the purpose and functionality of each section. These changes align with the project's focus on complex systems theory, cognitive science, and machine learning. The enhanced PatternMemory class now better captures the temporal dynamics of patterns in the narrative field and provides a more sophisticated encoding mechanism. --- src/nfs_story_waves.py | 80 ++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index df38415..819640f 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -32,13 +32,20 @@ def __post_init__(self): class PatternMemory: - def __init__(self): - self.patterns = [] - self.pattern_strengths = torch.tensor([]) - - def update_patterns(self, new_pattern, field_state): - """Track and evolve observed patterns""" + def __init__(self, story_dict: Dict[str, NarrativeWave]): + self.patterns: List[torch.Tensor] = [] + self.pattern_strengths: torch.Tensor = torch.tensor([]) + self.pattern_history: List[Dict[str, Any]] = [] # Track temporal evolution + self.decay_rate: float = 0.95 # Pattern memory decay + self.story_dict: Dict[str, NarrativeWave] = story_dict + + def update_patterns(self, new_pattern: Dict[str, Any], field_state: torch.Tensor) -> None: + """Enhanced pattern tracking with temporal dynamics""" pattern_embedding = self.encode_pattern(new_pattern) + pattern_time = len(self.pattern_history) + + # Apply temporal decay to existing patterns + self.pattern_strengths *= self.decay_rate if len(self.patterns) > 0: similarities = torch.cosine_similarity( @@ -46,24 +53,60 @@ def update_patterns(self, new_pattern, field_state): torch.stack(self.patterns) ) + # Enhanced pattern merging with temporal weighting if torch.any(similarities > 0.9): idx = torch.argmax(similarities) - self.patterns[idx] = 0.9 * self.patterns[idx] + 0.1 * pattern_embedding + age_factor = torch.exp(torch.tensor(-0.1 * (pattern_time - len(self.pattern_history)))) + self.patterns[idx] = (age_factor * self.patterns[idx] + + (1 - age_factor) * pattern_embedding) + self.pattern_strengths[idx] += 1.0 - age_factor else: self.patterns.append(pattern_embedding) + self.pattern_strengths = torch.cat([ + self.pattern_strengths, + torch.tensor([1.0]) + ]) else: self.patterns.append(pattern_embedding) + self.pattern_strengths = torch.tensor([1.0]) - # Update pattern strengths based on field state - self.pattern_strengths = torch.tensor([ - torch.cosine_similarity(p.unsqueeze(0), field_state.unsqueeze(0)) - for p in self.patterns - ]) - - def encode_pattern(self, pattern: Dict) -> torch.Tensor: - # Implement pattern encoding logic here - # This is a placeholder implementation - return torch.randn(768) # Same dimension as story embeddings + # Update temporal history + self.pattern_history.append({ + 'time': pattern_time, + 'embedding': pattern_embedding, + 'field_state': field_state.clone() + }) + + # Prune old patterns below strength threshold + mask = self.pattern_strengths > 0.1 + self.patterns = [p for p, m in zip(self.patterns, mask) if m] + self.pattern_strengths = self.pattern_strengths[mask] + + def encode_pattern(self, pattern: Dict[str, Any]) -> torch.Tensor: + """Enhanced pattern encoding with semantic structure""" + # Extract story embeddings + story_embeddings = [] + for story_id in pattern['stories']: + if story_id in self.story_dict: + story_embeddings.append(self.story_dict[story_id].embedding) + else: + logger.warning(f"Story {story_id} not found in story_dict") + + if not story_embeddings: + logger.warning("No valid story embeddings found for pattern") + return torch.zeros(768) + + # Combine embeddings weighted by coherence + combined = torch.stack(story_embeddings).mean(dim=0) + + # Add pattern metadata as modulation + coherence_factor = torch.tensor(pattern['coherence'], dtype=torch.float32) + strength_factor = torch.tensor(pattern['field_strength'], dtype=torch.float32) + + # Modulate combined embedding + modulated = combined * coherence_factor * strength_factor + + return torch.nn.functional.normalize(modulated, dim=0) class NarrativeFieldSimulator: @@ -76,7 +119,7 @@ def __init__(self): self.field_state = torch.zeros(self.quantum_dim) self.total_energy = 1.0 # System's total energy self.energy_threshold = 2.0 # Maximum allowed energy - self.pattern_memory = PatternMemory() + self.pattern_memory = PatternMemory(self.stories) def create_wave_function(self, content: str) -> NarrativeWave: """Convert story to quantum wave function""" @@ -293,3 +336,4 @@ def simulate_timestep(self, dt: float): print(f"Field energy: {field_energy:.2f}") print(f"Number of active stories: {len(simulator.stories)}") + From 7a5e3cfbec0414402a1ee8af14044fe5a4989081 Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 07:09:33 +0100 Subject: [PATCH 05/15] Explanation of the updates: We introduce a processed_stories set to keep track of stories that have already been included in a pattern. In the first loop, we skip stories that have already been processed to avoid redundant patterns. After adding a pattern, we update the processed_stories set with all the stories in that pattern. In the pattern memory section, we only consider stories that haven't been processed yet. We create a new pattern only if there are new stories to add. 5. We update the processed_stories set after adding a pattern from the pattern memory as well. These changes should significantly reduce redundancy in the detected patterns by ensuring that each story is only included in one pattern during a single detection cycle. This approach favors larger, more comprehensive patterns over smaller, overlapping ones. --- src/nfs_story_waves.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index 819640f..a262dbb 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -233,11 +233,17 @@ def detect_emergence(self) -> List[Dict]: ) threshold = 0.8 + processed_stories = set() + for i in range(len(similarity_matrix)): + if story_keys[i] in processed_stories: + continue + connected = (similarity_matrix[i] > threshold).nonzero().squeeze(1) if len(connected) > 2: + pattern_stories = [story_keys[j.item()] for j in connected if j.item() < len(story_keys)] pattern = { - "stories": [story_keys[j.item()] for j in connected if j.item() < len(story_keys)], + "stories": pattern_stories, "coherence": float(similarity_matrix[i, connected].mean()), "field_strength": float( self.stories[story_keys[i]].amplitude @@ -245,6 +251,7 @@ def detect_emergence(self) -> List[Dict]: } patterns.append(pattern) logger.debug(f"Found pattern: {pattern}") + processed_stories.update(pattern_stories) # Consider pattern memory in emergence detection for i, pattern_embedding in enumerate(self.pattern_memory.patterns): @@ -253,12 +260,16 @@ def detect_emergence(self) -> List[Dict]: embeddings ) if torch.any(similarity > threshold): - pattern = { - "stories": [story_keys[j] for j in (similarity > threshold).nonzero().squeeze(1)], - "coherence": float(similarity[similarity > threshold].mean()), - "field_strength": float(self.pattern_memory.pattern_strengths[i]), - } - patterns.append(pattern) + pattern_stories = [story_keys[j] for j in (similarity > threshold).nonzero().squeeze(1)] + new_stories = [story for story in pattern_stories if story not in processed_stories] + if new_stories: + pattern = { + "stories": new_stories, + "coherence": float(similarity[similarity > threshold].mean()), + "field_strength": float(self.pattern_memory.pattern_strengths[i]), + } + patterns.append(pattern) + processed_stories.update(new_stories) logger.debug(f"Detected {len(patterns)} patterns") return patterns From a5c753b1052e4ec1e47491a92593f5490153680a Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 07:11:53 +0100 Subject: [PATCH 06/15] These changes ensure that the PatternMemory class has access to the story embeddings and can create meaningful pattern encodings. The encode_pattern method now uses actual story data to generate pattern representations, which should improve the overall simulation quality and pattern detection capabilities. --- src/nfs_story_waves.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index a262dbb..7a15b04 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -121,15 +121,15 @@ def __init__(self): self.energy_threshold = 2.0 # Maximum allowed energy self.pattern_memory = PatternMemory(self.stories) - def create_wave_function(self, content: str) -> NarrativeWave: - """Convert story to quantum wave function""" + def create_wave_function(self, content: str, story_id: str) -> NarrativeWave: + """Convert story to quantum wave function and add to stories dict""" # Create semantic embedding tokens = self.tokenizer(content, return_tensors="pt", padding=True, truncation=True, max_length=512) with torch.no_grad(): embedding = self.encoder(**tokens).last_hidden_state.mean(dim=1).squeeze(0) # Initialize quantum properties - return NarrativeWave( + wave = NarrativeWave( content=content, embedding=embedding, amplitude=torch.tensor([1.0], dtype=torch.float32), @@ -137,6 +137,8 @@ def create_wave_function(self, content: str) -> NarrativeWave: coherence=torch.tensor([1.0], dtype=torch.float32), entanglement={}, ) + self.stories[story_id] = wave + return wave def quantum_interference(self, wave1: NarrativeWave, wave2: NarrativeWave) -> float: """Enhanced quantum interference with uncertainty""" @@ -322,8 +324,8 @@ def simulate_timestep(self, dt: float): ] for i, content in enumerate(stories): - wave = simulator.create_wave_function(content) - simulator.stories[f"story_{i}"] = wave + story_id = f"story_{i}" + simulator.create_wave_function(content, story_id) # Run simulation for t in range(100): @@ -347,4 +349,3 @@ def simulate_timestep(self, dt: float): print(f"Field energy: {field_energy:.2f}") print(f"Number of active stories: {len(simulator.stories)}") - From b8f30c4a7ec1833fba67354018d240dbcee81f58 Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 07:15:19 +0100 Subject: [PATCH 07/15] These changes introduce the following improvements: Enhanced Pattern Detection: The detect_emergence method now uses a geometric approach with centers and radii to better identify unique patterns. It calculates the center and radius for each potential pattern and includes all stories within a slightly expanded radius. Sophisticated Quantum Interference: The quantum_interference method now includes more complex interactions between stories, considering coherence coupling, uncertainty principles, quantum tunneling, and entanglement effects. Pattern Evolution Tracking: A new PatternEvolution class has been added to track pattern lifecycles. It maintains trajectories of patterns over time, matching current patterns with existing trajectories or creating new ones as needed. 4. Integration with Simulation: The simulate_timestep method now updates the pattern evolution after detecting emergent patterns in each timestep. These enhancements should provide a more nuanced and realistic simulation of narrative field dynamics, with improved pattern detection and tracking over time. The quantum interference calculations now capture a wider range of quantum effects, potentially leading to more interesting and complex story interactions. --- src/nfs_story_waves.py | 167 ++++++++++++++++++++++++++++------------- 1 file changed, 116 insertions(+), 51 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index 7a15b04..5bc4e9c 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -2,9 +2,10 @@ from dataclasses import dataclass, field import torch import torch.autograd -from typing import List, Dict, Any +from typing import List, Dict, Any, Set from transformers import AutoTokenizer, AutoModel import logging +import torch.nn.functional as F logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) @@ -109,6 +110,59 @@ def encode_pattern(self, pattern: Dict[str, Any]) -> torch.Tensor: return torch.nn.functional.normalize(modulated, dim=0) +class PatternEvolution: + def __init__(self): + self.pattern_trajectories: Dict[int, List[Dict]] = {} + self.next_pattern_id = 0 + + def update(self, current_patterns: List[Dict], field_state: torch.Tensor): + new_trajectories = {} + + for pattern in current_patterns: + best_match = None + best_match_score = 0.8 # Minimum similarity threshold + + for pattern_id, trajectory in self.pattern_trajectories.items(): + if trajectory[-1]["active"]: # Only consider active trajectories + similarity = self.calculate_pattern_similarity( + pattern, trajectory[-1]["pattern"] + ) + if similarity > best_match_score: + best_match = pattern_id + best_match_score = similarity + + if best_match is not None: + # Continue existing trajectory + self.pattern_trajectories[best_match].append({ + "pattern": pattern, + "time": len(self.pattern_trajectories[best_match]), + "field_state": field_state, + "active": True + }) + new_trajectories[best_match] = True + else: + # Start new trajectory + self.pattern_trajectories[self.next_pattern_id] = [{ + "pattern": pattern, + "time": 0, + "field_state": field_state, + "active": True + }] + new_trajectories[self.next_pattern_id] = True + self.next_pattern_id += 1 + + # Mark unmatched trajectories as inactive + for pattern_id in self.pattern_trajectories: + if pattern_id not in new_trajectories: + self.pattern_trajectories[pattern_id][-1]["active"] = False + + def calculate_pattern_similarity(self, pattern1: Dict, pattern2: Dict) -> float: + # Implement similarity calculation between patterns + # This is a placeholder implementation + return F.cosine_similarity(pattern1["center"].unsqueeze(0), + pattern2["center"].unsqueeze(0)).item() + + class NarrativeFieldSimulator: def __init__(self): # Initialize quantum semantic space @@ -120,6 +174,7 @@ def __init__(self): self.total_energy = 1.0 # System's total energy self.energy_threshold = 2.0 # Maximum allowed energy self.pattern_memory = PatternMemory(self.stories) + self.pattern_evolution = PatternEvolution() def create_wave_function(self, content: str, story_id: str) -> NarrativeWave: """Convert story to quantum wave function and add to stories dict""" @@ -141,19 +196,34 @@ def create_wave_function(self, content: str, story_id: str) -> NarrativeWave: return wave def quantum_interference(self, wave1: NarrativeWave, wave2: NarrativeWave) -> float: - """Enhanced quantum interference with uncertainty""" + """More sophisticated quantum interference calculation""" + similarity = torch.cosine_similarity(wave1.embedding.unsqueeze(0), + wave2.embedding.unsqueeze(0)) + phase_factor = torch.cos(wave1.phase - wave2.phase) + + coherence_coupling = wave1.coherence * wave2.coherence + position_uncertainty = torch.std(wave1.embedding) momentum_uncertainty = torch.std(wave2.embedding) uncertainty_factor = 1.0 / (position_uncertainty * momentum_uncertainty) semantic_distance = torch.norm(wave1.embedding - wave2.embedding) - tunnel_probability = torch.exp(-semantic_distance) + barrier_height = 1.0 / (wave1.amplitude * wave2.amplitude) + tunnel_probability = torch.exp(-semantic_distance * barrier_height) - similarity = torch.cosine_similarity(wave1.embedding.unsqueeze(0), - wave2.embedding.unsqueeze(0)) - phase_factor = torch.cos(wave1.phase - wave2.phase) + entanglement_strength = torch.tensor( + sum(set(wave1.entanglement.values()) & + set(wave2.entanglement.values())) + ) - return float(similarity * phase_factor * uncertainty_factor * tunnel_probability) + return float( + similarity * + phase_factor * + coherence_coupling * + uncertainty_factor * + tunnel_probability * + (1 + entanglement_strength) + ) def apply_field_effects(self, wave: NarrativeWave, dt: float): """Apply quantum field effects to a narrative wave""" @@ -220,13 +290,10 @@ def update_field_state(self): self.field_state = self.field_state / torch.norm(self.field_state) def detect_emergence(self) -> List[Dict]: - """Detect emergent patterns in the narrative field""" - logger.debug(f"Detecting emergence with {len(self.stories)} stories") + """Enhanced pattern detection with better uniqueness handling""" patterns = [] - if len(self.stories) < 3: - logger.debug("Not enough stories for meaningful patterns") - return patterns - + processed_pairs: Set[Tuple[int, int]] = set() + story_keys = list(self.stories.keys()) embeddings = torch.stack([self.stories[key].embedding for key in story_keys]) @@ -235,45 +302,40 @@ def detect_emergence(self) -> List[Dict]: ) threshold = 0.8 - processed_stories = set() - + for i in range(len(similarity_matrix)): - if story_keys[i] in processed_stories: - continue - - connected = (similarity_matrix[i] > threshold).nonzero().squeeze(1) - if len(connected) > 2: - pattern_stories = [story_keys[j.item()] for j in connected if j.item() < len(story_keys)] - pattern = { - "stories": pattern_stories, - "coherence": float(similarity_matrix[i, connected].mean()), - "field_strength": float( - self.stories[story_keys[i]].amplitude - ), - } - patterns.append(pattern) - logger.debug(f"Found pattern: {pattern}") - processed_stories.update(pattern_stories) - - # Consider pattern memory in emergence detection - for i, pattern_embedding in enumerate(self.pattern_memory.patterns): - similarity = torch.cosine_similarity( - pattern_embedding.unsqueeze(0), - embeddings - ) - if torch.any(similarity > threshold): - pattern_stories = [story_keys[j] for j in (similarity > threshold).nonzero().squeeze(1)] - new_stories = [story for story in pattern_stories if story not in processed_stories] - if new_stories: - pattern = { - "stories": new_stories, - "coherence": float(similarity[similarity > threshold].mean()), - "field_strength": float(self.pattern_memory.pattern_strengths[i]), - } - patterns.append(pattern) - processed_stories.update(new_stories) - - logger.debug(f"Detected {len(patterns)} patterns") + for j in range(i + 1, len(similarity_matrix)): + if (i, j) in processed_pairs: + continue + + similarity = similarity_matrix[i, j] + if similarity > threshold: + center = (embeddings[i] + embeddings[j]) / 2 + radius = torch.norm(embeddings[i] - embeddings[j]) + + distances = torch.norm(embeddings - center.unsqueeze(0), dim=1) + members = (distances <= radius * 1.2).nonzero().squeeze(1) + + if len(members) >= 2: + pattern = { + "stories": [story_keys[k.item()] for k in members], + "coherence": float(similarity), + "field_strength": float( + torch.mean(torch.stack([ + self.stories[story_keys[k.item()]].amplitude + for k in members + ])) + ), + "center": center, + "radius": radius + } + patterns.append(pattern) + + for k1 in members: + for k2 in members: + if k1 < k2: + processed_pairs.add((k1.item(), k2.item())) + return patterns def simulate_timestep(self, dt: float): @@ -312,6 +374,9 @@ def simulate_timestep(self, dt: float): for pattern in patterns: self.pattern_memory.update_patterns(pattern, self.field_state) + # Update pattern evolution + self.pattern_evolution.update(patterns, self.field_state) + # Example usage simulator = NarrativeFieldSimulator() From 21e711df37f50da920250a317f7f8b449c70ad5a Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 07:20:15 +0100 Subject: [PATCH 08/15] These changes introduce the following improvements: Enhanced Phase Space Analysis: The PhaseSpaceTracker class is added to record and analyze the system's evolution in phase space. It tracks the field state and pattern properties over time and provides methods to analyze attractor properties. Pattern Interaction Dynamics: The calculate_pattern_interaction method is added to compute interactions between patterns based on their spatial overlap, phase relationship, and field interaction. This information is used in the simulate_timestep method to modify pattern evolution. Environmental Coupling: The EnvironmentalCoupling class is introduced to generate temporally correlated (colored) noise, providing a more realistic simulation of environmental effects. This is integrated into the apply_environmental_effects method. These enhancements allow for a more sophisticated analysis of the system's behavior, including oscillatory patterns and attractor properties. The pattern interactions are now more dynamic, and the environmental effects are more realistic with temporally correlated noise. To fully integrate these changes, you'll need to update the simulate_timestep method to use the new pattern interaction calculations and modify the pattern evolution accordingly. You may also want to add logging or visualization of the phase space trajectory and attractor properties for a better understanding of the system's behavior. --- src/nfs_story_waves.py | 115 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 6 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index 5bc4e9c..6aeb9bf 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -6,6 +6,7 @@ from transformers import AutoTokenizer, AutoModel import logging import torch.nn.functional as F +import torch.fft logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) @@ -163,6 +164,67 @@ def calculate_pattern_similarity(self, pattern1: Dict, pattern2: Dict) -> float: pattern2["center"].unsqueeze(0)).item() +class PhaseSpaceTracker: + """Track system evolution in phase space""" + def __init__(self, dim: int): + self.trajectory = [] + self.phase_space_dim = dim + + def record_state(self, field_state: torch.Tensor, patterns: List[Dict]): + """Record current state in phase space""" + state_vector = { + 'field': field_state.clone(), + 'pattern_coherence': torch.tensor([p['coherence'] for p in patterns]), + 'pattern_strength': torch.tensor([p['field_strength'] for p in patterns]), + 'pattern_radius': torch.tensor([p['radius'] for p in patterns]) + } + self.trajectory.append(state_vector) + + def analyze_attractor(self) -> Dict: + """Analyze attractor properties in phase space""" + if len(self.trajectory) < 10: + return {} + + recent_states = self.trajectory[-10:] + + field_variance = torch.var(torch.stack([s['field'] for s in recent_states])) + strength_variance = torch.var(torch.stack([s['pattern_strength'] for s in recent_states])) + + strength_series = torch.stack([s['pattern_strength'] for s in recent_states]) + fft = torch.fft.fft(strength_series) + frequencies = torch.fft.fftfreq(len(strength_series)) + + return { + 'field_stability': float(1.0 / (1.0 + field_variance)), + 'strength_stability': float(1.0 / (1.0 + strength_variance)), + 'dominant_frequency': float(frequencies[torch.argmax(torch.abs(fft))]) + } + + +class EnvironmentalCoupling: + """Handle system-environment interactions""" + def __init__(self, temperature: float = 0.1): + self.temperature = torch.tensor(temperature, dtype=torch.float32) + self.noise_history = [] + self.correlation_time = torch.tensor(10, dtype=torch.float32) + + def generate_colored_noise(self, shape: tuple) -> torch.Tensor: + """Generate temporally correlated noise""" + white_noise = torch.randn(shape) + if not self.noise_history: + self.noise_history = [white_noise] + return white_noise + + alpha = torch.exp(-1.0 / self.correlation_time) + colored_noise = alpha * self.noise_history[-1] + torch.sqrt(1 - alpha**2) * white_noise + + self.noise_history.append(colored_noise) + if len(self.noise_history) > self.correlation_time.item(): + self.noise_history.pop(0) + + return colored_noise * self.temperature + + class NarrativeFieldSimulator: def __init__(self): # Initialize quantum semantic space @@ -175,6 +237,8 @@ def __init__(self): self.energy_threshold = 2.0 # Maximum allowed energy self.pattern_memory = PatternMemory(self.stories) self.pattern_evolution = PatternEvolution() + self.phase_space_tracker = PhaseSpaceTracker(self.quantum_dim) + self.environmental_coupling = EnvironmentalCoupling() def create_wave_function(self, content: str, story_id: str) -> NarrativeWave: """Convert story to quantum wave function and add to stories dict""" @@ -243,16 +307,16 @@ def apply_field_effects(self, wave: NarrativeWave, dt: float): self.field_state += vacuum_fluctuation def apply_environmental_effects(self, wave: NarrativeWave, dt: float): - """Simulate interaction with environment""" - noise = torch.randn_like(wave.embedding) * 0.01 + """Simulate interaction with environment using colored noise""" + colored_noise = self.environmental_coupling.generate_colored_noise(wave.embedding.shape) environment_coupling = torch.tensor(0.1, dtype=torch.float32) - wave.coherence *= torch.exp(-environment_coupling * dt) + wave.coherence *= torch.exp(-environment_coupling * torch.tensor(dt, dtype=torch.float32)) - vacuum_energy = 0.01 - vacuum_fluctuation = torch.randn_like(self.field_state) * vacuum_energy + vacuum_energy = torch.tensor(0.01, dtype=torch.float32) + vacuum_fluctuation = colored_noise * vacuum_energy - return wave.embedding + noise, vacuum_fluctuation + return wave.embedding + colored_noise, vacuum_fluctuation def enforce_energy_conservation(self): """Enforce energy conservation in the field""" @@ -338,6 +402,27 @@ def detect_emergence(self) -> List[Dict]: return patterns + def calculate_pattern_interaction(self, pattern1: Dict, pattern2: Dict) -> Dict: + """Calculate interaction between patterns""" + distance = torch.norm(pattern1['center'] - pattern2['center']) + overlap = torch.max(torch.zeros(1), + (pattern1['radius'] + pattern2['radius'] - distance) / + (pattern1['radius'] + pattern2['radius'])) + + phase_coherence = torch.cos(pattern1['phase'] - pattern2['phase']) + + field_interaction = torch.cosine_similarity( + pattern1['center'].unsqueeze(0), + pattern2['center'].unsqueeze(0) + ) + + return { + 'overlap': float(overlap), + 'phase_coherence': float(phase_coherence), + 'field_interaction': float(field_interaction), + 'interaction_strength': float(overlap * phase_coherence * field_interaction) + } + def simulate_timestep(self, dt: float): """Simulate one timestep of field evolution""" # Update all wave functions @@ -377,6 +462,23 @@ def simulate_timestep(self, dt: float): # Update pattern evolution self.pattern_evolution.update(patterns, self.field_state) + # Record state in phase space + self.phase_space_tracker.record_state(self.field_state, patterns) + + # Analyze pattern interactions + for i, pattern1 in enumerate(patterns): + for j, pattern2 in enumerate(patterns[i+1:], start=i+1): + interaction = self.calculate_pattern_interaction(pattern1, pattern2) + # Use interaction data to modify pattern evolution + # This is a placeholder and should be implemented based on your specific requirements + pattern1['field_strength'] *= (1 + interaction['interaction_strength'] * dt) + pattern2['field_strength'] *= (1 + interaction['interaction_strength'] * dt) + + # Analyze attractor properties periodically + if len(self.phase_space_tracker.trajectory) % 100 == 0: + attractor_properties = self.phase_space_tracker.analyze_attractor() + logger.info(f"Attractor properties: {attractor_properties}") + # Example usage simulator = NarrativeFieldSimulator() @@ -414,3 +516,4 @@ def simulate_timestep(self, dt: float): print(f"Field energy: {field_energy:.2f}") print(f"Number of active stories: {len(simulator.stories)}") + From d66f67bb5db6e4aaf5ae03ff4c1af6d12a79beee Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 07:22:43 +0100 Subject: [PATCH 09/15] . These changes implement the suggested refinements: 1. In apply_field_effects, we've added amplitude-dependent damping to better control field strength growth. The decoherence rate now depends on the wave's amplitude, and we've introduced a damping factor for amplitude evolution. The calculate_pattern_interaction method now includes stability controls. We calculate a stability factor based on the field strengths of the interacting patterns and use it to modify the interaction strength. The enforce_energy_conservation method has been enhanced with soft clamping using the tanh function and a small dissipation term. This should provide more nuanced energy conservation while maintaining interesting dynamics. These refinements should help control the field strength growth while maintaining interesting dynamics in the simulation. The amplitude-dependent damping will prevent excessive growth of individual wave amplitudes, the stability factors in pattern interactions will help manage the overall system behavior, and the enhanced energy conservation will provide a more balanced approach to maintaining the system's energy within desired bounds. --- src/nfs_story_waves.py | 60 ++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index 6aeb9bf..1e18d9d 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -290,18 +290,25 @@ def quantum_interference(self, wave1: NarrativeWave, wave2: NarrativeWave) -> fl ) def apply_field_effects(self, wave: NarrativeWave, dt: float): - """Apply quantum field effects to a narrative wave""" - # Simulate quantum evolution + """Enhanced field effects with better damping""" + # Original evolution wave.phase += dt * wave.amplitude - wave.coherence *= torch.exp(torch.tensor(-dt / 10.0)) # Gradual decoherence - - # Apply field interactions + + # Enhanced decoherence with amplitude-dependent damping + decoherence_rate = torch.tensor(-dt / 10.0) * (1.0 + 0.1 * wave.amplitude) + wave.coherence *= torch.exp(decoherence_rate) + + # Field interaction with damping field_interaction = torch.cosine_similarity( - wave.embedding.unsqueeze(0), self.field_state.unsqueeze(0) + wave.embedding.unsqueeze(0), + self.field_state.unsqueeze(0) ) - wave.amplitude *= 1.0 + field_interaction * dt + + # Damped amplitude evolution + damping_factor = torch.exp(-0.01 * wave.amplitude) # Stronger damping for higher amplitudes + wave.amplitude *= (1.0 + field_interaction * dt) * damping_factor - # Apply environmental effects + # Apply environmental effects (keep this part from the original method) env_embedding, vacuum_fluctuation = self.apply_environmental_effects(wave, dt) wave.embedding = 0.9 * wave.embedding + 0.1 * env_embedding self.field_state += vacuum_fluctuation @@ -319,13 +326,24 @@ def apply_environmental_effects(self, wave: NarrativeWave, dt: float): return wave.embedding + colored_noise, vacuum_fluctuation def enforce_energy_conservation(self): - """Enforce energy conservation in the field""" + """More sophisticated energy conservation""" current_energy = torch.norm(self.field_state) if current_energy > self.energy_threshold: - self.field_state = self.field_state * (self.total_energy / current_energy) - scale_factor = torch.sqrt(self.total_energy / current_energy) + # Calculate excess energy + excess = current_energy - self.total_energy + + # Apply soft clamping using tanh + damping = torch.tanh(excess / self.energy_threshold) + scale_factor = (self.total_energy / current_energy) * (1.0 - damping) + + # Apply scaled correction + self.field_state = self.field_state * scale_factor for story in self.stories.values(): - story.amplitude *= scale_factor + story.amplitude *= torch.sqrt(scale_factor) + + # Add small dissipation term + dissipation = 0.01 + self.field_state *= (1.0 - dissipation) def update_field_state(self): """Update the overall field state based on all stories with non-linear effects""" @@ -403,7 +421,8 @@ def detect_emergence(self) -> List[Dict]: return patterns def calculate_pattern_interaction(self, pattern1: Dict, pattern2: Dict) -> Dict: - """Calculate interaction between patterns""" + """Enhanced pattern interaction with stability controls""" + # Calculate base interaction (using existing logic) distance = torch.norm(pattern1['center'] - pattern2['center']) overlap = torch.max(torch.zeros(1), (pattern1['radius'] + pattern2['radius'] - distance) / @@ -416,12 +435,25 @@ def calculate_pattern_interaction(self, pattern1: Dict, pattern2: Dict) -> Dict: pattern2['center'].unsqueeze(0) ) - return { + base_interaction = { 'overlap': float(overlap), 'phase_coherence': float(phase_coherence), 'field_interaction': float(field_interaction), 'interaction_strength': float(overlap * phase_coherence * field_interaction) } + + # Add stability terms + stability_factor = torch.exp( + -0.1 * (pattern1['field_strength'] + pattern2['field_strength']) + ) + + # Modify interaction strength + base_interaction['interaction_strength'] *= float(stability_factor) + + # Add stability metrics + base_interaction['stability'] = float(stability_factor) + + return base_interaction def simulate_timestep(self, dt: float): """Simulate one timestep of field evolution""" From 48da70a13b7dda4e8609fe65183c4735f4862bbb Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 07:59:45 +0100 Subject: [PATCH 10/15] These changes should help create a more dynamic and realistic simulation of the narrative field. --- src/nfs_story_waves.py | 205 +++++++++++++++++++++++++++++++---------- 1 file changed, 155 insertions(+), 50 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index 1e18d9d..6640bda 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -7,6 +7,7 @@ import logging import torch.nn.functional as F import torch.fft +import random logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) @@ -174,30 +175,48 @@ def record_state(self, field_state: torch.Tensor, patterns: List[Dict]): """Record current state in phase space""" state_vector = { 'field': field_state.clone(), - 'pattern_coherence': torch.tensor([p['coherence'] for p in patterns]), - 'pattern_strength': torch.tensor([p['field_strength'] for p in patterns]), - 'pattern_radius': torch.tensor([p['radius'] for p in patterns]) + 'pattern_coherence': torch.tensor([p['coherence'] for p in patterns] if patterns else [0.0]), + 'pattern_strength': torch.tensor([p['field_strength'] for p in patterns] if patterns else [0.0]), + 'pattern_radius': torch.tensor([p['radius'] for p in patterns] if patterns else [0.0]) } self.trajectory.append(state_vector) def analyze_attractor(self) -> Dict: """Analyze attractor properties in phase space""" if len(self.trajectory) < 10: - return {} + return { + 'field_stability': 0.0, + 'strength_stability': 0.0, + 'dominant_frequency': 0.0 + } recent_states = self.trajectory[-10:] field_variance = torch.var(torch.stack([s['field'] for s in recent_states])) - strength_variance = torch.var(torch.stack([s['pattern_strength'] for s in recent_states])) - strength_series = torch.stack([s['pattern_strength'] for s in recent_states]) - fft = torch.fft.fft(strength_series) - frequencies = torch.fft.fftfreq(len(strength_series)) + # Handle case where pattern_strength might be empty + strength_tensors = [s['pattern_strength'] for s in recent_states if s['pattern_strength'].numel() > 0] + if strength_tensors: + strength_variance = torch.var(torch.cat(strength_tensors)) + strength_series = torch.cat(strength_tensors) + if strength_series.numel() > 1: + fft = torch.fft.fft(strength_series) + frequencies = torch.fft.fftfreq(len(strength_series)) + dominant_frequency = float(frequencies[torch.argmax(torch.abs(fft))]) + else: + dominant_frequency = 0.0 + else: + strength_variance = torch.tensor(0.0) + dominant_frequency = 0.0 + + # Avoid division by zero + field_stability = float(1.0 / (1.0 + field_variance)) if field_variance != 0 else 1.0 + strength_stability = float(1.0 / (1.0 + strength_variance)) if strength_variance != 0 else 1.0 return { - 'field_stability': float(1.0 / (1.0 + field_variance)), - 'strength_stability': float(1.0 / (1.0 + strength_variance)), - 'dominant_frequency': float(frequencies[torch.argmax(torch.abs(fft))]) + 'field_stability': field_stability, + 'strength_stability': strength_stability, + 'dominant_frequency': dominant_frequency } @@ -239,6 +258,7 @@ def __init__(self): self.pattern_evolution = PatternEvolution() self.phase_space_tracker = PhaseSpaceTracker(self.quantum_dim) self.environmental_coupling = EnvironmentalCoupling() + self.current_timestep = 0 def create_wave_function(self, content: str, story_id: str) -> NarrativeWave: """Convert story to quantum wave function and add to stories dict""" @@ -290,29 +310,40 @@ def quantum_interference(self, wave1: NarrativeWave, wave2: NarrativeWave) -> fl ) def apply_field_effects(self, wave: NarrativeWave, dt: float): - """Enhanced field effects with better damping""" - # Original evolution - wave.phase += dt * wave.amplitude + """Enhanced field effects with better damping and stability""" + # Phase evolution + wave.phase += dt * wave.amplitude.clamp(max=10.0) # Limit maximum phase change # Enhanced decoherence with amplitude-dependent damping - decoherence_rate = torch.tensor(-dt / 10.0) * (1.0 + 0.1 * wave.amplitude) - wave.coherence *= torch.exp(decoherence_rate) + decoherence_rate = torch.tensor(-dt / 10.0) * (1.0 + 0.1 * wave.amplitude.clamp(max=5.0)) + wave.coherence *= torch.exp(decoherence_rate).clamp(min=0.1, max=1.0) # Field interaction with damping field_interaction = torch.cosine_similarity( wave.embedding.unsqueeze(0), self.field_state.unsqueeze(0) - ) + ).clamp(min=-1.0, max=1.0) # Damped amplitude evolution - damping_factor = torch.exp(-0.01 * wave.amplitude) # Stronger damping for higher amplitudes - wave.amplitude *= (1.0 + field_interaction * dt) * damping_factor + damping_factor = torch.exp(-0.01 * wave.amplitude.clamp(max=10.0)) + amplitude_change = (1.0 + field_interaction * dt) * damping_factor + wave.amplitude *= amplitude_change.clamp(min=0.1, max=2.0) - # Apply environmental effects (keep this part from the original method) + # Apply environmental effects env_embedding, vacuum_fluctuation = self.apply_environmental_effects(wave, dt) wave.embedding = 0.9 * wave.embedding + 0.1 * env_embedding self.field_state += vacuum_fluctuation + # Ensure all tensor values are finite + wave.amplitude = torch.where(torch.isfinite(wave.amplitude), wave.amplitude, torch.tensor([1.0])) + wave.coherence = torch.where(torch.isfinite(wave.coherence), wave.coherence, torch.tensor([1.0])) + wave.embedding = torch.where(torch.isfinite(wave.embedding), wave.embedding, torch.rand_like(wave.embedding) * 1e-6) + + # More gradual coherence change + coherence_change = torch.randn(1) * 0.01 # Small random change + wave.coherence += coherence_change + wave.coherence = wave.coherence.clamp(min=0.1, max=1.0) + def apply_environmental_effects(self, wave: NarrativeWave, dt: float): """Simulate interaction with environment using colored noise""" colored_noise = self.environmental_coupling.generate_colored_noise(wave.embedding.shape) @@ -326,8 +357,17 @@ def apply_environmental_effects(self, wave: NarrativeWave, dt: float): return wave.embedding + colored_noise, vacuum_fluctuation def enforce_energy_conservation(self): - """More sophisticated energy conservation""" + """More sophisticated energy conservation with nan handling""" + if torch.isnan(self.field_state).any(): + logger.warning("NaN detected in field state. Resetting to small random values.") + self.field_state = torch.rand_like(self.field_state) * 1e-6 + current_energy = torch.norm(self.field_state) + if torch.isnan(current_energy) or current_energy == 0: + logger.warning("Invalid current energy. Resetting field state.") + self.field_state = torch.rand_like(self.field_state) * 1e-6 + current_energy = torch.norm(self.field_state) + if current_energy > self.energy_threshold: # Calculate excess energy excess = current_energy - self.total_energy @@ -346,30 +386,39 @@ def enforce_energy_conservation(self): self.field_state *= (1.0 - dissipation) def update_field_state(self): - """Update the overall field state based on all stories with non-linear effects""" + """Update the overall field state based on all stories with non-linear effects and stability controls""" contributions = torch.zeros(self.quantum_dim, dtype=torch.complex64) for story in self.stories.values(): - # Convert phase to tensor and combine wave functions with phase and amplitude - phase_tensor = torch.tensor(story.phase, dtype=torch.float32) + phase_tensor = story.phase.clone().detach() # Use clone().detach() instead of torch.tensor() phase_factor = torch.complex(torch.cos(phase_tensor), torch.sin(phase_tensor)) contribution = story.embedding * story.amplitude * phase_factor contributions += contribution new_field = contributions.requires_grad_() - # Apply non-linear transformation - field_potential = torch.tanh(new_field.real) + # Apply non-linear transformation with stability control + field_potential = torch.tanh(new_field.abs().clamp(min=-10, max=10)) - # Calculate field gradient + # Calculate field gradient with stability control field_gradient = torch.autograd.grad(field_potential.sum(), new_field, create_graph=True)[0] + field_gradient_abs = field_gradient.abs().clamp(min=-1, max=1) + field_gradient_angle = torch.angle(field_gradient) + field_gradient = field_gradient_abs * torch.complex(torch.cos(field_gradient_angle), torch.sin(field_gradient_angle)) # Combine linear and non-linear effects - alpha = 0.7 # Adjustable parameter for balance between linear and non-linear effects - self.field_state = alpha * new_field.real + (1 - alpha) * field_gradient.real + alpha = 0.7 + self.field_state = (alpha * new_field + (1 - alpha) * field_gradient).real + + # Ensure field state values are finite + self.field_state = torch.where(torch.isfinite(self.field_state), self.field_state, torch.rand_like(self.field_state) * 1e-6) # Normalize field state - self.field_state = self.field_state / torch.norm(self.field_state) + norm = torch.norm(self.field_state) + if norm > 0: + self.field_state = self.field_state / norm + else: + self.field_state = torch.rand_like(self.field_state) * 1e-6 def detect_emergence(self) -> List[Dict]: """Enhanced pattern detection with better uniqueness handling""" @@ -377,6 +426,12 @@ def detect_emergence(self) -> List[Dict]: processed_pairs: Set[Tuple[int, int]] = set() story_keys = list(self.stories.keys()) + + # Check if there are any stories to process + if not story_keys: + logger.warning("No stories available for pattern detection") + return patterns + embeddings = torch.stack([self.stories[key].embedding for key in story_keys]) similarity_matrix = torch.cosine_similarity( @@ -422,41 +477,41 @@ def detect_emergence(self) -> List[Dict]: def calculate_pattern_interaction(self, pattern1: Dict, pattern2: Dict) -> Dict: """Enhanced pattern interaction with stability controls""" - # Calculate base interaction (using existing logic) distance = torch.norm(pattern1['center'] - pattern2['center']) overlap = torch.max(torch.zeros(1), (pattern1['radius'] + pattern2['radius'] - distance) / (pattern1['radius'] + pattern2['radius'])) - phase_coherence = torch.cos(pattern1['phase'] - pattern2['phase']) - field_interaction = torch.cosine_similarity( pattern1['center'].unsqueeze(0), pattern2['center'].unsqueeze(0) - ) + ).clamp(min=-1, max=1) base_interaction = { 'overlap': float(overlap), - 'phase_coherence': float(phase_coherence), 'field_interaction': float(field_interaction), - 'interaction_strength': float(overlap * phase_coherence * field_interaction) + 'interaction_strength': float(overlap * field_interaction) } - # Add stability terms stability_factor = torch.exp( -0.1 * (pattern1['field_strength'] + pattern2['field_strength']) - ) + ).clamp(min=0.1, max=1.0) - # Modify interaction strength base_interaction['interaction_strength'] *= float(stability_factor) - - # Add stability metrics base_interaction['stability'] = float(stability_factor) + # Ensure all values are finite + for key, value in base_interaction.items(): + if not np.isfinite(value): + base_interaction[key] = 0.0 + return base_interaction def simulate_timestep(self, dt: float): - """Simulate one timestep of field evolution""" + """Simulate one timestep of field evolution with enhanced stability checks""" + # Log the number of active stories at the beginning of each timestep + logger.info(f"Number of active stories at start of timestep: {len(self.stories)}") + # Update all wave functions for story in self.stories.values(): self.apply_field_effects(story, dt) @@ -481,12 +536,29 @@ def simulate_timestep(self, dt: float): self.update_field_state() # Remove fully decohered stories + initial_story_count = len(self.stories) self.stories = {k: v for k, v in self.stories.items() if v.coherence > 0.1} + removed_stories = initial_story_count - len(self.stories) + if removed_stories > 0: + logger.info(f"Removed {removed_stories} fully decohered stories") + + # Dynamic story management + if random.random() < 0.1: # 10% chance each timestep + if random.random() < 0.5 and len(self.stories) > 5: # 50% chance to remove a story if more than 5 exist + story_to_remove = random.choice(list(self.stories.keys())) + del self.stories[story_to_remove] + logger.info(f"Removed story: {story_to_remove}") + else: # 50% chance to add a new story + new_story = f"New research finding at timestep {self.current_timestep}" + new_story_id = f"story_{len(self.stories)}" + self.create_wave_function(new_story, new_story_id) + logger.info(f"Added new story: {new_story}") # Enforce energy conservation self.enforce_energy_conservation() # Update pattern memory + self.pattern_memory.story_dict = self.stories # Update story_dict before detecting patterns patterns = self.detect_emergence() for pattern in patterns: self.pattern_memory.update_patterns(pattern, self.field_state) @@ -509,7 +581,29 @@ def simulate_timestep(self, dt: float): # Analyze attractor properties periodically if len(self.phase_space_tracker.trajectory) % 100 == 0: attractor_properties = self.phase_space_tracker.analyze_attractor() + field_energy = torch.norm(self.field_state) + + if torch.isnan(field_energy): + logger.warning("NaN detected in field energy calculation.") + logger.info(f"Attractor properties: {attractor_properties}") + logger.info(f"Current field energy: {field_energy:.4f}") + logger.info(f"Number of active stories: {len(self.stories)}") + if self.stories: + avg_coherence = sum(story.coherence.item() for story in self.stories.values()) / len(self.stories) + logger.info(f"Average story coherence: {avg_coherence:.4f}") + + # Log the number of active stories at the end of the timestep + logger.info(f"Number of active stories at end of timestep: {len(self.stories)}") + + # Global stability check + for story in self.stories.values(): + story.amplitude = story.amplitude.clamp(min=0.1, max=10.0) + story.coherence = story.coherence.clamp(min=0.1, max=1.0) + story.embedding = torch.where(torch.isfinite(story.embedding), story.embedding, torch.rand_like(story.embedding) * 1e-6) + + self.field_state = torch.where(torch.isfinite(self.field_state), self.field_state, torch.rand_like(self.field_state) * 1e-6) + self.field_state = self.field_state.clamp(min=-10, max=10) # Example usage @@ -528,24 +622,35 @@ def simulate_timestep(self, dt: float): # Run simulation for t in range(100): + simulator.current_timestep = t simulator.simulate_timestep(0.1) + # Add a new story every 10 timesteps + if t % 10 == 0: + new_story = f"New research finding at timestep {t}" + new_story_id = f"story_{len(simulator.stories)}" + simulator.create_wave_function(new_story, new_story_id) + logger.info(f"Added new story: {new_story}") + # Check for emergent patterns if t % 10 == 0: patterns = simulator.detect_emergence() if patterns: - print(f"Timestep {t}: Detected {len(patterns)} emergent patterns") + logger.info(f"Timestep {t}: Detected {len(patterns)} emergent patterns") for i, pattern in enumerate(patterns): - print(f" Pattern {i + 1}:") - print(f" Stories: {', '.join(pattern['stories'])}") - print(f" Coherence: {pattern['coherence']:.2f}") - print(f" Field Strength: {pattern['field_strength']:.2f}") + logger.info(f" Pattern {i + 1}:") + logger.info(f" Stories: {', '.join(pattern['stories'])}") + logger.info(f" Coherence: {pattern['coherence']:.2f}") + logger.info(f" Field Strength: {pattern['field_strength']:.2f}") else: - print(f"Timestep {t}: No emergent patterns detected") + logger.info(f"Timestep {t}: No emergent patterns detected") # Analyze pattern effects on field field_energy = torch.norm(simulator.field_state) - print(f"Field energy: {field_energy:.2f}") + logger.info(f"Field energy: {field_energy:.2f}") + + logger.info(f"Number of active stories: {len(simulator.stories)}") + + - print(f"Number of active stories: {len(simulator.stories)}") From 1858f5440aa5c7d281b5c563c8b6dc3e2dd29937 Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 08:08:01 +0100 Subject: [PATCH 11/15] These additions introduce three new classes: FrequencyAnalyzer, StoryInteractionAnalyzer, and NarrativeFieldMetrics. They are integrated into the NarrativeFieldSimulator class to provide enhanced analysis capabilities: 1. FrequencyAnalyzer: Implements wavelet-based frequency analysis to detect dominant frequencies at multiple scales. StoryInteractionAnalyzer: Provides detailed analysis of story interactions, including eigenvalue decomposition and cluster detection. NarrativeFieldMetrics: Calculates comprehensive metrics including field entropy, story diversity, and pattern stability. To use these new features, you'll need to install the PyWavelets library --- requirements.txt | 1 + src/nfs_story_waves.py | 176 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 176 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 12f6443..5bd13e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,3 +10,4 @@ pytest pytest-asyncio pytest-mock transformers +PyWavelets diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index 6640bda..c5e437a 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -8,6 +8,7 @@ import torch.nn.functional as F import torch.fft import random +import pywt # For wavelet analysis logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) @@ -244,6 +245,155 @@ def generate_colored_noise(self, shape: tuple) -> torch.Tensor: return colored_noise * self.temperature +class FrequencyAnalyzer: + """Enhance frequency analysis capabilities""" + def __init__(self, window_size: int = 50): + self.window_size = window_size + self.frequency_history = [] + + def analyze_frequencies(self, field_state: torch.Tensor, patterns: List[Dict]) -> Dict: + """Multi-scale frequency analysis""" + if not patterns: + return {'dominant_frequencies': [], 'frequency_powers': []} + + signal = torch.tensor([p['field_strength'] for p in patterns]) + + # Convert to numpy array for pywt + np_signal = signal.numpy() + + # Determine appropriate decomposition level + max_level = pywt.dwt_max_level(len(np_signal), 'db4') + level = min(3, max_level) # Use 3 or max_level, whichever is smaller + + if level == 0: + # Not enough data for decomposition + return {'dominant_frequencies': [1], 'frequency_powers': [float(np.mean(np_signal**2))]} + + # Wavelet decomposition + coeffs = pywt.wavedec(np_signal, 'db4', level=level) + + # Calculate power spectrum + power_spectrum = [float(np.mean(np.abs(c)**2)) for c in coeffs] + + # Identify dominant frequencies + dominant_scales = np.argsort(power_spectrum)[::-1] + + return { + 'dominant_frequencies': [2**(level-i) for i in dominant_scales], + 'frequency_powers': power_spectrum + } + + +class StoryInteractionAnalyzer: + """Enhanced story interaction analysis""" + def __init__(self): + self.interaction_history = [] + + def analyze_interactions(self, stories: Dict[str, NarrativeWave]) -> Dict: + """Analyze story interaction patterns""" + story_ids = list(stories.keys()) + n_stories = len(story_ids) + + if n_stories < 2: + return {} + + # Create interaction matrix + interaction_matrix = torch.zeros((n_stories, n_stories)) + + for i in range(n_stories): + for j in range(i+1, n_stories): + story1 = stories[story_ids[i]] + story2 = stories[story_ids[j]] + + semantic_similarity = torch.cosine_similarity( + story1.embedding.unsqueeze(0), + story2.embedding.unsqueeze(0) + ) + + phase_coupling = torch.cos(story1.phase - story2.phase) + amplitude_ratio = torch.min(story1.amplitude, story2.amplitude) / \ + torch.max(story1.amplitude, story2.amplitude) + + interaction_strength = ( + semantic_similarity * + phase_coupling * + amplitude_ratio + ).item() + + interaction_matrix[i, j] = interaction_matrix[j, i] = interaction_strength + + # Analyze interaction structure + eigenvalues, eigenvectors = torch.linalg.eigh(interaction_matrix) + + # Find interaction clusters + clusters = [] + threshold = 0.7 + for i, vec in enumerate(eigenvectors.T): + if eigenvalues[i] > threshold: + cluster_members = [ + story_ids[j] for j in range(n_stories) + if abs(vec[j]) > 0.3 + ] + if cluster_members: + clusters.append({ + 'strength': float(eigenvalues[i]), + 'members': cluster_members + }) + + return { + 'interaction_matrix': interaction_matrix.tolist(), + 'eigenvalues': eigenvalues.tolist(), + 'clusters': clusters + } + + +class NarrativeFieldMetrics: + """Track and analyze field metrics""" + def __init__(self): + self.metrics_history = [] + + def update(self, field_state: torch.Tensor, stories: Dict[str, NarrativeWave], + patterns: List[Dict]) -> Dict: + """Calculate comprehensive field metrics""" + # Calculate field complexity (entropy) + if field_state.dim() == 1: + field_state = field_state.unsqueeze(0) # Add a dimension if 1D + + normalized_field = torch.nn.functional.normalize(field_state.abs(), dim=-1) + field_entropy = -torch.sum(normalized_field * torch.log(normalized_field + 1e-10)) + + # Calculate story diversity + if stories: + embeddings = torch.stack([s.embedding for s in stories.values()]) + similarity_matrix = torch.cosine_similarity( + embeddings.unsqueeze(1), + embeddings.unsqueeze(0) + ) + story_diversity = 1.0 - similarity_matrix.mean() + else: + story_diversity = 0.0 + + # Calculate pattern stability + if patterns: + pattern_strengths = torch.tensor([p['field_strength'] for p in patterns]) + pattern_stability = 1.0 / (1.0 + torch.std(pattern_strengths)) + if torch.isnan(pattern_stability): + pattern_stability = 0.0 + else: + pattern_stability = 0.0 + + metrics = { + 'field_entropy': float(field_entropy), + 'story_diversity': float(story_diversity), + 'pattern_stability': float(pattern_stability), + 'active_stories': len(stories), + 'active_patterns': len(patterns) + } + + self.metrics_history.append(metrics) + return metrics + + class NarrativeFieldSimulator: def __init__(self): # Initialize quantum semantic space @@ -259,6 +409,9 @@ def __init__(self): self.phase_space_tracker = PhaseSpaceTracker(self.quantum_dim) self.environmental_coupling = EnvironmentalCoupling() self.current_timestep = 0 + self.frequency_analyzer = FrequencyAnalyzer() + self.interaction_analyzer = StoryInteractionAnalyzer() + self.field_metrics = NarrativeFieldMetrics() def create_wave_function(self, content: str, story_id: str) -> NarrativeWave: """Convert story to quantum wave function and add to stories dict""" @@ -494,7 +647,7 @@ def calculate_pattern_interaction(self, pattern1: Dict, pattern2: Dict) -> Dict: } stability_factor = torch.exp( - -0.1 * (pattern1['field_strength'] + pattern2['field_strength']) + torch.tensor(-0.1 * (pattern1['field_strength'] + pattern2['field_strength'])) ).clamp(min=0.1, max=1.0) base_interaction['interaction_strength'] *= float(stability_factor) @@ -605,6 +758,19 @@ def simulate_timestep(self, dt: float): self.field_state = torch.where(torch.isfinite(self.field_state), self.field_state, torch.rand_like(self.field_state) * 1e-6) self.field_state = self.field_state.clamp(min=-10, max=10) + # Frequency analysis + frequency_data = self.frequency_analyzer.analyze_frequencies(self.field_state, patterns) + logger.info(f"Dominant frequencies: {frequency_data['dominant_frequencies']}") + + # Interaction analysis + interaction_data = self.interaction_analyzer.analyze_interactions(self.stories) + if interaction_data: + logger.info(f"Detected {len(interaction_data['clusters'])} interaction clusters") + + # Comprehensive metrics + metrics = self.field_metrics.update(self.field_state, self.stories, patterns) + logger.info(f"Field metrics: {metrics}") + # Example usage simulator = NarrativeFieldSimulator() @@ -654,3 +820,11 @@ def simulate_timestep(self, dt: float): + + + + + + + + From 20c897b2fb023f770c3ba023f9fa9ea8df4b5ddc Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 08:10:27 +0100 Subject: [PATCH 12/15] These changes should address the main issues we're seeing: 1. The torch.linalg.eigh error should be handled gracefully now. The pattern_stability metric should provide more meaningful information. We'll have more detailed logging about why stories are being added or removed. Additionally, to get more insights into the simulation's behavior, you might want to add some periodic logging of the overall system state, perhaps every 10 or 20 timesteps. This could include things like the average story coherence, the total field energy, and other relevant metrics. --- src/nfs_story_waves.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index c5e437a..f721e2d 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -322,9 +322,13 @@ def analyze_interactions(self, stories: Dict[str, NarrativeWave]) -> Dict: interaction_matrix[i, j] = interaction_matrix[j, i] = interaction_strength - # Analyze interaction structure - eigenvalues, eigenvectors = torch.linalg.eigh(interaction_matrix) - + try: + eigenvalues, eigenvectors = torch.linalg.eigh(interaction_matrix) + except torch._C._LinAlgError: + # Fallback to SVD if eigh fails + U, S, V = torch.svd(interaction_matrix) + eigenvalues, eigenvectors = S, V + # Find interaction clusters clusters = [] threshold = 0.7 @@ -376,9 +380,10 @@ def update(self, field_state: torch.Tensor, stories: Dict[str, NarrativeWave], # Calculate pattern stability if patterns: pattern_strengths = torch.tensor([p['field_strength'] for p in patterns]) - pattern_stability = 1.0 / (1.0 + torch.std(pattern_strengths)) - if torch.isnan(pattern_stability): - pattern_stability = 0.0 + if len(pattern_strengths) > 1: + pattern_stability = 1.0 / (1.0 + torch.std(pattern_strengths)) + else: + pattern_stability = 1.0 # If there's only one pattern, consider it stable else: pattern_stability = 0.0 @@ -700,7 +705,7 @@ def simulate_timestep(self, dt: float): if random.random() < 0.5 and len(self.stories) > 5: # 50% chance to remove a story if more than 5 exist story_to_remove = random.choice(list(self.stories.keys())) del self.stories[story_to_remove] - logger.info(f"Removed story: {story_to_remove}") + logger.info(f"Randomly removed story: {story_to_remove}") else: # 50% chance to add a new story new_story = f"New research finding at timestep {self.current_timestep}" new_story_id = f"story_{len(self.stories)}" @@ -828,3 +833,6 @@ def simulate_timestep(self, dt: float): + + + From 0db70cc41131f679ba24847eaea02dadd58d2010 Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 08:17:59 +0100 Subject: [PATCH 13/15] Adds extensive comments. The simulator now incorporates all the components we've discussed, including pattern detection, frequency analysis, interaction analysis, and comprehensive field metrics. The simulation loop demonstrates how to run the simulator for multiple timesteps, add new stories periodically, and check for emergent patterns. --- src/nfs_story_waves.py | 342 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 305 insertions(+), 37 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index f721e2d..b17712c 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -16,17 +16,24 @@ @dataclass class NarrativeWave: - """Represents a story as a quantum wave function""" - - content: str - embedding: torch.Tensor # Semantic embedding as quantum state - amplitude: torch.Tensor # Story strength/influence - phase: torch.Tensor # Story's phase in narrative space - coherence: torch.Tensor # Measure of story stability - entanglement: Dict[str, float] # Connections to other stories - uncertainty: torch.Tensor = field(init=False) + """ + Represents a story as a quantum wave function in the narrative field. + + This class encapsulates the quantum properties of a story, including its + semantic embedding, amplitude (influence), phase, coherence, and entanglement + with other stories. + """ + + content: str # The actual text content of the story + embedding: torch.Tensor # Semantic embedding as quantum state (768-dimensional vector) + amplitude: torch.Tensor # Story strength/influence (scalar value) + phase: torch.Tensor # Story's phase in narrative space (scalar value) + coherence: torch.Tensor # Measure of story stability (scalar value) + entanglement: Dict[str, float] # Connections to other stories (story_id: entanglement_strength) + uncertainty: torch.Tensor = field(init=False) # Heisenberg uncertainty principle analog def __post_init__(self): + # Validate and normalize the input tensors assert self.embedding.dim() == 1, f"Embedding must be 1D, got shape {self.embedding.shape}" assert self.embedding.shape[0] == 768, f"Embedding must have 768 elements, got {self.embedding.shape[0]}" self.amplitude = self.amplitude.clone().detach().view(1) @@ -36,15 +43,31 @@ def __post_init__(self): class PatternMemory: + """ + Tracks and updates emergent patterns in the narrative field over time. + + This class maintains a memory of detected patterns, their strengths, + and their temporal evolution throughout the simulation. + """ + def __init__(self, story_dict: Dict[str, NarrativeWave]): - self.patterns: List[torch.Tensor] = [] - self.pattern_strengths: torch.Tensor = torch.tensor([]) - self.pattern_history: List[Dict[str, Any]] = [] # Track temporal evolution - self.decay_rate: float = 0.95 # Pattern memory decay - self.story_dict: Dict[str, NarrativeWave] = story_dict + self.patterns: List[torch.Tensor] = [] # List of pattern embeddings + self.pattern_strengths: torch.Tensor = torch.tensor([]) # Corresponding pattern strengths + self.pattern_history: List[Dict[str, Any]] = [] # Track temporal evolution of patterns + self.decay_rate: float = 0.95 # Pattern memory decay rate + self.story_dict: Dict[str, NarrativeWave] = story_dict # Reference to all active stories def update_patterns(self, new_pattern: Dict[str, Any], field_state: torch.Tensor) -> None: - """Enhanced pattern tracking with temporal dynamics""" + """ + Updates the pattern memory with a newly detected pattern. + + This method handles pattern merging, strength updates, and temporal decay. + It also prunes old patterns that fall below a certain strength threshold. + + Args: + new_pattern (Dict[str, Any]): The newly detected pattern + field_state (torch.Tensor): Current state of the narrative field + """ pattern_embedding = self.encode_pattern(new_pattern) pattern_time = len(self.pattern_history) @@ -52,6 +75,7 @@ def update_patterns(self, new_pattern: Dict[str, Any], field_state: torch.Tensor self.pattern_strengths *= self.decay_rate if len(self.patterns) > 0: + # Calculate similarities between new pattern and existing patterns similarities = torch.cosine_similarity( pattern_embedding.unsqueeze(0), torch.stack(self.patterns) @@ -65,12 +89,14 @@ def update_patterns(self, new_pattern: Dict[str, Any], field_state: torch.Tensor (1 - age_factor) * pattern_embedding) self.pattern_strengths[idx] += 1.0 - age_factor else: + # Add new pattern if no similar patterns exist self.patterns.append(pattern_embedding) self.pattern_strengths = torch.cat([ self.pattern_strengths, torch.tensor([1.0]) ]) else: + # Initialize first pattern self.patterns.append(pattern_embedding) self.pattern_strengths = torch.tensor([1.0]) @@ -87,7 +113,18 @@ def update_patterns(self, new_pattern: Dict[str, Any], field_state: torch.Tensor self.pattern_strengths = self.pattern_strengths[mask] def encode_pattern(self, pattern: Dict[str, Any]) -> torch.Tensor: - """Enhanced pattern encoding with semantic structure""" + """ + Encodes a pattern into a semantic embedding representation. + + This method combines the embeddings of stories involved in the pattern, + weighted by their coherence and the pattern's overall strength. + + Args: + pattern (Dict[str, Any]): The pattern to encode + + Returns: + torch.Tensor: The encoded pattern embedding + """ # Extract story embeddings story_embeddings = [] for story_id in pattern['stories']: @@ -114,11 +151,30 @@ def encode_pattern(self, pattern: Dict[str, Any]) -> torch.Tensor: class PatternEvolution: + """ + Tracks the evolution of patterns over time in the narrative field. + + This class maintains trajectories of patterns, allowing for analysis + of pattern dynamics, stability, and interactions over the course of + the simulation. + """ + def __init__(self): self.pattern_trajectories: Dict[int, List[Dict]] = {} self.next_pattern_id = 0 def update(self, current_patterns: List[Dict], field_state: torch.Tensor): + """ + Updates the pattern trajectories based on the current detected patterns. + + This method matches current patterns to existing trajectories or starts + new trajectories as needed. It also handles the deactivation of unmatched + trajectories. + + Args: + current_patterns (List[Dict]): List of currently detected patterns + field_state (torch.Tensor): Current state of the narrative field + """ new_trajectories = {} for pattern in current_patterns: @@ -160,20 +216,50 @@ def update(self, current_patterns: List[Dict], field_state: torch.Tensor): self.pattern_trajectories[pattern_id][-1]["active"] = False def calculate_pattern_similarity(self, pattern1: Dict, pattern2: Dict) -> float: + """ + Calculates the similarity between two patterns. + + This method computes the cosine similarity between the center embeddings + of two patterns to determine their similarity. + + Args: + pattern1 (Dict): First pattern for comparison + pattern2 (Dict): Second pattern for comparison + + Returns: + float: Similarity score between the two patterns + """ # Implement similarity calculation between patterns - # This is a placeholder implementation + # This is a placeholder implementation using cosine similarity return F.cosine_similarity(pattern1["center"].unsqueeze(0), pattern2["center"].unsqueeze(0)).item() class PhaseSpaceTracker: - """Track system evolution in phase space""" + """ + Tracks the evolution of the narrative field in phase space. + + This class records the trajectory of the system in a high-dimensional + phase space, allowing for analysis of system dynamics, attractors, + and overall stability. + """ + def __init__(self, dim: int): self.trajectory = [] self.phase_space_dim = dim def record_state(self, field_state: torch.Tensor, patterns: List[Dict]): - """Record current state in phase space""" + """ + Records the current state of the narrative field in phase space. + + This method captures the field state and various pattern properties + to construct a comprehensive representation of the system's state + at each time step. + + Args: + field_state (torch.Tensor): Current state of the narrative field + patterns (List[Dict]): List of currently detected patterns + """ state_vector = { 'field': field_state.clone(), 'pattern_coherence': torch.tensor([p['coherence'] for p in patterns] if patterns else [0.0]), @@ -183,7 +269,16 @@ def record_state(self, field_state: torch.Tensor, patterns: List[Dict]): self.trajectory.append(state_vector) def analyze_attractor(self) -> Dict: - """Analyze attractor properties in phase space""" + """ + Analyzes attractor properties in the phase space trajectory. + + This method examines recent states in the trajectory to determine + stability properties of the field and patterns, as well as + identifying dominant frequencies in the system's evolution. + + Returns: + Dict: A dictionary containing attractor properties + """ if len(self.trajectory) < 10: return { 'field_stability': 0.0, @@ -222,14 +317,32 @@ def analyze_attractor(self) -> Dict: class EnvironmentalCoupling: - """Handle system-environment interactions""" + """ + Handles interactions between the narrative field and its environment. + + This class simulates the effects of external factors on the narrative + field, introducing noise and perturbations that can influence the + evolution of stories and patterns. + """ + def __init__(self, temperature: float = 0.1): self.temperature = torch.tensor(temperature, dtype=torch.float32) self.noise_history = [] self.correlation_time = torch.tensor(10, dtype=torch.float32) def generate_colored_noise(self, shape: tuple) -> torch.Tensor: - """Generate temporally correlated noise""" + """ + Generates temporally correlated noise to simulate environmental effects. + + This method produces colored noise that represents persistent + environmental influences on the narrative field. + + Args: + shape (tuple): The shape of the noise tensor to generate + + Returns: + torch.Tensor: The generated colored noise + """ white_noise = torch.randn(shape) if not self.noise_history: self.noise_history = [white_noise] @@ -246,13 +359,31 @@ def generate_colored_noise(self, shape: tuple) -> torch.Tensor: class FrequencyAnalyzer: - """Enhance frequency analysis capabilities""" + """ + Performs frequency analysis on the narrative field and patterns. + + This class uses wavelet decomposition to identify dominant frequencies + and rhythms in the evolution of the narrative field and its patterns. + """ + def __init__(self, window_size: int = 50): self.window_size = window_size self.frequency_history = [] def analyze_frequencies(self, field_state: torch.Tensor, patterns: List[Dict]) -> Dict: - """Multi-scale frequency analysis""" + """ + Performs multi-scale frequency analysis on the field and patterns. + + This method uses wavelet decomposition to identify dominant frequencies + at different scales in the evolution of patterns and the overall field. + + Args: + field_state (torch.Tensor): Current state of the narrative field + patterns (List[Dict]): List of currently detected patterns + + Returns: + Dict: A dictionary containing dominant frequencies and their powers + """ if not patterns: return {'dominant_frequencies': [], 'frequency_powers': []} @@ -285,12 +416,32 @@ def analyze_frequencies(self, field_state: torch.Tensor, patterns: List[Dict]) - class StoryInteractionAnalyzer: - """Enhanced story interaction analysis""" + """ + Analyzes interactions between stories in the narrative field. + + This class examines the relationships and influences between different + stories, identifying clusters of related stories and quantifying the + strength of their interactions. + """ + def __init__(self): self.interaction_history = [] def analyze_interactions(self, stories: Dict[str, NarrativeWave]) -> Dict: - """Analyze story interaction patterns""" + """ + Analyzes interaction patterns between stories in the narrative field. + + This method computes an interaction matrix based on semantic similarity, + phase relationships, and amplitude ratios between stories. It then + identifies clusters of interacting stories using eigendecomposition. + + Args: + stories (Dict[str, NarrativeWave]): Dictionary of active stories + + Returns: + Dict: A dictionary containing the interaction matrix, eigenvalues, + and identified story clusters + """ story_ids = list(stories.keys()) n_stories = len(story_ids) @@ -352,13 +503,33 @@ def analyze_interactions(self, stories: Dict[str, NarrativeWave]) -> Dict: class NarrativeFieldMetrics: - """Track and analyze field metrics""" + """ + Tracks and analyzes various metrics of the narrative field. + + This class computes and maintains a history of key metrics that characterize + the state and evolution of the narrative field, including complexity, + diversity, and stability measures. + """ + def __init__(self): self.metrics_history = [] def update(self, field_state: torch.Tensor, stories: Dict[str, NarrativeWave], patterns: List[Dict]) -> Dict: - """Calculate comprehensive field metrics""" + """ + Calculates comprehensive field metrics for the current state. + + This method computes various metrics including field complexity (entropy), + story diversity, pattern stability, and counts of active stories and patterns. + + Args: + field_state (torch.Tensor): Current state of the narrative field + stories (Dict[str, NarrativeWave]): Dictionary of active stories + patterns (List[Dict]): List of currently detected patterns + + Returns: + Dict: A dictionary containing the calculated metrics + """ # Calculate field complexity (entropy) if field_state.dim() == 1: field_state = field_state.unsqueeze(0) # Add a dimension if 1D @@ -400,6 +571,15 @@ def update(self, field_state: torch.Tensor, stories: Dict[str, NarrativeWave], class NarrativeFieldSimulator: + """ + Main class for simulating the evolution of the narrative field. + + This class integrates all components of the narrative field simulation, + including story creation, field evolution, pattern detection, and analysis. + It manages the overall simulation process and provides methods for + running the simulation and analyzing its results. + """ + def __init__(self): # Initialize quantum semantic space self.tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") @@ -419,7 +599,19 @@ def __init__(self): self.field_metrics = NarrativeFieldMetrics() def create_wave_function(self, content: str, story_id: str) -> NarrativeWave: - """Convert story to quantum wave function and add to stories dict""" + """ + Converts a story to a quantum wave function and adds it to the stories dict. + + This method creates a semantic embedding for the story content and + initializes its quantum properties (amplitude, phase, coherence). + + Args: + content (str): The text content of the story + story_id (str): A unique identifier for the story + + Returns: + NarrativeWave: The created wave function representation of the story + """ # Create semantic embedding tokens = self.tokenizer(content, return_tensors="pt", padding=True, truncation=True, max_length=512) with torch.no_grad(): @@ -438,7 +630,20 @@ def create_wave_function(self, content: str, story_id: str) -> NarrativeWave: return wave def quantum_interference(self, wave1: NarrativeWave, wave2: NarrativeWave) -> float: - """More sophisticated quantum interference calculation""" + """ + Calculates the quantum interference between two story wave functions. + + This method computes a sophisticated interference value based on + semantic similarity, phase relationships, coherence, and other + quantum-inspired properties of the stories. + + Args: + wave1 (NarrativeWave): First story wave function + wave2 (NarrativeWave): Second story wave function + + Returns: + float: The calculated interference value + """ similarity = torch.cosine_similarity(wave1.embedding.unsqueeze(0), wave2.embedding.unsqueeze(0)) phase_factor = torch.cos(wave1.phase - wave2.phase) @@ -468,7 +673,17 @@ def quantum_interference(self, wave1: NarrativeWave, wave2: NarrativeWave) -> fl ) def apply_field_effects(self, wave: NarrativeWave, dt: float): - """Enhanced field effects with better damping and stability""" + """ + Applies the effects of the narrative field to a story wave function. + + This method updates the quantum properties of a story based on its + interaction with the overall narrative field, including phase evolution, + decoherence, and amplitude changes. + + Args: + wave (NarrativeWave): The story wave function to update + dt (float): The time step of the simulation + """ # Phase evolution wave.phase += dt * wave.amplitude.clamp(max=10.0) # Limit maximum phase change @@ -503,7 +718,19 @@ def apply_field_effects(self, wave: NarrativeWave, dt: float): wave.coherence = wave.coherence.clamp(min=0.1, max=1.0) def apply_environmental_effects(self, wave: NarrativeWave, dt: float): - """Simulate interaction with environment using colored noise""" + """ + Simulates the interaction of a story with the environment. + + This method applies environmental noise and fluctuations to the + story's quantum properties, simulating external influences on the narrative. + + Args: + wave (NarrativeWave): The story wave function to update + dt (float): The time step of the simulation + + Returns: + Tuple[torch.Tensor, torch.Tensor]: Updated embedding and vacuum fluctuation + """ colored_noise = self.environmental_coupling.generate_colored_noise(wave.embedding.shape) environment_coupling = torch.tensor(0.1, dtype=torch.float32) @@ -515,7 +742,13 @@ def apply_environmental_effects(self, wave: NarrativeWave, dt: float): return wave.embedding + colored_noise, vacuum_fluctuation def enforce_energy_conservation(self): - """More sophisticated energy conservation with nan handling""" + """ + Enforces energy conservation in the narrative field. + + This method ensures that the total energy of the system remains + within specified bounds, applying corrections to the field state + and story amplitudes when necessary. + """ if torch.isnan(self.field_state).any(): logger.warning("NaN detected in field state. Resetting to small random values.") self.field_state = torch.rand_like(self.field_state) * 1e-6 @@ -544,7 +777,12 @@ def enforce_energy_conservation(self): self.field_state *= (1.0 - dissipation) def update_field_state(self): - """Update the overall field state based on all stories with non-linear effects and stability controls""" + """ + Updates the overall field state based on all stories with non-linear effects and stability controls. + + This method calculates the contributions of all stories to the field state, + applies non-linear transformations, and updates the field state accordingly. + """ contributions = torch.zeros(self.quantum_dim, dtype=torch.complex64) for story in self.stories.values(): @@ -579,7 +817,15 @@ def update_field_state(self): self.field_state = torch.rand_like(self.field_state) * 1e-6 def detect_emergence(self) -> List[Dict]: - """Enhanced pattern detection with better uniqueness handling""" + """ + Enhanced pattern detection with better uniqueness handling. + + This method detects emergent patterns in the narrative field by + identifying groups of similar stories based on their semantic embeddings. + + Returns: + List[Dict]: List of detected patterns + """ patterns = [] processed_pairs: Set[Tuple[int, int]] = set() @@ -634,7 +880,20 @@ def detect_emergence(self) -> List[Dict]: return patterns def calculate_pattern_interaction(self, pattern1: Dict, pattern2: Dict) -> Dict: - """Enhanced pattern interaction with stability controls""" + """ + Enhanced pattern interaction with stability controls. + + This method calculates the interaction between two patterns based on + their spatial overlap and field interaction, while also considering + stability factors. + + Args: + pattern1 (Dict): First pattern for interaction calculation + pattern2 (Dict): Second pattern for interaction calculation + + Returns: + Dict: A dictionary containing interaction properties + """ distance = torch.norm(pattern1['center'] - pattern2['center']) overlap = torch.max(torch.zeros(1), (pattern1['radius'] + pattern2['radius'] - distance) / @@ -666,7 +925,16 @@ def calculate_pattern_interaction(self, pattern1: Dict, pattern2: Dict) -> Dict: return base_interaction def simulate_timestep(self, dt: float): - """Simulate one timestep of field evolution with enhanced stability checks""" + """ + Simulates one timestep of field evolution with enhanced stability checks. + + This method updates the state of the narrative field and all stories + based on their interactions, while also handling dynamic story management, + energy conservation, pattern detection, and analysis. + + Args: + dt (float): The time step of the simulation + """ # Log the number of active stories at the beginning of each timestep logger.info(f"Number of active stories at start of timestep: {len(self.stories)}") From 180153fdc59b8b9ca20f131c5998f8b575f42829 Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 08:23:01 +0100 Subject: [PATCH 14/15] Update src/nfs_story_waves.py Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- src/nfs_story_waves.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index b17712c..adf632c 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -101,6 +101,9 @@ def update_patterns(self, new_pattern: Dict[str, Any], field_state: torch.Tensor self.pattern_strengths = torch.tensor([1.0]) # Update temporal history + # Keep only the most recent patterns + if len(self.pattern_history) >= 1000: + self.pattern_history.pop(0) self.pattern_history.append({ 'time': pattern_time, 'embedding': pattern_embedding, From 6d59bf0337f0451939a11a4048874563caada16c Mon Sep 17 00:00:00 2001 From: Leon van Bokhorst Date: Sun, 27 Oct 2024 08:25:46 +0100 Subject: [PATCH 15/15] Update src/nfs_story_waves.py Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- src/nfs_story_waves.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nfs_story_waves.py b/src/nfs_story_waves.py index adf632c..c7eb124 100644 --- a/src/nfs_story_waves.py +++ b/src/nfs_story_waves.py @@ -1076,8 +1076,7 @@ def simulate_timestep(self, dt: float): # Check for emergent patterns if t % 10 == 0: - patterns = simulator.detect_emergence() - if patterns: + if patterns := simulator.detect_emergence(): logger.info(f"Timestep {t}: Detected {len(patterns)} emergent patterns") for i, pattern in enumerate(patterns): logger.info(f" Pattern {i + 1}:")