IA / Cortex /memory /associative.py
Barouia's picture
Update Cortex/memory/associative.py
874c890 verified
Raw
History Blame
8.14 kB
import asyncio
import numpy as np
from typing import Dict, List, Any, Optional, Set
import logging
from dataclasses import dataclass
import networkx as nx
from collections import defaultdict
import re
@dataclass
class Association:
"""Représente une association entre concepts"""
source: str
target: str
strength: float # 0.0 à 1.0
type: str # 'semantic', 'temporal', 'emotional', 'causal'
created_at: float
last_accessed: float
class AssociativeMemory:
"""
Mémoire associative avec réseaux sémantiques
et mécanismes de rappel par similarité
"""
def __init__(self):
self.logger = logging.getLogger("associative_memory")
self.associations: Dict[str, List[Association]] = defaultdict(list)
self.concept_vectors: Dict[str, np.ndarray] = {}
self.semantic_network = nx.Graph()
self.activation_threshold = 0.3
self.spreading_activation_depth = 3
async def initialize(self):
"""Initialise la mémoire associative"""
self.logger.info("🧠 Initialisation de la mémoire associative...")
try:
await self._load_semantic_primitives()
await self._build_initial_network()
self.logger.info("✅ Mémoire associative initialisée")
return True
except Exception as e:
self.logger.error(f"❌ Erreur d'initialisation associative: {e}")
return False
async def create_association(self, concept_a: str, concept_b: str,
association_type: str = "semantic",
strength: float = 0.5) -> bool:
"""Crée une association entre deux concepts"""
try:
# Vérifie si l'association existe déjà
existing = await self._find_association(concept_a, concept_b)
if existing:
# Renforce l'association existante
existing.strength = min(1.0, existing.strength + 0.1)
existing.last_accessed = asyncio.get_event_loop().time()
return True
# Crée une nouvelle association
association = Association(
source=concept_a,
target=concept_b,
strength=strength,
type=association_type,
created_at=asyncio.get_event_loop().time(),
last_accessed=asyncio.get_event_loop().time()
)
# Ajoute dans les deux directions
self.associations[concept_a].append(association)
self.associations[concept_b].append(Association(
source=concept_b,
target=concept_a,
strength=strength,
type=association_type,
created_at=association.created_at,
last_accessed=association.last_accessed
))
# Met à jour le réseau sémantique
self.semantic_network.add_edge(concept_a, concept_b,
weight=strength, type=association_type)
# Met à jour les vecteurs conceptuels
await self._update_concept_vectors(concept_a, concept_b)
self.logger.info(f"🔗 Association créée: {concept_a}{concept_b} ({association_type})")
return True
except Exception as e:
self.logger.error(f"Erreur création association: {e}")
return False
async def get_associations(self, concept: str, max_results: int = 10) -> List[Dict[str, Any]]:
"""Récupère les associations d'un concept"""
try:
if concept not in self.associations:
return []
associations = self.associations[concept]
# Trie par force et récence
associations.sort(key=lambda a: (a.strength, a.last_accessed), reverse=True)
results = []
for assoc in associations[:max_results]:
results.append({
'target': assoc.target,
'strength': assoc.strength,
'type': assoc.type,
'last_accessed': assoc.last_accessed
})
return results
except Exception as e:
self.logger.error(f"Erreur récupération associations: {e}")
return []
async def pattern_completion(self, partial_pattern: List[str], context: Dict[str, Any] = None) -> List[str]:
"""Complète un pattern partiel basé sur les associations"""
try:
completions = []
for concept in partial_pattern:
associations = await self.get_associations(concept, max_results=20)
for assoc in associations:
if assoc['target'] not in partial_pattern and assoc['target'] not in completions:
# Calcule un score de pertinence
relevance_score = await self._calculate_relevance_score(
assoc['target'], partial_pattern, context
)
if relevance_score > self.activation_threshold:
completions.append(assoc['target'])
# Trie par pertinence
scored_completions = []
for completion in completions:
score = await self._calculate_relevance_score(completion, partial_pattern, context)
scored_completions.append((score, completion))
scored_completions.sort(reverse=True)
return [comp for score, comp in scored_completions[:10]]
except Exception as e:
self.logger.error(f"Erreur complétion pattern: {e}")
return []
async def spreading_activation(self, start_concepts: List[str], depth: int = 3) -> Dict[str, float]:
"""Simule l'activation propagée dans le réseau sémantique"""
try:
activation_levels = defaultdict(float)
# Activation initiale
for concept in start_concepts:
activation_levels[concept] = 1.0
# Propagation sur plusieurs niveaux
for current_depth in range(depth):
next_activation = activation_levels.copy()
for concept, activation in activation_levels.items():
if activation < 0.1: # Seuil d'activation minimal
continue
associations = await self.get_associations(concept, max_results=20)
for assoc in associations:
# Propagation avec décroissance
propagation_strength = activation * assoc['strength'] * 0.7
# Mise à jour de l'activation
if assoc['target'] not in start_concepts:
next_activation[assoc['target']] = max(
next_activation[assoc['target']],
propagation_strength
)
activation_levels = next_activation
# Filtre les concepts avec activation significative
significant_activations = {
concept: activation
for concept, activation in activation_levels.items()
if activation > self.activation_threshold
}
return dict(sorted(significant_activations.items(),
key=lambda x: x[1], reverse=True))
except Exception as e:
self.logger.error(f"Erreur activation propagée: {e}")
return {}
async def semantic_similarity(self,