scirs2_interpolate/advanced_coordinator_modules/
knowledge_transfer.rs

1//! Cross-domain knowledge transfer system for interpolation methods
2//!
3//! This module provides sophisticated knowledge transfer capabilities that enable
4//! interpolation methods to learn from experience across different domains and
5//! data types, improving performance through accumulated knowledge.
6
7use scirs2_core::numeric::Float;
8use std::collections::HashMap;
9use std::fmt::Debug;
10
11use crate::advanced_coordinator_modules::types::{
12    DataProfile, InterpolationMethodType, PerformanceMetrics, PerformanceTargets,
13};
14use crate::error::{InterpolateError, InterpolateResult};
15
16/// Cross-domain knowledge transfer system
17#[derive(Debug)]
18pub struct CrossDomainInterpolationKnowledge<F: Float + Debug> {
19    /// Knowledge base
20    knowledge_base: InterpolationKnowledgeBase<F>,
21    /// Transfer learning model
22    transfer_model: TransferLearningModel<F>,
23    /// Domain adaptation system
24    domain_adapter: DomainAdapter<F>,
25}
26
27impl<F: Float + Debug + std::ops::MulAssign + std::default::Default>
28    CrossDomainInterpolationKnowledge<F>
29{
30    /// Create new cross-domain knowledge system
31    pub fn new() -> Self {
32        Self {
33            knowledge_base: InterpolationKnowledgeBase::new(),
34            transfer_model: TransferLearningModel::new(),
35            domain_adapter: DomainAdapter::new(),
36        }
37    }
38
39    /// Learn from interpolation experience
40    pub fn learn_from_experience(
41        &mut self,
42        domain: String,
43        data_profile: &DataProfile<F>,
44        method: InterpolationMethodType,
45        performance: &PerformanceMetrics,
46    ) -> InterpolateResult<()> {
47        // Add knowledge to domain
48        self.knowledge_base.add_domain_experience(
49            domain.clone(),
50            data_profile,
51            method,
52            performance,
53        )?;
54
55        // Update transfer learning model
56        self.transfer_model
57            .update_model(&domain, data_profile, performance)?;
58
59        // Update domain adaptation
60        self.domain_adapter.update_mappings(&domain, data_profile)?;
61
62        Ok(())
63    }
64
65    /// Transfer knowledge to new domain
66    pub fn transfer_knowledge(
67        &self,
68        source_domain: &str,
69        target_domain: &str,
70        target_profile: &DataProfile<F>,
71    ) -> InterpolateResult<TransferKnowledgeResult<F>> {
72        // Get source domain knowledge
73        let source_knowledge = self
74            .knowledge_base
75            .get_domain_knowledge(source_domain)
76            .ok_or_else(|| InterpolateError::InvalidInput {
77                message: format!(
78                    "No knowledge available for source domain: {}",
79                    source_domain
80                ),
81            })?;
82
83        // Find applicable patterns
84        let applicable_patterns = self.knowledge_base.find_applicable_patterns(
85            source_domain,
86            target_domain,
87            target_profile,
88        )?;
89
90        // Perform domain adaptation
91        let adapted_knowledge = self.domain_adapter.adapt_knowledge(
92            source_knowledge,
93            target_profile,
94            &applicable_patterns,
95        )?;
96
97        // Generate transfer recommendations
98        let recommendations = self.transfer_model.generate_recommendations(
99            source_domain,
100            target_domain,
101            &adapted_knowledge,
102            target_profile,
103        )?;
104
105        Ok(TransferKnowledgeResult {
106            adapted_knowledge,
107            recommendations,
108            confidence_score: self.calculate_transfer_confidence(
109                source_domain,
110                target_domain,
111                &applicable_patterns,
112            ),
113        })
114    }
115
116    /// Get knowledge summary
117    pub fn get_knowledge_summary(&self) -> KnowledgeSummary {
118        KnowledgeSummary {
119            total_domains: self.knowledge_base.domain_knowledge.len(),
120            total_patterns: self.knowledge_base.cross_domain_patterns.len(),
121            average_confidence: self.knowledge_base.calculate_average_confidence(),
122            most_successful_methods: self.knowledge_base.get_most_successful_methods(),
123        }
124    }
125
126    /// Calculate transfer confidence
127    fn calculate_transfer_confidence(
128        &self,
129        source_domain: &str,
130        target_domain: &str,
131        patterns: &[CrossDomainPattern<F>],
132    ) -> f64 {
133        if patterns.is_empty() {
134            return 0.1; // Low confidence with no patterns
135        }
136
137        let pattern_strengths: Vec<f64> = patterns
138            .iter()
139            .map(|p| p.transfer_strength.to_f64().unwrap_or(0.0))
140            .collect();
141
142        let avg_strength = pattern_strengths.iter().sum::<f64>() / pattern_strengths.len() as f64;
143
144        // Apply domain-specific confidence adjustments
145        let domain_confidence = self
146            .knowledge_base
147            .get_domain_confidence(source_domain)
148            .unwrap_or(0.5);
149
150        (avg_strength * 0.7 + domain_confidence * 0.3).min(1.0)
151    }
152}
153
154impl<F: Float + Debug + std::ops::MulAssign + std::default::Default> Default
155    for CrossDomainInterpolationKnowledge<F>
156{
157    fn default() -> Self {
158        Self::new()
159    }
160}
161
162/// Knowledge base for interpolation
163#[derive(Debug)]
164pub struct InterpolationKnowledgeBase<F: Float> {
165    /// Domain-specific knowledge
166    domain_knowledge: HashMap<String, DomainKnowledge<F>>,
167    /// Cross-domain patterns
168    cross_domain_patterns: Vec<CrossDomainPattern<F>>,
169    /// Knowledge confidence scores
170    confidence_scores: HashMap<String, f64>,
171}
172
173impl<F: Float + std::default::Default> InterpolationKnowledgeBase<F> {
174    /// Create new knowledge base
175    pub fn new() -> Self {
176        Self {
177            domain_knowledge: HashMap::new(),
178            cross_domain_patterns: Vec::new(),
179            confidence_scores: HashMap::new(),
180        }
181    }
182
183    /// Add domain experience
184    pub fn add_domain_experience(
185        &mut self,
186        domain: String,
187        data_profile: &DataProfile<F>,
188        method: InterpolationMethodType,
189        performance: &PerformanceMetrics,
190    ) -> InterpolateResult<()> {
191        let domain_knowledge = self
192            .domain_knowledge
193            .entry(domain.clone())
194            .or_insert_with(|| DomainKnowledge::new(domain.clone()));
195
196        domain_knowledge.add_experience(data_profile, method, performance)?;
197
198        // Update confidence score
199        let current_confidence = self.confidence_scores.get(&domain).unwrap_or(&0.5);
200        let new_confidence = (current_confidence + 0.1).min(1.0);
201        self.confidence_scores.insert(domain, new_confidence);
202
203        // Discover new cross-domain patterns
204        self.discover_cross_domain_patterns()?;
205
206        Ok(())
207    }
208
209    /// Get domain knowledge
210    pub fn get_domain_knowledge(&self, domain: &str) -> Option<&DomainKnowledge<F>> {
211        self.domain_knowledge.get(domain)
212    }
213
214    /// Find applicable patterns
215    pub fn find_applicable_patterns(
216        &self,
217        source_domain: &str,
218        target_domain: &str,
219        target_profile: &DataProfile<F>,
220    ) -> InterpolateResult<Vec<CrossDomainPattern<F>>> {
221        let patterns: Vec<CrossDomainPattern<F>> = self
222            .cross_domain_patterns
223            .iter()
224            .filter(|pattern| {
225                pattern.source_domains.contains(&source_domain.to_string())
226                    && (pattern.target_domains.contains(&target_domain.to_string())
227                        || pattern.target_domains.is_empty())
228                    && self.pattern_matches_profile(pattern, target_profile)
229            })
230            .cloned()
231            .collect();
232
233        Ok(patterns)
234    }
235
236    /// Get domain confidence
237    pub fn get_domain_confidence(&self, domain: &str) -> Option<f64> {
238        self.confidence_scores.get(domain).copied()
239    }
240
241    /// Calculate average confidence
242    pub fn calculate_average_confidence(&self) -> f64 {
243        if self.confidence_scores.is_empty() {
244            return 0.0;
245        }
246
247        let sum: f64 = self.confidence_scores.values().sum();
248        sum / self.confidence_scores.len() as f64
249    }
250
251    /// Get most successful methods
252    pub fn get_most_successful_methods(&self) -> Vec<InterpolationMethodType> {
253        let mut method_scores: HashMap<InterpolationMethodType, f64> = HashMap::new();
254
255        for domain_knowledge in self.domain_knowledge.values() {
256            for method in &domain_knowledge.optimal_methods {
257                let score = method_scores.entry(*method).or_insert(0.0);
258                *score += domain_knowledge
259                    .performance_profile
260                    .accuracy_profile
261                    .mean_accuracy
262                    .to_f64()
263                    .unwrap_or(0.0);
264            }
265        }
266
267        let mut methods: Vec<(InterpolationMethodType, f64)> = method_scores.into_iter().collect();
268        methods.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
269
270        methods
271            .into_iter()
272            .take(5)
273            .map(|(method, _)| method)
274            .collect()
275    }
276
277    /// Discover cross-domain patterns
278    fn discover_cross_domain_patterns(&mut self) -> InterpolateResult<()> {
279        // Analyze all domain combinations for patterns
280        let domains: Vec<String> = self.domain_knowledge.keys().cloned().collect();
281
282        for i in 0..domains.len() {
283            for j in (i + 1)..domains.len() {
284                let source_domain = &domains[i];
285                let target_domain = &domains[j];
286
287                if let Some(pattern) =
288                    self.analyze_domain_similarity(source_domain, target_domain)?
289                {
290                    // Check if pattern already exists
291                    if !self
292                        .cross_domain_patterns
293                        .iter()
294                        .any(|p| p.pattern_signature == pattern.pattern_signature)
295                    {
296                        self.cross_domain_patterns.push(pattern);
297                    }
298                }
299            }
300        }
301
302        Ok(())
303    }
304
305    /// Analyze similarity between domains
306    fn analyze_domain_similarity(
307        &self,
308        source_domain: &str,
309        target_domain: &str,
310    ) -> InterpolateResult<Option<CrossDomainPattern<F>>> {
311        let source_knowledge = self.domain_knowledge.get(source_domain);
312        let target_knowledge = self.domain_knowledge.get(target_domain);
313
314        if let (Some(source), Some(target)) = (source_knowledge, target_knowledge) {
315            // Calculate method overlap
316            let method_overlap =
317                self.calculate_method_overlap(&source.optimal_methods, &target.optimal_methods);
318
319            if method_overlap > 0.5 {
320                let pattern_signature =
321                    format!("method_overlap_{}_{}", source_domain, target_domain);
322                let transfer_strength = F::from(method_overlap).unwrap_or(F::zero());
323
324                return Ok(Some(CrossDomainPattern {
325                    source_domains: vec![source_domain.to_string()],
326                    target_domains: vec![target_domain.to_string()],
327                    pattern_signature,
328                    transfer_strength,
329                }));
330            }
331        }
332
333        Ok(None)
334    }
335
336    /// Calculate method overlap between domains
337    fn calculate_method_overlap(
338        &self,
339        methods1: &[InterpolationMethodType],
340        methods2: &[InterpolationMethodType],
341    ) -> f64 {
342        if methods1.is_empty() || methods2.is_empty() {
343            return 0.0;
344        }
345
346        let common_methods = methods1
347            .iter()
348            .filter(|method| methods2.contains(method))
349            .count();
350
351        let total_unique = methods1.len() + methods2.len() - common_methods;
352
353        if total_unique == 0 {
354            1.0
355        } else {
356            common_methods as f64 / total_unique as f64
357        }
358    }
359
360    /// Check if pattern matches profile
361    fn pattern_matches_profile(
362        &self,
363        pattern: &CrossDomainPattern<F>,
364        _profile: &DataProfile<F>,
365    ) -> bool {
366        // Simplified pattern matching - can be enhanced
367        pattern.transfer_strength > F::from(0.3).unwrap_or(F::zero())
368    }
369}
370
371impl<F: Float + std::default::Default> Default for InterpolationKnowledgeBase<F> {
372    fn default() -> Self {
373        Self::new()
374    }
375}
376
377/// Domain-specific knowledge
378#[derive(Debug, Clone)]
379pub struct DomainKnowledge<F: Float> {
380    /// Domain name
381    pub domain: String,
382    /// Optimal methods for this domain
383    pub optimal_methods: Vec<InterpolationMethodType>,
384    /// Domain-specific optimizations
385    pub optimizations: Vec<DomainOptimization>,
386    /// Performance profile
387    pub performance_profile: PerformanceProfile<F>,
388}
389
390impl<F: Float + std::default::Default> DomainKnowledge<F> {
391    /// Create new domain knowledge
392    pub fn new(domain: String) -> Self {
393        Self {
394            domain,
395            optimal_methods: Vec::new(),
396            optimizations: Vec::new(),
397            performance_profile: PerformanceProfile::default(),
398        }
399    }
400
401    /// Add experience to domain knowledge
402    pub fn add_experience(
403        &mut self,
404        _data_profile: &DataProfile<F>,
405        method: InterpolationMethodType,
406        performance: &PerformanceMetrics,
407    ) -> InterpolateResult<()> {
408        // Update optimal methods if this one performed well
409        if performance.accuracy > 0.8 && !self.optimal_methods.contains(&method) {
410            self.optimal_methods.push(method);
411        }
412
413        // Update performance profile
414        self.performance_profile
415            .execution_times
416            .push(F::from(performance.execution_time_ms).unwrap_or(F::zero()));
417        self.performance_profile
418            .memory_patterns
419            .push(performance.memory_usage_bytes);
420
421        // Update accuracy profile
422        let accuracy_f = F::from(performance.accuracy).unwrap_or(F::zero());
423        self.performance_profile
424            .accuracy_profile
425            .accuracy_distribution
426            .push(accuracy_f);
427
428        // Recalculate mean accuracy
429        let accuracies = &self
430            .performance_profile
431            .accuracy_profile
432            .accuracy_distribution;
433        if !accuracies.is_empty() {
434            let sum = accuracies.iter().fold(F::zero(), |acc, &x| acc + x);
435            self.performance_profile.accuracy_profile.mean_accuracy =
436                sum / F::from(accuracies.len()).unwrap_or(F::one());
437        }
438
439        Ok(())
440    }
441}
442
443/// Domain optimization
444#[derive(Debug, Clone)]
445pub struct DomainOptimization {
446    /// Optimization name
447    pub name: String,
448    /// Optimization parameters
449    pub parameters: HashMap<String, f64>,
450    /// Expected improvement
451    pub expected_improvement: f64,
452}
453
454/// Performance profile for domains
455#[derive(Debug, Clone, Default)]
456pub struct PerformanceProfile<F: Float> {
457    /// Typical execution times
458    pub execution_times: Vec<F>,
459    /// Memory usage patterns
460    pub memory_patterns: Vec<usize>,
461    /// Accuracy profile
462    pub accuracy_profile: AccuracyProfile<F>,
463}
464
465/// Accuracy profile
466#[derive(Debug, Clone, Default)]
467pub struct AccuracyProfile<F: Float> {
468    /// Mean accuracy
469    pub mean_accuracy: F,
470    /// Accuracy variance
471    pub accuracy_variance: F,
472    /// Accuracy distribution
473    pub accuracy_distribution: Vec<F>,
474}
475
476/// Cross-domain pattern
477#[derive(Debug, Clone)]
478pub struct CrossDomainPattern<F: Float> {
479    /// Source domains
480    pub source_domains: Vec<String>,
481    /// Target domains
482    pub target_domains: Vec<String>,
483    /// Pattern signature
484    pub pattern_signature: String,
485    /// Transfer strength
486    pub transfer_strength: F,
487}
488
489/// Transfer learning model
490#[derive(Debug)]
491pub struct TransferLearningModel<F: Float> {
492    /// Source domain models
493    source_models: HashMap<String, SourceModel<F>>,
494    /// Transfer weights
495    transfer_weights: HashMap<String, f64>,
496    /// Adaptation parameters
497    adaptation_params: AdaptationParameters<F>,
498}
499
500impl<F: Float> TransferLearningModel<F> {
501    /// Create new transfer learning model
502    pub fn new() -> Self {
503        Self {
504            source_models: HashMap::new(),
505            transfer_weights: HashMap::new(),
506            adaptation_params: AdaptationParameters::default(),
507        }
508    }
509
510    /// Update model with new data
511    pub fn update_model(
512        &mut self,
513        domain: &str,
514        data_profile: &DataProfile<F>,
515        performance: &PerformanceMetrics,
516    ) -> InterpolateResult<()> {
517        // Create or update source model for domain
518        let model = self
519            .source_models
520            .entry(domain.to_string())
521            .or_insert_with(|| SourceModel::new());
522
523        model.update_with_performance(data_profile, performance)?;
524
525        // Update transfer weights based on performance
526        let weight =
527            performance.accuracy * 0.8 + (1.0 - performance.execution_time_ms / 10000.0) * 0.2;
528        self.transfer_weights
529            .insert(domain.to_string(), weight.clamp(0.0, 1.0));
530
531        Ok(())
532    }
533
534    /// Generate transfer recommendations
535    pub fn generate_recommendations(
536        &self,
537        source_domain: &str,
538        target_domain: &str,
539        adapted_knowledge: &DomainKnowledge<F>,
540        _target_profile: &DataProfile<F>,
541    ) -> InterpolateResult<Vec<TransferRecommendation>> {
542        let mut recommendations = Vec::new();
543
544        // Recommend optimal methods from adapted knowledge
545        for method in &adapted_knowledge.optimal_methods {
546            let confidence = self.transfer_weights.get(source_domain).unwrap_or(&0.5);
547
548            recommendations.push(TransferRecommendation {
549                method: *method,
550                confidence: *confidence,
551                reasoning: format!(
552                    "Method {:?} showed good performance in source domain {}",
553                    method, source_domain
554                ),
555                estimated_improvement: confidence * 0.2,
556            });
557        }
558
559        // Sort by confidence
560        recommendations.sort_by(|a, b| {
561            b.confidence
562                .partial_cmp(&a.confidence)
563                .unwrap_or(std::cmp::Ordering::Equal)
564        });
565
566        Ok(recommendations)
567    }
568}
569
570impl<F: Float> Default for TransferLearningModel<F> {
571    fn default() -> Self {
572        Self::new()
573    }
574}
575
576/// Source model for transfer learning
577#[derive(Debug, Clone)]
578pub struct SourceModel<F: Float> {
579    /// Model parameters
580    pub parameters: Vec<F>,
581    /// Model accuracy
582    pub accuracy: F,
583    /// Model complexity
584    pub complexity: usize,
585}
586
587impl<F: Float> Default for SourceModel<F> {
588    fn default() -> Self {
589        Self::new()
590    }
591}
592
593impl<F: Float> SourceModel<F> {
594    /// Create new source model
595    pub fn new() -> Self {
596        Self {
597            parameters: Vec::new(),
598            accuracy: F::zero(),
599            complexity: 0,
600        }
601    }
602
603    /// Update model with performance data
604    pub fn update_with_performance(
605        &mut self,
606        _data_profile: &DataProfile<F>,
607        performance: &PerformanceMetrics,
608    ) -> InterpolateResult<()> {
609        self.accuracy = F::from(performance.accuracy).unwrap_or(F::zero());
610        self.complexity = performance.memory_usage_bytes / 1024; // Simple complexity measure
611
612        // Update parameters (simplified)
613        if self.parameters.is_empty() {
614            self.parameters = vec![self.accuracy, F::from(self.complexity).unwrap_or(F::zero())];
615        } else {
616            // Exponential moving average
617            let alpha = F::from(0.1).unwrap_or(F::zero());
618            self.parameters[0] = self.parameters[0] * (F::one() - alpha) + self.accuracy * alpha;
619        }
620
621        Ok(())
622    }
623}
624
625/// Adaptation parameters
626#[derive(Debug, Clone)]
627pub struct AdaptationParameters<F: Float> {
628    /// Learning rate for adaptation
629    pub learning_rate: F,
630    /// Regularization strength
631    pub regularization: F,
632    /// Transfer confidence threshold
633    pub confidence_threshold: F,
634}
635
636impl<F: Float> Default for AdaptationParameters<F> {
637    fn default() -> Self {
638        Self {
639            learning_rate: F::from(0.01).unwrap_or(F::zero()),
640            regularization: F::from(0.001).unwrap_or(F::zero()),
641            confidence_threshold: F::from(0.5).unwrap_or(F::zero()),
642        }
643    }
644}
645
646/// Domain adapter
647#[derive(Debug)]
648pub struct DomainAdapter<F: Float> {
649    /// Domain mappings
650    domain_mappings: HashMap<String, DomainMapping<F>>,
651    /// Adaptation strategies
652    adaptation_strategies: Vec<AdaptationStrategy<F>>,
653}
654
655impl<F: Float + std::ops::MulAssign> DomainAdapter<F> {
656    /// Create new domain adapter
657    pub fn new() -> Self {
658        Self {
659            domain_mappings: HashMap::new(),
660            adaptation_strategies: Vec::new(),
661        }
662    }
663
664    /// Update domain mappings
665    pub fn update_mappings(
666        &mut self,
667        domain: &str,
668        _data_profile: &DataProfile<F>,
669    ) -> InterpolateResult<()> {
670        // Simplified mapping update
671        let mapping_key = format!("general_to_{}", domain);
672        let mapping = DomainMapping {
673            source_domain: "general".to_string(),
674            target_domain: domain.to_string(),
675            mapping_params: vec![F::one()],
676            mapping_accuracy: F::from(0.8).unwrap_or(F::zero()),
677        };
678
679        self.domain_mappings.insert(mapping_key, mapping);
680        Ok(())
681    }
682
683    /// Adapt knowledge to target domain
684    pub fn adapt_knowledge(
685        &self,
686        source_knowledge: &DomainKnowledge<F>,
687        _target_profile: &DataProfile<F>,
688        patterns: &[CrossDomainPattern<F>],
689    ) -> InterpolateResult<DomainKnowledge<F>> {
690        let mut adapted_knowledge = source_knowledge.clone();
691
692        // Apply pattern-based adaptations
693        for pattern in patterns {
694            let strength = pattern.transfer_strength.to_f64().unwrap_or(0.0);
695
696            if strength > 0.5 {
697                // High-confidence pattern - use source methods directly
698                // Already copied in clone above
699            } else if strength > 0.3 {
700                // Medium-confidence pattern - modify methods
701                adapted_knowledge.optimal_methods.retain(|method| {
702                    // Keep only the most reliable methods
703                    matches!(
704                        method,
705                        InterpolationMethodType::Linear
706                            | InterpolationMethodType::CubicSpline
707                            | InterpolationMethodType::BSpline
708                    )
709                });
710            }
711        }
712
713        // Adjust performance expectations
714        let adaptation_factor = F::from(0.9).unwrap_or(F::one());
715        adapted_knowledge
716            .performance_profile
717            .accuracy_profile
718            .mean_accuracy *= adaptation_factor;
719
720        Ok(adapted_knowledge)
721    }
722}
723
724impl<F: Float + std::ops::MulAssign> Default for DomainAdapter<F> {
725    fn default() -> Self {
726        Self::new()
727    }
728}
729
730/// Domain mapping
731#[derive(Debug, Clone)]
732pub struct DomainMapping<F: Float> {
733    /// Source domain
734    pub source_domain: String,
735    /// Target domain
736    pub target_domain: String,
737    /// Mapping function parameters
738    pub mapping_params: Vec<F>,
739    /// Mapping accuracy
740    pub mapping_accuracy: F,
741}
742
743/// Adaptation strategy
744#[derive(Debug, Clone)]
745pub struct AdaptationStrategy<F: Float> {
746    /// Strategy name
747    pub name: String,
748    /// Strategy parameters
749    pub parameters: HashMap<String, F>,
750    /// Success rate
751    pub success_rate: f64,
752}
753
754/// Result of knowledge transfer
755#[derive(Debug)]
756pub struct TransferKnowledgeResult<F: Float> {
757    /// Adapted knowledge for target domain
758    pub adapted_knowledge: DomainKnowledge<F>,
759    /// Transfer recommendations
760    pub recommendations: Vec<TransferRecommendation>,
761    /// Confidence in transfer
762    pub confidence_score: f64,
763}
764
765/// Transfer recommendation
766#[derive(Debug, Clone)]
767pub struct TransferRecommendation {
768    /// Recommended method
769    pub method: InterpolationMethodType,
770    /// Confidence in recommendation
771    pub confidence: f64,
772    /// Reasoning for recommendation
773    pub reasoning: String,
774    /// Estimated performance improvement
775    pub estimated_improvement: f64,
776}
777
778/// Knowledge summary
779#[derive(Debug, Clone)]
780pub struct KnowledgeSummary {
781    /// Total number of domains
782    pub total_domains: usize,
783    /// Total number of patterns
784    pub total_patterns: usize,
785    /// Average confidence across domains
786    pub average_confidence: f64,
787    /// Most successful methods overall
788    pub most_successful_methods: Vec<InterpolationMethodType>,
789}