cqlib_core/circuit/control_flow/
body.rs1use crate::circuit::{ClassicalValue, Operation, Qubit};
14use std::collections::BTreeSet;
15use std::sync::Arc;
16
17#[derive(Debug, Clone, PartialEq)]
19pub struct ControlBody {
20 operations: Arc<Vec<Operation>>,
21}
22
23impl ControlBody {
24 pub fn new(operations: Vec<Operation>) -> Self {
26 Self {
27 operations: Arc::new(operations),
28 }
29 }
30
31 pub fn operations(&self) -> &[Operation] {
33 self.operations.as_slice()
34 }
35
36 pub fn used_qubits(&self) -> BTreeSet<Qubit> {
38 let mut qubits = BTreeSet::new();
39 for operation in self.operations() {
40 qubits.extend(operation.qubits.iter().copied());
41 }
42 qubits
43 }
44
45 pub fn has_measurement(&self) -> bool {
47 self.operations()
48 .iter()
49 .any(|operation| operation.instruction.has_measurement())
50 }
51
52 pub fn reads_value(&self, value: ClassicalValue) -> bool {
54 self.operations()
55 .iter()
56 .any(|operation| operation.instruction.reads_value(value))
57 }
58}
59
60impl From<Vec<Operation>> for ControlBody {
61 fn from(operations: Vec<Operation>) -> Self {
62 Self::new(operations)
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::ControlBody;
69 use crate::circuit::{
70 CircuitId, ClassicalDataOp, ClassicalExpr, ClassicalType, ClassicalValue,
71 ControlBody as Body, IfOp, Instruction, Operation, Qubit, StandardGate,
72 };
73 use smallvec::smallvec;
74
75 #[test]
76 fn body_reports_directly_used_qubits() {
77 let body = ControlBody::new(vec![
78 Operation {
79 instruction: Instruction::Standard(StandardGate::CX),
80 qubits: smallvec![Qubit::new(0), Qubit::new(2)],
81 params: smallvec![],
82 label: None,
83 },
84 Operation {
85 instruction: Instruction::Standard(StandardGate::H),
86 qubits: smallvec![Qubit::new(1)],
87 params: smallvec![],
88 label: None,
89 },
90 ]);
91
92 let qubits = body.used_qubits();
93 assert_eq!(qubits.len(), 3);
94 assert!(qubits.contains(&Qubit::new(0)));
95 assert!(qubits.contains(&Qubit::new(1)));
96 assert!(qubits.contains(&Qubit::new(2)));
97 }
98
99 #[test]
100 fn body_reports_nested_measurements() {
101 let value = ClassicalValue::new(CircuitId::new(), 0, ClassicalType::Bit);
102 let inner = Body::new(vec![Operation {
103 instruction: Instruction::ClassicalData(ClassicalDataOp::MeasureBit { result: value }),
104 qubits: smallvec![Qubit::new(0)],
105 params: smallvec![],
106 label: None,
107 }]);
108 let op = IfOp::new(ClassicalExpr::bool_literal(true), inner, None).unwrap();
109 let body = ControlBody::new(vec![Operation {
110 instruction: Instruction::ClassicalControl(super::super::ClassicalControlOp::If(op)),
111 qubits: smallvec![],
112 params: smallvec![],
113 label: None,
114 }]);
115
116 assert!(body.has_measurement());
117 }
118
119 #[test]
120 fn body_reports_nested_value_reads() {
121 let circuit_id = CircuitId::new();
122 let value = ClassicalValue::new(circuit_id, 0, ClassicalType::Bit);
123 let target = crate::circuit::ClassicalVar::new(circuit_id, 1, ClassicalType::Bit);
124 let inner = Body::new(vec![Operation {
125 instruction: Instruction::ClassicalData(ClassicalDataOp::Store {
126 target,
127 value: value.expr(),
128 }),
129 qubits: smallvec![],
130 params: smallvec![],
131 label: None,
132 }]);
133 let op = IfOp::new(ClassicalExpr::bool_literal(true), inner, None).unwrap();
134 let body = ControlBody::new(vec![Operation {
135 instruction: Instruction::ClassicalControl(super::super::ClassicalControlOp::If(op)),
136 qubits: smallvec![],
137 params: smallvec![],
138 label: None,
139 }]);
140
141 assert!(body.reads_value(value));
142 }
143}