1use crate::builder::Circuit;
7use crate::classical::{ClassicalCondition, ClassicalRegister};
8use quantrs2_core::{
9 error::{QuantRS2Error, QuantRS2Result},
10 gate::GateOp,
11 qubit::QubitId,
12};
13use std::collections::HashMap;
14use std::sync::Arc;
15
16#[derive(Debug, Clone)]
18pub struct Measurement {
19 pub qubit: QubitId,
21 pub target_bit: usize,
23 pub label: Option<String>,
25}
26
27impl Measurement {
28 #[must_use]
30 pub const fn new(qubit: QubitId, target_bit: usize) -> Self {
31 Self {
32 qubit,
33 target_bit,
34 label: None,
35 }
36 }
37
38 #[must_use]
40 pub fn with_label(mut self, label: String) -> Self {
41 self.label = Some(label);
42 self
43 }
44}
45
46#[derive(Debug, Clone)]
48pub struct FeedForward {
49 pub condition: ClassicalCondition,
51 pub gate: Box<dyn GateOp>,
53 pub else_gate: Option<Box<dyn GateOp>>,
55}
56
57impl FeedForward {
58 #[must_use]
60 pub fn new(condition: ClassicalCondition, gate: Box<dyn GateOp>) -> Self {
61 Self {
62 condition,
63 gate,
64 else_gate: None,
65 }
66 }
67
68 #[must_use]
70 pub fn with_else(mut self, else_gate: Box<dyn GateOp>) -> Self {
71 self.else_gate = Some(else_gate);
72 self
73 }
74}
75
76#[derive(Debug, Clone)]
78pub enum CircuitOp {
79 Gate(Box<dyn GateOp>),
81 Measure(Measurement),
83 FeedForward(FeedForward),
85 Barrier(Vec<QubitId>),
87 Reset(QubitId),
89}
90
91pub struct MeasurementCircuit<const N: usize> {
93 operations: Vec<CircuitOp>,
95 classical_registers: HashMap<String, ClassicalRegister>,
97 measurement_count: usize,
99 current_bit: usize,
101}
102
103impl<const N: usize> Default for MeasurementCircuit<N> {
104 fn default() -> Self {
105 Self::new()
106 }
107}
108
109impl<const N: usize> MeasurementCircuit<N> {
110 #[must_use]
112 pub fn new() -> Self {
113 let mut classical_registers = HashMap::new();
114 classical_registers.insert(
115 "default".to_string(),
116 ClassicalRegister::new("default".to_string(), N),
117 );
118
119 Self {
120 operations: Vec::new(),
121 classical_registers,
122 measurement_count: 0,
123 current_bit: 0,
124 }
125 }
126
127 pub fn add_gate(&mut self, gate: Box<dyn GateOp>) -> QuantRS2Result<()> {
129 for qubit in gate.qubits() {
131 if qubit.id() >= N as u32 {
132 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
133 }
134 }
135
136 self.operations.push(CircuitOp::Gate(gate));
137 Ok(())
138 }
139
140 pub fn measure(&mut self, qubit: QubitId) -> QuantRS2Result<usize> {
142 if qubit.id() >= N as u32 {
143 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
144 }
145
146 if self.current_bit >= N {
147 return Err(QuantRS2Error::InvalidInput(
148 "Not enough classical bits for measurement".to_string(),
149 ));
150 }
151
152 let target_bit = self.current_bit;
153 self.current_bit += 1;
154
155 let measurement =
156 Measurement::new(qubit, target_bit).with_label(format!("m{}", self.measurement_count));
157
158 self.operations.push(CircuitOp::Measure(measurement));
159 self.measurement_count += 1;
160
161 Ok(target_bit)
162 }
163
164 pub fn add_conditional(
166 &mut self,
167 condition: ClassicalCondition,
168 gate: Box<dyn GateOp>,
169 ) -> QuantRS2Result<()> {
170 for qubit in gate.qubits() {
175 if qubit.id() >= N as u32 {
176 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
177 }
178 }
179
180 let feed_forward = FeedForward::new(condition, gate);
181 self.operations.push(CircuitOp::FeedForward(feed_forward));
182 Ok(())
183 }
184
185 pub fn add_if_else(
187 &mut self,
188 condition: ClassicalCondition,
189 if_gate: Box<dyn GateOp>,
190 else_gate: Box<dyn GateOp>,
191 ) -> QuantRS2Result<()> {
192 for qubit in if_gate.qubits().iter().chain(else_gate.qubits().iter()) {
194 if qubit.id() >= N as u32 {
195 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
196 }
197 }
198
199 let feed_forward = FeedForward::new(condition, if_gate).with_else(else_gate);
200 self.operations.push(CircuitOp::FeedForward(feed_forward));
201 Ok(())
202 }
203
204 pub fn barrier(&mut self, qubits: Vec<QubitId>) -> QuantRS2Result<()> {
206 for qubit in &qubits {
207 if qubit.id() >= N as u32 {
208 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
209 }
210 }
211
212 self.operations.push(CircuitOp::Barrier(qubits));
213 Ok(())
214 }
215
216 pub fn reset(&mut self, qubit: QubitId) -> QuantRS2Result<()> {
218 if qubit.id() >= N as u32 {
219 return Err(QuantRS2Error::InvalidQubitId(qubit.id()));
220 }
221
222 self.operations.push(CircuitOp::Reset(qubit));
223 Ok(())
224 }
225
226 #[must_use]
228 pub fn num_operations(&self) -> usize {
229 self.operations.len()
230 }
231
232 #[must_use]
234 pub const fn num_measurements(&self) -> usize {
235 self.measurement_count
236 }
237
238 #[must_use]
240 pub fn operations(&self) -> &[CircuitOp] {
241 &self.operations
242 }
243
244 pub fn to_circuit(&self) -> QuantRS2Result<Circuit<N>> {
246 let mut circuit = Circuit::<N>::new();
247
248 for op in &self.operations {
249 match op {
250 CircuitOp::Gate(_)
251 | CircuitOp::Measure(_)
252 | CircuitOp::FeedForward(_)
253 | CircuitOp::Barrier(_)
254 | CircuitOp::Reset(_) => {
255 }
257 }
258 }
259
260 Ok(circuit)
261 }
262
263 #[must_use]
265 pub fn analyze_dependencies(&self) -> MeasurementDependencies {
266 let mut deps = MeasurementDependencies::new();
267 let mut measurement_map = HashMap::new();
268
269 for (i, op) in self.operations.iter().enumerate() {
271 if let CircuitOp::Measure(m) = op {
272 measurement_map.insert(m.target_bit, i);
273 deps.measurements.push((i, m.clone()));
274 }
275 }
276
277 for (i, op) in self.operations.iter().enumerate() {
279 if let CircuitOp::FeedForward(_ff) = op {
280 if !measurement_map.is_empty() {
283 let last_measurement = measurement_map.len() - 1;
284 deps.feed_forward_deps.push((last_measurement, i));
285 }
286 }
287 }
288
289 deps
290 }
291}
292
293#[derive(Debug)]
295pub struct MeasurementDependencies {
296 pub measurements: Vec<(usize, Measurement)>,
298 pub feed_forward_deps: Vec<(usize, usize)>,
300}
301
302impl MeasurementDependencies {
303 const fn new() -> Self {
304 Self {
305 measurements: Vec::new(),
306 feed_forward_deps: Vec::new(),
307 }
308 }
309
310 #[must_use]
312 pub fn has_feed_forward(&self) -> bool {
313 !self.feed_forward_deps.is_empty()
314 }
315
316 #[must_use]
318 pub fn num_measurements(&self) -> usize {
319 self.measurements.len()
320 }
321}
322
323pub struct MeasurementCircuitBuilder<const N: usize> {
325 circuit: MeasurementCircuit<N>,
326}
327
328impl<const N: usize> Default for MeasurementCircuitBuilder<N> {
329 fn default() -> Self {
330 Self::new()
331 }
332}
333
334impl<const N: usize> MeasurementCircuitBuilder<N> {
335 #[must_use]
337 pub fn new() -> Self {
338 Self {
339 circuit: MeasurementCircuit::new(),
340 }
341 }
342
343 pub fn gate(mut self, gate: Box<dyn GateOp>) -> QuantRS2Result<Self> {
345 self.circuit.add_gate(gate)?;
346 Ok(self)
347 }
348
349 pub fn measure(mut self, qubit: QubitId) -> QuantRS2Result<(Self, usize)> {
351 let bit = self.circuit.measure(qubit)?;
352 Ok((self, bit))
353 }
354
355 pub fn when(
357 mut self,
358 condition: ClassicalCondition,
359 gate: Box<dyn GateOp>,
360 ) -> QuantRS2Result<Self> {
361 self.circuit.add_conditional(condition, gate)?;
362 Ok(self)
363 }
364
365 pub fn if_else(
367 mut self,
368 condition: ClassicalCondition,
369 if_gate: Box<dyn GateOp>,
370 else_gate: Box<dyn GateOp>,
371 ) -> QuantRS2Result<Self> {
372 self.circuit.add_if_else(condition, if_gate, else_gate)?;
373 Ok(self)
374 }
375
376 pub fn barrier(mut self, qubits: Vec<QubitId>) -> QuantRS2Result<Self> {
378 self.circuit.barrier(qubits)?;
379 Ok(self)
380 }
381
382 pub fn reset(mut self, qubit: QubitId) -> QuantRS2Result<Self> {
384 self.circuit.reset(qubit)?;
385 Ok(self)
386 }
387
388 #[must_use]
390 pub fn build(self) -> MeasurementCircuit<N> {
391 self.circuit
392 }
393}
394
395#[cfg(test)]
396mod tests {
397 use super::*;
398 use quantrs2_core::gate::single::{Hadamard, PauliX};
399
400 #[test]
401 fn test_measurement_circuit() {
402 let mut circuit = MeasurementCircuit::<3>::new();
403
404 circuit
406 .add_gate(Box::new(Hadamard { target: QubitId(0) }))
407 .expect("Failed to add Hadamard gate");
408
409 let bit0 = circuit
411 .measure(QubitId(0))
412 .expect("Failed to measure qubit 0");
413 assert_eq!(bit0, 0);
414
415 let condition = ClassicalCondition::equals(
417 crate::classical::ClassicalValue::Integer(bit0 as u64),
418 crate::classical::ClassicalValue::Integer(1),
419 );
420 circuit
421 .add_conditional(condition, Box::new(PauliX { target: QubitId(1) }))
422 .expect("Failed to add conditional X gate");
423
424 assert_eq!(circuit.num_operations(), 3);
425 assert_eq!(circuit.num_measurements(), 1);
426 }
427
428 #[test]
429 fn test_feed_forward() {
430 let mut circuit = MeasurementCircuit::<2>::new();
431
432 circuit
434 .add_gate(Box::new(Hadamard { target: QubitId(0) }))
435 .expect("Failed to add Hadamard gate");
436 circuit
437 .add_gate(Box::new(quantrs2_core::gate::multi::CNOT {
438 control: QubitId(0),
439 target: QubitId(1),
440 }))
441 .expect("Failed to add CNOT gate");
442
443 let bit = circuit
445 .measure(QubitId(0))
446 .expect("Failed to measure qubit 0");
447
448 let condition = ClassicalCondition::equals(
450 crate::classical::ClassicalValue::Integer(bit as u64),
451 crate::classical::ClassicalValue::Integer(1),
452 );
453 circuit
454 .add_conditional(condition, Box::new(PauliX { target: QubitId(1) }))
455 .expect("Failed to add conditional X gate");
456
457 let deps = circuit.analyze_dependencies();
459 assert_eq!(deps.num_measurements(), 1);
460 assert!(deps.has_feed_forward());
461 }
462
463 #[test]
464 fn test_builder_pattern() {
465 let (builder, bit) = MeasurementCircuitBuilder::<2>::new()
466 .gate(Box::new(Hadamard { target: QubitId(0) }))
467 .expect("Failed to add gate")
468 .measure(QubitId(0))
469 .expect("Failed to measure qubit");
470
471 let circuit = builder
472 .when(
473 ClassicalCondition::equals(
474 crate::classical::ClassicalValue::Integer(bit as u64),
475 crate::classical::ClassicalValue::Integer(1),
476 ),
477 Box::new(PauliX { target: QubitId(1) }),
478 )
479 .expect("Failed to add conditional gate")
480 .build();
481
482 assert_eq!(circuit.num_operations(), 3);
483 }
484}