cqlib_core/circuit/control_flow/
switch_op.rs1use super::ControlBody;
14use crate::circuit::classical_expr::ClassicalExpr;
15use crate::circuit::{CircuitError, ClassicalValue, ClassicalVar, Qubit};
16use std::collections::BTreeSet;
17
18#[derive(Debug, Clone, PartialEq)]
20pub struct SwitchCase {
21 value: u128,
22 body: ControlBody,
23}
24
25impl SwitchCase {
26 pub fn new(value: u128, body: ControlBody) -> Self {
28 Self { value, body }
29 }
30
31 pub fn value(&self) -> u128 {
33 self.value
34 }
35
36 pub fn body(&self) -> &ControlBody {
38 &self.body
39 }
40}
41
42#[derive(Debug, Clone, PartialEq)]
44pub struct SwitchOp {
45 target: ClassicalExpr,
46 cases: Box<[SwitchCase]>,
47 default: Option<ControlBody>,
48}
49
50impl SwitchOp {
51 pub fn new(
53 target: ClassicalExpr,
54 cases: Vec<SwitchCase>,
55 default: Option<ControlBody>,
56 ) -> Result<Self, CircuitError> {
57 super::validate_switch(&target, cases.iter().map(|case| case.value))?;
58
59 Ok(Self {
60 target,
61 cases: cases.into_boxed_slice(),
62 default,
63 })
64 }
65
66 pub fn target(&self) -> &ClassicalExpr {
68 &self.target
69 }
70
71 pub fn cases(&self) -> &[SwitchCase] {
73 &self.cases
74 }
75
76 pub fn default(&self) -> Option<&ControlBody> {
78 self.default.as_ref()
79 }
80
81 pub fn classical_var_reads(&self) -> BTreeSet<ClassicalVar> {
83 self.target.vars()
84 }
85
86 pub fn classical_value_reads(&self) -> BTreeSet<ClassicalValue> {
88 self.target.values()
89 }
90
91 pub fn used_qubits(&self) -> BTreeSet<Qubit> {
93 let mut qubits = BTreeSet::new();
94 for case in self.cases.iter() {
95 qubits.extend(case.body.used_qubits());
96 }
97 if let Some(default) = &self.default {
98 qubits.extend(default.used_qubits());
99 }
100 qubits
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::{SwitchCase, SwitchOp};
107 use crate::circuit::{CircuitId, ClassicalExpr, ClassicalType, ClassicalValue, ControlBody};
108
109 #[test]
110 fn switch_requires_uint_target_and_valid_unique_cases() {
111 assert!(
112 SwitchOp::new(
113 ClassicalExpr::uint_literal(3, 0).unwrap(),
114 vec![
115 SwitchCase::new(1, ControlBody::new(vec![])),
116 SwitchCase::new(7, ControlBody::new(vec![])),
117 ],
118 None,
119 )
120 .is_ok()
121 );
122
123 assert!(
124 SwitchOp::new(ClassicalExpr::bit_vec_literal(3, 0).unwrap(), vec![], None,).is_err()
125 );
126 assert!(
127 SwitchOp::new(
128 ClassicalExpr::uint_literal(3, 0).unwrap(),
129 vec![SwitchCase::new(8, ControlBody::new(vec![]))],
130 None,
131 )
132 .is_err()
133 );
134 assert!(
135 SwitchOp::new(
136 ClassicalExpr::uint_literal(3, 0).unwrap(),
137 vec![
138 SwitchCase::new(1, ControlBody::new(vec![])),
139 SwitchCase::new(1, ControlBody::new(vec![])),
140 ],
141 None,
142 )
143 .is_err()
144 );
145 }
146
147 #[test]
148 fn switch_reports_target_value_reads() {
149 let value = ClassicalValue::new(CircuitId::new(), 5, ClassicalType::uint(3).unwrap());
150 let op = SwitchOp::new(value.expr(), vec![], None).unwrap();
151
152 assert!(op.classical_var_reads().is_empty());
153 assert!(op.classical_value_reads().contains(&value));
154 }
155}