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}