use crate::{MemoryId, Result};
use std::collections::{HashMap, HashSet};
#[derive(Clone, Debug)]
pub struct Concept {
pub id: MemoryId,
pub name: String,
pub activation: f64,
pub related_concepts: HashSet<MemoryId>,
}
pub struct ConceptGraph {
concepts: HashMap<MemoryId, Concept>,
relationships: HashMap<(MemoryId, MemoryId), f64>, }
impl ConceptGraph {
pub fn new() -> Self {
Self {
concepts: HashMap::new(),
relationships: HashMap::new(),
}
}
pub fn add_concept(&mut self, concept: Concept) {
self.concepts.insert(concept.id, concept);
}
pub fn add_relationship(&mut self, from_id: MemoryId, to_id: MemoryId, strength: f64) {
self.relationships.insert((from_id, to_id), strength);
if let Some(concept) = self.concepts.get_mut(&from_id) {
concept.related_concepts.insert(to_id);
}
if let Some(concept) = self.concepts.get_mut(&to_id) {
concept.related_concepts.insert(from_id);
}
}
pub fn get_related(&self, id: MemoryId) -> Vec<&Concept> {
self.concepts
.get(&id)
.map(|concept| {
concept
.related_concepts
.iter()
.filter_map(|rel_id| self.concepts.get(rel_id))
.collect()
})
.unwrap_or_default()
}
pub fn activate(&mut self, id: MemoryId, amount: f64) {
if let Some(concept) = self.concepts.get_mut(&id) {
concept.activation += amount;
let related: Vec<MemoryId> = concept.related_concepts.iter().copied().collect();
for rel_id in related {
if let Some(rel_concept) = self.concepts.get_mut(&rel_id) {
rel_concept.activation += amount * 0.5;
}
}
}
}
pub fn len(&self) -> usize {
self.concepts.len()
}
pub fn is_empty(&self) -> bool {
self.concepts.is_empty()
}
}
impl Default for ConceptGraph {
fn default() -> Self {
Self::new()
}
}
pub struct SemanticMemory {
graph: ConceptGraph,
}
impl SemanticMemory {
pub fn new() -> Self {
Self {
graph: ConceptGraph::new(),
}
}
pub fn store_concept(&mut self, concept: Concept) -> Result<()> {
self.graph.add_concept(concept);
Ok(())
}
pub fn len(&self) -> usize {
self.graph.len()
}
pub fn is_empty(&self) -> bool {
self.graph.is_empty()
}
pub fn graph(&self) -> &ConceptGraph {
&self.graph
}
pub fn graph_mut(&mut self) -> &mut ConceptGraph {
&mut self.graph
}
}
impl Default for SemanticMemory {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
use super::*;
#[test]
fn test_concept_storage() {
let mut sm = SemanticMemory::new();
let concept = Concept {
id: 1,
name: "test".to_string(),
activation: 0.5,
related_concepts: HashSet::new(),
};
sm.store_concept(concept).unwrap();
assert_eq!(sm.len(), 1);
}
#[test]
fn test_activation_spreading() {
let mut graph = ConceptGraph::new();
let c1 = Concept {
id: 1,
name: "A".to_string(),
activation: 0.0,
related_concepts: HashSet::new(),
};
let c2 = Concept {
id: 2,
name: "B".to_string(),
activation: 0.0,
related_concepts: HashSet::new(),
};
graph.add_concept(c1);
graph.add_concept(c2);
graph.add_relationship(1, 2, 0.8);
graph.activate(1, 1.0);
assert!(graph.concepts.get(&1).unwrap().activation >= 1.0);
assert!(graph.concepts.get(&2).unwrap().activation > 0.0);
}
}