1use crate::error::SparseResult;
7use crate::neural_adaptive_sparse::{NeuralAdaptiveConfig, NeuralAdaptiveSparseProcessor};
8use crate::quantum_inspired_sparse::{QuantumSparseConfig, QuantumSparseProcessor};
9use scirs2_core::numeric::{Float, NumAssign, NumCast, SparseElement};
10use scirs2_core::random::Rng;
11use scirs2_core::simd_ops::SimdUnifiedOps;
12use std::collections::HashMap;
13use std::sync::atomic::{AtomicUsize, Ordering};
14
15#[derive(Debug, Clone)]
17pub struct QuantumNeuralConfig {
18 pub quantum_config: QuantumSparseConfig,
20 pub neural_config: NeuralAdaptiveConfig,
22 pub hybrid_strategy: HybridStrategy,
24 pub coupling_strength: f64,
26 pub quantum_feedback: bool,
28 pub neural_guidance: bool,
30 pub coherence_threshold: f64,
32 pub hybrid_learning_rate: f64,
34}
35
36#[derive(Debug, Clone, Copy)]
38pub enum HybridStrategy {
39 Sequential,
41 Parallel,
43 Adaptive,
45 Entangled,
47 QuantumNeural,
49}
50
51impl Default for QuantumNeuralConfig {
52 fn default() -> Self {
53 Self {
54 quantum_config: QuantumSparseConfig::default(),
55 neural_config: NeuralAdaptiveConfig::default(),
56 hybrid_strategy: HybridStrategy::Adaptive,
57 coupling_strength: 0.5,
58 quantum_feedback: true,
59 neural_guidance: true,
60 coherence_threshold: 0.7,
61 hybrid_learning_rate: 0.001,
62 }
63 }
64}
65
66pub struct QuantumNeuralHybridProcessor {
68 _config: QuantumNeuralConfig,
69 quantum_processor: QuantumSparseProcessor,
70 neural_processor: NeuralAdaptiveSparseProcessor,
71 hybrid_state: HybridState,
72 performance_fusion: PerformanceFusion,
73 adaptation_counter: AtomicUsize,
74 hybrid_memory: HybridMemory,
75}
76
77#[derive(Debug)]
79struct HybridState {
80 quantum_coherence: f64,
81 neural_confidence: f64,
82 hybrid_synchronization: f64,
83 entanglement_strength: f64,
84 quantum_neural_coupling: Vec<f64>,
85 decision_history: Vec<HybridDecision>,
86}
87
88#[derive(Debug, Clone)]
90#[allow(dead_code)]
91struct HybridDecision {
92 timestamp: u64,
93 strategy_used: HybridProcessingMode,
94 quantum_contribution: f64,
95 neural_contribution: f64,
96 performance_achieved: f64,
97 coherence_at_decision: f64,
98}
99
100#[derive(Debug, Clone, Copy)]
102enum HybridProcessingMode {
103 PureQuantum,
104 PureNeural,
105 QuantumDominant,
106 NeuralDominant,
107 BalancedHybrid,
108 AdaptiveBlend,
109}
110
111#[derive(Debug)]
113#[allow(dead_code)]
114struct PerformanceFusion {
115 quantum_metrics: Vec<f64>,
116 neural_metrics: Vec<f64>,
117 fusion_weights: Vec<f64>,
118 adaptive_blending: bool,
119 fusion_history: Vec<FusionResult>,
120}
121
122#[derive(Debug, Clone)]
124#[allow(dead_code)]
125struct FusionResult {
126 fused_performance: f64,
127 quantum_weight: f64,
128 neural_weight: f64,
129 fusion_confidence: f64,
130}
131
132#[derive(Debug)]
134#[allow(dead_code)]
135struct HybridMemory {
136 quantum_states: HashMap<String, Vec<f64>>,
137 neural_patterns: HashMap<String, Vec<f64>>,
138 correlation_matrix: Vec<Vec<f64>>,
139 memory_capacity: usize,
140 forgetting_rate: f64,
141}
142
143impl QuantumNeuralHybridProcessor {
144 pub fn new(config: QuantumNeuralConfig) -> Self {
146 let quantum_processor = QuantumSparseProcessor::new(config.quantum_config.clone());
147 let neural_processor = NeuralAdaptiveSparseProcessor::new(config.neural_config.clone());
148
149 let hybrid_state = HybridState {
150 quantum_coherence: 1.0,
151 neural_confidence: 1.0,
152 hybrid_synchronization: 1.0,
153 entanglement_strength: 0.0,
154 quantum_neural_coupling: vec![0.0; 64],
155 decision_history: Vec::new(),
156 };
157
158 let performance_fusion = PerformanceFusion {
159 quantum_metrics: Vec::new(),
160 neural_metrics: Vec::new(),
161 fusion_weights: vec![0.5, 0.5], adaptive_blending: true,
163 fusion_history: Vec::new(),
164 };
165
166 let hybrid_memory = HybridMemory {
167 quantum_states: HashMap::new(),
168 neural_patterns: HashMap::new(),
169 correlation_matrix: vec![vec![0.0; 64]; 64],
170 memory_capacity: 1000,
171 forgetting_rate: 0.001,
172 };
173
174 Self {
175 _config: config,
176 quantum_processor,
177 neural_processor,
178 hybrid_state,
179 performance_fusion,
180 adaptation_counter: AtomicUsize::new(0),
181 hybrid_memory,
182 }
183 }
184
185 #[allow(clippy::too_many_arguments)]
187 pub fn hybrid_spmv<T>(
188 &mut self,
189 rows: usize,
190 cols: usize,
191 indptr: &[usize],
192 indices: &[usize],
193 data: &[T],
194 x: &[T],
195 y: &mut [T],
196 ) -> SparseResult<()>
197 where
198 T: Float
199 + SparseElement
200 + NumAssign
201 + Send
202 + Sync
203 + Copy
204 + SimdUnifiedOps
205 + Into<f64>
206 + From<f64>
207 + std::fmt::Debug
208 + 'static,
209 {
210 let start_time = std::time::Instant::now();
211
212 self.update_hybrid_state(indptr, indices);
214
215 let processing_mode = self.select_processing_mode(rows, cols, indptr, indices);
217
218 let result = match processing_mode {
220 HybridProcessingMode::PureQuantum => self
221 .quantum_processor
222 .quantum_spmv(rows, indptr, indices, data, x, y),
223 HybridProcessingMode::PureNeural => {
224 self.neural_processor
225 .adaptive_spmv(&[rows], &[cols], indptr, indices, data, x, y)
226 }
227 HybridProcessingMode::QuantumDominant => {
228 self.quantum_dominant_hybrid(rows, cols, indptr, indices, data, x, y)
229 }
230 HybridProcessingMode::NeuralDominant => {
231 self.neural_dominant_hybrid(rows, cols, indptr, indices, data, x, y)
232 }
233 HybridProcessingMode::BalancedHybrid => {
234 self.balanced_hybrid(rows, cols, indptr, indices, data, x, y)
235 }
236 HybridProcessingMode::AdaptiveBlend => {
237 self.adaptive_blend(rows, cols, indptr, indices, data, x, y)
238 }
239 };
240
241 let execution_time = start_time.elapsed().as_secs_f64();
243 self.update_performance_fusion(processing_mode, execution_time);
244
245 self.update_hybrid_learning(processing_mode, execution_time);
247
248 self.adaptation_counter.fetch_add(1, Ordering::Relaxed);
249
250 result
251 }
252
253 fn update_hybrid_state(&mut self, indptr: &[usize], indices: &[usize]) {
255 let sparsity_regularity = self.calculate_sparsity_regularity(indptr, indices);
257 self.hybrid_state.quantum_coherence = sparsity_regularity;
258
259 let pattern_familiarity = self.calculate_pattern_familiarity(indptr, indices);
261 self.hybrid_state.neural_confidence = pattern_familiarity;
262
263 self.hybrid_state.hybrid_synchronization =
265 (self.hybrid_state.quantum_coherence + self.hybrid_state.neural_confidence) / 2.0;
266
267 self.update_quantum_neural_coupling();
269
270 self.apply_memory_decay();
272 }
273
274 fn select_processing_mode(
276 &self,
277 rows: usize,
278 cols: usize,
279 indptr: &[usize],
280 indices: &[usize],
281 ) -> HybridProcessingMode {
282 match self._config.hybrid_strategy {
283 HybridStrategy::Sequential => {
284 if self.hybrid_state.quantum_coherence > self._config.coherence_threshold {
285 HybridProcessingMode::PureQuantum
286 } else {
287 HybridProcessingMode::PureNeural
288 }
289 }
290 HybridStrategy::Parallel => HybridProcessingMode::BalancedHybrid,
291 HybridStrategy::Adaptive => self.adaptive_mode_selection(rows, cols, indptr, indices),
292 HybridStrategy::Entangled => HybridProcessingMode::AdaptiveBlend,
293 HybridStrategy::QuantumNeural => HybridProcessingMode::QuantumDominant,
294 }
295 }
296
297 fn adaptive_mode_selection(
299 &self,
300 rows: usize,
301 _cols: usize,
302 indptr: &[usize],
303 _indices: &[usize],
304 ) -> HybridProcessingMode {
305 let quantum_score = self.hybrid_state.quantum_coherence * 0.7
306 + self.hybrid_state.entanglement_strength * 0.3;
307
308 let neural_score = self.hybrid_state.neural_confidence * 0.8
309 + self.hybrid_state.hybrid_synchronization * 0.2;
310
311 let size_factor = (rows as f64).log10() / 6.0; let avg_nnz = if rows > 0 { indptr[rows] / rows } else { 0 };
314 let sparsity_factor = (avg_nnz as f64 / 100.0).min(1.0);
315
316 let quantum_preference = quantum_score + size_factor * 0.3;
317 let neural_preference = neural_score + sparsity_factor * 0.3;
318
319 if quantum_preference > neural_preference + 0.2 {
320 HybridProcessingMode::QuantumDominant
321 } else if neural_preference > quantum_preference + 0.2 {
322 HybridProcessingMode::NeuralDominant
323 } else {
324 HybridProcessingMode::BalancedHybrid
325 }
326 }
327
328 fn quantum_dominant_hybrid<T>(
330 &mut self,
331 rows: usize,
332 cols: usize,
333 indptr: &[usize],
334 indices: &[usize],
335 data: &[T],
336 x: &[T],
337 y: &mut [T],
338 ) -> SparseResult<()>
339 where
340 T: Float
341 + SparseElement
342 + NumAssign
343 + Send
344 + Sync
345 + Copy
346 + SimdUnifiedOps
347 + Into<f64>
348 + From<f64>
349 + std::fmt::Debug
350 + 'static,
351 {
352 let mut quantum_result = vec![T::sparse_zero(); rows];
354 self.quantum_processor
355 .quantum_spmv(rows, indptr, indices, data, x, &mut quantum_result)?;
356
357 if self._config.neural_guidance {
359 let mut neural_result = vec![T::sparse_zero(); rows];
360 self.neural_processor.adaptive_spmv(
361 &[rows],
362 &[cols],
363 indptr,
364 indices,
365 data,
366 x,
367 &mut neural_result,
368 )?;
369
370 let quantum_weight = 0.85;
372 let neural_weight = 0.15;
373
374 for i in 0..rows {
375 y[i] = NumCast::from(
376 quantum_weight * quantum_result[i].into()
377 + neural_weight * neural_result[i].into(),
378 )
379 .unwrap_or(T::sparse_zero());
380 }
381 } else {
382 y.copy_from_slice(&quantum_result);
383 }
384
385 Ok(())
386 }
387
388 fn neural_dominant_hybrid<T>(
390 &mut self,
391 rows: usize,
392 cols: usize,
393 indptr: &[usize],
394 indices: &[usize],
395 data: &[T],
396 x: &[T],
397 y: &mut [T],
398 ) -> SparseResult<()>
399 where
400 T: Float
401 + SparseElement
402 + NumAssign
403 + Send
404 + Sync
405 + Copy
406 + SimdUnifiedOps
407 + Into<f64>
408 + From<f64>
409 + std::fmt::Debug
410 + 'static,
411 {
412 self.neural_processor
414 .adaptive_spmv(&[rows], &[cols], indptr, indices, data, x, y)?;
415
416 if self._config.quantum_feedback && self.hybrid_state.quantum_coherence > 0.5 {
418 let mut quantum_enhancement = vec![T::sparse_zero(); rows];
419 self.quantum_processor.quantum_spmv(
420 rows,
421 indptr,
422 indices,
423 data,
424 x,
425 &mut quantum_enhancement,
426 )?;
427
428 let enhancement_strength = self.hybrid_state.quantum_coherence * 0.2;
430
431 for i in 0..rows {
432 let current_val: f64 = y[i].into();
433 let enhancement: f64 = quantum_enhancement[i].into();
434 y[i] = NumCast::from(current_val + enhancement_strength * enhancement)
435 .unwrap_or(T::sparse_zero());
436 }
437 }
438
439 Ok(())
440 }
441
442 fn balanced_hybrid<T>(
444 &mut self,
445 rows: usize,
446 cols: usize,
447 indptr: &[usize],
448 indices: &[usize],
449 data: &[T],
450 x: &[T],
451 y: &mut [T],
452 ) -> SparseResult<()>
453 where
454 T: Float
455 + SparseElement
456 + NumAssign
457 + Send
458 + Sync
459 + Copy
460 + SimdUnifiedOps
461 + Into<f64>
462 + From<f64>
463 + std::fmt::Debug
464 + 'static,
465 {
466 let mut quantum_result = vec![T::sparse_zero(); rows];
468 let mut neural_result = vec![T::sparse_zero(); rows];
469
470 self.quantum_processor
472 .quantum_spmv(rows, indptr, indices, data, x, &mut quantum_result)?;
473 self.neural_processor.adaptive_spmv(
474 &[rows],
475 &[cols],
476 indptr,
477 indices,
478 data,
479 x,
480 &mut neural_result,
481 )?;
482
483 let quantum_weight = self.performance_fusion.fusion_weights[0];
485 let neural_weight = self.performance_fusion.fusion_weights[1];
486
487 for i in 0..rows {
488 y[i] = NumCast::from(
489 quantum_weight * quantum_result[i].into() + neural_weight * neural_result[i].into(),
490 )
491 .unwrap_or(T::sparse_zero());
492 }
493
494 Ok(())
495 }
496
497 fn adaptive_blend<T>(
499 &mut self,
500 rows: usize,
501 _cols: usize,
502 indptr: &[usize],
503 indices: &[usize],
504 data: &[T],
505 x: &[T],
506 y: &mut [T],
507 ) -> SparseResult<()>
508 where
509 T: Float
510 + SparseElement
511 + NumAssign
512 + Send
513 + Sync
514 + Copy
515 + SimdUnifiedOps
516 + Into<f64>
517 + From<f64>
518 + std::fmt::Debug
519 + 'static,
520 {
521 for row in 0..rows {
523 let start_idx = indptr[row];
524 let end_idx = indptr[row + 1];
525 let row_nnz = end_idx - start_idx;
526
527 let quantum_ratio = if row_nnz > 50 {
529 self.hybrid_state.quantum_coherence
530 } else {
531 self.hybrid_state.neural_confidence
532 };
533
534 let neural_ratio = 1.0 - quantum_ratio;
535
536 let mut quantum_sum = 0.0;
538 let mut neural_sum = 0.0;
539
540 for idx in start_idx..end_idx {
541 let col = indices[idx];
542 let val: f64 = data[idx].into();
543 let x_val: f64 = x[col].into();
544
545 let coupling_factor = if idx < self.hybrid_state.quantum_neural_coupling.len() {
547 self.hybrid_state.quantum_neural_coupling
548 [idx % self.hybrid_state.quantum_neural_coupling.len()]
549 } else {
550 1.0
551 };
552
553 quantum_sum += val * x_val * coupling_factor;
554 neural_sum += val * x_val; }
556
557 y[row] = NumCast::from(quantum_ratio * quantum_sum + neural_ratio * neural_sum)
559 .unwrap_or(T::sparse_zero());
560 }
561
562 Ok(())
563 }
564
565 fn calculate_sparsity_regularity(&self, indptr: &[usize], indices: &[usize]) -> f64 {
568 let rows = indptr.len() - 1;
569 if rows <= 1 {
570 return 1.0;
571 }
572
573 let mut nnz_per_row = Vec::new();
574 for row in 0..rows {
575 nnz_per_row.push(indptr[row + 1] - indptr[row]);
576 }
577
578 let mean = nnz_per_row.iter().sum::<usize>() as f64 / rows as f64;
579 let variance = nnz_per_row
580 .iter()
581 .map(|&x| (x as f64 - mean).powi(2))
582 .sum::<f64>()
583 / rows as f64;
584
585 (1.0 / (1.0 + variance.sqrt())).min(1.0)
587 }
588
589 fn calculate_pattern_familiarity(&self, _indptr: &[usize], indices: &[usize]) -> f64 {
590 let memory_size = self.hybrid_memory.neural_patterns.len();
592 let max_memory = self.hybrid_memory.memory_capacity;
593
594 (memory_size as f64 / max_memory as f64).min(1.0)
595 }
596
597 fn update_quantum_neural_coupling(&mut self) {
598 let coupling_strength = self._config.coupling_strength;
599 let synchronization = self.hybrid_state.hybrid_synchronization;
600
601 for coupling in &mut self.hybrid_state.quantum_neural_coupling {
602 let fluctuation = (scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1;
604 *coupling = coupling_strength * synchronization + fluctuation;
605 *coupling = coupling.clamp(0.0, 2.0);
606 }
607
608 self.hybrid_state.entanglement_strength = self
610 .hybrid_state
611 .quantum_neural_coupling
612 .iter()
613 .sum::<f64>()
614 / self.hybrid_state.quantum_neural_coupling.len() as f64;
615 }
616
617 fn apply_memory_decay(&mut self) {
618 let decay_factor = 1.0 - self.hybrid_memory.forgetting_rate;
619
620 for row in &mut self.hybrid_memory.correlation_matrix {
622 for val in row {
623 *val *= decay_factor;
624 }
625 }
626 }
627
628 fn update_performance_fusion(&mut self, mode: HybridProcessingMode, executiontime: f64) {
629 let performance = 1.0 / (executiontime + 1e-6);
630
631 match mode {
632 HybridProcessingMode::PureQuantum | HybridProcessingMode::QuantumDominant => {
633 self.performance_fusion.quantum_metrics.push(performance);
634 if self.performance_fusion.quantum_metrics.len() > 100 {
635 self.performance_fusion.quantum_metrics.remove(0);
636 }
637 }
638 HybridProcessingMode::PureNeural | HybridProcessingMode::NeuralDominant => {
639 self.performance_fusion.neural_metrics.push(performance);
640 if self.performance_fusion.neural_metrics.len() > 100 {
641 self.performance_fusion.neural_metrics.remove(0);
642 }
643 }
644 HybridProcessingMode::BalancedHybrid | HybridProcessingMode::AdaptiveBlend => {
645 self.performance_fusion
646 .quantum_metrics
647 .push(performance * 0.5);
648 self.performance_fusion
649 .neural_metrics
650 .push(performance * 0.5);
651 }
652 }
653
654 if self.performance_fusion.adaptive_blending {
656 self.update_fusion_weights();
657 }
658 }
659
660 fn update_fusion_weights(&mut self) {
661 let quantum_avg = if !self.performance_fusion.quantum_metrics.is_empty() {
662 self.performance_fusion.quantum_metrics.iter().sum::<f64>()
663 / self.performance_fusion.quantum_metrics.len() as f64
664 } else {
665 0.5
666 };
667
668 let neural_avg = if !self.performance_fusion.neural_metrics.is_empty() {
669 self.performance_fusion.neural_metrics.iter().sum::<f64>()
670 / self.performance_fusion.neural_metrics.len() as f64
671 } else {
672 0.5
673 };
674
675 let total = quantum_avg + neural_avg;
676 if total > 0.0 {
677 self.performance_fusion.fusion_weights[0] = quantum_avg / total;
678 self.performance_fusion.fusion_weights[1] = neural_avg / total;
679 }
680
681 let exploration = 0.05;
683 self.performance_fusion.fusion_weights[0] +=
684 (scirs2_core::random::rng().random::<f64>() - 0.5) * exploration;
685 self.performance_fusion.fusion_weights[1] = 1.0 - self.performance_fusion.fusion_weights[0];
686
687 self.performance_fusion.fusion_weights[0] =
689 self.performance_fusion.fusion_weights[0].clamp(0.1, 0.9);
690 self.performance_fusion.fusion_weights[1] = 1.0 - self.performance_fusion.fusion_weights[0];
691 }
692
693 fn update_hybrid_learning(&mut self, mode: HybridProcessingMode, executiontime: f64) {
694 let decision = HybridDecision {
695 timestamp: std::time::SystemTime::now()
696 .duration_since(std::time::UNIX_EPOCH)
697 .unwrap_or_default()
698 .as_secs(),
699 strategy_used: mode,
700 quantum_contribution: self.performance_fusion.fusion_weights[0],
701 neural_contribution: self.performance_fusion.fusion_weights[1],
702 performance_achieved: 1.0 / (executiontime + 1e-6),
703 coherence_at_decision: self.hybrid_state.quantum_coherence,
704 };
705
706 self.hybrid_state.decision_history.push(decision);
707
708 if self.hybrid_state.decision_history.len() > 1000 {
710 self.hybrid_state.decision_history.remove(0);
711 }
712 }
713
714 pub fn get_stats(&self) -> QuantumNeuralHybridStats {
716 let recent_decisions = self
717 .hybrid_state
718 .decision_history
719 .iter()
720 .rev()
721 .take(10)
722 .collect::<Vec<_>>();
723
724 let avg_performance = if !recent_decisions.is_empty() {
725 recent_decisions
726 .iter()
727 .map(|d| d.performance_achieved)
728 .sum::<f64>()
729 / recent_decisions.len() as f64
730 } else {
731 0.0
732 };
733
734 QuantumNeuralHybridStats {
735 total_operations: self.adaptation_counter.load(Ordering::Relaxed),
736 quantum_coherence: self.hybrid_state.quantum_coherence,
737 neural_confidence: self.hybrid_state.neural_confidence,
738 hybrid_synchronization: self.hybrid_state.hybrid_synchronization,
739 entanglement_strength: self.hybrid_state.entanglement_strength,
740 quantum_weight: self.performance_fusion.fusion_weights[0],
741 neural_weight: self.performance_fusion.fusion_weights[1],
742 average_performance: avg_performance,
743 memory_utilization: self.hybrid_memory.neural_patterns.len() as f64
744 / self.hybrid_memory.memory_capacity as f64,
745 decision_history_size: self.hybrid_state.decision_history.len(),
746 }
747 }
748}
749
750#[derive(Debug)]
752pub struct QuantumNeuralHybridStats {
753 pub total_operations: usize,
754 pub quantum_coherence: f64,
755 pub neural_confidence: f64,
756 pub hybrid_synchronization: f64,
757 pub entanglement_strength: f64,
758 pub quantum_weight: f64,
759 pub neural_weight: f64,
760 pub average_performance: f64,
761 pub memory_utilization: f64,
762 pub decision_history_size: usize,
763}
764
765#[cfg(test)]
766mod tests {
767 use super::*;
768 use approx::assert_relative_eq;
769
770 #[test]
771 #[ignore] fn test_quantum_neural_hybrid_creation() {
773 let config = QuantumNeuralConfig::default();
774 let processor = QuantumNeuralHybridProcessor::new(config);
775
776 assert_eq!(processor.hybrid_state.quantum_coherence, 1.0);
777 assert_eq!(processor.hybrid_state.neural_confidence, 1.0);
778 assert_eq!(processor.performance_fusion.fusion_weights.len(), 2);
779 }
780
781 #[test]
782 #[ignore = "timeout"]
783 fn test_hybrid_spmv() {
784 let config = QuantumNeuralConfig::default();
785 let mut processor = QuantumNeuralHybridProcessor::new(config);
786
787 let indptr = vec![0, 2, 3];
789 let indices = vec![0, 1, 1];
790 let data = vec![1.0, 2.0, 3.0];
791 let x = vec![1.0, 1.0];
792 let mut y = vec![0.0; 2];
793
794 processor
795 .hybrid_spmv(2, 2, &indptr, &indices, &data, &x, &mut y)
796 .unwrap();
797
798 assert!(y[0] > 2.0 && y[0] < 4.0);
800 assert!(y[1] > 2.0 && y[1] < 4.0);
801 }
802
803 #[test]
804 #[ignore] fn test_hybrid_stats() {
806 let config = QuantumNeuralConfig::default();
807 let processor = QuantumNeuralHybridProcessor::new(config);
808 let stats = processor.get_stats();
809
810 assert_eq!(stats.total_operations, 0);
811 assert_eq!(stats.quantum_coherence, 1.0);
812 assert_eq!(stats.neural_confidence, 1.0);
813 assert!(stats.quantum_weight > 0.0);
814 assert!(stats.neural_weight > 0.0);
815 assert_relative_eq!(
816 stats.quantum_weight + stats.neural_weight,
817 1.0,
818 epsilon = 1e-10
819 );
820 }
821}