diff --git a/cupy_similarity.py b/cupy_similarity.py index f49285a..5008197 100644 --- a/cupy_similarity.py +++ b/cupy_similarity.py @@ -45,6 +45,7 @@ # Try to import CuPy for GPU acceleration try: import cupy as cp + CUPY_AVAILABLE = True except ImportError: CUPY_AVAILABLE = False @@ -52,7 +53,7 @@ warnings.warn( "CuPy not available. GPU functions will fall back to CPU. " "Install CuPy with: pip install cupy-cuda11x (or cupy-cuda12x for CUDA 12+)", - ImportWarning + ImportWarning, ) @@ -95,7 +96,7 @@ def get_array_module(array): return np -def to_gpu(array: np.ndarray) -> Union[np.ndarray, 'cp.ndarray']: +def to_gpu(array: np.ndarray) -> Union[np.ndarray, "cp.ndarray"]: """ Transfer numpy array to GPU if available, otherwise return as-is. @@ -114,7 +115,7 @@ def to_gpu(array: np.ndarray) -> Union[np.ndarray, 'cp.ndarray']: return np.asarray(array, dtype=np.float64) -def to_cpu(array: Union[np.ndarray, 'cp.ndarray']) -> np.ndarray: +def to_cpu(array: Union[np.ndarray, "cp.ndarray"]) -> np.ndarray: """ Transfer array to CPU (numpy). @@ -134,10 +135,10 @@ def to_cpu(array: Union[np.ndarray, 'cp.ndarray']) -> np.ndarray: def lorentz_similarity_gpu( - u: Union[np.ndarray, 'cp.ndarray'], - v: Union[np.ndarray, 'cp.ndarray'], + u: Union[np.ndarray, "cp.ndarray"], + v: Union[np.ndarray, "cp.ndarray"], epsilon: float = 1e-10, - return_cpu: bool = True + return_cpu: bool = True, ) -> float: """ Compute Lorentz-invariant cosine similarity on GPU. @@ -227,11 +228,11 @@ def lorentz_similarity_gpu( def lorentz_similarity_batch_gpu( - U: Union[np.ndarray, 'cp.ndarray'], - V: Union[np.ndarray, 'cp.ndarray'], + U: Union[np.ndarray, "cp.ndarray"], + V: Union[np.ndarray, "cp.ndarray"], epsilon: float = 1e-10, - return_cpu: bool = True -) -> Union[np.ndarray, 'cp.ndarray']: + return_cpu: bool = True, +) -> Union[np.ndarray, "cp.ndarray"]: """ Compute Lorentz-invariant similarities for batches of vector pairs on GPU. @@ -314,7 +315,9 @@ def lorentz_similarity_batch_gpu( final_valid[temp_indices[valid_denom_mask]] = True # Compute similarities - similarities[final_valid] = lorentz_products_uv[final_valid] / xp.sqrt(denominator_squared[final_valid]) + similarities[final_valid] = lorentz_products_uv[final_valid] / xp.sqrt( + denominator_squared[final_valid] + ) # Clamp to valid range similarities = xp.clip(similarities, -1.0, 1.0) @@ -326,11 +329,11 @@ def lorentz_similarity_batch_gpu( def lorentz_similarity_matrix_gpu( - U: Union[np.ndarray, 'cp.ndarray'], - V: Optional[Union[np.ndarray, 'cp.ndarray']] = None, + U: Union[np.ndarray, "cp.ndarray"], + V: Optional[Union[np.ndarray, "cp.ndarray"]] = None, epsilon: float = 1e-10, - return_cpu: bool = True -) -> Union[np.ndarray, 'cp.ndarray']: + return_cpu: bool = True, +) -> Union[np.ndarray, "cp.ndarray"]: """ Compute pairwise Lorentz-invariant similarity matrix on GPU. @@ -408,8 +411,8 @@ def lorentz_similarity_matrix_gpu( # Self inner products (for normalization) # These are all zeros due to lightlike condition, but we compute for consistency - lorentz_products_uu = (norms_U ** 2) - (norms_U ** 2) # shape: (N, 1) - lorentz_products_vv = (norms_V ** 2) - (norms_V ** 2) # shape: (M, 1) + lorentz_products_uu = (norms_U**2) - (norms_U**2) # shape: (N, 1) + lorentz_products_vv = (norms_V**2) - (norms_V**2) # shape: (M, 1) # Denominators: sqrt(|_L| * |_L|) # Broadcast: (N, 1) * (1, M) -> (N, M) @@ -445,10 +448,10 @@ def lorentz_similarity_matrix_gpu( def standard_cosine_similarity_gpu( - u: Union[np.ndarray, 'cp.ndarray'], - v: Union[np.ndarray, 'cp.ndarray'], + u: Union[np.ndarray, "cp.ndarray"], + v: Union[np.ndarray, "cp.ndarray"], epsilon: float = 1e-10, - return_cpu: bool = True + return_cpu: bool = True, ) -> float: """ Compute standard cosine similarity on GPU. @@ -504,10 +507,7 @@ def standard_cosine_similarity_gpu( # Convenience function for automatic GPU/CPU selection def lorentz_similarity_auto( - u: np.ndarray, - v: np.ndarray, - epsilon: float = 1e-10, - prefer_gpu: bool = True + u: np.ndarray, v: np.ndarray, epsilon: float = 1e-10, prefer_gpu: bool = True ) -> float: """ Automatically select GPU or CPU implementation based on availability. @@ -533,4 +533,5 @@ def lorentz_similarity_auto( else: # Fall back to CPU implementation from similarity import lorentz_similarity + return lorentz_similarity(u, v, epsilon=epsilon) diff --git a/eigen_attention.py b/eigen_attention.py index 127def6..1c06945 100644 --- a/eigen_attention.py +++ b/eigen_attention.py @@ -66,11 +66,7 @@ def _reshape_from_heads(self, x: torch.Tensor, B: int, L: int) -> torch.Tensor: """ (B*H, L, d_head) -> (B, L, D) """ - return ( - x.view(B, self.num_heads, L, self.head_dim) - .transpose(1, 2) - .reshape(B, L, self.dim) - ) + return x.view(B, self.num_heads, L, self.head_dim).transpose(1, 2).reshape(B, L, self.dim) def forward( self, @@ -107,7 +103,7 @@ def forward( v = self._reshape_to_heads(v) # (B*H, L, d_head) # Eigen similarity per head: (B*H, L_q, L_k) - sim = eigen_similarity(q, k) # expected in [-1, 1] + sim = eigen_similarity(q, k) # expected in [-1, 1] # loop prevention: attenuate near-self/lightlike connections sim = torch.where( @@ -150,9 +146,7 @@ def forward( attn_mask_expanded = attn_mask.repeat(1, self.num_heads, 1, 1) else: attn_mask_expanded = attn_mask - attn_mask_expanded = attn_mask_expanded.reshape( - B * self.num_heads, L, L - ) + attn_mask_expanded = attn_mask_expanded.reshape(B * self.num_heads, L, L) logits = logits + attn_mask_expanded else: raise ValueError( diff --git a/eigen_memory.py b/eigen_memory.py index 0592a69..9a9b7dd 100644 --- a/eigen_memory.py +++ b/eigen_memory.py @@ -152,18 +152,18 @@ def forward( # temporal decay: favor recent entries (age=0 newest) # effective weight ∝ decay^age ∈ (0, 1] - decay_factor = (self.decay ** age).clamp(min=1e-6) # (N,) - sim = sim + decay_factor.log().unsqueeze(0) # add log-decay + decay_factor = (self.decay**age).clamp(min=1e-6) # (N,) + sim = sim + decay_factor.log().unsqueeze(0) # add log-decay # top-k selection k = min(self.k_top, N) - sim_topk, idx_topk = torch.topk(sim, k, dim=-1) # (B, k) + sim_topk, idx_topk = torch.topk(sim, k, dim=-1) # (B, k) # attention weights over top-k - attn = F.softmax(sim_topk, dim=-1) # (B, k) + attn = F.softmax(sim_topk, dim=-1) # (B, k) # gather memory vectors - mem_topk = mem[idx_topk] # (B, k, D) + mem_topk = mem[idx_topk] # (B, k, D) retrieved = torch.sum(attn.unsqueeze(-1) * mem_topk, dim=1) # (B, D) diff --git a/examples_gpu.py b/examples_gpu.py index 34e9965..2a7075e 100644 --- a/examples_gpu.py +++ b/examples_gpu.py @@ -41,6 +41,7 @@ def check_gpu_status(): print("✓ GPU (CUDA) is available!") try: import cupy as cp + device = cp.cuda.Device() print(f" Device: {device}") print(f" Compute Capability: {device.compute_capability}") @@ -139,9 +140,7 @@ def example_attention_mechanism(): # Compute attention scores using GPU start = time.time() - attention_scores = gpu_sim.lorentz_similarity_matrix_gpu( - embeddings, embeddings - ) + attention_scores = gpu_sim.lorentz_similarity_matrix_gpu(embeddings, embeddings) gpu_time = time.time() - start print(f"GPU attention matrix computation: {gpu_time*1000:.2f} ms") @@ -151,8 +150,10 @@ def example_attention_mechanism(): # Analyze self-attention (diagonal) diagonal = np.diag(attention_scores) print("Self-attention analysis:") - print(f" Diagonal values (self-similarity): mean={np.mean(diagonal):.6f}, " - f"std={np.std(diagonal):.6f}") + print( + f" Diagonal values (self-similarity): mean={np.mean(diagonal):.6f}, " + f"std={np.std(diagonal):.6f}" + ) print(f" All diagonal ~0.0? {np.allclose(diagonal, 0.0, atol=1e-6)}") print() @@ -162,8 +163,10 @@ def example_attention_mechanism(): off_diagonal = attention_scores[mask] print("Cross-attention analysis:") - print(f" Off-diagonal values: mean={np.mean(off_diagonal):.6f}, " - f"std={np.std(off_diagonal):.6f}") + print( + f" Off-diagonal values: mean={np.mean(off_diagonal):.6f}, " + f"std={np.std(off_diagonal):.6f}" + ) print(f" Range: [{np.min(off_diagonal):.3f}, {np.max(off_diagonal):.3f}]") print() @@ -203,9 +206,7 @@ def example_semantic_search(): # GPU search start = time.time() - similarity_matrix = gpu_sim.lorentz_similarity_matrix_gpu( - query_embeddings, doc_embeddings - ) + similarity_matrix = gpu_sim.lorentz_similarity_matrix_gpu(query_embeddings, doc_embeddings) gpu_time = time.time() - start print(f"GPU similarity computation: {gpu_time*1000:.2f} ms") @@ -219,8 +220,9 @@ def example_semantic_search(): for i in range(min(3, num_queries)): # Show first 3 queries top_k_indices = np.argsort(similarity_matrix[i])[-k:][::-1] top_k_scores = similarity_matrix[i][top_k_indices] - print(f" Query {i}: docs {top_k_indices} " - f"(scores: {[f'{s:.3f}' for s in top_k_scores]})") + print( + f" Query {i}: docs {top_k_indices} " f"(scores: {[f'{s:.3f}' for s in top_k_scores]})" + ) def example_loop_prevention_demo(): @@ -243,8 +245,10 @@ def example_loop_prevention_demo(): for i in range(iterations): self_sim = standard_cosine_similarity(state, state) standard_accumulation += self_sim - print(f" Iteration {i+1}: self-similarity = {self_sim:.6f}, " - f"accumulated = {standard_accumulation:.6f}") + print( + f" Iteration {i+1}: self-similarity = {self_sim:.6f}, " + f"accumulated = {standard_accumulation:.6f}" + ) print(f"\n Total accumulated: {standard_accumulation:.6f}") print(f" Average per iteration: {standard_accumulation/iterations:.6f}") @@ -257,8 +261,10 @@ def example_loop_prevention_demo(): for i in range(iterations): self_sim = gpu_sim.lorentz_similarity_gpu(state, state) lorentz_accumulation += self_sim - print(f" Iteration {i+1}: self-similarity = {self_sim:.6f}, " - f"accumulated = {lorentz_accumulation:.6f}") + print( + f" Iteration {i+1}: self-similarity = {self_sim:.6f}, " + f"accumulated = {lorentz_accumulation:.6f}" + ) print(f"\n Total accumulated: {lorentz_accumulation:.6f}") print(f" Average per iteration: {lorentz_accumulation/iterations:.6f}") @@ -313,12 +319,15 @@ def performance_comparison(): print("\n" + "-" * 70) print("Summary:") - print(f"{'Configuration':<20} {'Problem Size':<15} {'GPU (ms)':<12} " - f"{'CPU (ms)':<12} {'Speedup':<10}") + print( + f"{'Configuration':<20} {'Problem Size':<15} {'GPU (ms)':<12} " + f"{'CPU (ms)':<12} {'Speedup':<10}" + ) print("-" * 70) for label, size, gpu_t, cpu_t, speedup in results: - print(f"{label:<20} {size:<15,} {gpu_t*1000:<12.2f} " - f"{cpu_t*1000:<12.2f} {speedup:<10.2f}x") + print( + f"{label:<20} {size:<15,} {gpu_t*1000:<12.2f} " f"{cpu_t*1000:<12.2f} {speedup:<10.2f}x" + ) def main(): diff --git a/examples_loop_prevention.py b/examples_loop_prevention.py index 7eafeaf..dc7fdbf 100644 --- a/examples_loop_prevention.py +++ b/examples_loop_prevention.py @@ -28,9 +28,9 @@ def example_1_attention_mechanism(): Lorentz similarity gives 0.0 self-attention, forcing the mechanism to weight other tokens equally based on their actual relevance. """ - print("\n" + "="*70) + print("\n" + "=" * 70) print("EXAMPLE 1: Self-Attention Mechanism") - print("="*70) + print("=" * 70) # Simulate token embeddings token_embeddings = [ @@ -77,18 +77,18 @@ def example_2_graph_traversal(): Lorentz similarity prevents this by assigning 0.0 weight to self-edges. """ - print("\n" + "="*70) + print("\n" + "=" * 70) print("EXAMPLE 2: Graph Traversal with Similarity-Based Edges") - print("="*70) + print("=" * 70) # Semantic concept embeddings concepts = { - 'dog': np.array([0.8, 0.6, 0.1, 0.2]), - 'cat': np.array([0.7, 0.5, 0.2, 0.3]), - 'car': np.array([0.1, 0.2, 0.9, 0.8]), + "dog": np.array([0.8, 0.6, 0.1, 0.2]), + "cat": np.array([0.7, 0.5, 0.2, 0.3]), + "car": np.array([0.1, 0.2, 0.9, 0.8]), } - start_concept = 'dog' + start_concept = "dog" start_embedding = concepts[start_concept] print(f"\nStarting from concept: '{start_concept}'") @@ -128,9 +128,9 @@ def example_3_iterative_refinement(): Lorentz similarity's neutral self-reference encourages genuine evolution. """ - print("\n" + "="*70) + print("\n" + "=" * 70) print("EXAMPLE 3: Iterative Refinement System") - print("="*70) + print("=" * 70) # Initial state state = np.array([1.0, 0.5, 0.2]) @@ -153,8 +153,10 @@ def example_3_iterative_refinement(): noise = np.random.randn(3) * 0.1 current_standard = current_standard + noise * update_magnitude - print(f" Iteration {i+1}: self_sim = {self_sim:.4f}, " - f"update_magnitude = {update_magnitude:.4f}") + print( + f" Iteration {i+1}: self_sim = {self_sim:.4f}, " + f"update_magnitude = {update_magnitude:.4f}" + ) print(f" Final state: {current_standard}") print(f" Total change: {np.linalg.norm(current_standard - state):.4f}") @@ -169,8 +171,10 @@ def example_3_iterative_refinement(): noise = np.random.randn(3) * 0.1 current_lorentz = current_lorentz + noise * update_magnitude - print(f" Iteration {i+1}: self_sim = {self_sim:.4f}, " - f"update_magnitude = {update_magnitude:.4f}") + print( + f" Iteration {i+1}: self_sim = {self_sim:.4f}, " + f"update_magnitude = {update_magnitude:.4f}" + ) print(f" Final state: {current_lorentz}") print(f" Total change: {np.linalg.norm(current_lorentz - state):.4f}") @@ -190,15 +194,15 @@ def example_4_semantic_feedback(): to refine the query can create loops if the query becomes too similar to itself, preventing exploration of the semantic space. """ - print("\n" + "="*70) + print("\n" + "=" * 70) print("EXAMPLE 4: Semantic Search Query Refinement") - print("="*70) + print("=" * 70) # Document embeddings documents = { - 'doc_A': np.array([0.9, 0.1, 0.1]), - 'doc_B': np.array([0.1, 0.9, 0.1]), - 'doc_C': np.array([0.1, 0.1, 0.9]), + "doc_A": np.array([0.9, 0.1, 0.1]), + "doc_B": np.array([0.1, 0.9, 0.1]), + "doc_C": np.array([0.1, 0.1, 0.9]), } # Initial query @@ -234,9 +238,11 @@ def example_4_semantic_feedback(): # Refine query query_standard = 0.7 * query_standard + 0.3 * best_doc - print(f" Iteration {iteration + 1}: " - f"best_doc_sim = {best_sim:.4f}, " - f"query_self_sim = {self_sim:.4f}") + print( + f" Iteration {iteration + 1}: " + f"best_doc_sim = {best_sim:.4f}, " + f"query_self_sim = {self_sim:.4f}" + ) # Lorentz approach query_lorentz = query.copy() @@ -257,9 +263,11 @@ def example_4_semantic_feedback(): # Refine query query_lorentz = 0.7 * query_lorentz + 0.3 * best_doc - print(f" Iteration {iteration + 1}: " - f"best_doc_sim = {best_sim:.4f}, " - f"query_self_sim = {self_sim:.4f}") + print( + f" Iteration {iteration + 1}: " + f"best_doc_sim = {best_sim:.4f}, " + f"query_self_sim = {self_sim:.4f}" + ) print("\nAnalysis:") print(" Standard: Query self-similarity increases toward 1.0") @@ -278,9 +286,9 @@ def example_5_consciousness_model(): boundary (ds² = 0) inherently disrupt self-reinforcement, promoting evolutionary dynamics. """ - print("\n" + "="*70) + print("\n" + "=" * 70) print("EXAMPLE 5: Consciousness Model - Eigengate Framework") - print("="*70) + print("=" * 70) # Mental state embedding conscious_state = np.array([0.6, 0.8, 0.3, 0.5]) @@ -345,9 +353,9 @@ def example_5_consciousness_model(): def run_all_examples(): """Run all loop prevention examples.""" - print("\n" + "#"*70) + print("\n" + "#" * 70) print("# LORENTZ-INVARIANT SIMILARITY: LOOP PREVENTION DEMONSTRATIONS") - print("#"*70) + print("#" * 70) example_1_attention_mechanism() example_2_graph_traversal() @@ -355,9 +363,9 @@ def run_all_examples(): example_4_semantic_feedback() example_5_consciousness_model() - print("\n" + "#"*70) + print("\n" + "#" * 70) print("# SUMMARY") - print("#"*70) + print("#" * 70) print("\nKey Finding:") print(" Lorentz-invariant similarity's neutral self-reference (0.0)") print(" prevents pathological loops in self-referential systems by:") @@ -370,7 +378,7 @@ def run_all_examples(): print() print("This is NOT a general solution to the halting problem, but rather") print("a geometric safeguard within specifically designed architectures.") - print("#"*70 + "\n") + print("#" * 70 + "\n") if __name__ == "__main__": diff --git a/gpu_similarity.py b/gpu_similarity.py index 1a7c87a..a83fe40 100644 --- a/gpu_similarity.py +++ b/gpu_similarity.py @@ -126,8 +126,8 @@ def _eigen_similarity_2d( raise ValueError(f"Dimension mismatch: q has dim {D}, k has dim {D_k}") # Compute norms - norm_q_sq = torch.sum(q ** 2, dim=-1, keepdim=True) # (B, 1) - norm_k_sq = torch.sum(k ** 2, dim=-1, keepdim=True) # (N, 1) + norm_q_sq = torch.sum(q**2, dim=-1, keepdim=True) # (B, 1) + norm_k_sq = torch.sum(k**2, dim=-1, keepdim=True) # (N, 1) # Spatial inner products: q · k^T spatial_product = torch.mm(q, k.t()) # (B, N) @@ -148,7 +148,7 @@ def _eigen_similarity_2d( # Broadcast to (B, N) denominator_sq = lorentz_qq_abs.unsqueeze(1) * lorentz_kk_abs.unsqueeze(0) # (B, N) - denominator = torch.sqrt(denominator_sq + epsilon ** 2) + denominator = torch.sqrt(denominator_sq + epsilon**2) # Similarity similarity = lorentz_product_qk / denominator.clamp(min=epsilon) @@ -199,8 +199,8 @@ def _eigen_similarity_3d( B = B_q # Compute norms - norm_q_sq = torch.sum(q ** 2, dim=-1, keepdim=True) # (B, L_q, 1) - norm_k_sq = torch.sum(k ** 2, dim=-1, keepdim=True) # (B, L_k, 1) + norm_q_sq = torch.sum(q**2, dim=-1, keepdim=True) # (B, L_q, 1) + norm_k_sq = torch.sum(k**2, dim=-1, keepdim=True) # (B, L_k, 1) # Spatial inner products: q @ k^T spatial_product = torch.bmm(q, k.transpose(1, 2)) # (B, L_q, L_k) @@ -221,7 +221,7 @@ def _eigen_similarity_3d( # Broadcast to (B, L_q, L_k) denominator_sq = lorentz_qq_abs.unsqueeze(2) * lorentz_kk_abs.unsqueeze(1) # (B, L_q, L_k) - denominator = torch.sqrt(denominator_sq + epsilon ** 2) + denominator = torch.sqrt(denominator_sq + epsilon**2) # Similarity similarity = lorentz_product_qk / denominator.clamp(min=epsilon) @@ -276,9 +276,7 @@ def standard_cosine_similarity_torch( k_norm = F.normalize(k, p=2, dim=-1, eps=epsilon) return torch.bmm(q_norm, k_norm.transpose(1, 2)) else: - raise ValueError( - f"Unsupported tensor dimensions: q.shape={q.shape}, k.shape={k.shape}" - ) + raise ValueError(f"Unsupported tensor dimensions: q.shape={q.shape}, k.shape={k.shape}") def compare_self_similarity_torch( @@ -308,7 +306,7 @@ def compare_self_similarity_torch( norm = torch.linalg.norm(v.reshape(-1, v.shape[-1]), dim=-1) return { - 'standard': standard, - 'eigen': eigen, - 'vector_norm': norm, + "standard": standard, + "eigen": eigen, + "vector_norm": norm, } diff --git a/similarity.py b/similarity.py index 47141ca..bddd1ad 100644 --- a/similarity.py +++ b/similarity.py @@ -39,11 +39,7 @@ from typing import Union, Optional -def lorentz_similarity( - u: np.ndarray, - v: np.ndarray, - epsilon: float = 1e-10 -) -> float: +def lorentz_similarity(u: np.ndarray, v: np.ndarray, epsilon: float = 1e-10) -> float: """ Compute Lorentz-invariant cosine similarity between two vectors. @@ -119,11 +115,7 @@ def lorentz_similarity( return np.clip(similarity, -1.0, 1.0) -def standard_cosine_similarity( - u: np.ndarray, - v: np.ndarray, - epsilon: float = 1e-10 -) -> float: +def standard_cosine_similarity(u: np.ndarray, v: np.ndarray, epsilon: float = 1e-10) -> float: """ Compute standard cosine similarity between two vectors. @@ -207,11 +199,11 @@ def compare_self_similarity(vector: np.ndarray) -> dict: lorentz = lorentz_similarity(vector, vector) return { - 'standard': standard, - 'lorentz': lorentz, - 'vector_norm': np.linalg.norm(vector), - 'interpretation': { - 'standard': 'Perfect self-reinforcement (1.0) - potential loop amplifier', - 'lorentz': 'Neutral self-reference (0.0) - loop prevention via lightlike boundary' - } + "standard": standard, + "lorentz": lorentz, + "vector_norm": np.linalg.norm(vector), + "interpretation": { + "standard": "Perfect self-reinforcement (1.0) - potential loop amplifier", + "lorentz": "Neutral self-reference (0.0) - loop prevention via lightlike boundary", + }, } diff --git a/test_gpu_similarity.py b/test_gpu_similarity.py index 58c8ee5..fc9765d 100644 --- a/test_gpu_similarity.py +++ b/test_gpu_similarity.py @@ -13,10 +13,7 @@ import numpy as np import pytest import gpu_similarity as gpu_sim -from similarity import ( - lorentz_similarity, - standard_cosine_similarity -) +from similarity import lorentz_similarity, standard_cosine_similarity class TestGPUAvailability: @@ -55,15 +52,16 @@ def test_lorentz_similarity_self_consistency(self): np.array([3.0, 4.0]), np.array([1.0, 2.0, 3.0, 4.0, 5.0]), np.random.randn(10), - np.random.randn(100) + np.random.randn(100), ] for v in vectors: cpu_sim = lorentz_similarity(v, v) gpu_sim_result = gpu_sim.lorentz_similarity_gpu(v, v) - assert np.isclose(cpu_sim, gpu_sim_result, atol=1e-9), \ - f"CPU: {cpu_sim}, GPU: {gpu_sim_result}" + assert np.isclose( + cpu_sim, gpu_sim_result, atol=1e-9 + ), f"CPU: {cpu_sim}, GPU: {gpu_sim_result}" # Both should be ~0.0 for self-similarity assert np.isclose(gpu_sim_result, 0.0, atol=1e-6) @@ -81,8 +79,9 @@ def test_lorentz_similarity_pair_consistency(self): cpu_sim = lorentz_similarity(u, v) gpu_sim_result = gpu_sim.lorentz_similarity_gpu(u, v) - assert np.isclose(cpu_sim, gpu_sim_result, atol=1e-9), \ - f"Shape {u.shape}: CPU: {cpu_sim}, GPU: {gpu_sim_result}" + assert np.isclose( + cpu_sim, gpu_sim_result, atol=1e-9 + ), f"Shape {u.shape}: CPU: {cpu_sim}, GPU: {gpu_sim_result}" def test_standard_cosine_consistency(self): """GPU and CPU standard cosine similarity should match.""" @@ -96,8 +95,9 @@ def test_standard_cosine_consistency(self): cpu_sim = standard_cosine_similarity(u, v) gpu_sim_result = gpu_sim.standard_cosine_similarity_gpu(u, v) - assert np.isclose(cpu_sim, gpu_sim_result, atol=1e-9), \ - f"CPU: {cpu_sim}, GPU: {gpu_sim_result}" + assert np.isclose( + cpu_sim, gpu_sim_result, atol=1e-9 + ), f"CPU: {cpu_sim}, GPU: {gpu_sim_result}" class TestBatchOperations: @@ -115,8 +115,9 @@ def test_batch_self_similarity(self): similarities = gpu_sim.lorentz_similarity_batch_gpu(U, V) assert similarities.shape == (N,) - assert np.allclose(similarities, 0.0, atol=1e-6), \ - f"All self-similarities should be ~0.0, got {similarities[:5]}" + assert np.allclose( + similarities, 0.0, atol=1e-6 + ), f"All self-similarities should be ~0.0, got {similarities[:5]}" def test_batch_consistency_with_loop(self): """Batch processing should match individual computations.""" @@ -130,9 +131,7 @@ def test_batch_consistency_with_loop(self): batch_sims = gpu_sim.lorentz_similarity_batch_gpu(U, V) # Individual computations - individual_sims = np.array([ - lorentz_similarity(U[i], V[i]) for i in range(N) - ]) + individual_sims = np.array([lorentz_similarity(U[i], V[i]) for i in range(N)]) np.testing.assert_allclose(batch_sims, individual_sims, atol=1e-9) @@ -185,8 +184,7 @@ def test_matrix_self_similarity_diagonal(self): # Diagonal should be ~0.0 (self-similarity) diagonal = np.diag(sim_matrix) - assert np.allclose(diagonal, 0.0, atol=1e-6), \ - f"Diagonal should be ~0.0, got {diagonal[:5]}" + assert np.allclose(diagonal, 0.0, atol=1e-6), f"Diagonal should be ~0.0, got {diagonal[:5]}" def test_matrix_symmetry(self): """Self-similarity matrix should be symmetric.""" @@ -233,8 +231,9 @@ def test_matrix_consistency_with_pairwise(self): for j in range(M): expected = lorentz_similarity(U[i], V[j]) actual = sim_matrix[i, j] - assert np.isclose(expected, actual, atol=1e-9), \ - f"Mismatch at [{i},{j}]: {expected} vs {actual}" + assert np.isclose( + expected, actual, atol=1e-9 + ), f"Mismatch at [{i},{j}]: {expected} vs {actual}" def test_matrix_input_validation(self): """Test matrix computation input validation.""" @@ -274,19 +273,15 @@ def test_self_attention_no_self_loops(self): embeddings = np.random.randn(num_tokens, embedding_dim) # Compute attention scores (queries = keys for self-attention) - attention_scores = gpu_sim.lorentz_similarity_matrix_gpu( - embeddings, embeddings - ) + attention_scores = gpu_sim.lorentz_similarity_matrix_gpu(embeddings, embeddings) # Diagonal (self-attention) should be ~0.0 diagonal = np.diag(attention_scores) - assert np.allclose(diagonal, 0.0, atol=1e-6), \ - "Self-attention should be neutralized" + assert np.allclose(diagonal, 0.0, atol=1e-6), "Self-attention should be neutralized" # Off-diagonal should have meaningful values off_diagonal = attention_scores[np.triu_indices(num_tokens, k=1)] - assert not np.allclose(off_diagonal, 0.0), \ - "Cross-attention should have meaningful scores" + assert not np.allclose(off_diagonal, 0.0), "Cross-attention should have meaningful scores" def test_query_key_attention(self): """Test query-key attention pattern.""" diff --git a/test_pytorch_modules.py b/test_pytorch_modules.py index 7ea12f9..51e1a66 100644 --- a/test_pytorch_modules.py +++ b/test_pytorch_modules.py @@ -29,8 +29,9 @@ def test_eigen_similarity_2d_self_is_zero(self): # Diagonal should be near zero diag = torch.diagonal(sim) - assert torch.allclose(diag, torch.zeros_like(diag), atol=1e-5), \ - f"Expected diagonal ~0.0, got {diag}" + assert torch.allclose( + diag, torch.zeros_like(diag), atol=1e-5 + ), f"Expected diagonal ~0.0, got {diag}" def test_standard_cosine_2d_self_is_one(self): """Standard cosine self-similarity should be ~1.0.""" @@ -38,8 +39,9 @@ def test_standard_cosine_2d_self_is_one(self): sim = standard_cosine_similarity_torch(q, q) diag = torch.diagonal(sim) - assert torch.allclose(diag, torch.ones_like(diag), atol=1e-5), \ - f"Expected diagonal ~1.0, got {diag}" + assert torch.allclose( + diag, torch.ones_like(diag), atol=1e-5 + ), f"Expected diagonal ~1.0, got {diag}" def test_eigen_similarity_3d_self_is_zero(self): """Eigen self-similarity for sequences should be ~0.0.""" @@ -51,8 +53,9 @@ def test_eigen_similarity_3d_self_is_zero(self): # Diagonal should be near zero for each batch for b in range(4): diag = torch.diagonal(sim[b]) - assert torch.allclose(diag, torch.zeros_like(diag), atol=1e-5), \ - f"Batch {b}: Expected diagonal ~0.0, got {diag}" + assert torch.allclose( + diag, torch.zeros_like(diag), atol=1e-5 + ), f"Batch {b}: Expected diagonal ~0.0, got {diag}" def test_standard_cosine_3d_self_is_one(self): """Standard cosine for sequences should have diagonal ~1.0.""" @@ -86,16 +89,16 @@ def test_compare_self_similarity_torch(self): v = torch.randn(10, 64) result = compare_self_similarity_torch(v) - assert 'standard' in result - assert 'eigen' in result - assert 'vector_norm' in result + assert "standard" in result + assert "eigen" in result + assert "vector_norm" in result # Standard diagonal should be ~1.0 - std_diag = torch.diagonal(result['standard']) + std_diag = torch.diagonal(result["standard"]) assert torch.allclose(std_diag, torch.ones_like(std_diag), atol=1e-5) # Eigen diagonal should be ~0.0 - eigen_diag = torch.diagonal(result['eigen']) + eigen_diag = torch.diagonal(result["eigen"]) assert torch.allclose(eigen_diag, torch.zeros_like(eigen_diag), atol=1e-5) @pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available") @@ -105,7 +108,7 @@ def test_gpu_compatibility(self): k = torch.randn(32, 64).cuda() sim = eigen_similarity(q, k) - assert sim.device.type == 'cuda' + assert sim.device.type == "cuda" assert sim.shape == (16, 32) def test_numerical_stability_small_vectors(self): @@ -233,9 +236,9 @@ def test_loop_prevention_epsilon(self): @pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available") def test_gpu_device(self): """Test memory works on GPU.""" - mem = EigenMemory(dim=32, max_mem_slots=100, device='cuda') + mem = EigenMemory(dim=32, max_mem_slots=100, device="cuda") - assert mem.device.type == 'cuda' + assert mem.device.type == "cuda" x = torch.randn(10, 32).cuda() mem.write(x) @@ -243,7 +246,7 @@ def test_gpu_device(self): q = torch.randn(3, 32).cuda() retrieved = mem(q) - assert retrieved.device.type == 'cuda' + assert retrieved.device.type == "cuda" class TestEigenAttention: @@ -290,8 +293,9 @@ def test_causal_masking(self): for i in range(5): for j in range(i + 1, 5): # Position i should not attend to future position j - assert attn_weights[0, h, i, j].item() < 1e-5, \ - f"Causal mask violated: position {i} attends to {j}" + assert ( + attn_weights[0, h, i, j].item() < 1e-5 + ), f"Causal mask violated: position {i} attends to {j}" def test_external_mask_3d(self): """Test external 3D attention mask (B, L, L).""" @@ -301,7 +305,7 @@ def test_external_mask_3d(self): # Create mask that blocks position 0 from attending to position 4 mask = torch.zeros(2, 5, 5) - mask[:, 0, 4] = float('-inf') + mask[:, 0, 4] = float("-inf") _, attn_weights = attn(x, attn_mask=mask) @@ -318,7 +322,7 @@ def test_external_mask_4d(self): # 4D mask mask = torch.zeros(2, 1, 5, 5) - mask[:, :, 0, 4] = float('-inf') + mask[:, :, 0, 4] = float("-inf") _, attn_weights = attn(x, attn_mask=mask) @@ -340,12 +344,7 @@ def test_loop_prevention_epsilon(self): def test_negative_masking(self): """Test that negative similarities can be masked.""" - attn = EigenAttention( - dim=32, - num_heads=2, - mask_negative=True, - negative_floor=-10.0 - ) + attn = EigenAttention(dim=32, num_heads=2, mask_negative=True, negative_floor=-10.0) x = torch.randn(1, 5, 32) out, _ = attn(x) @@ -375,8 +374,8 @@ def test_gpu_compatibility(self): x = torch.randn(2, 10, 64).cuda() out, attn_weights = attn(x) - assert out.device.type == 'cuda' - assert attn_weights.device.type == 'cuda' + assert out.device.type == "cuda" + assert attn_weights.device.type == "cuda" def test_gradient_flow(self): """Test that gradients flow through attention.""" diff --git a/test_similarity.py b/test_similarity.py index 75f4ab4..ead34fa 100644 --- a/test_similarity.py +++ b/test_similarity.py @@ -8,11 +8,7 @@ import numpy as np import pytest -from similarity import ( - lorentz_similarity, - standard_cosine_similarity, - compare_self_similarity -) +from similarity import lorentz_similarity, standard_cosine_similarity, compare_self_similarity class TestSelfReferenceProperty: @@ -24,13 +20,14 @@ def test_standard_cosine_self_similarity_is_one(self): np.array([1.0, 0.0, 0.0]), np.array([3.0, 4.0]), np.array([1.0, 2.0, 3.0, 4.0, 5.0]), - np.random.randn(10) + np.random.randn(10), ] for v in vectors: sim = standard_cosine_similarity(v, v) - assert np.isclose(sim, 1.0, atol=1e-6), \ - f"Standard cosine self-similarity should be 1.0, got {sim}" + assert np.isclose( + sim, 1.0, atol=1e-6 + ), f"Standard cosine self-similarity should be 1.0, got {sim}" def test_lorentz_self_similarity_is_zero(self): """Lorentz-invariant similarity yields 0.0 for self-reference.""" @@ -38,26 +35,27 @@ def test_lorentz_self_similarity_is_zero(self): np.array([1.0, 0.0, 0.0]), np.array([3.0, 4.0]), np.array([1.0, 2.0, 3.0, 4.0, 5.0]), - np.random.randn(10) + np.random.randn(10), ] for v in vectors: sim = lorentz_similarity(v, v) - assert np.isclose(sim, 0.0, atol=1e-6), \ - f"Lorentz self-similarity should be 0.0, got {sim}" + assert np.isclose( + sim, 0.0, atol=1e-6 + ), f"Lorentz self-similarity should be 0.0, got {sim}" def test_comparison_function(self): """Test the comparison utility function.""" v = np.array([3.0, 4.0]) result = compare_self_similarity(v) - assert 'standard' in result - assert 'lorentz' in result - assert 'vector_norm' in result + assert "standard" in result + assert "lorentz" in result + assert "vector_norm" in result - assert np.isclose(result['standard'], 1.0, atol=1e-6) - assert np.isclose(result['lorentz'], 0.0, atol=1e-6) - assert np.isclose(result['vector_norm'], 5.0, atol=1e-6) + assert np.isclose(result["standard"], 1.0, atol=1e-6) + assert np.isclose(result["lorentz"], 0.0, atol=1e-6) + assert np.isclose(result["vector_norm"], 5.0, atol=1e-6) class TestOrthogonalVectors: @@ -164,10 +162,12 @@ def test_random_high_dimensional_self_similarity(self): standard_sim = standard_cosine_similarity(v, v) lorentz_sim = lorentz_similarity(v, v) - assert np.isclose(standard_sim, 1.0, atol=1e-6), \ - f"Dim {dim}: standard should be 1.0, got {standard_sim}" - assert np.isclose(lorentz_sim, 0.0, atol=1e-6), \ - f"Dim {dim}: Lorentz should be 0.0, got {lorentz_sim}" + assert np.isclose( + standard_sim, 1.0, atol=1e-6 + ), f"Dim {dim}: standard should be 1.0, got {standard_sim}" + assert np.isclose( + lorentz_sim, 0.0, atol=1e-6 + ), f"Dim {dim}: Lorentz should be 0.0, got {lorentz_sim}" def test_random_high_dimensional_pairs(self): """Test that different random vectors have non-trivial similarity.""" @@ -206,8 +206,7 @@ def test_iterative_self_reinforcement_standard(self): # In a naive recursive system, this weight would be multiplied # back into the system, creating potential for runaway feedback - assert standard_weight == 1.0, \ - "Standard self-weight is 1.0 - maximum reinforcement" + assert standard_weight == 1.0, "Standard self-weight is 1.0 - maximum reinforcement" def test_iterative_self_reinforcement_lorentz(self): """ @@ -223,8 +222,7 @@ def test_iterative_self_reinforcement_lorentz(self): # The neutral weight means self-reference contributes nothing, # forcing the system to incorporate external information - assert lorentz_weight == 0.0, \ - "Lorentz self-weight is 0.0 - neutral, non-reinforcing" + assert lorentz_weight == 0.0, "Lorentz self-weight is 0.0 - neutral, non-reinforcing" def test_recursive_accumulation_simulation(self): """ @@ -237,14 +235,10 @@ def test_recursive_accumulation_simulation(self): iterations = 10 # Standard cosine: accumulates self-similarity - standard_accumulation = sum( - standard_cosine_similarity(v, v) for _ in range(iterations) - ) + standard_accumulation = sum(standard_cosine_similarity(v, v) for _ in range(iterations)) # Lorentz: self-similarity doesn't accumulate - lorentz_accumulation = sum( - lorentz_similarity(v, v) for _ in range(iterations) - ) + lorentz_accumulation = sum(lorentz_similarity(v, v) for _ in range(iterations)) # Standard grows linearly with iterations assert np.isclose(standard_accumulation, iterations, atol=1e-6) diff --git a/tests/test_eigen_modules.py b/tests/test_eigen_modules.py index 656ba71..d30373e 100644 --- a/tests/test_eigen_modules.py +++ b/tests/test_eigen_modules.py @@ -131,17 +131,9 @@ def test_full_loop_prevention(self): Verify EigenAttention and EigenMemory can be composed without numerical issues. """ memory = EigenMemory( - self.dim, - max_mem_slots=20, - k_top=5, - loop_epsilon=1e-3, - device=self.device + self.dim, max_mem_slots=20, k_top=5, loop_epsilon=1e-3, device=self.device ) - attn = EigenAttention( - self.dim, - self.num_heads, - loop_epsilon=1e-3 - ).to(self.device) + attn = EigenAttention(self.dim, self.num_heads, loop_epsilon=1e-3).to(self.device) # Create a simple sequence B, L = 2, 5 @@ -170,7 +162,7 @@ def test_full_loop_prevention(self): attn_sums = attn_weights.sum(dim=-1) self.assertTrue( torch.allclose(attn_sums, torch.ones_like(attn_sums), atol=1e-5), - "Attention weights should sum to 1" + "Attention weights should sum to 1", )