z3-z3-4.13.0.src.cmd_context.cmd_context.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
cmd_context.cpp
Abstract:
Command context.
Author:
Leonardo (leonardo) 2011-03-01
Notes:
--*/
#include
#include "util/tptr.h"
#include "util/cancel_eh.h"
#include "util/scoped_ctrl_c.h"
#include "util/dec_ref_util.h"
#include "util/scoped_timer.h"
#include "ast/func_decl_dependencies.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/char_decl_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "ast/pb_decl_plugin.h"
#include "ast/fpa_decl_plugin.h"
#include "ast/special_relations_decl_plugin.h"
#include "ast/ast_pp.h"
#include "ast/rewriter/var_subst.h"
#include "ast/pp.h"
#include "ast/ast_smt2_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/decl_collector.h"
#include "ast/well_sorted.h"
#include "ast/for_each_expr.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/rewriter/recfun_replace.h"
#include "ast/polymorphism_util.h"
#include "model/model_evaluator.h"
#include "model/model_smt2_pp.h"
#include "model/model_v2_pp.h"
#include "model/model_params.hpp"
#include "tactic/tactic_exception.h"
#include "ast/converters/generic_model_converter.h"
#include "solver/smt_logics.h"
#include "cmd_context/basic_cmds.h"
#include "cmd_context/cmd_context.h"
#include
func_decls::func_decls(ast_manager & m, func_decl * f):
m_decls(TAG(func_decl*, f, 0)) {
m.inc_ref(f);
}
void func_decls::finalize(ast_manager & m) {
TRACE("cmd_context_detail", tout << "finalizing func_decls...\n";);
if (GET_TAG(m_decls) == 0) {
m.dec_ref(UNTAG(func_decl *, m_decls));
}
else {
TRACE("func_decls", tout << "finalize...\n";);
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
for (func_decl * f : *fs) {
TRACE("func_decls", tout << "dec_ref of " << f->get_name() << " ref_count: " << f->get_ref_count() << "\n";);
m.dec_ref(f);
}
dealloc(fs);
}
m_decls = nullptr;
}
bool func_decls::signatures_collide(func_decl* f, func_decl* g) const {
return f == g;
}
bool func_decls::signatures_collide(unsigned n, sort* const* domain, sort* range, func_decl* g) const {
if (g->get_range() != range)
return false;
if (n != g->get_arity())
return false;
for (unsigned i = 0; i < n; ++i)
if (domain[i] != g->get_domain(i))
return false;
return true;
}
bool func_decls::contains(func_decl * f) const {
if (GET_TAG(m_decls) == 0) {
func_decl* g = UNTAG(func_decl*, m_decls);
return g && signatures_collide(f, g);
}
else {
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
for (func_decl* g : *fs)
if (signatures_collide(f, g))
return true;
}
return false;
}
bool func_decls::contains(unsigned n, sort* const* domain, sort* range) const {
if (GET_TAG(m_decls) == 0) {
func_decl* g = UNTAG(func_decl*, m_decls);
return g && signatures_collide(n, domain, range, g);
}
else {
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
for (func_decl* g : *fs) {
if (signatures_collide(n, domain, range, g)) return true;
}
}
return false;
}
bool func_decls::insert(ast_manager & m, func_decl * f) {
if (contains(f))
return false;
m.inc_ref(f);
if (m_decls == nullptr) {
m_decls = TAG(func_decl*, f, 0);
}
else if (GET_TAG(m_decls) == 0) {
func_decl_set * new_fs = alloc(func_decl_set);
new_fs->insert(UNTAG(func_decl*, m_decls));
new_fs->insert(f);
m_decls = TAG(func_decl*, new_fs, 1);
}
else {
func_decl_set * fs = UNTAG(func_decl_set*, m_decls);
fs->insert(f);
}
return true;
}
void func_decls::erase(ast_manager & m, func_decl * f) {
if (!contains(f))
return;
if (GET_TAG(m_decls) == 0) {
m.dec_ref(f);
m_decls = nullptr;
}
else {
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
fs->erase(f);
m.dec_ref(f);
if (fs->empty()) {
dealloc(fs);
m_decls = nullptr;
}
}
}
/**
\brief Return true if func_decls contains a declaration different from f, but with the same domain.
*/
bool func_decls::clash(func_decl * f) const {
if (m_decls == nullptr)
return false;
if (GET_TAG(m_decls) == 0)
return false;
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
for (func_decl * g : *fs) {
if (g == f)
continue;
if (g->get_arity() != f->get_arity())
continue;
unsigned num = g->get_arity();
unsigned i;
for (i = 0; i < num; i++)
if (g->get_domain(i) != f->get_domain(i))
break;
if (i == num)
return true;
}
return false;
}
bool func_decls::more_than_one() const {
if (m_decls == nullptr || GET_TAG(m_decls) == 0)
return false;
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
return fs->size() > 1;
}
func_decl * func_decls::first() const {
if (m_decls == nullptr)
return nullptr;
if (GET_TAG(m_decls) == 0)
return UNTAG(func_decl*, m_decls);
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
SASSERT(!fs->empty());
return *(fs->begin());
}
bool func_decls::check_signature(ast_manager& m, func_decl* f, unsigned arity, sort * const* domain, sort* range, bool& coerced) const {
if (range != nullptr && f->get_range() != range)
return false;
if (f->get_arity() != arity)
return false;
if (!domain)
return true;
coerced = false;
for (unsigned i = 0; i < arity; i++) {
sort* s1 = f->get_domain(i);
sort* s2 = domain[i];
if (s1 == s2)
continue;
coerced = true;
arith_util au(m);
if (au.is_real(s1) && au.is_int(s2))
continue;
if (au.is_real(s2) && au.is_int(s1))
continue;
return false;
}
return true;
}
bool func_decls::check_poly_signature(ast_manager& m, func_decl* f, unsigned arity, sort* const* domain, sort* range, func_decl*& g) {
polymorphism::substitution sub(m);
arith_util au(m);
sort_ref range_ref(range, m);
if (range != nullptr && !sub.match(f->get_range(), range))
return false;
if (f->get_arity() != arity)
return false;
for (unsigned i = 0; i < arity; i++)
if (!sub.match(f->get_domain(i), domain[i]))
return false;
if (!range)
range_ref = sub(f->get_range());
recfun::util u(m);
auto& p = u.get_plugin();
if (!u.has_def(f)) {
g = m.instantiate_polymorphic(f, arity, domain, range_ref);
return true;
}
// this is an instantiation of a recursive polymorphic function.
// create a self-contained polymorphic definition for the instantiation.
auto def = u.get_def(f);
auto promise_def = p.mk_def(f->get_name(), arity, domain, range_ref, false);
recfun_replace replace(m);
expr_ref tt = sub(def.get_rhs());
p.set_definition(replace, promise_def, def.is_macro(), def.get_vars().size(), def.get_vars().data(), tt);
g = promise_def.get_def()->get_decl();
insert(m, g);
return true;
}
func_decl * func_decls::find(ast_manager& m, unsigned arity, sort * const * domain, sort * range) {
bool coerced = false;
func_decl* g = nullptr;
if (!more_than_one()) {
func_decl* f = first();
if (check_signature(m, f, arity, domain, range, coerced))
return f;
if (check_poly_signature(m, f, arity, domain, range, g))
return g;
return nullptr;
}
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
func_decl* best_f = nullptr;
for (func_decl * f : *fs) {
if (check_signature(m, f, arity, domain, range, coerced)) {
if (coerced)
best_f = f;
else
return f;
}
}
if (best_f != nullptr)
return best_f;
for (func_decl* f : *fs)
if (check_poly_signature(m, f, arity, domain, range, g))
return g;
return nullptr;
}
func_decl * func_decls::find(ast_manager & m, unsigned num_args, expr * const * args, sort * range) {
if (!more_than_one())
first();
ptr_buffer sorts;
for (unsigned i = 0; i < num_args; i++) {
if (!args[i])
return nullptr;
sorts.push_back(args[i]->get_sort());
}
return find(m, num_args, sorts.data(), range);
}
unsigned func_decls::get_num_entries() const {
if (!more_than_one())
return 1;
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
return fs->size();
}
func_decl * func_decls::get_entry(unsigned inx) {
if (!more_than_one()) {
SASSERT(inx == 0);
return first();
}
else {
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
auto b = fs->begin();
for (unsigned i = 0; i < inx; i++)
b++;
return *b;
}
}
void macro_decls::finalize(ast_manager& m) {
for (auto v : *m_decls) m.dec_ref(v.m_body);
dealloc(m_decls);
}
bool macro_decls::insert(ast_manager& m, unsigned arity, sort *const* domain, expr* body) {
if (find(arity, domain)) return false;
m.inc_ref(body);
if (!m_decls) m_decls = alloc(vector);
m_decls->push_back(macro_decl(arity, domain, body));
return true;
}
expr* macro_decls::find(unsigned arity, sort *const* domain) const {
if (!m_decls) return nullptr;
for (auto v : *m_decls) {
if (v.m_domain.size() != arity) continue;
bool eq = true;
for (unsigned i = 0; eq && i < arity; ++i) {
eq = domain[i] == v.m_domain[i];
}
if (eq) return v.m_body;
}
return nullptr;
}
void macro_decls::erase_last(ast_manager& m) {
SASSERT(m_decls);
SASSERT(!m_decls->empty());
m.dec_ref(m_decls->back().m_body);
m_decls->pop_back();
}
ast_manager * ast_context_params::mk_ast_manager() {
if (m_manager)
return m_manager;
ast_manager * r = alloc(ast_manager,
m_proof ? PGM_ENABLED : PGM_DISABLED,
m_trace ? m_trace_file_name.c_str() : nullptr);
if (m_smtlib2_compliant)
r->enable_int_real_coercions(false);
if (m_debug_ref_count)
r->debug_ref_count();
return r;
}
bool cmd_context::contains_func_decl(symbol const& s, unsigned n, sort* const* domain, sort* range) const {
func_decls fs;
return m_func_decls.find(s, fs) && fs.contains(n, domain, range);
}
bool cmd_context::contains_macro(symbol const& s) const {
macro_decls decls;
return m_macros.find(s, decls) && !decls.empty();
}
bool cmd_context::contains_macro(symbol const& s, func_decl* f) const {
return contains_macro(s, f->get_arity(), f->get_domain());
}
bool cmd_context::contains_macro(symbol const& s, unsigned arity, sort *const* domain) const {
macro_decls decls;
return m_macros.find(s, decls) && nullptr != decls.find(arity, domain);
}
void cmd_context::insert_macro(symbol const& s, unsigned arity, sort*const* domain, expr* t) {
macro_decls decls;
if (!m_macros.find(s, decls)) {
VERIFY(decls.insert(m(), arity, domain, t));
m_macros.insert(s, decls);
}
else {
VERIFY(decls.insert(m(), arity, domain, t));
}
recfun::decl::plugin& p = get_recfun_plugin();
recfun_replace replace(m());
var_ref_vector vars(m()), rvars(m());
for (unsigned i = 0; i < arity; ++i) {
vars.push_back(m().mk_var(i, domain[i]));
rvars.push_back(m().mk_var(i, domain[arity - i - 1]));
}
recfun::promise_def d = p.ensure_def(s, arity, domain, t->get_sort(), false);
// recursive functions have opposite calling convention from macros!
var_subst sub(m(), true);
expr_ref tt = sub(t, rvars);
p.set_definition(replace, d, true, vars.size(), vars.data(), tt);
register_fun(s, d.get_def()->get_decl());
}
void cmd_context::erase_macro(symbol const& s) {
macro_decls decls;
VERIFY(m_macros.find(s, decls));
decls.erase_last(m());
}
bool cmd_context::macros_find(symbol const& s, unsigned n, expr*const* args, expr_ref_vector& coerced_args, expr_ref& t) {
macro_decls decls;
if (!m_macros.find(s, decls))
return false;
for (macro_decl const& d : decls) {
if (d.m_domain.size() != n)
continue;
bool eq = true;
coerced_args.reset();
for (unsigned i = 0; eq && i < n; ++i) {
if (d.m_domain[i] == args[i]->get_sort()) {
coerced_args.push_back(args[i]);
continue;
}
arith_util au(m());
if (au.is_real(d.m_domain[i]) && au.is_int(args[i])) {
coerced_args.push_back(au.mk_to_real(args[i]));
continue;
}
if (au.is_int(d.m_domain[i]) && au.is_real(args[i])) {
coerced_args.push_back(au.mk_to_int(args[i]));
continue;
}
eq = false;
}
if (eq) {
t = d.m_body;
return true;
}
}
for (macro_decl const& d : decls) {
if (d.m_domain.size() != n)
continue;
polymorphism::substitution sub(m());
bool eq = true;
for (unsigned i = 0; eq && i < n; ++i) {
if (!sub.match(d.m_domain[i], args[i]->get_sort()))
eq = false;
}
if (eq) {
t = d.m_body;
t = sub(t);
verbose_stream() << "macro " << t << "\n";
ptr_buffer domain;
for (unsigned i = 0; i < n; ++i)
domain.push_back(args[i]->get_sort());
insert_macro(s, n, domain.data(), t);
return true;
}
}
return false;
}
ast_object_ref::ast_object_ref(cmd_context & ctx, ast * a):m_ast(a) {
ctx.m().inc_ref(a);
}
void ast_object_ref::finalize(cmd_context & ctx) {
ctx.m().dec_ref(m_ast);
}
void stream_ref::set(std::ostream& out) {
reset();
m_owner = false;
m_name = "caller-owned";
m_stream = &out;
}
void stream_ref::set(char const * name) {
if (!name) {
throw cmd_exception("invalid stream name");
}
reset();
SASSERT(!m_owner);
if (strcmp(name, "stdout") == 0) {
m_name = "stdout";
m_stream = &std::cout;
}
else if (strcmp(name, "stderr") == 0) {
m_name = "stderr";
m_stream = &std::cerr;
}
else {
m_stream = alloc(std::ofstream, name, std::ios_base::app);
m_name = name;
m_owner = true;
if (m_stream->bad() || m_stream->fail()) {
reset();
std::string msg = "failed to set output stream '";
msg += name;
msg += "'";
throw cmd_exception(std::move(msg));
}
SASSERT(m_stream);
}
}
void stream_ref::reset() {
if (m_owner)
dealloc(m_stream);
m_name = m_default_name;
m_stream = &m_default;
m_owner = false;
}
class cmd_context::pp_env : public smt2_pp_environment {
protected:
cmd_context & m_owner;
arith_util m_autil;
bv_util m_bvutil;
array_util m_arutil;
fpa_util m_futil;
seq_util m_sutil;
datatype_util m_dtutil;
datalog::dl_decl_util m_dlutil;
format_ns::format * pp_fdecl_name(symbol const & s, func_decls const & fs, func_decl * f, unsigned & len) {
format_ns::format * f_name = smt2_pp_environment::pp_fdecl_name(s, len, f->is_skolem());
if (!fs.more_than_one())
return f_name;
if (!fs.clash(f))
return f_name;
return pp_as(f_name, f->get_range());
}
format_ns::format * pp_fdecl_ref_core(symbol const & s, func_decls const & fs, func_decl * f) {
unsigned len;
format_ns::format * f_name = smt2_pp_environment::pp_fdecl_name(s, len, f->is_skolem());
if (!fs.more_than_one())
return f_name;
return pp_signature(f_name, f);
}
public:
pp_env(cmd_context & o):m_owner(o), m_autil(o.m()), m_bvutil(o.m()), m_arutil(o.m()), m_futil(o.m()), m_sutil(o.m()), m_dtutil(o.m()), m_dlutil(o.m()) {}
ast_manager & get_manager() const override { return m_owner.m(); }
arith_util & get_autil() override { return m_autil; }
bv_util & get_bvutil() override { return m_bvutil; }
array_util & get_arutil() override { return m_arutil; }
fpa_util & get_futil() override { return m_futil; }
seq_util & get_sutil() override { return m_sutil; }
datatype_util & get_dtutil() override { return m_dtutil; }
datalog::dl_decl_util& get_dlutil() override { return m_dlutil; }
bool uses(symbol const & s) const override {
return
m_owner.m_builtin_decls.contains(s) ||
m_owner.m_func_decls.contains(s);
}
format_ns::format * pp_sort(sort * s) override {
auto * f = m_owner.try_pp(s);
if (f)
return f;
return smt2_pp_environment::pp_sort(s);
}
format_ns::format * pp_fdecl(func_decl * f, unsigned & len) override {
symbol s = f->get_name();
func_decls fs;
if (m_owner.m_func_decls.find(s, fs) && fs.contains(f)) {
return pp_fdecl_name(s, fs, f, len);
}
if (m_owner.m_func_decl2alias.find(f, s) && m_owner.m_func_decls.find(s, fs) && fs.contains(f)) {
return pp_fdecl_name(s, fs, f, len);
}
return smt2_pp_environment::pp_fdecl(f, len);
}
format_ns::format * pp_fdecl_ref(func_decl * f) override {
symbol s = f->get_name();
func_decls fs;
if (m_owner.m_func_decls.find(s, fs) && fs.contains(f)) {
return pp_fdecl_ref_core(s, fs, f);
}
if (m_owner.m_func_decl2alias.find(f, s) && m_owner.m_func_decls.find(s, fs) && fs.contains(f)) {
return pp_fdecl_ref_core(s, fs, f);
}
return smt2_pp_environment::pp_fdecl_ref(f);
}
};
cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l):
m_main_ctx(main_ctx),
m_logic(l),
m_print_success(m_params.m_smtlib2_compliant),
m_manager(m),
m_own_manager(m == nullptr),
m_regular("stdout", std::cout),
m_diagnostic("stderr", std::cerr) {
SASSERT(m != 0 || !has_manager());
install_basic_cmds(*this);
install_ext_basic_cmds(*this);
install_core_tactic_cmds(*this);
install_core_simplifier_cmds(*this);
m_mcs.push_back(nullptr);
SASSERT(m != 0 || !has_manager());
if (m_main_ctx) {
set_verbose_stream(diagnostic_stream());
}
}
cmd_context::~cmd_context() {
if (m_main_ctx) {
set_verbose_stream(std::cerr);
}
pop(m_scopes.size());
finalize_cmds();
finalize_tactic_manager();
m_proof_cmds = nullptr;
reset(true);
m_mcs.reset();
m_solver = nullptr;
m_check_sat_result = nullptr;
}
void cmd_context::set_cancel(bool f) {
if (has_manager()) {
if (f) {
m().limit().cancel();
}
else {
m().limit().reset_cancel();
}
}
}
opt_wrapper* cmd_context::get_opt() {
return m_opt.get();
}
void cmd_context::set_opt(opt_wrapper* opt) {
m_opt = opt;
for (unsigned i = 0; i < m_scopes.size(); ++i)
m_opt->push();
m_opt->set_logic(m_logic);
}
void cmd_context::global_params_updated() {
m_params.updt_params();
if (m_params.m_smtlib2_compliant)
m_print_success = true;
set_produce_proofs(m_params.m_proof);
if (m_solver) {
params_ref p;
if (!m_params.m_auto_config)
p.set_bool("auto_config", false);
m_solver->updt_params(p);
}
if (m_opt) {
get_opt()->updt_params(gparams::get_module("opt"));
}
if (m_proof_cmds)
m_proof_cmds->updt_params(gparams::get_module("solver"));
}
void cmd_context::set_produce_models(bool f) {
if (m_solver)
m_solver->set_produce_models(f);
m_params.m_model = f;
}
void cmd_context::set_produce_unsat_cores(bool f) {
// can only be set before initialization
SASSERT(!has_assertions());
m_params.m_unsat_core |= f;
}
void cmd_context::set_produce_proofs(bool f) {
if (m_params.m_proof == f)
return;
SASSERT(!has_assertions());
m_params.m_proof = f;
if (has_manager()) {
m().toggle_proof_mode(f ? PGM_ENABLED : PGM_DISABLED);
if (m_solver_factory)
mk_solver();
}
}
bool cmd_context::produce_models() const {
return m_params.m_model;
}
bool cmd_context::produce_proofs() const {
return m_params.m_proof;
}
bool cmd_context::produce_unsat_cores() const {
return m_params.m_unsat_core;
}
bool cmd_context::well_sorted_check_enabled() const {
return m_params.m_well_sorted_check;
}
bool cmd_context::validate_model_enabled() const {
return m_params.m_model_validate;
}
cmd_context::check_sat_state cmd_context::cs_state() const {
if (m_check_sat_result.get() == nullptr)
return css_clear;
switch (m_check_sat_result->status()) {
case l_true: return css_sat;
case l_false: return css_unsat;
default: return css_unknown;
}
}
void cmd_context::register_builtin_sorts(decl_plugin * p) {
svector names;
p->get_sort_names(names, m_logic);
family_id fid = p->get_family_id();
for (builtin_name const& n : names) {
psort_decl * d = pm().mk_psort_builtin_decl(n.m_name, fid, n.m_kind);
insert(d);
}
}
void cmd_context::register_builtin_ops(decl_plugin * p) {
svector names;
p->get_op_names(names, m_logic);
family_id fid = p->get_family_id();
for (builtin_name const& n : names) {
if (m_builtin_decls.contains(n.m_name)) {
builtin_decl & d = m_builtin_decls.find(n.m_name);
builtin_decl * new_d = alloc(builtin_decl, fid, n.m_kind, d.m_next);
d.m_next = new_d;
m_extra_builtin_decls.push_back(new_d);
}
else {
m_builtin_decls.insert(n.m_name, builtin_decl(fid, n.m_kind));
}
}
}
void cmd_context::register_plugin(symbol const & name, decl_plugin * p, bool install_names) {
m_manager->register_plugin(name, p);
if (install_names) {
register_builtin_sorts(p);
register_builtin_ops(p);
}
}
void cmd_context::load_plugin(symbol const & name, bool install, svector& fids) {
family_id id = m_manager->get_family_id(name);
decl_plugin* p = m_manager->get_plugin(id);
if (install && p && fids.contains(id)) {
register_builtin_sorts(p);
register_builtin_ops(p);
}
fids.erase(id);
}
bool cmd_context::logic_has_arith() const {
return !has_logic() || smt_logics::logic_has_arith(m_logic);
}
bool cmd_context::logic_has_bv() const {
return !has_logic() || smt_logics::logic_has_bv(m_logic);
}
bool cmd_context::logic_has_seq() const {
return !has_logic() || smt_logics::logic_has_seq(m_logic);
}
bool cmd_context::logic_has_pb() const {
return !has_logic() || smt_logics::logic_has_pb(m_logic);
}
bool cmd_context::logic_has_fpa() const {
return !has_logic() || smt_logics::logic_has_fpa(m_logic);
}
bool cmd_context::logic_has_array() const {
return !has_logic() || smt_logics::logic_has_array(m_logic);
}
bool cmd_context::logic_has_datatype() const {
return !has_logic() || smt_logics::logic_has_datatype(m_logic);
}
bool cmd_context::logic_has_recfun() const { return true; }
void cmd_context::init_manager_core(bool new_manager) {
SASSERT(m_manager != 0);
SASSERT(m_pmanager != 0);
if (new_manager) {
decl_plugin * basic = m_manager->get_plugin(m_manager->get_basic_family_id());
register_builtin_sorts(basic);
register_builtin_ops(basic);
// the manager was created by the command context.
register_plugin(symbol("arith"), alloc(arith_decl_plugin), logic_has_arith());
register_plugin(symbol("bv"), alloc(bv_decl_plugin), logic_has_bv());
register_plugin(symbol("array"), alloc(array_decl_plugin), logic_has_array());
register_plugin(symbol("datatype"), alloc(datatype_decl_plugin), logic_has_datatype());
register_plugin(symbol("recfun"), alloc(recfun::decl::plugin), logic_has_recfun());
register_plugin(symbol("char"), alloc(char_decl_plugin), logic_has_seq());
register_plugin(symbol("seq"), alloc(seq_decl_plugin), logic_has_seq());
register_plugin(symbol("pb"), alloc(pb_decl_plugin), logic_has_pb());
register_plugin(symbol("fpa"), alloc(fpa_decl_plugin), logic_has_fpa());
register_plugin(symbol("datalog_relation"), alloc(datalog::dl_decl_plugin), !has_logic());
register_plugin(symbol("specrels"), alloc(special_relations_decl_plugin), !has_logic());
}
else {
// the manager was created by an external module
// we register all plugins available in the manager.
// unless the logic specifies otherwise.
svector fids;
m_manager->get_range(fids);
load_plugin(symbol("arith"), logic_has_arith(), fids);
load_plugin(symbol("bv"), logic_has_bv(), fids);
load_plugin(symbol("array"), logic_has_array(), fids);
load_plugin(symbol("datatype"), logic_has_datatype(), fids);
load_plugin(symbol("recfun"), logic_has_recfun(), fids);
load_plugin(symbol("char"), logic_has_seq(), fids);
load_plugin(symbol("seq"), logic_has_seq(), fids);
load_plugin(symbol("fpa"), logic_has_fpa(), fids);
load_plugin(symbol("pb"), logic_has_pb(), fids);
for (family_id fid : fids) {
decl_plugin * p = m_manager->get_plugin(fid);
if (p) {
register_builtin_sorts(p);
register_builtin_ops(p);
}
}
}
m_dt_eh = alloc(dt_eh, *this);
m_pmanager->set_new_datatype_eh(m_dt_eh.get());
if (!has_logic() && new_manager) {
TRACE("cmd_context", tout << "init manager " << m_logic << "\n";);
// add list type only if the logic is not specified.
// it prevents clashes with builtin types.
register_plist();
}
if (m_solver_factory) {
mk_solver();
}
m_check_logic.set_logic(m(), m_logic);
}
void cmd_context::register_plist() {
insert(pm().mk_plist_decl());
}
void cmd_context::init_manager() {
if (m_manager_initialized) {
// no-op
}
else if (m_manager) {
m_manager_initialized = true;
SASSERT(!m_own_manager);
init_external_manager();
}
else {
m_manager_initialized = true;
SASSERT(m_pmanager == 0);
m_check_sat_result = nullptr;
m_manager = m_params.mk_ast_manager();
m_pmanager = alloc(pdecl_manager, *m_manager);
init_manager_core(true);
}
}
void cmd_context::init_external_manager() {
SASSERT(m_manager != 0);
SASSERT(m_pmanager == 0);
m_pmanager = alloc(pdecl_manager, *m_manager);
init_manager_core(false);
}
bool cmd_context::set_logic(symbol const & s) {
TRACE("cmd_context", tout << s << "\n";);
if (has_logic())
throw cmd_exception("the logic has already been set");
if (has_assertions() && m_main_ctx)
throw cmd_exception("logic must be set before initialization");
if (!smt_logics::supported_logic(s))
return false;
m_logic = s;
if (m_solver)
mk_solver();
if (smt_logics::logic_has_reals_only(s))
m_numeral_as_real = true;
return true;
}
std::string cmd_context::reason_unknown() const {
if (m_check_sat_result.get() == nullptr)
return "state of the most recent check-sat command is not known";
return m_check_sat_result->reason_unknown();
}
bool cmd_context::is_func_decl(symbol const & s) const {
return m_builtin_decls.contains(s) || m_func_decls.contains(s);
}
void cmd_context::insert(symbol const & s, func_decl * f) {
if (!m_check_logic(f)) {
throw cmd_exception(m_check_logic.get_last_error());
}
if (contains_macro(s, f)) {
throw cmd_exception("invalid declaration, named expression already defined with this name ", s);
}
#if 0
if (m_builtin_decls.contains(s)) {
throw cmd_exception("invalid declaration, builtin symbol ", s);
}
#endif
func_decls & fs = m_func_decls.insert_if_not_there(s, func_decls());
if (!fs.insert(m(), f)) {
if (m_allow_duplicate_declarations)
return;
std::string msg = "invalid declaration, ";
msg += f->get_arity() == 0 ? "constant" : "function";
msg += " '";
msg += s.str();
msg += "' (with the given signature) already declared";
throw cmd_exception(std::move(msg));
}
if (s != f->get_name()) {
TRACE("func_decl_alias", tout << "adding alias for: " << f->get_name() << ", alias: " << s << "\n";);
m_func_decl2alias.insert(f, s);
}
if (!m_global_decls) {
m_func_decls_stack.push_back(sf_pair(s, f));
}
TRACE("cmd_context", tout << "new function decl\n" << mk_pp(f, m()) << "\n";);
}
void cmd_context::insert(symbol const & s, psort_decl * p) {
pm().inc_ref(p);
if (m_psort_decls.contains(s)) {
symbol _s = s;
pm().dec_ref(p);
throw cmd_exception("sort already defined ", _s);
}
m_psort_decls.insert(s, p);
if (!m_global_decls) {
m_psort_decls_stack.push_back(s);
}
TRACE("cmd_context", tout << "new sort decl\n"; p->display(tout); tout << "\n";);
}
void cmd_context::insert(symbol const & s, unsigned arity, sort *const* domain, expr * t) {
expr_ref _t(t, m());
#if 0
if (m_builtin_decls.contains(s)) {
throw cmd_exception("invalid macro/named expression, builtin symbol ", s);
}
#endif
if (contains_macro(s, arity, domain)) {
throw cmd_exception("named expression already defined");
}
if (contains_func_decl(s, arity, domain, t->get_sort())) {
throw cmd_exception("invalid named expression, declaration already defined with this name ", s);
}
TRACE("insert_macro", tout << "new macro " << arity << "\n" << mk_pp(t, m()) << "\n";);
insert_macro(s, arity, domain, t);
if (!m_global_decls) {
m_macros_stack.push_back(s);
}
}
void cmd_context::insert(cmd * c) {
symbol const & s = c->get_name();
cmd * old_c;
if (m_cmds.find(s, old_c) && c != old_c) {
old_c->finalize(*this);
dealloc(old_c);
}
m_cmds.insert(s, c);
}
void cmd_context::insert_user_tactic(symbol const & s, sexpr * d) {
sm().inc_ref(d);
sexpr * old_d;
if (m_user_tactic_decls.find(s, old_d))
sm().dec_ref(old_d);
m_user_tactic_decls.insert(s, d);
}
void cmd_context::insert(symbol const & s, object_ref * r) {
r->inc_ref(*this);
object_ref * old_r = nullptr;
if (m_object_refs.find(s, old_r))
old_r->dec_ref(*this);
m_object_refs.insert(s, r);
}
void cmd_context::model_add(symbol const & s, unsigned arity, sort *const* domain, expr * t) {
if (!mc0()) m_mcs.set(m_mcs.size()-1, alloc(generic_model_converter, m(), "cmd_context"));
if (m_solver.get() && !m_solver->mc0()) m_solver->set_model_converter(mc0());
func_decl_ref fn(m().mk_func_decl(s, arity, domain, t->get_sort()), m());
mc0()->add(fn, t);
VERIFY(fn->get_range() == t->get_sort());
register_fun(s, fn);
}
void cmd_context::register_fun(symbol const& s, func_decl* fn) {
func_decls & fs = m_func_decls.insert_if_not_there(s, func_decls());
fs.insert(m(), fn);
if (!m_global_decls)
m_func_decls_stack.push_back(sf_pair(s, fn));
}
void cmd_context::model_del(func_decl* f) {
if (!mc0()) m_mcs.set(m_mcs.size() - 1, alloc(generic_model_converter, m(), "cmd_context"));
if (m_solver.get() && !m_solver->mc0()) m_solver->set_model_converter(mc0());
mc0()->hide(f);
}
recfun::decl::plugin& cmd_context::get_recfun_plugin() {
recfun::util u(get_ast_manager());
return u.get_plugin();
}
recfun::promise_def cmd_context::decl_rec_fun(const symbol &name, unsigned int arity, sort *const *domain, sort *range) {
SASSERT(logic_has_recfun());
return get_recfun_plugin().mk_def(name, arity, domain, range, false);
}
void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* rhs) {
TRACE("recfun", tout<< "define recfun " << f->get_name() << " = " << mk_pp(rhs, m()) << "\n";);
recfun::decl::plugin& p = get_recfun_plugin();
var_ref_vector vars(m());
for (expr* b : binding) {
SASSERT(is_var(b));
vars.push_back(to_var(b));
}
recfun::promise_def d = p.get_promise_def(f);
recfun_replace replace(m());
p.set_definition(replace, d, false, vars.size(), vars.data(), rhs);
}
func_decl * cmd_context::find_func_decl(symbol const & s) const {
if (contains_macro(s)) {
throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s);
}
func_decls fs;
if (m_func_decls.find(s, fs)) {
if (fs.more_than_one())
throw cmd_exception("ambiguous function declaration reference, provide full signature to disambiguate ( (*) ) ", s);
return fs.first();
}
builtin_decl d;
if (m_builtin_decls.find(s, d)) {
try {
// Remark: ignoring m_next of d. We do not allow two different theories to define the same constant name.
func_decl * f;
f = m().mk_func_decl(d.m_fid, d.m_decl, 0, nullptr, 0, static_cast(nullptr), nullptr);
if (f != nullptr)
return f;
}
catch (ast_exception &) {
}
throw cmd_exception("invalid function declaration reference, must provide signature for builtin symbol ", s);
}
throw cmd_exception("invalid function declaration reference, unknown function ", s);
return nullptr;
}
/**
\brief Select a builtin_decl from the list starting at first.
We select the decl d s.t. d->m_fid == target_id
If there is none that satisfies this condition, we return first.
This is a HACK for supporting arithmetic and floating-point arithmetic.
These are two different theories in Z3, but they share builtin symbol names: +, -, *, /, <, <=, >, >=
*/
static builtin_decl const & peek_builtin_decl(builtin_decl const & first, family_id target_id) {
builtin_decl const * curr = &first;
while (curr != nullptr) {
if (curr->m_fid == target_id)
return *curr;
curr = curr->m_next;
}
return first;
}
func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices,
unsigned arity, sort * const * domain, sort * range) {
if (domain && contains_macro(s, arity, domain))
throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s);
func_decl * f = nullptr;
if (num_indices == 0 && m_func_decls.contains(s)) {
auto& fs = m_func_decls.find(s);
f = fs.find(m(), arity, domain, range);
}
if (f)
return f;
builtin_decl d;
if ((arity == 0 || domain) && m_builtin_decls.find(s, d)) {
family_id fid = d.m_fid;
decl_kind k = d.m_decl;
// Hack: if d.m_next != 0, we use domain[0] (if available) to decide which plugin we use.
if (d.m_decl != 0 && arity > 0) {
builtin_decl const & d2 = peek_builtin_decl(d, domain[0]->get_family_id());
fid = d2.m_fid;
k = d2.m_decl;
}
func_decl * f;
if (num_indices == 0) {
f = m().mk_func_decl(fid, k, 0, nullptr, arity, domain, range);
}
else {
buffer ps;
for (unsigned i = 0; i < num_indices; i++)
ps.push_back(parameter(indices[i]));
f = m().mk_func_decl(fid, k, num_indices, ps.data(), arity, domain, range);
}
if (f == nullptr)
throw cmd_exception("invalid function declaration reference, invalid builtin reference ", s);
return f;
}
if (num_indices > 0 && m_func_decls.contains(s)) {
auto& fs = m_func_decls.find(s);
f = fs.find(m(), arity, domain, range);
}
if (f)
return f;
throw cmd_exception("invalid function declaration reference, unknown indexed function ", s);
}
psort_decl * cmd_context::find_psort_decl(symbol const & s) const {
psort_decl * p = nullptr;
m_psort_decls.find(s, p);
return p;
}
cmd * cmd_context::find_cmd(symbol const & s) const {
cmd * c = nullptr;
m_cmds.find(s, c);
return c;
}
sexpr * cmd_context::find_user_tactic(symbol const & s) const {
sexpr * n = nullptr;
m_user_tactic_decls.find(s, n);
return n;
}
object_ref * cmd_context::find_object_ref(symbol const & s) const {
object_ref * r = nullptr;
m_object_refs.find(s, r);
if (r == nullptr) throw cmd_exception("unknown global variable ", s);
return r;
}
#define CHECK_SORT(T) if (well_sorted_check_enabled()) m().check_sorts_core(T)
void cmd_context::mk_const(symbol const & s, expr_ref & result) {
mk_app(s, 0, nullptr, 0, nullptr, nullptr, result);
}
bool cmd_context::try_mk_builtin_app(symbol const & s, unsigned num_args, expr * const * args,
unsigned num_indices, parameter const * indices, sort * range,
expr_ref & result) const {
builtin_decl d;
if (!m_builtin_decls.find(s, d))
return false;
family_id fid = d.m_fid;
decl_kind k = d.m_decl;
// Hack: if d.m_next != 0, we use the sort of args[0] (if available) to decide which plugin we use.
if (d.m_decl != 0 && num_args > 0) {
builtin_decl const & d2 = peek_builtin_decl(d, args[0]->get_sort()->get_family_id());
fid = d2.m_fid;
k = d2.m_decl;
}
if (num_indices == 0)
result = m().mk_app(fid, k, 0, nullptr, num_args, args, range);
else
result = m().mk_app(fid, k, num_indices, indices, num_args, args, range);
CHECK_SORT(result.get());
return nullptr != result.get();
}
bool cmd_context::try_mk_declared_app(symbol const & s, unsigned num_args, expr * const * args,
unsigned num_indices, parameter const * indices, sort * range,
expr_ref & result) {
if (!m_func_decls.contains(s))
return false;
func_decls& fs = m_func_decls.find(s);
if (num_args == 0 && !range) {
if (fs.more_than_one())
throw cmd_exception("ambiguous constant reference, more than one constant with the same sort, use a qualified expression (as ) to disambiguate ", s);
func_decl * f = fs.first();
if (!f)
return false;
if (f->get_arity() != 0)
result = array_util(m()).mk_as_array(f);
else
result = m().mk_const(f);
return true;
}
func_decl * f = fs.find(m(), num_args, args, range);
if (!f)
return false;
if (well_sorted_check_enabled())
m().check_sort(f, num_args, args);
result = m().mk_app(f, num_args, args);
return true;
}
bool cmd_context::try_mk_macro_app(symbol const & s, unsigned num_args, expr * const * args,
unsigned num_indices, parameter const * indices, sort * range,
expr_ref & result) {
expr_ref _t(m());
expr_ref_vector coerced_args(m());
if (macros_find(s, num_args, args, coerced_args, _t)) {
TRACE("macro_bug", tout << "well_sorted_check_enabled(): " << well_sorted_check_enabled() << "\n";
tout << "s: " << s << "\n";
tout << "body:\n" << mk_ismt2_pp(_t, m()) << "\n";
tout << "args:\n"; for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n" << mk_pp(args[i]->get_sort(), m()) << "\n";);
var_subst subst(m(), false);
scoped_rlimit no_limit(m().limit(), 0);
result = subst(_t, coerced_args);
if (well_sorted_check_enabled() && !is_well_sorted(m(), result))
throw cmd_exception("invalid macro application, sort mismatch ", s);
return true;
}
return false;
}
bool cmd_context::try_mk_pdecl_app(symbol const & s, unsigned num_args, expr * const * args, unsigned num_indices, parameter const * indices, expr_ref & r) const {
sort_ref_vector binding(m());
auto match = [&](sort* s, sort* ps) {
if (ps == s)
return true;
if (m().is_uninterp(ps) && ps->get_name().is_numerical()) {
int index = ps->get_name().get_num();
if (index < 0)
return false;
binding.reserve(index + 1);
if (binding.get(index) && binding.get(index) != s)
return false;
binding[index] = s;
return true;
}
// Other matching is TBD
return false;
};
datatype::util dt(m());
func_decl_ref fn(m());
for (auto* c : dt.plugin().get_constructors(s)) {
if (c->accessors().size() != num_args)
continue;
binding.reset();
unsigned i = 0;
for (auto* a : *c)
if (!match(args[i++]->get_sort(), a->range()))
goto match_failure;
if (binding.size() != c->get_def().params().size())
goto match_failure;
for (auto* b : binding)
if (!b)
goto match_failure;
fn = c->instantiate(binding);
r = m().mk_app(fn, num_args, args);
return true;
match_failure:
;
}
if (num_args != 1)
return false;
if (!dt.is_datatype(args[0]->get_sort()))
return false;
for (auto* a : dt.plugin().get_accessors(s)) {
fn = a->instantiate(args[0]->get_sort());
r = m().mk_app(fn, num_args, args);
return true;
}
return false;
}
void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * args,
unsigned num_indices, parameter const * indices, sort * range,
expr_ref & result) {
if (try_mk_macro_app(s, num_args, args, num_indices, indices, range, result))
return;
if (try_mk_declared_app(s, num_args, args, num_indices, indices, range, result))
return;
if (try_mk_builtin_app(s, num_args, args, num_indices, indices, range, result))
return;
if (!range && try_mk_pdecl_app(s, num_args, args, num_indices, indices, result))
return;
func_decls fs;
m_func_decls.find(s, fs);
std::ostringstream buffer;
buffer << "unknown constant " << s;
if (num_args > 0) {
buffer << " (";
for (unsigned i = 0; i < num_args; ++i)
if (args[i])
buffer << ((i > 0)?" ":"") << mk_pp(args[i]->get_sort(), m());
buffer << ") ";
}
if (range)
buffer << mk_pp(range, m()) << " ";
for (unsigned i = 0; i < fs.get_num_entries(); ++i)
if (fs.get_entry(i))
buffer << "\ndeclared: " << mk_pp(fs.get_entry(i), m()) << " ";
throw cmd_exception(buffer.str());
}
void cmd_context::erase_func_decl(symbol const & s) {
if (!global_decls()) {
throw cmd_exception("function declarations can only be erased when global declarations (instead of scoped) are used");
}
func_decls fs;
m_func_decls.find(s, fs);
while (!fs.empty()) {
func_decl * f = fs.first();
if (s != f->get_name()) {
SASSERT(m_func_decl2alias.contains(f));
m_func_decl2alias.erase(f);
}
fs.erase(m(), f);
}
fs.finalize(m());
m_func_decls.erase(s);
}
void cmd_context::erase_func_decl_core(symbol const & s, func_decl * f) {
func_decls fs;
m_func_decls.find(s, fs);
if (fs.contains(f)) {
if (s != f->get_name()) {
SASSERT(m_func_decl2alias.contains(f));
m_func_decl2alias.erase(f);
}
get_recfun_plugin().erase_def(f);
fs.erase(m(), f);
if (fs.empty())
m_func_decls.erase(s);
}
}
void cmd_context::erase_func_decl(symbol const & s, func_decl * f) {
if (!global_decls()) {
throw cmd_exception("function declarations can only be erased when global (instead of scoped) declarations are used");
}
erase_func_decl_core(s, f);
}
void cmd_context::erase_psort_decl_core(symbol const & s) {
psort_decl * p;
if (m_psort_decls.find(s, p)) {
pm().dec_ref(p);
m_psort_decls.erase(s);
}
}
void cmd_context::erase_psort_decl(symbol const & s) {
if (!global_decls()) {
throw cmd_exception("sort declarations can only be erased when global (instead of scoped) declarations are used");
}
erase_psort_decl_core(s);
}
void cmd_context::erase_cmd(symbol const & s) {
cmd * c;
if (m_cmds.find(s, c)) {
c->finalize(*this);
m_cmds.erase(s);
dealloc(c);
}
}
void cmd_context::erase_user_tactic(symbol const & s) {
sexpr * d;
if (m_user_tactic_decls.find(s, d)) {
m_user_tactic_decls.erase(s);
sm().dec_ref(d);
}
}
void cmd_context::erase_object_ref(symbol const & s) {
object_ref * r = nullptr;
if (m_object_refs.find(s, r)) {
r->dec_ref(*this);
m_object_refs.erase(s);
}
}
void cmd_context::reset_func_decls() {
for (auto & kv : m_func_decls) {
kv.m_value.finalize(m());
}
m_func_decls.reset();
m_func_decls_stack.reset();
m_func_decl2alias.reset();
}
void cmd_context::reset_psort_decls() {
for (auto & kv : m_psort_decls) {
psort_decl * p = kv.m_value;
pm().dec_ref(p);
}
m_psort_decls.reset();
m_psort_decls_stack.reset();
}
void cmd_context::reset_macros() {
for (auto & kv : m_macros) {
kv.m_value.finalize(m());
}
m_macros.reset();
m_macros_stack.reset();
}
void cmd_context::reset_cmds() {
for (auto& [k,v] : m_cmds) {
v->reset(*this);
}
}
void cmd_context::finalize_cmds() {
for (auto& [k,c] : m_cmds) {
c->finalize(*this);
dealloc(c);
}
m_cmds.reset();
}
void cmd_context::reset_user_tactics() {
dec_ref_values(sm(), m_user_tactic_decls);
m_user_tactic_decls.reset();
}
void cmd_context::reset_object_refs() {
for (auto& kv : m_object_refs) {
object_ref * r = kv.m_value;
r->dec_ref(*this);
}
m_object_refs.reset();
}
void cmd_context::insert_aux_pdecl(pdecl * p) {
pm().inc_ref(p);
m_aux_pdecls.push_back(p);
}
void cmd_context::reset(bool finalize) {
m_logic = symbol::null;
m_check_sat_result = nullptr;
m_numeral_as_real = false;
m_builtin_decls.reset();
m_extra_builtin_decls.reset();
m_check_logic.reset();
m_proof_cmds = nullptr;
reset_object_refs();
reset_cmds();
reset_psort_decls();
restore_aux_pdecls(0);
reset_macros();
reset_func_decls();
restore_assertions(0);
m_solver = nullptr;
m_mcs.reset();
m_mcs.push_back(nullptr);
m_scopes.reset();
m_opt = nullptr;
m_pp_env = nullptr;
m_dt_eh = nullptr;
if (m_manager) {
dealloc(m_pmanager);
m_pmanager = nullptr;
if (m_own_manager) {
dealloc(m_manager);
m_manager = nullptr;
m_manager_initialized = false;
}
else {
// doesn't own manager... so it cannot be deleted
// reinit cmd_context if this is not a finalization step
if (!finalize)
init_external_manager();
else
m_manager_initialized = false;
}
}
if (m_sexpr_manager) {
dealloc(m_sexpr_manager);
m_sexpr_manager = nullptr;
}
SASSERT(!m_own_manager || !has_manager());
}
void cmd_context::assert_expr(expr * t) {
scoped_rlimit no_limit(m().limit(), 0);
if (!m_check_logic(t))
throw cmd_exception(m_check_logic.get_last_error());
m_check_sat_result = nullptr;
m().inc_ref(t);
m_assertions.push_back(t);
if (produce_unsat_cores())
m_assertion_names.push_back(nullptr);
if (m_solver)
m_solver->assert_expr(t);
}
void cmd_context::assert_expr(symbol const & name, expr * t) {
if (!m_check_logic(t))
throw cmd_exception(m_check_logic.get_last_error());
if (!produce_unsat_cores() || name == symbol::null) {
assert_expr(t);
return;
}
scoped_rlimit no_limit(m().limit(), 0);
m_check_sat_result = nullptr;
m().inc_ref(t);
m_assertions.push_back(t);
app * ans = m().mk_skolem_const(name, m().mk_bool_sort());
m().inc_ref(ans);
m_assertion_names.push_back(ans);
if (m_solver)
m_solver->assert_expr(t, ans);
}
void cmd_context::push() {
m_check_sat_result = nullptr;
init_manager();
m_scopes.push_back(scope());
scope & s = m_scopes.back();
s.m_func_decls_stack_lim = m_func_decls_stack.size();
s.m_psort_decls_stack_lim = m_psort_decls_stack.size();
s.m_psort_inst_stack_lim = m_psort_inst_stack.size();
s.m_macros_stack_lim = m_macros_stack.size();
s.m_aux_pdecls_lim = m_aux_pdecls.size();
s.m_assertions_lim = m_assertions.size();
if (!m_global_decls)
pm().push();
ast_translation tr(m(), m());
m_mcs.push_back(m_mcs.back() ? m_mcs.back()->copy(tr) : nullptr);
unsigned timeout = m_params.m_timeout;
m().limit().push(m_params.rlimit());
cancel_eh eh(m().limit());
scoped_ctrl_c ctrlc(eh);
scoped_timer timer(timeout, &eh);
scoped_rlimit _rlimit(m().limit(), m_params.rlimit());
try {
if (m_solver)
m_solver->push();
if (m_opt)
m_opt->push();
}
catch (z3_error & ex) {
throw ex;
}
catch (z3_exception & ex) {
throw cmd_exception(ex.msg());
}
}
void cmd_context::push(unsigned n) {
for (unsigned i = 0; i < n; i++)
push();
}
void cmd_context::restore_func_decls(unsigned old_sz) {
SASSERT(old_sz <= m_func_decls_stack.size());
svector::iterator it = m_func_decls_stack.begin() + old_sz;
svector::iterator end = m_func_decls_stack.end();
for (; it != end; ++it) {
sf_pair const & p = *it;
erase_func_decl_core(p.first, p.second);
}
m_func_decls_stack.resize(old_sz);
}
void cmd_context::restore_psort_inst(unsigned old_sz) {
for (unsigned i = m_psort_inst_stack.size(); i-- > old_sz; ) {
pdecl * s = m_psort_inst_stack[i];
s->reset_cache(pm());
pm().dec_ref(s);
}
m_psort_inst_stack.resize(old_sz);
}
void cmd_context::restore_psort_decls(unsigned old_sz) {
SASSERT(old_sz <= m_psort_decls_stack.size());
svector::iterator it = m_psort_decls_stack.begin() + old_sz;
svector::iterator end = m_psort_decls_stack.end();
for (; it != end; ++it) {
symbol const & s = *it;
psort_decl * d = nullptr;
VERIFY(m_psort_decls.find(s, d));
pm().dec_ref(d);
m_psort_decls.erase(s);
}
m_psort_decls_stack.shrink(old_sz);
}
void cmd_context::restore_macros(unsigned old_sz) {
SASSERT(old_sz <= m_macros_stack.size());
svector::iterator it = m_macros_stack.begin() + old_sz;
svector::iterator end = m_macros_stack.end();
for (; it != end; ++it)
erase_macro(*it);
m_macros_stack.shrink(old_sz);
}
void cmd_context::restore_aux_pdecls(unsigned old_sz) {
SASSERT(old_sz <= m_aux_pdecls.size());
ptr_vector::iterator it = m_aux_pdecls.begin() + old_sz;
ptr_vector::iterator end = m_aux_pdecls.end();
for (; it != end; ++it) {
pm().dec_ref(*it);
}
m_aux_pdecls.shrink(old_sz);
}
static void restore(ast_manager & m, ptr_vector & c, unsigned old_sz) {
ptr_vector::iterator it = c.begin() + old_sz;
ptr_vector::iterator end = c.end();
for (; it != end; ++it) {
m.dec_ref(*it);
}
c.shrink(old_sz);
}
void cmd_context::restore_assertions(unsigned old_sz) {
if (!has_manager()) {
// restore_assertions invokes m(), so if cmd_context does not have a manager, it will try to create one.
SASSERT(old_sz == m_assertions.size());
SASSERT(m_assertions.empty());
return;
}
if (m_assertions.empty())
return;
if (old_sz == m_assertions.size())
return;
SASSERT(old_sz < m_assertions.size());
SASSERT(!m_interactive_mode || m_assertions.size() == m_assertion_strings.size());
restore(m(), m_assertions, old_sz);
if (produce_unsat_cores())
restore(m(), m_assertion_names, old_sz);
if (m_interactive_mode)
m_assertion_strings.resize(old_sz);
}
void cmd_context::pop(unsigned n) {
m_check_sat_result = nullptr;
if (n == 0)
return;
unsigned lvl = m_scopes.size();
if (n > lvl)
throw cmd_exception("invalid pop command, argument is greater than the current stack depth");
if (m_solver) {
m_solver->pop(n);
}
if (m_opt)
m_opt->pop(n);
unsigned new_lvl = lvl - n;
scope & s = m_scopes[new_lvl];
restore_func_decls(s.m_func_decls_stack_lim);
restore_psort_decls(s.m_psort_decls_stack_lim);
restore_macros(s.m_macros_stack_lim);
restore_aux_pdecls(s.m_aux_pdecls_lim);
restore_assertions(s.m_assertions_lim);
restore_psort_inst(s.m_psort_inst_stack_lim);
m_dt_eh.get()->reset();
m_mcs.shrink(m_mcs.size() - n);
m_scopes.shrink(new_lvl);
if (!m_global_decls)
pm().pop(n);
while (n--) {
m().limit().pop();
}
}
void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions) {
if (m_ignore_check)
return;
IF_VERBOSE(100, verbose_stream() << "(started \"check-sat\")" << std::endl;);
init_manager();
TRACE("before_check_sat", dump_assertions(tout););
unsigned timeout = m_params.m_timeout;
unsigned rlimit = m_params.rlimit();
scoped_watch sw(*this);
lbool r;
if (m_opt && !m_opt->empty()) {
bool is_clear = m_check_sat_result == nullptr;
m_check_sat_result = get_opt();
cancel_eh eh(m().limit());
scoped_ctrl_c ctrlc(eh);
scoped_timer timer(timeout, &eh);
scoped_rlimit _rlimit(m().limit(), rlimit);
expr_ref_vector asms(m());
asms.append(num_assumptions, assumptions);
if (!get_opt()->is_pareto() || is_clear) {
expr_ref_vector assertions(m());
unsigned sz = m_assertions.size();
for (unsigned i = 0; i < sz; ++i) {
if (m_assertion_names.size() > i && m_assertion_names[i]) {
asms.push_back(m_assertion_names[i]);
assertions.push_back(m().mk_implies(m_assertion_names[i], m_assertions[i]));
}
else {
assertions.push_back(m_assertions[i]);
}
}
get_opt()->set_hard_constraints(assertions);
}
try {
r = get_opt()->optimize(asms);
}
catch (z3_error & ex) {
throw ex;
}
catch (z3_exception & ex) {
throw cmd_exception(ex.msg());
}
get_opt()->set_status(r);
}
else if (m_solver) {
m_check_sat_result = m_solver.get(); // solver itself stores the result.
m_solver->set_progress_callback(this);
cancel_eh eh(m().limit());
scoped_ctrl_c ctrlc(eh);
scoped_timer timer(timeout, &eh);
scoped_rlimit _rlimit(m().limit(), rlimit);
try {
r = m_solver->check_sat(num_assumptions, assumptions);
if (r == l_undef && !m().inc()) {
m_solver->set_reason_unknown(eh);
}
}
catch (z3_error & ex) {
throw ex;
}
catch (z3_exception & ex) {
if (!m().inc()) {
m_solver->set_reason_unknown(eh);
}
else {
m_solver->set_reason_unknown(ex.msg());
}
r = l_undef;
}
m_solver->set_status(r);
}
else {
// There is no solver installed in the command context.
regular_stream() << "unknown" << std::endl;
return;
}
display_sat_result(r);
if (r == l_true) {
validate_model();
}
validate_check_sat_result(r);
model_ref md;
if (r == l_true && m_params.m_dump_models && is_model_available(md)) {
display_model(md);
}
}
void cmd_context::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector & conseq) {
unsigned timeout = m_params.m_timeout;
unsigned rlimit = m_params.rlimit();
lbool r;
m_check_sat_result = m_solver.get(); // solver itself stores the result.
m_solver->set_progress_callback(this);
cancel_eh eh(m().limit());
scoped_ctrl_c ctrlc(eh);
scoped_timer timer(timeout, &eh);
scoped_rlimit _rlimit(m().limit(), rlimit);
try {
r = m_solver->get_consequences(assumptions, vars, conseq);
}
catch (z3_error & ex) {
throw ex;
}
catch (z3_exception & ex) {
m_solver->set_reason_unknown(ex.msg());
r = l_undef;
}
m_solver->set_status(r);
display_sat_result(r);
}
void cmd_context::reset_assertions() {
if (m_opt) {
m_opt = nullptr;
}
if (m_solver) {
m_solver = nullptr;
mk_solver();
}
restore_assertions(0);
for (scope& s : m_scopes) {
s.m_assertions_lim = 0;
if (m_solver) m_solver->push();
}
}
void cmd_context::display_dimacs() {
if (m_solver) {
try {
gparams::set("sat.dimacs.display", "true");
params_ref p;
m_solver->updt_params(p);
m_solver->check_sat(0, nullptr);
}
catch (...) {
gparams::set("sat.dimacs.display", "false");
params_ref p;
m_solver->updt_params(p);
throw;
}
gparams::set("sat.dimacs.display", "false");
params_ref p;
m_solver->updt_params(p);
}
}
void cmd_context::display_model(model_ref& mdl) {
if (mdl) {
if (mc0()) (*mc0())(mdl);
model_params p;
if (p.compact()) mdl->compress();
add_declared_functions(*mdl);
if (p.v1() || p.v2()) {
std::ostringstream buffer;
model_v2_pp(buffer, *mdl, false);
regular_stream() << '"' << escaped(buffer.str(), true) << '"' << std::endl;
} else {
regular_stream() << "(" << std::endl;
model_smt2_pp(regular_stream(), *this, *mdl, 2);
regular_stream() << ")" << std::endl;
}
}
}
void cmd_context::add_declared_functions(model& mdl) {
model_params p;
if (!p.user_functions())
return;
for (auto const& kv : m_func_decls) {
func_decl* f = kv.m_value.first();
if (f->get_family_id() == null_family_id && !mdl.has_interpretation(f)) {
expr* val = mdl.get_some_value(f->get_range());
if (f->get_arity() == 0) {
mdl.register_decl(f, val);
}
else {
func_interp* fi = alloc(func_interp, m(), f->get_arity());
fi->set_else(val);
mdl.register_decl(f, fi);
}
}
}
mdl.add_rec_funs();
}
void cmd_context::display_sat_result(lbool r) {
if (has_manager() && m().has_trace_stream()) {
m().trace_stream().flush();
}
switch (r) {
case l_true:
regular_stream() << "sat" << std::endl;
break;
case l_false:
regular_stream() << "unsat" << std::endl;
break;
case l_undef:
regular_stream() << "unknown" << std::endl;
break;
}
}
void cmd_context::validate_check_sat_result(lbool r) {
switch (r) {
case l_true:
if (m_status == UNSAT) {
#ifdef _EXTERNAL_RELEASE
throw cmd_exception("check annotation that says unsat");
#else
diagnostic_stream() << "BUG: incompleteness" << std::endl;
// WORKAROUND: `exit()` causes LSan to be invoked and produce
// many false positives.
_Exit(ERR_INCOMPLETENESS);
#endif
}
break;
case l_false:
if (m_status == SAT) {
#ifdef _EXTERNAL_RELEASE
throw cmd_exception("check annotation that says sat");
#else
diagnostic_stream() << "BUG: unsoundness" << std::endl;
// WORKAROUND: `exit()` causes LSan to be invoked and produce
// many false positives.
_Exit(ERR_UNSOUNDNESS);
#endif
}
break;
default:
break;
}
}
void cmd_context::set_diagnostic_stream(char const * name) {
m_diagnostic.set(name);
if (m_main_ctx) {
set_warning_stream(&(*m_diagnostic));
set_verbose_stream(diagnostic_stream());
}
}
struct contains_underspecified_op_proc {
struct found {};
family_id m_array_fid;
datatype_util m_dt;
arith_util m_arith;
seq_util m_seq;
family_id m_seq_id;
contains_underspecified_op_proc(ast_manager & m):
m_array_fid(m.mk_family_id("array")),
m_dt(m),
m_arith(m),
m_seq(m),
m_seq_id(m_seq.get_family_id()) {}
void operator()(var * n) {}
void operator()(app * n) {
if (m_dt.is_accessor(n->get_decl()))
throw found();
if (m_dt.is_update_field(n->get_decl()))
throw found();
if (n->get_family_id() == m_seq_id && m_seq.is_re(n))
throw found();
if (m_arith.plugin().is_considered_uninterpreted(n->get_decl()))
throw found();
if (m_arith.is_non_algebraic(n))
throw found();
if (m_arith.is_irrational_algebraic_numeral(n))
throw found();
if (n->get_family_id() == m_array_fid) {
decl_kind k = n->get_decl_kind();
if (k == OP_AS_ARRAY ||
k == OP_STORE ||
k == OP_ARRAY_MAP ||
k == OP_CONST_ARRAY)
throw found();
}
}
void operator()(quantifier * n) {}
};
/**
\brief Complete the model if necessary.
*/
void cmd_context::complete_model(model_ref& md) const {
if (!md.get())
return;
if (gparams::get_value("model.completion") != "true")
return;
params_ref p;
p.set_uint("max_degree", UINT_MAX); // evaluate algebraic numbers of any degree.
p.set_uint("sort_store", true);
p.set_bool("completion", true);
model_evaluator evaluator(*(md.get()), p);
evaluator.set_expand_array_equalities(false);
scoped_rlimit _rlimit(m().limit(), 0);
cancel_eh eh(m().limit());
expr_ref r(m());
scoped_ctrl_c ctrlc(eh);
for (auto kd : m_psort_decls) {
symbol const & k = kd.m_key;
psort_decl * v = kd.m_value;
if (v->is_user_decl()) {
SASSERT(!v->has_var_params());
IF_VERBOSE(12, verbose_stream() << "(model.completion " << k << ")\n"; );
ptr_vector param_sorts(v->get_num_params(), m().mk_bool_sort());
sort * srt = v->instantiate(pm(), param_sorts.size(), param_sorts.data());
if (!md->has_uninterpreted_sort(srt)) {
expr * singleton = m().get_some_value(srt);
md->register_usort(srt, 1, &singleton);
}
}
}
for (unsigned i = 0; i < md->get_num_functions(); i++) {
func_decl * f = md->get_function(i);
func_interp * fi = md->get_func_interp(f);
IF_VERBOSE(12, verbose_stream() << "(model.completion " << f->get_name() << ")\n"; );
if (fi->is_partial()) {
sort * range = f->get_range();
fi->set_else(m().get_some_value(range));
}
}
for (auto& [k, v] : m_func_decls) {
IF_VERBOSE(12, verbose_stream() << "(model.completion " << k << ")\n"; );
for (unsigned i = 0; i < v.get_num_entries(); i++) {
func_decl * f = v.get_entry(i);
if (md->has_interpretation(f))
continue;
macro_decls decls;
expr* body = nullptr;
if (m_macros.find(k, decls))
body = decls.find(f->get_arity(), f->get_domain());
sort * range = f->get_range();
if (!body)
body = m().get_some_value(range);
if (f->get_arity() > 0) {
func_interp * fi = alloc(func_interp, m(), f->get_arity());
fi->set_else(body);
md->register_decl(f, fi);
}
else
md->register_decl(f, body);
}
}
}
/**
\brief Check if the current model satisfies the quantifier free formulas.
*/
void cmd_context::validate_model() {
model_ref md;
if (!validate_model_enabled())
return;
if (!is_model_available(md))
return;
SASSERT(md.get() != 0);
params_ref p;
p.set_uint("max_degree", UINT_MAX); // evaluate algebraic numbers of any degree.
p.set_uint("sort_store", true);
p.set_bool("completion", true);
model_evaluator evaluator(*(md.get()), p);
evaluator.set_expand_array_equalities(false);
contains_underspecified_op_proc contains_underspecified(m());
{
scoped_rlimit _rlimit(m().limit(), 0);
cancel_eh eh(m().limit());
expr_ref r(m());
scoped_ctrl_c ctrlc(eh);
expr_mark seen;
bool invalid_model = false;
for (expr * a : assertions()) {
if (is_ground(a)) {
r = nullptr;
evaluator(a, r);
TRACE("model_validate", tout << "checking\n" << mk_ismt2_pp(a, m()) << "\nresult: " << mk_ismt2_pp(r, m()) << "\n";);
if (m().is_true(r))
continue;
TRACE("model_validate", tout << *md << "\n";);
// The evaluator for array expressions is not complete
// If r contains as_array/store/map/const expressions, then we do not generate the error.
// TODO: improve evaluator for model expressions.
// Note that, if "a" evaluates to false, then the error will be generated.
if (has_quantifiers(r)) {
continue;
}
try {
if (!m().is_false(r))
for_each_expr(contains_underspecified, a);
for_each_expr(contains_underspecified, r);
}
catch (const contains_underspecified_op_proc::found &) {
continue;
}
analyze_failure(seen, evaluator, a, true);
IF_VERBOSE(11, model_smt2_pp(verbose_stream(), *this, *md, 0););
TRACE("model_validate", model_smt2_pp(tout, *this, *md, 0););
invalid_model |= m().is_false(r);
}
}
if (invalid_model) {
throw cmd_exception("an invalid model was generated");
}
}
}
void cmd_context::analyze_failure(expr_mark& seen, model_evaluator& ev, expr* a, bool expected_value) {
expr* c = nullptr, *t = nullptr, *e = nullptr;
if (seen.is_marked(a))
return;
seen.mark(a, true);
if (m().is_not(a, e)) {
analyze_failure(seen, ev, e, !expected_value);
return;
}
if (!expected_value && m().is_or(a)) {
for (expr* arg : *to_app(a)) {
if (ev.is_true(arg)) {
analyze_failure(seen, ev, arg, false);
return;
}
}
}
if (expected_value && m().is_and(a)) {
for (expr* arg : *to_app(a)) {
if (ev.is_false(arg)) {
analyze_failure(seen, ev, arg, true);
return;
}
}
}
if (expected_value && m().is_ite(a, c, t, e)) {
if (ev.is_true(c) && ev.is_false(t)) {
if (!m().is_true(c)) analyze_failure(seen, ev, c, false);
if (!m().is_false(t)) analyze_failure(seen, ev, t, true);
return;
}
if (ev.is_false(c) && ev.is_false(e)) {
if (!m().is_false(c)) analyze_failure(seen, ev, c, true);
if (!m().is_false(e)) analyze_failure(seen, ev, e, true);
return;
}
}
if (!expected_value && m().is_ite(a, c, t, e)) {
if (ev.is_true(c) && ev.is_true(t)) {
if (!m().is_true(c)) analyze_failure(seen, ev, c, false);
if (!m().is_true(t)) analyze_failure(seen, ev, t, false);
return;
}
if (ev.is_false(c) && ev.is_true(e)) {
if (!m().is_false(c)) analyze_failure(seen, ev, c, true);
if (!m().is_true(e)) analyze_failure(seen, ev, e, false);
return;
}
}
IF_VERBOSE(10, verbose_stream() << "#" << a->get_id() << " " << mk_pp(a, m()) << " expected: "
<< (expected_value?"true":"false") << "\n";);
IF_VERBOSE(11, display_detailed_analysis(verbose_stream(), ev, a));
if (m().is_iff(a)) {
ptr_vector todo;
todo.push_back(a);
for (unsigned i = 0; i < todo.size(); ++i) {
e = todo[i];
if (m().is_and(e) || m().is_or(e) || m().is_iff(e) || m().is_implies(e) || m().is_not(e))
for (expr* arg : *to_app(e))
todo.push_back(arg);
else
IF_VERBOSE(10, verbose_stream() << "#" << e->get_id() << " " << mk_bounded_pp(e, m()) << " " << (ev.is_true(e)?"true":"false") << "\n");
}
return;
}
}
void cmd_context::display_detailed_analysis(std::ostream& out, model_evaluator& ev, expr* e) {
ptr_vector es;
es.push_back(e);
expr_mark visited;
for (unsigned i = 0; i < es.size(); ++i) {
e = es[i];
if (visited.is_marked(e)) {
continue;
}
visited.mark(e, true);
expr_ref val = ev(e);
out << "#" << e->get_id() << ": " << mk_bounded_pp(e, m(), 1) << " " << val << "\n";
if (is_app(e)) {
for (expr* arg : *to_app(e)) {
es.push_back(arg);
}
}
}
}
void cmd_context::mk_solver() {
bool proofs_enabled = m().proofs_enabled(), models_enabled = true, unsat_core_enabled = true;
params_ref p;
m_params.get_solver_params(p, proofs_enabled, models_enabled, unsat_core_enabled);
m_solver = (*m_solver_factory)(m(), p, proofs_enabled, models_enabled, unsat_core_enabled, m_logic);
}
void cmd_context::set_solver_factory(solver_factory * f) {
m_solver_factory = f;
m_check_sat_result = nullptr;
if (has_manager() && f != nullptr) {
mk_solver();
// assert formulas and create scopes in the new solver.
unsigned lim = 0;
for (scope& s : m_scopes) {
for (unsigned i = lim; i < s.m_assertions_lim; i++) {
m_solver->assert_expr(m_assertions[i]);
}
lim = s.m_assertions_lim;
m_solver->push();
}
unsigned sz = m_assertions.size();
for (unsigned i = lim; i < sz; i++) {
m_solver->assert_expr(m_assertions[i]);
}
}
}
void cmd_context::display_statistics(bool show_total_time, double total_time) {
statistics st;
if (show_total_time)
st.update("total time", total_time);
st.update("time", get_seconds());
get_memory_statistics(st);
get_rlimit_statistics(m().limit(), st);
if (m_check_sat_result) {
m_check_sat_result->collect_statistics(st);
}
else if (m_solver) {
m_solver->collect_statistics(st);
}
else if (m_opt) {
m_opt->collect_statistics(st);
}
st.display_smt2(regular_stream());
}
vector> cmd_context::tracked_assertions() {
vector> result;
if (assertion_names().size() == assertions().size()) {
for (unsigned i = 0; i < assertions().size(); ++i) {
expr* an = assertion_names()[i];
expr* asr = assertions()[i];
result.push_back({ asr, an });
}
}
else {
for (expr * e : assertions())
result.push_back({ e, nullptr});
}
return result;
}
void cmd_context::reset_tracked_assertions() {
for (expr* a : m_assertion_names)
m().dec_ref(a);
m_assertion_names.reset();
for (expr* a : m_assertions)
m().dec_ref(a);
m_assertions.reset();
}
void cmd_context::display_assertions() {
if (!m_interactive_mode)
throw cmd_exception("command is only available in interactive mode, use command (set-option :interactive-mode true)");
regular_stream() << "(";
bool first = true;
for (std::string const& s : m_assertion_strings) {
if (first)
first = false;
else
regular_stream() << "\n ";
regular_stream() << s;
}
regular_stream() << ")" << std::endl;
}
bool cmd_context::is_model_available(model_ref& md) const {
if (produce_models() &&
has_manager() &&
(cs_state() == css_sat || cs_state() == css_unknown)) {
get_check_sat_result()->get_model(md);
params_ref p;
if (md.get()) md->updt_params(p);
complete_model(md);
return md.get() != nullptr;
}
return false;
}
format_ns::format * cmd_context::pp(sort * s) const {
return get_pp_env().pp_sort(s);
}
format_ns::format* cmd_context::try_pp(sort* s) const {
TRACE("cmd_context", tout << "pp(sort * s), s: " << mk_pp(s, m()) << "\n";);
return pm().pp(get_pp_env(), s);
}
cmd_context::pp_env & cmd_context::get_pp_env() const {
if (m_pp_env.get() == nullptr)
const_cast(this)->m_pp_env = alloc(pp_env, *const_cast(this));
return *(m_pp_env.get());
}
void cmd_context::pp(expr * n, unsigned num_vars, char const * var_prefix, format_ns::format_ref & r, sbuffer & var_names) const {
mk_smt2_format(n, get_pp_env(), params_ref(), num_vars, var_prefix, r, var_names);
}
void cmd_context::pp(expr * n, format_ns::format_ref & r) const {
sbuffer buf;
pp(n, 0, nullptr, r, buf);
}
void cmd_context::pp(func_decl * f, format_ns::format_ref & r) const {
mk_smt2_format(f, get_pp_env(), params_ref(), r, "declare-fun");
}
void cmd_context::display(std::ostream & out, sort * s, unsigned indent) const {
format_ns::format_ref f(format_ns::fm(m()));
f = pp(s);
if (indent > 0)
f = format_ns::mk_indent(m(), indent, f);
::pp(out, f.get(), m());
}
void cmd_context::display(std::ostream & out, expr * n, unsigned indent, unsigned num_vars, char const * var_prefix, sbuffer & var_names) const {
format_ns::format_ref f(format_ns::fm(m()));
pp(n, num_vars, var_prefix, f, var_names);
if (indent > 0)
f = format_ns::mk_indent(m(), indent, f);
::pp(out, f.get(), m());
}
void cmd_context::display(std::ostream & out, expr * n, unsigned indent) const {
sbuffer buf;
display(out, n, indent, 0, nullptr, buf);
}
void cmd_context::display(std::ostream & out, func_decl * d, unsigned indent) const {
format_ns::format_ref f(format_ns::fm(m()));
pp(d, f);
if (indent > 0)
f = format_ns::mk_indent(m(), indent, f);
::pp(out, f.get(), m());
}
void cmd_context::dump_assertions(std::ostream & out) const {
for (expr * e : m_assertions) {
display(out, e);
out << std::endl;
}
}
void cmd_context::display_smt2_benchmark(std::ostream & out, unsigned num, expr * const * assertions, symbol const & logic) const {
if (logic != symbol::null)
out << "(set-logic " << logic << ")" << std::endl;
// collect uninterpreted function declarations
decl_collector decls(m());
for (unsigned i = 0; i < num; i++)
decls.visit(assertions[i]);
// TODO: display uninterpreted sort decls, and datatype decls.
for (func_decl* f : decls.get_func_decls()) {
display(out, f);
out << std::endl;
}
for (unsigned i = 0; i < num; i++) {
out << "(assert ";
display(out, assertions[i], 8);
out << ")" << std::endl;
}
out << "(check-sat)" << std::endl;
}
void cmd_context::slow_progress_sample() {
SASSERT(m_solver);
statistics st;
regular_stream() << "(progress\n";
m_solver->collect_statistics(st);
st.display_smt2(regular_stream());
svector labels;
m_solver->get_labels(labels);
regular_stream() << "(labels";
for (symbol const& s : labels)
regular_stream() << " " << s;
regular_stream() << "))" << std::endl;
}
void cmd_context::fast_progress_sample() {
}
cmd_context::dt_eh::dt_eh(cmd_context & owner):
m_owner(owner),
m_dt_util(owner.m()) {
}
cmd_context::dt_eh::~dt_eh() {
}
void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) {
TRACE("new_dt_eh", tout << "new datatype: "; m_owner.pm().display(tout, dt); tout << "\n";);
for (func_decl * c : *m_dt_util.get_datatype_constructors(dt)) {
TRACE("new_dt_eh", tout << "new constructor: " << c->get_name() << "\n";);
m_owner.insert(c);
func_decl * r = m_dt_util.get_constructor_recognizer(c);
m_owner.insert(r);
// TRACE("new_dt_eh", tout << "new recognizer: " << r->get_name() << "\n";);
for (func_decl * a : *m_dt_util.get_constructor_accessors(c)) {
TRACE("new_dt_eh", tout << "new accessor: " << a->get_name() << "\n";);
m_owner.insert(a);
}
}
if (!m_owner.m_scopes.empty() && !m_owner.m_global_decls) {
m_owner.pm().inc_ref(pd);
m_owner.m_psort_inst_stack.push_back(pd);
}
}
std::ostream & operator<<(std::ostream & out, cmd_context::status st) {
switch (st) {
case cmd_context::UNSAT: out << "unsat"; break;
case cmd_context::SAT: out << "sat"; break;
default: out << "unknown"; break;
}
return out;
}