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, Eq)]
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 #[must_use]
84 pub const fn equals(lhs: ClassicalValue, rhs: ClassicalValue) -> Self {
85 Self {
86 lhs,
87 op: ComparisonOp::Equal,
88 rhs,
89 }
90 }
91
92 #[must_use]
94 pub fn register_equals(register: &str, value: u64) -> Self {
95 Self {
96 lhs: ClassicalValue::Register(register.to_string()),
97 op: ComparisonOp::Equal,
98 rhs: ClassicalValue::Integer(value),
99 }
100 }
101}
102
103#[derive(Debug, Clone)]
105pub struct MeasureOp {
106 pub qubit: QubitId,
108 pub cbit: ClassicalBit,
110}
111
112impl MeasureOp {
113 #[must_use]
115 pub fn new(qubit: QubitId, register: &str, bit_index: usize) -> Self {
116 Self {
117 qubit,
118 cbit: ClassicalBit {
119 register: register.to_string(),
120 index: bit_index,
121 },
122 }
123 }
124}
125
126pub struct ConditionalGate {
128 pub condition: ClassicalCondition,
130 pub gate: Box<dyn GateOp>,
132}
133
134impl fmt::Debug for ConditionalGate {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 f.debug_struct("ConditionalGate")
137 .field("condition", &self.condition)
138 .field("gate", &self.gate.name())
139 .finish()
140 }
141}
142
143#[derive(Debug)]
145pub enum ClassicalOp {
146 Measure(MeasureOp),
148 Reset(String),
150 Conditional(ConditionalGate),
152 Compute {
154 output: String,
156 op: String,
158 inputs: Vec<String>,
160 },
161}
162
163pub struct ClassicalCircuit<const N: usize> {
165 pub classical_registers: HashMap<String, ClassicalRegister>,
167 pub operations: Vec<CircuitOp>,
169}
170
171pub enum CircuitOp {
173 Quantum(Box<dyn GateOp>),
175 Classical(ClassicalOp),
177}
178
179impl<const N: usize> Default for ClassicalCircuit<N> {
180 fn default() -> Self {
181 Self::new()
182 }
183}
184
185impl<const N: usize> ClassicalCircuit<N> {
186 #[must_use]
188 pub fn new() -> Self {
189 Self {
190 classical_registers: HashMap::new(),
191 operations: Vec::new(),
192 }
193 }
194
195 pub fn add_classical_register(&mut self, name: &str, size: usize) -> QuantRS2Result<()> {
197 if self.classical_registers.contains_key(name) {
198 return Err(QuantRS2Error::InvalidInput(format!(
199 "Classical register '{name}' already exists"
200 )));
201 }
202
203 self.classical_registers
204 .insert(name.to_string(), ClassicalRegister::new(name, size));
205 Ok(())
206 }
207
208 pub fn add_gate<G: GateOp + 'static>(&mut self, gate: G) -> QuantRS2Result<()> {
210 for qubit in gate.qubits() {
212 if qubit.id() as usize >= N {
213 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
214 }
215 }
216
217 self.operations.push(CircuitOp::Quantum(Box::new(gate)));
218 Ok(())
219 }
220
221 pub fn measure(&mut self, qubit: QubitId, register: &str, bit: usize) -> QuantRS2Result<()> {
223 if qubit.id() as usize >= N {
225 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
226 }
227
228 let creg = self.classical_registers.get(register).ok_or_else(|| {
230 QuantRS2Error::InvalidInput(format!("Classical register '{register}' not found"))
231 })?;
232
233 if bit >= creg.size {
234 return Err(QuantRS2Error::InvalidInput(format!(
235 "Bit index {} out of range for register '{}' (size: {})",
236 bit, register, creg.size
237 )));
238 }
239
240 self.operations
241 .push(CircuitOp::Classical(ClassicalOp::Measure(MeasureOp::new(
242 qubit, register, bit,
243 ))));
244 Ok(())
245 }
246
247 pub fn add_conditional<G: GateOp + 'static>(
268 &mut self,
269 condition: ClassicalCondition,
270 gate: G,
271 ) -> QuantRS2Result<()> {
272 for qubit in gate.qubits() {
274 if qubit.id() as usize >= N {
275 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
276 }
277 }
278
279 self.validate_classical_value(&condition.lhs)?;
281 self.validate_classical_value(&condition.rhs)?;
282
283 self.operations
284 .push(CircuitOp::Classical(ClassicalOp::Conditional(
285 ConditionalGate {
286 condition,
287 gate: Box::new(gate),
288 },
289 )));
290 Ok(())
291 }
292
293 fn validate_classical_value(&self, value: &ClassicalValue) -> QuantRS2Result<()> {
295 match value {
296 ClassicalValue::Register(register_name) => {
297 if !self.classical_registers.contains_key(register_name) {
298 return Err(QuantRS2Error::InvalidInput(format!(
299 "Classical register '{register_name}' not found. Available registers: {:?}",
300 self.classical_registers.keys().collect::<Vec<_>>()
301 )));
302 }
303 }
304 ClassicalValue::Bit(_) | ClassicalValue::Integer(_) => {
305 }
307 }
308 Ok(())
309 }
310
311 pub fn reset_classical(&mut self, register: &str) -> QuantRS2Result<()> {
313 if !self.classical_registers.contains_key(register) {
314 return Err(QuantRS2Error::InvalidInput(format!(
315 "Classical register '{register}' not found"
316 )));
317 }
318
319 self.operations
320 .push(CircuitOp::Classical(ClassicalOp::Reset(
321 register.to_string(),
322 )));
323 Ok(())
324 }
325
326 #[must_use]
328 pub fn num_operations(&self) -> usize {
329 self.operations.len()
330 }
331}
332
333pub struct ClassicalCircuitBuilder<const N: usize> {
335 circuit: ClassicalCircuit<N>,
336}
337
338impl<const N: usize> Default for ClassicalCircuitBuilder<N> {
339 fn default() -> Self {
340 Self::new()
341 }
342}
343
344impl<const N: usize> ClassicalCircuitBuilder<N> {
345 #[must_use]
347 pub fn new() -> Self {
348 Self {
349 circuit: ClassicalCircuit::new(),
350 }
351 }
352
353 pub fn classical_register(mut self, name: &str, size: usize) -> QuantRS2Result<Self> {
355 self.circuit.add_classical_register(name, size)?;
356 Ok(self)
357 }
358
359 pub fn gate<G: GateOp + 'static>(mut self, gate: G) -> QuantRS2Result<Self> {
361 self.circuit.add_gate(gate)?;
362 Ok(self)
363 }
364
365 pub fn measure(mut self, qubit: QubitId, register: &str, bit: usize) -> QuantRS2Result<Self> {
367 self.circuit.measure(qubit, register, bit)?;
368 Ok(self)
369 }
370
371 pub fn conditional<G: GateOp + 'static>(
373 mut self,
374 condition: ClassicalCondition,
375 gate: G,
376 ) -> QuantRS2Result<Self> {
377 self.circuit.add_conditional(condition, gate)?;
378 Ok(self)
379 }
380
381 #[must_use]
383 pub fn build(self) -> ClassicalCircuit<N> {
384 self.circuit
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391 use quantrs2_core::gate::single::PauliX;
392
393 #[test]
394 fn test_classical_register() {
395 let reg = ClassicalRegister::new("c", 3);
396 assert_eq!(reg.name, "c");
397 assert_eq!(reg.size, 3);
398 }
399
400 #[test]
401 fn test_classical_condition() {
402 let cond = ClassicalCondition::register_equals("c", 1);
403 assert_eq!(cond.op, ComparisonOp::Equal);
404
405 match &cond.lhs {
406 ClassicalValue::Register(name) => assert_eq!(name, "c"),
407 _ => panic!("Expected Register variant"),
408 }
409
410 match &cond.rhs {
411 ClassicalValue::Integer(val) => assert_eq!(*val, 1),
412 _ => panic!("Expected Integer variant"),
413 }
414 }
415
416 #[test]
417 fn test_classical_circuit_builder() {
418 let circuit = ClassicalCircuitBuilder::<2>::new()
419 .classical_register("c", 2)
420 .expect("Failed to add classical register")
421 .gate(PauliX { target: QubitId(0) })
422 .expect("Failed to add PauliX gate")
423 .measure(QubitId(0), "c", 0)
424 .expect("Failed to add measurement")
425 .conditional(
426 ClassicalCondition::register_equals("c", 1),
427 PauliX { target: QubitId(1) },
428 )
429 .expect("Failed to add conditional gate")
430 .build();
431
432 assert_eq!(circuit.classical_registers.len(), 1);
433 assert_eq!(circuit.num_operations(), 3);
434 }
435
436 #[test]
437 fn test_conditional_validation_invalid_register() {
438 let mut circuit = ClassicalCircuit::<2>::new();
440 circuit
441 .add_classical_register("measurement", 1)
442 .expect("Failed to add classical register");
443
444 let condition = ClassicalCondition::register_equals("nonexistent", 1);
446 let result = circuit.add_conditional(condition, PauliX { target: QubitId(0) });
447
448 assert!(result.is_err());
449 match result {
450 Err(QuantRS2Error::InvalidInput(msg)) => {
451 assert!(msg.contains("nonexistent"));
452 assert!(msg.contains("not found"));
453 }
454 _ => panic!("Expected InvalidInput error"),
455 }
456 }
457
458 #[test]
459 fn test_conditional_validation_valid_register() {
460 let mut circuit = ClassicalCircuit::<2>::new();
462 circuit
463 .add_classical_register("measurement", 1)
464 .expect("Failed to add classical register");
465 circuit
466 .measure(QubitId(0), "measurement", 0)
467 .expect("Failed to add measurement");
468
469 let condition = ClassicalCondition::register_equals("measurement", 1);
471 let result = circuit.add_conditional(condition, PauliX { target: QubitId(1) });
472
473 assert!(result.is_ok());
474 assert_eq!(circuit.num_operations(), 2); }
476}