use quest_bind::{
Qreal,
QuestEnv,
QuestError,
Qureg,
PI,
};
use rand::Rng;
const NUM_QUBITS: i32 = 0x10;
const NUM_ELEMS: i64 = 1 << NUM_QUBITS;
fn tensor_gate<'a, F>(
qureg: &mut Qureg<'a>,
gate: F,
qubits: &[i32],
) -> Result<(), QuestError>
where
F: for<'b> Fn(&'b mut Qureg<'a>, i32) -> Result<(), QuestError>,
{
qubits.iter().try_for_each(|&q| gate(qureg, q))
}
fn apply_oracle(
qureg: &mut Qureg<'_>,
qubits: &[i32],
sol_elem: i64,
) -> Result<(), QuestError> {
let sol_ctrls = &qubits
.iter()
.filter_map(|&q| ((sol_elem >> q) & 1 == 0).then_some(q))
.collect::<Vec<_>>();
qureg
.multi_qubit_not(sol_ctrls)
.and(qureg.multi_controlled_phase_flip(qubits))
.and(qureg.multi_qubit_not(sol_ctrls))
}
fn apply_diffuser(
qureg: &mut Qureg<'_>,
qubits: &[i32],
) -> Result<(), QuestError> {
tensor_gate(qureg, Qureg::hadamard, qubits)
.and(qureg.multi_qubit_not(qubits))?;
qureg.multi_controlled_phase_flip(qubits)?;
qureg.multi_qubit_not(qubits).and(tensor_gate(
qureg,
Qureg::hadamard,
qubits,
))
}
fn main() -> Result<(), QuestError> {
let env = &QuestEnv::new();
let num_reps = (PI / 4.0 * (NUM_ELEMS as Qreal).sqrt()).ceil() as usize;
println!(
"num_qubits: {NUM_QUBITS}, num_elems: {NUM_ELEMS}, num_reps: \
{num_reps}"
);
let mut rng = rand::thread_rng();
let sol_elem = rng.gen_range(0..NUM_ELEMS);
const N: i32 = NUM_QUBITS;
let mut qureg = Qureg::<'_>::try_new(N, env)?;
qureg.init_plus_state();
let qubits = &(0..NUM_QUBITS).collect::<Vec<_>>();
(0..num_reps).try_for_each(|_| {
apply_oracle(&mut qureg, qubits, sol_elem)
.and(apply_diffuser(&mut qureg, qubits))
.and(qureg.get_prob_amp(sol_elem))
.map(|prob| {
println!("prob of solution |{sol_elem}> = {:.8}", prob);
})
})
}