1use scirs2_core::ndarray::{Array1, Array2};
7use std::collections::HashMap;
8
9use super::config::HardwareArchitecture;
10use crate::circuit_interfaces::{InterfaceCircuit, InterfaceGateType};
11
12#[derive(Debug, Clone)]
14pub struct ParameterizedQuantumCircuit {
15 pub circuit: InterfaceCircuit,
17 pub parameters: Array1<f64>,
19 pub parameter_names: Vec<String>,
21 pub gate_parameter_map: HashMap<usize, Vec<usize>>,
23 pub hardware_optimizations: HardwareOptimizations,
25}
26
27#[derive(Debug, Clone)]
29pub struct HardwareOptimizations {
30 pub connectivity_graph: Array2<bool>,
32 pub gate_fidelities: HashMap<String, f64>,
34 pub decoherence_times: Array1<f64>,
36 pub gate_times: HashMap<String, f64>,
38 pub crosstalk_matrix: Array2<f64>,
40}
41
42impl ParameterizedQuantumCircuit {
43 pub fn new(
45 circuit: InterfaceCircuit,
46 parameters: Array1<f64>,
47 parameter_names: Vec<String>,
48 hardware_architecture: HardwareArchitecture,
49 ) -> Self {
50 let num_qubits = circuit.num_qubits;
51 let hardware_optimizations =
52 HardwareOptimizations::for_hardware(hardware_architecture, num_qubits);
53
54 Self {
55 circuit,
56 parameters,
57 parameter_names,
58 gate_parameter_map: HashMap::new(),
59 hardware_optimizations,
60 }
61 }
62
63 pub fn update_parameters(&mut self, new_parameters: Array1<f64>) -> Result<(), String> {
65 if new_parameters.len() != self.parameters.len() {
66 return Err(format!(
67 "Parameter count mismatch: expected {}, got {}",
68 self.parameters.len(),
69 new_parameters.len()
70 ));
71 }
72 self.parameters = new_parameters;
73 Ok(())
74 }
75
76 pub fn get_parameter(&self, index: usize) -> Option<f64> {
78 self.parameters.get(index).copied()
79 }
80
81 pub fn set_parameter(&mut self, index: usize, value: f64) -> Result<(), String> {
83 if index >= self.parameters.len() {
84 return Err(format!("Parameter index {} out of bounds", index));
85 }
86 self.parameters[index] = value;
87 Ok(())
88 }
89
90 pub fn num_parameters(&self) -> usize {
92 self.parameters.len()
93 }
94
95 pub fn num_qubits(&self) -> usize {
97 self.circuit.num_qubits
98 }
99
100 pub fn depth(&self) -> usize {
102 self.circuit.gates.len()
103 }
104
105 pub fn add_parameter_mapping(&mut self, gate_index: usize, parameter_indices: Vec<usize>) {
107 self.gate_parameter_map
108 .insert(gate_index, parameter_indices);
109 }
110
111 pub fn get_parameter_mapping(&self, gate_index: usize) -> Option<&Vec<usize>> {
113 self.gate_parameter_map.get(&gate_index)
114 }
115
116 pub fn estimate_fidelity(&self) -> f64 {
118 let mut total_fidelity = 1.0;
119
120 for gate in &self.circuit.gates {
121 let gate_name = Self::gate_type_to_string(&gate.gate_type);
122 if let Some(&fidelity) = self.hardware_optimizations.gate_fidelities.get(&gate_name) {
123 total_fidelity *= fidelity;
124 } else {
125 total_fidelity *= 0.99;
127 }
128 }
129
130 total_fidelity
131 }
132
133 pub fn estimate_execution_time(&self) -> f64 {
135 let mut total_time = 0.0;
136
137 for gate in &self.circuit.gates {
138 let gate_name = Self::gate_type_to_string(&gate.gate_type);
139 if let Some(&time) = self.hardware_optimizations.gate_times.get(&gate_name) {
140 total_time += time;
141 } else {
142 total_time += 1e-6;
144 }
145 }
146
147 total_time
148 }
149
150 pub fn are_qubits_connected(&self, qubit1: usize, qubit2: usize) -> bool {
152 if qubit1 >= self.num_qubits() || qubit2 >= self.num_qubits() {
153 return false;
154 }
155 self.hardware_optimizations.connectivity_graph[[qubit1, qubit2]]
156 }
157
158 pub fn get_decoherence_time(&self, qubit: usize) -> Option<f64> {
160 self.hardware_optimizations
161 .decoherence_times
162 .get(qubit)
163 .copied()
164 }
165
166 pub fn with_parameters(&self, parameters: Array1<f64>) -> Result<Self, String> {
168 let mut new_circuit = self.clone();
169 new_circuit.update_parameters(parameters)?;
170 Ok(new_circuit)
171 }
172
173 fn gate_type_to_string(gate_type: &InterfaceGateType) -> String {
175 match gate_type {
176 InterfaceGateType::Identity => "I".to_string(),
177 InterfaceGateType::PauliX | InterfaceGateType::X => "X".to_string(),
178 InterfaceGateType::PauliY => "Y".to_string(),
179 InterfaceGateType::PauliZ => "Z".to_string(),
180 InterfaceGateType::Hadamard | InterfaceGateType::H => "H".to_string(),
181 InterfaceGateType::S => "S".to_string(),
182 InterfaceGateType::T => "T".to_string(),
183 InterfaceGateType::Phase(_) => "Phase".to_string(),
184 InterfaceGateType::RX(_) => "RX".to_string(),
185 InterfaceGateType::RY(_) => "RY".to_string(),
186 InterfaceGateType::RZ(_) => "RZ".to_string(),
187 InterfaceGateType::U1(_) => "U1".to_string(),
188 InterfaceGateType::U2(_, _) => "U2".to_string(),
189 InterfaceGateType::U3(_, _, _) => "U3".to_string(),
190 InterfaceGateType::CNOT => "CNOT".to_string(),
191 InterfaceGateType::CZ => "CZ".to_string(),
192 InterfaceGateType::CY => "CY".to_string(),
193 InterfaceGateType::SWAP => "SWAP".to_string(),
194 InterfaceGateType::ISwap => "ISwap".to_string(),
195 InterfaceGateType::CRX(_) => "CRX".to_string(),
196 InterfaceGateType::CRY(_) => "CRY".to_string(),
197 InterfaceGateType::CRZ(_) => "CRZ".to_string(),
198 InterfaceGateType::CPhase(_) => "CPhase".to_string(),
199 InterfaceGateType::Toffoli => "Toffoli".to_string(),
200 InterfaceGateType::Fredkin => "Fredkin".to_string(),
201 InterfaceGateType::MultiControlledX(_) => "MCX".to_string(),
202 InterfaceGateType::MultiControlledZ(_) => "MCZ".to_string(),
203 InterfaceGateType::Custom(name, _) => name.clone(),
204 InterfaceGateType::Measure => "Measure".to_string(),
205 InterfaceGateType::Reset => "Reset".to_string(),
206 }
207 }
208}
209
210impl HardwareOptimizations {
211 pub fn for_hardware(architecture: HardwareArchitecture, num_qubits: usize) -> Self {
213 let connectivity_graph = match architecture {
214 HardwareArchitecture::Superconducting => {
215 let mut graph = Array2::from_elem((num_qubits, num_qubits), false);
217 for i in 0..num_qubits.saturating_sub(1) {
218 graph[[i, i + 1]] = true;
219 graph[[i + 1, i]] = true;
220 }
221 graph
222 }
223 HardwareArchitecture::TrappedIon => {
224 Array2::from_elem((num_qubits, num_qubits), true)
226 }
227 HardwareArchitecture::Photonic => {
228 let mut graph = Array2::from_elem((num_qubits, num_qubits), false);
230 for i in 0..num_qubits {
231 for j in 0..num_qubits {
232 if (i as i32 - j as i32).abs() <= 2 {
233 graph[[i, j]] = true;
234 }
235 }
236 }
237 graph
238 }
239 _ => Array2::from_elem((num_qubits, num_qubits), true),
240 };
241
242 let gate_fidelities = match architecture {
243 HardwareArchitecture::Superconducting => {
244 let mut fidelities = HashMap::new();
245 fidelities.insert("X".to_string(), 0.999);
246 fidelities.insert("Y".to_string(), 0.999);
247 fidelities.insert("Z".to_string(), 0.9999);
248 fidelities.insert("H".to_string(), 0.998);
249 fidelities.insert("CNOT".to_string(), 0.995);
250 fidelities.insert("CZ".to_string(), 0.996);
251 fidelities
252 }
253 HardwareArchitecture::TrappedIon => {
254 let mut fidelities = HashMap::new();
255 fidelities.insert("X".to_string(), 0.9999);
256 fidelities.insert("Y".to_string(), 0.9999);
257 fidelities.insert("Z".to_string(), 0.99999);
258 fidelities.insert("H".to_string(), 0.9999);
259 fidelities.insert("CNOT".to_string(), 0.999);
260 fidelities.insert("CZ".to_string(), 0.999);
261 fidelities
262 }
263 _ => {
264 let mut fidelities = HashMap::new();
265 fidelities.insert("X".to_string(), 0.99);
266 fidelities.insert("Y".to_string(), 0.99);
267 fidelities.insert("Z".to_string(), 0.999);
268 fidelities.insert("H".to_string(), 0.99);
269 fidelities.insert("CNOT".to_string(), 0.98);
270 fidelities.insert("CZ".to_string(), 0.98);
271 fidelities
272 }
273 };
274
275 let decoherence_times = match architecture {
276 HardwareArchitecture::Superconducting => {
277 Array1::from_vec(vec![50e-6; num_qubits]) }
279 HardwareArchitecture::TrappedIon => {
280 Array1::from_vec(vec![100e-3; num_qubits]) }
282 _ => Array1::from_vec(vec![10e-6; num_qubits]),
283 };
284
285 let gate_times = match architecture {
286 HardwareArchitecture::Superconducting => {
287 let mut times = HashMap::new();
288 times.insert("X".to_string(), 20e-9);
289 times.insert("Y".to_string(), 20e-9);
290 times.insert("Z".to_string(), 0.0);
291 times.insert("H".to_string(), 20e-9);
292 times.insert("CNOT".to_string(), 40e-9);
293 times.insert("CZ".to_string(), 40e-9);
294 times
295 }
296 HardwareArchitecture::TrappedIon => {
297 let mut times = HashMap::new();
298 times.insert("X".to_string(), 10e-6);
299 times.insert("Y".to_string(), 10e-6);
300 times.insert("Z".to_string(), 0.0);
301 times.insert("H".to_string(), 10e-6);
302 times.insert("CNOT".to_string(), 100e-6);
303 times.insert("CZ".to_string(), 100e-6);
304 times
305 }
306 _ => {
307 let mut times = HashMap::new();
308 times.insert("X".to_string(), 1e-6);
309 times.insert("Y".to_string(), 1e-6);
310 times.insert("Z".to_string(), 0.0);
311 times.insert("H".to_string(), 1e-6);
312 times.insert("CNOT".to_string(), 10e-6);
313 times.insert("CZ".to_string(), 10e-6);
314 times
315 }
316 };
317
318 let crosstalk_matrix = Array2::zeros((num_qubits, num_qubits));
319
320 Self {
321 connectivity_graph,
322 gate_fidelities,
323 decoherence_times,
324 gate_times,
325 crosstalk_matrix,
326 }
327 }
328
329 pub fn set_gate_fidelity(&mut self, gate_name: &str, fidelity: f64) {
331 self.gate_fidelities.insert(gate_name.to_string(), fidelity);
332 }
333
334 pub fn set_gate_time(&mut self, gate_name: &str, time: f64) {
336 self.gate_times.insert(gate_name.to_string(), time);
337 }
338
339 pub fn set_decoherence_time(&mut self, qubit: usize, time: f64) {
341 if qubit < self.decoherence_times.len() {
342 self.decoherence_times[qubit] = time;
343 }
344 }
345
346 pub fn set_connectivity(&mut self, qubit1: usize, qubit2: usize, connected: bool) {
348 if qubit1 < self.connectivity_graph.nrows() && qubit2 < self.connectivity_graph.ncols() {
349 self.connectivity_graph[[qubit1, qubit2]] = connected;
350 self.connectivity_graph[[qubit2, qubit1]] = connected; }
352 }
353
354 pub fn average_gate_fidelity(&self) -> f64 {
356 let fidelities: Vec<f64> = self.gate_fidelities.values().cloned().collect();
357 if fidelities.is_empty() {
358 1.0
359 } else {
360 fidelities.iter().sum::<f64>() / fidelities.len() as f64
361 }
362 }
363
364 pub fn connectivity_degree(&self, qubit: usize) -> usize {
366 if qubit >= self.connectivity_graph.nrows() {
367 return 0;
368 }
369 self.connectivity_graph
370 .row(qubit)
371 .iter()
372 .map(|&x| if x { 1 } else { 0 })
373 .sum()
374 }
375}