quantrs2_device/mapping_scirs2/
utils.rs1use super::*;
4use crate::calibration::create_ideal_calibration as create_ideal_calibration_fn;
5use scirs2_core::random::prelude::*;
6
7pub fn create_standard_topology(
9 topology_type: &str,
10 num_qubits: usize,
11) -> DeviceResult<HardwareTopology> {
12 match topology_type {
13 "linear" => Ok(create_linear_topology(num_qubits)),
14 "grid" => Ok(create_grid_topology(num_qubits)),
15 "star" => Ok(create_star_topology(num_qubits)),
16 "complete" => Ok(create_complete_topology(num_qubits)),
17 _ => Err(DeviceError::InvalidTopology(format!(
18 "Unknown topology: {}",
19 topology_type
20 ))),
21 }
22}
23
24fn create_linear_topology(num_qubits: usize) -> HardwareTopology {
26 HardwareTopology::linear_topology(num_qubits)
27}
28
29fn create_grid_topology(num_qubits: usize) -> HardwareTopology {
31 let side_length = (num_qubits as f64).sqrt().ceil() as usize;
32 let rows = side_length;
33 let cols = num_qubits.div_ceil(side_length);
34 HardwareTopology::grid_topology(rows, cols)
35}
36
37fn create_star_topology(num_qubits: usize) -> HardwareTopology {
39 use crate::topology::{GateProperties, QubitProperties};
40
41 let mut topology = HardwareTopology::new(num_qubits);
42
43 for i in 0..num_qubits {
45 topology.add_qubit(QubitProperties {
46 id: i as u32,
47 index: i as u32,
48 t1: 50.0,
49 t2: 70.0,
50 single_qubit_gate_error: 0.001,
51 gate_error_1q: 0.001,
52 readout_error: 0.01,
53 frequency: 5.0 + 0.1 * i as f64,
54 });
55 }
56
57 for i in 1..num_qubits {
59 topology.add_connection(
60 0,
61 i as u32,
62 GateProperties {
63 error_rate: 0.01,
64 duration: 200.0,
65 gate_type: "CZ".to_string(),
66 },
67 );
68 }
69 topology
70}
71
72fn create_complete_topology(num_qubits: usize) -> HardwareTopology {
74 use crate::topology::{GateProperties, QubitProperties};
75
76 let mut topology = HardwareTopology::new(num_qubits);
78
79 for i in 0..num_qubits {
81 topology.add_qubit(QubitProperties {
82 id: i as u32,
83 index: i as u32,
84 t1: 50.0,
85 t2: 70.0,
86 single_qubit_gate_error: 0.001,
87 gate_error_1q: 0.001,
88 readout_error: 0.01,
89 frequency: 5.0 + 0.1 * i as f64,
90 });
91 }
92
93 for i in 0..num_qubits {
95 for j in i + 1..num_qubits {
96 topology.add_connection(
97 i as u32,
98 j as u32,
99 GateProperties {
100 error_rate: 0.01,
101 duration: 200.0,
102 gate_type: "CZ".to_string(),
103 },
104 );
105 }
106 }
107 topology
108}
109
110pub fn create_ideal_calibration(device_name: String, num_qubits: usize) -> DeviceCalibration {
112 create_ideal_calibration_fn(device_name, num_qubits)
113}
114
115pub fn validate_mapping(
117 mapping: &HashMap<usize, usize>,
118 num_logical_qubits: usize,
119 num_physical_qubits: usize,
120) -> DeviceResult<()> {
121 for i in 0..num_logical_qubits {
123 if !mapping.contains_key(&i) {
124 return Err(DeviceError::InvalidMapping(format!(
125 "Logical qubit {} not mapped",
126 i
127 )));
128 }
129 }
130
131 for &physical in mapping.values() {
133 if physical >= num_physical_qubits {
134 return Err(DeviceError::InvalidMapping(format!(
135 "Physical qubit {} exceeds device capacity",
136 physical
137 )));
138 }
139 }
140
141 let mut used_physical = HashSet::new();
143 for &physical in mapping.values() {
144 if !used_physical.insert(physical) {
145 return Err(DeviceError::InvalidMapping(format!(
146 "Physical qubit {} mapped multiple times",
147 physical
148 )));
149 }
150 }
151
152 Ok(())
153}
154
155pub fn calculate_mapping_quality(
157 mapping: &HashMap<usize, usize>,
158 logical_graph: &Graph<usize, f64>,
159 topology: &HardwareTopology,
160) -> DeviceResult<f64> {
161 let mut total_distance = 0.0;
162 let mut edge_count = 0;
163
164 for edge in logical_graph.edges() {
165 let source = edge.source;
168 let target = edge.target;
169
170 if let (Some(&phys_source), Some(&phys_target)) =
171 (mapping.get(&source), mapping.get(&target))
172 {
173 let distance = topology
175 .shortest_path_distance(phys_source, phys_target)
176 .unwrap_or(f64::INFINITY);
177
178 total_distance += distance;
179 edge_count += 1;
180 }
181 }
182
183 if edge_count > 0 {
184 Ok(1.0 / (1.0 + total_distance / edge_count as f64))
185 } else {
186 Ok(1.0)
187 }
188}
189
190pub fn generate_random_circuit<const N: usize>(
192 gate_count: usize,
193 two_qubit_ratio: f64,
194) -> Circuit<N> {
195 let mut circuit = Circuit::<N>::new();
196 let mut rng = thread_rng();
197
198 for _ in 0..gate_count {
199 if rng.gen::<f64>() < two_qubit_ratio {
200 let q1 = rng.gen_range(0..N);
202 let mut q2 = rng.gen_range(0..N);
203 while q2 == q1 {
204 q2 = rng.gen_range(0..N);
205 }
206 let _ = circuit.cnot(QubitId(q1 as u32), QubitId(q2 as u32));
207 } else {
208 let q = rng.gen_range(0..N);
210 let _ = circuit.x(QubitId(q as u32));
211 }
212 }
213
214 circuit
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220
221 #[test]
222 fn test_linear_topology_creation() {
223 let topology = create_linear_topology(4);
224 assert_eq!(topology.num_qubits(), 4);
225 assert!(topology.are_connected(0, 1));
226 assert!(topology.are_connected(1, 2));
227 assert!(topology.are_connected(2, 3));
228 assert!(!topology.are_connected(0, 3));
229 }
230
231 #[test]
232 fn test_grid_topology_creation() {
233 let topology = create_grid_topology(4);
234 assert_eq!(topology.num_qubits(), 4);
235 assert!(topology.are_connected(0, 1));
237 assert!(topology.are_connected(0, 2));
238 }
239
240 #[test]
241 fn test_star_topology_creation() {
242 let topology = create_star_topology(5);
243 assert_eq!(topology.num_qubits(), 5);
244 for i in 1..5 {
246 assert!(topology.are_connected(0, i));
247 }
248 assert!(!topology.are_connected(1, 2));
250 }
251
252 #[test]
253 fn test_mapping_validation() {
254 let mut mapping = HashMap::new();
255 mapping.insert(0, 0);
256 mapping.insert(1, 1);
257 mapping.insert(2, 2);
258
259 assert!(validate_mapping(&mapping, 3, 4).is_ok());
260
261 mapping.insert(3, 2); assert!(validate_mapping(&mapping, 4, 4).is_err());
264 }
265
266 #[test]
267 fn test_mapping_quality_calculation() {
268 let topology = create_linear_topology(4);
269 let mut graph = Graph::new();
270 let _nodes: Vec<_> = (0..4).map(|i| graph.add_node(i)).collect();
271
272 let _ = graph.add_edge(0, 3, 1.0);
274
275 let mut mapping = HashMap::new();
276 mapping.insert(0, 0);
277 mapping.insert(1, 1);
278 mapping.insert(2, 2);
279 mapping.insert(3, 3);
280
281 let quality = calculate_mapping_quality(&mapping, &graph, &topology)
282 .expect("should calculate mapping quality");
283 assert!(quality > 0.0 && quality <= 1.0);
284 }
285
286 #[test]
287 fn test_random_circuit_generation() {
288 let circuit = generate_random_circuit::<4>(10, 0.5);
289 assert!(circuit.gates().len() <= 10);
290 }
291
292 #[test]
293 fn test_standard_topology_creation() {
294 assert!(create_standard_topology("linear", 4).is_ok());
295 assert!(create_standard_topology("grid", 4).is_ok());
296 assert!(create_standard_topology("star", 4).is_ok());
297 assert!(create_standard_topology("complete", 4).is_ok());
298 assert!(create_standard_topology("invalid", 4).is_err());
299 }
300
301 #[test]
302 fn test_complete_topology() {
303 let topology = create_complete_topology(4);
304 assert_eq!(topology.num_qubits(), 4);
305
306 for i in 0..4 {
308 for j in i + 1..4 {
309 assert!(topology.are_connected(i, j));
310 }
311 }
312 }
313
314 #[test]
315 fn test_ideal_calibration_creation() {
316 let _calibration = create_ideal_calibration("test_device".to_string(), 4);
317 }
320
321 #[test]
322 fn test_mapping_validation_edge_cases() {
323 let mapping = HashMap::new();
325 assert!(validate_mapping(&mapping, 0, 4).is_ok());
326
327 let mut mapping = HashMap::new();
329 mapping.insert(0, 10);
330 assert!(validate_mapping(&mapping, 1, 4).is_err());
331
332 let mut mapping = HashMap::new();
334 mapping.insert(0, 0);
335 assert!(validate_mapping(&mapping, 2, 4).is_err());
336 }
337}