1use thiserror::Error;
7
8#[derive(Error, Debug)]
10pub enum NSRError {
11 #[error("Perception error: {0}")]
13 Perception(#[from] PerceptionError),
14
15 #[error("Parser error: {0}")]
17 Parser(#[from] ParserError),
18
19 #[error("Program error: {0}")]
21 Program(#[from] ProgramError),
22
23 #[error("Learning error: {0}")]
25 Learning(#[from] LearningError),
26
27 #[error("GSS error: {0}")]
29 GSS(#[from] GSSError),
30
31 #[error("MCTS error: {0}")]
33 MCTS(#[from] MCTSError),
34
35 #[error("LLM synthesis error: {0}")]
37 LLMSynthesis(#[from] LLMSynthesisError),
38
39 #[error("VSA error: {0}")]
41 VSA(#[from] VSAError),
42
43 #[error("Configuration error: {message}")]
45 Config { message: String },
46
47 #[error("IO error: {0}")]
49 IO(#[from] std::io::Error),
50
51 #[error("Internal error: {message}")]
53 Internal { message: String },
54}
55
56#[derive(Error, Debug)]
58pub enum PerceptionError {
59 #[error("Unknown symbol: {symbol_id}")]
60 UnknownSymbol { symbol_id: usize },
61
62 #[error("Embedding dimension mismatch: expected {expected}, got {actual}")]
63 DimensionMismatch { expected: usize, actual: usize },
64
65 #[error("Empty input sequence")]
66 EmptyInput,
67
68 #[error("Invalid input type for modality: {message}")]
69 InvalidInputType { message: String },
70
71 #[error("Training failed: {message}")]
72 TrainingFailed { message: String },
73
74 #[error("Vocabulary not initialized")]
75 VocabularyNotInitialized,
76}
77
78#[derive(Error, Debug)]
80pub enum ParserError {
81 #[error("Invalid transition: {transition} in state {state}")]
82 InvalidTransition { transition: String, state: String },
83
84 #[error("Parse failed: could not find valid parse for input")]
85 ParseFailed,
86
87 #[error("Empty stack during parsing")]
88 EmptyStack,
89
90 #[error("Buffer underflow during parsing")]
91 BufferUnderflow,
92
93 #[error("Cycle detected in dependency structure")]
94 CycleDetected,
95
96 #[error("Non-projective structure not supported")]
97 NonProjective,
98}
99
100#[derive(Error, Debug)]
102pub enum ProgramError {
103 #[error("Type error: expected {expected}, got {actual}")]
104 TypeError { expected: String, actual: String },
105
106 #[error("Division by zero")]
107 DivisionByZero,
108
109 #[error("Undefined variable: {name}")]
110 UndefinedVariable { name: String },
111
112 #[error("Invalid primitive: {name}")]
113 InvalidPrimitive { name: String },
114
115 #[error("Stack overflow: maximum recursion depth {depth} exceeded")]
116 StackOverflow { depth: usize },
117
118 #[error("Arity mismatch: {name} expected {expected} arguments, got {actual}")]
119 ArityMismatch {
120 name: String,
121 expected: usize,
122 actual: usize,
123 },
124
125 #[error("Synthesis failed: {message}")]
126 SynthesisFailed { message: String },
127
128 #[error("Program too deep: depth {depth} exceeds maximum {max_depth}")]
129 ProgramTooDeep { depth: usize, max_depth: usize },
130}
131
132#[derive(Error, Debug)]
134pub enum LearningError {
135 #[error("Abduction failed: could not find satisfying GSS after {attempts} attempts")]
136 AbductionFailed { attempts: usize },
137
138 #[error("Training diverged: loss {loss} exceeds threshold")]
139 TrainingDiverged { loss: f64 },
140
141 #[error("No training examples provided")]
142 NoExamples,
143
144 #[error("Convergence failed: {message}")]
145 ConvergenceFailed { message: String },
146
147 #[error("Invalid learning rate: {rate}")]
148 InvalidLearningRate { rate: f64 },
149
150 #[error("Curriculum violation: example difficulty {difficulty} exceeds current level {level}")]
151 CurriculumViolation { difficulty: f64, level: f64 },
152}
153
154#[derive(Error, Debug)]
156pub enum GSSError {
157 #[error("Invalid node ID: {node_id}")]
158 InvalidNodeId { node_id: usize },
159
160 #[error("Invalid edge: {from} -> {to}")]
161 InvalidEdge { from: usize, to: usize },
162
163 #[error("Cycle detected in GSS")]
164 CycleDetected,
165
166 #[error("Missing root node")]
167 MissingRoot,
168
169 #[error("Orphaned node: {node_id}")]
170 OrphanedNode { node_id: usize },
171
172 #[error("Semantic computation failed at node {node_id}: {message}")]
173 SemanticComputationFailed { node_id: usize, message: String },
174}
175
176#[derive(Error, Debug)]
178pub enum MCTSError {
179 #[error("Search budget exhausted: {simulations} simulations with no improvement")]
180 BudgetExhausted { simulations: usize },
181
182 #[error("No valid actions from state")]
183 NoValidActions,
184
185 #[error("Value network failed: {message}")]
186 ValueNetworkFailed { message: String },
187
188 #[error("Policy network failed: {message}")]
189 PolicyNetworkFailed { message: String },
190
191 #[error("Tree size exceeded maximum: {size} > {max_size}")]
192 TreeSizeExceeded { size: usize, max_size: usize },
193}
194
195#[derive(Error, Debug)]
197pub enum VSAError {
198 #[error("Empty vector list: cannot bundle empty vector list")]
199 EmptyVectorList,
200
201 #[error("Invalid dimension: {dimension} (must be greater than zero)")]
202 InvalidDimension { dimension: usize },
203
204 #[error("Dimension mismatch: expected {expected}, got {actual}")]
205 DimensionMismatch { expected: usize, actual: usize },
206
207 #[error("Symbol not found in codebook: {symbol}")]
208 SymbolNotFound { symbol: String },
209
210 #[error("Invalid similarity threshold: {threshold} (must be in range [0, 1])")]
211 InvalidThreshold { threshold: f64 },
212
213 #[error("Invalid sparsity: {sparsity} (must be in range [0.0, 1.0))")]
214 InvalidSparsity { sparsity: f64 },
215
216 #[error("Memory capacity exceeded: {size} items exceeds capacity of {capacity}")]
217 CapacityExceeded { size: usize, capacity: usize },
218}
219
220#[derive(Error, Debug)]
222pub enum LLMSynthesisError {
223 #[error("LLM API error: {message}")]
224 APIError { message: String },
225
226 #[error("Rate limited: retry after {retry_after_secs} seconds")]
227 RateLimited { retry_after_secs: u64 },
228
229 #[error("Invalid response format: {message}")]
230 InvalidResponse { message: String },
231
232 #[error("Verification failed: program does not satisfy specification")]
233 VerificationFailed,
234
235 #[error("Parse error: could not parse generated program: {message}")]
236 ParseError { message: String },
237
238 #[error("Timeout: LLM did not respond within {timeout_secs} seconds")]
239 Timeout { timeout_secs: u64 },
240
241 #[error("Context length exceeded: {tokens} tokens > {max_tokens} maximum")]
242 ContextLengthExceeded { tokens: usize, max_tokens: usize },
243}
244
245pub type NSRResult<T> = Result<T, NSRError>;
247
248pub trait ErrorContext<T> {
250 fn context(self, message: impl Into<String>) -> NSRResult<T>;
252
253 fn with_context<F: FnOnce() -> String>(self, f: F) -> NSRResult<T>;
255}
256
257impl<T, E: Into<NSRError>> ErrorContext<T> for Result<T, E> {
258 fn context(self, message: impl Into<String>) -> NSRResult<T> {
259 self.map_err(|e| {
260 let inner = e.into();
261 NSRError::Internal {
262 message: format!("{}: {}", message.into(), inner),
263 }
264 })
265 }
266
267 fn with_context<F: FnOnce() -> String>(self, f: F) -> NSRResult<T> {
268 self.map_err(|e| {
269 let inner = e.into();
270 NSRError::Internal {
271 message: format!("{}: {}", f(), inner),
272 }
273 })
274 }
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 #[test]
282 fn test_error_display() {
283 let err = PerceptionError::UnknownSymbol { symbol_id: 42 };
284 assert_eq!(err.to_string(), "Unknown symbol: 42");
285
286 let err = ProgramError::TypeError {
287 expected: "Integer".to_string(),
288 actual: "String".to_string(),
289 };
290 assert_eq!(err.to_string(), "Type error: expected Integer, got String");
291 }
292
293 #[test]
294 fn test_error_conversion() {
295 let perception_err = PerceptionError::EmptyInput;
296 let nsr_err: NSRError = perception_err.into();
297 assert!(matches!(nsr_err, NSRError::Perception(_)));
298 }
299
300 #[test]
301 fn test_error_context() {
302 let result: Result<(), PerceptionError> = Err(PerceptionError::EmptyInput);
303 let contextualized = result.context("During symbol grounding");
304 assert!(contextualized.is_err());
305 }
306}