1use super::types::*;
7use crate::error::InterpolateResult;
8use scirs2_core::numeric::Float;
9use std::collections::{HashMap, VecDeque};
10use std::fmt::Debug;
11use std::time::Instant;
12
13#[derive(Debug)]
15pub struct IntelligentMethodSelector<F: Float + Debug> {
16 method_db: HashMap<MethodKey, MethodPerformanceData>,
18 current_data_profile: Option<DataProfile<F>>,
20 selection_model: MethodSelectionModel<F>,
22 performance_history: VecDeque<MethodPerformanceRecord>,
24}
25
26#[derive(Debug)]
28pub struct MethodSelectionModel<F: Float> {
29 feature_weights: HashMap<String, f64>,
31 decision_tree: Vec<MethodSelectionRule>,
33 learning_rate: f64,
35 model_confidence: F,
37}
38
39#[derive(Debug, Clone)]
41pub struct MethodSelectionRule {
42 pub condition: MethodSelectionCondition,
44 pub method: InterpolationMethodType,
46 pub confidence: f64,
48 pub expected_accuracy: f64,
50}
51
52#[derive(Debug, Clone)]
54pub enum MethodSelectionCondition {
55 DataSizeRange { min: usize, max: usize },
57 SmoothnessThreshold { threshold: f64 },
59 NoiseLevel { max_noise: f64 },
61 PatternTypeMatch { pattern: DataPatternType },
63 AccuracyRequirement { min_accuracy: f64 },
65 PerformanceRequirement { max_time: f64 },
67 And {
69 conditions: Vec<MethodSelectionCondition>,
70 },
71 Or {
73 conditions: Vec<MethodSelectionCondition>,
74 },
75}
76
77impl<F: Float + Debug> IntelligentMethodSelector<F> {
78 pub fn new() -> InterpolateResult<Self> {
80 Ok(Self {
81 method_db: HashMap::new(),
82 current_data_profile: None,
83 selection_model: MethodSelectionModel::new()?,
84 performance_history: VecDeque::new(),
85 })
86 }
87
88 pub fn select_method(
90 &mut self,
91 data_profile: &DataProfile<F>,
92 performance_targets: &PerformanceTargets,
93 ) -> InterpolateResult<InterpolationRecommendation<F>> {
94 self.current_data_profile = Some(data_profile.clone());
95
96 let method_scores = self.evaluate_methods(data_profile, performance_targets)?;
98
99 let best_method = self.select_best_method(&method_scores)?;
101
102 self.generate_recommendation(best_method, &method_scores, data_profile)
104 }
105
106 pub fn update_performance(
108 &mut self,
109 method: InterpolationMethodType,
110 data_profile: &DataProfile<F>,
111 performance: &MethodPerformanceData,
112 ) -> InterpolateResult<()> {
113 let key = self.create_method_key(method, data_profile);
114
115 let existing = self
117 .method_db
118 .entry(key)
119 .or_insert_with(|| MethodPerformanceData {
120 avg_execution_time: 0.0,
121 memory_usage: 0,
122 accuracy: 0.0,
123 noise_robustness: 0.0,
124 sample_count: 0,
125 last_update: Instant::now(),
126 });
127
128 let alpha = 0.1; existing.avg_execution_time =
131 (1.0 - alpha) * existing.avg_execution_time + alpha * performance.avg_execution_time;
132 existing.accuracy = (1.0 - alpha) * existing.accuracy + alpha * performance.accuracy;
133 existing.noise_robustness =
134 (1.0 - alpha) * existing.noise_robustness + alpha * performance.noise_robustness;
135 existing.memory_usage = ((1.0 - alpha) * existing.memory_usage as f64
136 + alpha * performance.memory_usage as f64) as usize;
137 existing.sample_count += 1;
138 existing.last_update = Instant::now();
139
140 self.performance_history.push_back(MethodPerformanceRecord {
142 timestamp: Instant::now(),
143 method,
144 execution_time: performance.avg_execution_time,
145 memory_usage: performance.memory_usage,
146 accuracy: performance.accuracy,
147 data_size: data_profile.size,
148 success: true,
149 });
150
151 if self.performance_history.len() > 1000 {
153 self.performance_history.pop_front();
154 }
155
156 self.update_selection_model()?;
158
159 Ok(())
160 }
161
162 pub fn get_method_performance(
164 &self,
165 method: InterpolationMethodType,
166 data_profile: &DataProfile<F>,
167 ) -> Option<&MethodPerformanceData> {
168 let key = self.create_method_key(method, data_profile);
169 self.method_db.get(&key)
170 }
171
172 pub fn get_available_methods(
174 &self,
175 data_profile: &DataProfile<F>,
176 ) -> Vec<InterpolationMethodType> {
177 let mut methods = Vec::new();
178
179 methods.push(InterpolationMethodType::Linear);
181 methods.push(InterpolationMethodType::CubicSpline);
182
183 if data_profile.size < 10000 {
184 methods.push(InterpolationMethodType::Polynomial);
185 methods.push(InterpolationMethodType::RadialBasisFunction);
186 }
187
188 if data_profile.dimensionality <= 3 {
189 methods.push(InterpolationMethodType::Kriging);
190 methods.push(InterpolationMethodType::ThinPlateSpline);
191 }
192
193 methods.push(InterpolationMethodType::BSpline);
194 methods.push(InterpolationMethodType::PchipInterpolation);
195 methods.push(InterpolationMethodType::AkimaSpline);
196
197 if data_profile.size >= 1000 {
198 methods.push(InterpolationMethodType::NaturalNeighbor);
199 methods.push(InterpolationMethodType::ShepardsMethod);
200 }
201
202 methods
203 }
204
205 fn evaluate_methods(
207 &self,
208 data_profile: &DataProfile<F>,
209 performance_targets: &PerformanceTargets,
210 ) -> InterpolateResult<HashMap<InterpolationMethodType, f64>> {
211 let mut scores = HashMap::new();
212 let available_methods = self.get_available_methods(data_profile);
213
214 for method in available_methods {
215 let score = self.calculate_method_score(method, data_profile, performance_targets)?;
216 scores.insert(method, score);
217 }
218
219 Ok(scores)
220 }
221
222 fn calculate_method_score(
224 &self,
225 method: InterpolationMethodType,
226 data_profile: &DataProfile<F>,
227 performance_targets: &PerformanceTargets,
228 ) -> InterpolateResult<f64> {
229 let mut score = 0.0;
230
231 let base_score = match method {
233 InterpolationMethodType::Linear => 0.6,
234 InterpolationMethodType::CubicSpline => 0.8,
235 InterpolationMethodType::BSpline => 0.85,
236 InterpolationMethodType::RadialBasisFunction => 0.75,
237 InterpolationMethodType::Kriging => 0.9,
238 InterpolationMethodType::Polynomial => 0.7,
239 InterpolationMethodType::PchipInterpolation => 0.8,
240 InterpolationMethodType::AkimaSpline => 0.82,
241 InterpolationMethodType::ThinPlateSpline => 0.78,
242 InterpolationMethodType::NaturalNeighbor => 0.76,
243 InterpolationMethodType::ShepardsMethod => 0.65,
244 InterpolationMethodType::QuantumInspired => 0.95,
245 };
246
247 score += base_score * 0.3; let smoothness_factor = data_profile.smoothness.to_f64().unwrap_or(0.5);
251 let noise_factor = 1.0 - data_profile.noise_level.to_f64().unwrap_or(0.1);
252
253 score += smoothness_factor * 0.2; score += noise_factor * 0.2; if let Some(perf_data) = self.get_method_performance(method, data_profile) {
258 let accuracy_score = perf_data.accuracy;
259 let speed_score = 1.0 / (1.0 + perf_data.avg_execution_time / 1000.0); score += accuracy_score * 0.15; score += speed_score * 0.15; }
264
265 for rule in &self.selection_model.decision_tree {
267 if self.evaluate_condition(&rule.condition, data_profile, performance_targets)?
268 && rule.method == method
269 {
270 score += rule.confidence * 0.1; }
272 }
273
274 Ok(score.min(1.0)) }
276
277 fn evaluate_condition(
279 &self,
280 condition: &MethodSelectionCondition,
281 data_profile: &DataProfile<F>,
282 performance_targets: &PerformanceTargets,
283 ) -> InterpolateResult<bool> {
284 match condition {
285 MethodSelectionCondition::DataSizeRange { min, max } => {
286 Ok(data_profile.size >= *min && data_profile.size <= *max)
287 }
288 MethodSelectionCondition::SmoothnessThreshold { threshold } => {
289 Ok(data_profile.smoothness.to_f64().unwrap_or(0.0) >= *threshold)
290 }
291 MethodSelectionCondition::NoiseLevel { max_noise } => {
292 Ok(data_profile.noise_level.to_f64().unwrap_or(1.0) <= *max_noise)
293 }
294 MethodSelectionCondition::PatternTypeMatch { pattern } => {
295 Ok(true) }
298 MethodSelectionCondition::AccuracyRequirement { min_accuracy } => {
299 Ok(performance_targets.target_accuracy >= *min_accuracy)
300 }
301 MethodSelectionCondition::PerformanceRequirement { max_time } => {
302 Ok(performance_targets.max_time <= *max_time)
303 }
304 MethodSelectionCondition::And { conditions } => {
305 for cond in conditions {
306 if !self.evaluate_condition(cond, data_profile, performance_targets)? {
307 return Ok(false);
308 }
309 }
310 Ok(true)
311 }
312 MethodSelectionCondition::Or { conditions } => {
313 for cond in conditions {
314 if self.evaluate_condition(cond, data_profile, performance_targets)? {
315 return Ok(true);
316 }
317 }
318 Ok(false)
319 }
320 }
321 }
322
323 fn select_best_method(
325 &self,
326 method_scores: &HashMap<InterpolationMethodType, f64>,
327 ) -> InterpolateResult<InterpolationMethodType> {
328 let best = method_scores
329 .iter()
330 .max_by(|a, b| a.1.partial_cmp(b.1).unwrap_or(std::cmp::Ordering::Equal))
331 .map(|(method, _)| *method);
332
333 best.ok_or_else(|| {
334 crate::error::InterpolateError::invalid_input("No suitable method found".to_string())
335 })
336 }
337
338 fn generate_recommendation(
340 &self,
341 best_method: InterpolationMethodType,
342 method_scores: &HashMap<InterpolationMethodType, f64>,
343 data_profile: &DataProfile<F>,
344 ) -> InterpolateResult<InterpolationRecommendation<F>> {
345 let primary_score = method_scores.get(&best_method).copied().unwrap_or(0.0);
346
347 let mut alternatives: Vec<_> = method_scores
349 .iter()
350 .filter(|(method, _)| **method != best_method)
351 .map(|(method, score)| (*method, *score))
352 .collect();
353 alternatives.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
354 alternatives.truncate(3); let primary_recommendation = MethodRecommendation {
357 method: best_method,
358 confidence: 0.8, expected_performance: ExpectedPerformance {
360 accuracy_range: (0.8, 0.95),
361 time_range: (100.0, 1000.0),
362 memory_range: (1024, 10240),
363 performance_score: 0.8,
364 },
365 parameters: self.get_default_parameters(best_method),
366 configuration: self.get_method_configuration(best_method),
367 benefits: self.get_method_benefits(best_method),
368 limitations: self.get_method_limitations(best_method),
369 };
370
371 let alternative_recommendations: Vec<_> = alternatives
372 .into_iter()
373 .map(|(method, _)| MethodRecommendation {
374 method,
375 confidence: 0.6, expected_performance: ExpectedPerformance {
377 accuracy_range: (0.8, 0.95),
378 time_range: (100.0, 1000.0),
379 memory_range: (1024, 10240),
380 performance_score: 0.8,
381 },
382 parameters: self.get_default_parameters(method),
383 configuration: self.get_method_configuration(method),
384 benefits: self.get_method_benefits(method),
385 limitations: self.get_method_limitations(method),
386 })
387 .collect();
388
389 let expected_performance = self.estimate_performance(best_method, data_profile);
390
391 Ok(InterpolationRecommendation {
392 primary_method: primary_recommendation,
393 alternatives: alternative_recommendations,
394 expected_performance,
395 confidence: F::from(primary_score).unwrap(),
396 reasoning: self.generate_reasoning(best_method, data_profile),
397 })
398 }
399
400 fn create_method_key(
402 &self,
403 method: InterpolationMethodType,
404 data_profile: &DataProfile<F>,
405 ) -> MethodKey {
406 let size_class = match data_profile.size {
407 0..=1000 => DataSizeClass::Small,
408 1001..=100000 => DataSizeClass::Medium,
409 100001..=10000000 => DataSizeClass::Large,
410 _ => DataSizeClass::Massive,
411 };
412
413 let pattern_type = self.classify_pattern(data_profile);
414
415 MethodKey {
416 method_type: method,
417 size_class,
418 pattern_type,
419 dimensionality: data_profile.dimensionality as u8,
420 }
421 }
422
423 fn classify_pattern(&self, data_profile: &DataProfile<F>) -> DataPatternType {
425 let smoothness = data_profile.smoothness.to_f64().unwrap_or(0.5);
426 let noise = data_profile.noise_level.to_f64().unwrap_or(0.1);
427 let sparsity = data_profile.sparsity.to_f64().unwrap_or(0.0);
428
429 if noise > 0.1 {
430 DataPatternType::Noisy
431 } else if sparsity > 0.5 {
432 DataPatternType::Sparse
433 } else if smoothness > 0.8 {
434 DataPatternType::Smooth
435 } else if smoothness < 0.3 {
436 DataPatternType::Irregular
437 } else {
438 DataPatternType::Structured
439 }
440 }
441
442 fn update_selection_model(&mut self) -> InterpolateResult<()> {
444 if self.performance_history.len() >= 10 {
446 let recent_records: Vec<_> = self.performance_history.iter().rev().take(10).collect();
448
449 let success_rate = recent_records.iter().filter(|r| r.success).count() as f64
451 / recent_records.len() as f64;
452 self.selection_model.model_confidence = F::from(success_rate * 0.9 + 0.1).unwrap();
453 }
454
455 Ok(())
456 }
457
458 fn get_default_parameters(&self, method: InterpolationMethodType) -> Vec<f64> {
460 match method {
461 InterpolationMethodType::Linear => vec![],
462 InterpolationMethodType::CubicSpline => vec![0.0], InterpolationMethodType::BSpline => vec![3.0], InterpolationMethodType::RadialBasisFunction => vec![1.0], InterpolationMethodType::Kriging => vec![1.0, 1.0], InterpolationMethodType::Polynomial => vec![3.0], _ => vec![],
468 }
469 }
470
471 fn get_method_configuration(&self, method: InterpolationMethodType) -> String {
473 match method {
474 InterpolationMethodType::Linear => "Standard linear interpolation".to_string(),
475 InterpolationMethodType::CubicSpline => "Natural boundary conditions".to_string(),
476 InterpolationMethodType::BSpline => "Cubic B-spline with clamped ends".to_string(),
477 InterpolationMethodType::RadialBasisFunction => {
478 "Gaussian RBF with automatic scaling".to_string()
479 }
480 InterpolationMethodType::Kriging => {
481 "Ordinary kriging with exponential variogram".to_string()
482 }
483 _ => "Default configuration".to_string(),
484 }
485 }
486
487 fn get_method_benefits(&self, method: InterpolationMethodType) -> Vec<String> {
489 match method {
490 InterpolationMethodType::Linear => {
491 vec!["Fast".to_string(), "Memory efficient".to_string()]
492 }
493 InterpolationMethodType::CubicSpline => {
494 vec!["Smooth".to_string(), "Good for smooth data".to_string()]
495 }
496 InterpolationMethodType::BSpline => {
497 vec!["Flexible".to_string(), "Numerical stability".to_string()]
498 }
499 InterpolationMethodType::RadialBasisFunction => vec![
500 "Handles scattered data".to_string(),
501 "High accuracy".to_string(),
502 ],
503 InterpolationMethodType::Kriging => vec![
504 "Uncertainty quantification".to_string(),
505 "Optimal for spatial data".to_string(),
506 ],
507 _ => vec!["General purpose".to_string()],
508 }
509 }
510
511 fn get_method_limitations(&self, method: InterpolationMethodType) -> Vec<String> {
513 match method {
514 InterpolationMethodType::Linear => {
515 vec!["Low accuracy".to_string(), "Not smooth".to_string()]
516 }
517 InterpolationMethodType::CubicSpline => vec![
518 "Sensitive to outliers".to_string(),
519 "Requires ordered data".to_string(),
520 ],
521 InterpolationMethodType::RadialBasisFunction => vec![
522 "Computationally expensive".to_string(),
523 "Memory intensive".to_string(),
524 ],
525 _ => vec!["None significant".to_string()],
526 }
527 }
528
529 fn estimate_performance(
531 &self,
532 method: InterpolationMethodType,
533 data_profile: &DataProfile<F>,
534 ) -> ExpectedPerformance {
535 let base_time = match method {
536 InterpolationMethodType::Linear => 10.0,
537 InterpolationMethodType::CubicSpline => 100.0,
538 InterpolationMethodType::BSpline => 150.0,
539 InterpolationMethodType::RadialBasisFunction => 1000.0,
540 InterpolationMethodType::Kriging => 2000.0,
541 _ => 500.0,
542 };
543
544 let time_factor = (data_profile.size as f64).log10();
545 let estimated_time = base_time * time_factor;
546
547 ExpectedPerformance {
548 accuracy_range: (0.95, 0.99),
549 time_range: (estimated_time * 0.5, estimated_time * 2.0),
550 memory_range: (data_profile.size * 8, data_profile.size * 32),
551 performance_score: 0.8,
552 }
553 }
554
555 fn generate_reasoning(
557 &self,
558 method: InterpolationMethodType,
559 data_profile: &DataProfile<F>,
560 ) -> String {
561 format!(
562 "Selected {} for {} points with dimensionality {} based on data characteristics and performance history.",
563 format!("{:?}", method),
564 data_profile.size,
565 data_profile.dimensionality
566 )
567 }
568}
569
570impl<F: Float> MethodSelectionModel<F> {
571 pub fn new() -> InterpolateResult<Self> {
573 let mut model = Self {
574 feature_weights: HashMap::new(),
575 decision_tree: Vec::new(),
576 learning_rate: 0.01,
577 model_confidence: F::from(0.8).unwrap(),
578 };
579
580 model.initialize_default_rules();
582
583 Ok(model)
584 }
585
586 fn initialize_default_rules(&mut self) {
588 self.decision_tree.push(MethodSelectionRule {
590 condition: MethodSelectionCondition::And {
591 conditions: vec![
592 MethodSelectionCondition::DataSizeRange { min: 0, max: 1000 },
593 MethodSelectionCondition::SmoothnessThreshold { threshold: 0.8 },
594 ],
595 },
596 method: InterpolationMethodType::CubicSpline,
597 confidence: 0.9,
598 expected_accuracy: 0.95,
599 });
600
601 self.decision_tree.push(MethodSelectionRule {
603 condition: MethodSelectionCondition::DataSizeRange {
604 min: 100000,
605 max: usize::MAX,
606 },
607 method: InterpolationMethodType::Linear,
608 confidence: 0.7,
609 expected_accuracy: 0.8,
610 });
611
612 self.decision_tree.push(MethodSelectionRule {
614 condition: MethodSelectionCondition::NoiseLevel { max_noise: 0.05 },
615 method: InterpolationMethodType::BSpline,
616 confidence: 0.85,
617 expected_accuracy: 0.9,
618 });
619
620 self.decision_tree.push(MethodSelectionRule {
622 condition: MethodSelectionCondition::AccuracyRequirement { min_accuracy: 0.99 },
623 method: InterpolationMethodType::Kriging,
624 confidence: 0.9,
625 expected_accuracy: 0.99,
626 });
627 }
628
629 pub fn get_confidence(&self) -> F {
631 self.model_confidence
632 }
633
634 pub fn update_model(&mut self, feedback: &[MethodPerformanceRecord]) -> InterpolateResult<()> {
636 if feedback.len() >= 5 {
638 let success_rate =
639 feedback.iter().filter(|r| r.success).count() as f64 / feedback.len() as f64;
640 self.model_confidence = F::from(success_rate * 0.9 + 0.1).unwrap();
641 }
642 Ok(())
643 }
644}