Skip to main content

q_rust/ir/
circuit.rs

1use super::operations::Operation;
2
3/// Intermediate Representation of a Quantum Circuit.
4///
5/// A `Circuit` consists of a sequence of operations and metadata about the
6/// number of qubits and classical bits required.
7#[derive(Debug, Clone, Default)]
8pub struct Circuit {
9    /// Total number of qubits in the circuit.
10    pub num_qubits: usize,
11    /// Total number of classical bits in the circuit.
12    pub num_cbits: usize,
13    /// Sequence of operations (gates, measurements, etc.).
14    pub operations: Vec<Operation>,
15}
16
17impl Circuit {
18    /// Creates a new empty circuit.
19    ///
20    /// # Arguments
21    ///
22    /// * `num_qubits` - The number of qubits to allocate.
23    /// * `num_cbits` - The number of classical bits to allocate.
24    pub fn new(num_qubits: usize, num_cbits: usize) -> Self {
25        Self {
26            num_qubits,
27            num_cbits,
28            operations: Vec::new(),
29        }
30    }
31
32    /// Adds an operation to the circuit.
33    pub fn add_op(&mut self, op: Operation) {
34        self.operations.push(op);
35    }
36
37    /// Validates the circuit and returns a list of warnings.
38    ///
39    /// Checks:
40    /// - Presence of at least one measurement.
41    pub fn validate(&self) -> Vec<String> {
42        let mut warnings = Vec::new();
43        let has_measurement = self
44            .operations
45            .iter()
46            .any(|op| matches!(op, Operation::Measure { .. }));
47
48        if !has_measurement {
49            warnings.push("Warning: No measurements found. The circuit will not produce classical output on hardware.".to_string());
50        }
51
52        warnings
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use crate::ir::gates::GateType;
60
61    #[test]
62    fn test_circuit_creation() {
63        let circuit = Circuit::new(2, 2);
64        assert_eq!(circuit.num_qubits, 2);
65        assert_eq!(circuit.num_cbits, 2);
66        assert!(circuit.operations.is_empty());
67    }
68
69    #[test]
70    fn test_add_op() {
71        let mut circuit = Circuit::new(1, 0);
72        let op = Operation::Gate {
73            name: GateType::H,
74            qubits: vec![0],
75            params: vec![],
76        };
77        circuit.add_op(op.clone());
78        assert_eq!(circuit.operations.len(), 1);
79        assert_eq!(circuit.operations[0], op);
80    }
81
82    #[test]
83    fn test_validation_no_measurements() {
84        let mut circuit = Circuit::new(1, 0);
85        circuit.add_op(Operation::Gate {
86            name: GateType::H,
87            qubits: vec![0],
88            params: vec![],
89        });
90        let warnings = circuit.validate();
91        assert_eq!(warnings.len(), 1);
92        assert!(warnings[0].contains("No measurements found"));
93    }
94
95    #[test]
96    fn test_validation_with_measurements() {
97        let mut circuit = Circuit::new(1, 1);
98        circuit.add_op(Operation::Measure { qubit: 0, cbit: 0 });
99        let warnings = circuit.validate();
100        assert!(warnings.is_empty());
101    }
102}