use quantrs2_core::{
error::QuantRS2Result,
gate::{single::Hadamard, GateOp},
qubit::QubitId,
};
use scirs2_core::Complex64;
const T: usize = 3; const N: usize = T + 1; const DIM: usize = 1 << N;
fn main() -> QuantRS2Result<()> {
println!("=== Quantum Phase Estimation: U = RZ(π/4), eigenstate |1⟩ ===\n");
let theta = std::f64::consts::PI / 4.0; let true_phase = 1.0 / 16.0; let n_states = 1u32 << T;
println!("Unitary : U = RZ(π/4)");
println!("Eigenstate: |1⟩ with eigenvalue e^{{iπ/8}}");
println!("True phase: φ = 1/16 = {true_phase:.6}");
println!("Precision qubits: t = {T} → resolution = 1/{n_states}\n");
let mut state = [Complex64::new(0.0, 0.0); DIM];
state[1] = Complex64::new(1.0, 0.0);
let h = Hadamard { target: QubitId(0) };
let h_mat = h.matrix()?;
for q in 0..T {
apply_single_qubit(&mut state, &h_mat, q);
}
for k in 0..T {
let angle = theta * (1u32 << (T - 1 - k)) as f64; apply_controlled_rz_on_eigenstate(&mut state, k, angle);
}
apply_iqft(&mut state, T)?;
let mut probs = [0.0f64; 1 << T];
for (i, amp) in state.iter().enumerate() {
let prec_reg = i >> 1; probs[prec_reg] += amp.norm_sqr();
}
println!("Measurement probabilities (precision register):");
let mut max_prob = 0.0f64;
let mut max_state = 0usize;
for (s, &p) in probs.iter().enumerate() {
let estimated_phase = s as f64 / n_states as f64;
let bar_len = (p * 30.0).round() as usize;
let bar: String = "█".repeat(bar_len);
println!(" |{s:03b}⟩ → φ={estimated_phase:.4} P={p:.4} {bar}");
if p > max_prob {
max_prob = p;
max_state = s;
}
}
let estimated_phase = max_state as f64 / n_states as f64;
println!("\nMost probable readout: |{max_state:03b}⟩ → φ ≈ {estimated_phase:.4}");
println!("True phase : φ = {true_phase:.4}");
println!(
"Error : {:.4}",
(estimated_phase - true_phase).abs()
);
assert!(
max_prob > 0.30,
"Peak probability should be substantial, got {max_prob:.4}"
);
assert!(
probs.iter().sum::<f64>() > 0.99,
"Probabilities should sum to 1"
);
println!("\nOK — Phase estimation completed.");
Ok(())
}
fn apply_controlled_rz_on_eigenstate(state: &mut [Complex64; DIM], ctrl_qubit: usize, angle: f64) {
let ctrl_bit = N - 1 - ctrl_qubit; let eigen_bit = 0usize; let ctrl_mask = 1usize << ctrl_bit;
let eigen_mask = 1usize << eigen_bit;
let phase = Complex64::new(0.0, angle / 2.0).exp();
for (i, amp) in state.iter_mut().enumerate() {
if (i & ctrl_mask != 0) && (i & eigen_mask != 0) {
*amp *= phase;
}
}
}
fn apply_iqft(state: &mut [Complex64; DIM], t: usize) -> QuantRS2Result<()> {
let h = Hadamard { target: QubitId(0) };
let h_mat = h.matrix()?;
for j in (0..t).rev() {
for k in (0..j).rev() {
let angle = -std::f64::consts::PI / (1u32 << (j - k)) as f64;
apply_controlled_phase(state, k, j, angle);
}
apply_single_qubit(state, &h_mat, j);
}
bit_reverse_permutation(state, t);
Ok(())
}
fn apply_controlled_phase(state: &mut [Complex64; DIM], ctrl: usize, target: usize, angle: f64) {
let ctrl_bit = N - 1 - ctrl;
let tgt_bit = N - 1 - target;
let ctrl_mask = 1usize << ctrl_bit;
let tgt_mask = 1usize << tgt_bit;
let phase = Complex64::new(0.0, angle).exp();
for (i, amp) in state.iter_mut().enumerate() {
if (i & ctrl_mask != 0) && (i & tgt_mask != 0) {
*amp *= phase;
}
}
}
fn bit_reverse_permutation(state: &mut [Complex64; DIM], t: usize) {
let mut visited = [false; DIM];
for i in 0..DIM {
if visited[i] {
continue;
}
let top_bits = i >> (N - t); let bottom_bits = i & ((1 << (N - t)) - 1); let rev_top = bit_reverse(top_bits, t);
let j = (rev_top << (N - t)) | bottom_bits;
if j > i {
state.swap(i, j);
}
visited[i] = true;
visited[j] = true;
}
}
fn bit_reverse(x: usize, bits: usize) -> usize {
let mut result = 0usize;
let mut val = x;
for _ in 0..bits {
result = (result << 1) | (val & 1);
val >>= 1;
}
result
}
fn apply_single_qubit(state: &mut [Complex64; DIM], matrix: &[Complex64], q: usize) {
let m00 = matrix[0];
let m01 = matrix[1];
let m10 = matrix[2];
let m11 = matrix[3];
let bit = N - 1 - q;
let mask = 1usize << bit;
let mut i = 0usize;
while i < DIM {
if i & mask == 0 {
let j = i | mask;
let (a0, a1) = (state[i], state[j]);
state[i] = m00 * a0 + m01 * a1;
state[j] = m10 * a0 + m11 * a1;
}
i += 1;
}
}