use quantrs2_core::{
error::QuantRS2Result,
gate::{single::Hadamard, GateOp},
qubit::QubitId,
register::Register,
};
use scirs2_core::Complex64;
const N_QUBITS: usize = 3;
const DIM: usize = 1 << N_QUBITS;
fn main() -> QuantRS2Result<()> {
println!("=== Grover's Search (3 qubits, target = |101⟩) ===\n");
let target = 0b101usize; println!("Target state: |{target:03b}⟩ (decimal {target})");
println!("Search space: {DIM} states");
println!("Optimal iterations: {}", optimal_iterations(DIM));
println!();
let mut state = [Complex64::new(0.0, 0.0); DIM];
state[0] = Complex64::new(1.0, 0.0);
apply_hadamard_all(&mut state)?;
println!("After H⊗3 (uniform superposition):");
print_probabilities(&state);
let k = optimal_iterations(DIM);
for iter in 1..=k {
apply_oracle(&mut state, target);
apply_diffusion(&mut state)?;
println!("\nAfter iteration {iter}:");
print_probabilities(&state);
}
let (max_idx, max_prob) = state
.iter()
.enumerate()
.map(|(i, a)| (i, a.norm_sqr()))
.fold(
(0, 0.0f64),
|(bi, bp), (i, p)| {
if p > bp {
(i, p)
} else {
(bi, bp)
}
},
);
println!("\n=== Result ===");
println!("Most probable state: |{max_idx:03b}⟩ with P = {max_prob:.6}");
let register = Register::<N_QUBITS>::with_amplitudes(state.to_vec())?;
for q in 0..N_QUBITS {
let ez = register.expectation_z(q as u32)?;
let bit = (target >> (N_QUBITS - 1 - q)) & 1; println!(" ⟨Z_{q}⟩ = {ez:+.4} (target bit = {bit})");
}
assert_eq!(
max_idx, target,
"Grover should find |{target:03b}⟩ but found |{max_idx:03b}⟩"
);
assert!(
max_prob > 0.90,
"Target probability should be >0.90 for 3-qubit Grover, got {max_prob:.4}"
);
println!("\nOK — Grover found |{target:03b}⟩ with probability {max_prob:.4}");
Ok(())
}
fn optimal_iterations(n: usize) -> usize {
let k = (std::f64::consts::PI / 4.0 * (n as f64).sqrt()).floor() as usize;
k.max(1)
}
fn apply_hadamard_all(state: &mut [Complex64; DIM]) -> QuantRS2Result<()> {
let h = Hadamard { target: QubitId(0) };
let mat = h.matrix()?;
for q in 0..N_QUBITS {
apply_single_qubit(state, &mat, q);
}
Ok(())
}
fn apply_oracle(state: &mut [Complex64; DIM], target: usize) {
state[target] = -state[target];
}
fn apply_diffusion(state: &mut [Complex64; DIM]) -> QuantRS2Result<()> {
let h = Hadamard { target: QubitId(0) };
let mat = h.matrix()?;
for q in 0..N_QUBITS {
apply_single_qubit(state, &mat, q);
}
for item in state.iter_mut().skip(1) {
*item = -*item;
}
for q in 0..N_QUBITS {
apply_single_qubit(state, &mat, q);
}
Ok(())
}
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_QUBITS - 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;
}
}
fn print_probabilities(state: &[Complex64; DIM]) {
for (i, amp) in state.iter().enumerate() {
let p = amp.norm_sqr();
if p > 0.001 {
let bar_len = (p * 20.0).round() as usize;
let bar: String = "█".repeat(bar_len);
println!(" |{i:03b}⟩ ({i:>2}): {p:.4} {bar}");
}
}
}