1#![allow(unused_variables)] use crate::tensor::Tensor;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::sync::{Arc, RwLock};
7use std::time::{Duration, Instant};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct AdaptiveComputationConfig {
11 pub max_layers: usize,
12 pub min_layers: usize,
13 pub halt_threshold: f32,
14 pub time_penalty: f32,
15 pub early_exit_threshold: f32,
16 pub complexity_estimation_method: ComplexityEstimationMethod,
17 pub dynamic_depth_strategy: DynamicDepthStrategy,
18}
19
20impl Default for AdaptiveComputationConfig {
21 fn default() -> Self {
22 Self {
23 max_layers: 12,
24 min_layers: 2,
25 halt_threshold: 0.99,
26 time_penalty: 0.01,
27 early_exit_threshold: 0.95,
28 complexity_estimation_method: ComplexityEstimationMethod::EntropyBased,
29 dynamic_depth_strategy: DynamicDepthStrategy::ConfidenceBased,
30 }
31 }
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub enum ComplexityEstimationMethod {
36 EntropyBased,
37 AttentionBased,
38 GradientNorm,
39 LearningCurve,
40 Hybrid,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub enum DynamicDepthStrategy {
45 ConfidenceBased,
46 UncertaintyBased,
47 ResourceConstrained,
48 LatencyOptimized,
49 AccuracyOptimized,
50}
51
52#[derive(Debug, Clone)]
53pub struct ComputationBudget {
54 pub max_flops: u64,
55 pub max_memory_mb: u32,
56 pub max_latency_ms: u32,
57 pub remaining_flops: u64,
58 pub remaining_memory_mb: u32,
59 pub remaining_time_ms: u32,
60}
61
62impl ComputationBudget {
63 pub fn new(max_flops: u64, max_memory_mb: u32, max_latency_ms: u32) -> Self {
64 Self {
65 max_flops,
66 max_memory_mb,
67 max_latency_ms,
68 remaining_flops: max_flops,
69 remaining_memory_mb: max_memory_mb,
70 remaining_time_ms: max_latency_ms,
71 }
72 }
73
74 pub fn can_afford(&self, flops: u64, memory_mb: u32, time_ms: u32) -> bool {
75 self.remaining_flops >= flops
76 && self.remaining_memory_mb >= memory_mb
77 && self.remaining_time_ms >= time_ms
78 }
79
80 pub fn consume(&mut self, flops: u64, memory_mb: u32, time_ms: u32) {
81 self.remaining_flops = self.remaining_flops.saturating_sub(flops);
82 self.remaining_memory_mb = self.remaining_memory_mb.saturating_sub(memory_mb);
83 self.remaining_time_ms = self.remaining_time_ms.saturating_sub(time_ms);
84 }
85}
86
87#[derive(Debug, Clone)]
88pub struct LayerMetrics {
89 pub layer_id: usize,
90 pub flops_estimate: u64,
91 pub memory_usage_mb: u32,
92 pub execution_time_ms: u32,
93 pub confidence_score: f32,
94 pub uncertainty_score: f32,
95 pub output_entropy: f32,
96}
97
98pub trait AdaptiveComputationStrategy {
99 fn should_continue(
100 &self,
101 layer_id: usize,
102 metrics: &LayerMetrics,
103 budget: &ComputationBudget,
104 config: &AdaptiveComputationConfig,
105 ) -> bool;
106
107 fn estimate_remaining_cost(
108 &self,
109 current_layer: usize,
110 total_layers: usize,
111 current_metrics: &LayerMetrics,
112 ) -> (u64, u32, u32); fn adjust_computation_path(
115 &self,
116 input_complexity: f32,
117 available_budget: &ComputationBudget,
118 config: &AdaptiveComputationConfig,
119 ) -> ComputationPath;
120}
121
122#[derive(Debug, Clone)]
123pub struct ComputationPath {
124 pub layers_to_execute: Vec<usize>,
125 pub skip_patterns: Vec<LayerSkipPattern>,
126 pub early_exit_points: Vec<usize>,
127 pub resource_allocation: ResourceAllocation,
128}
129
130#[derive(Debug, Clone)]
131pub enum LayerSkipPattern {
132 Skip,
133 Approximate,
134 Cached,
135 Pruned,
136}
137
138#[derive(Debug, Clone)]
139pub struct ResourceAllocation {
140 pub memory_per_layer: HashMap<usize, u32>,
141 pub compute_intensity: HashMap<usize, f32>,
142 pub parallelism_factor: HashMap<usize, u32>,
143}
144
145pub struct ConfidenceBasedStrategy {
146 confidence_history: Arc<RwLock<Vec<f32>>>,
147 #[allow(dead_code)]
148 performance_tracker: Arc<RwLock<PerformanceTracker>>,
149}
150
151impl Default for ConfidenceBasedStrategy {
152 fn default() -> Self {
153 Self::new()
154 }
155}
156
157impl ConfidenceBasedStrategy {
158 pub fn new() -> Self {
159 Self {
160 confidence_history: Arc::new(RwLock::new(Vec::new())),
161 performance_tracker: Arc::new(RwLock::new(PerformanceTracker::new())),
162 }
163 }
164}
165
166impl AdaptiveComputationStrategy for ConfidenceBasedStrategy {
167 fn should_continue(
168 &self,
169 layer_id: usize,
170 metrics: &LayerMetrics,
171 budget: &ComputationBudget,
172 config: &AdaptiveComputationConfig,
173 ) -> bool {
174 if metrics.confidence_score >= config.early_exit_threshold {
176 return false;
177 }
178
179 if layer_id < config.min_layers {
181 return true;
182 }
183
184 if layer_id >= config.max_layers {
186 return false;
187 }
188
189 let (est_flops, est_memory, est_time) =
191 self.estimate_remaining_cost(layer_id, config.max_layers, metrics);
192
193 if !budget.can_afford(est_flops, est_memory, est_time) {
194 return false;
195 }
196
197 let mut confidence_history = self
199 .confidence_history
200 .write()
201 .expect("confidence_history lock should not be poisoned");
202 confidence_history.push(metrics.confidence_score);
203
204 if confidence_history.len() >= 3 {
205 let recent_growth = confidence_history[confidence_history.len() - 1]
206 - confidence_history[confidence_history.len() - 3];
207
208 if recent_growth < 0.01 && metrics.confidence_score > config.halt_threshold {
209 return false;
210 }
211 }
212
213 true
214 }
215
216 fn estimate_remaining_cost(
217 &self,
218 current_layer: usize,
219 total_layers: usize,
220 current_metrics: &LayerMetrics,
221 ) -> (u64, u32, u32) {
222 let remaining_layers = total_layers.saturating_sub(current_layer);
223
224 let avg_flops_per_layer = current_metrics.flops_estimate;
226 let avg_memory_per_layer = current_metrics.memory_usage_mb;
227 let avg_time_per_layer = current_metrics.execution_time_ms;
228
229 (
230 avg_flops_per_layer * remaining_layers as u64,
231 avg_memory_per_layer * remaining_layers as u32,
232 avg_time_per_layer * remaining_layers as u32,
233 )
234 }
235
236 fn adjust_computation_path(
237 &self,
238 input_complexity: f32,
239 available_budget: &ComputationBudget,
240 config: &AdaptiveComputationConfig,
241 ) -> ComputationPath {
242 let mut layers_to_execute = Vec::new();
243 let mut skip_patterns = HashMap::new();
244 let mut resource_allocation = ResourceAllocation {
245 memory_per_layer: HashMap::new(),
246 compute_intensity: HashMap::new(),
247 parallelism_factor: HashMap::new(),
248 };
249
250 let estimated_layers = if input_complexity < 0.3 {
252 config.min_layers
253 } else if input_complexity < 0.7 {
254 (config.min_layers + config.max_layers) / 2
255 } else {
256 config.max_layers
257 };
258
259 for layer_id in 0..estimated_layers {
260 layers_to_execute.push(layer_id);
261
262 let layer_importance = 1.0 - (layer_id as f32 / estimated_layers as f32);
264 let complexity_factor = input_complexity * layer_importance;
265
266 resource_allocation.memory_per_layer.insert(
267 layer_id,
268 (available_budget.max_memory_mb as f32 / estimated_layers as f32
269 * complexity_factor) as u32,
270 );
271
272 resource_allocation.compute_intensity.insert(layer_id, complexity_factor);
273 resource_allocation.parallelism_factor.insert(layer_id, 1);
274
275 if complexity_factor < 0.3 && layer_id > config.min_layers {
277 skip_patterns.insert(layer_id, LayerSkipPattern::Approximate);
278 }
279 }
280
281 ComputationPath {
282 layers_to_execute,
283 skip_patterns: skip_patterns.into_values().collect(),
284 early_exit_points: vec![estimated_layers / 2, estimated_layers * 3 / 4],
285 resource_allocation,
286 }
287 }
288}
289
290pub struct UncertaintyBasedStrategy {
291 #[allow(dead_code)]
292 uncertainty_tracker: Arc<RwLock<Vec<f32>>>,
293}
294
295impl Default for UncertaintyBasedStrategy {
296 fn default() -> Self {
297 Self::new()
298 }
299}
300
301impl UncertaintyBasedStrategy {
302 pub fn new() -> Self {
303 Self {
304 uncertainty_tracker: Arc::new(RwLock::new(Vec::new())),
305 }
306 }
307}
308
309impl AdaptiveComputationStrategy for UncertaintyBasedStrategy {
310 fn should_continue(
311 &self,
312 layer_id: usize,
313 metrics: &LayerMetrics,
314 budget: &ComputationBudget,
315 config: &AdaptiveComputationConfig,
316 ) -> bool {
317 if metrics.uncertainty_score > 0.1 && layer_id < config.max_layers {
319 let (est_flops, est_memory, est_time) =
320 self.estimate_remaining_cost(layer_id, config.max_layers, metrics);
321 return budget.can_afford(est_flops, est_memory, est_time);
322 }
323
324 layer_id < config.min_layers
326 }
327
328 fn estimate_remaining_cost(
329 &self,
330 current_layer: usize,
331 total_layers: usize,
332 current_metrics: &LayerMetrics,
333 ) -> (u64, u32, u32) {
334 let remaining_layers = total_layers.saturating_sub(current_layer);
335
336 let uncertainty_factor = current_metrics.uncertainty_score.max(0.1);
338
339 (
340 (current_metrics.flops_estimate as f32 * remaining_layers as f32 * uncertainty_factor)
341 as u64,
342 (current_metrics.memory_usage_mb as f32 * remaining_layers as f32 * uncertainty_factor)
343 as u32,
344 (current_metrics.execution_time_ms as f32
345 * remaining_layers as f32
346 * uncertainty_factor) as u32,
347 )
348 }
349
350 fn adjust_computation_path(
351 &self,
352 input_complexity: f32,
353 available_budget: &ComputationBudget,
354 config: &AdaptiveComputationConfig,
355 ) -> ComputationPath {
356 let estimated_layers = ((input_complexity * config.max_layers as f32) as usize)
358 .max(config.min_layers)
359 .min(config.max_layers);
360
361 let layers_to_execute: Vec<usize> = (0..estimated_layers).collect();
362 let mut resource_allocation = ResourceAllocation {
363 memory_per_layer: HashMap::new(),
364 compute_intensity: HashMap::new(),
365 parallelism_factor: HashMap::new(),
366 };
367
368 for layer_id in &layers_to_execute {
370 let uncertainty_reduction_factor = 1.0 + (*layer_id as f32 / estimated_layers as f32);
371
372 resource_allocation.memory_per_layer.insert(
373 *layer_id,
374 (available_budget.max_memory_mb as f32 / estimated_layers as f32
375 * uncertainty_reduction_factor) as u32,
376 );
377
378 resource_allocation
379 .compute_intensity
380 .insert(*layer_id, uncertainty_reduction_factor);
381 resource_allocation.parallelism_factor.insert(*layer_id, 1);
382 }
383
384 ComputationPath {
385 layers_to_execute,
386 skip_patterns: Vec::new(),
387 early_exit_points: vec![estimated_layers / 3, estimated_layers * 2 / 3],
388 resource_allocation,
389 }
390 }
391}
392
393#[derive(Debug, Clone)]
394pub struct PerformanceTracker {
395 layer_execution_times: HashMap<usize, Vec<u32>>,
396 accuracy_by_layers: HashMap<usize, Vec<f32>>,
397 resource_usage_history: Vec<(u64, u32, u32)>, }
399
400impl Default for PerformanceTracker {
401 fn default() -> Self {
402 Self::new()
403 }
404}
405
406impl PerformanceTracker {
407 pub fn new() -> Self {
408 Self {
409 layer_execution_times: HashMap::new(),
410 accuracy_by_layers: HashMap::new(),
411 resource_usage_history: Vec::new(),
412 }
413 }
414
415 pub fn record_layer_execution(&mut self, layer_id: usize, execution_time_ms: u32) {
416 self.layer_execution_times.entry(layer_id).or_default().push(execution_time_ms);
417 }
418
419 pub fn record_accuracy(&mut self, layers_used: usize, accuracy: f32) {
420 self.accuracy_by_layers.entry(layers_used).or_default().push(accuracy);
421 }
422
423 pub fn record_resource_usage(&mut self, flops: u64, memory_mb: u32, time_ms: u32) {
424 self.resource_usage_history.push((flops, memory_mb, time_ms));
425 }
426
427 pub fn get_average_execution_time(&self, layer_id: usize) -> Option<f32> {
428 self.layer_execution_times
429 .get(&layer_id)
430 .map(|times| times.iter().sum::<u32>() as f32 / times.len() as f32)
431 }
432
433 pub fn get_accuracy_trend(&self, layers_used: usize) -> Option<f32> {
434 self.accuracy_by_layers.get(&layers_used).and_then(|accuracies| {
435 if accuracies.is_empty() {
436 None
437 } else {
438 Some(accuracies.iter().sum::<f32>() / accuracies.len() as f32)
439 }
440 })
441 }
442}
443
444pub struct AdaptiveComputationManager {
445 config: AdaptiveComputationConfig,
446 strategy: Box<dyn AdaptiveComputationStrategy + Send + Sync>,
447 performance_tracker: Arc<RwLock<PerformanceTracker>>,
448 complexity_estimator: Box<dyn ComplexityEstimator + Send + Sync>,
449}
450
451impl AdaptiveComputationManager {
452 pub fn new(
453 config: AdaptiveComputationConfig,
454 strategy: Box<dyn AdaptiveComputationStrategy + Send + Sync>,
455 complexity_estimator: Box<dyn ComplexityEstimator + Send + Sync>,
456 ) -> Self {
457 Self {
458 config,
459 strategy,
460 performance_tracker: Arc::new(RwLock::new(PerformanceTracker::new())),
461 complexity_estimator,
462 }
463 }
464
465 pub fn plan_computation(
466 &self,
467 input: &Tensor,
468 budget: &ComputationBudget,
469 ) -> Result<ComputationPath, Box<dyn std::error::Error>> {
470 let input_complexity = self.complexity_estimator.estimate_complexity(input)?;
472
473 let path = self.strategy.adjust_computation_path(input_complexity, budget, &self.config);
475
476 Ok(path)
477 }
478
479 pub fn should_continue_layer(
480 &self,
481 layer_id: usize,
482 layer_output: &Tensor,
483 budget: &ComputationBudget,
484 ) -> Result<bool, Box<dyn std::error::Error>> {
485 let metrics = self.calculate_layer_metrics(layer_id, layer_output)?;
487
488 let should_continue =
490 self.strategy.should_continue(layer_id, &metrics, budget, &self.config);
491
492 {
494 let mut tracker = self
495 .performance_tracker
496 .write()
497 .expect("performance_tracker lock should not be poisoned");
498 tracker.record_layer_execution(layer_id, metrics.execution_time_ms);
499 }
500
501 Ok(should_continue)
502 }
503
504 fn calculate_layer_metrics(
505 &self,
506 layer_id: usize,
507 layer_output: &Tensor,
508 ) -> Result<LayerMetrics, Box<dyn std::error::Error>> {
509 let flops_estimate = self.estimate_flops(layer_output)?;
511 let memory_usage_mb = self.estimate_memory_usage(layer_output)?;
512
513 let confidence_score = self.calculate_confidence(layer_output)?;
515 let uncertainty_score = 1.0 - confidence_score;
516
517 let output_entropy = self.calculate_entropy(layer_output)?;
519
520 Ok(LayerMetrics {
521 layer_id,
522 flops_estimate,
523 memory_usage_mb,
524 execution_time_ms: 10, confidence_score,
526 uncertainty_score,
527 output_entropy,
528 })
529 }
530
531 fn estimate_flops(&self, tensor: &Tensor) -> Result<u64, Box<dyn std::error::Error>> {
532 let size: u64 = tensor.shape().iter().map(|&x| x as u64).product();
534 Ok(size * 2) }
536
537 fn estimate_memory_usage(&self, tensor: &Tensor) -> Result<u32, Box<dyn std::error::Error>> {
538 let size: u64 = tensor.shape().iter().map(|&x| x as u64).product();
539 Ok((size * 4 / (1024 * 1024)) as u32) }
541
542 fn calculate_confidence(&self, tensor: &Tensor) -> Result<f32, Box<dyn std::error::Error>> {
543 let max_value = tensor.max_value()?;
545 let mean_value = tensor.mean()?;
546
547 let max_scalar = max_value.get_float(0)?;
549 let mean_scalar = mean_value.get_float(0)?;
550
551 let confidence = (max_scalar / (mean_scalar + 1e-8)).min(1.0);
553 Ok(confidence)
554 }
555
556 fn calculate_entropy(&self, tensor: &Tensor) -> Result<f32, Box<dyn std::error::Error>> {
557 let softmax_output = tensor.softmax(-1)?;
559 let log_probs = softmax_output.log()?;
560 let entropy_tensor = softmax_output
561 .mul(&log_probs)?
562 .neg()?
563 .sum(Some(vec![tensor.shape().len() - 1]), false)?;
564
565 let mean_entropy = entropy_tensor.mean()?;
566 Ok(mean_entropy.get_float(0)?)
567 }
568}
569
570pub trait ComplexityEstimator {
571 fn estimate_complexity(&self, input: &Tensor) -> Result<f32, Box<dyn std::error::Error>>;
572}
573
574pub struct EntropyBasedComplexityEstimator;
575
576impl ComplexityEstimator for EntropyBasedComplexityEstimator {
577 fn estimate_complexity(&self, input: &Tensor) -> Result<f32, Box<dyn std::error::Error>> {
578 let input_normalized = input.softmax(-1)?;
580 let log_input = input_normalized.log()?;
581 let entropy_tensor = input_normalized.mul(&log_input)?.neg()?.mean()?;
582 let entropy = entropy_tensor.get_float(0)?;
583
584 let max_entropy = (*input.shape().last().unwrap_or(&1) as f32).ln();
586 Ok((entropy / max_entropy).clamp(0.0, 1.0))
587 }
588}
589
590#[derive(Debug, Clone, Serialize, Deserialize)]
594pub struct DynamicArchitectureConfig {
595 pub enable_dynamic_topology: bool,
596 pub max_concurrent_paths: usize,
597 pub path_selection_strategy: PathSelectionStrategy,
598 pub architecture_search_enabled: bool,
599 pub runtime_modification_enabled: bool,
600 pub voting_mechanism: VotingMechanism,
601 pub layer_insertion_threshold: f32,
602 pub layer_removal_threshold: f32,
603 pub branching_confidence_threshold: f32,
604}
605
606impl Default for DynamicArchitectureConfig {
607 fn default() -> Self {
608 Self {
609 enable_dynamic_topology: true,
610 max_concurrent_paths: 4,
611 path_selection_strategy: PathSelectionStrategy::ConfidenceBased,
612 architecture_search_enabled: false,
613 runtime_modification_enabled: true,
614 voting_mechanism: VotingMechanism::WeightedAverage,
615 layer_insertion_threshold: 0.3,
616 layer_removal_threshold: 0.8,
617 branching_confidence_threshold: 0.5,
618 }
619 }
620}
621
622#[derive(Debug, Clone, Serialize, Deserialize)]
623pub enum PathSelectionStrategy {
624 ConfidenceBased,
625 UncertaintyBased,
626 EnsembleVoting,
627 AdaptiveRouting,
628 CostEffectiveness,
629}
630
631#[derive(Debug, Clone, Serialize, Deserialize)]
632pub enum VotingMechanism {
633 MajorityVote,
634 WeightedAverage,
635 ConfidenceWeighted,
636 UncertaintyWeighted,
637 ExpertMixing,
638}
639
640#[derive(Debug)]
642pub struct DynamicArchitectureManager {
643 config: DynamicArchitectureConfig,
644 #[allow(dead_code)]
645 active_paths: Arc<RwLock<HashMap<String, ExecutionPath>>>,
646 #[allow(dead_code)]
647 architecture_cache: Arc<RwLock<HashMap<String, CachedArchitecture>>>,
648 performance_history: Arc<RwLock<Vec<ArchitecturePerformance>>>,
649 topology_modifier: TopologyModifier,
650 path_router: PathRouter,
651}
652
653impl DynamicArchitectureManager {
654 pub fn new(config: DynamicArchitectureConfig) -> Self {
655 Self {
656 config: config.clone(),
657 active_paths: Arc::new(RwLock::new(HashMap::new())),
658 architecture_cache: Arc::new(RwLock::new(HashMap::new())),
659 performance_history: Arc::new(RwLock::new(Vec::new())),
660 topology_modifier: TopologyModifier::new(config.clone()),
661 path_router: PathRouter::new(config.clone()),
662 }
663 }
664
665 pub fn create_dynamic_execution_plan(
667 &self,
668 input: &Tensor,
669 base_architecture: &ArchitectureBlueprint,
670 constraints: &ComputationBudget,
671 ) -> Result<DynamicExecutionPlan, Box<dyn std::error::Error>> {
672 let input_complexity = self.analyze_input_complexity(input)?;
673
674 let execution_paths =
676 self.generate_execution_paths(input_complexity, base_architecture, constraints)?;
677
678 let selected_paths = self.path_router.select_optimal_paths(
680 &execution_paths,
681 &self.config.path_selection_strategy,
682 self.config.max_concurrent_paths,
683 )?;
684
685 Ok(DynamicExecutionPlan {
686 paths: selected_paths,
687 voting_mechanism: self.config.voting_mechanism.clone(),
688 fallback_path: self.create_fallback_path(base_architecture)?,
689 modification_points: self.identify_modification_points(base_architecture)?,
690 })
691 }
692
693 pub fn modify_architecture_runtime(
695 &self,
696 current_state: &ExecutionState,
697 performance_metrics: &LayerMetrics,
698 architecture: &mut ArchitectureBlueprint,
699 ) -> Result<Vec<TopologyModification>, Box<dyn std::error::Error>> {
700 if !self.config.runtime_modification_enabled {
701 return Ok(vec![]);
702 }
703
704 let mut modifications = Vec::new();
705
706 if performance_metrics.uncertainty_score > self.config.layer_insertion_threshold {
708 let insertion_point = self
709 .topology_modifier
710 .find_optimal_insertion_point(current_state, architecture)?;
711
712 if let Some(point) = insertion_point {
713 let new_layer =
714 self.topology_modifier.create_adaptive_layer(point, performance_metrics)?;
715
716 modifications.push(TopologyModification::InsertLayer {
717 position: point,
718 layer_config: new_layer,
719 });
720 }
721 }
722
723 if performance_metrics.confidence_score > self.config.layer_removal_threshold {
725 let removal_candidates =
726 self.topology_modifier.identify_redundant_layers(current_state, architecture)?;
727
728 for candidate in removal_candidates {
729 modifications.push(TopologyModification::RemoveLayer {
730 position: candidate,
731 });
732 }
733 }
734
735 if self.should_create_branch(performance_metrics) {
737 let branch_config = self
738 .topology_modifier
739 .create_branch_configuration(current_state, performance_metrics)?;
740
741 modifications.push(TopologyModification::CreateBranch {
742 source_position: current_state.current_layer,
743 branch_config,
744 });
745 }
746
747 for modification in &modifications {
749 self.topology_modifier.apply_modification(architecture, modification)?;
750 }
751
752 Ok(modifications)
753 }
754
755 pub fn execute_multi_path(
757 &self,
758 input: &Tensor,
759 execution_plan: &DynamicExecutionPlan,
760 ) -> Result<MultiPathResult, Box<dyn std::error::Error>> {
761 let start_time = Instant::now();
762 let mut path_results = Vec::new();
763 let mut path_metrics = Vec::new();
764
765 for (path_id, path) in execution_plan.paths.iter().enumerate() {
767 let path_start = Instant::now();
768 let result = self.execute_single_path(input, path)?;
769 let execution_time = path_start.elapsed();
770
771 let metrics = PathExecutionMetrics {
772 path_id,
773 execution_time,
774 confidence: result.confidence,
775 accuracy_estimate: result.accuracy_estimate,
776 resource_usage: result.resource_usage.clone(),
777 };
778
779 path_results.push(result);
780 path_metrics.push(metrics);
781 }
782
783 let final_result = self.combine_path_results(
785 &path_results,
786 &path_metrics,
787 &execution_plan.voting_mechanism,
788 )?;
789
790 self.record_multi_path_performance(&path_metrics, &final_result);
792
793 Ok(MultiPathResult {
794 result: final_result,
795 path_metrics,
796 total_execution_time: start_time.elapsed(),
797 paths_executed: path_results.len(),
798 })
799 }
800
801 fn analyze_input_complexity(&self, input: &Tensor) -> Result<f32, Box<dyn std::error::Error>> {
802 let entropy = self.compute_entropy(input)?;
804 let variance = self.compute_variance(input)?;
805 let sparsity = self.compute_sparsity(input)?;
806
807 let complexity = (entropy * 0.4 + variance * 0.3 + (1.0 - sparsity) * 0.3).clamp(0.0, 1.0);
809 Ok(complexity)
810 }
811
812 fn generate_execution_paths(
813 &self,
814 complexity: f32,
815 architecture: &ArchitectureBlueprint,
816 constraints: &ComputationBudget,
817 ) -> Result<Vec<ExecutionPath>, Box<dyn std::error::Error>> {
818 let mut paths = Vec::new();
819
820 let conservative_path = ExecutionPath {
822 path_id: "conservative".to_string(),
823 layers: self.select_essential_layers(architecture)?,
824 skip_patterns: HashMap::new(),
825 resource_allocation: self.allocate_resources_conservatively(constraints)?,
826 expected_accuracy: 0.9,
827 expected_latency: Duration::from_millis(50),
828 };
829 paths.push(conservative_path);
830
831 let aggressive_path = ExecutionPath {
833 path_id: "aggressive".to_string(),
834 layers: architecture.layers.clone(),
835 skip_patterns: HashMap::new(),
836 resource_allocation: self.allocate_resources_aggressively(constraints)?,
837 expected_accuracy: 0.95,
838 expected_latency: Duration::from_millis(200),
839 };
840 paths.push(aggressive_path);
841
842 let adaptive_layers = self.select_adaptive_layers(architecture, complexity)?;
844 let adaptive_path = ExecutionPath {
845 path_id: "adaptive".to_string(),
846 layers: adaptive_layers,
847 skip_patterns: self.generate_skip_patterns(complexity)?,
848 resource_allocation: self.allocate_resources_adaptively(constraints, complexity)?,
849 expected_accuracy: 0.85 + complexity * 0.1,
850 expected_latency: Duration::from_millis((100.0 + complexity * 100.0) as u64),
851 };
852 paths.push(adaptive_path);
853
854 let efficient_path = ExecutionPath {
856 path_id: "efficient".to_string(),
857 layers: self.select_efficient_layers(architecture)?,
858 skip_patterns: self.generate_efficiency_skip_patterns()?,
859 resource_allocation: self.allocate_resources_efficiently(constraints)?,
860 expected_accuracy: 0.8,
861 expected_latency: Duration::from_millis(30),
862 };
863 paths.push(efficient_path);
864
865 Ok(paths)
866 }
867
868 fn should_create_branch(&self, metrics: &LayerMetrics) -> bool {
869 metrics.uncertainty_score > self.config.branching_confidence_threshold
870 && metrics.confidence_score < 0.8 }
872
873 fn execute_single_path(
874 &self,
875 input: &Tensor,
876 path: &ExecutionPath,
877 ) -> Result<PathResult, Box<dyn std::error::Error>> {
878 Ok(PathResult {
881 output: input.clone(), confidence: 0.85,
883 accuracy_estimate: path.expected_accuracy,
884 resource_usage: ResourceUsage {
885 memory_mb: 100,
886 flops: 1000000,
887 time_ms: path.expected_latency.as_millis() as u32,
888 },
889 })
890 }
891
892 fn combine_path_results(
893 &self,
894 results: &[PathResult],
895 metrics: &[PathExecutionMetrics],
896 voting_mechanism: &VotingMechanism,
897 ) -> Result<CombinedResult, Box<dyn std::error::Error>> {
898 match voting_mechanism {
899 VotingMechanism::WeightedAverage => {
900 let total_confidence: f32 = metrics.iter().map(|m| m.confidence).sum();
902 let mut weighted_output = Tensor::zeros_like(&results[0].output)?;
903
904 for (result, metric) in results.iter().zip(metrics.iter()) {
905 let weight = metric.confidence / total_confidence;
906 let scaled_output = result.output.mul_scalar(weight)?;
907 weighted_output = weighted_output.add(&scaled_output)?;
908 }
909
910 Ok(CombinedResult {
911 output: weighted_output,
912 confidence: total_confidence / results.len() as f32,
913 consensus_score: self.calculate_consensus_score(metrics),
914 })
915 },
916 VotingMechanism::MajorityVote => {
917 let best_idx = metrics
919 .iter()
920 .enumerate()
921 .max_by(|(_, a), (_, b)| {
922 a.confidence.partial_cmp(&b.confidence).expect("Partial comparison failed")
923 })
924 .map(|(idx, _)| idx)
925 .unwrap_or(0);
926
927 Ok(CombinedResult {
928 output: results[best_idx].output.clone(),
929 confidence: metrics[best_idx].confidence,
930 consensus_score: self.calculate_consensus_score(metrics),
931 })
932 },
933 _ => {
934 self.combine_path_results(results, metrics, &VotingMechanism::WeightedAverage)
936 },
937 }
938 }
939
940 fn calculate_consensus_score(&self, metrics: &[PathExecutionMetrics]) -> f32 {
941 if metrics.len() < 2 {
942 return 1.0;
943 }
944
945 let mean_confidence: f32 =
946 metrics.iter().map(|m| m.confidence).sum::<f32>() / metrics.len() as f32;
947 let variance =
948 metrics.iter().map(|m| (m.confidence - mean_confidence).powi(2)).sum::<f32>()
949 / metrics.len() as f32;
950
951 (1.0 - variance.sqrt()).clamp(0.0, 1.0)
953 }
954
955 fn record_multi_path_performance(
956 &self,
957 path_metrics: &[PathExecutionMetrics],
958 result: &CombinedResult,
959 ) {
960 let performance = ArchitecturePerformance {
961 timestamp: Instant::now(),
962 path_count: path_metrics.len(),
963 average_confidence: path_metrics.iter().map(|m| m.confidence).sum::<f32>()
964 / path_metrics.len() as f32,
965 consensus_score: result.consensus_score,
966 total_resource_usage: path_metrics.iter().map(|m| m.resource_usage.memory_mb).sum(),
967 };
968
969 if let Ok(mut history) = self.performance_history.write() {
970 history.push(performance);
971 if history.len() > 1000 {
973 let drain_count = history.len() - 1000;
974 history.drain(0..drain_count);
975 }
976 }
977 }
978
979 fn select_essential_layers(
981 &self,
982 arch: &ArchitectureBlueprint,
983 ) -> Result<Vec<LayerConfig>, Box<dyn std::error::Error>> {
984 Ok(arch.layers.iter().take(arch.layers.len() / 2).cloned().collect())
985 }
986
987 fn select_adaptive_layers(
988 &self,
989 arch: &ArchitectureBlueprint,
990 complexity: f32,
991 ) -> Result<Vec<LayerConfig>, Box<dyn std::error::Error>> {
992 let layer_count =
993 ((arch.layers.len() as f32 * (0.5 + complexity * 0.5)) as usize).min(arch.layers.len());
994 Ok(arch.layers.iter().take(layer_count).cloned().collect())
995 }
996
997 fn select_efficient_layers(
998 &self,
999 arch: &ArchitectureBlueprint,
1000 ) -> Result<Vec<LayerConfig>, Box<dyn std::error::Error>> {
1001 Ok(arch.layers.iter().step_by(2).cloned().collect())
1002 }
1003
1004 fn generate_skip_patterns(
1005 &self,
1006 complexity: f32,
1007 ) -> Result<HashMap<usize, LayerSkipPattern>, Box<dyn std::error::Error>> {
1008 let mut patterns = HashMap::new();
1009 if complexity < 0.3 {
1010 for i in (1..10).step_by(2) {
1012 patterns.insert(i, LayerSkipPattern::Skip);
1013 }
1014 }
1015 Ok(patterns)
1016 }
1017
1018 fn generate_efficiency_skip_patterns(
1019 &self,
1020 ) -> Result<HashMap<usize, LayerSkipPattern>, Box<dyn std::error::Error>> {
1021 let mut patterns = HashMap::new();
1022 for i in 2..10 {
1024 if i % 3 == 0 {
1025 patterns.insert(i, LayerSkipPattern::Approximate);
1026 }
1027 }
1028 Ok(patterns)
1029 }
1030
1031 fn allocate_resources_conservatively(
1032 &self,
1033 budget: &ComputationBudget,
1034 ) -> Result<ResourceAllocation, Box<dyn std::error::Error>> {
1035 Ok(ResourceAllocation {
1036 memory_per_layer: (0..5).map(|i| (i, budget.max_memory_mb / 10)).collect(),
1037 compute_intensity: (0..5).map(|i| (i, 0.5)).collect(),
1038 parallelism_factor: (0..5).map(|i| (i, 1)).collect(),
1039 })
1040 }
1041
1042 fn allocate_resources_aggressively(
1043 &self,
1044 budget: &ComputationBudget,
1045 ) -> Result<ResourceAllocation, Box<dyn std::error::Error>> {
1046 Ok(ResourceAllocation {
1047 memory_per_layer: (0..10).map(|i| (i, budget.max_memory_mb / 5)).collect(),
1048 compute_intensity: (0..10).map(|i| (i, 1.0)).collect(),
1049 parallelism_factor: (0..10).map(|i| (i, 2)).collect(),
1050 })
1051 }
1052
1053 fn allocate_resources_adaptively(
1054 &self,
1055 budget: &ComputationBudget,
1056 complexity: f32,
1057 ) -> Result<ResourceAllocation, Box<dyn std::error::Error>> {
1058 let layer_count = (8.0 * (0.5 + complexity * 0.5)) as usize;
1059 Ok(ResourceAllocation {
1060 memory_per_layer: (0..layer_count)
1061 .map(|i| {
1062 (
1063 i,
1064 (budget.max_memory_mb as f32 * (0.5 + complexity * 0.5)) as u32
1065 / layer_count as u32,
1066 )
1067 })
1068 .collect(),
1069 compute_intensity: (0..layer_count).map(|i| (i, 0.5 + complexity * 0.5)).collect(),
1070 parallelism_factor: (0..layer_count)
1071 .map(|i| (i, 1 + (complexity * 2.0) as u32))
1072 .collect(),
1073 })
1074 }
1075
1076 fn allocate_resources_efficiently(
1077 &self,
1078 budget: &ComputationBudget,
1079 ) -> Result<ResourceAllocation, Box<dyn std::error::Error>> {
1080 Ok(ResourceAllocation {
1081 memory_per_layer: (0..3).map(|i| (i, budget.max_memory_mb / 20)).collect(),
1082 compute_intensity: (0..3).map(|i| (i, 0.3)).collect(),
1083 parallelism_factor: (0..3).map(|i| (i, 4)).collect(),
1084 })
1085 }
1086
1087 fn create_fallback_path(
1088 &self,
1089 arch: &ArchitectureBlueprint,
1090 ) -> Result<ExecutionPath, Box<dyn std::error::Error>> {
1091 Ok(ExecutionPath {
1092 path_id: "fallback".to_string(),
1093 layers: vec![arch.layers[0].clone()], skip_patterns: HashMap::new(),
1095 resource_allocation: ResourceAllocation {
1096 memory_per_layer: HashMap::from([(0, 50)]),
1097 compute_intensity: HashMap::from([(0, 0.1)]),
1098 parallelism_factor: HashMap::from([(0, 1)]),
1099 },
1100 expected_accuracy: 0.6,
1101 expected_latency: Duration::from_millis(10),
1102 })
1103 }
1104
1105 fn identify_modification_points(
1106 &self,
1107 arch: &ArchitectureBlueprint,
1108 ) -> Result<Vec<ModificationPoint>, Box<dyn std::error::Error>> {
1109 let mut points = Vec::new();
1110
1111 for i in 0..arch.layers.len() - 1 {
1113 points.push(ModificationPoint {
1114 position: i,
1115 modification_type: ModificationType::LayerInsertion,
1116 confidence_threshold: 0.3,
1117 });
1118 }
1119
1120 for &fraction in &[0.25, 0.5, 0.75] {
1122 let position = (arch.layers.len() as f32 * fraction) as usize;
1123 points.push(ModificationPoint {
1124 position,
1125 modification_type: ModificationType::BranchingPoint,
1126 confidence_threshold: 0.5,
1127 });
1128 }
1129
1130 Ok(points)
1131 }
1132
1133 fn compute_entropy(&self, tensor: &Tensor) -> Result<f32, Box<dyn std::error::Error>> {
1135 Ok(0.5) }
1138
1139 fn compute_variance(&self, tensor: &Tensor) -> Result<f32, Box<dyn std::error::Error>> {
1140 Ok(0.3) }
1143
1144 fn compute_sparsity(&self, tensor: &Tensor) -> Result<f32, Box<dyn std::error::Error>> {
1145 Ok(0.2) }
1148}
1149
1150#[derive(Debug, Clone)]
1153pub struct ArchitectureBlueprint {
1154 pub layers: Vec<LayerConfig>,
1155 pub connections: Vec<ConnectionConfig>,
1156 pub metadata: ArchitectureMetadata,
1157}
1158
1159#[derive(Debug, Clone)]
1160pub struct LayerConfig {
1161 pub layer_id: usize,
1162 pub layer_type: LayerType,
1163 pub parameters: HashMap<String, f32>,
1164 pub optional: bool,
1165}
1166
1167#[derive(Debug, Clone)]
1168pub enum LayerType {
1169 Attention,
1170 FeedForward,
1171 Normalization,
1172 Embedding,
1173 Output,
1174 Custom(String),
1175}
1176
1177#[derive(Debug, Clone)]
1178pub struct ConnectionConfig {
1179 pub from_layer: usize,
1180 pub to_layer: usize,
1181 pub connection_type: ConnectionType,
1182}
1183
1184#[derive(Debug, Clone)]
1185pub enum ConnectionType {
1186 Sequential,
1187 Residual,
1188 Attention,
1189 Custom(String),
1190}
1191
1192#[derive(Debug, Clone)]
1193pub struct ArchitectureMetadata {
1194 pub name: String,
1195 pub version: String,
1196 pub parameter_count: u64,
1197 pub memory_footprint_mb: u32,
1198}
1199
1200#[derive(Debug, Clone)]
1201pub struct ExecutionPath {
1202 pub path_id: String,
1203 pub layers: Vec<LayerConfig>,
1204 pub skip_patterns: HashMap<usize, LayerSkipPattern>,
1205 pub resource_allocation: ResourceAllocation,
1206 pub expected_accuracy: f32,
1207 pub expected_latency: Duration,
1208}
1209
1210#[derive(Debug)]
1211pub struct DynamicExecutionPlan {
1212 pub paths: Vec<ExecutionPath>,
1213 pub voting_mechanism: VotingMechanism,
1214 pub fallback_path: ExecutionPath,
1215 pub modification_points: Vec<ModificationPoint>,
1216}
1217
1218#[derive(Debug)]
1219pub struct ExecutionState {
1220 pub current_layer: usize,
1221 pub intermediate_results: HashMap<usize, Tensor>,
1222 pub execution_metrics: Vec<LayerMetrics>,
1223 pub resource_usage: ResourceUsage,
1224}
1225
1226#[derive(Debug, Clone)]
1227pub struct ResourceUsage {
1228 pub memory_mb: u32,
1229 pub flops: u64,
1230 pub time_ms: u32,
1231}
1232
1233#[derive(Debug)]
1234pub enum TopologyModification {
1235 InsertLayer {
1236 position: usize,
1237 layer_config: LayerConfig,
1238 },
1239 RemoveLayer {
1240 position: usize,
1241 },
1242 CreateBranch {
1243 source_position: usize,
1244 branch_config: BranchConfig,
1245 },
1246 ModifyConnection {
1247 connection: ConnectionConfig,
1248 },
1249}
1250
1251#[derive(Debug, Clone)]
1252pub struct BranchConfig {
1253 pub branch_layers: Vec<LayerConfig>,
1254 pub merge_strategy: MergeStrategy,
1255 pub condition: BranchCondition,
1256}
1257
1258#[derive(Debug, Clone)]
1259pub enum MergeStrategy {
1260 Concatenation,
1261 Average,
1262 WeightedSum,
1263 Attention,
1264}
1265
1266#[derive(Debug, Clone)]
1267pub enum BranchCondition {
1268 Always,
1269 ConfidenceThreshold(f32),
1270 UncertaintyThreshold(f32),
1271 Custom(String),
1272}
1273
1274#[derive(Debug)]
1275pub struct ModificationPoint {
1276 pub position: usize,
1277 pub modification_type: ModificationType,
1278 pub confidence_threshold: f32,
1279}
1280
1281#[derive(Debug)]
1282pub enum ModificationType {
1283 LayerInsertion,
1284 LayerRemoval,
1285 BranchingPoint,
1286 ConnectionModification,
1287}
1288
1289#[derive(Debug)]
1290pub struct TopologyModifier {
1291 #[allow(dead_code)]
1292 config: DynamicArchitectureConfig,
1293}
1294
1295impl TopologyModifier {
1296 pub fn new(config: DynamicArchitectureConfig) -> Self {
1297 Self { config }
1298 }
1299
1300 pub fn find_optimal_insertion_point(
1301 &self,
1302 state: &ExecutionState,
1303 architecture: &ArchitectureBlueprint,
1304 ) -> Result<Option<usize>, Box<dyn std::error::Error>> {
1305 if state.current_layer > 0 && state.current_layer < architecture.layers.len() {
1307 Ok(Some(state.current_layer))
1308 } else {
1309 Ok(None)
1310 }
1311 }
1312
1313 pub fn create_adaptive_layer(
1314 &self,
1315 position: usize,
1316 metrics: &LayerMetrics,
1317 ) -> Result<LayerConfig, Box<dyn std::error::Error>> {
1318 let layer_type = if metrics.uncertainty_score > 0.7 {
1320 LayerType::Attention } else {
1322 LayerType::FeedForward };
1324
1325 Ok(LayerConfig {
1326 layer_id: position * 1000, layer_type,
1328 parameters: HashMap::from([
1329 ("hidden_size".to_string(), 512.0),
1330 ("dropout".to_string(), 0.1),
1331 ]),
1332 optional: true,
1333 })
1334 }
1335
1336 pub fn identify_redundant_layers(
1337 &self,
1338 state: &ExecutionState,
1339 architecture: &ArchitectureBlueprint,
1340 ) -> Result<Vec<usize>, Box<dyn std::error::Error>> {
1341 let mut redundant = Vec::new();
1342
1343 for (i, layer) in architecture.layers.iter().enumerate() {
1345 if layer.optional
1346 && state.execution_metrics.get(i).is_some_and(|m| m.confidence_score > 0.9)
1347 {
1348 redundant.push(i);
1349 }
1350 }
1351
1352 Ok(redundant)
1353 }
1354
1355 pub fn create_branch_configuration(
1356 &self,
1357 state: &ExecutionState,
1358 metrics: &LayerMetrics,
1359 ) -> Result<BranchConfig, Box<dyn std::error::Error>> {
1360 let branch_layers = vec![LayerConfig {
1361 layer_id: 9000, layer_type: LayerType::Attention,
1363 parameters: HashMap::from([("heads".to_string(), 8.0)]),
1364 optional: true,
1365 }];
1366
1367 Ok(BranchConfig {
1368 branch_layers,
1369 merge_strategy: MergeStrategy::WeightedSum,
1370 condition: BranchCondition::UncertaintyThreshold(metrics.uncertainty_score),
1371 })
1372 }
1373
1374 pub fn apply_modification(
1375 &self,
1376 architecture: &mut ArchitectureBlueprint,
1377 modification: &TopologyModification,
1378 ) -> Result<(), Box<dyn std::error::Error>> {
1379 match modification {
1380 TopologyModification::InsertLayer {
1381 position,
1382 layer_config,
1383 } => {
1384 if *position <= architecture.layers.len() {
1385 architecture.layers.insert(*position, layer_config.clone());
1386 }
1387 },
1388 TopologyModification::RemoveLayer { position } => {
1389 if *position < architecture.layers.len() {
1390 architecture.layers.remove(*position);
1391 }
1392 },
1393 TopologyModification::CreateBranch {
1394 source_position,
1395 branch_config,
1396 } => {
1397 for (i, layer) in branch_config.branch_layers.iter().enumerate() {
1399 architecture.layers.insert(source_position + i + 1, layer.clone());
1400 }
1401 },
1402 TopologyModification::ModifyConnection { connection } => {
1403 architecture.connections.push(connection.clone());
1405 },
1406 }
1407 Ok(())
1408 }
1409}
1410
1411#[derive(Debug)]
1412pub struct PathRouter {
1413 #[allow(dead_code)]
1414 config: DynamicArchitectureConfig,
1415}
1416
1417impl PathRouter {
1418 pub fn new(config: DynamicArchitectureConfig) -> Self {
1419 Self { config }
1420 }
1421
1422 pub fn select_optimal_paths(
1423 &self,
1424 paths: &[ExecutionPath],
1425 strategy: &PathSelectionStrategy,
1426 max_paths: usize,
1427 ) -> Result<Vec<ExecutionPath>, Box<dyn std::error::Error>> {
1428 let mut selected = match strategy {
1429 PathSelectionStrategy::ConfidenceBased => {
1430 let mut sorted_paths = paths.to_vec();
1431 sorted_paths.sort_by(|a, b| {
1432 b.expected_accuracy
1433 .partial_cmp(&a.expected_accuracy)
1434 .expect("Partial comparison failed")
1435 });
1436 sorted_paths
1437 },
1438 PathSelectionStrategy::CostEffectiveness => {
1439 let mut sorted_paths = paths.to_vec();
1440 sorted_paths.sort_by(|a, b| {
1441 let cost_a = a.expected_latency.as_millis() as f32 / a.expected_accuracy;
1442 let cost_b = b.expected_latency.as_millis() as f32 / b.expected_accuracy;
1443 cost_a.partial_cmp(&cost_b).expect("Partial comparison failed")
1444 });
1445 sorted_paths
1446 },
1447 _ => paths.to_vec(),
1448 };
1449
1450 selected.truncate(max_paths);
1451 Ok(selected)
1452 }
1453}
1454
1455#[derive(Debug)]
1456pub struct PathResult {
1457 pub output: Tensor,
1458 pub confidence: f32,
1459 pub accuracy_estimate: f32,
1460 pub resource_usage: ResourceUsage,
1461}
1462
1463#[derive(Debug)]
1464pub struct PathExecutionMetrics {
1465 pub path_id: usize,
1466 pub execution_time: Duration,
1467 pub confidence: f32,
1468 pub accuracy_estimate: f32,
1469 pub resource_usage: ResourceUsage,
1470}
1471
1472#[derive(Debug)]
1473pub struct CombinedResult {
1474 pub output: Tensor,
1475 pub confidence: f32,
1476 pub consensus_score: f32,
1477}
1478
1479#[derive(Debug)]
1480pub struct MultiPathResult {
1481 pub result: CombinedResult,
1482 pub path_metrics: Vec<PathExecutionMetrics>,
1483 pub total_execution_time: Duration,
1484 pub paths_executed: usize,
1485}
1486
1487#[derive(Debug)]
1488pub struct ArchitecturePerformance {
1489 pub timestamp: Instant,
1490 pub path_count: usize,
1491 pub average_confidence: f32,
1492 pub consensus_score: f32,
1493 pub total_resource_usage: u32,
1494}
1495
1496#[derive(Debug)]
1497pub struct CachedArchitecture {
1498 pub blueprint: ArchitectureBlueprint,
1499 pub performance_history: Vec<ArchitecturePerformance>,
1500 pub last_used: Instant,
1501}
1502
1503#[cfg(test)]
1504mod tests {
1505 use super::*;
1506
1507 #[test]
1508 fn test_computation_budget() {
1509 let mut budget = ComputationBudget::new(1000, 100, 50);
1510
1511 assert!(budget.can_afford(500, 50, 25));
1512 budget.consume(500, 50, 25);
1513
1514 assert_eq!(budget.remaining_flops, 500);
1515 assert_eq!(budget.remaining_memory_mb, 50);
1516 assert_eq!(budget.remaining_time_ms, 25);
1517
1518 assert!(!budget.can_afford(600, 60, 30));
1519 }
1520
1521 #[test]
1522 fn test_confidence_based_strategy() {
1523 let strategy = ConfidenceBasedStrategy::new();
1524 let config = AdaptiveComputationConfig::default();
1525 let budget = ComputationBudget::new(10000, 1000, 100);
1526
1527 let metrics = LayerMetrics {
1528 layer_id: 0,
1529 flops_estimate: 100,
1530 memory_usage_mb: 10,
1531 execution_time_ms: 5,
1532 confidence_score: 0.5,
1533 uncertainty_score: 0.5,
1534 output_entropy: 1.0,
1535 };
1536
1537 assert!(strategy.should_continue(0, &metrics, &budget, &config));
1539
1540 let high_confidence_metrics = LayerMetrics {
1541 confidence_score: 0.98,
1542 ..metrics
1543 };
1544
1545 assert!(!strategy.should_continue(5, &high_confidence_metrics, &budget, &config));
1547 }
1548
1549 #[test]
1550 fn test_performance_tracker() {
1551 let mut tracker = PerformanceTracker::new();
1552
1553 tracker.record_layer_execution(0, 10);
1554 tracker.record_layer_execution(0, 20);
1555 tracker.record_accuracy(5, 0.85);
1556 tracker.record_accuracy(5, 0.90);
1557
1558 assert_eq!(tracker.get_average_execution_time(0), Some(15.0));
1559 assert_eq!(tracker.get_accuracy_trend(5), Some(0.875));
1560 }
1561
1562 #[test]
1563 fn test_entropy_complexity_estimator() {
1564 let estimator = EntropyBasedComplexityEstimator;
1565
1566 let low_entropy_input = Tensor::from_vec(vec![10.0, 0.0, 0.0, 0.0, 0.0], &[1, 5])
1568 .expect("Tensor from_vec failed");
1569
1570 let high_entropy_input = Tensor::ones(&[1, 5]).expect("Failed to create ones tensor");
1572
1573 let low_complexity = estimator
1574 .estimate_complexity(&low_entropy_input)
1575 .expect("operation failed in test");
1576 let high_complexity = estimator
1577 .estimate_complexity(&high_entropy_input)
1578 .expect("operation failed in test");
1579
1580 assert!(high_complexity > low_complexity);
1582
1583 assert!((0.0..=1.0).contains(&low_complexity));
1585 assert!((0.0..=1.0).contains(&high_complexity));
1586 }
1587}