use crate::error::{QuantumError, Result};
use crate::state::QuantumState;
use moonlab_sys::{
grover_config_t, grover_optimal_iterations, grover_result_t, grover_search,
quantum_entropy_ctx_create_hw, quantum_entropy_ctx_destroy,
quantum_entropy_ctx_t,
};
use std::ptr;
struct EntropyGuard {
ctx: *mut quantum_entropy_ctx_t,
}
impl EntropyGuard {
fn new() -> Result<Self> {
let ctx = unsafe { quantum_entropy_ctx_create_hw() };
if ctx.is_null() {
return Err(QuantumError::Ffi(
"quantum_entropy_ctx_create_hw returned NULL".to_string(),
));
}
Ok(Self { ctx })
}
}
impl Drop for EntropyGuard {
fn drop(&mut self) {
if !self.ctx.is_null() {
unsafe { quantum_entropy_ctx_destroy(self.ctx) };
self.ctx = ptr::null_mut();
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct GroverResult {
pub found_state: u64,
pub success_probability: f64,
pub oracle_calls: usize,
pub iterations_performed: usize,
pub fidelity: f64,
pub found_marked_state: bool,
}
impl GroverResult {
fn from_c(r: grover_result_t) -> Self {
Self {
found_state: r.found_state,
success_probability: r.success_probability,
oracle_calls: r.oracle_calls,
iterations_performed: r.iterations_performed,
fidelity: r.fidelity,
found_marked_state: r.found_marked_state != 0,
}
}
}
pub fn search(
state: &mut QuantumState,
marked_state: u64,
num_iterations: Option<usize>,
) -> Result<GroverResult> {
let num_qubits = state.num_qubits();
let (iters, auto) = match num_iterations {
Some(n) => (n, 0),
None => (0, 1),
};
let config = grover_config_t {
num_qubits,
marked_state,
num_iterations: iters,
use_optimal_iterations: auto,
};
let entropy = EntropyGuard::new()?;
let result = unsafe {
grover_search(
state.as_ptr(),
&config,
entropy.ctx,
)
};
drop(entropy);
Ok(GroverResult::from_c(result))
}
pub fn optimal_iterations(num_qubits: usize) -> usize {
unsafe { grover_optimal_iterations(num_qubits) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn optimal_iterations_matches_textbook_for_n4() {
assert_eq!(optimal_iterations(4), 3);
}
#[test]
fn search_finds_marked_state_at_n4() {
for attempt in 0..3 {
let mut state = QuantumState::new(4).unwrap();
let r = search(&mut state, 0b1010, None).unwrap();
assert!(
r.success_probability > 0.9,
"Grover P(success) = {:.3} on 4-qubit |1010>; expected > 0.9",
r.success_probability
);
assert_eq!(r.iterations_performed, optimal_iterations(4));
if r.found_marked_state && r.found_state == 0b1010 {
return;
}
eprintln!("search_finds_marked_state_at_n4: attempt {} \
landed off-target (found_state={:#06b}); retrying",
attempt, r.found_state);
}
panic!("Grover Born sample missed marked state 3x in a row \
-- chance is 0.0064%, investigate");
}
#[test]
fn search_honours_explicit_iteration_count() {
let mut state = QuantumState::new(4).unwrap();
let r = search(&mut state, 0b0101, Some(2)).unwrap();
assert_eq!(r.iterations_performed, 2);
}
}