use crate::ast::{Ast, Bool};
use crate::{Context, Fixedpoint, FuncDecl, Params, SatResult, Statistics};
use std::ffi::CString;
use std::fmt;
use z3_sys::*;
impl Drop for Fixedpoint {
fn drop(&mut self) {
unsafe {
Z3_fixedpoint_dec_ref(self.ctx.z3_ctx.0, self.z3_fp);
}
}
}
impl Fixedpoint {
pub fn new() -> Fixedpoint {
let ctx = Context::thread_local();
unsafe {
let fp = Z3_mk_fixedpoint(ctx.z3_ctx.0).unwrap();
Z3_fixedpoint_inc_ref(ctx.z3_ctx.0, fp);
Fixedpoint {
ctx: ctx.clone(),
z3_fp: fp,
}
}
}
pub fn add_rule(&self, rule: &impl Ast, name: Option<&str>) {
let name_sym = name.map(|name| {
let cname = CString::new(name).unwrap();
unsafe { Z3_mk_string_symbol(self.ctx.z3_ctx.0, cname.as_ptr()).unwrap() }
});
unsafe {
Z3_fixedpoint_add_rule(self.ctx.z3_ctx.0, self.z3_fp, rule.get_z3_ast(), name_sym);
}
}
pub fn add_fact(&self, pred: &FuncDecl, args: &[u32]) {
let mut args: Vec<u32> = args.to_vec();
unsafe {
Z3_fixedpoint_add_fact(
self.ctx.z3_ctx.0,
self.z3_fp,
pred.z3_func_decl,
args.len() as u32,
args.as_mut_ptr(),
);
}
}
pub fn assert(&self, axiom: &impl Ast) {
unsafe {
Z3_fixedpoint_assert(self.ctx.z3_ctx.0, self.z3_fp, axiom.get_z3_ast());
}
}
pub fn query(&self, query: &impl Ast) -> SatResult {
unsafe {
match Z3_fixedpoint_query(self.ctx.z3_ctx.0, self.z3_fp, query.get_z3_ast()) {
Z3_L_TRUE => SatResult::Sat,
Z3_L_FALSE => SatResult::Unsat,
_ => SatResult::Unknown,
}
}
}
pub fn query_relations(&self, relations: &[&FuncDecl]) -> SatResult {
let decls: Vec<Z3_func_decl> = relations.iter().map(|r| r.z3_func_decl).collect();
unsafe {
match Z3_fixedpoint_query_relations(
self.ctx.z3_ctx.0,
self.z3_fp,
decls.len() as u32,
decls.as_ptr(),
) {
Z3_L_TRUE => SatResult::Sat,
Z3_L_FALSE => SatResult::Unsat,
_ => SatResult::Unknown,
}
}
}
pub fn get_answer(&self) -> Option<Bool> {
unsafe {
let answer = Z3_fixedpoint_get_answer(self.ctx.z3_ctx.0, self.z3_fp);
answer.map(|answer| Bool::wrap(&self.ctx, answer))
}
}
pub fn get_reason_unknown(&self) -> String {
unsafe {
let reason = Z3_fixedpoint_get_reason_unknown(self.ctx.z3_ctx.0, self.z3_fp);
std::ffi::CStr::from_ptr(reason)
.to_string_lossy()
.into_owned()
}
}
pub fn update_rule(&self, rule: &impl Ast, name: &str) {
unsafe {
let cname = CString::new(name).unwrap();
let name_sym = Z3_mk_string_symbol(self.ctx.z3_ctx.0, cname.as_ptr()).unwrap();
Z3_fixedpoint_update_rule(self.ctx.z3_ctx.0, self.z3_fp, rule.get_z3_ast(), name_sym);
}
}
pub fn get_num_levels(&self, pred: &FuncDecl) -> u32 {
unsafe { Z3_fixedpoint_get_num_levels(self.ctx.z3_ctx.0, self.z3_fp, pred.z3_func_decl) }
}
pub fn get_cover_delta(&self, level: i32, predicate: &FuncDecl) -> Option<Bool> {
unsafe {
Z3_fixedpoint_get_cover_delta(
self.ctx.z3_ctx.0,
self.z3_fp,
level,
predicate.z3_func_decl,
)
.map(|d| Bool::wrap(&self.ctx, d))
}
}
pub fn add_cover(&self, level: i32, predicate: &FuncDecl, property: &impl Ast) {
unsafe {
Z3_fixedpoint_add_cover(
self.ctx.z3_ctx.0,
self.z3_fp,
level,
predicate.z3_func_decl,
property.get_z3_ast(),
);
}
}
pub fn get_statistics(&self) -> Statistics {
unsafe {
Statistics::wrap(
&self.ctx,
Z3_fixedpoint_get_statistics(self.ctx.z3_ctx.0, self.z3_fp).unwrap(),
)
}
}
pub fn register_relation(&self, pred: &FuncDecl) {
unsafe {
Z3_fixedpoint_register_relation(self.ctx.z3_ctx.0, self.z3_fp, pred.z3_func_decl);
}
}
pub fn set_params(&self, params: &Params) {
unsafe {
Z3_fixedpoint_set_params(self.ctx.z3_ctx.0, self.z3_fp, params.z3_params);
}
}
pub fn get_help(&self) -> String {
unsafe {
let help = Z3_fixedpoint_get_help(self.ctx.z3_ctx.0, self.z3_fp);
std::ffi::CStr::from_ptr(help)
.to_string_lossy()
.into_owned()
}
}
pub fn from_string(&self, s: &str) -> Result<(), String> {
let cs = CString::new(s).map_err(|_| "String contains null byte")?;
unsafe {
let result = Z3_fixedpoint_from_string(self.ctx.z3_ctx.0, self.z3_fp, cs.as_ptr());
match result {
Some(_) => Ok(()),
None => Err("Failed to parse fixedpoint from string".to_string()),
}
}
}
pub fn from_file(&self, filename: &str) -> Result<(), String> {
let cs = CString::new(filename).map_err(|_| "Filename contains null byte")?;
unsafe {
let result = Z3_fixedpoint_from_file(self.ctx.z3_ctx.0, self.z3_fp, cs.as_ptr());
match result {
Some(_) => Ok(()),
None => Err("Failed to parse fixedpoint from file".to_string()),
}
}
}
}
impl Default for Fixedpoint {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for Fixedpoint {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let s = unsafe {
let s = Z3_fixedpoint_to_string(self.ctx.z3_ctx.0, self.z3_fp, 0, std::ptr::null_mut());
std::ffi::CStr::from_ptr(s).to_string_lossy().into_owned()
};
write!(f, "{s}")
}
}
impl fmt::Debug for Fixedpoint {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
<Self as fmt::Display>::fmt(self, f)
}
}