quantrs2_device/process_tomography/reconstruction/
mod.rs1pub mod bayesian;
4pub mod compressed_sensing;
5pub mod ensemble;
6pub mod linear_inversion;
7pub mod machine_learning;
8pub mod maximum_likelihood;
9
10use scirs2_core::ndarray::{Array1, Array2, Array4};
11use scirs2_core::Complex64;
12
13use super::core::SciRS2ProcessTomographer;
14use super::results::{ExperimentalData, PhysicalValidityMetrics, ReconstructionQuality};
15use crate::DeviceResult;
16
17pub use bayesian::*;
18pub use compressed_sensing::*;
19pub use ensemble::*;
20pub use linear_inversion::*;
21pub use machine_learning::*;
22pub use maximum_likelihood::*;
23
24impl SciRS2ProcessTomographer {
26 pub fn linear_inversion_reconstruction(
28 &self,
29 experimental_data: &ExperimentalData,
30 ) -> DeviceResult<(Array4<Complex64>, ReconstructionQuality)> {
31 linear_inversion::reconstruct_linear_inversion(self, experimental_data)
32 }
33
34 pub fn maximum_likelihood_reconstruction(
36 &self,
37 experimental_data: &ExperimentalData,
38 ) -> DeviceResult<(Array4<Complex64>, ReconstructionQuality)> {
39 maximum_likelihood::reconstruct_maximum_likelihood(self, experimental_data)
40 }
41
42 pub fn compressed_sensing_reconstruction(
44 &self,
45 experimental_data: &ExperimentalData,
46 ) -> DeviceResult<(Array4<Complex64>, ReconstructionQuality)> {
47 compressed_sensing::reconstruct_compressed_sensing(self, experimental_data)
48 }
49
50 pub fn bayesian_reconstruction(
52 &self,
53 experimental_data: &ExperimentalData,
54 ) -> DeviceResult<(Array4<Complex64>, ReconstructionQuality)> {
55 bayesian::reconstruct_bayesian(self, experimental_data)
56 }
57
58 pub fn ensemble_reconstruction(
60 &self,
61 experimental_data: &ExperimentalData,
62 ) -> DeviceResult<(Array4<Complex64>, ReconstructionQuality)> {
63 ensemble::reconstruct_ensemble(self, experimental_data)
64 }
65
66 pub fn ml_reconstruction(
68 &self,
69 experimental_data: &ExperimentalData,
70 ) -> DeviceResult<(Array4<Complex64>, ReconstructionQuality)> {
71 machine_learning::reconstruct_machine_learning(self, experimental_data)
72 }
73
74 pub fn build_measurement_matrix(
76 &self,
77 experimental_data: &ExperimentalData,
78 ) -> DeviceResult<Array2<f64>> {
79 let num_measurements = experimental_data.measurement_results.len();
80 let num_qubits = (experimental_data.input_states[0].dim().0 as f64).log2() as usize;
81 let process_dim = (1_usize << num_qubits).pow(2); let mut measurement_matrix = Array2::zeros((num_measurements, process_dim));
84
85 for (m_idx, (&result, &uncertainty)) in experimental_data
86 .measurement_results
87 .iter()
88 .zip(experimental_data.measurement_uncertainties.iter())
89 .enumerate()
90 {
91 let input_idx = m_idx / experimental_data.measurement_operators.len();
92 let meas_idx = m_idx % experimental_data.measurement_operators.len();
93
94 if input_idx < experimental_data.input_states.len()
95 && meas_idx < experimental_data.measurement_operators.len()
96 {
97 let input_state = &experimental_data.input_states[input_idx];
98 let measurement = &experimental_data.measurement_operators[meas_idx];
99
100 for i in 0..(1 << num_qubits) {
102 for j in 0..(1 << num_qubits) {
103 for k in 0..(1 << num_qubits) {
104 for l in 0..(1 << num_qubits) {
105 let process_idx = i * (1_usize << num_qubits).pow(3)
106 + j * (1_usize << num_qubits).pow(2)
107 + k * (1_usize << num_qubits)
108 + l;
109
110 if process_idx < process_dim {
111 let coefficient = self.compute_process_coefficient(
112 input_state,
113 measurement,
114 i,
115 j,
116 k,
117 l,
118 )?;
119 measurement_matrix[[m_idx, process_idx]] = coefficient;
120 }
121 }
122 }
123 }
124 }
125 }
126 }
127
128 Ok(measurement_matrix)
129 }
130}
131
132pub mod utils {
134 use super::*;
135 use crate::DeviceResult;
136
137 pub fn check_physical_validity(process_matrix: &Array4<Complex64>) -> PhysicalValidityMetrics {
139 let dim = process_matrix.dim().0;
140
141 let mut is_cp = true;
143 let mut positivity_measure = 1.0;
144
145 let mut trace_sum = 0.0;
147 for i in 0..dim {
148 for j in 0..dim {
149 trace_sum += process_matrix[[i, j, i, j]].re;
150 }
151 }
152 let is_tp = (trace_sum - 1.0).abs() < 1e-6;
153 let tp_measure = 1.0 - (trace_sum - 1.0).abs();
154
155 PhysicalValidityMetrics {
156 is_completely_positive: is_cp,
157 is_trace_preserving: is_tp,
158 positivity_measure,
159 trace_preservation_measure: tp_measure.max(0.0),
160 }
161 }
162
163 pub fn calculate_reconstruction_quality(
165 process_matrix: &Array4<Complex64>,
166 experimental_data: &ExperimentalData,
167 log_likelihood: f64,
168 ) -> ReconstructionQuality {
169 let physical_validity = check_physical_validity(process_matrix);
170
171 let condition_number = 10.0; ReconstructionQuality {
175 log_likelihood,
176 physical_validity,
177 condition_number,
178 }
179 }
180}