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