cqlib_core/circuit/control_flow/
if_op.rs1use super::ControlBody;
14use crate::circuit::classical_expr::ClassicalExpr;
15use crate::circuit::{CircuitError, ClassicalType, ClassicalValue, ClassicalVar, Qubit};
16use std::collections::BTreeSet;
17
18#[derive(Debug, Clone, PartialEq)]
20pub struct IfOp {
21 condition: ClassicalExpr,
22 then_body: ControlBody,
23 else_body: Option<ControlBody>,
24}
25
26impl IfOp {
27 pub fn new(
29 condition: ClassicalExpr,
30 then_body: ControlBody,
31 else_body: Option<ControlBody>,
32 ) -> Result<Self, CircuitError> {
33 if condition.ty() != ClassicalType::Bool {
34 return Err(CircuitError::InvalidOperation(format!(
35 "if condition must be Bool, got {:?}",
36 condition.ty()
37 )));
38 }
39 Ok(Self {
40 condition,
41 then_body,
42 else_body,
43 })
44 }
45
46 pub fn condition(&self) -> &ClassicalExpr {
48 &self.condition
49 }
50
51 pub fn then_body(&self) -> &ControlBody {
53 &self.then_body
54 }
55
56 pub fn else_body(&self) -> Option<&ControlBody> {
58 self.else_body.as_ref()
59 }
60
61 pub fn classical_var_reads(&self) -> BTreeSet<ClassicalVar> {
63 self.condition.vars()
64 }
65
66 pub fn classical_value_reads(&self) -> BTreeSet<ClassicalValue> {
68 self.condition.values()
69 }
70
71 pub fn used_qubits(&self) -> BTreeSet<Qubit> {
73 let mut qubits = self.then_body.used_qubits();
74 if let Some(else_body) = &self.else_body {
75 qubits.extend(else_body.used_qubits());
76 }
77 qubits
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::IfOp;
84 use crate::circuit::{
85 CircuitId, ClassicalExpr, ClassicalType, ClassicalValue, ClassicalVar, ControlBody,
86 };
87
88 #[test]
89 fn if_requires_bool_condition() {
90 let condition = ClassicalExpr::bool_literal(true);
91 let op = IfOp::new(condition, ControlBody::new(vec![]), None).unwrap();
92
93 assert!(op.else_body().is_none());
94 assert!(
95 IfOp::new(
96 ClassicalExpr::bit_literal(true),
97 ControlBody::new(vec![]),
98 None
99 )
100 .is_err()
101 );
102 }
103
104 #[test]
105 fn if_reports_condition_var_reads() {
106 let circuit_id = CircuitId::new();
107 let bit = ClassicalExpr::var(ClassicalVar::new(circuit_id, 3, ClassicalType::Bit));
108 let condition = ClassicalExpr::bit_to_bool(bit).unwrap();
109 let op = IfOp::new(condition, ControlBody::new(vec![]), None).unwrap();
110
111 assert!(op.classical_var_reads().contains(&ClassicalVar::new(
112 circuit_id,
113 3,
114 ClassicalType::Bit
115 )));
116 }
117
118 #[test]
119 fn if_reports_condition_value_reads() {
120 let value = ClassicalValue::new(CircuitId::new(), 4, ClassicalType::Bit);
121 let condition = ClassicalExpr::bit_to_bool(value.expr()).unwrap();
122 let op = IfOp::new(condition, ControlBody::new(vec![]), None).unwrap();
123
124 assert!(op.classical_var_reads().is_empty());
125 assert!(op.classical_value_reads().contains(&value));
126 }
127}