1use crate::{MemoryId, Result};
4use std::collections::{HashMap, HashSet};
5
6#[derive(Clone, Debug)]
8pub struct Concept {
9 pub id: MemoryId,
10 pub name: String,
11 pub activation: f64,
12 pub related_concepts: HashSet<MemoryId>,
13}
14
15pub struct ConceptGraph {
17 concepts: HashMap<MemoryId, Concept>,
18 relationships: HashMap<(MemoryId, MemoryId), f64>, }
20
21impl ConceptGraph {
22 pub fn new() -> Self {
24 Self {
25 concepts: HashMap::new(),
26 relationships: HashMap::new(),
27 }
28 }
29
30 pub fn add_concept(&mut self, concept: Concept) {
32 self.concepts.insert(concept.id, concept);
33 }
34
35 pub fn add_relationship(&mut self, from_id: MemoryId, to_id: MemoryId, strength: f64) {
37 self.relationships.insert((from_id, to_id), strength);
38
39 if let Some(concept) = self.concepts.get_mut(&from_id) {
41 concept.related_concepts.insert(to_id);
42 }
43 if let Some(concept) = self.concepts.get_mut(&to_id) {
44 concept.related_concepts.insert(from_id);
45 }
46 }
47
48 pub fn get_related(&self, id: MemoryId) -> Vec<&Concept> {
50 self.concepts
51 .get(&id)
52 .map(|concept| {
53 concept
54 .related_concepts
55 .iter()
56 .filter_map(|rel_id| self.concepts.get(rel_id))
57 .collect()
58 })
59 .unwrap_or_default()
60 }
61
62 pub fn activate(&mut self, id: MemoryId, amount: f64) {
64 if let Some(concept) = self.concepts.get_mut(&id) {
65 concept.activation += amount;
66
67 let related: Vec<MemoryId> = concept.related_concepts.iter().copied().collect();
69 for rel_id in related {
70 if let Some(rel_concept) = self.concepts.get_mut(&rel_id) {
71 rel_concept.activation += amount * 0.5;
73 }
74 }
75 }
76 }
77
78 pub fn len(&self) -> usize {
80 self.concepts.len()
81 }
82
83 pub fn is_empty(&self) -> bool {
85 self.concepts.is_empty()
86 }
87}
88
89impl Default for ConceptGraph {
90 fn default() -> Self {
91 Self::new()
92 }
93}
94
95pub struct SemanticMemory {
97 graph: ConceptGraph,
98}
99
100impl SemanticMemory {
101 pub fn new() -> Self {
103 Self {
104 graph: ConceptGraph::new(),
105 }
106 }
107
108 pub fn store_concept(&mut self, concept: Concept) -> Result<()> {
110 self.graph.add_concept(concept);
111 Ok(())
112 }
113
114 pub fn len(&self) -> usize {
116 self.graph.len()
117 }
118
119 pub fn is_empty(&self) -> bool {
121 self.graph.is_empty()
122 }
123
124 pub fn graph(&self) -> &ConceptGraph {
126 &self.graph
127 }
128
129 pub fn graph_mut(&mut self) -> &mut ConceptGraph {
131 &mut self.graph
132 }
133}
134
135impl Default for SemanticMemory {
136 fn default() -> Self {
137 Self::new()
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
145 use super::*;
146
147 #[test]
148 fn test_concept_storage() {
149 let mut sm = SemanticMemory::new();
150
151 let concept = Concept {
152 id: 1,
153 name: "test".to_string(),
154 activation: 0.5,
155 related_concepts: HashSet::new(),
156 };
157
158 sm.store_concept(concept).unwrap();
159 assert_eq!(sm.len(), 1);
160 }
161
162 #[test]
163 fn test_activation_spreading() {
164 let mut graph = ConceptGraph::new();
165
166 let c1 = Concept {
168 id: 1,
169 name: "A".to_string(),
170 activation: 0.0,
171 related_concepts: HashSet::new(),
172 };
173 let c2 = Concept {
174 id: 2,
175 name: "B".to_string(),
176 activation: 0.0,
177 related_concepts: HashSet::new(),
178 };
179
180 graph.add_concept(c1);
181 graph.add_concept(c2);
182 graph.add_relationship(1, 2, 0.8);
183
184 graph.activate(1, 1.0);
186
187 assert!(graph.concepts.get(&1).unwrap().activation >= 1.0);
189 assert!(graph.concepts.get(&2).unwrap().activation > 0.0);
190 }
191}