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};
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 + NumAssign
200 + Send
201 + Sync
202 + Copy
203 + SimdUnifiedOps
204 + Into<f64>
205 + From<f64>
206 + std::fmt::Debug
207 + 'static,
208 {
209 let start_time = std::time::Instant::now();
210
211 self.update_hybrid_state(indptr, indices);
213
214 let processing_mode = self.select_processing_mode(rows, cols, indptr, indices);
216
217 let result = match processing_mode {
219 HybridProcessingMode::PureQuantum => self
220 .quantum_processor
221 .quantum_spmv(rows, indptr, indices, data, x, y),
222 HybridProcessingMode::PureNeural => {
223 self.neural_processor
224 .adaptive_spmv(&[rows], &[cols], indptr, indices, data, x, y)
225 }
226 HybridProcessingMode::QuantumDominant => {
227 self.quantum_dominant_hybrid(rows, cols, indptr, indices, data, x, y)
228 }
229 HybridProcessingMode::NeuralDominant => {
230 self.neural_dominant_hybrid(rows, cols, indptr, indices, data, x, y)
231 }
232 HybridProcessingMode::BalancedHybrid => {
233 self.balanced_hybrid(rows, cols, indptr, indices, data, x, y)
234 }
235 HybridProcessingMode::AdaptiveBlend => {
236 self.adaptive_blend(rows, cols, indptr, indices, data, x, y)
237 }
238 };
239
240 let execution_time = start_time.elapsed().as_secs_f64();
242 self.update_performance_fusion(processing_mode, execution_time);
243
244 self.update_hybrid_learning(processing_mode, execution_time);
246
247 self.adaptation_counter.fetch_add(1, Ordering::Relaxed);
248
249 result
250 }
251
252 fn update_hybrid_state(&mut self, indptr: &[usize], indices: &[usize]) {
254 let sparsity_regularity = self.calculate_sparsity_regularity(indptr, indices);
256 self.hybrid_state.quantum_coherence = sparsity_regularity;
257
258 let pattern_familiarity = self.calculate_pattern_familiarity(indptr, indices);
260 self.hybrid_state.neural_confidence = pattern_familiarity;
261
262 self.hybrid_state.hybrid_synchronization =
264 (self.hybrid_state.quantum_coherence + self.hybrid_state.neural_confidence) / 2.0;
265
266 self.update_quantum_neural_coupling();
268
269 self.apply_memory_decay();
271 }
272
273 fn select_processing_mode(
275 &self,
276 rows: usize,
277 cols: usize,
278 indptr: &[usize],
279 indices: &[usize],
280 ) -> HybridProcessingMode {
281 match self._config.hybrid_strategy {
282 HybridStrategy::Sequential => {
283 if self.hybrid_state.quantum_coherence > self._config.coherence_threshold {
284 HybridProcessingMode::PureQuantum
285 } else {
286 HybridProcessingMode::PureNeural
287 }
288 }
289 HybridStrategy::Parallel => HybridProcessingMode::BalancedHybrid,
290 HybridStrategy::Adaptive => self.adaptive_mode_selection(rows, cols, indptr, indices),
291 HybridStrategy::Entangled => HybridProcessingMode::AdaptiveBlend,
292 HybridStrategy::QuantumNeural => HybridProcessingMode::QuantumDominant,
293 }
294 }
295
296 fn adaptive_mode_selection(
298 &self,
299 rows: usize,
300 _cols: usize,
301 indptr: &[usize],
302 _indices: &[usize],
303 ) -> HybridProcessingMode {
304 let quantum_score = self.hybrid_state.quantum_coherence * 0.7
305 + self.hybrid_state.entanglement_strength * 0.3;
306
307 let neural_score = self.hybrid_state.neural_confidence * 0.8
308 + self.hybrid_state.hybrid_synchronization * 0.2;
309
310 let size_factor = (rows as f64).log10() / 6.0; let avg_nnz = if rows > 0 { indptr[rows] / rows } else { 0 };
313 let sparsity_factor = (avg_nnz as f64 / 100.0).min(1.0);
314
315 let quantum_preference = quantum_score + size_factor * 0.3;
316 let neural_preference = neural_score + sparsity_factor * 0.3;
317
318 if quantum_preference > neural_preference + 0.2 {
319 HybridProcessingMode::QuantumDominant
320 } else if neural_preference > quantum_preference + 0.2 {
321 HybridProcessingMode::NeuralDominant
322 } else {
323 HybridProcessingMode::BalancedHybrid
324 }
325 }
326
327 fn quantum_dominant_hybrid<T>(
329 &mut self,
330 rows: usize,
331 cols: usize,
332 indptr: &[usize],
333 indices: &[usize],
334 data: &[T],
335 x: &[T],
336 y: &mut [T],
337 ) -> SparseResult<()>
338 where
339 T: Float
340 + NumAssign
341 + Send
342 + Sync
343 + Copy
344 + SimdUnifiedOps
345 + Into<f64>
346 + From<f64>
347 + std::fmt::Debug
348 + 'static,
349 {
350 let mut quantum_result = vec![T::zero(); rows];
352 self.quantum_processor
353 .quantum_spmv(rows, indptr, indices, data, x, &mut quantum_result)?;
354
355 if self._config.neural_guidance {
357 let mut neural_result = vec![T::zero(); rows];
358 self.neural_processor.adaptive_spmv(
359 &[rows],
360 &[cols],
361 indptr,
362 indices,
363 data,
364 x,
365 &mut neural_result,
366 )?;
367
368 let quantum_weight = 0.85;
370 let neural_weight = 0.15;
371
372 for i in 0..rows {
373 y[i] = NumCast::from(
374 quantum_weight * quantum_result[i].into()
375 + neural_weight * neural_result[i].into(),
376 )
377 .unwrap_or(T::zero());
378 }
379 } else {
380 y.copy_from_slice(&quantum_result);
381 }
382
383 Ok(())
384 }
385
386 fn neural_dominant_hybrid<T>(
388 &mut self,
389 rows: usize,
390 cols: usize,
391 indptr: &[usize],
392 indices: &[usize],
393 data: &[T],
394 x: &[T],
395 y: &mut [T],
396 ) -> SparseResult<()>
397 where
398 T: Float
399 + NumAssign
400 + Send
401 + Sync
402 + Copy
403 + SimdUnifiedOps
404 + Into<f64>
405 + From<f64>
406 + std::fmt::Debug
407 + 'static,
408 {
409 self.neural_processor
411 .adaptive_spmv(&[rows], &[cols], indptr, indices, data, x, y)?;
412
413 if self._config.quantum_feedback && self.hybrid_state.quantum_coherence > 0.5 {
415 let mut quantum_enhancement = vec![T::zero(); rows];
416 self.quantum_processor.quantum_spmv(
417 rows,
418 indptr,
419 indices,
420 data,
421 x,
422 &mut quantum_enhancement,
423 )?;
424
425 let enhancement_strength = self.hybrid_state.quantum_coherence * 0.2;
427
428 for i in 0..rows {
429 let current_val: f64 = y[i].into();
430 let enhancement: f64 = quantum_enhancement[i].into();
431 y[i] = NumCast::from(current_val + enhancement_strength * enhancement)
432 .unwrap_or(T::zero());
433 }
434 }
435
436 Ok(())
437 }
438
439 fn balanced_hybrid<T>(
441 &mut self,
442 rows: usize,
443 cols: usize,
444 indptr: &[usize],
445 indices: &[usize],
446 data: &[T],
447 x: &[T],
448 y: &mut [T],
449 ) -> SparseResult<()>
450 where
451 T: Float
452 + NumAssign
453 + Send
454 + Sync
455 + Copy
456 + SimdUnifiedOps
457 + Into<f64>
458 + From<f64>
459 + std::fmt::Debug
460 + 'static,
461 {
462 let mut quantum_result = vec![T::zero(); rows];
464 let mut neural_result = vec![T::zero(); rows];
465
466 self.quantum_processor
468 .quantum_spmv(rows, indptr, indices, data, x, &mut quantum_result)?;
469 self.neural_processor.adaptive_spmv(
470 &[rows],
471 &[cols],
472 indptr,
473 indices,
474 data,
475 x,
476 &mut neural_result,
477 )?;
478
479 let quantum_weight = self.performance_fusion.fusion_weights[0];
481 let neural_weight = self.performance_fusion.fusion_weights[1];
482
483 for i in 0..rows {
484 y[i] = NumCast::from(
485 quantum_weight * quantum_result[i].into() + neural_weight * neural_result[i].into(),
486 )
487 .unwrap_or(T::zero());
488 }
489
490 Ok(())
491 }
492
493 fn adaptive_blend<T>(
495 &mut self,
496 rows: usize,
497 _cols: usize,
498 indptr: &[usize],
499 indices: &[usize],
500 data: &[T],
501 x: &[T],
502 y: &mut [T],
503 ) -> SparseResult<()>
504 where
505 T: Float
506 + NumAssign
507 + Send
508 + Sync
509 + Copy
510 + SimdUnifiedOps
511 + Into<f64>
512 + From<f64>
513 + std::fmt::Debug
514 + 'static,
515 {
516 for row in 0..rows {
518 let start_idx = indptr[row];
519 let end_idx = indptr[row + 1];
520 let row_nnz = end_idx - start_idx;
521
522 let quantum_ratio = if row_nnz > 50 {
524 self.hybrid_state.quantum_coherence
525 } else {
526 self.hybrid_state.neural_confidence
527 };
528
529 let neural_ratio = 1.0 - quantum_ratio;
530
531 let mut quantum_sum = 0.0;
533 let mut neural_sum = 0.0;
534
535 for idx in start_idx..end_idx {
536 let col = indices[idx];
537 let val: f64 = data[idx].into();
538 let x_val: f64 = x[col].into();
539
540 let coupling_factor = if idx < self.hybrid_state.quantum_neural_coupling.len() {
542 self.hybrid_state.quantum_neural_coupling
543 [idx % self.hybrid_state.quantum_neural_coupling.len()]
544 } else {
545 1.0
546 };
547
548 quantum_sum += val * x_val * coupling_factor;
549 neural_sum += val * x_val; }
551
552 y[row] = NumCast::from(quantum_ratio * quantum_sum + neural_ratio * neural_sum)
554 .unwrap_or(T::zero());
555 }
556
557 Ok(())
558 }
559
560 fn calculate_sparsity_regularity(&self, indptr: &[usize], indices: &[usize]) -> f64 {
563 let rows = indptr.len() - 1;
564 if rows <= 1 {
565 return 1.0;
566 }
567
568 let mut nnz_per_row = Vec::new();
569 for row in 0..rows {
570 nnz_per_row.push(indptr[row + 1] - indptr[row]);
571 }
572
573 let mean = nnz_per_row.iter().sum::<usize>() as f64 / rows as f64;
574 let variance = nnz_per_row
575 .iter()
576 .map(|&x| (x as f64 - mean).powi(2))
577 .sum::<f64>()
578 / rows as f64;
579
580 (1.0 / (1.0 + variance.sqrt())).min(1.0)
582 }
583
584 fn calculate_pattern_familiarity(&self, _indptr: &[usize], indices: &[usize]) -> f64 {
585 let memory_size = self.hybrid_memory.neural_patterns.len();
587 let max_memory = self.hybrid_memory.memory_capacity;
588
589 (memory_size as f64 / max_memory as f64).min(1.0)
590 }
591
592 fn update_quantum_neural_coupling(&mut self) {
593 let coupling_strength = self._config.coupling_strength;
594 let synchronization = self.hybrid_state.hybrid_synchronization;
595
596 for coupling in &mut self.hybrid_state.quantum_neural_coupling {
597 let fluctuation = (scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1;
599 *coupling = coupling_strength * synchronization + fluctuation;
600 *coupling = coupling.clamp(0.0, 2.0);
601 }
602
603 self.hybrid_state.entanglement_strength = self
605 .hybrid_state
606 .quantum_neural_coupling
607 .iter()
608 .sum::<f64>()
609 / self.hybrid_state.quantum_neural_coupling.len() as f64;
610 }
611
612 fn apply_memory_decay(&mut self) {
613 let decay_factor = 1.0 - self.hybrid_memory.forgetting_rate;
614
615 for row in &mut self.hybrid_memory.correlation_matrix {
617 for val in row {
618 *val *= decay_factor;
619 }
620 }
621 }
622
623 fn update_performance_fusion(&mut self, mode: HybridProcessingMode, executiontime: f64) {
624 let performance = 1.0 / (executiontime + 1e-6);
625
626 match mode {
627 HybridProcessingMode::PureQuantum | HybridProcessingMode::QuantumDominant => {
628 self.performance_fusion.quantum_metrics.push(performance);
629 if self.performance_fusion.quantum_metrics.len() > 100 {
630 self.performance_fusion.quantum_metrics.remove(0);
631 }
632 }
633 HybridProcessingMode::PureNeural | HybridProcessingMode::NeuralDominant => {
634 self.performance_fusion.neural_metrics.push(performance);
635 if self.performance_fusion.neural_metrics.len() > 100 {
636 self.performance_fusion.neural_metrics.remove(0);
637 }
638 }
639 HybridProcessingMode::BalancedHybrid | HybridProcessingMode::AdaptiveBlend => {
640 self.performance_fusion
641 .quantum_metrics
642 .push(performance * 0.5);
643 self.performance_fusion
644 .neural_metrics
645 .push(performance * 0.5);
646 }
647 }
648
649 if self.performance_fusion.adaptive_blending {
651 self.update_fusion_weights();
652 }
653 }
654
655 fn update_fusion_weights(&mut self) {
656 let quantum_avg = if !self.performance_fusion.quantum_metrics.is_empty() {
657 self.performance_fusion.quantum_metrics.iter().sum::<f64>()
658 / self.performance_fusion.quantum_metrics.len() as f64
659 } else {
660 0.5
661 };
662
663 let neural_avg = if !self.performance_fusion.neural_metrics.is_empty() {
664 self.performance_fusion.neural_metrics.iter().sum::<f64>()
665 / self.performance_fusion.neural_metrics.len() as f64
666 } else {
667 0.5
668 };
669
670 let total = quantum_avg + neural_avg;
671 if total > 0.0 {
672 self.performance_fusion.fusion_weights[0] = quantum_avg / total;
673 self.performance_fusion.fusion_weights[1] = neural_avg / total;
674 }
675
676 let exploration = 0.05;
678 self.performance_fusion.fusion_weights[0] +=
679 (scirs2_core::random::rng().random::<f64>() - 0.5) * exploration;
680 self.performance_fusion.fusion_weights[1] = 1.0 - self.performance_fusion.fusion_weights[0];
681
682 self.performance_fusion.fusion_weights[0] =
684 self.performance_fusion.fusion_weights[0].clamp(0.1, 0.9);
685 self.performance_fusion.fusion_weights[1] = 1.0 - self.performance_fusion.fusion_weights[0];
686 }
687
688 fn update_hybrid_learning(&mut self, mode: HybridProcessingMode, executiontime: f64) {
689 let decision = HybridDecision {
690 timestamp: std::time::SystemTime::now()
691 .duration_since(std::time::UNIX_EPOCH)
692 .unwrap_or_default()
693 .as_secs(),
694 strategy_used: mode,
695 quantum_contribution: self.performance_fusion.fusion_weights[0],
696 neural_contribution: self.performance_fusion.fusion_weights[1],
697 performance_achieved: 1.0 / (executiontime + 1e-6),
698 coherence_at_decision: self.hybrid_state.quantum_coherence,
699 };
700
701 self.hybrid_state.decision_history.push(decision);
702
703 if self.hybrid_state.decision_history.len() > 1000 {
705 self.hybrid_state.decision_history.remove(0);
706 }
707 }
708
709 pub fn get_stats(&self) -> QuantumNeuralHybridStats {
711 let recent_decisions = self
712 .hybrid_state
713 .decision_history
714 .iter()
715 .rev()
716 .take(10)
717 .collect::<Vec<_>>();
718
719 let avg_performance = if !recent_decisions.is_empty() {
720 recent_decisions
721 .iter()
722 .map(|d| d.performance_achieved)
723 .sum::<f64>()
724 / recent_decisions.len() as f64
725 } else {
726 0.0
727 };
728
729 QuantumNeuralHybridStats {
730 total_operations: self.adaptation_counter.load(Ordering::Relaxed),
731 quantum_coherence: self.hybrid_state.quantum_coherence,
732 neural_confidence: self.hybrid_state.neural_confidence,
733 hybrid_synchronization: self.hybrid_state.hybrid_synchronization,
734 entanglement_strength: self.hybrid_state.entanglement_strength,
735 quantum_weight: self.performance_fusion.fusion_weights[0],
736 neural_weight: self.performance_fusion.fusion_weights[1],
737 average_performance: avg_performance,
738 memory_utilization: self.hybrid_memory.neural_patterns.len() as f64
739 / self.hybrid_memory.memory_capacity as f64,
740 decision_history_size: self.hybrid_state.decision_history.len(),
741 }
742 }
743}
744
745#[derive(Debug)]
747pub struct QuantumNeuralHybridStats {
748 pub total_operations: usize,
749 pub quantum_coherence: f64,
750 pub neural_confidence: f64,
751 pub hybrid_synchronization: f64,
752 pub entanglement_strength: f64,
753 pub quantum_weight: f64,
754 pub neural_weight: f64,
755 pub average_performance: f64,
756 pub memory_utilization: f64,
757 pub decision_history_size: usize,
758}
759
760#[cfg(test)]
761mod tests {
762 use super::*;
763 use approx::assert_relative_eq;
764
765 #[test]
766 #[ignore] fn test_quantum_neural_hybrid_creation() {
768 let config = QuantumNeuralConfig::default();
769 let processor = QuantumNeuralHybridProcessor::new(config);
770
771 assert_eq!(processor.hybrid_state.quantum_coherence, 1.0);
772 assert_eq!(processor.hybrid_state.neural_confidence, 1.0);
773 assert_eq!(processor.performance_fusion.fusion_weights.len(), 2);
774 }
775
776 #[test]
777 #[ignore = "timeout"]
778 fn test_hybrid_spmv() {
779 let config = QuantumNeuralConfig::default();
780 let mut processor = QuantumNeuralHybridProcessor::new(config);
781
782 let indptr = vec![0, 2, 3];
784 let indices = vec![0, 1, 1];
785 let data = vec![1.0, 2.0, 3.0];
786 let x = vec![1.0, 1.0];
787 let mut y = vec![0.0; 2];
788
789 processor
790 .hybrid_spmv(2, 2, &indptr, &indices, &data, &x, &mut y)
791 .unwrap();
792
793 assert!(y[0] > 2.0 && y[0] < 4.0);
795 assert!(y[1] > 2.0 && y[1] < 4.0);
796 }
797
798 #[test]
799 #[ignore] fn test_hybrid_stats() {
801 let config = QuantumNeuralConfig::default();
802 let processor = QuantumNeuralHybridProcessor::new(config);
803 let stats = processor.get_stats();
804
805 assert_eq!(stats.total_operations, 0);
806 assert_eq!(stats.quantum_coherence, 1.0);
807 assert_eq!(stats.neural_confidence, 1.0);
808 assert!(stats.quantum_weight > 0.0);
809 assert!(stats.neural_weight > 0.0);
810 assert_relative_eq!(
811 stats.quantum_weight + stats.neural_weight,
812 1.0,
813 epsilon = 1e-10
814 );
815 }
816}