use ruqu_core::gate::Gate;
use ruqu_core::state::QuantumState;
use ruqu_core::types::{Complex, QubitIndex};
pub struct GroverConfig {
pub num_qubits: u32,
pub target_states: Vec<usize>,
pub num_iterations: Option<u32>,
pub seed: Option<u64>,
}
pub struct GroverResult {
pub measured_state: usize,
pub target_found: bool,
pub success_probability: f64,
pub num_iterations: u32,
pub state: QuantumState,
}
pub fn optimal_iterations(num_qubits: u32, num_targets: usize) -> u32 {
let n = 1usize << num_qubits;
let theta = (num_targets as f64 / n as f64).sqrt().asin();
let k = (std::f64::consts::FRAC_PI_4 / theta - 0.5).round().max(1.0);
k as u32
}
pub fn run_grover(config: &GroverConfig) -> ruqu_core::error::Result<GroverResult> {
let n = config.num_qubits;
let dim = 1usize << n;
for &t in &config.target_states {
assert!(
t < dim,
"target state index {} out of range for {} qubits (max {})",
t,
n,
dim - 1,
);
}
let iterations = config
.num_iterations
.unwrap_or_else(|| optimal_iterations(n, config.target_states.len()));
let mut state = match config.seed {
Some(s) => QuantumState::new_with_seed(n, s)?,
None => QuantumState::new(n)?,
};
for q in 0..n {
state.apply_gate(&Gate::H(q))?;
}
for _ in 0..iterations {
{
let amps = state.amplitudes_mut();
for &target in &config.target_states {
let a = amps[target];
amps[target] = Complex {
re: -a.re,
im: -a.im,
};
}
}
for q in 0..n {
state.apply_gate(&Gate::H(q))?;
}
{
let amps = state.amplitudes_mut();
for i in 1..amps.len() {
let a = amps[i];
amps[i] = Complex {
re: -a.re,
im: -a.im,
};
}
}
for q in 0..n {
state.apply_gate(&Gate::H(q))?;
}
}
let probs = state.probabilities();
let success_probability: f64 = config.target_states.iter().map(|&t| probs[t]).sum();
let measured = measure_all_qubits(&mut state, n)?;
let target_found = config.target_states.contains(&measured);
Ok(GroverResult {
measured_state: measured,
target_found,
success_probability,
num_iterations: iterations,
state,
})
}
fn measure_all_qubits(
state: &mut QuantumState,
num_qubits: u32,
) -> ruqu_core::error::Result<usize> {
let mut result: usize = 0;
for q in 0..num_qubits {
let outcome = state.measure(q as QubitIndex)?;
if outcome.result {
result |= 1 << q;
}
}
Ok(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_optimal_iterations_single_target() {
let k = optimal_iterations(3, 1);
assert_eq!(k, 2);
}
#[test]
fn test_optimal_iterations_half_marked() {
let k = optimal_iterations(2, 2);
assert!(k >= 1);
}
#[test]
fn test_optimal_iterations_minimum_one() {
let k = optimal_iterations(1, 1);
assert!(k >= 1);
}
}