1use thiserror::Error;
9
10#[derive(Error, Debug, Clone, PartialEq)]
12pub enum SVMError {
13 #[error("Invalid input data: {message}")]
16 InvalidInput {
17 message: String,
18 suggestion: Option<String>,
19 },
20
21 #[error("Dimension mismatch in {context}: expected {expected_str}, got {actual_str}")]
23 DimensionMismatch {
24 expected: Vec<usize>,
25 actual: Vec<usize>,
26 context: String,
27 expected_str: String,
28 actual_str: String,
29 },
30
31 #[error("Empty dataset: cannot train on zero samples")]
33 EmptyDataset { context: String },
34
35 #[error("Invalid labels: {reason}")]
37 InvalidLabels { reason: String, suggestion: String },
38
39 #[error("Insufficient data: need at least {required} samples, got {actual}")]
41 InsufficientData {
42 required: usize,
43 actual: usize,
44 context: String,
45 },
46
47 #[error("Invalid hyperparameter '{parameter}': {reason}")]
50 InvalidHyperparameter {
51 parameter: String,
52 value: String,
53 reason: String,
54 valid_range: Option<String>,
55 },
56
57 #[error("Invalid kernel configuration: {message}")]
59 InvalidKernel {
60 kernel_type: String,
61 message: String,
62 suggestion: String,
63 },
64
65 #[error("Invalid solver configuration for {solver}: {reason}")]
67 InvalidSolver {
68 solver: String,
69 reason: String,
70 compatible_solvers: Vec<String>,
71 },
72
73 #[error("Training failed to converge after {iterations} iterations")]
76 ConvergenceFailure {
77 iterations: usize,
78 final_objective: Option<f64>,
79 tolerance: f64,
80 suggestions: Vec<String>,
81 },
82
83 #[error("Numerical instability detected: {issue}")]
85 NumericalInstability {
86 issue: String,
87 context: String,
88 suggestions: Vec<String>,
89 },
90
91 #[error("Optimization algorithm '{algorithm}' failed: {reason}")]
93 OptimizationFailure {
94 algorithm: String,
95 reason: String,
96 iteration: Option<usize>,
97 objective_value: Option<f64>,
98 },
99
100 #[error("Optimization problem is infeasible: {reason}")]
102 InfeasibleProblem {
103 reason: String,
104 suggestions: Vec<String>,
105 },
106
107 #[error("Kernel matrix computation failed: {reason}")]
110 KernelComputationError {
111 kernel_type: String,
112 reason: String,
113 sample_indices: Option<Vec<usize>>,
114 },
115
116 #[error("Kernel matrix is not positive semidefinite")]
118 NonPositiveSemidefiniteKernel {
119 eigenvalue_info: Option<String>,
120 suggestions: Vec<String>,
121 },
122
123 #[error("Kernel cache error: {operation} failed")]
125 KernelCacheError {
126 operation: String,
127 reason: String,
128 memory_usage: Option<usize>,
129 },
130
131 #[error("Out of memory during {operation}")]
134 OutOfMemory {
135 operation: String,
136 requested_bytes: Option<usize>,
137 available_bytes: Option<usize>,
138 suggestions: Vec<String>,
139 },
140
141 #[error("Insufficient computational resources: {resource}")]
143 InsufficientResources {
144 resource: String,
145 required: String,
146 available: String,
147 },
148
149 #[error("Memory allocation failed for {purpose}: {reason}")]
151 AllocationError {
152 purpose: String,
153 reason: String,
154 size_bytes: Option<usize>,
155 },
156
157 #[error("Model not trained: call fit() before predict()")]
160 ModelNotTrained {
161 operation: String,
162 suggestions: Vec<String>,
163 },
164
165 #[error("Prediction failed: {reason}")]
167 PredictionError {
168 reason: String,
169 sample_count: Option<usize>,
170 context: String,
171 },
172
173 #[error("Model state inconsistency detected: {issue}")]
175 ModelStateInconsistency { issue: String, context: String },
176
177 #[error("Parallel processing error in {operation}: {reason}")]
180 ParallelProcessingError {
181 operation: String,
182 reason: String,
183 thread_count: Option<usize>,
184 },
185
186 #[error("Thread synchronization error: {details}")]
188 SynchronizationError { details: String, operation: String },
189
190 #[error("GPU computation error: {reason}")]
193 GpuError {
194 reason: String,
195 device_info: Option<String>,
196 fallback_available: bool,
197 },
198
199 #[error("SIMD operation error: {operation} failed")]
201 SimdError {
202 operation: String,
203 reason: String,
204 fallback_used: bool,
205 },
206
207 #[error("Model serialization error: {operation}")]
210 SerializationError {
211 operation: String,
212 reason: String,
213 format: String,
214 },
215
216 #[error("File I/O error: {operation}")]
218 IoError {
219 operation: String,
220 path: Option<String>,
221 reason: String,
222 },
223
224 #[error("Cross-validation error: {reason}")]
227 CrossValidationError {
228 fold: Option<usize>,
229 reason: String,
230 total_folds: Option<usize>,
231 },
232
233 #[error("Hyperparameter optimization failed: {method}")]
235 HyperparameterOptimizationError {
236 method: String,
237 reason: String,
238 iteration: Option<usize>,
239 best_score: Option<f64>,
240 },
241
242 #[error("Multi-class strategy '{strategy}' error: {reason}")]
245 MultiClassError {
246 strategy: String,
247 reason: String,
248 class_count: Option<usize>,
249 },
250
251 #[error("Multi-label SVM error: {reason}")]
253 MultiLabelError {
254 reason: String,
255 label_indices: Option<Vec<usize>>,
256 },
257
258 #[error("Structured SVM error: {reason}")]
260 StructuredSVMError {
261 reason: String,
262 sequence_info: Option<String>,
263 },
264
265 #[error("Topic modeling error: {reason}")]
268 TopicModelingError {
269 model_type: String,
270 reason: String,
271 topic_count: Option<usize>,
272 },
273
274 #[error("Text processing error: {operation}")]
276 TextProcessingError {
277 operation: String,
278 reason: String,
279 document_index: Option<usize>,
280 },
281
282 #[error("Computer vision kernel error: {kernel_type}")]
284 ComputerVisionError {
285 kernel_type: String,
286 reason: String,
287 image_dimensions: Option<(usize, usize)>,
288 },
289
290 #[error("Internal error: {message}")]
293 InternalError {
294 message: String,
295 location: String,
296 debug_info: Option<String>,
297 },
298
299 #[error("Unknown error occurred: {message}")]
301 Unknown { message: String, context: String },
302}
303
304pub type SVMResult<T> = Result<T, SVMError>;
306
307#[derive(Debug, Clone, Copy, PartialEq, Eq)]
309pub enum ErrorSeverity {
310 Low,
312 Medium,
314 High,
316 Critical,
318}
319
320#[derive(Debug, Clone)]
322pub struct ErrorContext {
323 pub operation: String,
324 pub timestamp: std::time::SystemTime,
325 pub severity: ErrorSeverity,
326 pub metadata: std::collections::HashMap<String, String>,
327}
328
329impl SVMError {
330 pub fn severity(&self) -> ErrorSeverity {
332 match self {
333 SVMError::InvalidInput { .. } => ErrorSeverity::Medium,
335 SVMError::DimensionMismatch { .. } => ErrorSeverity::Medium,
336 SVMError::EmptyDataset { .. } => ErrorSeverity::High,
337 SVMError::InvalidLabels { .. } => ErrorSeverity::Medium,
338 SVMError::InsufficientData { .. } => ErrorSeverity::High,
339
340 SVMError::InvalidHyperparameter { .. } => ErrorSeverity::Medium,
342 SVMError::InvalidKernel { .. } => ErrorSeverity::Medium,
343 SVMError::InvalidSolver { .. } => ErrorSeverity::Medium,
344
345 SVMError::ConvergenceFailure { .. } => ErrorSeverity::Medium,
347 SVMError::NumericalInstability { .. } => ErrorSeverity::High,
348 SVMError::OptimizationFailure { .. } => ErrorSeverity::High,
349 SVMError::InfeasibleProblem { .. } => ErrorSeverity::High,
350
351 SVMError::KernelComputationError { .. } => ErrorSeverity::High,
353 SVMError::NonPositiveSemidefiniteKernel { .. } => ErrorSeverity::High,
354 SVMError::KernelCacheError { .. } => ErrorSeverity::Medium,
355
356 SVMError::OutOfMemory { .. } => ErrorSeverity::Critical,
358 SVMError::InsufficientResources { .. } => ErrorSeverity::Critical,
359 SVMError::AllocationError { .. } => ErrorSeverity::Critical,
360
361 SVMError::ModelNotTrained { .. } => ErrorSeverity::High,
363 SVMError::PredictionError { .. } => ErrorSeverity::Medium,
364 SVMError::ModelStateInconsistency { .. } => ErrorSeverity::Critical,
365
366 SVMError::ParallelProcessingError { .. } => ErrorSeverity::Medium,
368 SVMError::SynchronizationError { .. } => ErrorSeverity::High,
369
370 SVMError::GpuError {
372 fallback_available: true,
373 ..
374 } => ErrorSeverity::Low,
375 SVMError::GpuError {
376 fallback_available: false,
377 ..
378 } => ErrorSeverity::High,
379 SVMError::SimdError {
380 fallback_used: true,
381 ..
382 } => ErrorSeverity::Low,
383 SVMError::SimdError {
384 fallback_used: false,
385 ..
386 } => ErrorSeverity::Medium,
387
388 SVMError::SerializationError { .. } => ErrorSeverity::Medium,
390 SVMError::IoError { .. } => ErrorSeverity::Medium,
391
392 SVMError::CrossValidationError { .. } => ErrorSeverity::Medium,
394 SVMError::HyperparameterOptimizationError { .. } => ErrorSeverity::Medium,
395
396 SVMError::MultiClassError { .. } => ErrorSeverity::Medium,
398 SVMError::MultiLabelError { .. } => ErrorSeverity::Medium,
399 SVMError::StructuredSVMError { .. } => ErrorSeverity::Medium,
400
401 SVMError::TopicModelingError { .. } => ErrorSeverity::Medium,
403 SVMError::TextProcessingError { .. } => ErrorSeverity::Medium,
404 SVMError::ComputerVisionError { .. } => ErrorSeverity::Medium,
405
406 SVMError::InternalError { .. } => ErrorSeverity::Critical,
408 SVMError::Unknown { .. } => ErrorSeverity::Critical,
409 }
410 }
411
412 pub fn error_code(&self) -> u32 {
414 match self {
415 SVMError::InvalidInput { .. } => 1001,
416 SVMError::DimensionMismatch { .. } => 1002,
417 SVMError::EmptyDataset { .. } => 1003,
418 SVMError::InvalidLabels { .. } => 1004,
419 SVMError::InsufficientData { .. } => 1005,
420
421 SVMError::InvalidHyperparameter { .. } => 2001,
422 SVMError::InvalidKernel { .. } => 2002,
423 SVMError::InvalidSolver { .. } => 2003,
424
425 SVMError::ConvergenceFailure { .. } => 3001,
426 SVMError::NumericalInstability { .. } => 3002,
427 SVMError::OptimizationFailure { .. } => 3003,
428 SVMError::InfeasibleProblem { .. } => 3004,
429
430 SVMError::KernelComputationError { .. } => 4001,
431 SVMError::NonPositiveSemidefiniteKernel { .. } => 4002,
432 SVMError::KernelCacheError { .. } => 4003,
433
434 SVMError::OutOfMemory { .. } => 5001,
435 SVMError::InsufficientResources { .. } => 5002,
436 SVMError::AllocationError { .. } => 5003,
437
438 SVMError::ModelNotTrained { .. } => 6001,
439 SVMError::PredictionError { .. } => 6002,
440 SVMError::ModelStateInconsistency { .. } => 6003,
441
442 SVMError::ParallelProcessingError { .. } => 7001,
443 SVMError::SynchronizationError { .. } => 7002,
444
445 SVMError::GpuError { .. } => 8001,
446 SVMError::SimdError { .. } => 8002,
447
448 SVMError::SerializationError { .. } => 9001,
449 SVMError::IoError { .. } => 9002,
450
451 SVMError::CrossValidationError { .. } => 10001,
452 SVMError::HyperparameterOptimizationError { .. } => 10002,
453
454 SVMError::MultiClassError { .. } => 11001,
455 SVMError::MultiLabelError { .. } => 11002,
456 SVMError::StructuredSVMError { .. } => 11003,
457
458 SVMError::TopicModelingError { .. } => 12001,
459 SVMError::TextProcessingError { .. } => 12002,
460 SVMError::ComputerVisionError { .. } => 12003,
461
462 SVMError::InternalError { .. } => 99001,
463 SVMError::Unknown { .. } => 99999,
464 }
465 }
466
467 pub fn suggestions(&self) -> Vec<String> {
469 match self {
470 SVMError::ConvergenceFailure { suggestions, .. } => suggestions.clone(),
471 SVMError::NumericalInstability { suggestions, .. } => suggestions.clone(),
472 SVMError::InfeasibleProblem { suggestions, .. } => suggestions.clone(),
473 SVMError::NonPositiveSemidefiniteKernel { suggestions, .. } => suggestions.clone(),
474 SVMError::OutOfMemory { suggestions, .. } => suggestions.clone(),
475 SVMError::ModelNotTrained { suggestions, .. } => suggestions.clone(),
476
477 SVMError::InvalidInput {
478 suggestion: Some(s),
479 ..
480 } => vec![s.clone()],
481 SVMError::InvalidKernel { suggestion, .. } => vec![suggestion.clone()],
482 SVMError::InvalidLabels { suggestion, .. } => vec![suggestion.clone()],
483
484 SVMError::DimensionMismatch { .. } => vec![
486 "Check that input arrays have compatible dimensions".to_string(),
487 "Ensure training and test data have same number of features".to_string(),
488 ],
489
490 SVMError::EmptyDataset { .. } => vec![
491 "Provide at least one training sample".to_string(),
492 "Check data loading and preprocessing steps".to_string(),
493 ],
494
495 SVMError::InvalidHyperparameter {
496 valid_range: Some(range),
497 ..
498 } => vec![
499 format!("Use values in range: {}", range),
500 "Check hyperparameter documentation for valid ranges".to_string(),
501 ],
502
503 _ => vec!["Check documentation for this error type".to_string()],
504 }
505 }
506
507 pub fn detailed_report(&self) -> String {
509 let mut report = format!("SVM Error [Code: {}]\n", self.error_code());
510 report.push_str(&format!("Severity: {:?}\n", self.severity()));
511 report.push_str(&format!("Message: {}\n", self));
512
513 let suggestions = self.suggestions();
514 if !suggestions.is_empty() {
515 report.push_str("\nSuggestions:\n");
516 for (i, suggestion) in suggestions.iter().enumerate() {
517 report.push_str(&format!(" {}. {}\n", i + 1, suggestion));
518 }
519 }
520
521 report
522 }
523}
524
525impl SVMError {
527 pub fn invalid_input(message: impl Into<String>) -> Self {
529 SVMError::InvalidInput {
530 message: message.into(),
531 suggestion: None,
532 }
533 }
534
535 pub fn invalid_input_with_suggestion(
537 message: impl Into<String>,
538 suggestion: impl Into<String>,
539 ) -> Self {
540 SVMError::InvalidInput {
541 message: message.into(),
542 suggestion: Some(suggestion.into()),
543 }
544 }
545
546 pub fn dimension_mismatch(
548 expected: Vec<usize>,
549 actual: Vec<usize>,
550 context: impl Into<String>,
551 ) -> Self {
552 let expected_str = format!("{:?}", expected);
553 let actual_str = format!("{:?}", actual);
554 SVMError::DimensionMismatch {
555 expected,
556 actual,
557 context: context.into(),
558 expected_str,
559 actual_str,
560 }
561 }
562
563 pub fn convergence_failure(
565 iterations: usize,
566 tolerance: f64,
567 suggestions: Vec<String>,
568 ) -> Self {
569 SVMError::ConvergenceFailure {
570 iterations,
571 final_objective: None,
572 tolerance,
573 suggestions,
574 }
575 }
576
577 pub fn model_not_trained(operation: impl Into<String>) -> Self {
579 SVMError::ModelNotTrained {
580 operation: operation.into(),
581 suggestions: vec![
582 "Call fit() method to train the model first".to_string(),
583 "Ensure training completed successfully".to_string(),
584 ],
585 }
586 }
587
588 pub fn out_of_memory(operation: impl Into<String>) -> Self {
590 SVMError::OutOfMemory {
591 operation: operation.into(),
592 requested_bytes: None,
593 available_bytes: None,
594 suggestions: vec![
595 "Reduce dataset size or use chunked processing".to_string(),
596 "Increase system memory or use out-of-core algorithms".to_string(),
597 "Consider using LinearSVC for large datasets".to_string(),
598 ],
599 }
600 }
601}
602
603impl From<std::io::Error> for SVMError {
605 fn from(err: std::io::Error) -> Self {
606 SVMError::IoError {
607 operation: "file operation".to_string(),
608 path: None,
609 reason: err.to_string(),
610 }
611 }
612}
613
614impl From<crate::gpu_kernels::GpuKernelError> for SVMError {
616 fn from(err: crate::gpu_kernels::GpuKernelError) -> Self {
617 use crate::gpu_kernels::GpuKernelError::*;
618 match err {
619 DeviceNotAvailable => SVMError::GpuError {
620 reason: "GPU device not available".to_string(),
621 device_info: None,
622 fallback_available: true,
623 },
624 InsufficientMemory => SVMError::GpuError {
625 reason: "Insufficient GPU memory".to_string(),
626 device_info: None,
627 fallback_available: true,
628 },
629 ComputationFailed(msg) => SVMError::GpuError {
630 reason: format!("GPU computation failed: {}", msg),
631 device_info: None,
632 fallback_available: true,
633 },
634 ShaderCompilationFailed(msg) => SVMError::GpuError {
635 reason: format!("Shader compilation failed: {}", msg),
636 device_info: None,
637 fallback_available: false,
638 },
639 BufferCreationFailed => SVMError::GpuError {
640 reason: "Buffer creation failed".to_string(),
641 device_info: None,
642 fallback_available: true,
643 },
644 FeatureNotSupported(feature) => SVMError::GpuError {
645 reason: format!("Feature not supported: {}", feature),
646 device_info: None,
647 fallback_available: true,
648 },
649 DimensionMismatch => SVMError::DimensionMismatch {
650 expected: vec![],
651 actual: vec![],
652 context: "GPU kernel computation".to_string(),
653 expected_str: "[]".to_string(),
654 actual_str: "[]".to_string(),
655 },
656 }
657 }
658}
659
660#[allow(non_snake_case)]
661#[cfg(test)]
662mod tests {
663 use super::*;
664
665 #[test]
666 fn test_error_creation() {
667 let error = SVMError::invalid_input("test message");
668 assert_eq!(error.error_code(), 1001);
669 assert_eq!(error.severity(), ErrorSeverity::Medium);
670 }
671
672 #[test]
673 fn test_error_suggestions() {
674 let error = SVMError::model_not_trained("predict");
675 let suggestions = error.suggestions();
676 assert!(!suggestions.is_empty());
677 assert!(suggestions[0].contains("fit()"));
678 }
679
680 #[test]
681 fn test_detailed_report() {
682 let error = SVMError::convergence_failure(
683 1000,
684 1e-3,
685 vec![
686 "Increase max_iter".to_string(),
687 "Decrease tolerance".to_string(),
688 ],
689 );
690
691 let report = error.detailed_report();
692 assert!(report.contains("Code: 3001"));
693 assert!(report.contains("Severity:"));
694 assert!(report.contains("Suggestions:"));
695 assert!(report.contains("Increase max_iter"));
696 }
697
698 #[test]
699 fn test_dimension_mismatch() {
700 let error = SVMError::dimension_mismatch(vec![100, 50], vec![100, 40], "training data");
701
702 assert_eq!(error.error_code(), 1002);
703 let suggestions = error.suggestions();
704 assert!(suggestions
705 .iter()
706 .any(|s| s.contains("compatible dimensions")));
707 }
708}