quantrs2_sim/mixed_precision_impl/
mod.rs1pub mod analysis;
9pub mod config;
10pub mod simulator;
11pub mod state_vector;
12
13pub use analysis::{AnalysisSummary, PerformanceMetrics, PrecisionAnalysis, PrecisionAnalyzer};
15pub use config::{
16 AdaptiveStrategy, MixedPrecisionConfig, MixedPrecisionContext, PrecisionLevel, QuantumPrecision,
17};
18pub use simulator::{MixedPrecisionSimulator, MixedPrecisionStats};
19pub use state_vector::MixedPrecisionStateVector;
20
21use crate::error::Result;
22
23#[allow(clippy::missing_const_for_fn)] pub fn initialize() -> Result<()> {
26 #[cfg(feature = "advanced_math")]
28 {
29 let _context = MixedPrecisionContext::new(AdaptiveStrategy::ErrorBased(1e-6));
31 let _ = _context; }
33
34 Ok(())
35}
36
37#[must_use]
39pub const fn is_available() -> bool {
40 cfg!(feature = "advanced_math")
41}
42
43#[must_use]
45pub fn get_supported_precisions() -> Vec<QuantumPrecision> {
46 vec![
47 QuantumPrecision::Half,
48 QuantumPrecision::Single,
49 QuantumPrecision::Double,
50 QuantumPrecision::Adaptive,
51 ]
52}
53
54#[must_use]
56pub const fn default_accuracy_config() -> MixedPrecisionConfig {
57 MixedPrecisionConfig::for_accuracy()
58}
59
60#[must_use]
62pub const fn default_performance_config() -> MixedPrecisionConfig {
63 MixedPrecisionConfig::for_performance()
64}
65
66#[must_use]
68pub fn default_balanced_config() -> MixedPrecisionConfig {
69 MixedPrecisionConfig::balanced()
70}
71
72pub fn validate_config(config: &MixedPrecisionConfig) -> Result<()> {
74 config.validate()
75}
76
77#[must_use]
79pub fn estimate_memory_usage(config: &MixedPrecisionConfig, num_qubits: usize) -> usize {
80 config.estimate_memory_usage(num_qubits)
81}
82
83#[must_use]
85pub fn calculate_memory_savings(config: &MixedPrecisionConfig, num_qubits: usize) -> f64 {
86 simulator::utils::memory_savings(config, num_qubits)
87}
88
89#[must_use]
91pub fn get_performance_factor(precision: QuantumPrecision) -> f64 {
92 simulator::utils::performance_improvement_factor(precision)
93}
94
95pub fn benchmark_precisions() -> Result<analysis::PrecisionAnalysis> {
97 let mut analyzer = PrecisionAnalyzer::new();
98 Ok(analyzer.analyze_for_tolerance(1e-6))
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use scirs2_core::ndarray::Array1;
105 use scirs2_core::Complex64;
106
107 #[test]
108 fn test_precision_initialization() {
109 let result = initialize();
110 assert!(result.is_ok());
111 }
112
113 #[test]
114 fn test_supported_precisions() {
115 let precisions = get_supported_precisions();
116 assert_eq!(precisions.len(), 4);
117 assert!(precisions.contains(&QuantumPrecision::Half));
118 assert!(precisions.contains(&QuantumPrecision::Single));
119 assert!(precisions.contains(&QuantumPrecision::Double));
120 assert!(precisions.contains(&QuantumPrecision::Adaptive));
121 }
122
123 #[test]
124 fn test_config_creation() {
125 let accuracy_config = default_accuracy_config();
126 assert_eq!(
127 accuracy_config.state_vector_precision,
128 QuantumPrecision::Double
129 );
130
131 let performance_config = default_performance_config();
132 assert_eq!(
133 performance_config.state_vector_precision,
134 QuantumPrecision::Half
135 );
136
137 let balanced_config = default_balanced_config();
138 assert_eq!(
139 balanced_config.state_vector_precision,
140 QuantumPrecision::Single
141 );
142 }
143
144 #[test]
145 fn test_config_validation() {
146 let config = MixedPrecisionConfig::default();
147 assert!(validate_config(&config).is_ok());
148
149 let mut invalid_config = config;
150 invalid_config.error_tolerance = -1.0;
151 assert!(validate_config(&invalid_config).is_err());
152 }
153
154 #[test]
155 fn test_memory_estimation() {
156 let config = MixedPrecisionConfig::default();
157 let memory_4q = estimate_memory_usage(&config, 4);
158 let memory_8q = estimate_memory_usage(&config, 8);
159
160 assert!(memory_8q > memory_4q * 10);
162 }
163
164 #[test]
165 fn test_precision_properties() {
166 assert_eq!(QuantumPrecision::Half.memory_factor(), 0.25);
167 assert_eq!(QuantumPrecision::Single.memory_factor(), 0.5);
168 assert_eq!(QuantumPrecision::Double.memory_factor(), 1.0);
169
170 assert!(QuantumPrecision::Half.typical_error() > QuantumPrecision::Single.typical_error());
171 assert!(
172 QuantumPrecision::Single.typical_error() > QuantumPrecision::Double.typical_error()
173 );
174 }
175
176 #[test]
177 fn test_precision_transitions() {
178 assert_eq!(
179 QuantumPrecision::Half.higher_precision(),
180 Some(QuantumPrecision::Single)
181 );
182 assert_eq!(
183 QuantumPrecision::Single.higher_precision(),
184 Some(QuantumPrecision::Double)
185 );
186 assert_eq!(QuantumPrecision::Double.higher_precision(), None);
187
188 assert_eq!(
189 QuantumPrecision::Double.lower_precision(),
190 Some(QuantumPrecision::Single)
191 );
192 assert_eq!(
193 QuantumPrecision::Single.lower_precision(),
194 Some(QuantumPrecision::Half)
195 );
196 assert_eq!(QuantumPrecision::Half.lower_precision(), None);
197 }
198
199 #[test]
200 fn test_state_vector_creation() {
201 let state = MixedPrecisionStateVector::new(4, QuantumPrecision::Single);
202 assert_eq!(state.len(), 4);
203 assert_eq!(state.precision(), QuantumPrecision::Single);
204
205 let basis_state =
206 MixedPrecisionStateVector::computational_basis(2, QuantumPrecision::Double);
207 assert_eq!(basis_state.len(), 4);
208 assert_eq!(basis_state.precision(), QuantumPrecision::Double);
209 }
210
211 #[test]
212 fn test_state_vector_operations() {
213 let mut state = MixedPrecisionStateVector::new(4, QuantumPrecision::Single);
214
215 let amplitude = Complex64::new(0.5, 0.3);
217 assert!(state.set_amplitude(0, amplitude).is_ok());
218
219 let retrieved_amplitude = state
221 .amplitude(0)
222 .expect("should retrieve amplitude at index 0");
223 assert!((retrieved_amplitude.re - amplitude.re).abs() < 1e-6);
224 assert!((retrieved_amplitude.im - amplitude.im).abs() < 1e-6);
225
226 let prob = state
228 .probability(0)
229 .expect("should calculate probability at index 0");
230 assert!((prob - amplitude.norm_sqr()).abs() < 1e-6);
231 }
232
233 #[test]
234 fn test_precision_conversion() {
235 let state_single = MixedPrecisionStateVector::new(4, QuantumPrecision::Single);
236 let state_double = state_single.to_precision(QuantumPrecision::Double);
237
238 assert!(state_double.is_ok());
239 let converted = state_double.expect("precision conversion should succeed");
240 assert_eq!(converted.precision(), QuantumPrecision::Double);
241 assert_eq!(converted.len(), 4);
242 }
243
244 #[test]
245 fn test_simulator_creation() {
246 let config = MixedPrecisionConfig::default();
247 let simulator = MixedPrecisionSimulator::new(2, config);
248
249 assert!(simulator.is_ok());
250 let sim = simulator.expect("mixed precision simulator creation should succeed");
251 assert!(sim.get_state().is_some());
252 }
253
254 #[test]
255 fn test_performance_metrics() {
256 let metrics = PerformanceMetrics::new(100.0, 1024, 10.0, 5.0);
257 assert_eq!(metrics.execution_time_ms, 100.0);
258 assert_eq!(metrics.memory_usage_bytes, 1024);
259 assert_eq!(metrics.throughput_ops_per_sec, 10.0);
260 assert_eq!(metrics.energy_efficiency, 5.0);
261
262 let score = metrics.performance_score();
263 assert!((0.0..=1.0).contains(&score));
264 }
265
266 #[test]
267 fn test_precision_analysis() {
268 let mut analysis = PrecisionAnalysis::new();
269 analysis.add_recommendation("test_op".to_string(), QuantumPrecision::Single);
270 analysis.add_error_estimate(QuantumPrecision::Single, 1e-6);
271
272 let metrics = PerformanceMetrics::new(50.0, 512, 20.0, 10.0);
273 analysis.add_performance_metrics(QuantumPrecision::Single, metrics);
274
275 analysis.calculate_quality_score();
276
277 assert_eq!(
278 analysis.get_best_precision("test_op"),
279 Some(QuantumPrecision::Single)
280 );
281 assert!(analysis.quality_score > 0.0);
282 }
283
284 #[test]
285 fn test_analyzer() {
286 let mut analyzer = PrecisionAnalyzer::new();
287 let result = analyzer.analyze_for_tolerance(1e-6);
288 assert!(!result.error_estimates.is_empty());
289 assert!(!result.performance_metrics.is_empty());
290 }
291}