Hyperbolic Embedding Engine (L1 Component) β
Advanced geometric embedding system optimized for hierarchical knowledge representation. Leverages hyperbolic geometry to preserve semantic relationships and enable efficient navigation through complex knowledge structures.
Architecture Overview β
text
ββββββββββββββββββββββββββββββββββββββββββββββββ
β Hyperbolic Engine Core β
β ββββββββββββββββββββββββββββββββββββββββββ β
β β PoincarΓ© Ball Model β β
β β β’ Hyperbolic Embeddings β β
β β β’ Distance Calculations β β
β β β’ Geodesic Path Finding β β
β β β’ Hierarchical Optimization β β
β ββββββββββββββββββ¬ββββββββββββββββββββββββ β
βββββββββββββββββββββΌβββββββββββββββββββββββββββ
β
βββββββββββββββββΌββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββ βββββββββββββββ βββββββββββββββ
βConcept β βHierarchical β β Navigation β
βEmbedder β β Optimizer β β Engine β
β β β β β β
ββ’ Train β ββ’ Tree Loss β ββ’ Geodesic β
ββ’ Embed β ββ’ Hierarchy β ββ’ Search β
ββ’ Update β ββ’ Constraint β ββ’ Pathfind β
βββββββββββ βββββββββββββββ βββββββββββββββ
Mathematical Foundation β
PoincarΓ© Ball Model Implementation β
python
import torch
import torch.nn as nn
import numpy as np
from typing import Tuple, List, Optional
class PoincareBall:
"""PoincarΓ© ball model for hyperbolic geometry operations"""
def __init__(self, dim: int, c: float = 1.0):
self.dim = dim
self.c = c # Curvature parameter
self.eps = 1e-8 # Numerical stability
def exp_map(self, x: torch.Tensor, v: torch.Tensor) -> torch.Tensor:
"""Exponential map: tangent vector to hyperbolic point"""
v_norm = torch.norm(v, dim=-1, keepdim=True)
x_norm_sq = torch.sum(x * x, dim=-1, keepdim=True)
# Compute lambda_x (conformal factor)
lambda_x = 2 / (1 - self.c * x_norm_sq + self.eps)
# Compute the exponential map
v_norm_clamped = torch.clamp(v_norm, min=self.eps)
exp_v = torch.tanh(np.sqrt(self.c) * lambda_x * v_norm_clamped / 2)
exp_v = exp_v / (np.sqrt(self.c) * v_norm_clamped + self.eps) * v
return self.mobius_add(x, exp_v)
def log_map(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
"""Logarithmic map: hyperbolic point to tangent vector"""
xy_diff = self.mobius_add(y, -x)
xy_diff_norm = torch.norm(xy_diff, dim=-1, keepdim=True)
x_norm_sq = torch.sum(x * x, dim=-1, keepdim=True)
lambda_x = 2 / (1 - self.c * x_norm_sq + self.eps)
log_factor = (2 / (np.sqrt(self.c) * lambda_x + self.eps)) * \
torch.arctanh(np.sqrt(self.c) * xy_diff_norm + self.eps)
return log_factor / (xy_diff_norm + self.eps) * xy_diff
def mobius_add(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
"""MΓΆbius addition in PoincarΓ© ball"""
x_norm_sq = torch.sum(x * x, dim=-1, keepdim=True)
y_norm_sq = torch.sum(y * y, dim=-1, keepdim=True)
xy_dot = torch.sum(x * y, dim=-1, keepdim=True)
numerator = (1 + 2 * self.c * xy_dot + self.c * y_norm_sq) * x + \
(1 - self.c * x_norm_sq) * y
denominator = 1 + 2 * self.c * xy_dot + self.c**2 * x_norm_sq * y_norm_sq
return numerator / (denominator.unsqueeze(-1) + self.eps)
def distance(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
"""Hyperbolic distance between points"""
xy_diff = self.mobius_add(y, -x)
xy_diff_norm = torch.norm(xy_diff, dim=-1)
return (2 / np.sqrt(self.c)) * torch.arctanh(
np.sqrt(self.c) * xy_diff_norm + self.eps
)
def project_to_ball(self, x: torch.Tensor, max_norm: float = 1 - 1e-3) -> torch.Tensor:
"""Project points to valid PoincarΓ© ball"""
norm = torch.norm(x, dim=-1, keepdim=True)
cond = norm >= max_norm
projected = x / norm * max_norm
return torch.where(cond, projected, x)
Distance Metrics and Optimization β
python
class HyperbolicDistanceMetrics:
"""Advanced distance calculations in hyperbolic space"""
def __init__(self, poincare_ball: PoincareBall):
self.ball = poincare_ball
def semantic_distance(self,
concept1: torch.Tensor,
concept2: torch.Tensor,
hierarchy_weight: float = 0.3) -> torch.Tensor:
"""Semantic distance incorporating hierarchical structure"""
# Base hyperbolic distance
base_distance = self.ball.distance(concept1, concept2)
# Hierarchical adjustment based on norm (distance from origin)
norm1 = torch.norm(concept1, dim=-1)
norm2 = torch.norm(concept2, dim=-1)
# Concepts closer to origin are more general/abstract
hierarchy_penalty = torch.abs(norm1 - norm2) * hierarchy_weight
return base_distance + hierarchy_penalty
def angular_similarity(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
"""Angular similarity in hyperbolic space"""
x_tangent = self.ball.log_map(torch.zeros_like(x), x)
y_tangent = self.ball.log_map(torch.zeros_like(y), y)
cos_similarity = torch.cosine_similarity(x_tangent, y_tangent, dim=-1)
return (1 + cos_similarity) / 2 # Normalize to [0, 1]
def centripetal_distance(self, x: torch.Tensor) -> torch.Tensor:
"""Distance from origin (generality measure)"""
return self.ball.distance(torch.zeros_like(x), x)
def geodesic_midpoint(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
"""Find geodesic midpoint between two points"""
t = 0.5 # Midpoint parameter
# Compute tangent vector from x to y
tangent_xy = self.ball.log_map(x, y)
# Move halfway along the geodesic
midpoint = self.ball.exp_map(x, t * tangent_xy)
return self.ball.project_to_ball(midpoint)
Concept Embedding System β
Hierarchical Concept Embedder β
python
class HyperbolicConceptEmbedder(nn.Module):
"""Neural network for learning hyperbolic concept embeddings"""
def __init__(self,
vocab_size: int,
embed_dim: int,
hierarchy_levels: int = 5,
curvature: float = 1.0):
super().__init__()
self.vocab_size = vocab_size
self.embed_dim = embed_dim
self.hierarchy_levels = hierarchy_levels
self.ball = PoincareBall(embed_dim, curvature)
self.metrics = HyperbolicDistanceMetrics(self.ball)
# Euclidean embedding layer
self.euclidean_embed = nn.Embedding(vocab_size, embed_dim)
# Hyperbolic projection networks
self.hyperbolic_proj = nn.Sequential(
nn.Linear(embed_dim, embed_dim * 2),
nn.ReLU(),
nn.Linear(embed_dim * 2, embed_dim),
nn.Tanh() # Ensure output is in valid range
)
# Hierarchy level predictor
self.hierarchy_predictor = nn.Sequential(
nn.Linear(embed_dim, embed_dim // 2),
nn.ReLU(),
nn.Linear(embed_dim // 2, 1),
nn.Sigmoid() # Output in [0, 1] for norm scaling
)
self.init_weights()
def init_weights(self):
"""Initialize weights with small values for numerical stability"""
nn.init.uniform_(self.euclidean_embed.weight, -0.01, 0.01)
for layer in self.hyperbolic_proj:
if isinstance(layer, nn.Linear):
nn.init.uniform_(layer.weight, -0.01, 0.01)
def forward(self, concept_ids: torch.Tensor) -> torch.Tensor:
"""Embed concepts in hyperbolic space"""
# Get Euclidean embeddings
euclidean_embeds = self.euclidean_embed(concept_ids)
# Project to hyperbolic space
hyperbolic_embeds = self.hyperbolic_proj(euclidean_embeds)
# Predict hierarchy level (distance from origin)
hierarchy_levels = self.hierarchy_predictor(euclidean_embeds)
# Scale embeddings based on hierarchy level
# More general concepts (lower hierarchy) β closer to origin
scaled_embeds = hyperbolic_embeds * (0.1 + 0.8 * hierarchy_levels)
# Project to valid PoincarΓ© ball
return self.ball.project_to_ball(scaled_embeds)
def embed_text(self, text_features: torch.Tensor) -> torch.Tensor:
"""Embed arbitrary text features in hyperbolic space"""
hyperbolic_embeds = self.hyperbolic_proj(text_features)
hierarchy_levels = self.hierarchy_predictor(text_features)
scaled_embeds = hyperbolic_embeds * (0.1 + 0.8 * hierarchy_levels)
return self.ball.project_to_ball(scaled_embeds)
Hierarchical Loss Functions β
python
class HyperbolicLossFunctions:
"""Specialized loss functions for hyperbolic embeddings"""
def __init__(self, poincare_ball: PoincareBall):
self.ball = poincare_ball
self.metrics = HyperbolicDistanceMetrics(poincare_ball)
def hierarchy_preserving_loss(self,
embeddings: torch.Tensor,
hierarchy_matrix: torch.Tensor,
margin: float = 1.0) -> torch.Tensor:
"""Loss that preserves hierarchical relationships"""
# hierarchy_matrix[i,j] = 1 if concept i is parent of concept j
batch_size = embeddings.shape[0]
losses = []
for i in range(batch_size):
for j in range(i+1, batch_size):
dist_ij = self.ball.distance(embeddings[i], embeddings[j])
if hierarchy_matrix[i, j] == 1: # i is parent of j
# Parent should be closer to origin (more general)
parent_dist = self.metrics.centripetal_distance(embeddings[i])
child_dist = self.metrics.centripetal_distance(embeddings[j])
# Loss if child is not farther from origin than parent
hierarchy_loss = torch.max(
torch.tensor(0.0),
margin + parent_dist - child_dist
)
losses.append(hierarchy_loss)
elif hierarchy_matrix[j, i] == 1: # j is parent of i
parent_dist = self.metrics.centripetal_distance(embeddings[j])
child_dist = self.metrics.centripetal_distance(embeddings[i])
hierarchy_loss = torch.max(
torch.tensor(0.0),
margin + parent_dist - child_dist
)
losses.append(hierarchy_loss)
return torch.mean(torch.stack(losses)) if losses else torch.tensor(0.0)
def semantic_similarity_loss(self,
anchor: torch.Tensor,
positive: torch.Tensor,
negative: torch.Tensor,
margin: float = 2.0) -> torch.Tensor:
"""Triplet loss adapted for hyperbolic space"""
pos_dist = self.ball.distance(anchor, positive)
neg_dist = self.ball.distance(anchor, negative)
loss = torch.max(
torch.tensor(0.0),
pos_dist - neg_dist + margin
)
return loss
def tree_distortion_loss(self,
embeddings: torch.Tensor,
tree_distances: torch.Tensor,
alpha: float = 1.0) -> torch.Tensor:
"""Minimize distortion between tree distances and hyperbolic distances"""
hyperbolic_distances = torch.cdist(
embeddings.unsqueeze(0),
embeddings.unsqueeze(0),
p=2
).squeeze(0)
# Use PoincarΓ© distance instead of Euclidean
batch_size = embeddings.shape[0]
hyp_dist_matrix = torch.zeros(batch_size, batch_size)
for i in range(batch_size):
for j in range(i+1, batch_size):
dist = self.ball.distance(embeddings[i], embeddings[j])
hyp_dist_matrix[i, j] = dist
hyp_dist_matrix[j, i] = dist
# Mean squared error between tree distances and hyperbolic distances
mse_loss = torch.nn.functional.mse_loss(
hyp_dist_matrix,
tree_distances
)
return alpha * mse_loss
Navigation and Search Algorithms β
Hyperbolic Search Engine β
python
class HyperbolicSearchEngine:
"""Advanced search using hyperbolic geometry"""
def __init__(self,
embedder: HyperbolicConceptEmbedder,
concept_embeddings: torch.Tensor,
concept_names: List[str]):
self.embedder = embedder
self.concept_embeddings = concept_embeddings
self.concept_names = concept_names
self.ball = embedder.ball
self.metrics = embedder.metrics
def hierarchical_search(self,
query_embedding: torch.Tensor,
k: int = 20,
hierarchy_bias: float = 0.1) -> List[Tuple[str, float]]:
"""Search with hierarchical bias towards appropriate abstraction level"""
query_level = self.metrics.centripetal_distance(query_embedding)
distances = []
for i, concept_embed in enumerate(self.concept_embeddings):
# Base semantic distance
semantic_dist = self.metrics.semantic_distance(
query_embedding, concept_embed, hierarchy_bias
)
# Hierarchy level penalty
concept_level = self.metrics.centripetal_distance(concept_embed)
level_penalty = torch.abs(query_level - concept_level) * hierarchy_bias
final_distance = semantic_dist + level_penalty
distances.append((self.concept_names[i], float(final_distance)))
# Sort by distance and return top k
distances.sort(key=lambda x: x[1])
return distances[:k]
def geodesic_path_search(self,
start_concept: str,
end_concept: str,
max_steps: int = 10) -> List[str]:
"""Find semantic path between concepts via geodesics"""
start_idx = self.concept_names.index(start_concept)
end_idx = self.concept_names.index(end_concept)
start_embed = self.concept_embeddings[start_idx]
end_embed = self.concept_embeddings[end_idx]
path = [start_concept]
current_embed = start_embed
for step in range(max_steps):
if step == max_steps - 1:
path.append(end_concept)
break
# Move along geodesic towards target
t = (step + 1) / max_steps
tangent_vector = self.ball.log_map(current_embed, end_embed)
next_embed = self.ball.exp_map(current_embed, t * tangent_vector)
# Find closest concept to this point
distances = [
(i, float(self.ball.distance(next_embed, concept_embed)))
for i, concept_embed in enumerate(self.concept_embeddings)
]
distances.sort(key=lambda x: x[1])
closest_idx = distances[0][0]
closest_name = self.concept_names[closest_idx]
if closest_name not in path:
path.append(closest_name)
current_embed = self.concept_embeddings[closest_idx]
return path
def concept_neighborhood(self,
concept: str,
radius: float = 1.0,
min_similarity: float = 0.5) -> List[Tuple[str, float]]:
"""Find concepts within hyperbolic neighborhood"""
concept_idx = self.concept_names.index(concept)
concept_embed = self.concept_embeddings[concept_idx]
neighbors = []
for i, other_embed in enumerate(self.concept_embeddings):
if i == concept_idx:
continue
distance = float(self.ball.distance(concept_embed, other_embed))
if distance <= radius:
# Convert distance to similarity score
similarity = 1.0 / (1.0 + distance)
if similarity >= min_similarity:
neighbors.append((self.concept_names[i], similarity))
neighbors.sort(key=lambda x: x[1], reverse=True)
return neighbors
Integration with Knowledge Graph β
Hybrid Graph-Hyperbolic System β
python
class HyperbolicGraphIntegration:
"""Integration between hyperbolic embeddings and knowledge graphs"""
def __init__(self,
hyperbolic_engine: HyperbolicSearchEngine,
graph_client): # Neo4j or other graph DB client
self.hyp_engine = hyperbolic_engine
self.graph_client = graph_client
def enhance_graph_with_hyperbolic(self):
"""Add hyperbolic coordinates to graph nodes"""
query = """
MATCH (c:Concept)
RETURN c.name as concept_name, id(c) as node_id
"""
results = self.graph_client.run(query)
for record in results:
concept_name = record['concept_name']
node_id = record['node_id']
if concept_name in self.hyp_engine.concept_names:
idx = self.hyp_engine.concept_names.index(concept_name)
embedding = self.hyp_engine.concept_embeddings[idx]
# Store hyperbolic coordinates in graph
update_query = """
MATCH (c:Concept) WHERE id(c) = $node_id
SET c.hyperbolic_coords = $coords,
c.hierarchy_level = $level
"""
hierarchy_level = float(
self.hyp_engine.metrics.centripetal_distance(embedding)
)
self.graph_client.run(update_query, {
'node_id': node_id,
'coords': embedding.tolist(),
'level': hierarchy_level
})
def hyperbolic_influenced_traversal(self,
start_concept: str,
max_depth: int = 3,
hyperbolic_weight: float = 0.3) -> List[str]:
"""Graph traversal influenced by hyperbolic similarity"""
query = """
MATCH path = (start:Concept {name: $start_name})-[:RELATED_TO*1..$max_depth]-(end:Concept)
WHERE start.hyperbolic_coords IS NOT NULL
AND end.hyperbolic_coords IS NOT NULL
RETURN path, end.name as end_name, end.hyperbolic_coords as end_coords
"""
results = self.graph_client.run(query, {
'start_name': start_concept,
'max_depth': max_depth
})
# Get start concept's hyperbolic embedding
start_idx = self.hyp_engine.concept_names.index(start_concept)
start_embed = self.hyp_engine.concept_embeddings[start_idx]
scored_paths = []
for record in results:
end_coords = torch.tensor(record['end_coords'])
# Combine graph path length with hyperbolic similarity
path_length = len(record['path']) - 1
hyp_distance = float(
self.hyp_engine.ball.distance(start_embed, end_coords)
)
# Weighted score combining both signals
combined_score = (1 - hyperbolic_weight) * path_length + \
hyperbolic_weight * hyp_distance
scored_paths.append((record['end_name'], combined_score))
scored_paths.sort(key=lambda x: x[1])
return [name for name, _ in scored_paths]
Provider Abstraction Layer β
Hyperbolic Backend Interface β
python
from abc import ABC, abstractmethod
from typing import Protocol, Union
class HyperbolicBackendProvider(Protocol):
"""Abstract interface for hyperbolic geometry backends"""
@abstractmethod
def embed_concepts(self, concepts: List[str]) -> torch.Tensor:
"""Embed concepts in hyperbolic space"""
pass
@abstractmethod
def compute_distance(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
"""Compute hyperbolic distance between embeddings"""
pass
@abstractmethod
def find_neighbors(self, query: torch.Tensor, k: int) -> List[Tuple[str, float]]:
"""Find k nearest neighbors in hyperbolic space"""
pass
@abstractmethod
def save_embeddings(self, path: str) -> bool:
"""Save embeddings to storage"""
pass
@abstractmethod
def load_embeddings(self, path: str) -> bool:
"""Load embeddings from storage"""
pass
class PyTorchHyperbolicProvider(HyperbolicBackendProvider):
"""PyTorch-based hyperbolic geometry implementation"""
def __init__(self, config: dict):
self.embedder = HyperbolicConceptEmbedder(**config['embedder'])
self.search_engine = None
self.config = config
def embed_concepts(self, concepts: List[str]) -> torch.Tensor:
# Convert concepts to IDs and embed
concept_ids = self._concepts_to_ids(concepts)
return self.embedder(concept_ids)
def compute_distance(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
return self.embedder.ball.distance(x, y)
# ... implement other methods
class GeometricProvider(HyperbolicBackendProvider):
"""Alternative provider using geometric libraries"""
def __init__(self, config: dict):
# Initialize with different geometric backend
self.config = config
# Could use libraries like geomstats, geoopt, etc.
# ... implement interface methods
class HyperbolicProviderFactory:
"""Factory for creating hyperbolic providers"""
_providers = {
'pytorch': PyTorchHyperbolicProvider,
'geometric': GeometricProvider,
# Add more providers as needed
}
@classmethod
def create_provider(cls, provider_type: str, config: dict) -> HyperbolicBackendProvider:
if provider_type not in cls._providers:
raise ValueError(f"Unknown provider type: {provider_type}")
return cls._providers[provider_type](config)
Performance and Optimization β
Computational Efficiency β
python
class HyperbolicOptimization:
"""Performance optimizations for hyperbolic computations"""
@staticmethod
def batch_distance_computation(embeddings1: torch.Tensor,
embeddings2: torch.Tensor,
ball: PoincareBall) -> torch.Tensor:
"""Efficiently compute pairwise distances"""
# Vectorized MΓΆbius operations for better performance
batch_size1, batch_size2 = embeddings1.shape[0], embeddings2.shape[0]
# Expand for broadcasting
x_expanded = embeddings1.unsqueeze(1).expand(-1, batch_size2, -1)
y_expanded = embeddings2.unsqueeze(0).expand(batch_size1, -1, -1)
# Vectorized distance computation
distances = torch.zeros(batch_size1, batch_size2)
for i in range(batch_size1):
for j in range(batch_size2):
distances[i, j] = ball.distance(
x_expanded[i, j],
y_expanded[i, j]
)
return distances
@staticmethod
def approximate_distance(x: torch.Tensor,
y: torch.Tensor,
tolerance: float = 1e-3) -> torch.Tensor:
"""Fast approximate hyperbolic distance"""
# Use first-order approximation for small distances
diff = x - y
diff_norm = torch.norm(diff, dim=-1)
if diff_norm < tolerance:
# Linear approximation for small distances
return diff_norm
else:
# Fall back to exact computation
return PoincareBall(x.shape[-1]).distance(x, y)
Training and Evaluation β
Training Pipeline β
python
class HyperbolicTrainingPipeline:
"""Complete training pipeline for hyperbolic embeddings"""
def __init__(self,
embedder: HyperbolicConceptEmbedder,
loss_functions: HyperbolicLossFunctions,
config: dict):
self.embedder = embedder
self.loss_functions = loss_functions
self.config = config
self.optimizer = torch.optim.Adam(
embedder.parameters(),
lr=config['learning_rate']
)
def train_epoch(self,
concept_data: List[Tuple[str, str, int]], # (parent, child, hierarchy_level)
similarity_data: List[Tuple[str, str, float]]) -> float:
"""Train one epoch on hierarchical and similarity data"""
total_loss = 0.0
batch_size = self.config['batch_size']
# Process hierarchical relationships
for batch_start in range(0, len(concept_data), batch_size):
batch = concept_data[batch_start:batch_start + batch_size]
# Convert to embeddings
parent_embeds = []
child_embeds = []
for parent, child, level in batch:
parent_embed = self._get_concept_embedding(parent)
child_embed = self._get_concept_embedding(child)
parent_embeds.append(parent_embed)
child_embeds.append(child_embed)
parent_tensor = torch.stack(parent_embeds)
child_tensor = torch.stack(child_embeds)
# Create hierarchy matrix
hierarchy_matrix = torch.zeros(len(batch), len(batch))
for i, (_, _, _) in enumerate(batch):
hierarchy_matrix[i, i] = 1 # Each parent-child pair
# Compute hierarchical loss
hier_loss = self.loss_functions.hierarchy_preserving_loss(
torch.cat([parent_tensor, child_tensor]),
hierarchy_matrix
)
self.optimizer.zero_grad()
hier_loss.backward()
self.optimizer.step()
total_loss += float(hier_loss)
return total_loss / max(len(concept_data), 1)
def evaluate_embedding_quality(self, test_data: List) -> dict:
"""Evaluate quality of learned embeddings"""
metrics = {
'hierarchy_preservation': 0.0,
'semantic_coherence': 0.0,
'tree_distortion': 0.0
}
# Implement evaluation metrics
# ... evaluation logic
return metrics
Related Links β
Explore related documentation:
- Noosphere Layer - README - π Noosphere Layer - README | Step-by-step tutorial for Mnemoverse AI memory engine. Learn spatial memory concepts with practical examples.
- AI Staff - π AI Staff | Step-by-step tutorial for Mnemoverse AI memory engine. Learn spatial memory concepts with practical examples.
- Architecture - π Architecture | Step-by-step tutorial for Mnemoverse AI memory engine. Learn spatial memory concepts with practical examples.
- Knowledge Graph - π Knowledge Graph | Step-by-step tutorial for Mnemoverse AI memory engine. Learn spatial memory concepts with practical examples.
- MCP Integration - π MCP Integration | Step-by-step tutorial for Mnemoverse AI memory engine. Learn spatial memory concepts with practical examples.