stabilizer_ch_form_rust/form/
project.rs

1use crate::{
2    StabilizerCHForm,
3    error::{Error, Result},
4    form::types::{PhaseFactor, QubitState},
5};
6
7impl StabilizerCHForm {
8    /// Projects a qubit onto a computational basis state (`|0>` or `|1>`).
9    ///
10    /// This operation modifies the stabilizer state in place.
11    ///
12    /// In a stabilizer state, measuring a qubit in the computational basis yields either a
13    /// deterministic outcome (`|0>` or `|1>`) or a perfectly random one (50% probability for each).
14    /// This function attempts to force the qubit into the specified `outcome`, succeeding if the
15    /// projection is physically possible.
16    ///
17    /// ## Arguments
18    /// * `qarg`: The index of the qubit to project.
19    /// * `outcome`: The desired basis state to project onto (`false` for `|0>`, `true` for `|1>`).
20    ///
21    /// ## Returns
22    /// A `Result` indicating the outcome of the projection:
23    /// * `Ok(true)` if the projection was **deterministic**. This means the qubit was already
24    ///   in the desired state. The stabilizer state is unchanged.
25    /// * `Ok(false)` if the projection was **non-deterministic** (probabilistic). This means the
26    ///   qubit was in a superposition and has now been collapsed to the desired state. The
27    ///   stabilizer state has been updated.
28    ///
29    /// ## Errors
30    /// Returns an `ChFormError` if the projection is impossible. This occurs when the qubit has a
31    /// deterministic value that is orthogonal to the desired `outcome` (e.g., attempting to
32    /// project a qubit in state `|0>` onto `|1>`).
33    pub fn project(&mut self, qarg: usize, outcome: bool) -> Result<bool> {
34        if qarg >= self.n {
35            return Err(Error::QubitIndexOutOfBounds(qarg, self.n));
36        }
37
38        let qubit_state = self.get_qubit_state(qarg)?;
39        match qubit_state {
40            QubitState::Determined(value) => {
41                if value != outcome {
42                    Err(Error::ImpossibleProjection {
43                        qubit_index: qarg,
44                        desired: outcome,
45                    })
46                } else {
47                    // No change needed if the state is already determined and matches the outcome.
48                    Ok(true)
49                }
50            }
51            QubitState::Superposition => {
52                // Collapse the state to the desired outcome.
53                // Applys the operator: (I + (-1)^(1-outcome) * Z_qarg) / 2
54                // Z_arg application can be represented as:
55                //   Z_qarg U_C U_H |s> = (-1)^α |t>
56                // according to eq.(48) and (49) in arXiv:1808.00128
57                let g_row = self.mat_g.row(qarg);
58                let vec_t = &(&g_row & &self.vec_v) ^ &self.vec_s;
59                let alpha = g_row
60                    .iter()
61                    .zip(&self.vec_v)
62                    .zip(&self.vec_s)
63                    .filter(|&((&g, &v), &s)| g && !v && s)
64                    .count()
65                    % 2
66                    != 0;
67                let delta = if alpha ^ outcome {
68                    PhaseFactor::MINUS_ONE
69                } else {
70                    PhaseFactor::PLUS_ONE
71                };
72                self._resolve_superposition(&self.vec_s.to_owned(), &vec_t, delta)?;
73                Ok(false)
74            }
75        }
76    }
77}