quantrs2_device/process_tomography/
mod.rs

1//! Comprehensive quantum process tomography module
2//!
3//! This module provides advanced quantum process tomography capabilities using SciRS2
4//! for statistical analysis, optimization, and machine learning.
5
6pub mod analysis;
7pub mod config;
8pub mod core;
9pub mod fallback;
10pub mod reconstruction;
11pub mod results;
12pub mod utils;
13pub mod validation;
14
15// Re-export main types and functions
16pub use analysis::*;
17pub use config::*;
18pub use core::{ProcessTomographyExecutor, SciRS2ProcessTomographer};
19pub use reconstruction::*;
20pub use results::*;
21pub use utils::*;
22pub use validation::*;
23
24// Conditional exports based on feature availability
25#[cfg(feature = "scirs2")]
26pub use fallback as scirs2_fallback;
27
28#[cfg(not(feature = "scirs2"))]
29pub use fallback::*;
30
31use scirs2_core::ndarray::{Array1, Array2, Array4};
32use scirs2_core::Complex64;
33// Import specific types to avoid naming conflicts
34use quantrs2_circuit::prelude::{
35    Circuit,
36    PerformanceAnalyzer,
37    PerformanceSnapshot,
38    PerformanceSummary,
39    ProfilerConfig as ProfilerConfiguration,
40    // Avoid importing AnomalyDetectionAlgorithm to prevent conflicts with local enum
41    ProfilingReport,
42    ProfilingSession,
43    QuantumProfiler,
44};
45use std::collections::HashMap;
46
47use crate::{calibration::CalibrationManager, DeviceResult};
48
49/// Create a new process tomographer with default configuration
50pub fn create_process_tomographer(
51    calibration_manager: CalibrationManager,
52) -> SciRS2ProcessTomographer {
53    let config = SciRS2ProcessTomographyConfig::default();
54    SciRS2ProcessTomographer::new(config, calibration_manager)
55}
56
57/// Create a process tomographer with custom configuration
58pub const fn create_process_tomographer_with_config(
59    config: SciRS2ProcessTomographyConfig,
60    calibration_manager: CalibrationManager,
61) -> SciRS2ProcessTomographer {
62    SciRS2ProcessTomographer::new(config, calibration_manager)
63}
64
65/// Perform quick process tomography with minimal configuration
66pub async fn quick_process_tomography<const N: usize, E: ProcessTomographyExecutor>(
67    process_circuit: &Circuit<N>,
68    executor: &E,
69    num_qubits: usize,
70) -> DeviceResult<ProcessMetrics> {
71    let calibration_manager = CalibrationManager::new();
72    let mut tomographer = create_process_tomographer(calibration_manager);
73
74    // Generate input states and measurements
75    tomographer.generate_input_states(num_qubits)?;
76    tomographer.generate_measurement_operators(num_qubits)?;
77
78    // Perform tomography
79    let result = tomographer
80        .perform_process_tomography("quick_tomography", process_circuit, executor)
81        .await?;
82
83    Ok(result.process_metrics)
84}
85
86/// Comprehensive process characterization with full analysis
87pub async fn comprehensive_process_characterization<
88    const N: usize,
89    E: ProcessTomographyExecutor,
90>(
91    device_id: &str,
92    process_circuit: &Circuit<N>,
93    executor: &E,
94    num_qubits: usize,
95    config: Option<SciRS2ProcessTomographyConfig>,
96) -> DeviceResult<SciRS2ProcessTomographyResult> {
97    let calibration_manager = CalibrationManager::new();
98    let config = config.unwrap_or_default();
99    let mut tomographer = SciRS2ProcessTomographer::new(config, calibration_manager);
100
101    // Generate input states and measurements
102    tomographer.generate_input_states(num_qubits)?;
103    tomographer.generate_measurement_operators(num_qubits)?;
104
105    // Perform comprehensive tomography
106    tomographer
107        .perform_process_tomography(device_id, process_circuit, executor)
108        .await
109}
110
111/// Create process monitoring system for continuous characterization
112pub const fn create_process_monitoring_system(
113    reference_metrics: ProcessMetrics,
114    anomaly_threshold: f64,
115    drift_sensitivity: f64,
116) -> (ProcessAnomalyDetector, ProcessDriftDetector) {
117    let anomaly_detector = ProcessAnomalyDetector::new(
118        anomaly_threshold,
119        AnomalyDetectionAlgorithm::StatisticalThreshold,
120    );
121
122    let drift_detector = ProcessDriftDetector::new(
123        reference_metrics,
124        drift_sensitivity,
125        DriftDetectionMethod::StatisticalTest,
126    );
127
128    (anomaly_detector, drift_detector)
129}
130
131/// Benchmark process against standard quantum channels
132pub async fn benchmark_process<const N: usize, E: ProcessTomographyExecutor>(
133    process_circuit: &Circuit<N>,
134    executor: &E,
135    num_qubits: usize,
136    benchmark_channels: &[String],
137) -> DeviceResult<HashMap<String, f64>> {
138    let calibration_manager = CalibrationManager::new();
139    let mut config = SciRS2ProcessTomographyConfig::default();
140    config.validation_config.enable_benchmarking = true;
141    config.validation_config.benchmark_processes = benchmark_channels.to_vec();
142
143    let mut tomographer = SciRS2ProcessTomographer::new(config, calibration_manager);
144
145    // Generate input states and measurements
146    tomographer.generate_input_states(num_qubits)?;
147    tomographer.generate_measurement_operators(num_qubits)?;
148
149    // Perform tomography
150    let result = tomographer
151        .perform_process_tomography("benchmark", process_circuit, executor)
152        .await?;
153
154    Ok(result.process_comparisons.standard_process_fidelities)
155}
156
157/// Compare two quantum processes
158pub fn compare_processes(
159    process1: &Array4<Complex64>,
160    process2: &Array4<Complex64>,
161) -> DeviceResult<ProcessComparisonResult> {
162    // Calculate various distance measures
163    let trace_distance = utils::process_utils::trace_distance(process1, process2)?;
164
165    // Calculate fidelity (simplified)
166    let mut fidelity = 0.0;
167    let mut norm1 = 0.0;
168    let mut norm2 = 0.0;
169
170    let dim = process1.dim();
171    for i in 0..dim.0 {
172        for j in 0..dim.1 {
173            for k in 0..dim.2 {
174                for l in 0..dim.3 {
175                    let element1 = process1[[i, j, k, l]];
176                    let element2 = process2[[i, j, k, l]];
177
178                    fidelity += (element1.conj() * element2).re;
179                    norm1 += element1.norm_sqr();
180                    norm2 += element2.norm_sqr();
181                }
182            }
183        }
184    }
185
186    let process_fidelity = if norm1 > 1e-12 && norm2 > 1e-12 {
187        fidelity / (norm1 * norm2).sqrt()
188    } else {
189        0.0
190    };
191
192    Ok(ProcessComparisonResult {
193        process_fidelity,
194        trace_distance,
195        diamond_norm_distance: 2.0 * (1.0 - process_fidelity).sqrt(),
196    })
197}
198
199/// Result of process comparison
200#[derive(Debug, Clone)]
201pub struct ProcessComparisonResult {
202    pub process_fidelity: f64,
203    pub trace_distance: f64,
204    pub diamond_norm_distance: f64,
205}
206
207/// Validate process tomography result
208pub fn validate_process_result(
209    result: &SciRS2ProcessTomographyResult,
210    tolerance: f64,
211) -> ProcessValidationReport {
212    let mut issues = Vec::new();
213    let mut warnings = Vec::new();
214
215    // Check physical validity
216    let physical_validity = &result
217        .statistical_analysis
218        .reconstruction_quality
219        .physical_validity;
220
221    if !physical_validity.is_completely_positive {
222        issues.push("Process is not completely positive".to_string());
223    }
224
225    if !physical_validity.is_trace_preserving {
226        issues.push("Process is not trace preserving".to_string());
227    }
228
229    if physical_validity.positivity_measure < 0.9 {
230        warnings.push(format!(
231            "Low positivity measure: {:.3}",
232            physical_validity.positivity_measure
233        ));
234    }
235
236    if physical_validity.trace_preservation_measure < 0.95 {
237        warnings.push(format!(
238            "Poor trace preservation: {:.3}",
239            physical_validity.trace_preservation_measure
240        ));
241    }
242
243    // Check process metrics
244    if result.process_metrics.process_fidelity < 0.5 {
245        warnings.push("Low process fidelity detected".to_string());
246    }
247
248    if result.process_metrics.unitarity < 0.1 {
249        warnings.push("Very low unitarity detected".to_string());
250    }
251
252    // Check reconstruction quality
253    if result
254        .statistical_analysis
255        .reconstruction_quality
256        .condition_number
257        > 1e10
258    {
259        warnings.push("High condition number indicates numerical instability".to_string());
260    }
261
262    let is_valid = issues.is_empty();
263    let quality_score = calculate_overall_quality_score(result);
264
265    ProcessValidationReport {
266        is_valid,
267        quality_score,
268        issues,
269        warnings,
270    }
271}
272
273/// Process validation report
274#[derive(Debug, Clone)]
275pub struct ProcessValidationReport {
276    pub is_valid: bool,
277    pub quality_score: f64,
278    pub issues: Vec<String>,
279    pub warnings: Vec<String>,
280}
281
282/// Calculate overall quality score for a process tomography result
283fn calculate_overall_quality_score(result: &SciRS2ProcessTomographyResult) -> f64 {
284    let physical_score = f64::midpoint(
285        result
286            .statistical_analysis
287            .reconstruction_quality
288            .physical_validity
289            .positivity_measure,
290        result
291            .statistical_analysis
292            .reconstruction_quality
293            .physical_validity
294            .trace_preservation_measure,
295    );
296
297    let fidelity_score = result.process_metrics.process_fidelity;
298    let unitarity_score = result.process_metrics.unitarity;
299
300    let numerical_score = 1.0
301        / (1.0
302            + result
303                .statistical_analysis
304                .reconstruction_quality
305                .condition_number
306                / 1e6);
307
308    // Weighted average
309    numerical_score
310        .mul_add(
311            0.2,
312            unitarity_score.mul_add(0.2, fidelity_score.mul_add(0.3, physical_score * 0.3)),
313        )
314        .clamp(0.0, 1.0)
315}
316
317/// Export process tomography results in various formats
318pub fn export_process_results(
319    result: &SciRS2ProcessTomographyResult,
320    format: ExportFormat,
321) -> DeviceResult<String> {
322    match format {
323        ExportFormat::Json => export_as_json(result),
324        ExportFormat::Csv => export_as_csv(result),
325        ExportFormat::Hdf5 => export_as_hdf5(result),
326        ExportFormat::Matlab => export_as_matlab(result),
327    }
328}
329
330/// Export formats
331#[derive(Debug, Clone)]
332pub enum ExportFormat {
333    Json,
334    Csv,
335    Hdf5,
336    Matlab,
337}
338
339fn export_as_json(result: &SciRS2ProcessTomographyResult) -> DeviceResult<String> {
340    // Simplified JSON export
341    let json_data = format!(
342        r#"{{
343    "device_id": "{}",
344    "process_fidelity": {:.6},
345    "average_gate_fidelity": {:.6},
346    "unitarity": {:.6},
347    "entangling_power": {:.6},
348    "reconstruction_method": "{:?}",
349    "log_likelihood": {:.6}
350}}"#,
351        result.device_id,
352        result.process_metrics.process_fidelity,
353        result.process_metrics.average_gate_fidelity,
354        result.process_metrics.unitarity,
355        result.process_metrics.entangling_power,
356        result.config.reconstruction_method,
357        result
358            .statistical_analysis
359            .reconstruction_quality
360            .log_likelihood
361    );
362
363    Ok(json_data)
364}
365
366fn export_as_csv(result: &SciRS2ProcessTomographyResult) -> DeviceResult<String> {
367    let csv_data = format!(
368        "device_id,process_fidelity,average_gate_fidelity,unitarity,entangling_power,log_likelihood\n{},{:.6},{:.6},{:.6},{:.6},{:.6}",
369        result.device_id,
370        result.process_metrics.process_fidelity,
371        result.process_metrics.average_gate_fidelity,
372        result.process_metrics.unitarity,
373        result.process_metrics.entangling_power,
374        result.statistical_analysis.reconstruction_quality.log_likelihood
375    );
376
377    Ok(csv_data)
378}
379
380fn export_as_hdf5(_result: &SciRS2ProcessTomographyResult) -> DeviceResult<String> {
381    // Placeholder for HDF5 export
382    Ok("HDF5 export not yet implemented".to_string())
383}
384
385fn export_as_matlab(_result: &SciRS2ProcessTomographyResult) -> DeviceResult<String> {
386    // Placeholder for MATLAB export
387    Ok("MATLAB export not yet implemented".to_string())
388}