use itertools::Itertools;
use miette::IntoDiagnostic;
use smtlib::{
and,
backend::{cvc5_binary::Cvc5Binary, z3_binary::Z3Binary, Backend},
distinct, or,
prelude::*,
BitVec, SatResultWithModel, Solver, Storage,
};
fn queens<B: Backend>(st: &Storage, backend: B) -> miette::Result<()> {
let x0 = BitVec::<4>::new_const(st, "x0");
let x1 = BitVec::<4>::new_const(st, "x1");
let x2 = BitVec::<4>::new_const(st, "x2");
let x3 = BitVec::<4>::new_const(st, "x3");
let x4 = BitVec::<4>::new_const(st, "x4");
let x5 = BitVec::<4>::new_const(st, "x5");
let x6 = BitVec::<4>::new_const(st, "x6");
let x7 = BitVec::<4>::new_const(st, "x7");
let xs = [x0, x1, x2, x3, x4, x5, x6, x7];
let mut solver = Solver::new(st, backend)?;
dbg!(BitVec::<4>::new(st, 8));
solver.assert(and(
st,
[
x0._eq(BitVec::new(st, 8) % x0),
],
))?;
for i in 1.. {
match solver.check_sat_with_model()? {
SatResultWithModel::Unsat => {
eprintln!("No more solutions!");
break;
}
SatResultWithModel::Sat(model) => {
println!(
"{i:5}: {}",
xs.map(|x| model.eval(x).map(|x| x.to_string()).unwrap_or_default())
.iter()
.format(",")
);
solver.assert(or(
st,
xs.map(|x| distinct(st, [x.into(), model.eval(x).unwrap()])),
))?;
}
SatResultWithModel::Unknown => todo!(),
}
}
Ok(())
}
fn main() -> miette::Result<()> {
miette::set_panic_hook();
let st = Storage::new();
match std::env::args().nth(1).as_deref().unwrap_or("z3") {
"z3" => queens(&st, Z3Binary::new("z3").into_diagnostic()?)?,
"cvc5" => queens(&st, Cvc5Binary::new("cvc5").into_diagnostic()?)?,
given => miette::bail!(
"Invalid backend: '{}'. Available backends are: 'z3', 'cvc5'",
given
),
}
Ok(())
}