1use crate::circuit_integration::{DeviceTopology, QubitProperties};
7use crate::error::{MLError, Result};
8use quantrs2_circuit::prelude::*;
9use quantrs2_core::prelude::*;
10use scirs2_core::ndarray::{Array1, Array2};
11use std::collections::{HashMap, HashSet, VecDeque};
12
13pub struct DeviceCompiler {
15 topology: DeviceTopology,
17 options: CompilationOptions,
19 characterization: DeviceCharacterization,
21}
22
23#[derive(Debug, Clone)]
25pub struct CompilationOptions {
26 pub optimization_level: u8,
28 pub max_compilation_time: f64,
30 pub error_threshold: f64,
32 pub noise_aware: bool,
34 pub crosstalk_mitigation: bool,
36 pub routing_algorithm: RoutingAlgorithm,
38 pub synthesis_method: SynthesisMethod,
40}
41
42impl Default for CompilationOptions {
43 fn default() -> Self {
44 Self {
45 optimization_level: 2,
46 max_compilation_time: 60.0,
47 error_threshold: 0.01,
48 noise_aware: true,
49 crosstalk_mitigation: true,
50 routing_algorithm: RoutingAlgorithm::SABRE,
51 synthesis_method: SynthesisMethod::SolovayKitaev,
52 }
53 }
54}
55
56#[derive(Debug, Clone, Copy)]
58pub enum RoutingAlgorithm {
59 SABRE,
61 Lookahead,
63 TokenSwapping,
65 Heuristic,
67}
68
69#[derive(Debug, Clone, Copy)]
71pub enum SynthesisMethod {
72 SolovayKitaev,
74 Shannon,
76 KAK,
78 Cartan,
80}
81
82#[derive(Debug, Clone)]
84pub struct DeviceCharacterization {
85 pub gate_errors: HashMap<String, f64>,
87 pub two_qubit_errors: HashMap<(usize, usize), f64>,
89 pub readout_errors: Array1<f64>,
91 pub crosstalk_matrix: Array2<f64>,
93 pub gate_times: HashMap<String, f64>,
95 pub calibration_time: std::time::SystemTime,
97}
98
99impl DeviceCharacterization {
100 pub fn default_for_device(num_qubits: usize) -> Self {
102 let mut gate_errors = HashMap::new();
103 gate_errors.insert("X".to_string(), 0.001);
104 gate_errors.insert("Y".to_string(), 0.001);
105 gate_errors.insert("Z".to_string(), 0.0001);
106 gate_errors.insert("H".to_string(), 0.002);
107 gate_errors.insert("CNOT".to_string(), 0.01);
108
109 let mut gate_times = HashMap::new();
110 gate_times.insert("X".to_string(), 0.02); gate_times.insert("Y".to_string(), 0.02);
112 gate_times.insert("Z".to_string(), 0.0); gate_times.insert("H".to_string(), 0.02);
114 gate_times.insert("CNOT".to_string(), 0.2); Self {
117 gate_errors,
118 two_qubit_errors: HashMap::new(),
119 readout_errors: Array1::from_elem(num_qubits, 0.02),
120 crosstalk_matrix: Array2::zeros((num_qubits, num_qubits)),
121 gate_times,
122 calibration_time: std::time::SystemTime::now(),
123 }
124 }
125
126 pub fn set_gate_error(&mut self, gate: &str, qubits: &[usize], error: f64) {
128 if qubits.len() == 2 {
129 self.two_qubit_errors.insert((qubits[0], qubits[1]), error);
130 } else {
131 self.gate_errors.insert(gate.to_string(), error);
132 }
133 }
134
135 pub fn get_gate_error(&self, gate: &str, qubits: &[usize]) -> f64 {
137 if qubits.len() == 2 {
138 self.two_qubit_errors
139 .get(&(qubits[0], qubits[1]))
140 .or_else(|| self.two_qubit_errors.get(&(qubits[1], qubits[0])))
141 .copied()
142 .unwrap_or_else(|| self.gate_errors.get(gate).copied().unwrap_or(0.01))
143 } else {
144 self.gate_errors.get(gate).copied().unwrap_or(0.001)
145 }
146 }
147}
148
149impl DeviceCompiler {
150 pub fn new(topology: DeviceTopology) -> Self {
152 let num_qubits = topology.num_qubits();
153 Self {
154 topology,
155 options: CompilationOptions::default(),
156 characterization: DeviceCharacterization::default_for_device(num_qubits),
157 }
158 }
159
160 pub fn with_options(mut self, options: CompilationOptions) -> Self {
162 self.options = options;
163 self
164 }
165
166 pub fn with_characterization(mut self, characterization: DeviceCharacterization) -> Self {
168 self.characterization = characterization;
169 self
170 }
171
172 pub fn compile_model<const N: usize>(
174 &self,
175 model: &QuantumMLModel,
176 ) -> Result<CompiledModel<N>> {
177 let start_time = std::time::Instant::now();
178
179 let mut circuit = self.model_to_circuit::<N>(model)?;
181
182 circuit = self.initial_optimization::<N>(&circuit)?;
184
185 let (mut circuit, qubit_mapping) = self.route_circuit::<N>(&circuit)?;
187
188 circuit = self.synthesize_gates::<N>(&circuit)?;
190
191 if self.options.noise_aware {
193 circuit = self.noise_aware_optimization::<N>(&circuit)?;
194 }
195
196 if self.options.crosstalk_mitigation {
198 circuit = self.mitigate_crosstalk::<N>(&circuit)?;
199 }
200
201 circuit = self.final_optimization::<N>(&circuit)?;
203
204 let compilation_time = start_time.elapsed().as_secs_f64();
205
206 let metrics = self.analyze_compiled_circuit::<N>(&circuit, compilation_time)?;
208
209 Ok(CompiledModel {
210 circuit,
211 qubit_mapping,
212 metrics,
213 target_device: self.topology.clone(),
214 characterization: self.characterization.clone(),
215 })
216 }
217
218 fn model_to_circuit<const N: usize>(&self, model: &QuantumMLModel) -> Result<Circuit<N>> {
220 let mut builder = CircuitBuilder::<N>::new();
221
222 for layer in &model.layers {
224 match layer {
225 ModelLayer::Encoding(encoding_layer) => {
226 self.add_encoding_layer::<N>(&mut builder, encoding_layer)?;
227 }
228 ModelLayer::Variational(var_layer) => {
229 self.add_variational_layer::<N>(&mut builder, var_layer)?;
230 }
231 ModelLayer::Measurement(meas_layer) => {
232 self.add_measurement_layer::<N>(&mut builder, meas_layer)?;
233 }
234 }
235 }
236
237 Ok(builder.build())
238 }
239
240 fn add_encoding_layer<const N: usize>(
242 &self,
243 builder: &mut CircuitBuilder<N>,
244 layer: &EncodingLayer,
245 ) -> Result<()> {
246 match &layer.encoding_type {
247 EncodingType::Amplitude => {
248 for qubit in &layer.qubits {
250 builder.ry(*qubit, 0.0)?; }
252 }
253 EncodingType::Angle => {
254 for qubit in &layer.qubits {
256 builder.rz(*qubit, 0.0)?; }
258 }
259 EncodingType::Basis => {
260 }
262 }
263 Ok(())
264 }
265
266 fn add_variational_layer<const N: usize>(
268 &self,
269 builder: &mut CircuitBuilder<N>,
270 layer: &VariationalLayer,
271 ) -> Result<()> {
272 match &layer.ansatz_type {
273 AnsatzType::HardwareEfficient => {
274 for qubit in &layer.qubits {
276 builder.ry(*qubit, 0.0)?;
277 builder.rz(*qubit, 0.0)?;
278 }
279
280 for i in 0..layer.qubits.len() - 1 {
282 builder.cnot(layer.qubits[i], layer.qubits[i + 1])?;
283 }
284 }
285 AnsatzType::QAOA => {
286 for qubit in &layer.qubits {
288 builder.rx(*qubit, 0.0)?; }
290
291 }
293 AnsatzType::Custom(gates) => {
294 for gate in gates {
296 self.add_custom_gate(builder, gate)?;
297 }
298 }
299 }
300 Ok(())
301 }
302
303 fn add_measurement_layer<const N: usize>(
305 &self,
306 builder: &mut CircuitBuilder<N>,
307 layer: &MeasurementLayer,
308 ) -> Result<()> {
309 for qubit in &layer.qubits {
310 }
312 Ok(())
313 }
314
315 fn add_custom_gate<const N: usize>(
317 &self,
318 builder: &mut CircuitBuilder<N>,
319 gate: &CustomGate,
320 ) -> Result<()> {
321 match gate {
322 CustomGate::SingleQubit {
323 qubit,
324 gate_type,
325 parameter,
326 } => match gate_type.as_str() {
327 "RX" => {
328 builder.rx(*qubit, *parameter)?;
329 }
330 "RY" => {
331 builder.ry(*qubit, *parameter)?;
332 }
333 "RZ" => {
334 builder.rz(*qubit, *parameter)?;
335 }
336 "H" => {
337 builder.h(*qubit)?;
338 }
339 _ => {
340 return Err(MLError::InvalidConfiguration(format!(
341 "Unknown gate type: {}",
342 gate_type
343 )))
344 }
345 },
346 CustomGate::TwoQubit {
347 control,
348 target,
349 gate_type,
350 parameter,
351 } => {
352 match gate_type.as_str() {
353 "CNOT" => {
354 builder.cnot(*control, *target)?;
355 }
356 "CZ" => {
357 builder.cz(*control, *target)?;
358 }
359 "RZZ" => {
360 builder.crz(*control, *target, *parameter)?;
361 } _ => {
363 return Err(MLError::InvalidConfiguration(format!(
364 "Unknown two-qubit gate type: {}",
365 gate_type
366 )))
367 }
368 }
369 }
370 }
371 Ok(())
372 }
373
374 fn initial_optimization<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
376 let mut optimized = circuit.clone();
377
378 if self.options.optimization_level >= 1 {
379 optimized = self.remove_redundant_gates::<N>(&optimized)?;
381 }
382
383 if self.options.optimization_level >= 2 {
384 optimized = self.merge_rotations::<N>(&optimized)?;
386 }
387
388 if self.options.optimization_level >= 3 {
389 optimized = self.commutation_optimization::<N>(&optimized)?;
391 }
392
393 Ok(optimized)
394 }
395
396 fn route_circuit<const N: usize>(
398 &self,
399 circuit: &Circuit<N>,
400 ) -> Result<(Circuit<N>, QubitMapping)> {
401 match self.options.routing_algorithm {
402 RoutingAlgorithm::SABRE => self.sabre_routing(circuit),
403 RoutingAlgorithm::Lookahead => self.lookahead_routing(circuit),
404 RoutingAlgorithm::TokenSwapping => self.token_swapping_routing(circuit),
405 RoutingAlgorithm::Heuristic => self.heuristic_routing(circuit),
406 }
407 }
408
409 fn sabre_routing<const N: usize>(
411 &self,
412 circuit: &Circuit<N>,
413 ) -> Result<(Circuit<N>, QubitMapping)> {
414 let mut routed_circuit = CircuitBuilder::<N>::new();
415 let mut mapping = QubitMapping::identity(circuit.num_qubits());
416
417 for gate in circuit.gates() {
419 if gate.num_qubits() == 2 {
420 let (q1, q2) = (gate.qubits()[0], gate.qubits()[1]);
421 if !self.topology.are_connected(
422 mapping.logical_to_physical(q1.into()),
423 mapping.logical_to_physical(q2.into()),
424 ) {
425 let swaps = self.find_swap_path(
427 mapping.logical_to_physical(q1.into()),
428 mapping.logical_to_physical(q2.into()),
429 )?;
430
431 for (qa, qb) in swaps {
432 routed_circuit.swap(qa, qb)?;
433 mapping.apply_swap(qa, qb);
434 }
435 }
436 }
437
438 self.add_mapped_gate::<N>(&mut routed_circuit, gate.as_ref(), &mapping)?;
440 }
441
442 Ok((routed_circuit.build(), mapping))
443 }
444
445 fn find_swap_path(&self, start: usize, end: usize) -> Result<Vec<(usize, usize)>> {
447 let mut queue = VecDeque::new();
449 let mut visited = HashSet::new();
450 let mut parent = HashMap::new();
451
452 queue.push_back(start);
453 visited.insert(start);
454
455 while let Some(current) = queue.pop_front() {
456 if current == end {
457 let mut path = Vec::new();
459 let mut node = end;
460 while let Some(&prev) = parent.get(&node) {
461 path.push((prev, node));
462 node = prev;
463 }
464 path.reverse();
465 return Ok(path);
466 }
467
468 for neighbor in self.topology.neighbors(current) {
469 if !visited.contains(&neighbor) {
470 visited.insert(neighbor);
471 parent.insert(neighbor, current);
472 queue.push_back(neighbor);
473 }
474 }
475 }
476
477 Err(MLError::InvalidConfiguration(
478 "No path found between qubits".to_string(),
479 ))
480 }
481
482 fn lookahead_routing<const N: usize>(
484 &self,
485 circuit: &Circuit<N>,
486 ) -> Result<(Circuit<N>, QubitMapping)> {
487 self.sabre_routing(circuit)
489 }
490
491 fn token_swapping_routing<const N: usize>(
492 &self,
493 circuit: &Circuit<N>,
494 ) -> Result<(Circuit<N>, QubitMapping)> {
495 self.sabre_routing(circuit)
497 }
498
499 fn heuristic_routing<const N: usize>(
500 &self,
501 circuit: &Circuit<N>,
502 ) -> Result<(Circuit<N>, QubitMapping)> {
503 self.sabre_routing(circuit)
505 }
506
507 fn add_mapped_gate<const N: usize>(
509 &self,
510 builder: &mut CircuitBuilder<N>,
511 gate: &dyn GateOp,
512 mapping: &QubitMapping,
513 ) -> Result<()> {
514 let mapped_qubits: Vec<usize> = gate
515 .qubits()
516 .iter()
517 .map(|&q| mapping.logical_to_physical(q.into()))
518 .collect();
519
520 match gate.name() {
521 "H" => {
522 builder.h(mapped_qubits[0])?;
523 }
524 "X" => {
525 builder.x(mapped_qubits[0])?;
526 }
527 "Y" => {
528 builder.y(mapped_qubits[0])?;
529 }
530 "Z" => {
531 builder.z(mapped_qubits[0])?;
532 }
533 "RX" => {
534 let theta = gate
535 .as_any()
536 .downcast_ref::<single::RotationX>()
537 .map(|g| g.theta)
538 .unwrap_or(0.0);
539 builder.rx(mapped_qubits[0], theta)?;
540 }
541 "RY" => {
542 let theta = gate
543 .as_any()
544 .downcast_ref::<single::RotationY>()
545 .map(|g| g.theta)
546 .unwrap_or(0.0);
547 builder.ry(mapped_qubits[0], theta)?;
548 }
549 "RZ" => {
550 let theta = gate
551 .as_any()
552 .downcast_ref::<single::RotationZ>()
553 .map(|g| g.theta)
554 .unwrap_or(0.0);
555 builder.rz(mapped_qubits[0], theta)?;
556 }
557 "CNOT" => {
558 builder.cnot(mapped_qubits[0], mapped_qubits[1])?;
559 }
560 "CZ" => {
561 builder.cz(mapped_qubits[0], mapped_qubits[1])?;
562 }
563 "SWAP" => {
564 builder.swap(mapped_qubits[0], mapped_qubits[1])?;
565 }
566 _ => {
567 return Err(MLError::InvalidConfiguration(format!(
568 "Unknown gate type: {}",
569 gate.name()
570 )))
571 }
572 }
573
574 Ok(())
575 }
576
577 fn synthesize_gates<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
579 match self.options.synthesis_method {
580 SynthesisMethod::SolovayKitaev => self.solovay_kitaev_synthesis(circuit),
581 SynthesisMethod::Shannon => self.shannon_synthesis(circuit),
582 SynthesisMethod::KAK => self.kak_synthesis(circuit),
583 SynthesisMethod::Cartan => self.cartan_synthesis(circuit),
584 }
585 }
586
587 fn solovay_kitaev_synthesis<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
589 Ok(circuit.clone())
591 }
592
593 fn shannon_synthesis<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
595 Ok(circuit.clone())
597 }
598
599 fn kak_synthesis<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
601 Ok(circuit.clone())
603 }
604
605 fn cartan_synthesis<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
607 Ok(circuit.clone())
609 }
610
611 fn noise_aware_optimization<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
613 let mut optimized = circuit.clone();
614
615 optimized = self.schedule_for_coherence::<N>(&optimized)?;
617
618 optimized = self.select_low_error_gates::<N>(&optimized)?;
620
621 Ok(optimized)
622 }
623
624 fn schedule_for_coherence<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
626 Ok(circuit.clone())
628 }
629
630 fn select_low_error_gates<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
632 Ok(circuit.clone())
634 }
635
636 fn mitigate_crosstalk<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
638 Ok(circuit.clone())
640 }
641
642 fn final_optimization<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
644 let mut optimized = circuit.clone();
645
646 optimized = self.merge_rotations::<N>(&optimized)?;
648
649 optimized = self.remove_identity_gates::<N>(&optimized)?;
651
652 Ok(optimized)
653 }
654
655 fn remove_redundant_gates<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
657 Ok(circuit.clone())
659 }
660
661 fn merge_rotations<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
663 Ok(circuit.clone())
665 }
666
667 fn commutation_optimization<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
669 Ok(circuit.clone())
671 }
672
673 fn remove_identity_gates<const N: usize>(&self, circuit: &Circuit<N>) -> Result<Circuit<N>> {
675 Ok(circuit.clone())
677 }
678
679 fn analyze_compiled_circuit<const N: usize>(
681 &self,
682 circuit: &Circuit<N>,
683 compilation_time: f64,
684 ) -> Result<CompilationMetrics> {
685 let gate_count = circuit.num_gates();
686 let depth = {
691 let gates = circuit.gates();
692 let mut qubit_depth: HashMap<usize, usize> = HashMap::new();
694 let mut max_depth: usize = 0;
695 for gate in gates {
696 let qubits_usize: Vec<usize> = gate.qubits().iter().map(|&q| q.into()).collect();
697 let gate_layer = qubits_usize
698 .iter()
699 .map(|q| qubit_depth.get(q).copied().unwrap_or(0))
700 .max()
701 .unwrap_or(0)
702 + 1;
703 for q in &qubits_usize {
704 qubit_depth.insert(*q, gate_layer);
705 }
706 if gate_layer > max_depth {
707 max_depth = gate_layer;
708 }
709 }
710 max_depth
711 };
712 let two_qubit_gate_count = circuit
713 .gates()
714 .iter()
715 .filter(|g| g.num_qubits() == 2)
716 .count();
717
718 let mut total_error = 0.0;
720 for gate in circuit.gates() {
721 let qubits_usize: Vec<usize> = gate.qubits().iter().map(|&q| q.into()).collect();
722 total_error += self
723 .characterization
724 .get_gate_error(gate.name(), &qubits_usize);
725 }
726
727 let mut execution_time = 0.0;
729 for gate in circuit.gates() {
730 execution_time += self
731 .characterization
732 .gate_times
733 .get(gate.name())
734 .copied()
735 .unwrap_or(0.1);
736 }
737
738 Ok(CompilationMetrics {
739 gate_count,
740 depth,
741 two_qubit_gate_count,
742 total_error,
743 execution_time,
744 compilation_time,
745 swap_count: 0, })
747 }
748}
749
750#[derive(Debug, Clone)]
752pub struct QuantumMLModel {
753 pub layers: Vec<ModelLayer>,
755 pub num_qubits: usize,
757 pub num_parameters: usize,
759}
760
761#[derive(Debug, Clone)]
763pub enum ModelLayer {
764 Encoding(EncodingLayer),
766 Variational(VariationalLayer),
768 Measurement(MeasurementLayer),
770}
771
772#[derive(Debug, Clone)]
774pub struct EncodingLayer {
775 pub qubits: Vec<usize>,
777 pub encoding_type: EncodingType,
779}
780
781#[derive(Debug, Clone)]
783pub enum EncodingType {
784 Amplitude,
786 Angle,
788 Basis,
790}
791
792#[derive(Debug, Clone)]
794pub struct VariationalLayer {
795 pub qubits: Vec<usize>,
797 pub ansatz_type: AnsatzType,
799 pub repetitions: usize,
801}
802
803#[derive(Debug, Clone)]
805pub enum AnsatzType {
806 HardwareEfficient,
808 QAOA,
810 Custom(Vec<CustomGate>),
812}
813
814#[derive(Debug, Clone)]
816pub enum CustomGate {
817 SingleQubit {
819 qubit: usize,
820 gate_type: String,
821 parameter: f64,
822 },
823 TwoQubit {
825 control: usize,
826 target: usize,
827 gate_type: String,
828 parameter: f64,
829 },
830}
831
832#[derive(Debug, Clone)]
834pub struct MeasurementLayer {
835 pub qubits: Vec<usize>,
837 pub basis: MeasurementBasis,
839}
840
841#[derive(Debug, Clone)]
843pub enum MeasurementBasis {
844 Computational,
846 X,
848 Y,
850 Pauli(String),
852}
853
854#[derive(Debug, Clone)]
856pub struct CompiledModel<const N: usize> {
857 pub circuit: Circuit<N>,
859 pub qubit_mapping: QubitMapping,
861 pub metrics: CompilationMetrics,
863 pub target_device: DeviceTopology,
865 pub characterization: DeviceCharacterization,
867}
868
869#[derive(Debug, Clone)]
871pub struct QubitMapping {
872 logical_to_physical: Vec<usize>,
874 physical_to_logical: Vec<Option<usize>>,
876}
877
878impl QubitMapping {
879 pub fn identity(num_qubits: usize) -> Self {
881 Self {
882 logical_to_physical: (0..num_qubits).collect(),
883 physical_to_logical: (0..num_qubits).map(Some).collect(),
884 }
885 }
886
887 pub fn logical_to_physical(&self, logical: usize) -> usize {
889 self.logical_to_physical[logical]
890 }
891
892 pub fn physical_to_logical(&self, physical: usize) -> Option<usize> {
894 self.physical_to_logical.get(physical).copied().flatten()
895 }
896
897 pub fn apply_swap(&mut self, q1: usize, q2: usize) {
899 for logical in &mut self.logical_to_physical {
901 if *logical == q1 {
902 *logical = q2;
903 } else if *logical == q2 {
904 *logical = q1;
905 }
906 }
907
908 self.physical_to_logical.swap(q1, q2);
910 }
911}
912
913#[derive(Debug, Clone)]
915pub struct CompilationMetrics {
916 pub gate_count: usize,
918 pub depth: usize,
920 pub two_qubit_gate_count: usize,
922 pub total_error: f64,
924 pub execution_time: f64,
926 pub compilation_time: f64,
928 pub swap_count: usize,
930}
931
932#[cfg(test)]
933mod tests {
934 use super::*;
935 use crate::circuit_integration::DeviceTopology;
936
937 #[test]
938 fn test_device_compiler_creation() {
939 let topology = DeviceTopology::new(5)
940 .add_edge(0, 1)
941 .add_edge(1, 2)
942 .add_edge(2, 3)
943 .add_edge(3, 4);
944
945 let compiler = DeviceCompiler::new(topology);
946 assert_eq!(compiler.options.optimization_level, 2);
947 }
948
949 #[test]
950 fn test_device_characterization() {
951 let mut char = DeviceCharacterization::default_for_device(3);
952 char.set_gate_error("CNOT", &[0, 1], 0.005);
953
954 assert_eq!(char.get_gate_error("CNOT", &[0, 1]), 0.005);
955 assert_eq!(char.get_gate_error("X", &[0]), 0.001);
956 }
957
958 #[test]
959 fn test_qubit_mapping() {
960 let mut mapping = QubitMapping::identity(3);
961 assert_eq!(mapping.logical_to_physical(1), 1);
962
963 mapping.apply_swap(0, 2);
964 assert_eq!(mapping.logical_to_physical(0), 2);
965 assert_eq!(mapping.logical_to_physical(2), 0);
966 }
967
968 #[test]
969 fn test_compilation_options() {
970 let options = CompilationOptions {
971 optimization_level: 3,
972 noise_aware: false,
973 routing_algorithm: RoutingAlgorithm::Lookahead,
974 ..Default::default()
975 };
976
977 assert_eq!(options.optimization_level, 3);
978 assert!(!options.noise_aware);
979 }
980}