Skip to main content

everett/backend/
statevector.rs

1//! The dense statevector backend.
2
3use super::{Backend, drive};
4use crate::circuit::Circuit;
5use crate::gate::{Gate1, Gate2};
6use crate::kernel;
7use crate::measure::measure_qubit;
8use crate::rng::Rng;
9use crate::state::State;
10
11/// Simulates a circuit by evolving a dense [`State`] of `2^n` amplitudes.
12///
13/// # Examples
14///
15/// ```
16/// use everett::prelude::*;
17///
18/// let mut c = Circuit::new(1);
19/// c.h(0);
20/// let exec = StateVectorBackend::run(&c)?;
21/// // |+> has equal probability on |0> and |1>.
22/// assert!((exec.state().probability(0) - 0.5).abs() < 1e-12);
23/// # Ok::<(), everett::Error>(())
24/// ```
25pub struct StateVectorBackend {
26    state: State,
27    rng: Rng,
28}
29
30/// The result of running a circuit: the final state and classical register.
31#[derive(Clone, Debug)]
32pub struct Execution {
33    state: State,
34    classical: Vec<bool>,
35}
36
37impl Execution {
38    /// The final statevector.
39    #[must_use]
40    pub fn state(&self) -> &State {
41        &self.state
42    }
43
44    /// The final classical register, indexed by [`crate::ClassicalBit`].
45    #[must_use]
46    pub fn classical(&self) -> &[bool] {
47        &self.classical
48    }
49
50    /// Consumes the execution, returning the owned final state.
51    #[must_use]
52    pub fn into_state(self) -> State {
53        self.state
54    }
55}
56
57impl StateVectorBackend {
58    /// Runs `circuit` from the all-zeros state with a default RNG seed.
59    ///
60    /// Because the seed is fixed, runs are reproducible. Use [`Self::run_seeded`]
61    /// to vary the measurement stream.
62    ///
63    /// # Errors
64    ///
65    /// Returns an error if the circuit is malformed (e.g. an out-of-range qubit
66    /// index). Such circuits are normally rejected at build time; this is the
67    /// final guard.
68    pub fn run(circuit: &Circuit) -> crate::Result<Execution> {
69        Self::run_seeded(circuit, 0)
70    }
71
72    /// Runs `circuit` from the all-zeros state with the given RNG seed.
73    ///
74    /// # Errors
75    ///
76    /// See [`Self::run`].
77    pub fn run_seeded(circuit: &Circuit, seed: u64) -> crate::Result<Execution> {
78        circuit.validate()?;
79        let mut backend = Self {
80            state: State::zero(circuit.num_qubits()),
81            rng: Rng::seed_from_u64(seed),
82        };
83        let classical = drive(&mut backend, circuit.ops(), circuit.num_classical());
84        Ok(Execution {
85            state: backend.state,
86            classical,
87        })
88    }
89}
90
91impl Backend for StateVectorBackend {
92    fn apply_1q(&mut self, gate: &Gate1, target: usize) {
93        kernel::apply_1q(self.state.amplitudes_mut(), target, gate);
94    }
95
96    fn apply_2q(&mut self, gate: &Gate2, a: usize, b: usize) {
97        kernel::apply_2q(self.state.amplitudes_mut(), a, b, gate);
98    }
99
100    fn apply_controlled(&mut self, controls: &[usize], gate: &Gate1, target: usize) {
101        kernel::apply_controlled_1q(self.state.amplitudes_mut(), controls, target, gate);
102    }
103
104    fn measure(&mut self, qubit: usize) -> bool {
105        measure_qubit(&mut self.state, qubit, &mut self.rng)
106    }
107}