Skip to main content

optirs_nas/nas_engine/
results.rs

1// Neural Architecture Search Results and Statistics
2//
3// This module contains all result types, evaluation metrics, statistics tracking,
4// and performance measurement functionality for the Neural Architecture Search system.
5
6use crate::error::Result;
7use crate::multi_objective::ParetoFront;
8use crate::numeric::{count_as, scalar_as};
9use crate::EvaluationMetric;
10use scirs2_core::numeric::Float;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13use std::fmt::Debug;
14use std::time::{Duration, Instant};
15
16// Define missing types as placeholders since they're not available
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct OptimizerArchitecture<T: Float + Debug + Send + Sync + 'static> {
19    pub components: Vec<String>,
20    pub parameters: HashMap<String, T>,
21    pub connections: Vec<(usize, usize)>,
22    pub metadata: HashMap<String, String>,
23    pub hyperparameters: HashMap<String, T>,
24    pub architecture_id: String,
25}
26
27#[derive(Debug, Clone)]
28pub struct OptimizerComponent<T: Float + Debug + Send + Sync + 'static> {
29    pub name: String,
30    pub parameters: HashMap<String, T>,
31}
32
33#[derive(Debug, Clone)]
34pub struct ConvergenceData<T: Float + Debug + Send + Sync + 'static> {
35    pub iteration: usize,
36    pub best_score: T,
37    pub convergence_rate: T,
38    pub stability_measure: T,
39    pub best_scores_over_time: Vec<T>,
40    pub diversity_over_time: Vec<T>,
41    pub convergence_generation: usize,
42    pub final_diversity: T,
43}
44
45/// Search result for tracking individual architecture evaluations
46#[derive(Debug, Clone)]
47pub struct SearchResult<T: Float + Debug + Send + Sync + 'static> {
48    /// Generated architecture
49    pub architecture: OptimizerArchitecture<T>,
50
51    /// Evaluation results
52    pub evaluation_results: EvaluationResults<T>,
53
54    /// Generation number
55    pub generation: usize,
56
57    /// Search time (seconds)
58    pub search_time: f64,
59
60    /// Resource usage
61    pub resource_usage: ResourceUsage<T>,
62
63    /// Architecture encoding
64    pub encoding: ArchitectureEncoding,
65
66    /// Additional metadata
67    pub metadata: SearchResultMetadata,
68}
69
70/// Evaluation results for a single architecture
71#[derive(Debug, Clone)]
72pub struct EvaluationResults<T: Float + Debug + Send + Sync + 'static> {
73    /// Metric scores
74    pub metric_scores: HashMap<EvaluationMetric, T>,
75
76    /// Overall score
77    pub overall_score: T,
78
79    /// Statistical confidence intervals
80    pub confidence_intervals: HashMap<EvaluationMetric, (T, T)>,
81
82    /// Evaluation time
83    pub evaluation_time: Duration,
84
85    /// Success flag
86    pub success: bool,
87
88    /// Error message (if failed)
89    pub error_message: Option<String>,
90
91    /// Cross-validation results
92    pub cv_results: Option<CrossValidationResults<T>>,
93
94    /// Benchmark-specific results
95    pub benchmark_results: HashMap<String, BenchmarkResult<T>>,
96
97    /// Performance trajectory during training
98    pub training_trajectory: Vec<TrainingSnapshot<T>>,
99}
100
101/// Cross-validation results
102#[derive(Debug, Clone)]
103pub struct CrossValidationResults<T: Float + Debug + Send + Sync + 'static> {
104    /// Results for each fold
105    pub fold_results: Vec<T>,
106
107    /// Mean score across folds
108    pub mean_score: T,
109
110    /// Standard deviation across folds
111    pub std_score: T,
112
113    /// Confidence interval for mean
114    pub confidence_interval: (T, T),
115
116    /// Statistical significance tests
117    pub statistical_tests: HashMap<String, StatisticalTestResult<T>>,
118}
119
120/// Statistical test result
121#[derive(Debug, Clone)]
122pub struct StatisticalTestResult<T: Float + Debug + Send + Sync + 'static> {
123    /// Test statistic value
124    pub test_statistic: T,
125
126    /// P-value
127    pub p_value: T,
128
129    /// Critical value
130    pub critical_value: T,
131
132    /// Reject null hypothesis flag
133    pub reject_null: bool,
134
135    /// Effect size
136    pub effect_size: Option<T>,
137}
138
139/// Benchmark-specific evaluation result
140#[derive(Debug, Clone)]
141pub struct BenchmarkResult<T: Float + Debug + Send + Sync + 'static> {
142    /// Benchmark name
143    pub benchmark_name: String,
144
145    /// Primary metric score
146    pub primary_score: T,
147
148    /// All metric scores
149    pub all_scores: HashMap<EvaluationMetric, T>,
150
151    /// Evaluation time
152    pub evaluation_time: Duration,
153
154    /// Memory usage peak
155    pub peak_memory_usage: usize,
156
157    /// Success flag
158    pub success: bool,
159
160    /// Benchmark-specific metadata
161    pub metadata: HashMap<String, String>,
162}
163
164/// Training snapshot during evaluation
165#[derive(Debug, Clone)]
166pub struct TrainingSnapshot<T: Float + Debug + Send + Sync + 'static> {
167    /// Epoch number
168    pub epoch: usize,
169
170    /// Training loss
171    pub training_loss: T,
172
173    /// Validation loss
174    pub validation_loss: Option<T>,
175
176    /// Training metrics
177    pub training_metrics: HashMap<EvaluationMetric, T>,
178
179    /// Validation metrics
180    pub validation_metrics: HashMap<EvaluationMetric, T>,
181
182    /// Learning rate
183    pub learning_rate: T,
184
185    /// Timestamp
186    pub timestamp: Duration,
187
188    /// Memory usage at this point
189    pub memory_usage: usize,
190}
191
192/// Resource usage tracking
193#[derive(Debug, Clone)]
194pub struct ResourceUsage<T: Float + Debug + Send + Sync + 'static> {
195    /// Memory usage (GB)
196    pub memory_gb: T,
197
198    /// CPU time (seconds)
199    pub cpu_time_seconds: T,
200
201    /// GPU time (seconds)
202    pub gpu_time_seconds: T,
203
204    /// Energy consumption (kWh)
205    pub energy_kwh: T,
206
207    /// Network I/O (GB)
208    pub network_io_gb: T,
209
210    /// Disk I/O (GB)
211    pub disk_io_gb: T,
212
213    /// Peak memory usage
214    pub peak_memory_gb: T,
215
216    /// Resource efficiency score
217    pub efficiency_score: T,
218
219    /// Cost in USD
220    pub cost_usd: T,
221
222    /// Network usage (GB) - alias for network_io_gb
223    pub network_gb: T,
224}
225
226/// Architecture encoding for reproducibility and analysis
227#[derive(Debug, Clone)]
228pub struct ArchitectureEncoding {
229    /// Encoding type
230    pub encoding_type: EncodingType,
231
232    /// Binary encoding
233    pub binary_encoding: Option<Vec<u8>>,
234
235    /// String encoding
236    pub string_encoding: Option<String>,
237
238    /// Graph encoding
239    pub graph_encoding: Option<GraphEncoding>,
240
241    /// Hash for quick comparison
242    pub hash: u64,
243
244    /// Encoding metadata
245    pub metadata: EncodingMetadata,
246}
247
248/// Architecture encoding types
249#[derive(Debug, Clone, Copy)]
250pub enum EncodingType {
251    Binary,
252    String,
253    Graph,
254    Neural,
255    Hybrid,
256}
257
258/// Graph-based architecture encoding
259#[derive(Debug, Clone)]
260pub struct GraphEncoding {
261    /// Nodes (components)
262    pub nodes: Vec<NodeEncoding>,
263
264    /// Edges (connections)
265    pub edges: Vec<EdgeEncoding>,
266
267    /// Graph properties
268    pub properties: GraphProperties,
269}
270
271/// Node encoding in graph representation
272#[derive(Debug, Clone)]
273pub struct NodeEncoding {
274    /// Node ID
275    pub id: usize,
276
277    /// Component type
278    pub component_type: String,
279
280    /// Component parameters
281    pub parameters: HashMap<String, f64>,
282
283    /// Node properties
284    pub properties: HashMap<String, String>,
285}
286
287/// Edge encoding in graph representation
288#[derive(Debug, Clone)]
289pub struct EdgeEncoding {
290    /// Source node ID
291    pub source: usize,
292
293    /// Target node ID
294    pub target: usize,
295
296    /// Connection type
297    pub connection_type: String,
298
299    /// Edge weight
300    pub weight: f64,
301
302    /// Edge properties
303    pub properties: HashMap<String, String>,
304}
305
306/// Graph properties
307#[derive(Debug, Clone)]
308pub struct GraphProperties {
309    /// Number of nodes
310    pub num_nodes: usize,
311
312    /// Number of edges
313    pub num_edges: usize,
314
315    /// Graph density
316    pub density: f64,
317
318    /// Average degree
319    pub average_degree: f64,
320
321    /// Is directed
322    pub is_directed: bool,
323
324    /// Has cycles
325    pub has_cycles: bool,
326}
327
328/// Encoding metadata
329#[derive(Debug, Clone)]
330pub struct EncodingMetadata {
331    /// Encoding version
332    pub version: String,
333
334    /// Creation timestamp
335    pub created_at: Instant,
336
337    /// Encoding size (bytes)
338    pub size_bytes: usize,
339
340    /// Compression ratio
341    pub compression_ratio: Option<f64>,
342
343    /// Encoding quality score
344    pub quality_score: Option<f64>,
345}
346
347/// Search result metadata
348#[derive(Debug, Clone)]
349pub struct SearchResultMetadata {
350    /// Search strategy used
351    pub search_strategy: String,
352
353    /// Controller type used
354    pub controller_type: String,
355
356    /// Evaluation method
357    pub evaluation_method: String,
358
359    /// Search phase (for progressive search)
360    pub search_phase: Option<String>,
361
362    /// Parent architectures (for evolutionary methods)
363    pub parent_architectures: Vec<u64>,
364
365    /// Mutation/crossover information
366    pub operation_info: Option<OperationInfo>,
367
368    /// Additional tags
369    pub tags: HashMap<String, String>,
370}
371
372/// Operation information for evolutionary/genetic methods
373#[derive(Debug, Clone)]
374pub struct OperationInfo {
375    /// Operation type (mutation, crossover, etc.)
376    pub operation_type: String,
377
378    /// Operation parameters
379    pub parameters: HashMap<String, f64>,
380
381    /// Success flag
382    pub success: bool,
383
384    /// Operation time
385    pub operation_time: Duration,
386}
387
388/// Search statistics tracking
389#[derive(Debug, Clone)]
390pub struct SearchStatistics<T: Float + Debug + Send + Sync + 'static> {
391    /// Total architectures evaluated
392    pub total_architectures_evaluated: usize,
393
394    /// Total evaluations (alias for compatibility)
395    pub total_evaluations: usize,
396
397    /// Current generation in evolutionary search
398    pub current_generation: usize,
399
400    /// Population diversity metric
401    pub population_diversity: T,
402
403    /// Average score across all evaluations
404    pub average_score: T,
405
406    /// Successful evaluations
407    pub successful_evaluations: usize,
408
409    /// Failed evaluations
410    pub failed_evaluations: usize,
411
412    /// Best score found
413    pub best_score: Option<T>,
414
415    /// Best architecture hash
416    pub best_architecture_hash: Option<u64>,
417
418    /// Average evaluation time
419    pub average_evaluation_time: Duration,
420
421    /// Total search time
422    pub total_search_time: Duration,
423
424    /// Score improvement over time
425    pub score_history: Vec<T>,
426
427    /// Resource utilization statistics
428    pub resource_stats: ResourceStatistics<T>,
429
430    /// Convergence metrics
431    pub convergence_metrics: ConvergenceMetrics<T>,
432
433    /// Diversity metrics
434    pub diversity_metrics: DiversityMetrics<T>,
435
436    /// Search efficiency metrics
437    pub efficiency_metrics: EfficiencyMetrics<T>,
438}
439
440/// Resource utilization statistics
441#[derive(Debug, Clone)]
442pub struct ResourceStatistics<T: Float + Debug + Send + Sync + 'static> {
443    /// Total memory used (GB)
444    pub total_memory_gb: T,
445
446    /// Total CPU time (hours)
447    pub total_cpu_hours: T,
448
449    /// Total GPU time (hours)
450    pub total_gpu_hours: T,
451
452    /// Total energy consumed (kWh)
453    pub total_energy_kwh: T,
454
455    /// Peak memory usage (GB)
456    pub peak_memory_gb: T,
457
458    /// Average resource utilization
459    pub average_utilization: T,
460
461    /// Resource efficiency score
462    pub efficiency_score: T,
463}
464
465/// Convergence metrics
466#[derive(Debug, Clone)]
467pub struct ConvergenceMetrics<T: Float + Debug + Send + Sync + 'static> {
468    /// Generations to convergence
469    pub generations_to_convergence: Option<usize>,
470
471    /// Convergence rate
472    pub convergence_rate: Option<T>,
473
474    /// Plateau detection
475    pub plateau_generations: usize,
476
477    /// Score variance over last N generations
478    pub recent_score_variance: T,
479
480    /// Improvement rate (scores per generation)
481    pub improvement_rate: T,
482
483    /// Stagnation detection
484    pub is_stagnating: bool,
485}
486
487/// Diversity metrics
488#[derive(Debug, Clone)]
489pub struct DiversityMetrics<T: Float + Debug + Send + Sync + 'static> {
490    /// Population diversity score
491    pub population_diversity: T,
492
493    /// Architecture uniqueness ratio
494    pub uniqueness_ratio: T,
495
496    /// Genotypic diversity
497    pub genotypic_diversity: T,
498
499    /// Phenotypic diversity
500    pub phenotypic_diversity: T,
501
502    /// Diversity trends over time
503    pub diversity_history: Vec<T>,
504
505    /// Diversity maintenance score
506    pub diversity_maintenance: T,
507}
508
509/// Search efficiency metrics
510#[derive(Debug, Clone)]
511pub struct EfficiencyMetrics<T: Float + Debug + Send + Sync + 'static> {
512    /// Evaluations per unit improvement
513    pub evaluations_per_improvement: T,
514
515    /// Time to find best solution
516    pub time_to_best: Duration,
517
518    /// Resource cost per unit improvement
519    pub resource_cost_per_improvement: T,
520
521    /// Search efficiency score
522    pub efficiency_score: T,
523
524    /// Pareto efficiency (for multi-objective)
525    pub pareto_efficiency: Option<T>,
526
527    /// Hypervolume indicator (for multi-objective)
528    pub hypervolume: Option<T>,
529}
530
531/// Final search results
532#[derive(Debug, Clone)]
533pub struct SearchResults<T: Float + Debug + Send + Sync + 'static> {
534    /// Best architectures found
535    pub best_architectures: Vec<SearchResult<T>>,
536
537    /// Pareto front (for multi-objective optimization)
538    pub pareto_front: Option<ParetoFront<T>>,
539
540    /// Complete search history
541    pub search_history: Vec<SearchResult<T>>,
542
543    /// Search statistics
544    pub search_statistics: SearchStatistics<T>,
545
546    /// Final evaluation summary
547    pub evaluation_summary: EvaluationSummary<T>,
548
549    /// Search configuration used
550    pub search_configuration: SearchConfigSummary,
551
552    /// Recommendations for future searches
553    pub recommendations: Vec<SearchRecommendation>,
554
555    /// Resource usage summary
556    pub resource_usage_summary: ResourceUsageSummary<T>,
557
558    /// Total search time in seconds
559    pub search_time_seconds: f64,
560
561    /// Convergence data
562    pub convergence_data: ConvergenceData<T>,
563
564    /// Original configuration
565    pub config: SearchConfigSummary,
566}
567
568/// Resource usage summary
569#[derive(Debug, Clone)]
570pub struct ResourceUsageSummary<T: Float + Debug + Send + Sync + 'static> {
571    /// Total memory used (GB)
572    pub total_memory_gb: T,
573
574    /// Total CPU time (hours)
575    pub total_cpu_hours: T,
576
577    /// Total GPU time (hours)
578    pub total_gpu_hours: T,
579
580    /// Total energy consumed (kWh)
581    pub total_energy_kwh: T,
582
583    /// Total cost (USD)
584    pub total_cost_usd: T,
585
586    /// Average efficiency score
587    pub average_efficiency: T,
588}
589
590/// Evaluation summary
591#[derive(Debug, Clone)]
592pub struct EvaluationSummary<T: Float + Debug + Send + Sync + 'static> {
593    /// Total evaluations performed
594    pub total_evaluations: usize,
595
596    /// Evaluation success rate
597    pub success_rate: T,
598
599    /// Best score achieved
600    pub best_score: T,
601
602    /// Score distribution statistics
603    pub score_statistics: ScoreStatistics<T>,
604
605    /// Benchmark performance summary
606    pub benchmark_summary: HashMap<String, BenchmarkSummary<T>>,
607
608    /// Resource usage summary
609    pub resource_summary: ResourceSummary<T>,
610}
611
612/// Score distribution statistics
613#[derive(Debug, Clone)]
614pub struct ScoreStatistics<T: Float + Debug + Send + Sync + 'static> {
615    /// Mean score
616    pub mean: T,
617
618    /// Median score
619    pub median: T,
620
621    /// Standard deviation
622    pub std_dev: T,
623
624    /// Minimum score
625    pub min: T,
626
627    /// Maximum score
628    pub max: T,
629
630    /// Percentiles (25th, 75th, 90th, 95th, 99th)
631    pub percentiles: HashMap<usize, T>,
632
633    /// Score distribution histogram
634    pub histogram: Vec<(T, usize)>,
635}
636
637/// Benchmark performance summary
638#[derive(Debug, Clone)]
639pub struct BenchmarkSummary<T: Float + Debug + Send + Sync + 'static> {
640    /// Benchmark name
641    pub benchmark_name: String,
642
643    /// Best score on this benchmark
644    pub best_score: T,
645
646    /// Average score on this benchmark
647    pub average_score: T,
648
649    /// Number of successful evaluations
650    pub successful_evaluations: usize,
651
652    /// Evaluation time statistics
653    pub time_statistics: TimeStatistics,
654
655    /// Score improvement over time
656    pub improvement_trajectory: Vec<T>,
657}
658
659/// Time statistics
660#[derive(Debug, Clone)]
661pub struct TimeStatistics {
662    /// Mean time
663    pub mean: Duration,
664
665    /// Median time
666    pub median: Duration,
667
668    /// Standard deviation
669    pub std_dev: Duration,
670
671    /// Minimum time
672    pub min: Duration,
673
674    /// Maximum time
675    pub max: Duration,
676}
677
678/// Resource usage summary
679#[derive(Debug, Clone)]
680pub struct ResourceSummary<T: Float + Debug + Send + Sync + 'static> {
681    /// Total resources consumed
682    pub total_consumption: ResourceUsage<T>,
683
684    /// Average resource usage per evaluation
685    pub average_per_evaluation: ResourceUsage<T>,
686
687    /// Peak resource usage
688    pub peak_usage: ResourceUsage<T>,
689
690    /// Resource efficiency metrics
691    pub efficiency_metrics: ResourceEfficiencyMetrics<T>,
692}
693
694/// Resource efficiency metrics
695#[derive(Debug, Clone)]
696pub struct ResourceEfficiencyMetrics<T: Float + Debug + Send + Sync + 'static> {
697    /// Memory efficiency (useful work per GB)
698    pub memory_efficiency: T,
699
700    /// CPU efficiency (useful work per CPU hour)
701    pub cpu_efficiency: T,
702
703    /// GPU efficiency (useful work per GPU hour)
704    pub gpu_efficiency: T,
705
706    /// Energy efficiency (useful work per kWh)
707    pub energy_efficiency: T,
708
709    /// Overall resource efficiency score
710    pub overall_efficiency: T,
711}
712
713/// Search configuration summary for results
714#[derive(Debug, Clone)]
715pub struct SearchConfigSummary {
716    /// Search strategy used
717    pub search_strategy: String,
718
719    /// Population size
720    pub population_size: usize,
721
722    /// Search budget
723    pub search_budget: usize,
724
725    /// Evaluation configuration summary
726    pub evaluation_config: String,
727
728    /// Multi-objective configuration
729    pub multi_objective_config: Option<String>,
730
731    /// Resource constraints summary
732    pub resource_constraints: String,
733
734    /// Key hyperparameters
735    pub key_hyperparameters: HashMap<String, String>,
736}
737
738/// Search recommendations for future improvements
739#[derive(Debug, Clone)]
740pub struct SearchRecommendation {
741    /// Recommendation type
742    pub recommendation_type: RecommendationType,
743
744    /// Recommendation description
745    pub description: String,
746
747    /// Priority level
748    pub priority: RecommendationPriority,
749
750    /// Expected improvement
751    pub expected_improvement: Option<f64>,
752
753    /// Implementation effort
754    pub implementation_effort: ImplementationEffort,
755
756    /// Supporting evidence
757    pub evidence: Vec<String>,
758}
759
760/// Types of search recommendations
761#[derive(Debug, Clone, Copy)]
762pub enum RecommendationType {
763    SearchStrategyChange,
764    PopulationSizeAdjustment,
765    BudgetReallocation,
766    EvaluationMethodImprovement,
767    ResourceOptimization,
768    HyperparameterTuning,
769    SearchSpaceModification,
770    DiversityImprovement,
771    ConvergenceAcceleration,
772}
773
774/// Recommendation priority levels
775#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
776pub enum RecommendationPriority {
777    Low,
778    Medium,
779    High,
780    Critical,
781}
782
783/// Implementation effort estimates
784#[derive(Debug, Clone, Copy)]
785pub enum ImplementationEffort {
786    Minimal,
787    Low,
788    Medium,
789    High,
790    Extensive,
791}
792
793// Default implementations
794impl<T: Float + Debug + Send + Sync + 'static> Default for SearchStatistics<T> {
795    fn default() -> Self {
796        Self {
797            total_architectures_evaluated: 0,
798            total_evaluations: 0,
799            current_generation: 0,
800            population_diversity: T::zero(),
801            average_score: T::zero(),
802            successful_evaluations: 0,
803            failed_evaluations: 0,
804            best_score: None,
805            best_architecture_hash: None,
806            average_evaluation_time: Duration::from_secs(0),
807            total_search_time: Duration::from_secs(0),
808            score_history: Vec::new(),
809            resource_stats: ResourceStatistics::default(),
810            convergence_metrics: ConvergenceMetrics::default(),
811            diversity_metrics: DiversityMetrics::default(),
812            efficiency_metrics: EfficiencyMetrics::default(),
813        }
814    }
815}
816
817impl<T: Float + Debug + Send + Sync + 'static> Default for ResourceStatistics<T> {
818    fn default() -> Self {
819        Self {
820            total_memory_gb: T::zero(),
821            total_cpu_hours: T::zero(),
822            total_gpu_hours: T::zero(),
823            total_energy_kwh: T::zero(),
824            peak_memory_gb: T::zero(),
825            average_utilization: T::zero(),
826            efficiency_score: T::zero(),
827        }
828    }
829}
830
831impl<T: Float + Debug + Send + Sync + 'static> Default for ConvergenceMetrics<T> {
832    fn default() -> Self {
833        Self {
834            generations_to_convergence: None,
835            convergence_rate: None,
836            plateau_generations: 0,
837            recent_score_variance: T::zero(),
838            improvement_rate: T::zero(),
839            is_stagnating: false,
840        }
841    }
842}
843
844impl<T: Float + Debug + Send + Sync + 'static> Default for DiversityMetrics<T> {
845    fn default() -> Self {
846        Self {
847            population_diversity: T::one(),
848            uniqueness_ratio: T::one(),
849            genotypic_diversity: T::one(),
850            phenotypic_diversity: T::one(),
851            diversity_history: Vec::new(),
852            diversity_maintenance: T::one(),
853        }
854    }
855}
856
857impl<T: Float + Debug + Send + Sync + 'static> Default for EfficiencyMetrics<T> {
858    fn default() -> Self {
859        Self {
860            evaluations_per_improvement: T::one(),
861            time_to_best: Duration::from_secs(0),
862            resource_cost_per_improvement: T::zero(),
863            efficiency_score: T::zero(),
864            pareto_efficiency: None,
865            hypervolume: None,
866        }
867    }
868}
869
870impl<T: Float + Debug + Send + Sync + 'static> Default for ResourceUsage<T> {
871    fn default() -> Self {
872        Self {
873            memory_gb: T::zero(),
874            cpu_time_seconds: T::zero(),
875            gpu_time_seconds: T::zero(),
876            energy_kwh: T::zero(),
877            network_io_gb: T::zero(),
878            disk_io_gb: T::zero(),
879            peak_memory_gb: T::zero(),
880            efficiency_score: T::zero(),
881            cost_usd: T::zero(),
882            network_gb: T::zero(),
883        }
884    }
885}
886
887impl Default for ArchitectureEncoding {
888    fn default() -> Self {
889        Self {
890            encoding_type: EncodingType::String,
891            binary_encoding: None,
892            string_encoding: None,
893            graph_encoding: None,
894            hash: 0,
895            metadata: EncodingMetadata::default(),
896        }
897    }
898}
899
900impl Default for EncodingMetadata {
901    fn default() -> Self {
902        Self {
903            version: "1.0".to_string(),
904            created_at: Instant::now(),
905            size_bytes: 0,
906            compression_ratio: None,
907            quality_score: None,
908        }
909    }
910}
911
912impl Default for SearchResultMetadata {
913    fn default() -> Self {
914        Self {
915            search_strategy: "Unknown".to_string(),
916            controller_type: "Unknown".to_string(),
917            evaluation_method: "Unknown".to_string(),
918            search_phase: None,
919            parent_architectures: Vec::new(),
920            operation_info: None,
921            tags: HashMap::new(),
922        }
923    }
924}
925
926impl Default for GraphProperties {
927    fn default() -> Self {
928        Self {
929            num_nodes: 0,
930            num_edges: 0,
931            density: 0.0,
932            average_degree: 0.0,
933            is_directed: true,
934            has_cycles: false,
935        }
936    }
937}
938
939impl Default for TimeStatistics {
940    fn default() -> Self {
941        Self {
942            mean: Duration::from_secs(0),
943            median: Duration::from_secs(0),
944            std_dev: Duration::from_secs(0),
945            min: Duration::from_secs(0),
946            max: Duration::from_secs(0),
947        }
948    }
949}
950
951/// Utility functions for results analysis
952impl<T: Float + Debug + Send + Sync + 'static> SearchStatistics<T> {
953    /// Calculate search efficiency score.
954    ///
955    /// The mean of the evaluation success rate and the evaluations-per-second
956    /// rate. Zero when nothing has been evaluated; the time term is dropped (not
957    /// treated as infinite) when the search has not yet run for a whole second.
958    ///
959    /// Returns an error rather than panicking when a count cannot be represented
960    /// in `T`: the previous `.expect("unwrap failed")` on the elapsed-seconds
961    /// conversion would have aborted a completed search while it was reporting
962    /// its own statistics. The companion `unwrap_or_else(T::zero)` calls were no
963    /// better — a success count silently read as zero turns a perfect search into
964    /// an efficiency of zero.
965    pub fn calculate_efficiency_score(&self) -> Result<T> {
966        if self.total_architectures_evaluated == 0 {
967            return Ok(T::zero());
968        }
969
970        let successes: T = count_as(self.successful_evaluations, "successful evaluations")?;
971        let attempts: T = count_as(
972            self.total_architectures_evaluated,
973            "evaluated architectures",
974        )?;
975        let success_rate = successes / attempts;
976
977        let elapsed_seconds = self.total_search_time.as_secs();
978        let time_efficiency = if elapsed_seconds > 0 {
979            let seconds: T = count_as(elapsed_seconds as usize, "elapsed search seconds")?;
980            successes / seconds
981        } else {
982            T::zero()
983        };
984
985        let two: T = scalar_as(2.0, "efficiency averaging divisor")?;
986        Ok((success_rate + time_efficiency) / two)
987    }
988
989    /// Check if search has converged
990    pub fn has_converged(&self, patience: usize, min_improvement: T) -> bool {
991        if self.score_history.len() < patience {
992            return false;
993        }
994
995        let recent_scores = &self.score_history[self.score_history.len() - patience..];
996        let max_score = recent_scores
997            .iter()
998            .fold(T::neg_infinity(), |a, &b| a.max(b));
999        let min_score = recent_scores.iter().fold(T::infinity(), |a, &b| a.min(b));
1000
1001        max_score - min_score < min_improvement
1002    }
1003
1004    /// Get improvement trend
1005    pub fn get_improvement_trend(&self, window_size: usize) -> Option<T> {
1006        if self.score_history.len() < window_size * 2 {
1007            return None;
1008        }
1009
1010        let recent_scores = &self.score_history[self.score_history.len() - window_size..];
1011        let older_scores = &self.score_history
1012            [self.score_history.len() - window_size * 2..self.score_history.len() - window_size];
1013
1014        let recent_mean = recent_scores.iter().fold(T::zero(), |a, &b| a + b)
1015            / scirs2_core::numeric::NumCast::from(window_size).unwrap_or_else(|| T::zero());
1016        let older_mean = older_scores.iter().fold(T::zero(), |a, &b| a + b)
1017            / scirs2_core::numeric::NumCast::from(window_size).unwrap_or_else(|| T::zero());
1018
1019        Some(recent_mean - older_mean)
1020    }
1021}
1022
1023impl<T: Float + Debug + Send + Sync + 'static> ResourceUsage<T> {
1024    /// Calculate total resource cost
1025    pub fn total_cost(&self, costs: &ResourceCosts<T>) -> T {
1026        self.memory_gb * costs.memory_cost_per_gb
1027            + self.cpu_time_seconds * costs.cpu_cost_per_second
1028            + self.gpu_time_seconds * costs.gpu_cost_per_second
1029            + self.energy_kwh * costs.energy_cost_per_kwh
1030    }
1031
1032    /// Check if usage exceeds limits
1033    pub fn exceeds_limits(&self, limits: &ResourceLimits<T>) -> bool {
1034        self.memory_gb > limits.max_memory_gb
1035            || self.cpu_time_seconds > limits.max_cpu_seconds
1036            || self.gpu_time_seconds > limits.max_gpu_seconds
1037            || self.energy_kwh > limits.max_energy_kwh
1038    }
1039}
1040
1041/// Resource cost structure
1042#[derive(Debug, Clone)]
1043pub struct ResourceCosts<T: Float + Debug + Send + Sync + 'static> {
1044    pub memory_cost_per_gb: T,
1045    pub cpu_cost_per_second: T,
1046    pub gpu_cost_per_second: T,
1047    pub energy_cost_per_kwh: T,
1048}
1049
1050/// Resource limit structure
1051#[derive(Debug, Clone)]
1052pub struct ResourceLimits<T: Float + Debug + Send + Sync + 'static> {
1053    pub max_memory_gb: T,
1054    pub max_cpu_seconds: T,
1055    pub max_gpu_seconds: T,
1056    pub max_energy_kwh: T,
1057}
1058
1059// Default implementations for missing types
1060
1061impl<T: Float + Debug + Send + Sync + 'static> Default for ScoreStatistics<T> {
1062    fn default() -> Self {
1063        Self {
1064            mean: T::zero(),
1065            median: T::zero(),
1066            std_dev: T::zero(),
1067            min: T::zero(),
1068            max: T::zero(),
1069            percentiles: HashMap::new(),
1070            histogram: Vec::new(),
1071        }
1072    }
1073}
1074
1075impl<T: Float + Debug + Send + Sync + 'static> Default for ResourceSummary<T> {
1076    fn default() -> Self {
1077        Self {
1078            total_consumption: ResourceUsage::default(),
1079            average_per_evaluation: ResourceUsage::default(),
1080            peak_usage: ResourceUsage::default(),
1081            efficiency_metrics: ResourceEfficiencyMetrics::default(),
1082        }
1083    }
1084}
1085
1086impl<T: Float + Debug + Send + Sync + 'static> Default for ResourceEfficiencyMetrics<T> {
1087    fn default() -> Self {
1088        Self {
1089            cpu_efficiency: T::zero(),
1090            gpu_efficiency: T::zero(),
1091            memory_efficiency: T::zero(),
1092            energy_efficiency: T::zero(),
1093            overall_efficiency: T::zero(),
1094        }
1095    }
1096}
1097
1098#[cfg(test)]
1099mod tests {
1100    use super::*;
1101
1102    #[test]
1103    fn test_search_statistics_default() {
1104        let stats = SearchStatistics::<f32>::default();
1105        assert_eq!(stats.total_architectures_evaluated, 0);
1106        assert_eq!(stats.successful_evaluations, 0);
1107        assert_eq!(stats.failed_evaluations, 0);
1108        assert!(stats.best_score.is_none());
1109    }
1110
1111    #[test]
1112    fn test_efficiency_score_calculation() {
1113        let stats = SearchStatistics::<f32> {
1114            total_architectures_evaluated: 100,
1115            successful_evaluations: 80,
1116            total_search_time: Duration::from_secs(3600),
1117            ..Default::default()
1118        };
1119
1120        let efficiency = stats
1121            .calculate_efficiency_score()
1122            .expect("counts this small are representable in f32");
1123        assert!(efficiency > 0.0);
1124        assert!(efficiency <= 1.0);
1125
1126        // Nothing evaluated: an honest zero rather than a division by zero.
1127        let empty = SearchStatistics::<f32>::default();
1128        assert_eq!(
1129            empty
1130                .calculate_efficiency_score()
1131                .expect("an empty search has a defined score"),
1132            0.0
1133        );
1134
1135        // A search shorter than one second drops the rate term instead of
1136        // treating it as infinite.
1137        let brief = SearchStatistics::<f32> {
1138            total_architectures_evaluated: 4,
1139            successful_evaluations: 4,
1140            total_search_time: Duration::from_millis(120),
1141            ..Default::default()
1142        };
1143        assert!(
1144            (brief
1145                .calculate_efficiency_score()
1146                .expect("a sub-second search has a defined score")
1147                - 0.5)
1148                .abs()
1149                < 1e-6
1150        );
1151    }
1152
1153    #[test]
1154    fn test_convergence_detection() {
1155        let stats = SearchStatistics::<f32> {
1156            score_history: vec![0.5, 0.6, 0.65, 0.66, 0.67, 0.67, 0.67, 0.68],
1157            ..Default::default()
1158        };
1159
1160        let converged = stats.has_converged(5, 0.05);
1161        assert!(converged);
1162
1163        let not_converged = stats.has_converged(5, 0.001);
1164        assert!(!not_converged);
1165    }
1166
1167    #[test]
1168    fn test_improvement_trend() {
1169        let stats = SearchStatistics::<f32> {
1170            score_history: vec![0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
1171            ..Default::default()
1172        };
1173
1174        let trend = stats.get_improvement_trend(2);
1175        assert!(trend.is_some());
1176        assert!(trend.expect("unwrap failed") > 0.0); // Positive trend
1177    }
1178
1179    #[test]
1180    fn test_resource_usage_calculations() {
1181        let usage = ResourceUsage {
1182            memory_gb: 10.0,
1183            cpu_time_seconds: 3600.0,
1184            gpu_time_seconds: 1800.0,
1185            energy_kwh: 5.0,
1186            network_io_gb: 1.0,
1187            disk_io_gb: 2.0,
1188            peak_memory_gb: 12.0,
1189            efficiency_score: 0.8,
1190            cost_usd: 0.0,
1191            network_gb: 1.0,
1192        };
1193
1194        let costs = ResourceCosts {
1195            memory_cost_per_gb: 0.1,
1196            cpu_cost_per_second: 0.001,
1197            gpu_cost_per_second: 0.01,
1198            energy_cost_per_kwh: 0.2,
1199        };
1200
1201        let total_cost = usage.total_cost(&costs);
1202        assert!(total_cost > 0.0);
1203
1204        let limits = ResourceLimits {
1205            max_memory_gb: 8.0,
1206            max_cpu_seconds: 7200.0,
1207            max_gpu_seconds: 3600.0,
1208            max_energy_kwh: 10.0,
1209        };
1210
1211        let exceeds = usage.exceeds_limits(&limits);
1212        assert!(exceeds); // Memory exceeds limit
1213    }
1214
1215    #[test]
1216    fn test_architecture_encoding() {
1217        let encoding = ArchitectureEncoding::default();
1218        assert_eq!(encoding.hash, 0);
1219        assert!(matches!(encoding.encoding_type, EncodingType::String));
1220    }
1221}