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::BFloat16,
49 QuantumPrecision::TF32,
50 QuantumPrecision::Single,
51 QuantumPrecision::Double,
52 QuantumPrecision::Adaptive,
53 ]
54}
55
56#[must_use]
58pub const fn default_accuracy_config() -> MixedPrecisionConfig {
59 MixedPrecisionConfig::for_accuracy()
60}
61
62#[must_use]
64pub const fn default_performance_config() -> MixedPrecisionConfig {
65 MixedPrecisionConfig::for_performance()
66}
67
68#[must_use]
70pub fn default_balanced_config() -> MixedPrecisionConfig {
71 MixedPrecisionConfig::balanced()
72}
73
74pub fn validate_config(config: &MixedPrecisionConfig) -> Result<()> {
76 config.validate()
77}
78
79#[must_use]
81pub fn estimate_memory_usage(config: &MixedPrecisionConfig, num_qubits: usize) -> usize {
82 config.estimate_memory_usage(num_qubits)
83}
84
85#[must_use]
87pub fn calculate_memory_savings(config: &MixedPrecisionConfig, num_qubits: usize) -> f64 {
88 simulator::utils::memory_savings(config, num_qubits)
89}
90
91#[must_use]
93pub fn get_performance_factor(precision: QuantumPrecision) -> f64 {
94 simulator::utils::performance_improvement_factor(precision)
95}
96
97pub fn benchmark_precisions() -> Result<analysis::PrecisionAnalysis> {
99 let mut analyzer = PrecisionAnalyzer::new();
100 Ok(analyzer.analyze_for_tolerance(1e-6))
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use scirs2_core::ndarray::Array1;
107 use scirs2_core::Complex64;
108
109 #[test]
110 fn test_precision_initialization() {
111 let result = initialize();
112 assert!(result.is_ok());
113 }
114
115 #[test]
116 fn test_supported_precisions() {
117 let precisions = get_supported_precisions();
118 assert_eq!(precisions.len(), 6);
119 assert!(precisions.contains(&QuantumPrecision::Half));
120 assert!(precisions.contains(&QuantumPrecision::BFloat16));
121 assert!(precisions.contains(&QuantumPrecision::TF32));
122 assert!(precisions.contains(&QuantumPrecision::Single));
123 assert!(precisions.contains(&QuantumPrecision::Double));
124 assert!(precisions.contains(&QuantumPrecision::Adaptive));
125 }
126
127 #[test]
128 fn test_config_creation() {
129 let accuracy_config = default_accuracy_config();
130 assert_eq!(
131 accuracy_config.state_vector_precision,
132 QuantumPrecision::Double
133 );
134
135 let performance_config = default_performance_config();
136 assert_eq!(
137 performance_config.state_vector_precision,
138 QuantumPrecision::Half
139 );
140
141 let balanced_config = default_balanced_config();
142 assert_eq!(
143 balanced_config.state_vector_precision,
144 QuantumPrecision::Single
145 );
146 }
147
148 #[test]
149 fn test_config_validation() {
150 let config = MixedPrecisionConfig::default();
151 assert!(validate_config(&config).is_ok());
152
153 let mut invalid_config = config;
154 invalid_config.error_tolerance = -1.0;
155 assert!(validate_config(&invalid_config).is_err());
156 }
157
158 #[test]
159 fn test_memory_estimation() {
160 let config = MixedPrecisionConfig::default();
161 let memory_4q = estimate_memory_usage(&config, 4);
162 let memory_8q = estimate_memory_usage(&config, 8);
163
164 assert!(memory_8q > memory_4q * 10);
166 }
167
168 #[test]
169 fn test_precision_properties() {
170 assert_eq!(QuantumPrecision::Half.memory_factor(), 0.25);
171 assert_eq!(QuantumPrecision::Single.memory_factor(), 0.5);
172 assert_eq!(QuantumPrecision::Double.memory_factor(), 1.0);
173
174 assert!(QuantumPrecision::Half.typical_error() > QuantumPrecision::Single.typical_error());
175 assert!(
176 QuantumPrecision::Single.typical_error() > QuantumPrecision::Double.typical_error()
177 );
178 }
179
180 #[test]
181 fn test_precision_transitions() {
182 assert_eq!(
184 QuantumPrecision::Half.higher_precision(),
185 Some(QuantumPrecision::BFloat16)
186 );
187 assert_eq!(
188 QuantumPrecision::BFloat16.higher_precision(),
189 Some(QuantumPrecision::TF32)
190 );
191 assert_eq!(
192 QuantumPrecision::TF32.higher_precision(),
193 Some(QuantumPrecision::Single)
194 );
195 assert_eq!(
196 QuantumPrecision::Single.higher_precision(),
197 Some(QuantumPrecision::Double)
198 );
199 assert_eq!(QuantumPrecision::Double.higher_precision(), None);
200
201 assert_eq!(
203 QuantumPrecision::Double.lower_precision(),
204 Some(QuantumPrecision::Single)
205 );
206 assert_eq!(
207 QuantumPrecision::Single.lower_precision(),
208 Some(QuantumPrecision::TF32)
209 );
210 assert_eq!(
211 QuantumPrecision::TF32.lower_precision(),
212 Some(QuantumPrecision::BFloat16)
213 );
214 assert_eq!(
215 QuantumPrecision::BFloat16.lower_precision(),
216 Some(QuantumPrecision::Half)
217 );
218 assert_eq!(QuantumPrecision::Half.lower_precision(), None);
219 }
220
221 #[test]
222 fn test_tensor_core_precisions() {
223 assert!(QuantumPrecision::TF32.requires_tensor_cores());
225 assert!(QuantumPrecision::BFloat16.requires_tensor_cores());
226 assert!(!QuantumPrecision::Half.requires_tensor_cores());
227 assert!(!QuantumPrecision::Single.requires_tensor_cores());
228 assert!(!QuantumPrecision::Double.requires_tensor_cores());
229
230 assert!(QuantumPrecision::TF32.is_reduced_precision());
232 assert!(QuantumPrecision::BFloat16.is_reduced_precision());
233 assert!(QuantumPrecision::Half.is_reduced_precision());
234 assert!(!QuantumPrecision::Single.is_reduced_precision());
235 assert!(!QuantumPrecision::Double.is_reduced_precision());
236 }
237
238 #[test]
239 fn test_state_vector_creation() {
240 let state = MixedPrecisionStateVector::new(4, QuantumPrecision::Single);
241 assert_eq!(state.len(), 4);
242 assert_eq!(state.precision(), QuantumPrecision::Single);
243
244 let basis_state =
245 MixedPrecisionStateVector::computational_basis(2, QuantumPrecision::Double);
246 assert_eq!(basis_state.len(), 4);
247 assert_eq!(basis_state.precision(), QuantumPrecision::Double);
248 }
249
250 #[test]
251 fn test_state_vector_operations() {
252 let mut state = MixedPrecisionStateVector::new(4, QuantumPrecision::Single);
253
254 let amplitude = Complex64::new(0.5, 0.3);
256 assert!(state.set_amplitude(0, amplitude).is_ok());
257
258 let retrieved_amplitude = state
260 .amplitude(0)
261 .expect("should retrieve amplitude at index 0");
262 assert!((retrieved_amplitude.re - amplitude.re).abs() < 1e-6);
263 assert!((retrieved_amplitude.im - amplitude.im).abs() < 1e-6);
264
265 let prob = state
267 .probability(0)
268 .expect("should calculate probability at index 0");
269 assert!((prob - amplitude.norm_sqr()).abs() < 1e-6);
270 }
271
272 #[test]
273 fn test_precision_conversion() {
274 let state_single = MixedPrecisionStateVector::new(4, QuantumPrecision::Single);
275 let state_double = state_single.to_precision(QuantumPrecision::Double);
276
277 assert!(state_double.is_ok());
278 let converted = state_double.expect("precision conversion should succeed");
279 assert_eq!(converted.precision(), QuantumPrecision::Double);
280 assert_eq!(converted.len(), 4);
281 }
282
283 #[test]
284 fn test_simulator_creation() {
285 let config = MixedPrecisionConfig::default();
286 let simulator = MixedPrecisionSimulator::new(2, config);
287
288 assert!(simulator.is_ok());
289 let sim = simulator.expect("mixed precision simulator creation should succeed");
290 assert!(sim.get_state().is_some());
291 }
292
293 #[test]
294 fn test_performance_metrics() {
295 let metrics = PerformanceMetrics::new(100.0, 1024, 10.0, 5.0);
296 assert_eq!(metrics.execution_time_ms, 100.0);
297 assert_eq!(metrics.memory_usage_bytes, 1024);
298 assert_eq!(metrics.throughput_ops_per_sec, 10.0);
299 assert_eq!(metrics.energy_efficiency, 5.0);
300
301 let score = metrics.performance_score();
302 assert!((0.0..=1.0).contains(&score));
303 }
304
305 #[test]
306 fn test_precision_analysis() {
307 let mut analysis = PrecisionAnalysis::new();
308 analysis.add_recommendation("test_op".to_string(), QuantumPrecision::Single);
309 analysis.add_error_estimate(QuantumPrecision::Single, 1e-6);
310
311 let metrics = PerformanceMetrics::new(50.0, 512, 20.0, 10.0);
312 analysis.add_performance_metrics(QuantumPrecision::Single, metrics);
313
314 analysis.calculate_quality_score();
315
316 assert_eq!(
317 analysis.get_best_precision("test_op"),
318 Some(QuantumPrecision::Single)
319 );
320 assert!(analysis.quality_score > 0.0);
321 }
322
323 #[test]
324 fn test_analyzer() {
325 let mut analyzer = PrecisionAnalyzer::new();
326 let result = analyzer.analyze_for_tolerance(1e-6);
327 assert!(!result.error_estimates.is_empty());
328 assert!(!result.performance_metrics.is_empty());
329 }
330}