1use crate::{
8 error::{QuantRS2Error, QuantRS2Result},
9 gate::GateOp,
10};
11use ndarray::{Array1, Array2};
12use num_complex::Complex64;
13use std::{
14 collections::HashMap,
15 sync::{Arc, RwLock},
16 time::{Duration, Instant},
17};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub enum PrecisionMode {
22 Single,
24 Double,
26 Extended,
28 Arbitrary(u32), Adaptive,
32}
33
34impl Default for PrecisionMode {
35 fn default() -> Self {
36 PrecisionMode::Double
37 }
38}
39
40#[derive(Debug, Clone)]
42pub struct AdaptivePrecisionConfig {
43 pub initial_precision: PrecisionMode,
45 pub target_accuracy: f64,
47 pub max_error_threshold: f64,
49 pub min_precision: PrecisionMode,
51 pub max_precision: PrecisionMode,
53 pub error_estimation_samples: usize,
55 pub adaptation_interval: usize,
57 pub enable_auto_adjustment: bool,
59 pub performance_weight: f64,
61}
62
63impl Default for AdaptivePrecisionConfig {
64 fn default() -> Self {
65 Self {
66 initial_precision: PrecisionMode::Double,
67 target_accuracy: 1e-12,
68 max_error_threshold: 1e-10,
69 min_precision: PrecisionMode::Single,
70 max_precision: PrecisionMode::Arbitrary(256),
71 error_estimation_samples: 100,
72 adaptation_interval: 1000,
73 enable_auto_adjustment: true,
74 performance_weight: 0.3,
75 }
76 }
77}
78
79#[derive(Debug)]
81pub struct AdaptivePrecisionSimulator {
82 config: AdaptivePrecisionConfig,
83 current_precision: PrecisionMode,
84 error_monitor: Arc<RwLock<PrecisionErrorMonitor>>,
85 performance_monitor: Arc<RwLock<PrecisionPerformanceMonitor>>,
86 operation_count: usize,
87 last_adaptation: Instant,
88}
89
90#[derive(Debug)]
92pub struct PrecisionErrorMonitor {
93 error_history: Vec<f64>,
95 error_estimators: Vec<Box<dyn ErrorEstimator>>,
97 current_error: f64,
99 error_trend: ErrorTrend,
101}
102
103#[derive(Debug)]
105pub struct PrecisionPerformanceMonitor {
106 timing_by_precision: HashMap<PrecisionMode, Vec<f64>>,
108 memory_by_precision: HashMap<PrecisionMode, Vec<usize>>,
110 current_performance: PerformanceMetrics,
112}
113
114#[derive(Debug, Clone)]
115pub struct PerformanceMetrics {
116 pub operations_per_second: f64,
117 pub memory_usage_bytes: usize,
118 pub error_rate: f64,
119 pub adaptation_overhead: f64,
120}
121
122#[derive(Debug, Clone, Copy)]
123pub enum ErrorTrend {
124 Decreasing,
125 Stable,
126 Increasing,
127}
128
129pub trait ErrorEstimator: Send + Sync + std::fmt::Debug {
131 fn estimate_error(&self, result: &AdaptiveResult, reference: Option<&AdaptiveResult>) -> f64;
133
134 fn name(&self) -> &str;
136
137 fn is_applicable(&self, computation_type: ComputationType) -> bool;
139}
140
141#[derive(Debug, Clone)]
143pub struct AdaptiveResult {
144 pub value: Complex64,
146 pub precision: PrecisionMode,
148 pub estimated_error: f64,
150 pub computation_time: Duration,
152 pub memory_used: usize,
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
158pub enum ComputationType {
159 StateEvolution,
160 ExpectationValue,
161 Probability,
162 Measurement,
163 MatrixMultiplication,
164 EigenvalueDecomposition,
165 TensorContraction,
166}
167
168impl AdaptivePrecisionSimulator {
169 pub fn new(config: AdaptivePrecisionConfig) -> Self {
171 let error_monitor = Arc::new(RwLock::new(PrecisionErrorMonitor::new()));
172 let performance_monitor = Arc::new(RwLock::new(PrecisionPerformanceMonitor::new()));
173
174 Self {
175 current_precision: config.initial_precision,
176 config,
177 error_monitor,
178 performance_monitor,
179 operation_count: 0,
180 last_adaptation: Instant::now(),
181 }
182 }
183
184 pub fn execute_adaptive<F, R>(
186 &mut self,
187 computation: F,
188 comp_type: ComputationType,
189 ) -> QuantRS2Result<AdaptiveResult>
190 where
191 F: FnOnce(PrecisionMode) -> QuantRS2Result<R>,
192 R: Into<Complex64>,
193 {
194 let start_time = Instant::now();
195
196 let result = computation(self.current_precision)?;
198 let computation_time = start_time.elapsed();
199
200 let value = result.into();
202
203 let estimated_error = self.estimate_computation_error(&value, comp_type)?;
205
206 let adaptive_result = AdaptiveResult {
208 value,
209 precision: self.current_precision,
210 estimated_error,
211 computation_time,
212 memory_used: self.estimate_memory_usage(comp_type),
213 };
214
215 self.update_monitoring(&adaptive_result, comp_type)?;
217
218 if self.should_adapt()? {
220 self.adapt_precision(comp_type)?;
221 }
222
223 self.operation_count += 1;
224 Ok(adaptive_result)
225 }
226
227 pub fn apply_gate_adaptive(
229 &mut self,
230 gate: &dyn GateOp,
231 _state: &mut Array1<Complex64>,
232 ) -> QuantRS2Result<AdaptiveResult> {
233 let _matrix = gate.matrix()?;
234 let _current_precision = self.current_precision;
235
236 self.execute_adaptive(
237 move |precision| {
238 let result = match precision {
240 PrecisionMode::Single => {
241 std::thread::sleep(Duration::from_micros(10));
243 Ok::<f64, QuantRS2Error>(1.0)
244 }
245 PrecisionMode::Double => {
246 std::thread::sleep(Duration::from_micros(20));
248 Ok::<f64, QuantRS2Error>(1.0)
249 }
250 PrecisionMode::Extended => {
251 std::thread::sleep(Duration::from_micros(40));
253 Ok::<f64, QuantRS2Error>(1.0)
254 }
255 PrecisionMode::Arbitrary(bits) => {
256 let delay = (bits as u64 / 32) * 50;
258 std::thread::sleep(Duration::from_micros(delay));
259 Ok::<f64, QuantRS2Error>(1.0)
260 }
261 PrecisionMode::Adaptive => {
262 std::thread::sleep(Duration::from_micros(20));
264 Ok::<f64, QuantRS2Error>(1.0)
265 }
266 };
267 let result = result?;
268
269 Ok(result)
270 },
271 ComputationType::StateEvolution,
272 )
273 }
274
275 pub fn expectation_value_adaptive(
277 &mut self,
278 _observable: &Array2<Complex64>,
279 _state: &Array1<Complex64>,
280 ) -> QuantRS2Result<AdaptiveResult> {
281 self.execute_adaptive(
282 |precision| {
283 let result = match precision {
284 PrecisionMode::Single => {
285 std::thread::sleep(Duration::from_micros(15));
286 Complex64::new(0.5, 0.0)
287 }
288 PrecisionMode::Double => {
289 std::thread::sleep(Duration::from_micros(30));
290 Complex64::new(0.5, 0.0)
291 }
292 PrecisionMode::Extended => {
293 std::thread::sleep(Duration::from_micros(60));
294 Complex64::new(0.5, 0.0)
295 }
296 PrecisionMode::Arbitrary(bits) => {
297 let delay = (bits as u64 / 32) * 75;
298 std::thread::sleep(Duration::from_micros(delay));
299 Complex64::new(0.5, 0.0)
300 }
301 PrecisionMode::Adaptive => {
302 std::thread::sleep(Duration::from_micros(30));
303 Complex64::new(0.5, 0.0)
304 }
305 };
306
307 Ok(result)
308 },
309 ComputationType::ExpectationValue,
310 )
311 }
312
313 pub fn current_precision(&self) -> PrecisionMode {
315 self.current_precision
316 }
317
318 pub fn force_adaptation(&mut self, comp_type: ComputationType) -> QuantRS2Result<()> {
320 self.adapt_precision(comp_type)
321 }
322
323 pub fn get_precision_stats(&self) -> PrecisionStatistics {
325 let error_monitor = self.error_monitor.read().unwrap();
326 let perf_monitor = self.performance_monitor.read().unwrap();
327
328 PrecisionStatistics {
329 current_precision: self.current_precision,
330 current_error: error_monitor.current_error,
331 error_trend: error_monitor.error_trend,
332 operations_count: self.operation_count,
333 adaptations_count: self.count_adaptations(),
334 performance_metrics: perf_monitor.current_performance.clone(),
335 precision_usage: self.get_precision_usage(),
336 }
337 }
338
339 fn estimate_computation_error(
342 &self,
343 _result: &Complex64,
344 _comp_type: ComputationType,
345 ) -> QuantRS2Result<f64> {
346 let error_monitor = self.error_monitor.read().unwrap();
347
348 Ok(error_monitor.error_history.last().copied().unwrap_or(1e-15))
350 }
351
352 fn estimate_memory_usage(&self, comp_type: ComputationType) -> usize {
353 let base_memory = match comp_type {
355 ComputationType::StateEvolution => 1024,
356 ComputationType::ExpectationValue => 512,
357 ComputationType::Probability => 256,
358 ComputationType::Measurement => 128,
359 ComputationType::MatrixMultiplication => 2048,
360 ComputationType::EigenvalueDecomposition => 4096,
361 ComputationType::TensorContraction => 8192,
362 };
363
364 let precision_multiplier = match self.current_precision {
365 PrecisionMode::Single => 1.0,
366 PrecisionMode::Double => 2.0,
367 PrecisionMode::Extended => 2.5,
368 PrecisionMode::Arbitrary(bits) => (bits as f64) / 32.0,
369 PrecisionMode::Adaptive => 2.0,
370 };
371
372 (base_memory as f64 * precision_multiplier) as usize
373 }
374
375 fn update_monitoring(
376 &mut self,
377 result: &AdaptiveResult,
378 _comp_type: ComputationType,
379 ) -> QuantRS2Result<()> {
380 {
382 let mut error_monitor = self.error_monitor.write().unwrap();
383 error_monitor.add_error_sample(result.estimated_error);
384 error_monitor.update_error_trend();
385 }
386
387 {
389 let mut perf_monitor = self.performance_monitor.write().unwrap();
390 perf_monitor.add_timing_sample(
391 result.precision,
392 result.computation_time.as_secs_f64() * 1000.0,
393 );
394 perf_monitor.add_memory_sample(result.precision, result.memory_used);
395 perf_monitor.update_current_performance(result);
396 }
397
398 Ok(())
399 }
400
401 fn should_adapt(&self) -> QuantRS2Result<bool> {
402 if !self.config.enable_auto_adjustment {
403 return Ok(false);
404 }
405
406 if self.operation_count % self.config.adaptation_interval != 0 {
408 return Ok(false);
409 }
410
411 if self.last_adaptation.elapsed() < Duration::from_secs(1) {
413 return Ok(false);
414 }
415
416 let error_monitor = self.error_monitor.read().unwrap();
418 if error_monitor.current_error > self.config.max_error_threshold {
419 return Ok(true);
420 }
421
422 if error_monitor.current_error < self.config.target_accuracy / 10.0 {
424 return Ok(true);
425 }
426
427 Ok(false)
428 }
429
430 fn adapt_precision(&mut self, comp_type: ComputationType) -> QuantRS2Result<()> {
431 let error_monitor = self.error_monitor.read().unwrap();
432 let perf_monitor = self.performance_monitor.read().unwrap();
433
434 let current_error = error_monitor.current_error;
435 let error_trend = error_monitor.error_trend;
436
437 let new_precision = if current_error > self.config.max_error_threshold {
439 self.increase_precision(self.current_precision)
441 } else if current_error < self.config.target_accuracy / 10.0
442 && matches!(error_trend, ErrorTrend::Stable | ErrorTrend::Decreasing)
443 {
444 self.decrease_precision(self.current_precision)
446 } else {
447 self.current_precision
449 };
450
451 let final_precision =
453 self.consider_performance_factors(new_precision, &perf_monitor, comp_type);
454
455 if final_precision != self.current_precision {
456 println!(
457 "Adapting precision from {:?} to {:?} (error: {:.2e})",
458 self.current_precision, final_precision, current_error
459 );
460 self.current_precision = final_precision;
461 self.last_adaptation = Instant::now();
462 }
463
464 Ok(())
465 }
466
467 fn increase_precision(&self, current: PrecisionMode) -> PrecisionMode {
468 match current {
469 PrecisionMode::Single => PrecisionMode::Double,
470 PrecisionMode::Double => PrecisionMode::Extended,
471 PrecisionMode::Extended => PrecisionMode::Arbitrary(128),
472 PrecisionMode::Arbitrary(bits) if bits < 512 => PrecisionMode::Arbitrary(bits * 2),
473 _ => current, }
475 }
476
477 fn decrease_precision(&self, current: PrecisionMode) -> PrecisionMode {
478 match current {
479 PrecisionMode::Extended => PrecisionMode::Double,
480 PrecisionMode::Double => PrecisionMode::Single,
481 PrecisionMode::Arbitrary(bits) if bits > 64 => PrecisionMode::Arbitrary(bits / 2),
482 PrecisionMode::Arbitrary(_) => PrecisionMode::Extended,
483 _ => current, }
485 }
486
487 fn consider_performance_factors(
488 &self,
489 suggested: PrecisionMode,
490 _perf_monitor: &PrecisionPerformanceMonitor,
491 _comp_type: ComputationType,
492 ) -> PrecisionMode {
493 suggested
496 }
497
498 fn count_adaptations(&self) -> usize {
499 self.operation_count / self.config.adaptation_interval
501 }
502
503 fn get_precision_usage(&self) -> HashMap<PrecisionMode, f64> {
504 let mut usage = HashMap::new();
506 usage.insert(self.current_precision, 1.0);
507 usage
508 }
509
510 fn apply_gate_single_precision(
513 &self,
514 _matrix: &[Complex64],
515 _state: &mut Array1<Complex64>,
516 ) -> QuantRS2Result<f64> {
517 std::thread::sleep(Duration::from_micros(10)); Ok(1.0)
520 }
521
522 fn apply_gate_double_precision(
523 &self,
524 _matrix: &[Complex64],
525 _state: &mut Array1<Complex64>,
526 ) -> QuantRS2Result<f64> {
527 std::thread::sleep(Duration::from_micros(20)); Ok(1.0)
530 }
531
532 fn apply_gate_extended_precision(
533 &self,
534 _matrix: &[Complex64],
535 _state: &mut Array1<Complex64>,
536 ) -> QuantRS2Result<f64> {
537 std::thread::sleep(Duration::from_micros(40)); Ok(1.0)
540 }
541
542 fn apply_gate_arbitrary_precision(
543 &self,
544 _matrix: &[Complex64],
545 _state: &mut Array1<Complex64>,
546 bits: u32,
547 ) -> QuantRS2Result<f64> {
548 let delay = (bits as u64 / 32) * 50; std::thread::sleep(Duration::from_micros(delay));
551 Ok(1.0)
552 }
553
554 fn expectation_value_single_precision(
555 &self,
556 _observable: &Array2<Complex64>,
557 _state: &Array1<Complex64>,
558 ) -> QuantRS2Result<Complex64> {
559 std::thread::sleep(Duration::from_micros(15));
560 Ok(Complex64::new(0.5, 0.0))
561 }
562
563 fn expectation_value_double_precision(
564 &self,
565 _observable: &Array2<Complex64>,
566 _state: &Array1<Complex64>,
567 ) -> QuantRS2Result<Complex64> {
568 std::thread::sleep(Duration::from_micros(30));
569 Ok(Complex64::new(0.5, 0.0))
570 }
571
572 fn expectation_value_extended_precision(
573 &self,
574 _observable: &Array2<Complex64>,
575 _state: &Array1<Complex64>,
576 ) -> QuantRS2Result<Complex64> {
577 std::thread::sleep(Duration::from_micros(60));
578 Ok(Complex64::new(0.5, 0.0))
579 }
580
581 fn expectation_value_arbitrary_precision(
582 &self,
583 _observable: &Array2<Complex64>,
584 _state: &Array1<Complex64>,
585 bits: u32,
586 ) -> QuantRS2Result<Complex64> {
587 let delay = (bits as u64 / 32) * 75;
588 std::thread::sleep(Duration::from_micros(delay));
589 Ok(Complex64::new(0.5, 0.0))
590 }
591}
592
593#[derive(Debug, Clone)]
594pub struct PrecisionStatistics {
595 pub current_precision: PrecisionMode,
596 pub current_error: f64,
597 pub error_trend: ErrorTrend,
598 pub operations_count: usize,
599 pub adaptations_count: usize,
600 pub performance_metrics: PerformanceMetrics,
601 pub precision_usage: HashMap<PrecisionMode, f64>,
602}
603
604impl PrecisionErrorMonitor {
605 fn new() -> Self {
606 Self {
607 error_history: Vec::new(),
608 error_estimators: vec![
609 Box::new(RichardsonExtrapolationEstimator::new()),
610 Box::new(DoublePrecisionComparisonEstimator::new()),
611 Box::new(ResidualBasedEstimator::new()),
612 ],
613 current_error: 1e-15,
614 error_trend: ErrorTrend::Stable,
615 }
616 }
617
618 fn add_error_sample(&mut self, error: f64) {
619 self.error_history.push(error);
620 if self.error_history.len() > 1000 {
621 self.error_history.remove(0);
622 }
623 self.current_error = error;
624 }
625
626 fn update_error_trend(&mut self) {
627 if self.error_history.len() < 10 {
628 return;
629 }
630
631 let recent = &self.error_history[self.error_history.len().saturating_sub(10)..];
632 let first_half: f64 = recent[..5].iter().sum::<f64>() / 5.0;
633 let second_half: f64 = recent[5..].iter().sum::<f64>() / 5.0;
634
635 self.error_trend = if second_half > first_half * 1.1 {
636 ErrorTrend::Increasing
637 } else if second_half < first_half * 0.9 {
638 ErrorTrend::Decreasing
639 } else {
640 ErrorTrend::Stable
641 };
642 }
643}
644
645impl PrecisionPerformanceMonitor {
646 fn new() -> Self {
647 Self {
648 timing_by_precision: HashMap::new(),
649 memory_by_precision: HashMap::new(),
650 current_performance: PerformanceMetrics {
651 operations_per_second: 1000.0,
652 memory_usage_bytes: 1024,
653 error_rate: 1e-15,
654 adaptation_overhead: 0.01,
655 },
656 }
657 }
658
659 fn add_timing_sample(&mut self, precision: PrecisionMode, time_ms: f64) {
660 self.timing_by_precision
661 .entry(precision)
662 .or_insert_with(Vec::new)
663 .push(time_ms);
664 }
665
666 fn add_memory_sample(&mut self, precision: PrecisionMode, memory: usize) {
667 self.memory_by_precision
668 .entry(precision)
669 .or_insert_with(Vec::new)
670 .push(memory);
671 }
672
673 fn update_current_performance(&mut self, result: &AdaptiveResult) {
674 self.current_performance.operations_per_second =
675 1000.0 / result.computation_time.as_millis().max(1) as f64;
676 self.current_performance.memory_usage_bytes = result.memory_used;
677 self.current_performance.error_rate = result.estimated_error;
678 }
679}
680
681#[derive(Debug)]
684pub struct RichardsonExtrapolationEstimator {
685 name: String,
686}
687
688impl RichardsonExtrapolationEstimator {
689 pub fn new() -> Self {
690 Self {
691 name: "Richardson Extrapolation".to_string(),
692 }
693 }
694}
695
696impl ErrorEstimator for RichardsonExtrapolationEstimator {
697 fn estimate_error(&self, result: &AdaptiveResult, reference: Option<&AdaptiveResult>) -> f64 {
698 if let Some(ref_result) = reference {
700 (result.value - ref_result.value).norm() / 2.0
701 } else {
702 1e-15 }
704 }
705
706 fn name(&self) -> &str {
707 &self.name
708 }
709
710 fn is_applicable(&self, comp_type: ComputationType) -> bool {
711 matches!(
712 comp_type,
713 ComputationType::StateEvolution | ComputationType::ExpectationValue
714 )
715 }
716}
717
718#[derive(Debug)]
719pub struct DoublePrecisionComparisonEstimator {
720 name: String,
721}
722
723impl DoublePrecisionComparisonEstimator {
724 pub fn new() -> Self {
725 Self {
726 name: "Double Precision Comparison".to_string(),
727 }
728 }
729}
730
731impl ErrorEstimator for DoublePrecisionComparisonEstimator {
732 fn estimate_error(&self, result: &AdaptiveResult, _reference: Option<&AdaptiveResult>) -> f64 {
733 match result.precision {
735 PrecisionMode::Single => 1e-7,
736 PrecisionMode::Double => 1e-15,
737 PrecisionMode::Extended => 1e-19,
738 PrecisionMode::Arbitrary(bits) => 10.0_f64.powf(-(bits as f64) / 3.3),
739 PrecisionMode::Adaptive => 1e-15,
740 }
741 }
742
743 fn name(&self) -> &str {
744 &self.name
745 }
746
747 fn is_applicable(&self, _comp_type: ComputationType) -> bool {
748 true
749 }
750}
751
752#[derive(Debug)]
753pub struct ResidualBasedEstimator {
754 name: String,
755}
756
757impl ResidualBasedEstimator {
758 pub fn new() -> Self {
759 Self {
760 name: "Residual Based".to_string(),
761 }
762 }
763}
764
765impl ErrorEstimator for ResidualBasedEstimator {
766 fn estimate_error(&self, result: &AdaptiveResult, _reference: Option<&AdaptiveResult>) -> f64 {
767 result.value.norm() * 1e-16 }
770
771 fn name(&self) -> &str {
772 &self.name
773 }
774
775 fn is_applicable(&self, comp_type: ComputationType) -> bool {
776 matches!(
777 comp_type,
778 ComputationType::MatrixMultiplication | ComputationType::EigenvalueDecomposition
779 )
780 }
781}
782
783pub struct AdaptivePrecisionFactory;
785
786impl AdaptivePrecisionFactory {
787 pub fn create_high_accuracy() -> AdaptivePrecisionSimulator {
789 let config = AdaptivePrecisionConfig {
790 initial_precision: PrecisionMode::Double,
791 target_accuracy: 1e-15,
792 max_error_threshold: 1e-12,
793 min_precision: PrecisionMode::Double,
794 max_precision: PrecisionMode::Arbitrary(512),
795 performance_weight: 0.1, ..Default::default()
797 };
798 AdaptivePrecisionSimulator::new(config)
799 }
800
801 pub fn create_performance_optimized() -> AdaptivePrecisionSimulator {
803 let config = AdaptivePrecisionConfig {
804 initial_precision: PrecisionMode::Single,
805 target_accuracy: 1e-6,
806 max_error_threshold: 1e-4,
807 min_precision: PrecisionMode::Single,
808 max_precision: PrecisionMode::Double,
809 performance_weight: 0.8, adaptation_interval: 100, ..Default::default()
812 };
813 AdaptivePrecisionSimulator::new(config)
814 }
815
816 pub fn create_balanced() -> AdaptivePrecisionSimulator {
818 AdaptivePrecisionSimulator::new(AdaptivePrecisionConfig::default())
819 }
820
821 pub fn create_for_computation_type(comp_type: ComputationType) -> AdaptivePrecisionSimulator {
823 let config = match comp_type {
824 ComputationType::StateEvolution => AdaptivePrecisionConfig {
825 target_accuracy: 1e-12,
826 max_error_threshold: 1e-10,
827 performance_weight: 0.3,
828 ..Default::default()
829 },
830 ComputationType::ExpectationValue => AdaptivePrecisionConfig {
831 target_accuracy: 1e-10,
832 max_error_threshold: 1e-8,
833 performance_weight: 0.4,
834 ..Default::default()
835 },
836 ComputationType::Probability => AdaptivePrecisionConfig {
837 target_accuracy: 1e-8,
838 max_error_threshold: 1e-6,
839 performance_weight: 0.6,
840 ..Default::default()
841 },
842 ComputationType::Measurement => AdaptivePrecisionConfig {
843 target_accuracy: 1e-6,
844 max_error_threshold: 1e-4,
845 performance_weight: 0.7,
846 initial_precision: PrecisionMode::Single,
847 ..Default::default()
848 },
849 ComputationType::MatrixMultiplication => AdaptivePrecisionConfig {
850 target_accuracy: 1e-14,
851 max_error_threshold: 1e-12,
852 performance_weight: 0.2,
853 ..Default::default()
854 },
855 ComputationType::EigenvalueDecomposition => AdaptivePrecisionConfig {
856 target_accuracy: 1e-13,
857 max_error_threshold: 1e-11,
858 performance_weight: 0.1,
859 max_precision: PrecisionMode::Arbitrary(256),
860 ..Default::default()
861 },
862 ComputationType::TensorContraction => AdaptivePrecisionConfig {
863 target_accuracy: 1e-11,
864 max_error_threshold: 1e-9,
865 performance_weight: 0.5,
866 ..Default::default()
867 },
868 };
869 AdaptivePrecisionSimulator::new(config)
870 }
871}
872
873#[cfg(test)]
874mod tests {
875 use super::*;
876 use crate::{gate::single::Hadamard, qubit::QubitId};
877
878 #[test]
879 fn test_adaptive_precision_simulator_creation() {
880 let config = AdaptivePrecisionConfig::default();
881 let simulator = AdaptivePrecisionSimulator::new(config);
882
883 assert_eq!(simulator.current_precision(), PrecisionMode::Double);
884 assert_eq!(simulator.operation_count, 0);
885 }
886
887 #[test]
888 fn test_precision_factory() {
889 let high_acc = AdaptivePrecisionFactory::create_high_accuracy();
890 let perf_opt = AdaptivePrecisionFactory::create_performance_optimized();
891 let balanced = AdaptivePrecisionFactory::create_balanced();
892
893 assert_eq!(high_acc.current_precision(), PrecisionMode::Double);
894 assert_eq!(perf_opt.current_precision(), PrecisionMode::Single);
895 assert_eq!(balanced.current_precision(), PrecisionMode::Double);
896 }
897
898 #[test]
899 fn test_computation_type_specific_creation() {
900 let state_sim =
901 AdaptivePrecisionFactory::create_for_computation_type(ComputationType::StateEvolution);
902 let measurement_sim =
903 AdaptivePrecisionFactory::create_for_computation_type(ComputationType::Measurement);
904
905 assert_eq!(state_sim.current_precision(), PrecisionMode::Double);
906 assert_eq!(measurement_sim.current_precision(), PrecisionMode::Single);
907 }
908
909 #[test]
910 fn test_gate_application_with_adaptive_precision() {
911 let mut simulator = AdaptivePrecisionSimulator::new(AdaptivePrecisionConfig::default());
912 let hadamard = Hadamard { target: QubitId(0) };
913 let mut state = Array1::from_vec(vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]);
914
915 let result = simulator.apply_gate_adaptive(&hadamard, &mut state);
916 assert!(result.is_ok());
917
918 let adaptive_result = result.unwrap();
919 assert_eq!(adaptive_result.precision, PrecisionMode::Double);
920 assert!(adaptive_result.estimated_error > 0.0);
921 }
922
923 #[test]
924 fn test_expectation_value_adaptive() {
925 let mut simulator = AdaptivePrecisionSimulator::new(AdaptivePrecisionConfig::default());
926
927 let observable = Array2::from_shape_vec(
928 (2, 2),
929 vec![
930 Complex64::new(1.0, 0.0),
931 Complex64::new(0.0, 0.0),
932 Complex64::new(0.0, 0.0),
933 Complex64::new(-1.0, 0.0),
934 ],
935 )
936 .unwrap();
937
938 let state = Array1::from_vec(vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]);
939
940 let result = simulator.expectation_value_adaptive(&observable, &state);
941 assert!(result.is_ok());
942
943 let adaptive_result = result.unwrap();
944 assert_eq!(adaptive_result.value, Complex64::new(0.5, 0.0));
945 }
946
947 #[test]
948 fn test_precision_adaptation() {
949 let mut config = AdaptivePrecisionConfig::default();
950 config.adaptation_interval = 1; config.max_error_threshold = 1e-20; let mut simulator = AdaptivePrecisionSimulator::new(config);
954
955 let result = simulator.force_adaptation(ComputationType::StateEvolution);
957 assert!(result.is_ok());
958 }
959
960 #[test]
961 fn test_error_estimators() {
962 let richardson = RichardsonExtrapolationEstimator::new();
963 let comparison = DoublePrecisionComparisonEstimator::new();
964 let residual = ResidualBasedEstimator::new();
965
966 let result = AdaptiveResult {
967 value: Complex64::new(1.0, 0.0),
968 precision: PrecisionMode::Double,
969 estimated_error: 1e-15,
970 computation_time: Duration::from_millis(10),
971 memory_used: 1024,
972 };
973
974 assert!(richardson.is_applicable(ComputationType::StateEvolution));
975 assert!(comparison.is_applicable(ComputationType::ExpectationValue));
976 assert!(residual.is_applicable(ComputationType::MatrixMultiplication));
977
978 let error1 = richardson.estimate_error(&result, None);
979 let error2 = comparison.estimate_error(&result, None);
980 let error3 = residual.estimate_error(&result, None);
981
982 assert!(error1 > 0.0);
983 assert!(error2 > 0.0);
984 assert!(error3 > 0.0);
985 }
986
987 #[test]
988 fn test_precision_mode_transitions() {
989 let simulator = AdaptivePrecisionSimulator::new(AdaptivePrecisionConfig::default());
990
991 assert_eq!(
993 simulator.increase_precision(PrecisionMode::Single),
994 PrecisionMode::Double
995 );
996 assert_eq!(
997 simulator.increase_precision(PrecisionMode::Double),
998 PrecisionMode::Extended
999 );
1000 assert_eq!(
1001 simulator.increase_precision(PrecisionMode::Extended),
1002 PrecisionMode::Arbitrary(128)
1003 );
1004
1005 assert_eq!(
1007 simulator.decrease_precision(PrecisionMode::Extended),
1008 PrecisionMode::Double
1009 );
1010 assert_eq!(
1011 simulator.decrease_precision(PrecisionMode::Double),
1012 PrecisionMode::Single
1013 );
1014 assert_eq!(
1015 simulator.decrease_precision(PrecisionMode::Arbitrary(128)),
1016 PrecisionMode::Arbitrary(64)
1017 );
1018 }
1019
1020 #[test]
1021 fn test_precision_statistics() {
1022 let mut simulator = AdaptivePrecisionSimulator::new(AdaptivePrecisionConfig::default());
1023
1024 let hadamard = Hadamard { target: QubitId(0) };
1026 let mut state = Array1::from_vec(vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]);
1027
1028 let _ = simulator.apply_gate_adaptive(&hadamard, &mut state);
1029 let _ = simulator.apply_gate_adaptive(&hadamard, &mut state);
1030
1031 let stats = simulator.get_precision_stats();
1032 assert_eq!(stats.current_precision, PrecisionMode::Double);
1033 assert_eq!(stats.operations_count, 2);
1034 assert!(stats.performance_metrics.operations_per_second > 0.0);
1035 }
1036
1037 #[test]
1038 fn test_memory_estimation() {
1039 let simulator = AdaptivePrecisionSimulator::new(AdaptivePrecisionConfig::default());
1040
1041 let mem_state = simulator.estimate_memory_usage(ComputationType::StateEvolution);
1042 let mem_tensor = simulator.estimate_memory_usage(ComputationType::TensorContraction);
1043 let mem_measurement = simulator.estimate_memory_usage(ComputationType::Measurement);
1044
1045 assert!(mem_tensor > mem_state);
1047 assert!(mem_state > mem_measurement);
1049 }
1050
1051 #[test]
1052 fn test_performance_vs_accuracy_tradeoff() {
1053 let high_acc_config = AdaptivePrecisionConfig {
1054 performance_weight: 0.1, target_accuracy: 1e-15,
1056 ..Default::default()
1057 };
1058
1059 let perf_config = AdaptivePrecisionConfig {
1060 performance_weight: 0.9, target_accuracy: 1e-6,
1062 ..Default::default()
1063 };
1064
1065 let acc_sim = AdaptivePrecisionSimulator::new(high_acc_config);
1066 let perf_sim = AdaptivePrecisionSimulator::new(perf_config);
1067
1068 assert!(acc_sim.config.target_accuracy < perf_sim.config.target_accuracy);
1069 assert!(acc_sim.config.performance_weight < perf_sim.config.performance_weight);
1070 }
1071}