paulistrings/
circuit.rs

1//! [`Circuit<W>`] — an ordered sequence of channels.
2
3#![allow(unused)]
4
5use crate::channel::Channel;
6
7/// A circuit on `num_qubits` qubits, stored as a heterogeneous list of
8/// channels.
9///
10/// Channels are held as `Box<dyn `[`Channel`]`>` rather than a generic enum so
11/// user-defined channel types can be appended at runtime; the engine sees only
12/// the trait. The engine reads the list in order for
13/// [`Direction::Forward`](crate::Direction::Forward) propagation and in
14/// reverse (using each channel's adjoint) for
15/// [`Direction::Heisenberg`](crate::Direction::Heisenberg).
16///
17/// # Examples
18///
19/// ```
20/// use paulistrings::{Circuit, channel::Clifford1Q};
21///
22/// let mut c = Circuit::<1>::new(2);
23/// c.push(Clifford1Q::h(0));
24/// c.push(Clifford1Q::s(1));
25/// assert_eq!(c.len(), 2);
26/// ```
27///
28/// [`Channel`]: crate::Channel
29pub struct Circuit<const W: usize> {
30    /// Number of qubits this circuit acts on. Constrains the support of
31    /// channels that can be pushed.
32    pub num_qubits: usize,
33    /// Channels in application order. Index `0` is applied first under
34    /// [`Direction::Forward`](crate::Direction::Forward).
35    pub channels: Vec<Box<dyn Channel<W>>>,
36}
37
38impl<const W: usize> Circuit<W> {
39    /// Empty circuit on `num_qubits` qubits.
40    pub fn new(num_qubits: usize) -> Self {
41        Self {
42            num_qubits,
43            channels: Vec::new(),
44        }
45    }
46
47    /// Append a channel to the circuit.
48    pub fn push<C: Channel<W> + 'static>(&mut self, c: C) {
49        self.channels.push(Box::new(c));
50    }
51
52    /// Number of channels (gates + noise) currently in the circuit.
53    #[inline]
54    pub fn len(&self) -> usize {
55        self.channels.len()
56    }
57
58    /// `true` iff no channels have been pushed.
59    #[inline]
60    pub fn is_empty(&self) -> bool {
61        self.channels.is_empty()
62    }
63}