use super::Cnf;
use crate::{
Circuit, DenseSimulator, Error, Register, ResourceLimits, Result, StateVector, Unitary,
};
use burn::tensor::Device;
#[derive(Clone, Debug)]
pub struct GroverSat {
formula: Cnf,
engine: DenseSimulator,
preparation: Circuit,
oracle: Circuit,
diffusion: Circuit,
}
impl GroverSat {
pub fn new(formula: Cnf, limits: ResourceLimits) -> Result<Self> {
let n = formula.num_variables();
let total = n
.checked_add(formula.clauses().len())
.ok_or(Error::Overflow)?
.max(1);
let register = Register::qubits(total)?;
limits.check_state(1, register.size())?;
limits.check_plan(register.size())?;
if register.size() > i32::MAX as usize {
return Err(Error::Unsupported(
"dense gather indices exceed signed 32-bit range".into(),
));
}
if n > 0 {
limits.check_matrix(1, 2)?;
}
let mut preparation = Circuit::new(register.clone(), 0, 0);
let mut oracle = Circuit::new(register.clone(), 0, 0);
let mut diffusion = Circuit::new(register, 0, 0);
for wire in 0..n {
preparation.unitary(vec![wire], Unitary::h())?;
}
let falsifying = |clause: &[i32]| {
clause
.iter()
.map(|&x| (x.unsigned_abs() as usize - 1, usize::from(x < 0)))
.collect::<Vec<_>>()
};
for (i, clause) in formula.clauses().iter().enumerate() {
oracle.controlled_x(vec![], n + i)?;
oracle.controlled_x(falsifying(clause), n + i)?;
}
oracle.phase_flip((n..n + formula.clauses().len()).map(|w| (w, 1)).collect())?;
for (i, clause) in formula.clauses().iter().enumerate().rev() {
oracle.controlled_x(falsifying(clause), n + i)?;
oracle.controlled_x(vec![], n + i)?;
}
for wire in 0..n {
diffusion.unitary(vec![wire], Unitary::h())?;
}
diffusion.phase_flip((0..n).map(|w| (w, 0)).collect())?;
for wire in 0..n {
diffusion.unitary(vec![wire], Unitary::h())?;
}
diffusion.phase_flip(vec![])?;
Ok(Self {
formula,
engine: DenseSimulator::new(limits),
preparation,
oracle,
diffusion,
})
}
pub fn formula(&self) -> &Cnf {
&self.formula
}
pub fn num_qubits(&self) -> usize {
self.oracle.register().wires()
}
pub fn oracle(&self) -> &Circuit {
&self.oracle
}
pub fn diffusion(&self) -> &Circuit {
&self.diffusion
}
pub fn initial_state(&self, device: &Device) -> Result<StateVector> {
self.preparation.run(&self.engine, None, None, 1, device)
}
pub fn amplify(&self, iterations: usize, device: &Device) -> Result<StateVector> {
self.iterate(self.initial_state(device)?, iterations)
}
pub(super) fn iterate(&self, mut state: StateVector, iterations: usize) -> Result<StateVector> {
for _ in 0..iterations {
state = self.oracle.run_from(&self.engine, state, None, None)?;
state = self.diffusion.run_from(&self.engine, state, None, None)?;
}
Ok(state)
}
}