1use quantrs2_core::{
7 error::{QuantRS2Error, QuantRS2Result},
8 gate::GateOp,
9 qubit::QubitId,
10};
11use std::collections::HashMap;
12use std::fmt;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16pub struct ClassicalRegister {
17 pub name: String,
19 pub size: usize,
21}
22
23impl ClassicalRegister {
24 pub fn new(name: impl Into<String>, size: usize) -> Self {
26 Self {
27 name: name.into(),
28 size,
29 }
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
35pub struct ClassicalBit {
36 pub register: String,
38 pub index: usize,
40}
41
42#[derive(Debug, Clone, PartialEq)]
44pub enum ClassicalValue {
45 Bit(bool),
47 Integer(u64),
49 Register(String),
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum ComparisonOp {
56 Equal,
58 NotEqual,
60 Less,
62 LessEqual,
64 Greater,
66 GreaterEqual,
68}
69
70#[derive(Debug, Clone)]
72pub struct ClassicalCondition {
73 pub lhs: ClassicalValue,
75 pub op: ComparisonOp,
77 pub rhs: ClassicalValue,
79}
80
81impl ClassicalCondition {
82 pub fn equals(lhs: ClassicalValue, rhs: ClassicalValue) -> Self {
84 Self {
85 lhs,
86 op: ComparisonOp::Equal,
87 rhs,
88 }
89 }
90
91 pub fn register_equals(register: &str, value: u64) -> Self {
93 Self {
94 lhs: ClassicalValue::Register(register.to_string()),
95 op: ComparisonOp::Equal,
96 rhs: ClassicalValue::Integer(value),
97 }
98 }
99}
100
101#[derive(Debug, Clone)]
103pub struct MeasureOp {
104 pub qubit: QubitId,
106 pub cbit: ClassicalBit,
108}
109
110impl MeasureOp {
111 pub fn new(qubit: QubitId, register: &str, bit_index: usize) -> Self {
113 Self {
114 qubit,
115 cbit: ClassicalBit {
116 register: register.to_string(),
117 index: bit_index,
118 },
119 }
120 }
121}
122
123pub struct ConditionalGate {
125 pub condition: ClassicalCondition,
127 pub gate: Box<dyn GateOp>,
129}
130
131impl fmt::Debug for ConditionalGate {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 f.debug_struct("ConditionalGate")
134 .field("condition", &self.condition)
135 .field("gate", &self.gate.name())
136 .finish()
137 }
138}
139
140#[derive(Debug)]
142pub enum ClassicalOp {
143 Measure(MeasureOp),
145 Reset(String),
147 Conditional(ConditionalGate),
149 Compute {
151 output: String,
153 op: String,
155 inputs: Vec<String>,
157 },
158}
159
160pub struct ClassicalCircuit<const N: usize> {
162 pub classical_registers: HashMap<String, ClassicalRegister>,
164 pub operations: Vec<CircuitOp>,
166}
167
168pub enum CircuitOp {
170 Quantum(Box<dyn GateOp>),
172 Classical(ClassicalOp),
174}
175
176impl<const N: usize> ClassicalCircuit<N> {
177 pub fn new() -> Self {
179 Self {
180 classical_registers: HashMap::new(),
181 operations: Vec::new(),
182 }
183 }
184
185 pub fn add_classical_register(&mut self, name: &str, size: usize) -> QuantRS2Result<()> {
187 if self.classical_registers.contains_key(name) {
188 return Err(QuantRS2Error::InvalidInput(format!(
189 "Classical register '{}' already exists",
190 name
191 )));
192 }
193
194 self.classical_registers
195 .insert(name.to_string(), ClassicalRegister::new(name, size));
196 Ok(())
197 }
198
199 pub fn add_gate<G: GateOp + 'static>(&mut self, gate: G) -> QuantRS2Result<()> {
201 for qubit in gate.qubits() {
203 if qubit.id() as usize >= N {
204 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
205 }
206 }
207
208 self.operations.push(CircuitOp::Quantum(Box::new(gate)));
209 Ok(())
210 }
211
212 pub fn measure(&mut self, qubit: QubitId, register: &str, bit: usize) -> QuantRS2Result<()> {
214 if qubit.id() as usize >= N {
216 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
217 }
218
219 let creg = self.classical_registers.get(register).ok_or_else(|| {
221 QuantRS2Error::InvalidInput(format!("Classical register '{}' not found", register))
222 })?;
223
224 if bit >= creg.size {
225 return Err(QuantRS2Error::InvalidInput(format!(
226 "Bit index {} out of range for register '{}' (size: {})",
227 bit, register, creg.size
228 )));
229 }
230
231 self.operations
232 .push(CircuitOp::Classical(ClassicalOp::Measure(MeasureOp::new(
233 qubit, register, bit,
234 ))));
235 Ok(())
236 }
237
238 pub fn add_conditional<G: GateOp + 'static>(
240 &mut self,
241 condition: ClassicalCondition,
242 gate: G,
243 ) -> QuantRS2Result<()> {
244 for qubit in gate.qubits() {
246 if qubit.id() as usize >= N {
247 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
248 }
249 }
250
251 self.operations
254 .push(CircuitOp::Classical(ClassicalOp::Conditional(
255 ConditionalGate {
256 condition,
257 gate: Box::new(gate),
258 },
259 )));
260 Ok(())
261 }
262
263 pub fn reset_classical(&mut self, register: &str) -> QuantRS2Result<()> {
265 if !self.classical_registers.contains_key(register) {
266 return Err(QuantRS2Error::InvalidInput(format!(
267 "Classical register '{}' not found",
268 register
269 )));
270 }
271
272 self.operations
273 .push(CircuitOp::Classical(ClassicalOp::Reset(
274 register.to_string(),
275 )));
276 Ok(())
277 }
278
279 pub fn num_operations(&self) -> usize {
281 self.operations.len()
282 }
283}
284
285pub struct ClassicalCircuitBuilder<const N: usize> {
287 circuit: ClassicalCircuit<N>,
288}
289
290impl<const N: usize> ClassicalCircuitBuilder<N> {
291 pub fn new() -> Self {
293 Self {
294 circuit: ClassicalCircuit::new(),
295 }
296 }
297
298 pub fn classical_register(mut self, name: &str, size: usize) -> QuantRS2Result<Self> {
300 self.circuit.add_classical_register(name, size)?;
301 Ok(self)
302 }
303
304 pub fn gate<G: GateOp + 'static>(mut self, gate: G) -> QuantRS2Result<Self> {
306 self.circuit.add_gate(gate)?;
307 Ok(self)
308 }
309
310 pub fn measure(mut self, qubit: QubitId, register: &str, bit: usize) -> QuantRS2Result<Self> {
312 self.circuit.measure(qubit, register, bit)?;
313 Ok(self)
314 }
315
316 pub fn conditional<G: GateOp + 'static>(
318 mut self,
319 condition: ClassicalCondition,
320 gate: G,
321 ) -> QuantRS2Result<Self> {
322 self.circuit.add_conditional(condition, gate)?;
323 Ok(self)
324 }
325
326 pub fn build(self) -> ClassicalCircuit<N> {
328 self.circuit
329 }
330}
331
332#[cfg(test)]
333mod tests {
334 use super::*;
335 use quantrs2_core::gate::single::PauliX;
336
337 #[test]
338 fn test_classical_register() {
339 let reg = ClassicalRegister::new("c", 3);
340 assert_eq!(reg.name, "c");
341 assert_eq!(reg.size, 3);
342 }
343
344 #[test]
345 fn test_classical_condition() {
346 let cond = ClassicalCondition::register_equals("c", 1);
347 assert_eq!(cond.op, ComparisonOp::Equal);
348
349 match &cond.lhs {
350 ClassicalValue::Register(name) => assert_eq!(name, "c"),
351 _ => panic!("Expected Register variant"),
352 }
353
354 match &cond.rhs {
355 ClassicalValue::Integer(val) => assert_eq!(*val, 1),
356 _ => panic!("Expected Integer variant"),
357 }
358 }
359
360 #[test]
361 fn test_classical_circuit_builder() {
362 let circuit = ClassicalCircuitBuilder::<2>::new()
363 .classical_register("c", 2)
364 .unwrap()
365 .gate(PauliX { target: QubitId(0) })
366 .unwrap()
367 .measure(QubitId(0), "c", 0)
368 .unwrap()
369 .conditional(
370 ClassicalCondition::register_equals("c", 1),
371 PauliX { target: QubitId(1) },
372 )
373 .unwrap()
374 .build();
375
376 assert_eq!(circuit.classical_registers.len(), 1);
377 assert_eq!(circuit.num_operations(), 3);
378 }
379}