mod export;
mod fp;
mod import;
mod obligation;
#[cfg(test)]
mod tests;
pub use import::{Import, import};
pub use obligation::rule_obligation;
use crate::error::Error;
use crate::expr::{Context, Expr};
use crate::facts::{Assumptions, Reliance};
pub fn export(cx: &mut Context, roots: &[Expr]) -> Result<String, Error> {
export::emit(cx, roots)
}
pub fn equivalence_query(cx: &mut Context, a: Expr, b: Expr) -> Result<String, Error> {
if cx.width(a)? != cx.width(b)? {
return Err(Error::Unsupported("different widths".into()));
}
let body = export::emit(cx, &[a, b])?;
let mut s = logic(&body);
s.push_str(&body);
s.push_str("(assert (not (= root0 root1)))\n(check-sat)\n");
Ok(s)
}
pub fn satisfiability_query(cx: &mut Context, p: Expr) -> Result<String, Error> {
if cx.width(p)? != crate::Width::W1 {
return Err(Error::Unsupported("not a 1-bit predicate".into()));
}
let body = export::emit(cx, &[p])?;
let mut s = logic(&body);
s.push_str(&body);
s.push_str("(assert (= root0 #b1))\n(check-sat)\n");
Ok(s)
}
pub fn equivalence_query_under(
cx: &mut Context,
a: Expr,
b: Expr,
assumptions: &Assumptions,
relied: Reliance,
) -> Result<String, Error> {
if cx.width(a)? != cx.width(b)? {
return Err(Error::Unsupported("different widths".into()));
}
let mut roots = vec![a, b];
for (id, e, f) in assumptions.constraints() {
if relied.may_use(id) {
let value = cx.id(e)?;
let predicate = crate::facts::facts_predicate(cx, value, f)?;
roots.push(cx.handle(predicate));
}
}
let body = export::emit(cx, &roots)?;
let mut s = logic(&body);
s.push_str(&body);
for k in 2..roots.len() {
s.push_str(&format!("(assert (= root{k} #b1))\n"));
}
s.push_str("(assert (not (= root0 root1)))\n(check-sat)\n");
Ok(s)
}
fn logic(body: &str) -> String {
let uf = body.contains("(declare-fun ");
let fp = body.contains("(_ to_fp ");
String::from(match (uf, fp) {
(false, false) => "(set-logic QF_BV)\n",
(true, false) => "(set-logic QF_UFBV)\n",
(false, true) => "(set-logic QF_BVFP)\n",
(true, true) => "(set-logic ALL)\n",
})
}