1use exo_core::{Error, ManifoldConfig, ManifoldDelta, Pattern, Result, SearchResult};
24use parking_lot::RwLock;
25use std::sync::Arc;
26
27mod network;
28mod retrieval;
29mod deformation;
30mod forgetting;
31
32pub use network::LearnedManifold;
33pub use retrieval::GradientDescentRetriever;
34pub use deformation::ManifoldDeformer;
35pub use forgetting::StrategicForgetting;
36
37pub struct ManifoldEngine {
39 network: Arc<RwLock<LearnedManifold>>,
41 config: ManifoldConfig,
43 patterns: Arc<RwLock<Vec<Pattern>>>,
45}
46
47impl ManifoldEngine {
48 pub fn new(config: ManifoldConfig) -> Self {
50 let network = LearnedManifold::new(
51 config.dimension,
52 config.hidden_dim,
53 config.hidden_layers,
54 );
55
56 Self {
57 network: Arc::new(RwLock::new(network)),
58 config,
59 patterns: Arc::new(RwLock::new(Vec::new())),
60 }
61 }
62
63 pub fn retrieve(&self, query: &[f32], k: usize) -> Result<Vec<SearchResult>> {
65 if query.len() != self.config.dimension {
66 return Err(Error::InvalidDimension {
67 expected: self.config.dimension,
68 got: query.len(),
69 });
70 }
71
72 let retriever = GradientDescentRetriever::new(
73 self.network.clone(),
74 self.config.clone(),
75 );
76
77 retriever.retrieve(query, k, &self.patterns)
78 }
79
80 pub fn deform(&mut self, pattern: Pattern, salience: f32) -> Result<ManifoldDelta> {
82 if pattern.embedding.len() != self.config.dimension {
83 return Err(Error::InvalidDimension {
84 expected: self.config.dimension,
85 got: pattern.embedding.len(),
86 });
87 }
88
89 self.patterns.write().push(pattern.clone());
91
92 let mut deformer = ManifoldDeformer::new(
93 self.network.clone(),
94 self.config.learning_rate,
95 );
96
97 deformer.deform(&pattern, salience)
98 }
99
100 pub fn forget(&mut self, salience_threshold: f32, decay_rate: f32) -> Result<usize> {
102 let forgetter = StrategicForgetting::new(self.network.clone());
103
104 forgetter.forget(
105 &self.patterns,
106 salience_threshold,
107 decay_rate,
108 )
109 }
110
111 pub fn len(&self) -> usize {
113 self.patterns.read().len()
114 }
115
116 pub fn is_empty(&self) -> bool {
118 self.patterns.read().is_empty()
119 }
120
121 pub fn config(&self) -> &ManifoldConfig {
123 &self.config
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use exo_core::{Metadata, PatternId, SubstrateTime};
131
132 fn create_test_pattern(embedding: Vec<f32>, salience: f32) -> Pattern {
133 Pattern {
134 id: PatternId::new(),
135 embedding,
136 metadata: Metadata::default(),
137 timestamp: SubstrateTime::now(),
138 antecedents: vec![],
139 salience,
140 }
141 }
142
143 #[test]
144 fn test_manifold_engine_creation() {
145 let config = ManifoldConfig {
146 dimension: 128,
147 ..Default::default()
148 };
149 let engine = ManifoldEngine::new(config);
150
151 assert_eq!(engine.len(), 0);
152 assert!(engine.is_empty());
153 assert_eq!(engine.config().dimension, 128);
154 }
155
156 #[test]
157 fn test_deform_and_retrieve() {
158 let config = ManifoldConfig {
159 dimension: 64,
160 max_descent_steps: 10,
161 learning_rate: 0.01,
162 ..Default::default()
163 };
164 let mut engine = ManifoldEngine::new(config);
165
166 let embedding = vec![1.0; 64];
168 let pattern = create_test_pattern(embedding.clone(), 0.9);
169
170 let result = engine.deform(pattern, 0.9);
171 assert!(result.is_ok());
172 assert_eq!(engine.len(), 1);
173
174 let results = engine.retrieve(&embedding, 1);
176 assert!(results.is_ok());
177 }
178
179 #[test]
180 fn test_invalid_dimension() {
181 let config = ManifoldConfig {
182 dimension: 128,
183 ..Default::default()
184 };
185 let mut engine = ManifoldEngine::new(config);
186
187 let embedding = vec![1.0; 64];
189 let pattern = create_test_pattern(embedding.clone(), 0.9);
190
191 let result = engine.deform(pattern, 0.9);
192 assert!(result.is_err());
193
194 let retrieve_result = engine.retrieve(&embedding, 1);
195 assert!(retrieve_result.is_err());
196 }
197}