mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 09:35:32 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
e168d8a2eb
109 changed files with 4372 additions and 2743 deletions
|
@ -46,11 +46,15 @@ public:
|
|||
|
||||
void operator()(model_ref & md) override {
|
||||
TRACE("ackermannize", tout << (fixed_model? "fixed" : "nonfixed") << "\n";);
|
||||
SASSERT(!fixed_model || md.get() == 0 || (!md->get_num_constants() && !md->get_num_functions()));
|
||||
model_ref& old_model = fixed_model ? abstr_model : md;
|
||||
SASSERT(old_model.get());
|
||||
model * new_model = alloc(model, m);
|
||||
convert(old_model.get(), new_model);
|
||||
CTRACE("ackermannize", md, tout << *md << "\n");
|
||||
CTRACE("ackermannize", fixed_model, tout << *abstr_model << "\n");
|
||||
|
||||
model* new_model = alloc(model, m);
|
||||
|
||||
if (abstr_model)
|
||||
convert(abstr_model.get(), new_model);
|
||||
if (md)
|
||||
convert(md.get(), new_model);
|
||||
md = new_model;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,11 +35,12 @@ namespace api {
|
|||
|
||||
object::object(context& c): m_ref_count(0), m_context(c) { this->m_id = m_context.add_object(this); }
|
||||
|
||||
void object::inc_ref() { m_ref_count++; }
|
||||
void object::inc_ref() { ++m_ref_count; }
|
||||
|
||||
void object::dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) m_context.del_object(this); }
|
||||
void object::dec_ref() { SASSERT(m_ref_count > 0); if (--m_ref_count == 0) m_context.del_object(this); }
|
||||
|
||||
unsigned context::add_object(api::object* o) {
|
||||
flush_objects();
|
||||
unsigned id = m_allocated_objects.size();
|
||||
if (!m_free_object_ids.empty()) {
|
||||
id = m_free_object_ids.back();
|
||||
|
@ -50,9 +51,52 @@ namespace api {
|
|||
}
|
||||
|
||||
void context::del_object(api::object* o) {
|
||||
m_free_object_ids.push_back(o->id());
|
||||
m_allocated_objects.remove(o->id());
|
||||
dealloc(o);
|
||||
#ifndef SINGLE_THREAD
|
||||
if (m_concurrent_dec_ref) {
|
||||
lock_guard lock(m_mux);
|
||||
m_objects_to_flush.push_back(o);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_free_object_ids.push_back(o->id());
|
||||
m_allocated_objects.remove(o->id());
|
||||
dealloc(o);
|
||||
}
|
||||
}
|
||||
|
||||
void context::dec_ref(ast* a) {
|
||||
#ifndef SINGLE_THREAD
|
||||
if (m_concurrent_dec_ref) {
|
||||
lock_guard lock(m_mux);
|
||||
m_asts_to_flush.push_back(a);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
m().dec_ref(a);
|
||||
}
|
||||
|
||||
void context::flush_objects() {
|
||||
#ifndef SINGLE_THREAD
|
||||
if (!m_concurrent_dec_ref)
|
||||
return;
|
||||
{
|
||||
lock_guard lock(m_mux);
|
||||
if (m_asts_to_flush.empty() && m_objects_to_flush.empty())
|
||||
return;
|
||||
m_asts_to_flush2.swap(m_asts_to_flush);
|
||||
m_objects_to_flush2.swap(m_objects_to_flush);
|
||||
}
|
||||
for (ast* a : m_asts_to_flush2)
|
||||
m().dec_ref(a);
|
||||
for (auto* o : m_objects_to_flush2) {
|
||||
m_free_object_ids.push_back(o->id());
|
||||
m_allocated_objects.remove(o->id());
|
||||
dealloc(o);
|
||||
}
|
||||
m_objects_to_flush2.reset();
|
||||
m_asts_to_flush2.reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void default_error_handler(Z3_context ctx, Z3_error_code c) {
|
||||
|
@ -106,6 +150,7 @@ namespace api {
|
|||
|
||||
context::~context() {
|
||||
m_last_obj = nullptr;
|
||||
flush_objects();
|
||||
for (auto& kv : m_allocated_objects) {
|
||||
api::object* val = kv.m_value;
|
||||
DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", kv.m_key, typeid(*val).name()););
|
||||
|
@ -356,6 +401,13 @@ extern "C" {
|
|||
Z3_CATCH;
|
||||
}
|
||||
|
||||
void Z3_API Z3_enable_concurrent_dec_ref(Z3_context c) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_enable_concurrent_dec_ref(c);
|
||||
mk_c(c)->enable_concurrent_dec_ref();
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
||||
void Z3_API Z3_toggle_warning_messages(bool enabled) {
|
||||
LOG_Z3_toggle_warning_messages(enabled);
|
||||
enable_warning_messages(enabled != 0);
|
||||
|
@ -365,6 +417,7 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_inc_ref(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
mk_c(c)->flush_objects();
|
||||
mk_c(c)->m().inc_ref(to_ast(a));
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
@ -379,7 +432,7 @@ extern "C" {
|
|||
return;
|
||||
}
|
||||
if (a) {
|
||||
mk_c(c)->m().dec_ref(to_ast(a));
|
||||
mk_c(c)->dec_ref(to_ast(a));
|
||||
}
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,9 @@ namespace api {
|
|||
struct add_plugins { add_plugins(ast_manager & m); };
|
||||
ast_context_params m_params;
|
||||
bool m_user_ref_count; //!< if true, the user is responsible for managing reference counters.
|
||||
#ifndef SINGLE_THREAD
|
||||
bool m_concurrent_dec_ref = false;
|
||||
#endif
|
||||
scoped_ptr<ast_manager> m_manager;
|
||||
scoped_ptr<cmd_context> m_cmd;
|
||||
add_plugins m_plugins;
|
||||
|
@ -91,8 +94,12 @@ namespace api {
|
|||
smt_params m_fparams;
|
||||
// -------------------------------
|
||||
|
||||
ast_ref_vector m_ast_trail;
|
||||
#ifndef SINGLE_THREAD
|
||||
ptr_vector<ast> m_asts_to_flush, m_asts_to_flush2;
|
||||
ptr_vector<api::object> m_objects_to_flush, m_objects_to_flush2;
|
||||
#endif
|
||||
|
||||
ast_ref_vector m_ast_trail;
|
||||
ref<api::object> m_last_obj; //!< reference to the last API object returned by the APIs
|
||||
u_map<api::object*> m_allocated_objects; // !< table containing current set of allocated API objects
|
||||
unsigned_vector m_free_object_ids; // !< free list of identifiers available for allocated objects.
|
||||
|
@ -169,9 +176,18 @@ namespace api {
|
|||
void set_error_code(Z3_error_code err, char const* opt_msg);
|
||||
void set_error_code(Z3_error_code err, std::string &&opt_msg);
|
||||
void set_error_handler(Z3_error_handler h) { m_error_handler = h; }
|
||||
|
||||
|
||||
void enable_concurrent_dec_ref() {
|
||||
#ifdef SINGLE_THREAD
|
||||
set_error_code(Z3_EXCEPTION, "Can't use concurrent features with a single-thread build");
|
||||
#else
|
||||
m_concurrent_dec_ref = true;
|
||||
#endif
|
||||
}
|
||||
unsigned add_object(api::object* o);
|
||||
void del_object(api::object* o);
|
||||
void dec_ref(ast* a);
|
||||
void flush_objects();
|
||||
|
||||
Z3_ast_print_mode get_print_mode() const { return m_print_mode; }
|
||||
void set_print_mode(Z3_ast_print_mode m) { m_print_mode = m; }
|
||||
|
|
|
@ -35,6 +35,136 @@ extern "C" {
|
|||
// ---------------
|
||||
// Support for SMTLIB2
|
||||
|
||||
struct Z3_parser_context_ref : public api::object {
|
||||
scoped_ptr<cmd_context> ctx;
|
||||
|
||||
Z3_parser_context_ref(api::context& c): api::object(c) {
|
||||
ast_manager& m = c.m();
|
||||
ctx = alloc(cmd_context, false, &(m));
|
||||
install_dl_cmds(*ctx.get());
|
||||
install_opt_cmds(*ctx.get());
|
||||
install_smt2_extra_cmds(*ctx.get());
|
||||
ctx->register_plist();
|
||||
ctx->set_ignore_check(true);
|
||||
}
|
||||
|
||||
~Z3_parser_context_ref() override {}
|
||||
};
|
||||
|
||||
inline Z3_parser_context_ref * to_parser_context(Z3_parser_context pc) { return reinterpret_cast<Z3_parser_context_ref*>(pc); }
|
||||
inline Z3_parser_context of_parser_context(Z3_parser_context_ref* pc) { return reinterpret_cast<Z3_parser_context>(pc); }
|
||||
|
||||
Z3_parser_context Z3_API Z3_mk_parser_context(Z3_context c) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_parser_context(c);
|
||||
RESET_ERROR_CODE();
|
||||
Z3_parser_context_ref * pc = alloc(Z3_parser_context_ref, *mk_c(c));
|
||||
mk_c(c)->save_object(pc);
|
||||
Z3_parser_context r = of_parser_context(pc);
|
||||
RETURN_Z3(r);
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
void Z3_API Z3_parser_context_inc_ref(Z3_context c, Z3_parser_context pc) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_parser_context_inc_ref(c, pc);
|
||||
RESET_ERROR_CODE();
|
||||
to_parser_context(pc)->inc_ref();
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
||||
void Z3_API Z3_parser_context_dec_ref(Z3_context c, Z3_parser_context pc) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_parser_context_dec_ref(c, pc);
|
||||
RESET_ERROR_CODE();
|
||||
to_parser_context(pc)->dec_ref();
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
||||
static void insert_datatype(ast_manager& m, scoped_ptr<cmd_context>& ctx, sort* srt) {
|
||||
datatype_util dt(m);
|
||||
if (!dt.is_datatype(srt))
|
||||
return;
|
||||
|
||||
for (func_decl * c : *dt.get_datatype_constructors(srt)) {
|
||||
ctx->insert(c->get_name(), c);
|
||||
func_decl * r = dt.get_constructor_recognizer(c);
|
||||
ctx->insert(r->get_name(), r);
|
||||
for (func_decl * a : *dt.get_constructor_accessors(c)) {
|
||||
ctx->insert(a->get_name(), a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_sort(ast_manager& m, scoped_ptr<cmd_context>& ctx, symbol const& name, sort* srt) {
|
||||
if (ctx->find_psort_decl(name))
|
||||
return;
|
||||
psort* ps = ctx->pm().mk_psort_cnst(srt);
|
||||
ctx->insert(ctx->pm().mk_psort_user_decl(0, name, ps));
|
||||
insert_datatype(m, ctx, srt);
|
||||
}
|
||||
|
||||
void Z3_API Z3_parser_context_add_sort(Z3_context c, Z3_parser_context pc, Z3_sort s) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_parser_context_add_sort(c, pc, s);
|
||||
RESET_ERROR_CODE();
|
||||
auto& ctx = to_parser_context(pc)->ctx;
|
||||
sort* srt = to_sort(s);
|
||||
symbol name = srt->get_name();
|
||||
insert_sort(mk_c(c)->m(), ctx, name, srt);
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
||||
void Z3_API Z3_parser_context_add_decl(Z3_context c, Z3_parser_context pc, Z3_func_decl f) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_parser_context_add_decl(c, pc, f);
|
||||
RESET_ERROR_CODE();
|
||||
auto& ctx = *to_parser_context(pc)->ctx;
|
||||
func_decl* fn = to_func_decl(f);
|
||||
symbol name = fn->get_name();
|
||||
ctx.insert(name, fn);
|
||||
Z3_CATCH;
|
||||
}
|
||||
|
||||
Z3_ast_vector Z3_parser_context_parse_stream(Z3_context c, scoped_ptr<cmd_context>& ctx, bool owned, std::istream& is) {
|
||||
Z3_TRY;
|
||||
Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
|
||||
mk_c(c)->save_object(v);
|
||||
std::stringstream errstrm;
|
||||
ctx->set_regular_stream(errstrm);
|
||||
try {
|
||||
if (!parse_smt2_commands(*ctx, is)) {
|
||||
if (owned)
|
||||
ctx = nullptr;
|
||||
SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str());
|
||||
return of_ast_vector(v);
|
||||
}
|
||||
}
|
||||
catch (z3_exception& e) {
|
||||
if (owned)
|
||||
ctx = nullptr;
|
||||
errstrm << e.msg();
|
||||
SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str());
|
||||
return of_ast_vector(v);
|
||||
}
|
||||
for (expr* e : ctx->tracked_assertions())
|
||||
v->m_ast_vector.push_back(e);
|
||||
ctx->reset_tracked_assertions();
|
||||
return of_ast_vector(v);
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast_vector Z3_API Z3_parser_context_from_string(Z3_context c, Z3_parser_context pc, Z3_string str) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_parser_context_from_string(c, pc, str);
|
||||
std::string s(str);
|
||||
std::istringstream is(s);
|
||||
auto& ctx = to_parser_context(pc)->ctx;
|
||||
Z3_ast_vector r = Z3_parser_context_parse_stream(c, ctx, false, is);
|
||||
RETURN_Z3(r);
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_ast_vector parse_smtlib2_stream(bool exec, Z3_context c, std::istream& is,
|
||||
unsigned num_sorts,
|
||||
Z3_symbol const _sort_names[],
|
||||
|
@ -48,70 +178,16 @@ extern "C" {
|
|||
install_dl_cmds(*ctx.get());
|
||||
install_opt_cmds(*ctx.get());
|
||||
install_smt2_extra_cmds(*ctx.get());
|
||||
|
||||
ctx->register_plist();
|
||||
ctx->set_ignore_check(true);
|
||||
Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), m);
|
||||
|
||||
vector<symbol> sort_names;
|
||||
ptr_vector<sort> sorts;
|
||||
for (unsigned i = 0; i < num_sorts; ++i) {
|
||||
sorts.push_back(to_sort(_sorts[i]));
|
||||
sort_names.push_back(to_symbol(_sort_names[i]));
|
||||
}
|
||||
|
||||
mk_c(c)->save_object(v);
|
||||
for (unsigned i = 0; i < num_decls; ++i) {
|
||||
func_decl* d = to_func_decl(decls[i]);
|
||||
ctx->insert(to_symbol(decl_names[i]), d);
|
||||
sort_names.push_back(d->get_range()->get_name());
|
||||
sorts.push_back(d->get_range());
|
||||
for (sort* s : *d) {
|
||||
sort_names.push_back(s->get_name());
|
||||
sorts.push_back(s);
|
||||
}
|
||||
}
|
||||
datatype_util dt(m);
|
||||
for (unsigned i = 0; i < num_sorts; ++i) {
|
||||
sort* srt = sorts[i];
|
||||
symbol name = sort_names[i];
|
||||
if (ctx->find_psort_decl(name)) {
|
||||
continue;
|
||||
}
|
||||
psort* ps = ctx->pm().mk_psort_cnst(srt);
|
||||
ctx->insert(ctx->pm().mk_psort_user_decl(0, name, ps));
|
||||
if (!dt.is_datatype(srt)) {
|
||||
continue;
|
||||
}
|
||||
for (unsigned i = 0; i < num_decls; ++i)
|
||||
ctx->insert(to_symbol(decl_names[i]), to_func_decl(decls[i]));
|
||||
|
||||
for (func_decl * c : *dt.get_datatype_constructors(srt)) {
|
||||
ctx->insert(c->get_name(), c);
|
||||
func_decl * r = dt.get_constructor_recognizer(c);
|
||||
ctx->insert(r->get_name(), r);
|
||||
for (func_decl * a : *dt.get_constructor_accessors(c)) {
|
||||
ctx->insert(a->get_name(), a);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::stringstream errstrm;
|
||||
ctx->set_regular_stream(errstrm);
|
||||
try {
|
||||
if (!parse_smt2_commands(*ctx.get(), is)) {
|
||||
ctx = nullptr;
|
||||
SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str());
|
||||
return of_ast_vector(v);
|
||||
}
|
||||
}
|
||||
catch (z3_exception& e) {
|
||||
errstrm << e.msg();
|
||||
ctx = nullptr;
|
||||
SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str());
|
||||
return of_ast_vector(v);
|
||||
}
|
||||
for (expr* e : ctx->tracked_assertions()) {
|
||||
v->m_ast_vector.push_back(e);
|
||||
}
|
||||
return of_ast_vector(v);
|
||||
for (unsigned i = 0; i < num_sorts; ++i)
|
||||
insert_sort(m, ctx, to_symbol(_sort_names[i]), to_sort(_sorts[i]));
|
||||
|
||||
return Z3_parser_context_parse_stream(c, ctx, true, is);
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
|
@ -155,11 +231,13 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_eval_smtlib2_string(c, str);
|
||||
if (!mk_c(c)->cmd()) {
|
||||
mk_c(c)->cmd() = alloc(cmd_context, false, &(mk_c(c)->m()));
|
||||
install_dl_cmds(*mk_c(c)->cmd());
|
||||
install_opt_cmds(*mk_c(c)->cmd());
|
||||
install_smt2_extra_cmds(*mk_c(c)->cmd());
|
||||
mk_c(c)->cmd()->set_solver_factory(mk_smt_strategic_solver_factory());
|
||||
auto* ctx = alloc(cmd_context, false, &(mk_c(c)->m()));
|
||||
mk_c(c)->cmd() = ctx;
|
||||
install_dl_cmds(*ctx);
|
||||
install_opt_cmds(*ctx);
|
||||
install_smt2_extra_cmds(*ctx);
|
||||
ctx->register_plist();
|
||||
ctx->set_solver_factory(mk_smt_strategic_solver_factory());
|
||||
}
|
||||
scoped_ptr<cmd_context>& ctx = mk_c(c)->cmd();
|
||||
std::string s(str);
|
||||
|
@ -180,4 +258,6 @@ extern "C" {
|
|||
RETURN_Z3(mk_c(c)->mk_external_string(ous.str()));
|
||||
Z3_CATCH_RETURN(mk_c(c)->mk_external_string(ous.str()));
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
|
@ -256,7 +256,10 @@ extern "C" {
|
|||
}
|
||||
|
||||
void solver_from_stream(Z3_context c, Z3_solver s, std::istream& is) {
|
||||
scoped_ptr<cmd_context> ctx = alloc(cmd_context, false, &(mk_c(c)->m()));
|
||||
auto& solver = *to_solver(s);
|
||||
if (!solver.m_cmd_context)
|
||||
solver.m_cmd_context = alloc(cmd_context, false, &(mk_c(c)->m()));
|
||||
auto& ctx = solver.m_cmd_context;
|
||||
ctx->set_ignore_check(true);
|
||||
std::stringstream errstrm;
|
||||
ctx->set_regular_stream(errstrm);
|
||||
|
@ -272,6 +275,7 @@ extern "C" {
|
|||
init_solver(c, s);
|
||||
for (expr* e : ctx->tracked_assertions())
|
||||
to_solver(s)->assert_expr(e);
|
||||
ctx->reset_tracked_assertions();
|
||||
to_solver_ref(s)->set_model_converter(ctx->get_model_converter());
|
||||
}
|
||||
|
||||
|
@ -387,9 +391,11 @@ extern "C" {
|
|||
bool new_model = params.get_bool("model", true);
|
||||
if (old_model != new_model)
|
||||
to_solver_ref(s)->set_produce_models(new_model);
|
||||
param_descrs r;
|
||||
to_solver_ref(s)->collect_param_descrs(r);
|
||||
context_params::collect_solver_param_descrs(r);
|
||||
param_descrs& r = to_solver(s)->m_param_descrs;
|
||||
if(r.size () == 0) {
|
||||
to_solver_ref(s)->collect_param_descrs(r);
|
||||
context_params::collect_solver_param_descrs(r);
|
||||
}
|
||||
params.validate(r);
|
||||
to_solver_ref(s)->updt_params(params);
|
||||
}
|
||||
|
|
|
@ -42,8 +42,10 @@ struct Z3_solver_ref : public api::object {
|
|||
scoped_ptr<solver_factory> m_solver_factory;
|
||||
ref<solver> m_solver;
|
||||
params_ref m_params;
|
||||
param_descrs m_param_descrs;
|
||||
symbol m_logic;
|
||||
scoped_ptr<solver2smt2_pp> m_pp;
|
||||
scoped_ptr<cmd_context> m_cmd_context;
|
||||
mutex m_mux;
|
||||
event_handler* m_eh;
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ Revision History:
|
|||
|
||||
#include "util/params.h"
|
||||
#include "util/lbool.h"
|
||||
#include "util/mutex.h"
|
||||
#include "ast/ast.h"
|
||||
|
||||
#define Z3_TRY try {
|
||||
|
@ -34,7 +35,7 @@ namespace api {
|
|||
|
||||
// Generic wrapper for ref-count objects exposed by the API
|
||||
class object {
|
||||
unsigned m_ref_count;
|
||||
atomic<unsigned> m_ref_count;
|
||||
unsigned m_id;
|
||||
context& m_context;
|
||||
public:
|
||||
|
@ -87,7 +88,6 @@ inline lbool to_lbool(Z3_lbool b) { return static_cast<lbool>(b); }
|
|||
struct Z3_params_ref : public api::object {
|
||||
params_ref m_params;
|
||||
Z3_params_ref(api::context& c): api::object(c) {}
|
||||
~Z3_params_ref() override {}
|
||||
};
|
||||
|
||||
inline Z3_params_ref * to_params(Z3_params p) { return reinterpret_cast<Z3_params_ref *>(p); }
|
||||
|
@ -97,7 +97,6 @@ inline params_ref& to_param_ref(Z3_params p) { return p == nullptr ? const_cast<
|
|||
struct Z3_param_descrs_ref : public api::object {
|
||||
param_descrs m_descrs;
|
||||
Z3_param_descrs_ref(api::context& c): api::object(c) {}
|
||||
~Z3_param_descrs_ref() override {}
|
||||
};
|
||||
|
||||
inline Z3_param_descrs_ref * to_param_descrs(Z3_param_descrs p) { return reinterpret_cast<Z3_param_descrs_ref *>(p); }
|
||||
|
|
|
@ -57,6 +57,8 @@ namespace z3 {
|
|||
class param_descrs;
|
||||
class ast;
|
||||
class sort;
|
||||
class constructors;
|
||||
class constructor_list;
|
||||
class func_decl;
|
||||
class expr;
|
||||
class solver;
|
||||
|
@ -313,6 +315,34 @@ namespace z3 {
|
|||
*/
|
||||
func_decl tuple_sort(char const * name, unsigned n, char const * const * names, sort const* sorts, func_decl_vector & projs);
|
||||
|
||||
|
||||
/**
|
||||
\brief Create a recursive datatype over a single sort.
|
||||
\c name is the name of the recursive datatype
|
||||
\c n - the numer of constructors of the datatype
|
||||
\c cs - the \c n constructors used to define the datatype
|
||||
|
||||
References to the datatype can be created using \ref datatype_sort.
|
||||
*/
|
||||
sort datatype(symbol const& name, constructors const& cs);
|
||||
|
||||
/**
|
||||
\brief Create a set of mutually recursive datatypes.
|
||||
\c n - number of recursive datatypes
|
||||
\c names - array of names of length n
|
||||
\c cons - array of constructor lists of length n
|
||||
*/
|
||||
sort_vector datatypes(unsigned n, symbol const* names,
|
||||
constructor_list *const* cons);
|
||||
|
||||
|
||||
/**
|
||||
\brief a reference to a recursively defined datatype.
|
||||
Expect that it gets defined as a \ref datatype.
|
||||
*/
|
||||
sort datatype_sort(symbol const& name);
|
||||
|
||||
|
||||
/**
|
||||
\brief create an uninterpreted sort with the name given by the string or symbol.
|
||||
*/
|
||||
|
@ -2894,7 +2924,7 @@ namespace z3 {
|
|||
if (n == 0)
|
||||
return ctx().bool_val(true);
|
||||
else if (n == 1)
|
||||
return operator[](0);
|
||||
return operator[](0u);
|
||||
else {
|
||||
array<Z3_ast> args(n);
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
|
@ -3330,6 +3360,98 @@ namespace z3 {
|
|||
return func_decl(*this, tuple);
|
||||
}
|
||||
|
||||
class constructor_list {
|
||||
context& ctx;
|
||||
Z3_constructor_list clist;
|
||||
public:
|
||||
constructor_list(constructors const& cs);
|
||||
~constructor_list() { Z3_del_constructor_list(ctx, clist); }
|
||||
operator Z3_constructor_list() const { return clist; }
|
||||
};
|
||||
|
||||
class constructors {
|
||||
friend class constructor_list;
|
||||
context& ctx;
|
||||
std::vector<Z3_constructor> cons;
|
||||
std::vector<unsigned> num_fields;
|
||||
public:
|
||||
constructors(context& ctx): ctx(ctx) {}
|
||||
|
||||
~constructors() {
|
||||
for (auto con : cons)
|
||||
Z3_del_constructor(ctx, con);
|
||||
}
|
||||
|
||||
void add(symbol const& name, symbol const& rec, unsigned n, symbol const* names, sort const* fields) {
|
||||
array<unsigned> sort_refs(n);
|
||||
array<Z3_sort> sorts(n);
|
||||
array<Z3_symbol> _names(n);
|
||||
for (unsigned i = 0; i < n; ++i) sorts[i] = fields[i], _names[i] = names[i];
|
||||
cons.push_back(Z3_mk_constructor(ctx, name, rec, n, _names.ptr(), sorts.ptr(), sort_refs.ptr()));
|
||||
num_fields.push_back(n);
|
||||
}
|
||||
|
||||
Z3_constructor operator[](unsigned i) const { return cons[i]; }
|
||||
|
||||
unsigned size() const { return (unsigned)cons.size(); }
|
||||
|
||||
void query(unsigned i, func_decl& constructor, func_decl& test, func_decl_vector& accs) {
|
||||
Z3_func_decl _constructor;
|
||||
Z3_func_decl _test;
|
||||
array<Z3_func_decl> accessors(num_fields[i]);
|
||||
accs.resize(0);
|
||||
Z3_query_constructor(ctx,
|
||||
cons[i],
|
||||
num_fields[i],
|
||||
&_constructor,
|
||||
&_test,
|
||||
accessors.ptr());
|
||||
constructor = func_decl(ctx, _constructor);
|
||||
|
||||
test = func_decl(ctx, _test);
|
||||
for (unsigned j = 0; j < num_fields[i]; ++j)
|
||||
accs.push_back(func_decl(ctx, accessors[j]));
|
||||
}
|
||||
};
|
||||
|
||||
constructor_list::constructor_list(constructors const& cs): ctx(cs.ctx) {
|
||||
array<Z3_constructor> cons(cs.size());
|
||||
for (unsigned i = 0; i < cs.size(); ++i)
|
||||
cons[i] = cs[i];
|
||||
clist = Z3_mk_constructor_list(ctx, cs.size(), cons.ptr());
|
||||
}
|
||||
|
||||
inline sort context::datatype(symbol const& name, constructors const& cs) {
|
||||
array<Z3_constructor> _cs(cs.size());
|
||||
for (unsigned i = 0; i < cs.size(); ++i) _cs[i] = cs[i];
|
||||
Z3_sort s = Z3_mk_datatype(*this, name, cs.size(), _cs.ptr());
|
||||
check_error();
|
||||
return sort(*this, s);
|
||||
}
|
||||
|
||||
inline sort_vector context::datatypes(
|
||||
unsigned n, symbol const* names,
|
||||
constructor_list *const* cons) {
|
||||
sort_vector result(*this);
|
||||
array<Z3_symbol> _names(n);
|
||||
array<Z3_sort> _sorts(n);
|
||||
array<Z3_constructor_list> _cons(n);
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
_names[i] = names[i], _cons[i] = *cons[i];
|
||||
Z3_mk_datatypes(*this, n, _names.ptr(), _sorts.ptr(), _cons.ptr());
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
result.push_back(sort(*this, _sorts[i]));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
inline sort context::datatype_sort(symbol const& name) {
|
||||
Z3_sort s = Z3_mk_datatype_sort(*this, name);
|
||||
check_error();
|
||||
return sort(*this, s);
|
||||
}
|
||||
|
||||
|
||||
inline sort context::uninterpreted_sort(char const* name) {
|
||||
Z3_symbol _name = Z3_mk_string_symbol(*this, name);
|
||||
return to_sort(*this, Z3_mk_uninterpreted_sort(*this, _name));
|
||||
|
|
|
@ -4620,16 +4620,16 @@ namespace Microsoft.Z3
|
|||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Produces a term that represents the conversion of the floating-point term t into a
|
||||
/// bit-vector term of size sz in 2's complement format (signed when signed==true). If necessary,
|
||||
/// bit-vector term of size sz in 2's complement format (signed when sign==true). If necessary,
|
||||
/// the result will be rounded according to rounding mode rm.
|
||||
/// </remarks>
|
||||
/// <param name="rm">RoundingMode term.</param>
|
||||
/// <param name="t">FloatingPoint term</param>
|
||||
/// <param name="sz">Size of the resulting bit-vector.</param>
|
||||
/// <param name="signed">Indicates whether the result is a signed or unsigned bit-vector.</param>
|
||||
public BitVecExpr MkFPToBV(FPRMExpr rm, FPExpr t, uint sz, bool signed)
|
||||
/// <param name="sign">Indicates whether the result is a signed or unsigned bit-vector.</param>
|
||||
public BitVecExpr MkFPToBV(FPRMExpr rm, FPExpr t, uint sz, bool sign)
|
||||
{
|
||||
if (signed)
|
||||
if (sign)
|
||||
return new BitVecExpr(this, Native.Z3_mk_fpa_to_sbv(this.nCtx, rm.NativeObject, t.NativeObject, sz));
|
||||
else
|
||||
return new BitVecExpr(this, Native.Z3_mk_fpa_to_ubv(this.nCtx, rm.NativeObject, t.NativeObject, sz));
|
||||
|
|
|
@ -168,6 +168,16 @@ namespace Microsoft.Z3
|
|||
{
|
||||
return (Expr)base.Translate(ctx);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a duplicate of expression.
|
||||
/// This feature is to allow extending the life-time of expressions that were passed down as arguments
|
||||
/// by the user propagator callbacks. By default the life-time of arguments to callbacks is within the
|
||||
/// callback only.
|
||||
/// </summary>
|
||||
public Expr Dup() {
|
||||
return Expr.Create(Context, NativeObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of the expression.
|
||||
|
|
|
@ -100,6 +100,17 @@ namespace Microsoft.Z3
|
|||
return Native.Z3_mk_mul(nCtx, (uint)(ts?.Length ?? 0), ts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an expression representing <c>t[0] - t[1] - ...</c>.
|
||||
/// </summary>
|
||||
public Z3_ast MkSub(params Z3_ast[] t)
|
||||
{
|
||||
Debug.Assert(t != null);
|
||||
Debug.Assert(t.All(a => a != IntPtr.Zero));
|
||||
var ts = t.ToArray();
|
||||
return Native.Z3_mk_sub(nCtx, (uint)(ts?.Length ?? 0), ts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an expression representing <c>t1 / t2</c>.
|
||||
/// </summary>
|
||||
|
|
|
@ -41,6 +41,9 @@ namespace Microsoft.Z3
|
|||
{
|
||||
/// <summary>
|
||||
/// Delegate type for fixed callback
|
||||
/// Note that the life-time of the term and value only applies within the scope of the callback.
|
||||
/// That means the term and value cannot be stored in an array, dictionary or similar and accessed after the callback has returned.
|
||||
/// Use the functionality Dup on expressions to create a duplicate copy that extends the lifetime.
|
||||
/// </summary>
|
||||
public delegate void FixedEh(Expr term, Expr value);
|
||||
|
||||
|
@ -64,8 +67,7 @@ namespace Microsoft.Z3
|
|||
|
||||
// access managed objects through a static array.
|
||||
// thread safety is ignored for now.
|
||||
static List<UserPropagator> propagators = new List<UserPropagator>();
|
||||
int id;
|
||||
GCHandle gch;
|
||||
Solver solver;
|
||||
Context ctx;
|
||||
Z3_solver_callback callback = IntPtr.Zero;
|
||||
|
@ -107,27 +109,27 @@ namespace Microsoft.Z3
|
|||
|
||||
static void _push(voidp ctx, Z3_solver_callback cb)
|
||||
{
|
||||
var prop = propagators[ctx.ToInt32()];
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(ctx).Target;
|
||||
prop.Callback(() => prop.Push(), cb);
|
||||
}
|
||||
|
||||
static void _pop(voidp ctx, Z3_solver_callback cb, uint num_scopes)
|
||||
{
|
||||
var prop = propagators[ctx.ToInt32()];
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(ctx).Target;
|
||||
prop.Callback(() => prop.Pop(num_scopes), cb);
|
||||
}
|
||||
|
||||
static voidp _fresh(voidp _ctx, Z3_context new_context)
|
||||
{
|
||||
var prop = propagators[_ctx.ToInt32()];
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(_ctx).Target;
|
||||
var ctx = new Context(new_context);
|
||||
var prop1 = prop.Fresh(prop.ctx);
|
||||
return new IntPtr(prop1.id);
|
||||
return GCHandle.ToIntPtr(prop1.gch);
|
||||
}
|
||||
|
||||
static void _fixed(voidp ctx, Z3_solver_callback cb, Z3_ast _term, Z3_ast _value)
|
||||
{
|
||||
var prop = propagators[ctx.ToInt32()];
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(ctx).Target;
|
||||
using var term = Expr.Create(prop.ctx, _term);
|
||||
using var value = Expr.Create(prop.ctx, _value);
|
||||
prop.Callback(() => prop.fixed_eh(term, value), cb);
|
||||
|
@ -135,13 +137,13 @@ namespace Microsoft.Z3
|
|||
|
||||
static void _final(voidp ctx, Z3_solver_callback cb)
|
||||
{
|
||||
var prop = propagators[ctx.ToInt32()];
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(ctx).Target;
|
||||
prop.Callback(() => prop.final_eh(), cb);
|
||||
}
|
||||
|
||||
static void _eq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b)
|
||||
{
|
||||
var prop = propagators[ctx.ToInt32()];
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(ctx).Target;
|
||||
using var s = Expr.Create(prop.ctx, a);
|
||||
using var t = Expr.Create(prop.ctx, b);
|
||||
prop.Callback(() => prop.eq_eh(s, t), cb);
|
||||
|
@ -149,7 +151,7 @@ namespace Microsoft.Z3
|
|||
|
||||
static void _diseq(voidp ctx, Z3_solver_callback cb, Z3_ast a, Z3_ast b)
|
||||
{
|
||||
var prop = propagators[ctx.ToInt32()];
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(ctx).Target;
|
||||
using var s = Expr.Create(prop.ctx, a);
|
||||
using var t = Expr.Create(prop.ctx, b);
|
||||
prop.Callback(() => prop.diseq_eh(s, t), cb);
|
||||
|
@ -157,14 +159,14 @@ namespace Microsoft.Z3
|
|||
|
||||
static void _created(voidp ctx, Z3_solver_callback cb, Z3_ast a)
|
||||
{
|
||||
var prop = propagators[ctx.ToInt32()];
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(ctx).Target;
|
||||
using var t = Expr.Create(prop.ctx, a);
|
||||
prop.Callback(() => prop.created_eh(t), cb);
|
||||
}
|
||||
|
||||
static void _decide(voidp ctx, Z3_solver_callback cb, ref Z3_ast a, ref uint idx, ref int phase)
|
||||
{
|
||||
var prop = propagators[ctx.ToInt32()];
|
||||
var prop = (UserPropagator)GCHandle.FromIntPtr(ctx).Target;
|
||||
var t = Expr.Create(prop.ctx, a);
|
||||
var u = t;
|
||||
prop.callback = cb;
|
||||
|
@ -179,14 +181,13 @@ namespace Microsoft.Z3
|
|||
/// </summary>
|
||||
public UserPropagator(Solver s)
|
||||
{
|
||||
id = propagators.Count;
|
||||
propagators.Add(this);
|
||||
gch = GCHandle.Alloc(this);
|
||||
solver = s;
|
||||
ctx = solver.Context;
|
||||
push_eh = _push;
|
||||
pop_eh = _pop;
|
||||
fresh_eh = _fresh;
|
||||
Native.Z3_solver_propagate_init(ctx.nCtx, solver.NativeObject, new IntPtr(id), push_eh, pop_eh, fresh_eh);
|
||||
Native.Z3_solver_propagate_init(ctx.nCtx, solver.NativeObject, GCHandle.ToIntPtr(gch), push_eh, pop_eh, fresh_eh);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -194,8 +195,7 @@ namespace Microsoft.Z3
|
|||
/// </summary>
|
||||
public UserPropagator(Context _ctx)
|
||||
{
|
||||
id = propagators.Count;
|
||||
propagators.Add(this);
|
||||
gch = GCHandle.Alloc(this);
|
||||
solver = null;
|
||||
ctx = _ctx;
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ namespace Microsoft.Z3
|
|||
/// </summary>
|
||||
~UserPropagator()
|
||||
{
|
||||
propagators[id] = null;
|
||||
gch.Free();
|
||||
if (solver == null)
|
||||
ctx.Dispose();
|
||||
}
|
||||
|
|
|
@ -1717,8 +1717,8 @@ public class Context implements AutoCloseable {
|
|||
* {@code [domain -> range]}, and {@code i} must have the sort
|
||||
* {@code domain}. The sort of the result is {@code range}.
|
||||
*
|
||||
* @see #mkArraySort(Sort[], Sort)
|
||||
* @see #mkStore
|
||||
* @see #mkArraySort(Sort[], R)
|
||||
* @see #mkStore(Expr<ArraySort<D, R>> a, Expr<D> i, Expr<R> v)
|
||||
**/
|
||||
public <D extends Sort, R extends Sort> Expr<R> mkSelect(Expr<ArraySort<D, R>> a, Expr<D> i)
|
||||
{
|
||||
|
@ -1739,8 +1739,8 @@ public class Context implements AutoCloseable {
|
|||
* {@code [domains -> range]}, and {@code args} must have the sorts
|
||||
* {@code domains}. The sort of the result is {@code range}.
|
||||
*
|
||||
* @see #mkArraySort(Sort[], Sort)
|
||||
* @see #mkStore
|
||||
* @see #mkArraySort(Sort[], R)
|
||||
* @see #mkStore(Expr<ArraySort<D, R>> a, Expr<D> i, Expr<R> v)
|
||||
**/
|
||||
public <R extends Sort> Expr<R> mkSelect(Expr<ArraySort<Sort, R>> a, Expr<?>[] args)
|
||||
{
|
||||
|
@ -1763,8 +1763,8 @@ public class Context implements AutoCloseable {
|
|||
* {@code select}) on all indices except for {@code i}, where it
|
||||
* maps to {@code v} (and the {@code select} of {@code a}
|
||||
* with respect to {@code i} may be a different value).
|
||||
* @see #mkArraySort(Sort[], Sort)
|
||||
* @see #mkSelect
|
||||
* @see #mkArraySort(Sort[], R)
|
||||
* @see #mkSelect(Expr<ArraySort<D, R>> a, Expr<D> i)
|
||||
|
||||
**/
|
||||
public <D extends Sort, R extends Sort> ArrayExpr<D, R> mkStore(Expr<ArraySort<D, R>> a, Expr<D> i, Expr<R> v)
|
||||
|
@ -1788,8 +1788,8 @@ public class Context implements AutoCloseable {
|
|||
* {@code select}) on all indices except for {@code args}, where it
|
||||
* maps to {@code v} (and the {@code select} of {@code a}
|
||||
* with respect to {@code args} may be a different value).
|
||||
* @see #mkArraySort(Sort[], Sort)
|
||||
* @see #mkSelect
|
||||
* @see #mkArraySort(Sort[], R)
|
||||
* @see #mkSelect(Expr<ArraySort<D, R>> a, Expr<D> i)
|
||||
|
||||
**/
|
||||
public <R extends Sort> ArrayExpr<Sort, R> mkStore(Expr<ArraySort<Sort, R>> a, Expr<?>[] args, Expr<R> v)
|
||||
|
@ -1806,8 +1806,8 @@ public class Context implements AutoCloseable {
|
|||
* Remarks: The resulting term is an array, such
|
||||
* that a {@code select} on an arbitrary index produces the value
|
||||
* {@code v}.
|
||||
* @see #mkArraySort(Sort[], Sort)
|
||||
* @see #mkSelect
|
||||
* @see #mkArraySort(Sort[], R)
|
||||
* @see #mkSelect(Expr<ArraySort<D, R>> a, Expr<D> i)
|
||||
*
|
||||
**/
|
||||
public <D extends Sort, R extends Sort> ArrayExpr<D, R> mkConstArray(D domain, Expr<R> v)
|
||||
|
@ -1826,9 +1826,9 @@ public class Context implements AutoCloseable {
|
|||
* {@code f} must have type {@code range_1 .. range_n -> range}.
|
||||
* {@code v} must have sort range. The sort of the result is
|
||||
* {@code [domain_i -> range]}.
|
||||
* @see #mkArraySort(Sort[], Sort)
|
||||
* @see #mkSelect
|
||||
* @see #mkStore
|
||||
* @see #mkArraySort(Sort[], R)
|
||||
* @see #mkSelect(Expr<ArraySort<D, R>> a, Expr<D> i)
|
||||
* @see #mkStore(Expr<ArraySort<D, R>> a, Expr<D> i, Expr<R> v)
|
||||
|
||||
**/
|
||||
@SafeVarargs
|
||||
|
@ -2476,7 +2476,7 @@ public class Context implements AutoCloseable {
|
|||
*
|
||||
* @return A Term with value {@code num}/{@code den}
|
||||
* and sort Real
|
||||
* @see #mkNumeral(String,Sort)
|
||||
* @see #mkNumeral(String v, R ty)
|
||||
**/
|
||||
public RatNum mkReal(int num, int den)
|
||||
{
|
||||
|
@ -2612,7 +2612,7 @@ public class Context implements AutoCloseable {
|
|||
* 'names' of the bound variables, and {@code body} is the body
|
||||
* of the quantifier. Quantifiers are associated with weights indicating the
|
||||
* importance of using the quantifier during instantiation.
|
||||
* Note that the bound variables are de-Bruijn indices created using {@link #mkBound}.
|
||||
* Note that the bound variables are de-Bruijn indices created using {#mkBound}.
|
||||
* Z3 applies the convention that the last element in {@code names} and
|
||||
* {@code sorts} refers to the variable with index 0, the second to last element
|
||||
* of {@code names} and {@code sorts} refers to the variable
|
||||
|
@ -2707,7 +2707,7 @@ public class Context implements AutoCloseable {
|
|||
* with the sorts of the bound variables, {@code names} is an array with the
|
||||
* 'names' of the bound variables, and {@code body} is the body of the
|
||||
* lambda.
|
||||
* Note that the bound variables are de-Bruijn indices created using {@link #mkBound}
|
||||
* Note that the bound variables are de-Bruijn indices created using {#mkBound}
|
||||
* Z3 applies the convention that the last element in {@code names} and
|
||||
* {@code sorts} refers to the variable with index 0, the second to last element
|
||||
* of {@code names} and {@code sorts} refers to the variable
|
||||
|
|
|
@ -242,7 +242,7 @@ public class Model extends Z3Object {
|
|||
* values. We say this finite set is the "universe" of the sort.
|
||||
*
|
||||
* @see #getNumSorts
|
||||
* @see #getSortUniverse
|
||||
* @see #getSortUniverse(R s)
|
||||
*
|
||||
* @throws Z3Exception
|
||||
**/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Automatically generated file
|
||||
|
||||
#include<jni.h>
|
||||
#include<stdlib.h>
|
||||
#include"z3.h"
|
||||
|
|
|
@ -161,6 +161,12 @@ public class Quantifier extends BoolExpr
|
|||
/**
|
||||
* Create a quantified expression.
|
||||
*
|
||||
* @param ctx Context to create the quantifier on.
|
||||
* @param isForall Quantifier type.
|
||||
* @param sorts Sorts of bound variables.
|
||||
* @param names Names of bound variables
|
||||
* @param body Body of quantifier
|
||||
* @param weight Weight used to indicate priority for qunatifier instantiation
|
||||
* @param patterns Nullable patterns
|
||||
* @param noPatterns Nullable noPatterns
|
||||
* @param quantifierID Nullable quantifierID
|
||||
|
|
|
@ -9,7 +9,7 @@ The readme for the bindings themselves is located in [`PUBLISHED_README.md`](./P
|
|||
|
||||
You'll need to have emscripten set up, along with all of its dependencies. The easiest way to do that is with [emsdk](https://github.com/emscripten-core/emsdk).
|
||||
|
||||
Then run `npm i` to install dependencies, `npm run build-ts` to build the TypeScript wrapper, and `npm run build-wasm` to build the wasm artifact.
|
||||
Then run `npm i` to install dependencies, `npm run build:ts` to build the TypeScript wrapper, and `npm run build:wasm` to build the wasm artifact.
|
||||
|
||||
|
||||
## Tests
|
||||
|
|
2
src/api/js/package-lock.json
generated
2
src/api/js/package-lock.json
generated
|
@ -27,7 +27,7 @@
|
|||
"typescript": "^4.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 <18"
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
"homepage": "https://github.com/Z3Prover/z3/tree/master/src/api/js",
|
||||
"repository": "github:Z3Prover/z3",
|
||||
"engines": {
|
||||
"node": ">=16 <18"
|
||||
"node": ">=16"
|
||||
},
|
||||
"browser": "build/browser.js",
|
||||
"main": "build/node.js",
|
||||
"types": "build/node.d.ts",
|
||||
"files": [
|
||||
"build/*.{js,d.ts,wasm}"
|
||||
"build/**/*.{js,d.ts,wasm}"
|
||||
],
|
||||
"scripts": {
|
||||
"build:ts": "run-s -l build:ts:generate build:ts:tsc",
|
||||
|
|
|
@ -59,6 +59,7 @@ let mk_context (settings:(string * string) list) =
|
|||
Z3native.del_config cfg;
|
||||
Z3native.set_ast_print_mode res (Z3enums.int_of_ast_print_mode PRINT_SMTLIB2_COMPLIANT);
|
||||
Z3native.set_internal_error_handler res;
|
||||
Z3native.enable_concurrent_dec_ref res;
|
||||
res
|
||||
|
||||
module Symbol =
|
||||
|
|
|
@ -49,6 +49,13 @@ type context
|
|||
val mk_context : (string * string) list -> context
|
||||
|
||||
(** Interaction logging for Z3
|
||||
Interaction logs are used to record calls into the API into a text file.
|
||||
The text file can be replayed using z3. It has to be the same version of z3
|
||||
to ensure that low level codes emitted in a log are compatible with the
|
||||
version of z3 replaying the log. The file suffix ".log" is understood
|
||||
by z3 as the format of the file being an interaction log. You can use the
|
||||
optional comman-line parameter "-log" to force z3 to treat an input file
|
||||
as an interaction log.
|
||||
Note that this is a global, static log and if multiple Context
|
||||
objects are created, it logs the interaction with all of them. *)
|
||||
module Log :
|
||||
|
@ -927,10 +934,10 @@ end
|
|||
module FiniteDomain :
|
||||
sig
|
||||
(** Create a new finite domain sort. *)
|
||||
val mk_sort : context -> Symbol.symbol -> int -> Sort.sort
|
||||
val mk_sort : context -> Symbol.symbol -> int64 -> Sort.sort
|
||||
|
||||
(** Create a new finite domain sort. *)
|
||||
val mk_sort_s : context -> string -> int -> Sort.sort
|
||||
val mk_sort_s : context -> string -> int64 -> Sort.sort
|
||||
|
||||
(** Indicates whether the term is of an array sort. *)
|
||||
val is_finite_domain : Expr.expr -> bool
|
||||
|
@ -939,7 +946,7 @@ sig
|
|||
val is_lt : Expr.expr -> bool
|
||||
|
||||
(** The size of the finite domain sort. *)
|
||||
val get_size : Sort.sort -> int
|
||||
val get_size : Sort.sort -> int64
|
||||
end
|
||||
|
||||
|
||||
|
@ -2078,7 +2085,7 @@ sig
|
|||
val mk_numeral_i : context -> int -> Sort.sort -> Expr.expr
|
||||
|
||||
(** Create a numeral of FloatingPoint sort from a sign bit and two integers. *)
|
||||
val mk_numeral_i_u : context -> bool -> int -> int -> Sort.sort -> Expr.expr
|
||||
val mk_numeral_i_u : context -> bool -> int64 -> int64 -> Sort.sort -> Expr.expr
|
||||
|
||||
(** Create a numeral of FloatingPoint sort from a string *)
|
||||
val mk_numeral_s : context -> string -> Sort.sort -> Expr.expr
|
||||
|
@ -2303,7 +2310,7 @@ sig
|
|||
val get_numeral_exponent_string : context -> Expr.expr -> bool -> string
|
||||
|
||||
(** Return the exponent value of a floating-point numeral as a signed integer *)
|
||||
val get_numeral_exponent_int : context -> Expr.expr -> bool -> bool * int
|
||||
val get_numeral_exponent_int : context -> Expr.expr -> bool -> bool * int64
|
||||
|
||||
(** Return the exponent of a floating-point numeral as a bit-vector expression.
|
||||
Remark: NaN's do not have a bit-vector exponent, so they are invalid arguments. *)
|
||||
|
@ -2320,7 +2327,7 @@ sig
|
|||
Remark: This function extracts the significand bits, without the
|
||||
hidden bit or normalization. Throws an exception if the
|
||||
significand does not fit into an int. *)
|
||||
val get_numeral_significand_uint : context -> Expr.expr -> bool * int
|
||||
val get_numeral_significand_uint : context -> Expr.expr -> bool * int64
|
||||
|
||||
(** Indicates whether a floating-point numeral is a NaN. *)
|
||||
val is_numeral_nan : context -> Expr.expr -> bool
|
||||
|
|
|
@ -21,6 +21,7 @@ and solver_callback = ptr
|
|||
and goal = ptr
|
||||
and tactic = ptr
|
||||
and params = ptr
|
||||
and parser_context = ptr
|
||||
and probe = ptr
|
||||
and stats = ptr
|
||||
and ast_vector = ptr
|
||||
|
|
|
@ -418,6 +418,7 @@ MK_PLUS_OBJ_NO_REF(constructor_list, 16)
|
|||
MK_PLUS_OBJ_NO_REF(rcf_num, 16)
|
||||
MK_PLUS_OBJ(params, 64)
|
||||
MK_PLUS_OBJ(param_descrs, 64)
|
||||
MK_PLUS_OBJ(parser_context, 64)
|
||||
MK_PLUS_OBJ(model, 64)
|
||||
MK_PLUS_OBJ(func_interp, 32)
|
||||
MK_PLUS_OBJ(func_entry, 32)
|
||||
|
|
|
@ -129,6 +129,15 @@ def _configure_z3():
|
|||
for key, val in cmake_options.items():
|
||||
if type(val) is bool:
|
||||
cmake_options[key] = str(val).upper()
|
||||
|
||||
# Allow command-line arguments to add and override Z3_ options
|
||||
for i in range(len(sys.argv) - 1):
|
||||
key = sys.argv[i]
|
||||
if key.starts_with("Z3_"):
|
||||
val = sys.argv[i + 1].upper()
|
||||
if val == "TRUE" or val == "FALSE":
|
||||
cmake_options[key] = val
|
||||
|
||||
cmake_args = [ '-D' + key + '=' + value for key,value in cmake_options.items() ]
|
||||
args = [ 'cmake', *cmake_args, SRC_DIR ]
|
||||
if subprocess.call(args, env=build_env, cwd=BUILD_DIR) != 0:
|
||||
|
|
|
@ -5345,6 +5345,10 @@ class DatatypeRef(ExprRef):
|
|||
"""Return the datatype sort of the datatype expression `self`."""
|
||||
return DatatypeSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx)
|
||||
|
||||
def DatatypeSort(name, ctx = None):
|
||||
"""Create a reference to a sort that was declared, or will be declared, as a recursive datatype"""
|
||||
ctx = _get_ctx(ctx)
|
||||
return DatatypeSortRef(Z3_mk_datatype_sort(ctx.ref(), to_symbol(name, ctx)), ctx)
|
||||
|
||||
def TupleSort(name, sorts, ctx=None):
|
||||
"""Create a named tuple sort base on a set of underlying sorts
|
||||
|
@ -9192,6 +9196,25 @@ def _dict2darray(decls, ctx):
|
|||
i = i + 1
|
||||
return sz, _names, _decls
|
||||
|
||||
class ParserContext:
|
||||
def __init__(self, ctx= None):
|
||||
self.ctx = _get_ctx(ctx)
|
||||
self.pctx = Z3_mk_parser_context(self.ctx.ref())
|
||||
Z3_parser_context_inc_ref(self.ctx.ref(), self.pctx)
|
||||
|
||||
def __del__(self):
|
||||
if self.ctx.ref() is not None and self.pctx is not None and Z3_parser_context_dec_ref is not None:
|
||||
Z3_parser_context_dec_ref(self.ctx.ref(), self.pctx)
|
||||
self.pctx = None
|
||||
|
||||
def add_sort(self, sort):
|
||||
Z3_parser_context_add_sort(self.ctx.ref(), self.pctx, sort.as_ast())
|
||||
|
||||
def add_decl(self, decl):
|
||||
Z3_parser_context_add_decl(self.ctx.ref(), self.pctx, decl.as_ast())
|
||||
|
||||
def from_string(self, s):
|
||||
return AstVector(Z3_parser_context_from_string(self.ctx.ref(), self.pctx, s), self.ctx)
|
||||
|
||||
def parse_smt2_string(s, sorts={}, decls={}, ctx=None):
|
||||
"""Parse a string in SMT 2.0 format using the given sorts and decls.
|
||||
|
@ -11334,11 +11357,20 @@ def user_prop_pop(ctx, cb, num_scopes):
|
|||
prop.cb = cb
|
||||
prop.pop(num_scopes)
|
||||
|
||||
def to_ContextObj(ptr,):
|
||||
ctx = ContextObj(ptr)
|
||||
super(ctypes.c_void_p, ctx).__init__(ptr)
|
||||
return ctx
|
||||
|
||||
def user_prop_fresh(id, ctx):
|
||||
|
||||
def user_prop_fresh(ctx, new_ctx):
|
||||
_prop_closures.set_threaded()
|
||||
prop = _prop_closures.get(id)
|
||||
new_prop = prop.fresh()
|
||||
prop = _prop_closures.get(ctx)
|
||||
nctx = Context()
|
||||
new_ctx = to_ContextObj(new_ctx)
|
||||
nctx.ctx = new_ctx
|
||||
nctx.eh = Z3_set_error_handler(new_ctx, z3_error_handler)
|
||||
new_prop = prop.fresh(nctx)
|
||||
_prop_closures.set(new_prop.id, new_prop)
|
||||
return ctypes.c_void_p(new_prop.id)
|
||||
|
||||
|
@ -11401,6 +11433,7 @@ class UserPropagateBase:
|
|||
ensure_prop_closures()
|
||||
self.solver = s
|
||||
self._ctx = None
|
||||
self.fresh_ctx = None
|
||||
self.cb = None
|
||||
self.id = _prop_closures.insert(self)
|
||||
self.fixed = None
|
||||
|
@ -11408,12 +11441,7 @@ class UserPropagateBase:
|
|||
self.eq = None
|
||||
self.diseq = None
|
||||
if ctx:
|
||||
# TBD fresh is broken: ctx is not of the right type when we reach here.
|
||||
self._ctx = Context()
|
||||
#Z3_del_context(self._ctx.ctx)
|
||||
#self._ctx.ctx = ctx
|
||||
#self._ctx.eh = Z3_set_error_handler(ctx, z3_error_handler)
|
||||
#Z3_set_ast_print_mode(ctx, Z3_PRINT_SMTLIB2_COMPLIANT)
|
||||
self.fresh_ctx = ctx
|
||||
if s:
|
||||
Z3_solver_propagate_init(self.ctx_ref(),
|
||||
s.solver,
|
||||
|
@ -11427,8 +11455,8 @@ class UserPropagateBase:
|
|||
self._ctx.ctx = None
|
||||
|
||||
def ctx(self):
|
||||
if self._ctx:
|
||||
return self._ctx
|
||||
if self.fresh_ctx:
|
||||
return self.fresh_ctx
|
||||
else:
|
||||
return self.solver.ctx
|
||||
|
||||
|
@ -11438,25 +11466,29 @@ class UserPropagateBase:
|
|||
def add_fixed(self, fixed):
|
||||
assert not self.fixed
|
||||
assert not self._ctx
|
||||
Z3_solver_propagate_fixed(self.ctx_ref(), self.solver.solver, _user_prop_fixed)
|
||||
if self.solver:
|
||||
Z3_solver_propagate_fixed(self.ctx_ref(), self.solver.solver, _user_prop_fixed)
|
||||
self.fixed = fixed
|
||||
|
||||
def add_final(self, final):
|
||||
assert not self.final
|
||||
assert not self._ctx
|
||||
Z3_solver_propagate_final(self.ctx_ref(), self.solver.solver, _user_prop_final)
|
||||
if self.solver:
|
||||
Z3_solver_propagate_final(self.ctx_ref(), self.solver.solver, _user_prop_final)
|
||||
self.final = final
|
||||
|
||||
def add_eq(self, eq):
|
||||
assert not self.eq
|
||||
assert not self._ctx
|
||||
Z3_solver_propagate_eq(self.ctx_ref(), self.solver.solver, _user_prop_eq)
|
||||
if self.solver:
|
||||
Z3_solver_propagate_eq(self.ctx_ref(), self.solver.solver, _user_prop_eq)
|
||||
self.eq = eq
|
||||
|
||||
def add_diseq(self, diseq):
|
||||
assert not self.diseq
|
||||
assert not self._ctx
|
||||
Z3_solver_propagate_diseq(self.ctx_ref(), self.solver.solver, _user_prop_diseq)
|
||||
if self.solver:
|
||||
Z3_solver_propagate_diseq(self.ctx_ref(), self.solver.solver, _user_prop_diseq)
|
||||
self.diseq = diseq
|
||||
|
||||
def push(self):
|
||||
|
@ -11465,7 +11497,7 @@ class UserPropagateBase:
|
|||
def pop(self, num_scopes):
|
||||
raise Z3Exception("pop needs to be overwritten")
|
||||
|
||||
def fresh(self):
|
||||
def fresh(self, new_ctx):
|
||||
raise Z3Exception("fresh needs to be overwritten")
|
||||
|
||||
def add(self, e):
|
||||
|
|
|
@ -216,6 +216,13 @@ class ParamDescrs(ctypes.c_void_p):
|
|||
def from_param(obj):
|
||||
return obj
|
||||
|
||||
class ParserContextObj(ctypes.c_void_p):
|
||||
def __init__(self, pc):
|
||||
self._as_parameter_ = pc
|
||||
|
||||
def from_param(obj):
|
||||
return obj
|
||||
|
||||
|
||||
class FuncInterpObj(ctypes.c_void_p):
|
||||
def __init__(self, f):
|
||||
|
|
|
@ -20,6 +20,7 @@ DEFINE_TYPE(Z3_constructor);
|
|||
DEFINE_TYPE(Z3_constructor_list);
|
||||
DEFINE_TYPE(Z3_params);
|
||||
DEFINE_TYPE(Z3_param_descrs);
|
||||
DEFINE_TYPE(Z3_parser_context);
|
||||
DEFINE_TYPE(Z3_goal);
|
||||
DEFINE_TYPE(Z3_tactic);
|
||||
DEFINE_TYPE(Z3_probe);
|
||||
|
@ -58,6 +59,7 @@ DEFINE_TYPE(Z3_rcf_num);
|
|||
- \c Z3_constructor_list: list of constructors for a (recursive) datatype.
|
||||
- \c Z3_params: parameter set used to configure many components such as: simplifiers, tactics, solvers, etc.
|
||||
- \c Z3_param_descrs: provides a collection of parameter names, their types, default values and documentation strings. Solvers, tactics, and other objects accept different collection of parameters.
|
||||
- \c Z3_parser_context: context for incrementally parsing strings. Declarations can be added incrementally to the parser state.
|
||||
- \c Z3_model: model for the constraints asserted into the logical context.
|
||||
- \c Z3_func_interp: interpretation of a function in a model.
|
||||
- \c Z3_func_entry: representation of the value of a \c Z3_func_interp at a particular point.
|
||||
|
@ -1413,6 +1415,7 @@ typedef enum
|
|||
def_Type('CONSTRUCTOR_LIST', 'Z3_constructor_list', 'ConstructorList')
|
||||
def_Type('SOLVER', 'Z3_solver', 'SolverObj')
|
||||
def_Type('SOLVER_CALLBACK', 'Z3_solver_callback', 'SolverCallbackObj')
|
||||
def_Type('PARSER_CONTEXT', 'Z3_parser_context', 'ParserContextObj')
|
||||
def_Type('GOAL', 'Z3_goal', 'GoalObj')
|
||||
def_Type('TACTIC', 'Z3_tactic', 'TacticObj')
|
||||
def_Type('PARAMS', 'Z3_params', 'Params')
|
||||
|
@ -1702,6 +1705,16 @@ extern "C" {
|
|||
void Z3_API Z3_interrupt(Z3_context c);
|
||||
|
||||
|
||||
/**
|
||||
\brief use concurrency control for dec-ref.
|
||||
Reference counting decrements are allowed in separate threads from the context.
|
||||
If this setting is not invoked, reference counting decrements are not going to be thread safe.
|
||||
|
||||
def_API('Z3_enable_concurrent_dec_ref', VOID, (_in(CONTEXT),))
|
||||
*/
|
||||
void Z3_API Z3_enable_concurrent_dec_ref(Z3_context c);
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** @name Parameters */
|
||||
|
@ -5827,6 +5840,55 @@ extern "C" {
|
|||
|
||||
Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context, Z3_string str);
|
||||
|
||||
|
||||
/**
|
||||
\brief Create a parser context.
|
||||
|
||||
A parser context maintains state between calls to \c Z3_parser_context_parse_string
|
||||
where the caller can pass in a set of SMTLIB2 commands.
|
||||
It maintains all the declarations from previous calls together with
|
||||
of sorts and function declarations (including 0-ary) that are added directly to the context.
|
||||
|
||||
def_API('Z3_mk_parser_context', PARSER_CONTEXT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_parser_context Z3_API Z3_mk_parser_context(Z3_context c);
|
||||
|
||||
/**
|
||||
\brief Increment the reference counter of the given \c Z3_parser_context object.
|
||||
|
||||
def_API('Z3_parser_context_inc_ref', VOID, (_in(CONTEXT), _in(PARSER_CONTEXT)))
|
||||
*/
|
||||
void Z3_API Z3_parser_context_inc_ref(Z3_context c, Z3_parser_context pc);
|
||||
|
||||
/**
|
||||
\brief Decrement the reference counter of the given \c Z3_parser_context object.
|
||||
|
||||
def_API('Z3_parser_context_dec_ref', VOID, (_in(CONTEXT), _in(PARSER_CONTEXT)))
|
||||
*/
|
||||
void Z3_API Z3_parser_context_dec_ref(Z3_context c, Z3_parser_context pc);
|
||||
|
||||
/**
|
||||
\brief Add a sort declaration.
|
||||
|
||||
def_API('Z3_parser_context_add_sort', VOID, (_in(CONTEXT), _in(PARSER_CONTEXT), _in(SORT)))
|
||||
*/
|
||||
void Z3_API Z3_parser_context_add_sort(Z3_context c, Z3_parser_context pc, Z3_sort s);
|
||||
|
||||
/**
|
||||
\brief Add a function declaration.
|
||||
|
||||
def_API('Z3_parser_context_add_decl', VOID, (_in(CONTEXT), _in(PARSER_CONTEXT), _in(FUNC_DECL)))
|
||||
*/
|
||||
void Z3_API Z3_parser_context_add_decl(Z3_context c, Z3_parser_context pc, Z3_func_decl f);
|
||||
|
||||
/**
|
||||
\brief Parse a string of SMTLIB2 commands. Return assertions.
|
||||
|
||||
def_API('Z3_parser_context_from_string', AST_VECTOR, (_in(CONTEXT), _in(PARSER_CONTEXT), _in(STRING)))
|
||||
*/
|
||||
Z3_ast_vector Z3_API Z3_parser_context_from_string(Z3_context c, Z3_parser_context pc, Z3_string s);
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** @name Error Handling */
|
||||
|
@ -6811,7 +6873,7 @@ extern "C" {
|
|||
|
||||
/**
|
||||
\brief register a callback when a new expression with a registered function is used by the solver
|
||||
The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare.
|
||||
The registered function appears at the top level and is created using \ref Z3_solver_propagate_declare.
|
||||
|
||||
def_API('Z3_solver_propagate_created', VOID, (_in(CONTEXT), _in(SOLVER), _fnptr(Z3_created_eh)))
|
||||
*/
|
||||
|
@ -6837,7 +6899,7 @@ extern "C" {
|
|||
/**
|
||||
Create uninterpreted function declaration for the user propagator.
|
||||
When expressions using the function are created by the solver invoke a callback
|
||||
to \ref \Z3_solver_progate_created with arguments
|
||||
to \ref \Z3_solver_propagate_created with arguments
|
||||
1. context and callback solve
|
||||
2. declared_expr: expression using function that was used as the top-level symbol
|
||||
3. declared_id: a unique identifier (unique within the current scope) to track the expression.
|
||||
|
|
|
@ -471,26 +471,31 @@ bool compare_nodes(ast const * n1, ast const * n2) {
|
|||
return
|
||||
to_var(n1)->get_idx() == to_var(n2)->get_idx() &&
|
||||
to_var(n1)->get_sort() == to_var(n2)->get_sort();
|
||||
case AST_QUANTIFIER:
|
||||
case AST_QUANTIFIER: {
|
||||
quantifier const* q1 = to_quantifier(n1);
|
||||
quantifier const* q2 = to_quantifier(n2);
|
||||
return
|
||||
to_quantifier(n1)->get_kind() == to_quantifier(n2)->get_kind() &&
|
||||
to_quantifier(n1)->get_num_decls() == to_quantifier(n2)->get_num_decls() &&
|
||||
compare_arrays(to_quantifier(n1)->get_decl_sorts(),
|
||||
to_quantifier(n2)->get_decl_sorts(),
|
||||
to_quantifier(n1)->get_num_decls()) &&
|
||||
compare_arrays(to_quantifier(n1)->get_decl_names(),
|
||||
to_quantifier(n2)->get_decl_names(),
|
||||
to_quantifier(n1)->get_num_decls()) &&
|
||||
to_quantifier(n1)->get_expr() == to_quantifier(n2)->get_expr() &&
|
||||
to_quantifier(n1)->get_weight() == to_quantifier(n2)->get_weight() &&
|
||||
to_quantifier(n1)->get_num_patterns() == to_quantifier(n2)->get_num_patterns() &&
|
||||
compare_arrays(to_quantifier(n1)->get_patterns(),
|
||||
to_quantifier(n2)->get_patterns(),
|
||||
to_quantifier(n1)->get_num_patterns()) &&
|
||||
to_quantifier(n1)->get_num_no_patterns() == to_quantifier(n2)->get_num_no_patterns() &&
|
||||
compare_arrays(to_quantifier(n1)->get_no_patterns(),
|
||||
to_quantifier(n2)->get_no_patterns(),
|
||||
to_quantifier(n1)->get_num_no_patterns());
|
||||
q1->get_kind() == q2->get_kind() &&
|
||||
q1->get_num_decls() == q2->get_num_decls() &&
|
||||
compare_arrays(q1->get_decl_sorts(),
|
||||
q2->get_decl_sorts(),
|
||||
q1->get_num_decls()) &&
|
||||
compare_arrays(q1->get_decl_names(),
|
||||
q2->get_decl_names(),
|
||||
q1->get_num_decls()) &&
|
||||
q1->get_expr() == q2->get_expr() &&
|
||||
q1->get_weight() == q2->get_weight() &&
|
||||
q1->get_num_patterns() == q2->get_num_patterns() &&
|
||||
((q1->get_qid().is_numerical() && q2->get_qid().is_numerical()) ||
|
||||
(q1->get_qid() == q2->get_qid())) &&
|
||||
compare_arrays(q1->get_patterns(),
|
||||
q2->get_patterns(),
|
||||
q1->get_num_patterns()) &&
|
||||
q1->get_num_no_patterns() == q2->get_num_no_patterns() &&
|
||||
compare_arrays(q1->get_no_patterns(),
|
||||
q2->get_no_patterns(),
|
||||
q1->get_num_no_patterns());
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
|
|
@ -67,6 +67,30 @@ namespace recfun {
|
|||
m_decl = m.mk_func_decl(s, arity, domain, range, info);
|
||||
}
|
||||
|
||||
def* def::copy(util& dst, ast_translation& tr) {
|
||||
SASSERT(&dst.m() == &tr.to());
|
||||
sort_ref_vector domain(tr.to());
|
||||
sort_ref range(tr(m_range.get()), tr.to());
|
||||
for (auto* s : m_domain)
|
||||
domain.push_back(tr(s));
|
||||
family_id fid = dst.get_family_id();
|
||||
bool is_generated = m_decl->get_parameter(0).get_int() != 0;
|
||||
def* r = alloc(def, tr.to(), fid, m_name, domain.size(), domain.data(), range, is_generated);
|
||||
r->m_rhs = tr(m_rhs.get());
|
||||
for (auto* v : m_vars)
|
||||
r->m_vars.push_back(tr(v));
|
||||
for (auto const& c1 : m_cases) {
|
||||
r->m_cases.push_back(case_def(tr.to()));
|
||||
auto& c2 = r->m_cases.back();
|
||||
c2.m_pred = tr(c1.m_pred.get());
|
||||
c2.m_guards = tr(c1.m_guards);
|
||||
c2.m_rhs = tr(c1.m_rhs.get());
|
||||
c2.m_def = r;
|
||||
c2.m_immediate = c1.m_immediate;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool def::contains_def(util& u, expr * e) {
|
||||
struct def_find_p : public i_expr_pred {
|
||||
util& u;
|
||||
|
@ -415,6 +439,19 @@ namespace recfun {
|
|||
return promise_def(&u(), d);
|
||||
}
|
||||
|
||||
void plugin::inherit(decl_plugin* other, ast_translation& tr) {
|
||||
for (auto [k, v] : static_cast<plugin*>(other)->m_defs) {
|
||||
func_decl_ref f(tr(k), tr.to());
|
||||
if (m_defs.contains(f))
|
||||
continue;
|
||||
def* d = v->copy(u(), tr);
|
||||
m_defs.insert(f, d);
|
||||
for (case_def & c : d->get_cases())
|
||||
m_case_defs.insert(c.get_decl(), &c);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
promise_def plugin::ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated) {
|
||||
def* d = u().decl_fun(name, n, params, range, is_generated);
|
||||
erase_def(d->get_decl());
|
||||
|
|
|
@ -21,6 +21,7 @@ Revision History:
|
|||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_translation.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
|
||||
namespace recfun {
|
||||
|
@ -62,6 +63,12 @@ namespace recfun {
|
|||
def * m_def; //<! definition this is a part of
|
||||
bool m_immediate; //<! does `rhs` contain no defined_fun/case_pred?
|
||||
|
||||
case_def(ast_manager& m):
|
||||
m_pred(m),
|
||||
m_guards(m),
|
||||
m_rhs(m)
|
||||
{}
|
||||
|
||||
case_def(ast_manager & m,
|
||||
family_id fid,
|
||||
def * d,
|
||||
|
@ -132,6 +139,8 @@ namespace recfun {
|
|||
bool is_fun_macro() const { return m_cases.size() == 1; }
|
||||
bool is_fun_defined() const { return !is_fun_macro(); }
|
||||
|
||||
def* copy(util& dst, ast_translation& tr);
|
||||
|
||||
};
|
||||
|
||||
// definition to be complete (missing RHS)
|
||||
|
@ -205,6 +214,8 @@ namespace recfun {
|
|||
|
||||
expr_ref redirect_ite(replace& subst, unsigned n, var * const* vars, expr * e);
|
||||
|
||||
void inherit(decl_plugin* other, ast_translation& tr) override;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -37,21 +37,57 @@ br_status char_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * co
|
|||
case OP_CHAR_CONST:
|
||||
break;
|
||||
case OP_CHAR_LE:
|
||||
st = mk_char_le(args[0], args[1], result);
|
||||
break;
|
||||
case OP_CHAR_TO_INT:
|
||||
st = mk_char_to_int(args[0], result);
|
||||
break;
|
||||
case OP_CHAR_TO_BV:
|
||||
st = mk_char_to_bv(args[0], result);
|
||||
break;
|
||||
case OP_CHAR_FROM_BV:
|
||||
st = mk_char_from_bv(args[0], result);
|
||||
break;
|
||||
case OP_CHAR_IS_DIGIT:
|
||||
st = mk_char_is_digit(args[0], result);
|
||||
break;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
br_status char_rewriter::mk_char_is_digit(expr* a, expr_ref& result) {
|
||||
unsigned n;
|
||||
if (!m_char->is_const_char(a, n))
|
||||
return BR_FAILED;
|
||||
result = m.mk_bool_val('0' <= n && n <= '9');
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
br_status char_rewriter::mk_char_to_bv(expr* a, expr_ref& result) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status char_rewriter::mk_char_le(expr* a, expr* b, expr_ref& result) {
|
||||
unsigned na = 0, nb = 0;
|
||||
if (m_char->is_const_char(a, na)) {
|
||||
if (na == 0) {
|
||||
result = m.mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
if (m_char->is_const_char(b, nb)) {
|
||||
if (na != 0) {
|
||||
result = m.mk_bool_val(na <= nb);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (nb == m_char->max_char()) {
|
||||
result = m.mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status char_rewriter::mk_char_from_bv(expr* e, expr_ref& result) {
|
||||
bv_util bv(m);
|
||||
rational n;
|
||||
|
|
|
@ -35,6 +35,12 @@ class char_rewriter {
|
|||
|
||||
br_status mk_char_to_int(expr* e, expr_ref& result);
|
||||
|
||||
br_status mk_char_le(expr* a, expr* b, expr_ref& result);
|
||||
|
||||
br_status mk_char_is_digit(expr* a, expr_ref& result);
|
||||
|
||||
br_status mk_char_to_bv(expr* a, expr_ref& result);
|
||||
|
||||
public:
|
||||
|
||||
char_rewriter(ast_manager& m);
|
||||
|
|
|
@ -532,7 +532,12 @@ func_decl* seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
|
|||
case _OP_STRING_FROM_CHAR: {
|
||||
if (!(num_parameters == 1 && parameters[0].is_int()))
|
||||
m.raise_exception("character literal expects integer parameter");
|
||||
zstring zs(parameters[0].get_int());
|
||||
int i = parameters[0].get_int();
|
||||
if (i < 0)
|
||||
m.raise_exception("character literal expects a non-negative integer parameter");
|
||||
if (i > (int)m_char_plugin->max_char())
|
||||
m.raise_exception("character literal is out of bounds");
|
||||
zstring zs(i);
|
||||
parameter p(zs);
|
||||
return m.mk_const_decl(m_stringc_sym, m_string,func_decl_info(m_family_id, OP_STRING_CONST, 1, &p));
|
||||
}
|
||||
|
@ -966,6 +971,22 @@ bool seq_util::str::is_len_sub(expr const* s, expr*& l, expr*& u, rational& k) c
|
|||
return false;
|
||||
}
|
||||
|
||||
bool seq_util::str::is_concat_of_units(expr* s) const {
|
||||
ptr_vector<expr> todo;
|
||||
todo.push_back(s);
|
||||
while (!todo.empty()) {
|
||||
expr* e = todo.back();
|
||||
todo.pop_back();
|
||||
if (is_empty(e) || is_unit(e))
|
||||
continue;
|
||||
if (is_concat(e))
|
||||
todo.append(to_app(e)->get_num_args(), to_app(e)->get_args());
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seq_util::str::is_unit_string(expr const* s, expr_ref& c) const {
|
||||
zstring z;
|
||||
expr* ch = nullptr;
|
||||
|
|
|
@ -375,6 +375,7 @@ public:
|
|||
bool is_to_code(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_TO_CODE); }
|
||||
|
||||
bool is_len_sub(expr const* n, expr*& l, expr*& u, rational& k) const;
|
||||
bool is_concat_of_units(expr* n) const;
|
||||
|
||||
/*
|
||||
tests if s is a single character string(c) or a unit (c)
|
||||
|
|
|
@ -219,9 +219,8 @@ ATOMIC_CMD(get_proof_graph_cmd, "get-proof-graph", "retrieve proof and print it
|
|||
pr = ctx.get_check_sat_result()->get_proof();
|
||||
if (pr == 0)
|
||||
throw cmd_exception("proof is not available");
|
||||
if (ctx.well_sorted_check_enabled() && !is_well_sorted(ctx.m(), pr)) {
|
||||
if (ctx.well_sorted_check_enabled() && !is_well_sorted(ctx.m(), pr))
|
||||
throw cmd_exception("proof is not well sorted");
|
||||
}
|
||||
|
||||
context_params& params = ctx.params();
|
||||
const std::string& file = params.m_dot_proof_file;
|
||||
|
@ -235,11 +234,11 @@ static void print_core(cmd_context& ctx) {
|
|||
ctx.regular_stream() << "(";
|
||||
bool first = true;
|
||||
for (expr* e : core) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
ctx.regular_stream() << " ";
|
||||
ctx.regular_stream() << mk_ismt2_pp(e, ctx.m());
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
ctx.regular_stream() << " ";
|
||||
ctx.regular_stream() << mk_ismt2_pp(e, ctx.m());
|
||||
}
|
||||
ctx.regular_stream() << ")" << std::endl;
|
||||
}
|
||||
|
@ -260,9 +259,8 @@ ATOMIC_CMD(get_unsat_assumptions_cmd, "get-unsat-assumptions", "retrieve subset
|
|||
return;
|
||||
if (!ctx.produce_unsat_assumptions())
|
||||
throw cmd_exception("unsat assumptions construction is not enabled, use command (set-option :produce-unsat-assumptions true)");
|
||||
if (!ctx.has_manager() || ctx.cs_state() != cmd_context::css_unsat) {
|
||||
if (!ctx.has_manager() || ctx.cs_state() != cmd_context::css_unsat)
|
||||
throw cmd_exception("unsat assumptions is not available");
|
||||
}
|
||||
print_core(ctx);
|
||||
});
|
||||
|
||||
|
@ -410,6 +408,15 @@ class set_option_cmd : public set_get_option_cmd {
|
|||
}
|
||||
}
|
||||
|
||||
static void check_no_assertions(cmd_context & ctx, symbol const & opt_name) {
|
||||
if (ctx.has_assertions()) {
|
||||
std::string msg = "error setting '";
|
||||
msg += opt_name.str();
|
||||
msg += "', option value cannot be modified after assertions have been added";
|
||||
throw cmd_exception(std::move(msg));
|
||||
}
|
||||
}
|
||||
|
||||
void set_param(cmd_context & ctx, char const * value) {
|
||||
try {
|
||||
gparams::set(m_option, value);
|
||||
|
@ -437,11 +444,11 @@ class set_option_cmd : public set_get_option_cmd {
|
|||
ctx.set_interactive_mode(to_bool(value));
|
||||
}
|
||||
else if (m_option == m_produce_proofs) {
|
||||
check_not_initialized(ctx, m_produce_proofs);
|
||||
check_no_assertions(ctx, m_produce_proofs);
|
||||
ctx.set_produce_proofs(to_bool(value));
|
||||
}
|
||||
else if (m_option == m_produce_unsat_cores) {
|
||||
check_not_initialized(ctx, m_produce_unsat_cores);
|
||||
check_no_assertions(ctx, m_produce_unsat_cores);
|
||||
ctx.set_produce_unsat_cores(to_bool(value));
|
||||
}
|
||||
else if (m_option == m_produce_unsat_assumptions) {
|
||||
|
|
|
@ -538,22 +538,9 @@ public:
|
|||
cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l):
|
||||
m_main_ctx(main_ctx),
|
||||
m_logic(l),
|
||||
m_interactive_mode(false),
|
||||
m_global_decls(false),
|
||||
m_print_success(m_params.m_smtlib2_compliant),
|
||||
m_random_seed(0),
|
||||
m_produce_unsat_cores(false),
|
||||
m_produce_unsat_assumptions(false),
|
||||
m_produce_assignments(false),
|
||||
m_status(UNKNOWN),
|
||||
m_numeral_as_real(false),
|
||||
m_ignore_check(false),
|
||||
m_exit_on_error(false),
|
||||
m_manager(m),
|
||||
m_own_manager(m == nullptr),
|
||||
m_manager_initialized(false),
|
||||
m_pmanager(nullptr),
|
||||
m_sexpr_manager(nullptr),
|
||||
m_regular("stdout", std::cout),
|
||||
m_diagnostic("stderr", std::cerr) {
|
||||
SASSERT(m != 0 || !has_manager());
|
||||
|
@ -607,6 +594,7 @@ 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)
|
||||
|
@ -626,13 +614,14 @@ void cmd_context::set_produce_models(bool f) {
|
|||
|
||||
void cmd_context::set_produce_unsat_cores(bool f) {
|
||||
// can only be set before initialization
|
||||
SASSERT(!has_manager());
|
||||
SASSERT(!has_assertions());
|
||||
m_params.m_unsat_core |= f;
|
||||
}
|
||||
|
||||
void cmd_context::set_produce_proofs(bool f) {
|
||||
// can only be set before initialization
|
||||
SASSERT(!has_manager());
|
||||
SASSERT(!has_assertions() || m_params.m_proof == f);
|
||||
if (has_manager())
|
||||
m().toggle_proof_mode(f ? PGM_ENABLED : PGM_DISABLED);
|
||||
m_params.m_proof = f;
|
||||
}
|
||||
|
||||
|
@ -835,15 +824,16 @@ 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_manager() && m_main_ctx)
|
||||
if (has_assertions() && m_main_ctx)
|
||||
throw cmd_exception("logic must be set before initialization");
|
||||
if (!smt_logics::supported_logic(s)) {
|
||||
if (!smt_logics::supported_logic(s))
|
||||
return false;
|
||||
}
|
||||
|
||||
m_logic = s;
|
||||
if (smt_logics::logic_has_reals_only(s)) {
|
||||
if (m_solver)
|
||||
mk_solver();
|
||||
if (smt_logics::logic_has_reals_only(s))
|
||||
m_numeral_as_real = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1837,6 +1827,10 @@ void cmd_context::add_declared_functions(model& mdl) {
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -2203,22 +2197,25 @@ expr_ref_vector cmd_context::tracked_assertions() {
|
|||
for (unsigned i = 0; i < assertions().size(); ++i) {
|
||||
expr* an = assertion_names()[i];
|
||||
expr* asr = assertions()[i];
|
||||
if (an) {
|
||||
if (an)
|
||||
result.push_back(m().mk_implies(an, asr));
|
||||
}
|
||||
else {
|
||||
else
|
||||
result.push_back(asr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (expr * e : assertions()) {
|
||||
for (expr * e : assertions())
|
||||
result.push_back(e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void cmd_context::reset_tracked_assertions() {
|
||||
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)
|
||||
|
@ -2254,9 +2251,8 @@ format_ns::format * cmd_context::pp(sort * s) const {
|
|||
}
|
||||
|
||||
cmd_context::pp_env & cmd_context::get_pp_env() const {
|
||||
if (m_pp_env.get() == nullptr) {
|
||||
if (m_pp_env.get() == nullptr)
|
||||
const_cast<cmd_context*>(this)->m_pp_env = alloc(pp_env, *const_cast<cmd_context*>(this));
|
||||
}
|
||||
return *(m_pp_env.get());
|
||||
}
|
||||
|
||||
|
@ -2314,9 +2310,8 @@ void cmd_context::display_smt2_benchmark(std::ostream & out, unsigned num, expr
|
|||
out << "(set-logic " << logic << ")" << std::endl;
|
||||
// collect uninterpreted function declarations
|
||||
decl_collector decls(m());
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
decls.visit(assertions[i]);
|
||||
}
|
||||
|
||||
// TODO: display uninterpreted sort decls, and datatype decls.
|
||||
|
||||
|
@ -2342,9 +2337,8 @@ void cmd_context::slow_progress_sample() {
|
|||
svector<symbol> labels;
|
||||
m_solver->get_labels(labels);
|
||||
regular_stream() << "(labels";
|
||||
for (symbol const& s : labels) {
|
||||
for (symbol const& s : labels)
|
||||
regular_stream() << " " << s;
|
||||
}
|
||||
regular_stream() << "))" << std::endl;
|
||||
}
|
||||
|
||||
|
|
|
@ -194,21 +194,21 @@ public:
|
|||
|
||||
|
||||
protected:
|
||||
ast_context_params m_params;
|
||||
ast_context_params m_params;
|
||||
bool m_main_ctx;
|
||||
symbol m_logic;
|
||||
bool m_interactive_mode;
|
||||
bool m_global_decls;
|
||||
bool m_interactive_mode = false;
|
||||
bool m_global_decls = false;
|
||||
bool m_print_success;
|
||||
unsigned m_random_seed;
|
||||
bool m_produce_unsat_cores;
|
||||
bool m_produce_unsat_assumptions;
|
||||
bool m_produce_assignments;
|
||||
status m_status;
|
||||
bool m_numeral_as_real;
|
||||
bool m_ignore_check; // used by the API to disable check-sat() commands when parsing SMT 2.0 files.
|
||||
bool m_exit_on_error;
|
||||
bool m_allow_duplicate_declarations { false };
|
||||
unsigned m_random_seed = 0;
|
||||
bool m_produce_unsat_cores = false;
|
||||
bool m_produce_unsat_assumptions = false;
|
||||
bool m_produce_assignments = false;
|
||||
status m_status = UNKNOWN;
|
||||
bool m_numeral_as_real = false;
|
||||
bool m_ignore_check = false; // used by the API to disable check-sat() commands when parsing SMT 2.0 files.
|
||||
bool m_exit_on_error = false;
|
||||
bool m_allow_duplicate_declarations = false;
|
||||
|
||||
static std::ostringstream g_error_stream;
|
||||
|
||||
|
@ -216,9 +216,9 @@ protected:
|
|||
sref_vector<generic_model_converter> m_mcs;
|
||||
ast_manager * m_manager;
|
||||
bool m_own_manager;
|
||||
bool m_manager_initialized;
|
||||
pdecl_manager * m_pmanager;
|
||||
sexpr_manager * m_sexpr_manager;
|
||||
bool m_manager_initialized = false;
|
||||
pdecl_manager * m_pmanager = nullptr;
|
||||
sexpr_manager * m_sexpr_manager = nullptr;
|
||||
check_logic m_check_logic;
|
||||
stream_ref m_regular;
|
||||
stream_ref m_diagnostic;
|
||||
|
@ -362,6 +362,7 @@ public:
|
|||
bool produce_unsat_cores() const;
|
||||
bool well_sorted_check_enabled() const;
|
||||
bool validate_model_enabled() const;
|
||||
bool has_assertions() const { return !m_assertions.empty(); }
|
||||
void set_produce_models(bool flag);
|
||||
void set_produce_unsat_cores(bool flag);
|
||||
void set_produce_proofs(bool flag);
|
||||
|
@ -485,6 +486,7 @@ public:
|
|||
ptr_vector<expr> const& assertions() const { return m_assertions; }
|
||||
ptr_vector<expr> const& assertion_names() const { return m_assertion_names; }
|
||||
expr_ref_vector tracked_assertions();
|
||||
void reset_tracked_assertions();
|
||||
|
||||
/**
|
||||
\brief Hack: consume assertions if there are no scopes.
|
||||
|
|
|
@ -377,8 +377,8 @@ public:
|
|||
};
|
||||
|
||||
class get_interpolant_cmd : public cmd {
|
||||
expr* m_a;
|
||||
expr* m_b;
|
||||
scoped_ptr<expr_ref> m_a;
|
||||
scoped_ptr<expr_ref> m_b;
|
||||
public:
|
||||
get_interpolant_cmd():cmd("get-interpolant") {}
|
||||
char const * get_usage() const override { return "<expr> <expr>"; }
|
||||
|
@ -388,17 +388,24 @@ public:
|
|||
return CPK_EXPR;
|
||||
}
|
||||
void set_next_arg(cmd_context& ctx, expr * arg) override {
|
||||
if (m_a == nullptr)
|
||||
m_a = arg;
|
||||
ast_manager& m = ctx.m();
|
||||
if (!m.is_bool(arg))
|
||||
throw default_exception("argument to interpolation is not Boolean");
|
||||
if (!m_a)
|
||||
m_a = alloc(expr_ref, arg, m);
|
||||
else
|
||||
m_b = arg;
|
||||
m_b = alloc(expr_ref, arg, m);
|
||||
}
|
||||
void prepare(cmd_context & ctx) override { m_a = nullptr; m_b = nullptr; }
|
||||
void execute(cmd_context & ctx) override {
|
||||
ast_manager& m = ctx.m();
|
||||
qe::interpolator mbi(m);
|
||||
if (!m_a || !m_b)
|
||||
throw default_exception("interpolation requires two arguments");
|
||||
if (!m.is_bool(*m_a) || !m.is_bool(*m_b))
|
||||
throw default_exception("interpolation requires two Boolean arguments");
|
||||
expr_ref itp(m);
|
||||
mbi.pogo(ctx.get_solver_factory(), m_a, m_b, itp);
|
||||
mbi.pogo(ctx.get_solver_factory(), *m_a, *m_b, itp);
|
||||
ctx.regular_stream() << itp << "\n";
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1741,6 +1741,87 @@ namespace dd {
|
|||
return (*this) * rational::power_of_two(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief substitute variable v by r.
|
||||
* This base line implementation is simplistic and does not use operator caching.
|
||||
*/
|
||||
pdd pdd::subst_pdd(unsigned v, pdd const& r) const {
|
||||
if (is_val())
|
||||
return *this;
|
||||
if (m.m_var2level[var()] < m.m_var2level[v])
|
||||
return *this;
|
||||
pdd l = lo().subst_pdd(v, r);
|
||||
pdd h = hi().subst_pdd(v, r);
|
||||
if (var() == v)
|
||||
return r*h + l;
|
||||
else if (l == lo() && h == hi())
|
||||
return *this;
|
||||
else
|
||||
return m.mk_var(var())*h + l;
|
||||
}
|
||||
|
||||
std::pair<unsigned_vector, pdd> pdd::var_factors() const {
|
||||
if (is_val())
|
||||
return { unsigned_vector(), *this };
|
||||
unsigned v = var();
|
||||
if (lo().is_val()) {
|
||||
if (!lo().is_zero())
|
||||
return { unsigned_vector(), *this };
|
||||
auto [vars, p] = hi().var_factors();
|
||||
vars.push_back(v);
|
||||
return {vars, p};
|
||||
}
|
||||
auto [lo_vars, q] = lo().var_factors();
|
||||
if (lo_vars.empty())
|
||||
return { unsigned_vector(), *this };
|
||||
|
||||
unsigned_vector lo_and_hi;
|
||||
auto merge = [&](unsigned_vector& lo_vars, unsigned_vector& hi_vars) {
|
||||
unsigned ir = 0, jr = 0;
|
||||
for (unsigned i = 0, j = 0; i < lo_vars.size() || j < hi_vars.size(); ) {
|
||||
if (i == lo_vars.size())
|
||||
hi_vars[jr++] = hi_vars[j++];
|
||||
else if (j == hi_vars.size())
|
||||
lo_vars[ir++] = lo_vars[i++];
|
||||
else if (lo_vars[i] == hi_vars[j]) {
|
||||
lo_and_hi.push_back(lo_vars[i]);
|
||||
++i;
|
||||
++j;
|
||||
}
|
||||
else if (m.m_var2level[lo_vars[i]] > m.m_var2level[hi_vars[j]])
|
||||
hi_vars[jr++] = hi_vars[j++];
|
||||
else
|
||||
lo_vars[ir++] = lo_vars[i++];
|
||||
}
|
||||
lo_vars.shrink(ir);
|
||||
hi_vars.shrink(jr);
|
||||
};
|
||||
|
||||
auto mul = [&](unsigned_vector const& vars, pdd p) {
|
||||
for (auto v : vars)
|
||||
p *= m.mk_var(v);
|
||||
return p;
|
||||
};
|
||||
|
||||
auto [hi_vars, p] = hi().var_factors();
|
||||
if (lo_vars.back() == v) {
|
||||
lo_vars.pop_back();
|
||||
merge(lo_vars, hi_vars);
|
||||
lo_and_hi.push_back(v);
|
||||
return { lo_and_hi, mul(lo_vars, q) + mul(hi_vars, p) };
|
||||
}
|
||||
if (hi_vars.empty())
|
||||
return { unsigned_vector(), *this };
|
||||
|
||||
merge(lo_vars, hi_vars);
|
||||
hi_vars.push_back(v);
|
||||
if (lo_and_hi.empty())
|
||||
return { unsigned_vector(), *this };
|
||||
else
|
||||
return { lo_and_hi, mul(lo_vars, q) + mul(hi_vars, p) };
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, pdd const& b) { return b.display(out); }
|
||||
|
||||
void pdd_iterator::next() {
|
||||
|
|
|
@ -447,11 +447,22 @@ namespace dd {
|
|||
bool resolve(unsigned v, pdd const& other, pdd& result) { return m.resolve(v, *this, other, result); }
|
||||
pdd reduce(unsigned v, pdd const& other) const { return m.reduce(v, *this, other); }
|
||||
|
||||
/**
|
||||
* \brief factor out variables
|
||||
*/
|
||||
std::pair<unsigned_vector, pdd> var_factors() const;
|
||||
|
||||
pdd subst_val0(vector<std::pair<unsigned, rational>> const& s) const { return m.subst_val0(*this, s); }
|
||||
pdd subst_val(pdd const& s) const { return m.subst_val(*this, s); }
|
||||
pdd subst_val(vector<std::pair<unsigned, rational>> const& s) const { return m.subst_val0(*this, s); }
|
||||
pdd subst_val(unsigned v, rational const& val) const { return m.subst_val(*this, v, val); }
|
||||
pdd subst_add(unsigned var, rational const& val) { return m.subst_add(*this, var, val); }
|
||||
|
||||
/**
|
||||
* \brief substitute variable v by r.
|
||||
*/
|
||||
pdd subst_pdd(unsigned v, pdd const& r) const;
|
||||
|
||||
std::ostream& display(std::ostream& out) const { return m.display(out, *this); }
|
||||
bool operator==(pdd const& other) const { return root == other.root; }
|
||||
bool operator!=(pdd const& other) const { return root != other.root; }
|
||||
|
|
|
@ -27,7 +27,33 @@ typedef dep_intervals::with_deps_t w_dep;
|
|||
class pdd_interval {
|
||||
dep_intervals& m_dep_intervals;
|
||||
std::function<void (unsigned, bool, scoped_dep_interval&)> m_var2interval;
|
||||
|
||||
|
||||
// retrieve intervals after distributing multiplication over addition.
|
||||
template <w_dep wd>
|
||||
void get_interval_distributed(pdd const& p, scoped_dep_interval& i, scoped_dep_interval& ret) {
|
||||
bool deps = wd == w_dep::with_deps;
|
||||
if (p.is_val()) {
|
||||
if (deps)
|
||||
m_dep_intervals.mul<dep_intervals::with_deps>(p.val(), i, ret);
|
||||
else
|
||||
m_dep_intervals.mul<dep_intervals::without_deps>(p.val(), i, ret);
|
||||
return;
|
||||
}
|
||||
scoped_dep_interval hi(m()), lo(m()), t(m()), a(m());
|
||||
get_interval_distributed<wd>(p.lo(), i, lo);
|
||||
m_var2interval(p.var(), deps, a);
|
||||
if (deps) {
|
||||
m_dep_intervals.mul<dep_intervals::with_deps>(a, i, t);
|
||||
get_interval_distributed<wd>(p.hi(), t, hi);
|
||||
m_dep_intervals.add<dep_intervals::with_deps>(hi, lo, ret);
|
||||
}
|
||||
else {
|
||||
m_dep_intervals.mul<dep_intervals::without_deps>(a, i, t);
|
||||
get_interval_distributed<wd>(p.hi(), t, hi);
|
||||
m_dep_intervals.add<dep_intervals::without_deps>(hi, lo, ret);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
pdd_interval(dep_intervals& d): m_dep_intervals(d) {}
|
||||
|
@ -57,5 +83,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template <w_dep wd>
|
||||
void get_interval_distributed(pdd const& p, scoped_dep_interval& ret) {
|
||||
scoped_dep_interval i(m());
|
||||
m_dep_intervals.set_interval_for_scalar(i, rational::one());
|
||||
get_interval_distributed<wd>(p, i, ret);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ void grobner::display_vars(std::ostream & out, unsigned num_vars, expr * const *
|
|||
}
|
||||
}
|
||||
|
||||
void grobner::display_monomial(std::ostream & out, monomial const & m) const {
|
||||
void grobner::display_monomial(std::ostream & out, monomial const & m, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
if (!m.m_coeff.is_one() || m.m_vars.empty()) {
|
||||
out << m.m_coeff;
|
||||
if (!m.m_vars.empty())
|
||||
|
@ -165,7 +165,7 @@ void grobner::display_monomial(std::ostream & out, monomial const & m) const {
|
|||
}
|
||||
}
|
||||
|
||||
void grobner::display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials) const {
|
||||
void grobner::display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
bool first = true;
|
||||
for (unsigned i = 0; i < num_monomials; i++) {
|
||||
monomial const * m = monomials[i];
|
||||
|
@ -173,26 +173,26 @@ void grobner::display_monomials(std::ostream & out, unsigned num_monomials, mono
|
|||
first = false;
|
||||
else
|
||||
out << " + ";
|
||||
display_monomial(out, *m);
|
||||
display_monomial(out, *m, display_var);
|
||||
}
|
||||
}
|
||||
|
||||
void grobner::display_equation(std::ostream & out, equation const & eq) const {
|
||||
display_monomials(out, eq.m_monomials.size(), eq.m_monomials.data());
|
||||
void grobner::display_equation(std::ostream & out, equation const & eq, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
display_monomials(out, eq.m_monomials.size(), eq.m_monomials.data(), display_var);
|
||||
out << " = 0\n";
|
||||
}
|
||||
|
||||
void grobner::display_equations(std::ostream & out, equation_set const & v, char const * header) const {
|
||||
if (!v.empty()) {
|
||||
out << header << "\n";
|
||||
for (equation const* eq : v)
|
||||
display_equation(out, *eq);
|
||||
}
|
||||
void grobner::display_equations(std::ostream & out, equation_set const & v, char const * header, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
if (v.empty())
|
||||
return;
|
||||
out << header << "\n";
|
||||
for (equation const* eq : v)
|
||||
display_equation(out, *eq, display_var);
|
||||
}
|
||||
|
||||
void grobner::display(std::ostream & out) const {
|
||||
display_equations(out, m_processed, "processed:");
|
||||
display_equations(out, m_to_process, "to process:");
|
||||
void grobner::display(std::ostream & out, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
display_equations(out, m_processed, "processed:", display_var);
|
||||
display_equations(out, m_to_process, "to process:", display_var);
|
||||
}
|
||||
|
||||
void grobner::set_weight(expr * n, int weight) {
|
||||
|
@ -528,7 +528,7 @@ bool grobner::is_subset(monomial const * m1, monomial const * m2, ptr_vector<exp
|
|||
for (; i2 < sz2; i2++)
|
||||
rest.push_back(m2->m_vars[i2]);
|
||||
TRACE("grobner",
|
||||
tout << "monomail: "; display_monomial(tout, *m1); tout << " is a subset of ";
|
||||
tout << "monomial: "; display_monomial(tout, *m1); tout << " is a subset of ";
|
||||
display_monomial(tout, *m2); tout << "\n";
|
||||
tout << "rest: "; display_vars(tout, rest.size(), rest.data()); tout << "\n";);
|
||||
return true;
|
||||
|
@ -552,7 +552,7 @@ bool grobner::is_subset(monomial const * m1, monomial const * m2, ptr_vector<exp
|
|||
}
|
||||
}
|
||||
// is not subset
|
||||
TRACE("grobner", tout << "monomail: "; display_monomial(tout, *m1); tout << " is not a subset of ";
|
||||
TRACE("grobner", tout << "monomial: "; display_monomial(tout, *m1); tout << " is not a subset of ";
|
||||
display_monomial(tout, *m2); tout << "\n";);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -120,9 +120,16 @@ protected:
|
|||
|
||||
void display_var(std::ostream & out, expr * var) const;
|
||||
|
||||
void display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials) const;
|
||||
void display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void display_equations(std::ostream & out, equation_set const & v, char const * header) const;
|
||||
|
||||
void display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display_monomials(out, num_monomials, monomials, _fn);
|
||||
}
|
||||
|
||||
|
||||
void display_equations(std::ostream & out, equation_set const & v, char const * header, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void del_equations(unsigned old_size);
|
||||
|
||||
|
@ -281,11 +288,26 @@ public:
|
|||
|
||||
void pop_scope(unsigned num_scopes);
|
||||
|
||||
void display_equation(std::ostream & out, equation const & eq) const;
|
||||
void display_equation(std::ostream & out, equation const & eq) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display_equation(out, eq, _fn);
|
||||
}
|
||||
|
||||
void display_monomial(std::ostream & out, monomial const & m) const;
|
||||
void display_monomial(std::ostream & out, monomial const & m) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display_monomial(out, m, _fn);
|
||||
}
|
||||
|
||||
void display_equation(std::ostream & out, equation const & eq, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
void display_monomial(std::ostream & out, monomial const & m, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void display(std::ostream & out) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display(out, _fn);
|
||||
}
|
||||
|
||||
void display(std::ostream & out, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -223,6 +223,8 @@ namespace dd {
|
|||
for (unsigned i = 0; i < s.m_to_simplify.size(); ++i) {
|
||||
equation* e = s.m_to_simplify[i];
|
||||
pdd p = e->poly();
|
||||
if (p.is_val())
|
||||
continue;
|
||||
if (!p.hi().is_val()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
--*/
|
||||
|
||||
#include "util/uint_set.h"
|
||||
#include "math/grobner/pdd_solver.h"
|
||||
#include "math/grobner/pdd_simplifier.h"
|
||||
#include "util/uint_set.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
|
@ -169,7 +169,7 @@ namespace dd {
|
|||
/*
|
||||
Use the given equation to simplify equations in set
|
||||
*/
|
||||
void solver::simplify_using(equation_vector& set, equation const& eq) {
|
||||
void solver::simplify_using(equation_vector& set, std::function<bool(equation&, bool&)>& simplifier) {
|
||||
struct scoped_update {
|
||||
equation_vector& set;
|
||||
unsigned i, j, sz;
|
||||
|
@ -191,7 +191,7 @@ namespace dd {
|
|||
equation& target = *set[sr.i];
|
||||
bool changed_leading_term = false;
|
||||
bool simplified = true;
|
||||
simplified = !done() && try_simplify_using(target, eq, changed_leading_term);
|
||||
simplified = !done() && simplifier(target, changed_leading_term);
|
||||
|
||||
if (simplified && is_trivial(target)) {
|
||||
retire(&target);
|
||||
|
@ -200,7 +200,6 @@ namespace dd {
|
|||
// pushed to solved
|
||||
}
|
||||
else if (simplified && changed_leading_term) {
|
||||
SASSERT(target.state() == processed);
|
||||
push_equation(to_simplify, target);
|
||||
if (!m_var2level.empty()) {
|
||||
m_levelp1 = std::max(m_var2level[target.poly().var()]+1, m_levelp1);
|
||||
|
@ -210,6 +209,13 @@ namespace dd {
|
|||
sr.nextj();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void solver::simplify_using(equation_vector& set, equation const& eq) {
|
||||
std::function<bool(equation&, bool&)> simplifier = [&](equation& target, bool& changed_leading_term) {
|
||||
return try_simplify_using(target, eq, changed_leading_term);
|
||||
};
|
||||
simplify_using(set, simplifier);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -342,6 +348,7 @@ namespace dd {
|
|||
for (equation* e : m_solved) dealloc(e);
|
||||
for (equation* e : m_to_simplify) dealloc(e);
|
||||
for (equation* e : m_processed) dealloc(e);
|
||||
m_subst.reset();
|
||||
m_solved.reset();
|
||||
m_processed.reset();
|
||||
m_to_simplify.reset();
|
||||
|
@ -352,18 +359,54 @@ namespace dd {
|
|||
}
|
||||
|
||||
void solver::add(pdd const& p, u_dependency * dep) {
|
||||
if (p.is_zero()) return;
|
||||
equation * eq = alloc(equation, p, dep);
|
||||
if (check_conflict(*eq)) {
|
||||
if (p.is_zero())
|
||||
return;
|
||||
equation * eq = alloc(equation, p, dep);
|
||||
if (check_conflict(*eq))
|
||||
return;
|
||||
}
|
||||
push_equation(to_simplify, eq);
|
||||
|
||||
if (!m_var2level.empty()) {
|
||||
if (!m_var2level.empty())
|
||||
m_levelp1 = std::max(m_var2level[p.var()]+1, m_levelp1);
|
||||
}
|
||||
update_stats_max_degree_and_size(*eq);
|
||||
}
|
||||
}
|
||||
|
||||
void solver::add_subst(unsigned v, pdd const& p, u_dependency* dep) {
|
||||
m_subst.push_back({v, p, dep});
|
||||
if (!m_var2level.empty())
|
||||
m_levelp1 = std::max(m_var2level[v]+1, std::max(m_var2level[p.var()]+1, m_levelp1));
|
||||
|
||||
std::function<bool(equation&, bool&)> simplifier = [&](equation& dst, bool& changed_leading_term) {
|
||||
auto r = dst.poly().subst_pdd(v, p);
|
||||
if (r == dst.poly())
|
||||
return false;
|
||||
if (is_too_complex(r)) {
|
||||
m_too_complex = true;
|
||||
return false;
|
||||
}
|
||||
changed_leading_term = m.different_leading_term(r, dst.poly());
|
||||
dst = r;
|
||||
dst = m_dep_manager.mk_join(dst.dep(), dep);
|
||||
update_stats_max_degree_and_size(dst);
|
||||
return true;
|
||||
};
|
||||
if (!done())
|
||||
simplify_using(m_processed, simplifier);
|
||||
if (!done())
|
||||
simplify_using(m_to_simplify, simplifier);
|
||||
if (!done())
|
||||
simplify_using(m_solved, simplifier);
|
||||
}
|
||||
|
||||
void solver::simplify(pdd& p, u_dependency*& d) {
|
||||
for (auto const& [v, q, d2] : m_subst) {
|
||||
pdd r = p.subst_pdd(v, q);
|
||||
if (r != p) {
|
||||
p = r;
|
||||
d = m_dep_manager.mk_join(d, d2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool solver::canceled() {
|
||||
return m_limit.is_canceled();
|
||||
|
@ -446,9 +489,24 @@ namespace dd {
|
|||
}
|
||||
|
||||
std::ostream& solver::display(std::ostream& out) const {
|
||||
out << "solved\n"; for (auto e : m_solved) display(out, *e);
|
||||
out << "processed\n"; for (auto e : m_processed) display(out, *e);
|
||||
out << "to_simplify\n"; for (auto e : m_to_simplify) display(out, *e);
|
||||
if (!m_solved.empty()) {
|
||||
out << "solved\n"; for (auto e : m_solved) display(out, *e);
|
||||
}
|
||||
if (!m_processed.empty()) {
|
||||
out << "processed\n"; for (auto e : m_processed) display(out, *e);
|
||||
}
|
||||
if (!m_to_simplify.empty()) {
|
||||
out << "to_simplify\n"; for (auto e : m_to_simplify) display(out, *e);
|
||||
}
|
||||
if (!m_subst.empty()) {
|
||||
out << "subst\n";
|
||||
for (auto const& [v, p, d] : m_subst) {
|
||||
out << "v" << v << " := " << p;
|
||||
if (m_print_dep)
|
||||
m_print_dep(d, out);
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
return display_statistics(out);
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ private:
|
|||
equation_vector m_solved; // equations with solved variables, triangular
|
||||
equation_vector m_processed;
|
||||
equation_vector m_to_simplify;
|
||||
vector<std::tuple<unsigned, pdd, u_dependency*>> m_subst;
|
||||
mutable u_dependency_manager m_dep_manager;
|
||||
equation_vector m_all_eqs;
|
||||
equation* m_conflict;
|
||||
|
@ -136,6 +137,9 @@ public:
|
|||
void add(pdd const& p) { add(p, nullptr); }
|
||||
void add(pdd const& p, u_dependency * dep);
|
||||
|
||||
void simplify(pdd& p, u_dependency*& dep);
|
||||
void add_subst(unsigned v, pdd const& p, u_dependency* dep);
|
||||
|
||||
void simplify();
|
||||
void saturate();
|
||||
|
||||
|
@ -160,6 +164,7 @@ private:
|
|||
void simplify_using(equation& eq, equation_vector const& eqs);
|
||||
void simplify_using(equation_vector& set, equation const& eq);
|
||||
void simplify_using(equation & dst, equation const& src, bool& changed_leading_term);
|
||||
void simplify_using(equation_vector& set, std::function<bool(equation&, bool&)>& simplifier);
|
||||
bool try_simplify_using(equation& target, equation const& source, bool& changed_leading_term);
|
||||
|
||||
bool is_trivial(equation const& eq) const { return eq.poly().is_zero(); }
|
||||
|
|
|
@ -222,7 +222,6 @@ public:
|
|||
|
||||
template <enum with_deps_t wd>
|
||||
void mul(const rational& r, const interval& a, interval& b) const {
|
||||
if (r.is_zero()) return;
|
||||
m_imanager.mul(r.to_mpq(), a, b);
|
||||
if (wd == with_deps) {
|
||||
auto lower_dep = a.m_lower_dep;
|
||||
|
|
|
@ -34,6 +34,7 @@ z3_add_component(lp
|
|||
nla_basics_lemmas.cpp
|
||||
nla_common.cpp
|
||||
nla_core.cpp
|
||||
nla_grobner.cpp
|
||||
nla_intervals.cpp
|
||||
nla_monotone_lemmas.cpp
|
||||
nla_order_lemmas.cpp
|
||||
|
|
|
@ -40,7 +40,7 @@ bool horner::row_has_monomial_to_refine(const T& row) const {
|
|||
template <typename T>
|
||||
bool horner::row_is_interesting(const T& row) const {
|
||||
TRACE("nla_solver_details", c().print_row(row, tout););
|
||||
if (row.size() > c().m_nla_settings.horner_row_length_limit()) {
|
||||
if (row.size() > c().m_nla_settings.horner_row_length_limit) {
|
||||
TRACE("nla_solver_details", tout << "disregard\n";);
|
||||
return false;
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ bool horner::lemmas_on_row(const T& row) {
|
|||
}
|
||||
|
||||
bool horner::horner_lemmas() {
|
||||
if (!c().m_nla_settings.run_horner()) {
|
||||
if (!c().m_nla_settings.run_horner) {
|
||||
TRACE("nla_solver", tout << "not generating horner lemmas\n";);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -275,9 +275,6 @@ class lar_solver : public column_namer {
|
|||
return m_column_buffer;
|
||||
}
|
||||
bool bound_is_integer_for_integer_column(unsigned j, const mpq & right_side) const;
|
||||
inline unsigned get_base_column_in_row(unsigned row_index) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index);
|
||||
}
|
||||
inline lar_core_solver & get_core_solver() { return m_mpq_lar_core_solver; }
|
||||
void catch_up_in_updating_int_solver();
|
||||
var_index to_column(unsigned ext_j) const;
|
||||
|
@ -357,6 +354,10 @@ public:
|
|||
}
|
||||
|
||||
void set_value_for_nbasic_column(unsigned j, const impq& new_val);
|
||||
inline unsigned get_base_column_in_row(unsigned row_index) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index);
|
||||
}
|
||||
|
||||
|
||||
// lp_assert(implied_bound_is_correctly_explained(ib, explanation)); }
|
||||
constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side);
|
||||
|
@ -630,6 +631,7 @@ public:
|
|||
}
|
||||
void round_to_integer_solution();
|
||||
inline const row_strip<mpq> & get_row(unsigned i) const { return A_r().m_rows[i]; }
|
||||
inline const row_strip<mpq> & basic2row(unsigned i) const { return A_r().m_rows[row_of_basic_column(i)]; }
|
||||
inline const column_strip & get_column(unsigned i) const { return A_r().m_columns[i]; }
|
||||
bool row_is_correct(unsigned i) const;
|
||||
bool ax_is_correct() const;
|
||||
|
|
|
@ -71,11 +71,11 @@ void common::add_deps_of_fixed(lpvar j, u_dependency*& dep) {
|
|||
// creates a nex expression for the coeff and var,
|
||||
nex * common::nexvar(const rational & coeff, lpvar j, nex_creator& cn, u_dependency*& dep) {
|
||||
SASSERT(!coeff.is_zero());
|
||||
if (c().m_nla_settings.horner_subs_fixed() == 1 && c().var_is_fixed(j)) {
|
||||
if (c().m_nla_settings.horner_subs_fixed == 1 && c().var_is_fixed(j)) {
|
||||
add_deps_of_fixed(j, dep);
|
||||
return cn.mk_scalar(coeff * c().m_lar_solver.column_lower_bound(j).x);
|
||||
}
|
||||
if (c().m_nla_settings.horner_subs_fixed() == 2 && c().var_is_fixed_to_zero(j)) {
|
||||
if (c().m_nla_settings.horner_subs_fixed == 2 && c().var_is_fixed_to_zero(j)) {
|
||||
add_deps_of_fixed(j, dep);
|
||||
return cn.mk_scalar(rational(0));
|
||||
}
|
||||
|
@ -89,10 +89,10 @@ nex * common::nexvar(const rational & coeff, lpvar j, nex_creator& cn, u_depende
|
|||
mf *= coeff;
|
||||
u_dependency * initial_dep = dep;
|
||||
for (lpvar k : m.vars()) {
|
||||
if (c().m_nla_settings.horner_subs_fixed() && c().var_is_fixed(k)) {
|
||||
if (c().m_nla_settings.horner_subs_fixed == 1 && c().var_is_fixed(k)) {
|
||||
add_deps_of_fixed(k, dep);
|
||||
mf *= c().m_lar_solver.column_lower_bound(k).x;
|
||||
} else if (c().m_nla_settings.horner_subs_fixed() == 2 &&
|
||||
} else if (c().m_nla_settings.horner_subs_fixed == 2 &&
|
||||
c().var_is_fixed_to_zero(k)) {
|
||||
dep = initial_dep;
|
||||
add_deps_of_fixed(k, dep);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,15 +18,18 @@
|
|||
#include "math/lp/nla_basics_lemmas.h"
|
||||
#include "math/lp/nla_order_lemmas.h"
|
||||
#include "math/lp/nla_monotone_lemmas.h"
|
||||
#include "math/lp/nla_grobner.h"
|
||||
#include "math/lp/emonics.h"
|
||||
#include "math/lp/nla_settings.h"
|
||||
#include "math/lp/nex.h"
|
||||
#include "math/lp/horner.h"
|
||||
#include "math/lp/monomial_bounds.h"
|
||||
#include "math/lp/nla_intervals.h"
|
||||
#include "math/grobner/pdd_solver.h"
|
||||
#include "nlsat/nlsat_solver.h"
|
||||
|
||||
namespace nra {
|
||||
class solver;
|
||||
}
|
||||
|
||||
namespace nla {
|
||||
|
||||
|
@ -139,6 +142,20 @@ struct pp_factorization {
|
|||
};
|
||||
|
||||
class core {
|
||||
friend struct common;
|
||||
friend class new_lemma;
|
||||
friend class grobner;
|
||||
friend class order;
|
||||
friend struct basics;
|
||||
friend struct tangents;
|
||||
friend class monotone;
|
||||
friend struct nla_settings;
|
||||
friend class intervals;
|
||||
friend class horner;
|
||||
friend class solver;
|
||||
friend class monomial_bounds;
|
||||
friend class nra::solver;
|
||||
|
||||
struct stats {
|
||||
unsigned m_nla_explanations;
|
||||
unsigned m_nla_lemmas;
|
||||
|
@ -148,16 +165,18 @@ class core {
|
|||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
};
|
||||
stats m_stats;
|
||||
friend class new_lemma;
|
||||
|
||||
unsigned m_nlsat_delay { 50 };
|
||||
unsigned m_nlsat_fails { 0 };
|
||||
stats m_stats;
|
||||
unsigned m_nlsat_delay = 50;
|
||||
unsigned m_nlsat_fails = 0;
|
||||
|
||||
bool should_run_bounded_nlsat();
|
||||
lbool bounded_nlsat();
|
||||
public:
|
||||
|
||||
var_eqs<emonics> m_evars;
|
||||
|
||||
lp::lar_solver& m_lar_solver;
|
||||
reslimit& m_reslim;
|
||||
vector<lemma> * m_lemma_vec;
|
||||
lp::u_set m_to_refine;
|
||||
tangents m_tangents;
|
||||
|
@ -166,24 +185,21 @@ public:
|
|||
monotone m_monotone;
|
||||
intervals m_intervals;
|
||||
monomial_bounds m_monomial_bounds;
|
||||
nla_settings m_nla_settings;
|
||||
|
||||
horner m_horner;
|
||||
nla_settings m_nla_settings;
|
||||
dd::pdd_manager m_pdd_manager;
|
||||
dd::solver m_pdd_grobner;
|
||||
private:
|
||||
grobner m_grobner;
|
||||
emonics m_emons;
|
||||
svector<lpvar> m_add_buffer;
|
||||
mutable lp::u_set m_active_var_set;
|
||||
lp::u_set m_rows;
|
||||
|
||||
reslimit m_nra_lim;
|
||||
public:
|
||||
reslimit& m_reslim;
|
||||
bool m_use_nra_model;
|
||||
|
||||
bool m_use_nra_model = false;
|
||||
nra::solver m_nra;
|
||||
private:
|
||||
bool m_cautious_patching;
|
||||
lpvar m_patched_var;
|
||||
monic const* m_patched_monic;
|
||||
bool m_cautious_patching = true;
|
||||
lpvar m_patched_var = 0;
|
||||
monic const* m_patched_monic = nullptr;
|
||||
|
||||
void check_weighted(unsigned sz, std::pair<unsigned, std::function<void(void)>>* checks);
|
||||
|
||||
|
@ -205,6 +221,8 @@ public:
|
|||
m_active_var_set.resize(m_lar_solver.number_of_vars());
|
||||
}
|
||||
|
||||
unsigned get_var_weight(lpvar) const;
|
||||
|
||||
reslimit& reslim() { return m_reslim; }
|
||||
emonics& emons() { return m_emons; }
|
||||
const emonics& emons() const { return m_emons; }
|
||||
|
@ -243,12 +261,15 @@ public:
|
|||
|
||||
// returns true if the combination of the Horner's schema and Grobner Basis should be called
|
||||
bool need_run_horner() const {
|
||||
return m_nla_settings.run_horner() && lp_settings().stats().m_nla_calls % m_nla_settings.horner_frequency() == 0;
|
||||
return m_nla_settings.run_horner && lp_settings().stats().m_nla_calls % m_nla_settings.horner_frequency == 0;
|
||||
}
|
||||
|
||||
bool need_run_grobner() const {
|
||||
return m_nla_settings.run_grobner() && lp_settings().stats().m_nla_calls % m_nla_settings.grobner_frequency() == 0;
|
||||
return m_nla_settings.run_grobner && lp_settings().stats().m_nla_calls % m_nla_settings.grobner_frequency == 0;
|
||||
}
|
||||
|
||||
void set_active_vars_weights(nex_creator&);
|
||||
std::unordered_set<lpvar> get_vars_of_expr_with_opening_terms(const nex* e);
|
||||
|
||||
void incremental_linearization(bool);
|
||||
|
||||
|
@ -450,31 +471,19 @@ public:
|
|||
lpvar map_to_root(lpvar) const;
|
||||
std::ostream& print_terms(std::ostream&) const;
|
||||
std::ostream& print_term(const lp::lar_term&, std::ostream&) const;
|
||||
|
||||
template <typename T>
|
||||
std::ostream& print_row(const T & row , std::ostream& out) const {
|
||||
std::ostream& print_row(const T& row, std::ostream& out) const {
|
||||
vector<std::pair<rational, lpvar>> v;
|
||||
for (auto p : row) {
|
||||
v.push_back(std::make_pair(p.coeff(), p.var()));
|
||||
}
|
||||
return lp::print_linear_combination_customized(v, [this](lpvar j) { return var_str(j); },
|
||||
out);
|
||||
return lp::print_linear_combination_customized(v, [this](lpvar j) { return var_str(j); }, out);
|
||||
}
|
||||
void run_grobner();
|
||||
void find_nl_cluster();
|
||||
void prepare_rows_and_active_vars();
|
||||
void add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar>& q);
|
||||
std::unordered_set<lpvar> get_vars_of_expr_with_opening_terms(const nex* e);
|
||||
void display_matrix_of_m_rows(std::ostream & out) const;
|
||||
void set_active_vars_weights(nex_creator&);
|
||||
unsigned get_var_weight(lpvar) const;
|
||||
void add_row_to_grobner(const vector<lp::row_cell<rational>> & row);
|
||||
bool check_pdd_eq(const dd::solver::equation*);
|
||||
const rational& val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep);
|
||||
dd::pdd pdd_expr(const rational& c, lpvar j, u_dependency*&);
|
||||
void set_level2var_for_grobner();
|
||||
void configure_grobner();
|
||||
|
||||
bool influences_nl_var(lpvar) const;
|
||||
bool is_nl_var(lpvar) const;
|
||||
|
||||
bool is_used_in_monic(lpvar) const;
|
||||
void patch_monomials();
|
||||
void patch_monomials_on_to_refine();
|
||||
|
|
545
src/math/lp/nla_grobner.cpp
Normal file
545
src/math/lp/nla_grobner.cpp
Normal file
|
@ -0,0 +1,545 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
nla_grobner.cpp
|
||||
|
||||
Author:
|
||||
Lev Nachmanson (levnach)
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
|
||||
--*/
|
||||
#include "util/uint_set.h"
|
||||
#include "math/lp/nla_core.h"
|
||||
#include "math/lp/factorization_factory_imp.h"
|
||||
#include "math/lp/nex.h"
|
||||
#include "math/grobner/pdd_solver.h"
|
||||
#include "math/dd/pdd_interval.h"
|
||||
#include "math/dd/pdd_eval.h"
|
||||
|
||||
namespace nla {
|
||||
|
||||
grobner::grobner(core* c):
|
||||
common(c),
|
||||
m_pdd_manager(m_core.m_lar_solver.number_of_vars()),
|
||||
m_solver(m_core.m_reslim, m_pdd_manager),
|
||||
m_lar_solver(m_core.m_lar_solver)
|
||||
|
||||
{}
|
||||
|
||||
lp::lp_settings& grobner::lp_settings() {
|
||||
return c().lp_settings();
|
||||
}
|
||||
|
||||
void grobner::operator()() {
|
||||
unsigned& quota = c().m_nla_settings.grobner_quota;
|
||||
if (quota == 1)
|
||||
return;
|
||||
|
||||
lp_settings().stats().m_grobner_calls++;
|
||||
find_nl_cluster();
|
||||
configure();
|
||||
m_solver.saturate();
|
||||
|
||||
if (is_conflicting())
|
||||
return;
|
||||
|
||||
if (propagate_bounds())
|
||||
return;
|
||||
|
||||
if (propagate_eqs())
|
||||
return;
|
||||
|
||||
if (propagate_factorization())
|
||||
return;
|
||||
|
||||
if (quota > 1)
|
||||
quota--;
|
||||
|
||||
IF_VERBOSE(2, verbose_stream() << "grobner miss, quota " << quota << "\n");
|
||||
IF_VERBOSE(4, diagnose_pdd_miss(verbose_stream()));
|
||||
|
||||
#if 0
|
||||
// diagnostics: did we miss something
|
||||
vector<dd::pdd> eqs;
|
||||
for (auto eq : m_solver.equations())
|
||||
eqs.push_back(eq->poly());
|
||||
c().m_nra.check(eqs);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool grobner::is_conflicting() {
|
||||
unsigned conflicts = 0;
|
||||
for (auto eq : m_solver.equations())
|
||||
if (is_conflicting(*eq) && ++conflicts >= m_solver.number_of_conflicts_to_report())
|
||||
break;
|
||||
|
||||
if (conflicts > 0)
|
||||
lp_settings().stats().m_grobner_conflicts++;
|
||||
|
||||
TRACE("grobner", m_solver.display(tout));
|
||||
IF_VERBOSE(2, if (conflicts > 0) verbose_stream() << "grobner conflict\n");
|
||||
|
||||
return conflicts > 0;
|
||||
}
|
||||
|
||||
bool grobner::propagate_bounds() {
|
||||
unsigned changed = 0;
|
||||
for (auto eq : m_solver.equations())
|
||||
if (propagate_bounds(*eq) && ++changed >= m_solver.number_of_conflicts_to_report())
|
||||
return true;
|
||||
return changed > 0;
|
||||
}
|
||||
|
||||
bool grobner::propagate_eqs() {
|
||||
unsigned changed = 0;
|
||||
for (auto eq : m_solver.equations())
|
||||
if (propagate_fixed(*eq) && ++changed >= m_solver.number_of_conflicts_to_report())
|
||||
return true;
|
||||
return changed > 0;
|
||||
}
|
||||
|
||||
bool grobner::propagate_factorization() {
|
||||
unsigned changed = 0;
|
||||
for (auto eq : m_solver.equations())
|
||||
if (propagate_factorization(*eq) && ++changed >= m_solver.number_of_conflicts_to_report())
|
||||
return true;
|
||||
return changed > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief detect equalities
|
||||
- k*x = 0, that is x = 0
|
||||
- ax + b = 0
|
||||
*/
|
||||
typedef lp::lar_term term;
|
||||
bool grobner::propagate_fixed(const dd::solver::equation& eq) {
|
||||
dd::pdd const& p = eq.poly();
|
||||
//IF_VERBOSE(0, verbose_stream() << p << "\n");
|
||||
if (p.is_unary()) {
|
||||
unsigned v = p.var();
|
||||
if (c().var_is_fixed(v))
|
||||
return false;
|
||||
ineq new_eq(v, llc::EQ, rational::zero());
|
||||
if (c().ineq_holds(new_eq))
|
||||
return false;
|
||||
new_lemma lemma(c(), "pdd-eq");
|
||||
add_dependencies(lemma, eq);
|
||||
lemma |= new_eq;
|
||||
return true;
|
||||
}
|
||||
if (p.is_offset()) {
|
||||
unsigned v = p.var();
|
||||
if (c().var_is_fixed(v))
|
||||
return false;
|
||||
rational a = p.hi().val();
|
||||
rational b = -p.lo().val();
|
||||
rational d = lcm(denominator(a), denominator(b));
|
||||
a *= d;
|
||||
b *= d;
|
||||
ineq new_eq(term(a, v), llc::EQ, b);
|
||||
if (c().ineq_holds(new_eq))
|
||||
return false;
|
||||
new_lemma lemma(c(), "pdd-eq");
|
||||
add_dependencies(lemma, eq);
|
||||
lemma |= new_eq;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief detect simple factors
|
||||
x*q = 0 => x = 0 or q = 0
|
||||
*/
|
||||
|
||||
bool grobner::propagate_factorization(const dd::solver::equation& eq) {
|
||||
dd::pdd const& p = eq.poly();
|
||||
auto [vars, q] = p.var_factors();
|
||||
if (vars.empty() || !q.is_linear())
|
||||
return false;
|
||||
|
||||
// IF_VERBOSE(0, verbose_stream() << "factored " << q << " : " << vars << "\n");
|
||||
|
||||
term t;
|
||||
while (!q.is_val()) {
|
||||
t.add_monomial(q.hi().val(), q.var());
|
||||
q = q.lo();
|
||||
}
|
||||
vector<ineq> ineqs;
|
||||
for (auto v : vars)
|
||||
ineqs.push_back(ineq(v, llc::EQ, rational::zero()));
|
||||
ineqs.push_back(ineq(t, llc::EQ, -q.val()));
|
||||
for (auto const& i : ineqs)
|
||||
if (c().ineq_holds(i))
|
||||
return false;
|
||||
|
||||
new_lemma lemma(c(), "pdd-factored");
|
||||
add_dependencies(lemma, eq);
|
||||
for (auto const& i : ineqs)
|
||||
lemma |= i;
|
||||
//lemma.display(verbose_stream());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void grobner::add_dependencies(new_lemma& lemma, const dd::solver::equation& eq) {
|
||||
lp::explanation ex;
|
||||
u_dependency_manager dm;
|
||||
vector<unsigned, false> lv;
|
||||
dm.linearize(eq.dep(), lv);
|
||||
for (unsigned ci : lv)
|
||||
ex.push_back(ci);
|
||||
lemma &= ex;
|
||||
}
|
||||
|
||||
void grobner::configure() {
|
||||
m_solver.reset();
|
||||
try {
|
||||
set_level2var();
|
||||
TRACE("grobner",
|
||||
tout << "base vars: ";
|
||||
for (lpvar j : c().active_var_set())
|
||||
if (m_lar_solver.is_base(j))
|
||||
tout << "j" << j << " ";
|
||||
tout << "\n");
|
||||
for (lpvar j : c().active_var_set()) {
|
||||
if (m_lar_solver.is_base(j))
|
||||
add_row(m_lar_solver.basic2row(j));
|
||||
|
||||
if (c().is_monic_var(j) && c().var_is_fixed(j))
|
||||
add_fixed_monic(j);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
IF_VERBOSE(2, verbose_stream() << "pdd throw\n");
|
||||
return;
|
||||
}
|
||||
TRACE("grobner", m_solver.display(tout));
|
||||
|
||||
#if 0
|
||||
IF_VERBOSE(2, m_pdd_grobner.display(verbose_stream()));
|
||||
dd::pdd_eval eval(m_pdd_manager);
|
||||
eval.var2val() = [&](unsigned j){ return val(j); };
|
||||
for (auto* e : m_pdd_grobner.equations()) {
|
||||
dd::pdd p = e->poly();
|
||||
rational v = eval(p);
|
||||
if (p.is_linear() && !eval(p).is_zero()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "violated linear constraint " << p << "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct dd::solver::config cfg;
|
||||
cfg.m_max_steps = m_solver.equations().size();
|
||||
cfg.m_max_simplified = c().m_nla_settings.grobner_max_simplified;
|
||||
cfg.m_eqs_growth = c().m_nla_settings.grobner_eqs_growth;
|
||||
cfg.m_expr_size_growth = c().m_nla_settings.grobner_expr_size_growth;
|
||||
cfg.m_expr_degree_growth = c().m_nla_settings.grobner_expr_degree_growth;
|
||||
cfg.m_number_of_conflicts_to_report = c().m_nla_settings.grobner_number_of_conflicts_to_report;
|
||||
m_solver.set(cfg);
|
||||
m_solver.adjust_cfg();
|
||||
m_pdd_manager.set_max_num_nodes(10000); // or something proportional to the number of initial nodes.
|
||||
}
|
||||
|
||||
std::ostream& grobner::diagnose_pdd_miss(std::ostream& out) {
|
||||
|
||||
// m_pdd_grobner.display(out);
|
||||
|
||||
dd::pdd_eval eval;
|
||||
eval.var2val() = [&](unsigned j){ return val(j); };
|
||||
for (auto* e : m_solver.equations()) {
|
||||
dd::pdd p = e->poly();
|
||||
rational v = eval(p);
|
||||
if (!v.is_zero()) {
|
||||
out << p << " := " << v << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < m_lar_solver.number_of_vars(); ++j) {
|
||||
if (m_lar_solver.column_has_lower_bound(j) || m_lar_solver.column_has_upper_bound(j)) {
|
||||
out << j << ": [";
|
||||
if (m_lar_solver.column_has_lower_bound(j)) out << m_lar_solver.get_lower_bound(j);
|
||||
out << "..";
|
||||
if (m_lar_solver.column_has_upper_bound(j)) out << m_lar_solver.get_upper_bound(j);
|
||||
out << "]\n";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool grobner::is_conflicting(const dd::solver::equation& e) {
|
||||
auto& di = c().m_intervals.get_dep_intervals();
|
||||
dd::pdd_interval eval(di);
|
||||
eval.var2interval() = [this](lpvar j, bool deps, scoped_dep_interval& a) {
|
||||
if (deps) c().m_intervals.set_var_interval<dd::w_dep::with_deps>(j, a);
|
||||
else c().m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
|
||||
};
|
||||
scoped_dep_interval i(di), i_wd(di);
|
||||
eval.get_interval<dd::w_dep::without_deps>(e.poly(), i);
|
||||
if (!di.separated_from_zero(i)) {
|
||||
TRACE("grobner", m_solver.display(tout << "not separated from 0 ", e) << "\n";
|
||||
eval.get_interval_distributed<dd::w_dep::without_deps>(e.poly(), i);
|
||||
tout << "separated from 0: " << di.separated_from_zero(i) << "\n";
|
||||
for (auto j : e.poly().free_vars()) {
|
||||
scoped_dep_interval a(di);
|
||||
c().m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
|
||||
c().m_intervals.display(tout << "j" << j << " ", a); tout << " ";
|
||||
}
|
||||
tout << "\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
eval.get_interval<dd::w_dep::with_deps>(e.poly(), i_wd);
|
||||
std::function<void (const lp::explanation&)> f = [this](const lp::explanation& e) {
|
||||
new_lemma lemma(m_core, "pdd");
|
||||
lemma &= e;
|
||||
};
|
||||
if (di.check_interval_for_conflict_on_zero(i_wd, e.dep(), f)) {
|
||||
TRACE("grobner", m_solver.display(tout << "conflict ", e) << "\n");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
TRACE("grobner", m_solver.display(tout << "no conflict ", e) << "\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool grobner::propagate_bounds(const dd::solver::equation& e) {
|
||||
return false;
|
||||
// TODO
|
||||
auto& di = c().m_intervals.get_dep_intervals();
|
||||
dd::pdd_interval eval(di);
|
||||
eval.var2interval() = [this](lpvar j, bool deps, scoped_dep_interval& a) {
|
||||
if (deps) c().m_intervals.set_var_interval<dd::w_dep::with_deps>(j, a);
|
||||
else c().m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
|
||||
};
|
||||
scoped_dep_interval i(di), i_wd(di);
|
||||
eval.get_interval<dd::w_dep::without_deps>(e.poly(), i);
|
||||
return false;
|
||||
}
|
||||
|
||||
void grobner::add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar> & q) {
|
||||
if (c().active_var_set_contains(j))
|
||||
return;
|
||||
c().insert_to_active_var_set(j);
|
||||
if (c().is_monic_var(j)) {
|
||||
const monic& m = c().emons()[j];
|
||||
for (auto fcn : factorization_factory_imp(m, m_core))
|
||||
for (const factor& fc: fcn)
|
||||
q.push_back(var(fc));
|
||||
}
|
||||
|
||||
if (c().var_is_fixed(j))
|
||||
return;
|
||||
const auto& matrix = m_lar_solver.A_r();
|
||||
for (auto & s : matrix.m_columns[j]) {
|
||||
unsigned row = s.var();
|
||||
if (m_rows.contains(row))
|
||||
continue;
|
||||
m_rows.insert(row);
|
||||
unsigned k = m_lar_solver.get_base_column_in_row(row);
|
||||
if (m_lar_solver.column_is_free(k) && k != j)
|
||||
continue;
|
||||
CTRACE("grobner", matrix.m_rows[row].size() > c().m_nla_settings.grobner_row_length_limit,
|
||||
tout << "ignore the row " << row << " with the size " << matrix.m_rows[row].size() << "\n";);
|
||||
if (matrix.m_rows[row].size() > c().m_nla_settings.grobner_row_length_limit)
|
||||
continue;
|
||||
for (auto& rc : matrix.m_rows[row])
|
||||
add_var_and_its_factors_to_q_and_collect_new_rows(rc.var(), q);
|
||||
}
|
||||
}
|
||||
|
||||
const rational& grobner::val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep) {
|
||||
unsigned lc, uc;
|
||||
m_lar_solver.get_bound_constraint_witnesses_for_column(j, lc, uc);
|
||||
dep = c().m_intervals.mk_join(dep, c().m_intervals.mk_leaf(lc));
|
||||
dep = c().m_intervals.mk_join(dep, c().m_intervals.mk_leaf(uc));
|
||||
return m_lar_solver.column_lower_bound(j).x;
|
||||
}
|
||||
|
||||
dd::pdd grobner::pdd_expr(const rational& coeff, lpvar j, u_dependency*& dep) {
|
||||
dd::pdd r = m_pdd_manager.mk_val(coeff);
|
||||
sbuffer<lpvar> vars;
|
||||
vars.push_back(j);
|
||||
u_dependency* zero_dep = dep;
|
||||
while (!vars.empty()) {
|
||||
j = vars.back();
|
||||
vars.pop_back();
|
||||
if (c().m_nla_settings.grobner_subs_fixed > 0 && c().var_is_fixed_to_zero(j)) {
|
||||
r = m_pdd_manager.mk_val(val_of_fixed_var_with_deps(j, zero_dep));
|
||||
dep = zero_dep;
|
||||
return r;
|
||||
}
|
||||
if (c().m_nla_settings.grobner_subs_fixed == 1 && c().var_is_fixed(j))
|
||||
r *= val_of_fixed_var_with_deps(j, dep);
|
||||
else if (!c().is_monic_var(j))
|
||||
r *= m_pdd_manager.mk_var(j);
|
||||
else
|
||||
for (lpvar k : c().emons()[j].vars())
|
||||
vars.push_back(k);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief convert p == 0 into a solved form v == r, such that
|
||||
v has bounds [lo, oo) iff r has bounds [lo', oo)
|
||||
v has bounds (oo,hi] iff r has bounds (oo,hi']
|
||||
|
||||
The solved form allows the Grobner solver identify more bounds conflicts.
|
||||
A bad leading term can miss bounds conflicts.
|
||||
For example for x + y + z == 0 where x, y : [0, oo) and z : (oo,0]
|
||||
we prefer to solve z == -x - y instead of x == -z - y
|
||||
because the solution -z - y has neither an upper, nor a lower bound.
|
||||
*/
|
||||
bool grobner::is_solved(dd::pdd const& p, unsigned& v, dd::pdd& r) {
|
||||
if (!p.is_linear())
|
||||
return false;
|
||||
r = p;
|
||||
unsigned num_lo = 0, num_hi = 0;
|
||||
unsigned lo = 0, hi = 0;
|
||||
rational lc, hc, c;
|
||||
while (!r.is_val()) {
|
||||
SASSERT(r.hi().is_val());
|
||||
v = r.var();
|
||||
rational val = r.hi().val();
|
||||
switch (m_lar_solver.get_column_type(v)) {
|
||||
case lp::column_type::lower_bound:
|
||||
if (val > 0) num_lo++, lo = v, lc = val; else num_hi++, hi = v, hc = val;
|
||||
break;
|
||||
case lp::column_type::upper_bound:
|
||||
if (val < 0) num_lo++, lo = v, lc = val; else num_hi++, hi = v, hc = val;
|
||||
break;
|
||||
case lp::column_type::fixed:
|
||||
case lp::column_type::boxed:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (num_lo > 1 && num_hi > 1)
|
||||
return false;
|
||||
r = r.lo();
|
||||
}
|
||||
if (num_lo == 1 && num_hi > 1) {
|
||||
v = lo;
|
||||
c = lc;
|
||||
}
|
||||
else if (num_hi == 1 && num_lo > 1) {
|
||||
v = hi;
|
||||
c = hc;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
r = c*m_pdd_manager.mk_var(v) - p;
|
||||
if (c != 1)
|
||||
r = r * (1/c);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief add an equality to grobner solver, convert it to solved form if available.
|
||||
*/
|
||||
void grobner::add_eq(dd::pdd& p, u_dependency* dep) {
|
||||
unsigned v;
|
||||
dd::pdd q(m_pdd_manager);
|
||||
m_solver.simplify(p, dep);
|
||||
if (is_solved(p, v, q))
|
||||
m_solver.add_subst(v, q, dep);
|
||||
else
|
||||
m_solver.add(p, dep);
|
||||
}
|
||||
|
||||
void grobner::add_fixed_monic(unsigned j) {
|
||||
u_dependency* dep = nullptr;
|
||||
dd::pdd r = m_pdd_manager.mk_val(rational(1));
|
||||
for (lpvar k : c().emons()[j].vars())
|
||||
r *= pdd_expr(rational::one(), k, dep);
|
||||
r -= val_of_fixed_var_with_deps(j, dep);
|
||||
add_eq(r, dep);
|
||||
}
|
||||
|
||||
void grobner::add_row(const vector<lp::row_cell<rational>> & row) {
|
||||
u_dependency *dep = nullptr;
|
||||
rational val;
|
||||
dd::pdd sum = m_pdd_manager.mk_val(rational(0));
|
||||
for (const auto &p : row)
|
||||
sum += pdd_expr(p.coeff(), p.var(), dep);
|
||||
TRACE("grobner", c().print_row(row, tout) << " " << sum << "\n");
|
||||
add_eq(sum, dep);
|
||||
}
|
||||
|
||||
|
||||
void grobner::find_nl_cluster() {
|
||||
prepare_rows_and_active_vars();
|
||||
svector<lpvar> q;
|
||||
TRACE("grobner", for (lpvar j : c().m_to_refine) print_monic(c().emons()[j], tout) << "\n";);
|
||||
|
||||
for (lpvar j : c().m_to_refine)
|
||||
q.push_back(j);
|
||||
|
||||
while (!q.empty()) {
|
||||
lpvar j = q.back();
|
||||
q.pop_back();
|
||||
add_var_and_its_factors_to_q_and_collect_new_rows(j, q);
|
||||
}
|
||||
TRACE("grobner", tout << "vars in cluster: ";
|
||||
for (lpvar j : c().active_var_set()) tout << "j" << j << " "; tout << "\n";
|
||||
display_matrix_of_m_rows(tout);
|
||||
);
|
||||
}
|
||||
|
||||
void grobner::prepare_rows_and_active_vars() {
|
||||
m_rows.clear();
|
||||
m_rows.resize(m_lar_solver.row_count());
|
||||
c().clear_and_resize_active_var_set();
|
||||
}
|
||||
|
||||
|
||||
void grobner::display_matrix_of_m_rows(std::ostream & out) const {
|
||||
const auto& matrix = m_lar_solver.A_r();
|
||||
out << m_rows.size() << " rows" << "\n";
|
||||
out << "the matrix\n";
|
||||
for (const auto & r : matrix.m_rows)
|
||||
c().print_row(r, out) << std::endl;
|
||||
}
|
||||
|
||||
void grobner::set_level2var() {
|
||||
unsigned n = m_lar_solver.column_count();
|
||||
unsigned_vector sorted_vars(n), weighted_vars(n);
|
||||
for (unsigned j = 0; j < n; j++) {
|
||||
sorted_vars[j] = j;
|
||||
weighted_vars[j] = c().get_var_weight(j);
|
||||
}
|
||||
#if 1
|
||||
// potential update to weights
|
||||
for (unsigned j = 0; j < n; j++) {
|
||||
if (c().is_monic_var(j) && c().m_to_refine.contains(j)) {
|
||||
for (lpvar k : c().m_emons[j].vars()) {
|
||||
weighted_vars[k] += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::sort(sorted_vars.begin(), sorted_vars.end(), [&](unsigned a, unsigned b) {
|
||||
unsigned wa = weighted_vars[a];
|
||||
unsigned wb = weighted_vars[b];
|
||||
return wa < wb || (wa == wb && a < b); });
|
||||
|
||||
unsigned_vector l2v(n);
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
l2v[j] = sorted_vars[j];
|
||||
|
||||
m_pdd_manager.reset(l2v);
|
||||
|
||||
TRACE("grobner",
|
||||
for (auto v : sorted_vars)
|
||||
tout << "j" << v << " w:" << weighted_vars[v] << " ";
|
||||
tout << "\n");
|
||||
}
|
||||
|
||||
}
|
64
src/math/lp/nla_grobner.h
Normal file
64
src/math/lp/nla_grobner.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Author:
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "math/lp/nla_common.h"
|
||||
#include "math/lp/nla_intervals.h"
|
||||
#include "math/lp/nex.h"
|
||||
#include "math/lp/cross_nested.h"
|
||||
#include "math/lp/u_set.h"
|
||||
#include "math/grobner/pdd_solver.h"
|
||||
|
||||
namespace nla {
|
||||
class core;
|
||||
|
||||
class grobner : common {
|
||||
dd::pdd_manager m_pdd_manager;
|
||||
dd::solver m_solver;
|
||||
lp::lar_solver& m_lar_solver;
|
||||
lp::u_set m_rows;
|
||||
|
||||
lp::lp_settings& lp_settings();
|
||||
|
||||
// solving
|
||||
bool is_conflicting();
|
||||
bool is_conflicting(const dd::solver::equation& eq);
|
||||
|
||||
bool propagate_bounds();
|
||||
bool propagate_bounds(const dd::solver::equation& eq);
|
||||
|
||||
bool propagate_eqs();
|
||||
bool propagate_fixed(const dd::solver::equation& eq);
|
||||
|
||||
bool propagate_factorization();
|
||||
bool propagate_factorization(const dd::solver::equation& eq);
|
||||
|
||||
void add_dependencies(new_lemma& lemma, const dd::solver::equation& eq);
|
||||
|
||||
// setup
|
||||
void configure();
|
||||
void set_level2var();
|
||||
void find_nl_cluster();
|
||||
void prepare_rows_and_active_vars();
|
||||
void add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar>& q);
|
||||
void add_row(const vector<lp::row_cell<rational>>& row);
|
||||
void add_fixed_monic(unsigned j);
|
||||
bool is_solved(dd::pdd const& p, unsigned& v, dd::pdd& r);
|
||||
void add_eq(dd::pdd& p, u_dependency* dep);
|
||||
const rational& val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep);
|
||||
dd::pdd pdd_expr(const rational& c, lpvar j, u_dependency*& dep);
|
||||
|
||||
void display_matrix_of_m_rows(std::ostream& out) const;
|
||||
std::ostream& diagnose_pdd_miss(std::ostream& out);
|
||||
|
||||
public:
|
||||
grobner(core *core);
|
||||
void operator()();
|
||||
};
|
||||
}
|
|
@ -19,7 +19,7 @@ typedef lp::lar_term term;
|
|||
// a > b && c > 0 => ac > bc
|
||||
void order::order_lemma() {
|
||||
TRACE("nla_solver", );
|
||||
if (!c().m_nla_settings.run_order()) {
|
||||
if (!c().m_nla_settings.run_order) {
|
||||
TRACE("nla_solver", tout << "not generating order lemmas\n";);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -9,94 +9,38 @@ Author:
|
|||
|
||||
#pragma once
|
||||
namespace nla {
|
||||
class nla_settings {
|
||||
bool m_run_order;
|
||||
bool m_run_tangents;
|
||||
bool m_run_horner;
|
||||
// how often to call the horner heuristic
|
||||
unsigned m_horner_frequency;
|
||||
unsigned m_horner_row_length_limit;
|
||||
unsigned m_horner_subs_fixed;
|
||||
// grobner fields
|
||||
bool m_run_grobner;
|
||||
unsigned m_grobner_row_length_limit;
|
||||
unsigned m_grobner_subs_fixed;
|
||||
unsigned m_grobner_eqs_growth;
|
||||
unsigned m_grobner_tree_size_growth;
|
||||
unsigned m_grobner_expr_size_growth;
|
||||
unsigned m_grobner_expr_degree_growth;
|
||||
unsigned m_grobner_max_simplified;
|
||||
unsigned m_grobner_number_of_conflicts_to_report;
|
||||
unsigned m_grobner_quota;
|
||||
unsigned m_grobner_frequency;
|
||||
bool m_run_nra;
|
||||
// expensive patching
|
||||
bool m_expensive_patching;
|
||||
public:
|
||||
nla_settings() : m_run_order(true),
|
||||
m_run_tangents(true),
|
||||
m_run_horner(true),
|
||||
m_horner_frequency(4),
|
||||
m_horner_row_length_limit(10),
|
||||
m_horner_subs_fixed(2),
|
||||
m_run_grobner(true),
|
||||
m_grobner_row_length_limit(50),
|
||||
m_grobner_subs_fixed(false),
|
||||
m_grobner_quota(0),
|
||||
m_grobner_frequency(4),
|
||||
m_run_nra(false),
|
||||
m_expensive_patching(false)
|
||||
{}
|
||||
unsigned grobner_eqs_growth() const { return m_grobner_eqs_growth;}
|
||||
unsigned& grobner_eqs_growth() { return m_grobner_eqs_growth;}
|
||||
bool run_order() const { return m_run_order; }
|
||||
bool& run_order() { return m_run_order; }
|
||||
struct nla_settings {
|
||||
bool run_order = true;
|
||||
bool run_tangents = true;
|
||||
|
||||
// horner fields
|
||||
bool run_horner = true;
|
||||
unsigned horner_frequency = 4;
|
||||
unsigned horner_row_length_limit = 10;
|
||||
unsigned horner_subs_fixed = 2;
|
||||
|
||||
bool run_tangents() const { return m_run_tangents; }
|
||||
bool& run_tangents() { return m_run_tangents; }
|
||||
|
||||
// grobner fields
|
||||
bool run_grobner = true;
|
||||
unsigned grobner_row_length_limit = 50;
|
||||
unsigned grobner_subs_fixed = 1;
|
||||
unsigned grobner_eqs_growth = 10;
|
||||
unsigned grobner_tree_size_growth = 2;
|
||||
unsigned grobner_expr_size_growth = 2;
|
||||
unsigned grobner_expr_degree_growth = 2;
|
||||
unsigned grobner_max_simplified = 10000;
|
||||
unsigned grobner_number_of_conflicts_to_report = 1;
|
||||
unsigned grobner_quota = 0;
|
||||
unsigned grobner_frequency = 4;
|
||||
|
||||
bool expensive_patching() const { return m_expensive_patching; }
|
||||
bool& expensive_patching() { return m_expensive_patching; }
|
||||
|
||||
bool run_horner() const { return m_run_horner; }
|
||||
bool& run_horner() { return m_run_horner; }
|
||||
|
||||
unsigned horner_frequency() const { return m_horner_frequency; }
|
||||
unsigned& horner_frequency() { return m_horner_frequency; }
|
||||
unsigned horner_row_length_limit() const { return m_horner_row_length_limit; }
|
||||
unsigned& horner_row_length_limit() { return m_horner_row_length_limit; }
|
||||
unsigned horner_subs_fixed() const { return m_horner_subs_fixed; }
|
||||
unsigned& horner_subs_fixed() { return m_horner_subs_fixed; }
|
||||
|
||||
bool run_grobner() const { return m_run_grobner; }
|
||||
bool& run_grobner() { return m_run_grobner; }
|
||||
unsigned grobner_frequency() const { return m_grobner_frequency; }
|
||||
unsigned& grobner_frequency() { return m_grobner_frequency; }
|
||||
|
||||
bool run_nra() const { return m_run_nra; }
|
||||
bool& run_nra() { return m_run_nra; }
|
||||
|
||||
unsigned grobner_row_length_limit() const { return m_grobner_row_length_limit; }
|
||||
unsigned& grobner_row_length_limit() { return m_grobner_row_length_limit; }
|
||||
unsigned grobner_subs_fixed() const { return m_grobner_subs_fixed; }
|
||||
unsigned& grobner_subs_fixed() { return m_grobner_subs_fixed; }
|
||||
|
||||
unsigned grobner_tree_size_growth() const { return m_grobner_tree_size_growth; }
|
||||
unsigned & grobner_tree_size_growth() { return m_grobner_tree_size_growth; }
|
||||
|
||||
unsigned grobner_expr_size_growth() const { return m_grobner_expr_size_growth; }
|
||||
unsigned & grobner_expr_size_growth() { return m_grobner_expr_size_growth; }
|
||||
|
||||
unsigned grobner_expr_degree_growth() const { return m_grobner_expr_degree_growth; }
|
||||
unsigned & grobner_expr_degree_growth() { return m_grobner_expr_degree_growth; }
|
||||
|
||||
unsigned grobner_max_simplified() const { return m_grobner_max_simplified; }
|
||||
unsigned & grobner_max_simplified() { return m_grobner_max_simplified; }
|
||||
|
||||
unsigned grobner_number_of_conflicts_to_report() const { return m_grobner_number_of_conflicts_to_report; }
|
||||
unsigned & grobner_number_of_conflicts_to_report() { return m_grobner_number_of_conflicts_to_report; }
|
||||
|
||||
unsigned& grobner_quota() { return m_grobner_quota; }
|
||||
// nra fields
|
||||
bool run_nra = false;
|
||||
|
||||
};
|
||||
// expensive patching
|
||||
bool expensive_patching = false;
|
||||
|
||||
nla_settings() {}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ tangents::tangents(core * c) : common(c) {}
|
|||
void tangents::tangent_lemma() {
|
||||
factorization bf(nullptr);
|
||||
const monic* m = nullptr;
|
||||
if (c().m_nla_settings.run_tangents() && c().find_bfc_to_refine(m, bf)) {
|
||||
if (c().m_nla_settings.run_tangents && c().find_bfc_to_refine(m, bf)) {
|
||||
lpvar j = m->var();
|
||||
tangent_imp tangent(point(val(bf[0]), val(bf[1])), c().val(j), *m, bf, *this);
|
||||
tangent();
|
||||
|
|
|
@ -65,12 +65,10 @@ struct solver::imp {
|
|||
}
|
||||
|
||||
// add polynomial definitions.
|
||||
for (auto const& m : m_nla_core.emons()) {
|
||||
for (auto const& m : m_nla_core.emons())
|
||||
add_monic_eq(m);
|
||||
}
|
||||
for (unsigned i : m_term_set) {
|
||||
for (unsigned i : m_term_set)
|
||||
add_term(i);
|
||||
}
|
||||
// TBD: add variable bounds?
|
||||
|
||||
lbool r = l_undef;
|
||||
|
@ -176,7 +174,103 @@ struct solver::imp {
|
|||
lp_assert(false); // unreachable
|
||||
}
|
||||
m_nlsat->mk_clause(1, &lit, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lbool check(vector<dd::pdd> const& eqs) {
|
||||
m_zero = nullptr;
|
||||
m_nlsat = alloc(nlsat::solver, m_limit, m_params, false);
|
||||
m_zero = alloc(scoped_anum, am());
|
||||
m_lp2nl.reset();
|
||||
m_term_set.clear();
|
||||
for (auto const& eq : eqs)
|
||||
add_eq(eq);
|
||||
for (auto const& [v, w] : m_lp2nl) {
|
||||
auto& ls = m_nla_core.m_lar_solver;
|
||||
if (ls.column_has_lower_bound(v))
|
||||
add_lb(ls.get_lower_bound(v), w);
|
||||
if (ls.column_has_upper_bound(v))
|
||||
add_ub(ls.get_upper_bound(v), w);
|
||||
}
|
||||
|
||||
lbool r = l_undef;
|
||||
try {
|
||||
r = m_nlsat->check();
|
||||
}
|
||||
catch (z3_exception&) {
|
||||
if (m_limit.is_canceled()) {
|
||||
r = l_undef;
|
||||
}
|
||||
else {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
IF_VERBOSE(0, verbose_stream() << "check-nra " << r << "\n";
|
||||
m_nlsat->display(verbose_stream());
|
||||
for (auto const& [v, w] : m_lp2nl) {
|
||||
auto& ls = m_nla_core.m_lar_solver;
|
||||
if (ls.column_has_lower_bound(v))
|
||||
verbose_stream() << w << " >= " << ls.get_lower_bound(v) << "\n";
|
||||
if (ls.column_has_upper_bound(v))
|
||||
verbose_stream() << w << " <= " << ls.get_upper_bound(v) << "\n";
|
||||
});
|
||||
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void add_eq(dd::pdd const& eq) {
|
||||
dd::pdd normeq = eq;
|
||||
rational lc(1);
|
||||
for (auto const& [c, m] : eq)
|
||||
lc = lcm(denominator(c), lc);
|
||||
if (lc != 1)
|
||||
normeq *= lc;
|
||||
polynomial::manager& pm = m_nlsat->pm();
|
||||
polynomial::polynomial_ref p(pdd2polynomial(normeq), pm);
|
||||
bool is_even[1] = { false };
|
||||
polynomial::polynomial* ps[1] = { p };
|
||||
nlsat::literal lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even);
|
||||
m_nlsat->mk_clause(1, &lit, nullptr);
|
||||
}
|
||||
|
||||
void add_lb(lp::impq const& b, unsigned w) {
|
||||
add_bound(b.x, w, b.y <= 0, b.y > 0 ? nlsat::atom::kind::GT : nlsat::atom::kind::LT);
|
||||
}
|
||||
void add_ub(lp::impq const& b, unsigned w) {
|
||||
add_bound(b.x, w, b.y >= 0, b.y < 0 ? nlsat::atom::kind::LT : nlsat::atom::kind::GT);
|
||||
}
|
||||
|
||||
// w - bound < 0
|
||||
// w - bound > 0
|
||||
void add_bound(lp::mpq const& bound, unsigned w, bool neg, nlsat::atom::kind k) {
|
||||
polynomial::manager& pm = m_nlsat->pm();
|
||||
polynomial::polynomial_ref p1(pm.mk_polynomial(w), pm);
|
||||
polynomial::polynomial_ref p2(pm.mk_const(bound), pm);
|
||||
polynomial::polynomial_ref p(pm.sub(p1, p2), pm);
|
||||
polynomial::polynomial* ps[1] = { p };
|
||||
bool is_even[1] = { false };
|
||||
nlsat::literal lit = m_nlsat->mk_ineq_literal(k, 1, ps, is_even);
|
||||
if (neg)
|
||||
lit.neg();
|
||||
m_nlsat->mk_clause(1, &lit, nullptr);
|
||||
}
|
||||
|
||||
polynomial::polynomial* pdd2polynomial(dd::pdd const& p) {
|
||||
polynomial::manager& pm = m_nlsat->pm();
|
||||
if (p.is_val())
|
||||
return pm.mk_const(p.val());
|
||||
polynomial::polynomial_ref lo(pdd2polynomial(p.lo()), pm);
|
||||
polynomial::polynomial_ref hi(pdd2polynomial(p.hi()), pm);
|
||||
unsigned w, v = p.var();
|
||||
if (!m_lp2nl.find(v, w)) {
|
||||
w = m_nlsat->mk_var(false);
|
||||
m_lp2nl.insert(v, w);
|
||||
}
|
||||
polynomial::polynomial_ref vp(pm.mk_polynomial(w, 1), pm);
|
||||
return pm.add(lo, pm.mul(vp, hi));
|
||||
}
|
||||
|
||||
bool is_int(lp::var_index v) {
|
||||
return s.var_is_int(v);
|
||||
|
@ -265,6 +359,10 @@ lbool solver::check() {
|
|||
return m_imp->check();
|
||||
}
|
||||
|
||||
lbool solver::check(vector<dd::pdd> const& eqs) {
|
||||
return m_imp->check(eqs);
|
||||
}
|
||||
|
||||
bool solver::need_check() {
|
||||
return m_imp->need_check();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "util/rlimit.h"
|
||||
#include "util/params.h"
|
||||
#include "nlsat/nlsat_solver.h"
|
||||
#include "math/dd/dd_pdd.h"
|
||||
|
||||
namespace lp {
|
||||
class lar_solver;
|
||||
|
@ -36,6 +37,11 @@ namespace nra {
|
|||
*/
|
||||
lbool check();
|
||||
|
||||
/**
|
||||
\breif Check feasibility of equalities modulo bounds constraints on their variables.
|
||||
*/
|
||||
lbool check(vector<dd::pdd> const& eqs);
|
||||
|
||||
/*
|
||||
\brief determine whether nra check is needed.
|
||||
*/
|
||||
|
|
|
@ -137,9 +137,6 @@ namespace opt {
|
|||
m_model_fixed(),
|
||||
m_objective_refs(m),
|
||||
m_core(m),
|
||||
m_enable_sat(false),
|
||||
m_is_clausal(false),
|
||||
m_pp_neat(false),
|
||||
m_unknown("unknown")
|
||||
{
|
||||
params_ref p;
|
||||
|
@ -196,6 +193,8 @@ namespace opt {
|
|||
|
||||
void context::add_hard_constraint(expr* f) {
|
||||
if (m_calling_on_model) {
|
||||
if (!m_incremental)
|
||||
throw default_exception("Set opt.incremental = true to allow adding constraints during search");
|
||||
get_solver().assert_expr(f);
|
||||
for (auto const& [k, v] : m_maxsmts)
|
||||
v->reset_upper();
|
||||
|
@ -838,19 +837,14 @@ namespace opt {
|
|||
}
|
||||
|
||||
goal_ref g(alloc(goal, m, true, !asms.empty()));
|
||||
for (expr* fml : fmls) {
|
||||
for (expr* fml : fmls)
|
||||
g->assert_expr(fml);
|
||||
}
|
||||
for (expr * a : asms) {
|
||||
for (expr * a : asms)
|
||||
g->assert_expr(a, a);
|
||||
}
|
||||
tactic_ref tac0 =
|
||||
and_then(mk_simplify_tactic(m, m_params),
|
||||
mk_propagate_values_tactic(m),
|
||||
mk_solve_eqs_tactic(m),
|
||||
// NB: cannot ackermannize because max/min objectives would disappear
|
||||
// mk_ackermannize_bv_tactic(m, m_params),
|
||||
// NB: mk_elim_uncstr_tactic(m) is not sound with soft constraints
|
||||
m_incremental ? mk_skip_tactic() : mk_solve_eqs_tactic(m),
|
||||
mk_simplify_tactic(m));
|
||||
opt_params optp(m_params);
|
||||
tactic_ref tac1, tac2, tac3, tac4;
|
||||
|
@ -861,7 +855,7 @@ namespace opt {
|
|||
m.linearize(core, deps);
|
||||
has_dep |= !deps.empty();
|
||||
}
|
||||
if (optp.elim_01() && m_logic.is_null() && !has_dep) {
|
||||
if (optp.elim_01() && m_logic.is_null() && !has_dep && !m_incremental) {
|
||||
tac1 = mk_dt2bv_tactic(m);
|
||||
tac2 = mk_lia2card_tactic(m);
|
||||
tac3 = mk_eq2bv_tactic(m);
|
||||
|
@ -1568,6 +1562,7 @@ namespace opt {
|
|||
m_maxsat_engine = _p.maxsat_engine();
|
||||
m_pp_neat = _p.pp_neat();
|
||||
m_pp_wcnf = _p.pp_wcnf();
|
||||
m_incremental = _p.incremental();
|
||||
}
|
||||
|
||||
std::string context::to_string() {
|
||||
|
|
|
@ -194,11 +194,12 @@ namespace opt {
|
|||
func_decl_ref_vector m_objective_refs;
|
||||
expr_ref_vector m_core;
|
||||
tactic_ref m_simplify;
|
||||
bool m_enable_sat { true } ;
|
||||
bool m_enable_sls { false };
|
||||
bool m_is_clausal { false };
|
||||
bool m_pp_neat { true };
|
||||
bool m_pp_wcnf { false };
|
||||
bool m_enable_sat = true;
|
||||
bool m_enable_sls = false;
|
||||
bool m_is_clausal = false;
|
||||
bool m_pp_neat = false;
|
||||
bool m_pp_wcnf = false;
|
||||
bool m_incremental = false;
|
||||
symbol m_maxsat_engine;
|
||||
symbol m_logic;
|
||||
svector<symbol> m_labels;
|
||||
|
|
|
@ -15,6 +15,7 @@ def_module_params('opt',
|
|||
('enable_core_rotate', BOOL, False, 'enable core rotation to both sample cores and correction sets'),
|
||||
('enable_sat', BOOL, True, 'enable the new SAT core for propositional constraints'),
|
||||
('elim_01', BOOL, True, 'eliminate 01 variables'),
|
||||
('incremental', BOOL, False, 'set incremental mode. It disables pre-processing and enables adding constraints in model event handler'),
|
||||
('pp.neat', BOOL, True, 'use neat (as opposed to less readable, but faster) pretty printer when displaying context'),
|
||||
('pb.compile_equality', BOOL, False, 'compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites)'),
|
||||
('pp.wcnf', BOOL, False, 'print maxsat benchmark into wcnf format'),
|
||||
|
|
|
@ -536,6 +536,7 @@ namespace qe {
|
|||
th_rewriter rewrite(m);
|
||||
rewrite(a);
|
||||
rewrite(b);
|
||||
TRACE("interpolator", tout << a << " " << b << "\n");
|
||||
solver_ref sA = sf(m, p, false /* no proofs */, true, true, symbol::null);
|
||||
solver_ref sB = sf(m, p, false /* no proofs */, true, true, symbol::null);
|
||||
solver_ref sNotA = sf(m, p, false /* no proofs */, true, true, symbol::null);
|
||||
|
|
|
@ -1787,6 +1787,7 @@ namespace sat {
|
|||
clause& c = it.curr();
|
||||
if (!c.is_learned() && !c.was_removed()) {
|
||||
r.push_back(clause_wrapper(c));
|
||||
SASSERT(r.back().contains(l));
|
||||
SASSERT(r.back().size() == c.size());
|
||||
}
|
||||
}
|
||||
|
@ -1808,9 +1809,13 @@ namespace sat {
|
|||
Return false if the result is a tautology
|
||||
*/
|
||||
bool simplifier::resolve(clause_wrapper const & c1, clause_wrapper const & c2, literal l, literal_vector & r) {
|
||||
CTRACE("resolve_bug", !c1.contains(l), tout << c1 << "\n" << c2 << "\nl: " << l << "\n";);
|
||||
CTRACE("resolve_bug", !c1.contains(l) || !c2.contains(~l), tout << c1 << "\n" << c2 << "\nl: " << l << "\n";);
|
||||
if (m_visited.size() <= 2*s.num_vars())
|
||||
m_visited.resize(2*s.num_vars(), false);
|
||||
if (c1.was_removed())
|
||||
return false;
|
||||
if (c2.was_removed())
|
||||
return false;
|
||||
SASSERT(c1.contains(l));
|
||||
SASSERT(c2.contains(~l));
|
||||
bool res = true;
|
||||
|
@ -1973,7 +1978,14 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
}
|
||||
TRACE("sat_simplifier", tout << "eliminate " << v << ", before: " << before_clauses << " after: " << after_clauses << "\n";);
|
||||
TRACE("sat_simplifier", tout << "eliminate " << v << ", before: " << before_clauses << " after: " << after_clauses << "\n";
|
||||
tout << "pos\n";
|
||||
for (auto & c : m_pos_cls)
|
||||
tout << c << "\n";
|
||||
tout << "neg\n";
|
||||
for (auto & c : m_neg_cls)
|
||||
tout << c << "\n";
|
||||
);
|
||||
m_elim_counter -= num_pos * num_neg + before_lits;
|
||||
|
||||
m_elim_counter -= num_pos * num_neg + before_lits;
|
||||
|
@ -1988,6 +2000,8 @@ namespace sat {
|
|||
m_elim_counter -= num_pos * num_neg + before_lits;
|
||||
|
||||
for (auto & c1 : m_pos_cls) {
|
||||
if (c1.was_removed())
|
||||
continue;
|
||||
for (auto & c2 : m_neg_cls) {
|
||||
m_new_cls.reset();
|
||||
if (!resolve(c1, c2, pos_l, m_new_cls))
|
||||
|
|
|
@ -69,23 +69,23 @@ namespace arith {
|
|||
m_nla->push();
|
||||
}
|
||||
smt_params_helper prms(s().params());
|
||||
m_nla->settings().run_order() = prms.arith_nl_order();
|
||||
m_nla->settings().run_tangents() = prms.arith_nl_tangents();
|
||||
m_nla->settings().run_horner() = prms.arith_nl_horner();
|
||||
m_nla->settings().horner_subs_fixed() = prms.arith_nl_horner_subs_fixed();
|
||||
m_nla->settings().horner_frequency() = prms.arith_nl_horner_frequency();
|
||||
m_nla->settings().horner_row_length_limit() = prms.arith_nl_horner_row_length_limit();
|
||||
m_nla->settings().run_grobner() = prms.arith_nl_grobner();
|
||||
m_nla->settings().run_nra() = prms.arith_nl_nra();
|
||||
m_nla->settings().grobner_subs_fixed() = prms.arith_nl_grobner_subs_fixed();
|
||||
m_nla->settings().grobner_eqs_growth() = prms.arith_nl_grobner_eqs_growth();
|
||||
m_nla->settings().grobner_expr_size_growth() = prms.arith_nl_grobner_expr_size_growth();
|
||||
m_nla->settings().grobner_expr_degree_growth() = prms.arith_nl_grobner_expr_degree_growth();
|
||||
m_nla->settings().grobner_max_simplified() = prms.arith_nl_grobner_max_simplified();
|
||||
m_nla->settings().grobner_number_of_conflicts_to_report() = prms.arith_nl_grobner_cnfl_to_report();
|
||||
m_nla->settings().grobner_quota() = prms.arith_nl_gr_q();
|
||||
m_nla->settings().grobner_frequency() = prms.arith_nl_grobner_frequency();
|
||||
m_nla->settings().expensive_patching() = false;
|
||||
m_nla->settings().run_order = prms.arith_nl_order();
|
||||
m_nla->settings().run_tangents = prms.arith_nl_tangents();
|
||||
m_nla->settings().run_horner = prms.arith_nl_horner();
|
||||
m_nla->settings().horner_subs_fixed = prms.arith_nl_horner_subs_fixed();
|
||||
m_nla->settings().horner_frequency = prms.arith_nl_horner_frequency();
|
||||
m_nla->settings().horner_row_length_limit = prms.arith_nl_horner_row_length_limit();
|
||||
m_nla->settings().run_grobner = prms.arith_nl_grobner();
|
||||
m_nla->settings().run_nra = prms.arith_nl_nra();
|
||||
m_nla->settings().grobner_subs_fixed = prms.arith_nl_grobner_subs_fixed();
|
||||
m_nla->settings().grobner_eqs_growth = prms.arith_nl_grobner_eqs_growth();
|
||||
m_nla->settings().grobner_expr_size_growth = prms.arith_nl_grobner_expr_size_growth();
|
||||
m_nla->settings().grobner_expr_degree_growth = prms.arith_nl_grobner_expr_degree_growth();
|
||||
m_nla->settings().grobner_max_simplified = prms.arith_nl_grobner_max_simplified();
|
||||
m_nla->settings().grobner_number_of_conflicts_to_report = prms.arith_nl_grobner_cnfl_to_report();
|
||||
m_nla->settings().grobner_quota = prms.arith_nl_gr_q();
|
||||
m_nla->settings().grobner_frequency = prms.arith_nl_grobner_frequency();
|
||||
m_nla->settings().expensive_patching = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -442,6 +442,7 @@ namespace bv {
|
|||
SASSERT(bv.is_int2bv(n));
|
||||
euf::enode* e = expr2enode(n);
|
||||
mk_bits(e->get_th_var(get_id()));
|
||||
get_var(e->get_arg(0));
|
||||
assert_int2bv_axiom(n);
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,22 @@ namespace bv {
|
|||
if (is_bv(eq.v1())) {
|
||||
m_find.merge(eq.v1(), eq.v2());
|
||||
VERIFY(eq.is_eq());
|
||||
return;
|
||||
}
|
||||
euf::enode* n1 = var2enode(eq.v1());
|
||||
for (euf::enode* bv2int : euf::enode_class(n1)) {
|
||||
if (!bv.is_bv2int(bv2int->get_expr()))
|
||||
continue;
|
||||
euf::enode* bv2int_arg = bv2int->get_arg(0);
|
||||
for (euf::enode* p : euf::enode_parents(n1->get_root())) {
|
||||
if (bv.is_int2bv(p->get_expr()) && p->get_sort() == bv2int_arg->get_sort() && p->get_root() != bv2int_arg->get_root()) {
|
||||
euf::enode_pair_vector eqs;
|
||||
eqs.push_back({ n1, p->get_arg(0) });
|
||||
eqs.push_back({ n1, bv2int });
|
||||
ctx.propagate(p, bv2int_arg, euf::th_explain::propagate(*this, eqs, p, bv2int_arg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -506,7 +506,7 @@ namespace dt {
|
|||
return m_nodes;
|
||||
}
|
||||
|
||||
ptr_vector<euf::enode> const& solver::get_seq_args(enode* n) {
|
||||
ptr_vector<euf::enode> const& solver::get_seq_args(enode* n, enode*& sibling) {
|
||||
m_nodes.reset();
|
||||
m_todo.reset();
|
||||
auto add_todo = [&](enode* n) {
|
||||
|
@ -515,9 +515,15 @@ namespace dt {
|
|||
m_todo.push_back(n);
|
||||
}
|
||||
};
|
||||
|
||||
for (enode* sib : euf::enode_class(n))
|
||||
add_todo(sib);
|
||||
|
||||
for (enode* sib : euf::enode_class(n)) {
|
||||
if (m_sutil.str.is_concat_of_units(sib->get_expr())) {
|
||||
add_todo(sib);
|
||||
sibling = sib;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (unsigned i = 0; i < m_todo.size(); ++i) {
|
||||
enode* n = m_todo[i];
|
||||
|
@ -551,10 +557,10 @@ namespace dt {
|
|||
|
||||
// collect equalities on all children that may have been used.
|
||||
bool found = false;
|
||||
auto add = [&](enode* arg) {
|
||||
if (arg->get_root() == child->get_root()) {
|
||||
if (arg != child)
|
||||
m_used_eqs.push_back(enode_pair(arg, child));
|
||||
auto add = [&](enode* seq_arg) {
|
||||
if (seq_arg->get_root() == child->get_root()) {
|
||||
if (seq_arg != child)
|
||||
m_used_eqs.push_back(enode_pair(seq_arg, child));
|
||||
found = true;
|
||||
}
|
||||
};
|
||||
|
@ -564,11 +570,14 @@ namespace dt {
|
|||
if (m_autil.is_array(s) && dt.is_datatype(get_array_range(s)))
|
||||
for (enode* aarg : get_array_args(arg))
|
||||
add(aarg);
|
||||
}
|
||||
sort* se;
|
||||
if (m_sutil.is_seq(child->get_sort(), se) && dt.is_datatype(se)) {
|
||||
for (enode* aarg : get_seq_args(child))
|
||||
add(aarg);
|
||||
sort* se;
|
||||
if (m_sutil.is_seq(arg->get_sort(), se) && dt.is_datatype(se)) {
|
||||
enode* sibling = nullptr;
|
||||
for (enode* seq_arg : get_seq_args(arg, sibling))
|
||||
add(seq_arg);
|
||||
if (sibling && sibling != arg)
|
||||
m_used_eqs.push_back(enode_pair(arg, sibling));
|
||||
}
|
||||
}
|
||||
|
||||
VERIFY(found);
|
||||
|
@ -636,12 +645,13 @@ namespace dt {
|
|||
// explore `arg` (with parent)
|
||||
expr* earg = arg->get_expr();
|
||||
sort* s = earg->get_sort(), *se;
|
||||
enode* sibling;
|
||||
if (dt.is_datatype(s)) {
|
||||
m_parent.insert(arg->get_root(), parent);
|
||||
oc_push_stack(arg);
|
||||
}
|
||||
else if (m_sutil.is_seq(s, se) && dt.is_datatype(se)) {
|
||||
for (enode* sarg : get_seq_args(arg))
|
||||
for (enode* sarg : get_seq_args(arg, sibling))
|
||||
if (process_arg(sarg))
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ namespace dt {
|
|||
void oc_push_stack(enode * n);
|
||||
ptr_vector<enode> m_nodes, m_todo;
|
||||
ptr_vector<enode> const& get_array_args(enode* n);
|
||||
ptr_vector<enode> const& get_seq_args(enode* n);
|
||||
ptr_vector<enode> const& get_seq_args(enode* n, enode*& sibling);
|
||||
|
||||
void pop_core(unsigned n) override;
|
||||
|
||||
|
|
|
@ -1795,9 +1795,9 @@ namespace pb {
|
|||
}
|
||||
if (c.lit() != sat::null_literal && value(c.lit()) != l_true) return true;
|
||||
SASSERT(c.lit() == sat::null_literal || lvl(c.lit()) == 0 || (c.is_watched(*this, c.lit()) && c.is_watched(*this, ~c.lit())));
|
||||
if (eval(c) == l_true) {
|
||||
if (eval(c) == l_true)
|
||||
return true;
|
||||
}
|
||||
|
||||
literal_vector lits(c.literals());
|
||||
for (literal l : lits) {
|
||||
if (lvl(l) == 0) continue;
|
||||
|
@ -1823,6 +1823,8 @@ namespace pb {
|
|||
}
|
||||
|
||||
bool solver::validate_watch(pbc const& p, literal alit) const {
|
||||
if (value(p.lit()) != l_true)
|
||||
return true;
|
||||
for (unsigned i = 0; i < p.size(); ++i) {
|
||||
literal l = p[i].second;
|
||||
if (l != alit && lvl(l) != 0 && p.is_watched(*this, l) != (i < p.num_watch())) {
|
||||
|
@ -1833,9 +1835,8 @@ namespace pb {
|
|||
}
|
||||
}
|
||||
unsigned slack = 0;
|
||||
for (unsigned i = 0; i < p.num_watch(); ++i) {
|
||||
slack += p[i].first;
|
||||
}
|
||||
for (unsigned i = 0; i < p.num_watch(); ++i)
|
||||
slack += p[i].first;
|
||||
if (slack != p.slack()) {
|
||||
IF_VERBOSE(0, display(verbose_stream(), p, true););
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -270,6 +270,10 @@ namespace euf {
|
|||
return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), sat::null_literal, x, y, pma);
|
||||
}
|
||||
|
||||
th_explain* th_explain::propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, sat::proof_hint const* pma) {
|
||||
return mk(th, 0, nullptr, eqs.size(), eqs.data(), sat::null_literal, x, y, pma);
|
||||
}
|
||||
|
||||
th_explain* th_explain::propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y) {
|
||||
return mk(th, 1, &lit, 0, nullptr, sat::null_literal, x, y);
|
||||
}
|
||||
|
|
|
@ -241,6 +241,7 @@ namespace euf {
|
|||
static th_explain* conflict(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y);
|
||||
static th_explain* conflict(th_euf_solver& th, euf::enode* x, euf::enode* y);
|
||||
static th_explain* propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y);
|
||||
static th_explain* propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, sat::proof_hint const* pma = nullptr);
|
||||
static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, sat::proof_hint const* pma = nullptr);
|
||||
static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, sat::proof_hint const* pma = nullptr);
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ def_module_params(module_name='smt',
|
|||
('arith.nl.grobner_max_simplified', UINT, 10000, 'grobner\'s maximum number of simplifications'),
|
||||
('arith.nl.grobner_cnfl_to_report', UINT, 1, 'grobner\'s maximum number of conflicts to report'),
|
||||
('arith.nl.gr_q', UINT, 10, 'grobner\'s quota'),
|
||||
('arith.nl.grobner_subs_fixed', UINT, 2, '0 - no subs, 1 - substitute, 2 - substitute fixed zeros only'),
|
||||
('arith.nl.grobner_subs_fixed', UINT, 1, '0 - no subs, 1 - substitute, 2 - substitute fixed zeros only'),
|
||||
('arith.nl.delay', UINT, 500, 'number of calls to final check before invoking bounded nlsat check'),
|
||||
('arith.propagate_eqs', BOOL, True, 'propagate (cheap) equalities'),
|
||||
('arith.propagation_mode', UINT, 1, '0 - no propagation, 1 - propagate existing literals, 2 - refine finite bounds'),
|
||||
|
|
|
@ -1429,7 +1429,10 @@ namespace smt {
|
|||
inc_ref(l2);
|
||||
m_watches[(~l1).index()].insert_literal(l2);
|
||||
m_watches[(~l2).index()].insert_literal(l1);
|
||||
if (get_assignment(l2) == l_false) {
|
||||
if (get_assignment(l1) == l_false) {
|
||||
assign(l2, b_justification(~l1));
|
||||
}
|
||||
else if (get_assignment(l2) == l_false) {
|
||||
assign(l1, b_justification(~l2));
|
||||
}
|
||||
m_clause_proof.add(l1, l2, k, j);
|
||||
|
|
|
@ -258,7 +258,7 @@ namespace smt {
|
|||
bindings.set(num_decls - i - 1, sk_value);
|
||||
}
|
||||
|
||||
TRACE("model_checker", tout << q->get_qid() << " found (use_inv: " << use_inv << ") new instance: " << bindings << "\n" << defs << "\n";);
|
||||
TRACE("model_checker", tout << q->get_qid() << " found (use_inv: " << use_inv << ") new instance: " << bindings << "\ndefs:\n" << defs << "\n";);
|
||||
if (!defs.empty()) def = mk_and(defs);
|
||||
max_generation = std::max(m_qm->get_generation(q), max_generation);
|
||||
add_instance(q, bindings, max_generation, def.get());
|
||||
|
@ -453,7 +453,7 @@ namespace smt {
|
|||
TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";);
|
||||
m_max_cexs += m_params.m_mbqi_max_cexs;
|
||||
|
||||
if (num_failures == 0 && (!m_context->validate_model())) {
|
||||
if (num_failures == 0 && !m_context->validate_model()) {
|
||||
num_failures = 1;
|
||||
// this time force expanding recursive function definitions
|
||||
// that are not forced true in the current model.
|
||||
|
|
|
@ -348,6 +348,7 @@ public:
|
|||
m_eq_eh = nullptr;
|
||||
m_diseq_eh = nullptr;
|
||||
m_created_eh = nullptr;
|
||||
m_decide_eh = nullptr;
|
||||
}
|
||||
|
||||
void user_propagate_init(
|
||||
|
@ -385,6 +386,10 @@ public:
|
|||
void user_propagate_register_created(user_propagator::created_eh_t& created_eh) override {
|
||||
m_created_eh = created_eh;
|
||||
}
|
||||
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t& decide_eh) override {
|
||||
m_decide_eh = decide_eh;
|
||||
}
|
||||
};
|
||||
|
||||
static tactic * mk_seq_smt_tactic(ast_manager& m, params_ref const & p) {
|
||||
|
|
|
@ -492,6 +492,7 @@ namespace smt {
|
|||
void theory_arith<Ext>::mk_axiom(expr * ante, expr * conseq, bool simplify_conseq) {
|
||||
th_rewriter & s = ctx.get_rewriter();
|
||||
expr_ref s_ante(m), s_conseq(m);
|
||||
expr_ref p_ante(ante, m), p_conseq(conseq, m); // pinned versions
|
||||
expr* s_conseq_n, * s_ante_n;
|
||||
bool negated;
|
||||
|
||||
|
@ -562,7 +563,7 @@ namespace smt {
|
|||
if (!m_util.is_zero(divisor)) {
|
||||
// if divisor is zero, then idiv and mod are uninterpreted functions.
|
||||
expr_ref div(m), mod(m), zero(m), abs_divisor(m), one(m);
|
||||
expr_ref eqz(m), eq(m), lower(m), upper(m);
|
||||
expr_ref eqz(m), eq(m), lower(m), upper(m), qr(m);
|
||||
div = m_util.mk_idiv(dividend, divisor);
|
||||
mod = m_util.mk_mod(dividend, divisor);
|
||||
zero = m_util.mk_int(0);
|
||||
|
@ -570,7 +571,8 @@ namespace smt {
|
|||
abs_divisor = m_util.mk_sub(m.mk_ite(m_util.mk_lt(divisor, zero), m_util.mk_sub(zero, divisor), divisor), one);
|
||||
s(abs_divisor);
|
||||
eqz = m.mk_eq(divisor, zero);
|
||||
eq = m.mk_eq(m_util.mk_add(m_util.mk_mul(divisor, div), mod), dividend);
|
||||
qr = m_util.mk_add(m_util.mk_mul(divisor, div), mod);
|
||||
eq = m.mk_eq(qr, dividend);
|
||||
lower = m_util.mk_ge(mod, zero);
|
||||
upper = m_util.mk_le(mod, abs_divisor);
|
||||
TRACE("div_axiom_bug",
|
||||
|
@ -584,6 +586,8 @@ namespace smt {
|
|||
mk_axiom(eqz, upper, !m_util.is_numeral(abs_divisor));
|
||||
rational k;
|
||||
|
||||
m_arith_eq_adapter.mk_axioms(ensure_enode(qr), ensure_enode(mod));
|
||||
|
||||
if (m_util.is_zero(dividend)) {
|
||||
mk_axiom(eqz, m.mk_eq(div, zero));
|
||||
mk_axiom(eqz, m.mk_eq(mod, zero));
|
||||
|
@ -591,7 +595,7 @@ namespace smt {
|
|||
|
||||
// (or (= y 0) (<= (* y (div x y)) x))
|
||||
else if (!m_util.is_numeral(divisor)) {
|
||||
expr_ref div_ge(m), div_le(m), ge(m), le(m);
|
||||
expr_ref div_ge(m);
|
||||
div_ge = m_util.mk_ge(m_util.mk_sub(dividend, m_util.mk_mul(divisor, div)), zero);
|
||||
s(div_ge);
|
||||
mk_axiom(eqz, div_ge, false);
|
||||
|
|
|
@ -80,14 +80,12 @@ void theory_arith<Ext>::mark_dependents(theory_var v, svector<theory_var> & vars
|
|||
if (is_fixed(v))
|
||||
return;
|
||||
column & c = m_columns[v];
|
||||
typename svector<col_entry>::iterator it = c.begin_entries();
|
||||
typename svector<col_entry>::iterator end = c.end_entries();
|
||||
for (; it != end; ++it) {
|
||||
if (it->is_dead() || already_visited_rows.contains(it->m_row_id))
|
||||
for (auto& ce : c) {
|
||||
if (ce.is_dead() || already_visited_rows.contains(ce.m_row_id))
|
||||
continue;
|
||||
TRACE("non_linear_bug", tout << "visiting row: " << it->m_row_id << "\n";);
|
||||
already_visited_rows.insert(it->m_row_id);
|
||||
row & r = m_rows[it->m_row_id];
|
||||
TRACE("non_linear_bug", tout << "visiting row: " << ce.m_row_id << "\n";);
|
||||
already_visited_rows.insert(ce.m_row_id);
|
||||
row & r = m_rows[ce.m_row_id];
|
||||
theory_var s = r.get_base_var();
|
||||
// ignore quasi base vars... actually they should not be used if the problem is non linear...
|
||||
if (is_quasi_base(s))
|
||||
|
@ -97,14 +95,10 @@ void theory_arith<Ext>::mark_dependents(theory_var v, svector<theory_var> & vars
|
|||
// was eliminated by substitution.
|
||||
if (s != null_theory_var && is_free(s) && s != v)
|
||||
continue;
|
||||
typename vector<row_entry>::const_iterator it2 = r.begin_entries();
|
||||
typename vector<row_entry>::const_iterator end2 = r.end_entries();
|
||||
for (; it2 != end2; ++it2) {
|
||||
if (!it2->is_dead() && !is_fixed(it2->m_var))
|
||||
mark_var(it2->m_var, vars, already_found);
|
||||
if (!it2->is_dead() && is_fixed(it2->m_var)) {
|
||||
TRACE("non_linear", tout << "skipped fixed\n";);
|
||||
}
|
||||
for (auto& re : r) {
|
||||
if (!re.is_dead() && !is_fixed(re.m_var))
|
||||
mark_var(re.m_var, vars, already_found);
|
||||
CTRACE("non_linear", !re.is_dead() && is_fixed(re.m_var), tout << "skipped fixed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +113,7 @@ void theory_arith<Ext>::get_non_linear_cluster(svector<theory_var> & vars) {
|
|||
return;
|
||||
var_set already_found;
|
||||
row_set already_visited_rows;
|
||||
|
||||
for (theory_var v : m_nl_monomials) {
|
||||
expr * n = var2expr(v);
|
||||
if (ctx.is_relevant(n))
|
||||
|
@ -130,9 +125,9 @@ void theory_arith<Ext>::get_non_linear_cluster(svector<theory_var> & vars) {
|
|||
TRACE("non_linear", tout << "marking dependents of: v" << v << "\n";);
|
||||
mark_dependents(v, vars, already_found, already_visited_rows);
|
||||
}
|
||||
TRACE("non_linear", tout << "variables in non linear cluster:\n";
|
||||
for (theory_var v : vars) tout << "v" << v << " ";
|
||||
tout << "\n";);
|
||||
TRACE("non_linear", tout << "variables in non linear cluster: ";
|
||||
for (theory_var v : vars) tout << "v" << v << " "; tout << "\n";
|
||||
for (theory_var v : m_nl_monomials) tout << "non-linear v" << v << " " << mk_pp(var2expr(v), m) << "\n";);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1740,22 +1735,21 @@ grobner::monomial * theory_arith<Ext>::mk_gb_monomial(rational const & _coeff, e
|
|||
*/
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::add_row_to_gb(row const & r, grobner & gb) {
|
||||
TRACE("non_linear", tout << "adding row to gb\n"; display_row(tout, r););
|
||||
TRACE("grobner", tout << "adding row to gb\n"; display_row(tout, r););
|
||||
ptr_buffer<grobner::monomial> monomials;
|
||||
v_dependency * dep = nullptr;
|
||||
m_tmp_var_set.reset();
|
||||
typename vector<row_entry>::const_iterator it = r.begin_entries();
|
||||
typename vector<row_entry>::const_iterator end = r.end_entries();
|
||||
for (; it != end; ++it) {
|
||||
if (!it->is_dead()) {
|
||||
rational coeff = it->m_coeff.to_rational();
|
||||
expr * m = var2expr(it->m_var);
|
||||
TRACE("non_linear", tout << "monomial: " << mk_pp(m, get_manager()) << "\n";);
|
||||
grobner::monomial * new_m = mk_gb_monomial(coeff, m, gb, dep, m_tmp_var_set);
|
||||
TRACE("non_linear", tout << "new monomial:\n"; if (new_m) gb.display_monomial(tout, *new_m); else tout << "null"; tout << "\n";);
|
||||
if (new_m)
|
||||
monomials.push_back(new_m);
|
||||
}
|
||||
for (auto& re : r) {
|
||||
if (re.is_dead())
|
||||
continue;
|
||||
rational coeff = re.m_coeff.to_rational();
|
||||
expr * m = var2expr(re.m_var);
|
||||
grobner::monomial * new_m = mk_gb_monomial(coeff, m, gb, dep, m_tmp_var_set);
|
||||
if (new_m)
|
||||
monomials.push_back(new_m);
|
||||
TRACE("grobner",
|
||||
tout << "monomial: " << mk_pp(m, get_manager()) << "\n";
|
||||
tout << "new monomial: "; if (new_m) gb.display_monomial(tout, *new_m); else tout << "null"; tout << "\n";);
|
||||
}
|
||||
gb.assert_eq_0(monomials.size(), monomials.data(), dep);
|
||||
}
|
||||
|
@ -2158,8 +2152,9 @@ bool theory_arith<Ext>::get_gb_eqs_and_look_for_conflict(ptr_vector<grobner::equ
|
|||
eqs.reset();
|
||||
gb.get_equations(eqs);
|
||||
TRACE("grobner", tout << "after gb\n";
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { out << "v" << expr2var(v); };
|
||||
for (grobner::equation* eq : eqs)
|
||||
gb.display_equation(tout, *eq);
|
||||
gb.display_equation(tout, *eq, _fn);
|
||||
);
|
||||
for (grobner::equation* eq : eqs) {
|
||||
if (is_inconsistent(eq, gb) || is_inconsistent2(eq, gb)) {
|
||||
|
@ -2259,7 +2254,9 @@ typename theory_arith<Ext>::gb_result theory_arith<Ext>::compute_grobner(svector
|
|||
ptr_vector<grobner::equation> eqs;
|
||||
|
||||
do {
|
||||
TRACE("non_linear_gb", tout << "before:\n"; gb.display(tout););
|
||||
TRACE("grobner", tout << "before grobner:\n";
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { out << "v" << expr2var(v); };
|
||||
gb.display(tout, _fn));
|
||||
compute_basis(gb, warn);
|
||||
update_statistics(gb);
|
||||
TRACE("non_linear_gb", tout << "after:\n"; gb.display(tout););
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace smt {
|
|||
SASSERT(num_args >= 3);
|
||||
sel_args.push_back(n);
|
||||
for (unsigned i = 1; i < num_args - 1; ++i) {
|
||||
sel_args.push_back(to_app(n->get_arg(i)));
|
||||
sel_args.push_back(n->get_arg(i));
|
||||
}
|
||||
expr_ref sel(m);
|
||||
sel = mk_select(sel_args.size(), sel_args.data());
|
||||
|
|
|
@ -594,10 +594,13 @@ namespace smt {
|
|||
if (!ctx.add_fingerprint(this, m_default_lambda_fingerprint, 1, &arr))
|
||||
return false;
|
||||
m_stats.m_num_default_lambda_axiom++;
|
||||
expr* def = mk_default(arr->get_expr());
|
||||
expr* e = arr->get_expr();
|
||||
expr* def = mk_default(e);
|
||||
quantifier* lam = m.is_lambda_def(arr->get_decl());
|
||||
expr_ref_vector args(m);
|
||||
args.push_back(lam);
|
||||
TRACE("array", tout << mk_pp(lam, m) << "\n" << mk_pp(e, m) << "\n");
|
||||
expr_ref_vector args(m);
|
||||
var_subst subst(m, false);
|
||||
args.push_back(subst(lam, to_app(e)->get_num_args(), to_app(e)->get_args()));
|
||||
for (unsigned i = 0; i < lam->get_num_decls(); ++i)
|
||||
args.push_back(mk_epsilon(lam->get_decl_sort(i)).first);
|
||||
expr_ref val(mk_select(args), m);
|
||||
|
|
|
@ -52,9 +52,8 @@ namespace smt {
|
|||
bits.reset();
|
||||
m_bits_expr.reset();
|
||||
|
||||
for (unsigned i = 0; i < bv_size; i++) {
|
||||
for (unsigned i = 0; i < bv_size; i++)
|
||||
m_bits_expr.push_back(mk_bit2bool(owner, i));
|
||||
}
|
||||
ctx.internalize(m_bits_expr.data(), bv_size, true);
|
||||
|
||||
for (unsigned i = 0; i < bv_size; i++) {
|
||||
|
@ -601,9 +600,8 @@ namespace smt {
|
|||
TRACE("bv", tout << mk_bounded_pp(n, m) << "\n";);
|
||||
process_args(n);
|
||||
mk_enode(n);
|
||||
if (!ctx.relevancy()) {
|
||||
if (!ctx.relevancy())
|
||||
assert_bv2int_axiom(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -669,10 +667,12 @@ namespace smt {
|
|||
mk_enode(n);
|
||||
theory_var v = ctx.get_enode(n)->get_th_var(get_id());
|
||||
mk_bits(v);
|
||||
|
||||
if (!ctx.relevancy()) {
|
||||
enode* k = ctx.get_enode(n->get_arg(0));
|
||||
if (!is_attached_to_var(k))
|
||||
mk_var(k);
|
||||
|
||||
if (!ctx.relevancy())
|
||||
assert_int2bv_axiom(n);
|
||||
}
|
||||
}
|
||||
|
||||
void theory_bv::assert_int2bv_axiom(app* n) {
|
||||
|
@ -1497,6 +1497,26 @@ namespace smt {
|
|||
unsigned sz = m_bits[v1].size();
|
||||
bool changed = true;
|
||||
TRACE("bv", tout << "bits size: " << sz << "\n";);
|
||||
if (sz == 0) {
|
||||
// int2bv(bv2int(x)) = x when int2bv(bv2int(x)) has same sort as x
|
||||
enode* n1 = get_enode(r1);
|
||||
for (enode* bv2int : *n1) {
|
||||
if (!m_util.is_bv2int(bv2int->get_expr()))
|
||||
continue;
|
||||
enode* bv2int_arg = bv2int->get_arg(0);
|
||||
for (enode* p : enode::parents(n1->get_root())) {
|
||||
if (m_util.is_int2bv(p->get_expr()) && p->get_root() != bv2int_arg->get_root() && p->get_sort() == bv2int_arg->get_sort()) {
|
||||
enode_pair_vector eqs;
|
||||
eqs.push_back({n1, p->get_arg(0) });
|
||||
eqs.push_back({n1, bv2int});
|
||||
justification * js = ctx.mk_justification(
|
||||
ext_theory_eq_propagation_justification(get_id(), ctx.get_region(), 0, nullptr, eqs.size(), eqs.data(), p, bv2int_arg));
|
||||
ctx.assign_eq(p, bv2int_arg, eq_justification(js));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
do {
|
||||
// This outerloop is necessary to avoid missing propagation steps.
|
||||
// For example, let's assume that bits1 and bits2 contains the following
|
||||
|
|
|
@ -25,6 +25,7 @@ Revision History:
|
|||
#include "smt/theory_datatype.h"
|
||||
#include "smt/theory_array.h"
|
||||
#include "smt/smt_model_generator.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
@ -519,9 +520,8 @@ namespace smt {
|
|||
|
||||
void theory_datatype::explain_is_child(enode* parent, enode* child) {
|
||||
enode * parentc = oc_get_cstor(parent);
|
||||
if (parent != parentc) {
|
||||
if (parent != parentc)
|
||||
m_used_eqs.push_back(enode_pair(parent, parentc));
|
||||
}
|
||||
|
||||
// collect equalities on all children that may have been used.
|
||||
bool found = false;
|
||||
|
@ -546,14 +546,17 @@ namespace smt {
|
|||
}
|
||||
sort* se = nullptr;
|
||||
if (m_sutil.is_seq(s, se) && m_util.is_datatype(se)) {
|
||||
for (enode* aarg : get_seq_args(arg)) {
|
||||
enode* sibling;
|
||||
for (enode* aarg : get_seq_args(arg, sibling)) {
|
||||
if (aarg->get_root() == child->get_root()) {
|
||||
if (aarg != child) {
|
||||
if (aarg != child)
|
||||
m_used_eqs.push_back(enode_pair(aarg, child));
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (sibling && sibling != arg)
|
||||
m_used_eqs.push_back(enode_pair(arg, sibling));
|
||||
|
||||
}
|
||||
}
|
||||
VERIFY(found);
|
||||
|
@ -582,9 +585,11 @@ namespace smt {
|
|||
|
||||
TRACE("datatype",
|
||||
tout << "occurs_check\n";
|
||||
for (enode_pair const& p : m_used_eqs) {
|
||||
for (enode_pair const& p : m_used_eqs)
|
||||
tout << enode_eq_pp(p, ctx);
|
||||
});
|
||||
for (auto const& [a,b] : m_used_eqs)
|
||||
tout << mk_pp(a->get_expr(), m) << " = " << mk_pp(b->get_expr(), m) << "\n";
|
||||
);
|
||||
}
|
||||
|
||||
// start exploring subgraph below `app`
|
||||
|
@ -596,9 +601,9 @@ namespace smt {
|
|||
}
|
||||
v = m_find.find(v);
|
||||
var_data * d = m_var_data[v];
|
||||
if (!d->m_constructor) {
|
||||
|
||||
if (!d->m_constructor)
|
||||
return false;
|
||||
}
|
||||
enode * parent = d->m_constructor;
|
||||
oc_mark_on_stack(parent);
|
||||
auto process_arg = [&](enode* aarg) {
|
||||
|
@ -616,9 +621,8 @@ namespace smt {
|
|||
};
|
||||
|
||||
for (enode * arg : enode::args(parent)) {
|
||||
if (oc_cycle_free(arg)) {
|
||||
if (oc_cycle_free(arg))
|
||||
continue;
|
||||
}
|
||||
if (oc_on_stack(arg)) {
|
||||
// arg was explored before app, and is still on the stack: cycle
|
||||
occurs_check_explain(parent, arg);
|
||||
|
@ -632,9 +636,11 @@ namespace smt {
|
|||
oc_push_stack(arg);
|
||||
}
|
||||
else if (m_sutil.is_seq(s, se) && m_util.is_datatype(se)) {
|
||||
for (enode* sarg : get_seq_args(arg))
|
||||
if (process_arg(sarg))
|
||||
enode* sibling;
|
||||
for (enode* sarg : get_seq_args(arg, sibling)) {
|
||||
if (process_arg(sarg))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (m_autil.is_array(s) && m_util.is_datatype(get_array_range(s))) {
|
||||
for (enode* aarg : get_array_args(arg))
|
||||
|
@ -645,7 +651,7 @@ namespace smt {
|
|||
return false;
|
||||
}
|
||||
|
||||
ptr_vector<enode> const& theory_datatype::get_seq_args(enode* n) {
|
||||
ptr_vector<enode> const& theory_datatype::get_seq_args(enode* n, enode*& sibling) {
|
||||
m_args.reset();
|
||||
m_todo.reset();
|
||||
auto add_todo = [&](enode* n) {
|
||||
|
@ -654,9 +660,14 @@ namespace smt {
|
|||
m_todo.push_back(n);
|
||||
}
|
||||
};
|
||||
|
||||
for (enode* sib : *n)
|
||||
add_todo(sib);
|
||||
|
||||
for (enode* sib : *n) {
|
||||
if (m_sutil.str.is_concat_of_units(sib->get_expr())) {
|
||||
add_todo(sib);
|
||||
sibling = sib;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m_todo.size(); ++i) {
|
||||
enode* n = m_todo[i];
|
||||
|
@ -691,7 +702,7 @@ namespace smt {
|
|||
a3 = cons(v3, a1)
|
||||
*/
|
||||
bool theory_datatype::occurs_check(enode * n) {
|
||||
TRACE("datatype", tout << "occurs check: " << enode_pp(n, ctx) << "\n";);
|
||||
TRACE("datatype_verbose", tout << "occurs check: " << enode_pp(n, ctx) << "\n";);
|
||||
m_stats.m_occurs_check++;
|
||||
|
||||
bool res = false;
|
||||
|
@ -706,7 +717,7 @@ namespace smt {
|
|||
if (oc_cycle_free(app))
|
||||
continue;
|
||||
|
||||
TRACE("datatype", tout << "occurs check loop: " << enode_pp(app, ctx) << (op==ENTER?" enter":" exit")<< "\n";);
|
||||
TRACE("datatype_verbose", tout << "occurs check loop: " << enode_pp(app, ctx) << (op==ENTER?" enter":" exit")<< "\n";);
|
||||
|
||||
switch (op) {
|
||||
case ENTER:
|
||||
|
@ -830,15 +841,14 @@ namespace smt {
|
|||
SASSERT(d->m_constructor);
|
||||
func_decl * c_decl = d->m_constructor->get_decl();
|
||||
datatype_value_proc * result = alloc(datatype_value_proc, c_decl);
|
||||
for (enode* arg : enode::args(d->m_constructor)) {
|
||||
for (enode* arg : enode::args(d->m_constructor))
|
||||
result->add_dependency(arg);
|
||||
}
|
||||
TRACE("datatype",
|
||||
tout << pp(n, m) << "\n";
|
||||
tout << "depends on\n";
|
||||
for (enode* arg : enode::args(d->m_constructor)) {
|
||||
for (enode* arg : enode::args(d->m_constructor))
|
||||
tout << " " << pp(arg, m) << "\n";
|
||||
});
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -965,12 +975,11 @@ namespace smt {
|
|||
SASSERT(!lits.empty());
|
||||
region & reg = ctx.get_region();
|
||||
TRACE("datatype_conflict", tout << mk_ismt2_pp(recognizer->get_expr(), m) << "\n";
|
||||
for (literal l : lits) {
|
||||
for (literal l : lits)
|
||||
ctx.display_detailed_literal(tout, l) << "\n";
|
||||
}
|
||||
for (auto const& p : eqs) {
|
||||
for (auto const& p : eqs)
|
||||
tout << enode_eq_pp(p, ctx);
|
||||
});
|
||||
);
|
||||
ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), reg, lits.size(), lits.data(), eqs.size(), eqs.data())));
|
||||
}
|
||||
else if (num_unassigned == 1) {
|
||||
|
@ -1052,9 +1061,8 @@ namespace smt {
|
|||
ctx.mark_as_relevant(curr);
|
||||
return;
|
||||
}
|
||||
else if (ctx.get_assignment(curr) != l_false) {
|
||||
else if (ctx.get_assignment(curr) != l_false)
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (r == nullptr)
|
||||
return; // all recognizers are asserted to false... conflict will be detected...
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace smt {
|
|||
void oc_push_stack(enode * n);
|
||||
ptr_vector<enode> m_args, m_todo;
|
||||
ptr_vector<enode> const& get_array_args(enode* n);
|
||||
ptr_vector<enode> const& get_seq_args(enode* n);
|
||||
ptr_vector<enode> const& get_seq_args(enode* n, enode*& sibling);
|
||||
|
||||
// class for managing state of final_check
|
||||
class final_check_st {
|
||||
|
|
|
@ -276,23 +276,23 @@ class theory_lra::imp {
|
|||
m_nla->push();
|
||||
}
|
||||
smt_params_helper prms(ctx().get_params());
|
||||
m_nla->settings().run_order() = prms.arith_nl_order();
|
||||
m_nla->settings().run_tangents() = prms.arith_nl_tangents();
|
||||
m_nla->settings().run_horner() = prms.arith_nl_horner();
|
||||
m_nla->settings().horner_subs_fixed() = prms.arith_nl_horner_subs_fixed();
|
||||
m_nla->settings().horner_frequency() = prms.arith_nl_horner_frequency();
|
||||
m_nla->settings().horner_row_length_limit() = prms.arith_nl_horner_row_length_limit();
|
||||
m_nla->settings().run_grobner() = prms.arith_nl_grobner();
|
||||
m_nla->settings().run_nra() = prms.arith_nl_nra();
|
||||
m_nla->settings().grobner_subs_fixed() = prms.arith_nl_grobner_subs_fixed();
|
||||
m_nla->settings().grobner_eqs_growth() = prms.arith_nl_grobner_eqs_growth();
|
||||
m_nla->settings().grobner_expr_size_growth() = prms.arith_nl_grobner_expr_size_growth();
|
||||
m_nla->settings().grobner_expr_degree_growth() = prms.arith_nl_grobner_expr_degree_growth();
|
||||
m_nla->settings().grobner_max_simplified() = prms.arith_nl_grobner_max_simplified();
|
||||
m_nla->settings().grobner_number_of_conflicts_to_report() = prms.arith_nl_grobner_cnfl_to_report();
|
||||
m_nla->settings().grobner_quota() = prms.arith_nl_gr_q();
|
||||
m_nla->settings().grobner_frequency() = prms.arith_nl_grobner_frequency();
|
||||
m_nla->settings().expensive_patching() = false;
|
||||
m_nla->settings().run_order = prms.arith_nl_order();
|
||||
m_nla->settings().run_tangents = prms.arith_nl_tangents();
|
||||
m_nla->settings().run_horner = prms.arith_nl_horner();
|
||||
m_nla->settings().horner_subs_fixed = prms.arith_nl_horner_subs_fixed();
|
||||
m_nla->settings().horner_frequency = prms.arith_nl_horner_frequency();
|
||||
m_nla->settings().horner_row_length_limit = prms.arith_nl_horner_row_length_limit();
|
||||
m_nla->settings().run_grobner = prms.arith_nl_grobner();
|
||||
m_nla->settings().run_nra = prms.arith_nl_nra();
|
||||
m_nla->settings().grobner_subs_fixed = prms.arith_nl_grobner_subs_fixed();
|
||||
m_nla->settings().grobner_eqs_growth = prms.arith_nl_grobner_eqs_growth();
|
||||
m_nla->settings().grobner_expr_size_growth = prms.arith_nl_grobner_expr_size_growth();
|
||||
m_nla->settings().grobner_expr_degree_growth = prms.arith_nl_grobner_expr_degree_growth();
|
||||
m_nla->settings().grobner_max_simplified = prms.arith_nl_grobner_max_simplified();
|
||||
m_nla->settings().grobner_number_of_conflicts_to_report = prms.arith_nl_grobner_cnfl_to_report();
|
||||
m_nla->settings().grobner_quota = prms.arith_nl_gr_q();
|
||||
m_nla->settings().grobner_frequency = prms.arith_nl_grobner_frequency();
|
||||
m_nla->settings().expensive_patching = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1224,9 +1224,9 @@ public:
|
|||
return;
|
||||
}
|
||||
expr_ref mod_r(a.mk_add(a.mk_mul(q, div), mod), m);
|
||||
|
||||
ctx().get_rewriter()(mod_r);
|
||||
expr_ref eq_r(th.mk_eq_atom(mod_r, p), m);
|
||||
ctx().internalize(eq_r, false);
|
||||
ctx().internalize(eq_r, false);
|
||||
literal eq = ctx().get_literal(eq_r);
|
||||
|
||||
rational k(0);
|
||||
|
@ -1256,6 +1256,39 @@ public:
|
|||
}
|
||||
else {
|
||||
|
||||
expr_ref abs_q(m.mk_ite(a.mk_ge(q, zero), q, a.mk_uminus(q)), m);
|
||||
expr_ref mone(a.mk_int(-1), m);
|
||||
expr_ref modmq(a.mk_sub(mod, abs_q), m);
|
||||
ctx().get_rewriter()(modmq);
|
||||
literal eqz = mk_literal(m.mk_eq(q, zero));
|
||||
literal mod_ge_0 = mk_literal(a.mk_ge(mod, zero));
|
||||
literal mod_lt_q = mk_literal(a.mk_le(modmq, mone));
|
||||
|
||||
// q = 0 or p = (p mod q) + q * (p div q)
|
||||
// q = 0 or (p mod q) >= 0
|
||||
// q = 0 or (p mod q) < abs(q)
|
||||
|
||||
mk_axiom(eqz, eq);
|
||||
mk_axiom(eqz, mod_ge_0);
|
||||
mk_axiom(eqz, mod_lt_q);
|
||||
m_arith_eq_adapter.mk_axioms(th.ensure_enode(mod_r), th.ensure_enode(p));
|
||||
|
||||
if (a.is_zero(p)) {
|
||||
mk_axiom(eqz, mk_literal(m.mk_eq(div, zero)));
|
||||
mk_axiom(eqz, mk_literal(m.mk_eq(mod, zero)));
|
||||
}
|
||||
// (or (= y 0) (<= (* y (div x y)) x))
|
||||
else if (!a.is_numeral(q)) {
|
||||
expr_ref div_ge(m);
|
||||
div_ge = a.mk_ge(a.mk_sub(p, a.mk_mul(q, div)), zero);
|
||||
ctx().get_rewriter()(div_ge);
|
||||
mk_axiom(eqz, mk_literal(div_ge));
|
||||
TRACE("arith", tout << eqz << " " << div_ge << "\n");
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
/*literal div_ge_0 = */ mk_literal(a.mk_ge(div, zero));
|
||||
/*literal div_le_0 = */ mk_literal(a.mk_le(div, zero));
|
||||
/*literal p_ge_0 = */ mk_literal(a.mk_ge(p, zero));
|
||||
|
@ -1266,7 +1299,7 @@ public:
|
|||
// q >= 0 or (p mod q) >= 0
|
||||
// q <= 0 or (p mod q) >= 0
|
||||
// q <= 0 or (p mod q) < q
|
||||
// q >= 0 or (p mod q) < -q
|
||||
// q >= 0 or (p mod q) < -q
|
||||
literal q_ge_0 = mk_literal(a.mk_ge(q, zero));
|
||||
literal q_le_0 = mk_literal(a.mk_le(q, zero));
|
||||
literal mod_ge_0 = mk_literal(a.mk_ge(mod, zero));
|
||||
|
@ -1277,11 +1310,11 @@ public:
|
|||
mk_axiom(q_le_0, mod_ge_0);
|
||||
mk_axiom(q_le_0, ~mk_literal(a.mk_ge(a.mk_sub(mod, q), zero)));
|
||||
mk_axiom(q_ge_0, ~mk_literal(a.mk_ge(a.mk_add(mod, q), zero)));
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// seem expensive
|
||||
|
||||
|
||||
mk_axiom(q_le_0, ~p_ge_0, div_ge_0);
|
||||
mk_axiom(q_le_0, ~p_le_0, div_le_0);
|
||||
mk_axiom(q_ge_0, ~p_ge_0, div_le_0);
|
||||
|
@ -1293,19 +1326,21 @@ public:
|
|||
mk_axiom(q_ge_0, p_le_0, ~div_ge_0);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
std::function<void(void)> log = [&,this]() {
|
||||
th.log_axiom_unit(m.mk_implies(m.mk_not(m.mk_eq(q, zero)), c.bool_var2expr(eq.var())));
|
||||
th.log_axiom_unit(m.mk_implies(m.mk_not(m.mk_eq(q, zero)), c.bool_var2expr(mod_ge_0.var())));
|
||||
th.log_axiom_unit(m.mk_implies(a.mk_lt(q, zero), a.mk_lt(a.mk_sub(mod, q), zero)));
|
||||
th.log_axiom_unit(m.mk_implies(a.mk_lt(q, zero), a.mk_lt(a.mk_add(mod, q), zero)));
|
||||
};
|
||||
if_trace_stream _ts(m, log);
|
||||
#endif
|
||||
#if 0
|
||||
th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_gt(q, zero), c.bool_var2expr(p_ge_0.var())), c.bool_var2expr(div_ge_0.var())));
|
||||
th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_gt(q, zero), c.bool_var2expr(p_le_0.var())), c.bool_var2expr(div_le_0.var())));
|
||||
th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_lt(q, zero), c.bool_var2expr(p_ge_0.var())), c.bool_var2expr(div_le_0.var())));
|
||||
th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_lt(q, zero), c.bool_var2expr(p_le_0.var())), c.bool_var2expr(div_ge_0.var())));
|
||||
#endif
|
||||
};
|
||||
if_trace_stream _ts(m, log);
|
||||
}
|
||||
if (params().m_arith_enum_const_mod && k.is_pos() && k < rational(8)) {
|
||||
unsigned _k = k.get_unsigned();
|
||||
|
|
|
@ -43,32 +43,32 @@ namespace smt {
|
|||
|
||||
char const * theory_recfun::get_name() const { return "recfun"; }
|
||||
|
||||
theory* theory_recfun::mk_fresh(context* new_ctx) {
|
||||
theory* theory_recfun::mk_fresh(context* new_ctx) {
|
||||
return alloc(theory_recfun, *new_ctx);
|
||||
}
|
||||
|
||||
bool theory_recfun::internalize_atom(app * atom, bool gate_ctx) {
|
||||
TRACE("recfun", tout << mk_pp(atom, m) << " " << u().has_defs() << "\n");
|
||||
if (!u().has_defs()) {
|
||||
// if (u().is_defined(atom))
|
||||
// throw default_exception("recursive atom definition is out of scope");
|
||||
return false;
|
||||
}
|
||||
for (expr * arg : *atom) {
|
||||
for (expr * arg : *atom)
|
||||
ctx.internalize(arg, false);
|
||||
}
|
||||
if (!ctx.e_internalized(atom)) {
|
||||
if (!ctx.e_internalized(atom))
|
||||
ctx.mk_enode(atom, false, true, true);
|
||||
}
|
||||
if (!ctx.b_internalized(atom)) {
|
||||
bool_var v = ctx.mk_bool_var(atom);
|
||||
ctx.set_var_theory(v, get_id());
|
||||
}
|
||||
if (!ctx.relevancy() && u().is_defined(atom)) {
|
||||
if (!ctx.b_internalized(atom))
|
||||
ctx.set_var_theory(ctx.mk_bool_var(atom), get_id());
|
||||
if (!ctx.relevancy() && u().is_defined(atom))
|
||||
push_case_expand(atom);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool theory_recfun::internalize_term(app * term) {
|
||||
if (!u().has_defs()) {
|
||||
// if (u().is_defined(term))
|
||||
// throw default_exception("recursive term definition is out of scope");
|
||||
return false;
|
||||
}
|
||||
for (expr* e : *term) {
|
||||
|
|
|
@ -2783,26 +2783,25 @@ bool theory_seq::get_length(expr* e, rational& val) {
|
|||
todo.push_back(e1);
|
||||
todo.push_back(e2);
|
||||
}
|
||||
else if (m_util.str.is_unit(c)) {
|
||||
else if (m_util.str.is_unit(c))
|
||||
val += rational(1);
|
||||
}
|
||||
else if (m_util.str.is_empty(c)) {
|
||||
else if (m_util.str.is_empty(c))
|
||||
continue;
|
||||
}
|
||||
else if (m_util.str.is_string(c, s)) {
|
||||
else if (m_util.str.is_map(c, e1, e2))
|
||||
todo.push_back(e2);
|
||||
else if (m_util.str.is_mapi(c, e1, e2, c))
|
||||
todo.push_back(c);
|
||||
else if (m_util.str.is_string(c, s))
|
||||
val += rational(s.length());
|
||||
}
|
||||
else if (!has_length(c)) {
|
||||
len = mk_len(c);
|
||||
add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(0))));
|
||||
TRACE("seq", tout << "literal has no length " << mk_pp(c, m) << "\n";);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
len = mk_len(c);
|
||||
if (m_arith_value.get_value(len, val1) && !val1.is_neg()) {
|
||||
val += val1;
|
||||
if (!has_length(c)) {
|
||||
add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(0))));
|
||||
TRACE("seq", tout << "literal has no length " << mk_pp(c, m) << "\n";);
|
||||
return false;
|
||||
}
|
||||
else if (m_arith_value.get_value(len, val1) && !val1.is_neg())
|
||||
val += val1;
|
||||
else {
|
||||
TRACE("seq", tout << "length has not been internalized " << mk_pp(c, m) << "\n";);
|
||||
return false;
|
||||
|
@ -3071,9 +3070,13 @@ void theory_seq::assign_eh(bool_var v, bool is_true) {
|
|||
}
|
||||
else if (m_util.str.is_is_digit(e)) {
|
||||
|
||||
}
|
||||
else if (m_util.str.is_foldl(e) || m_util.str.is_foldli(e)) {
|
||||
|
||||
}
|
||||
else {
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n";);
|
||||
IF_VERBOSE(0, verbose_stream() << mk_pp(e, m) << "\n");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
@ -3216,18 +3219,15 @@ void theory_seq::relevant_eh(app* n) {
|
|||
add_ubv_string(n);
|
||||
|
||||
expr* arg = nullptr;
|
||||
if (m_sk.is_tail(n, arg)) {
|
||||
if (m_sk.is_tail(n, arg))
|
||||
add_length_limit(arg, m_max_unfolding_depth, true);
|
||||
}
|
||||
|
||||
if (m_util.str.is_length(n, arg) && !has_length(arg) && ctx.e_internalized(arg)) {
|
||||
if (m_util.str.is_length(n, arg) && !has_length(arg) && ctx.e_internalized(arg))
|
||||
add_length_to_eqc(arg);
|
||||
}
|
||||
|
||||
if (m_util.str.is_replace_all(n) ||
|
||||
m_util.str.is_replace_re(n) ||
|
||||
m_util.str.is_replace_re_all(n)
|
||||
) {
|
||||
m_util.str.is_replace_re_all(n)) {
|
||||
add_unhandled_expr(n);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,6 +154,7 @@ void asserted_formulas::assert_expr(expr * e, proof * _in_pr) {
|
|||
force_push();
|
||||
proof_ref in_pr(_in_pr, m), pr(_in_pr, m);
|
||||
expr_ref r(e, m);
|
||||
SASSERT(m.is_bool(e));
|
||||
|
||||
if (inconsistent())
|
||||
return;
|
||||
|
|
|
@ -39,10 +39,26 @@ Notes:
|
|||
#include "solver/parallel_tactic.h"
|
||||
#include "solver/parallel_params.hpp"
|
||||
|
||||
|
||||
class non_parallel_tactic : public tactic {
|
||||
public:
|
||||
non_parallel_tactic(solver* s, params_ref const& p) {
|
||||
}
|
||||
|
||||
char const* name() const override { return "parallel_tactic"; }
|
||||
|
||||
void operator()(const goal_ref & g,goal_ref_buffer & result) override {
|
||||
throw default_exception("parallel tactic is disabled in single threaded mode");
|
||||
}
|
||||
tactic * translate(ast_manager & m) override { return nullptr; }
|
||||
void cleanup() override {}
|
||||
|
||||
};
|
||||
|
||||
#ifdef SINGLE_THREAD
|
||||
|
||||
tactic * mk_parallel_tactic(solver* s, params_ref const& p) {
|
||||
throw default_exception("parallel tactic is disabled in single threaded mode");
|
||||
return alloc(non_parallel_tactic, s, p);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -97,9 +113,9 @@ class parallel_tactic : public tactic {
|
|||
|
||||
void shutdown() {
|
||||
if (!m_shutdown) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_shutdown = true;
|
||||
m_cond.notify_all();
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (solver_state* st : m_active) {
|
||||
st->m().limit().cancel();
|
||||
}
|
||||
|
@ -131,7 +147,9 @@ class parallel_tactic : public tactic {
|
|||
}
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_cond.wait(lock);
|
||||
if (!m_shutdown) {
|
||||
m_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
dec_wait();
|
||||
}
|
||||
|
|
|
@ -116,8 +116,8 @@ public:
|
|||
m_tactic->user_propagate_register_created(created_eh);
|
||||
}
|
||||
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t& created_eh) override {
|
||||
m_tactic->user_propagate_register_decide(created_eh);
|
||||
void user_propagate_register_decide(user_propagator::decide_eh_t& decide_eh) override {
|
||||
m_tactic->user_propagate_register_decide(decide_eh);
|
||||
}
|
||||
|
||||
void user_propagate_clear() override {
|
||||
|
|
|
@ -110,7 +110,28 @@ public:
|
|||
unsigned sz = g.size();
|
||||
numeral val;
|
||||
unsigned bv_sz;
|
||||
expr * f, * lhs, * rhs;
|
||||
expr * f, * lhs, * rhs;
|
||||
|
||||
auto match_bitmask = [&](expr* lhs, expr* rhs) {
|
||||
unsigned lo, hi;
|
||||
expr* arg;
|
||||
if (!m_util.is_numeral(rhs, val, bv_sz))
|
||||
return false;
|
||||
if (!val.is_zero())
|
||||
return false;
|
||||
if (!m_util.is_extract(lhs, lo, hi, arg))
|
||||
return false;
|
||||
if (lo == 0)
|
||||
return false;
|
||||
if (hi + 1 != m_util.get_bv_size(arg))
|
||||
return false;
|
||||
if (!is_uninterp_const(arg))
|
||||
return false;
|
||||
val = rational::power_of_two(lo - 1) -1 ;
|
||||
update_unsigned_upper(to_app(arg), val);
|
||||
return true;
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
bool negated = false;
|
||||
f = g.form(i);
|
||||
|
@ -152,22 +173,31 @@ public:
|
|||
else update_signed_lower(to_app(rhs), val);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if 0
|
||||
else if (m_util.is_bv_ule(f, lhs, rhs)) {
|
||||
if (is_uninterp_const(lhs) && m_util.is_numeral(rhs, val, bv_sz)) {
|
||||
TRACE("bv_size_reduction", tout << (negated?"not ":"") << mk_ismt2_pp(f, m) << std::endl; );
|
||||
// v <= k
|
||||
if (negated) update_unsigned_lower(to_app(lhs), val+numeral(1));
|
||||
else update_unsigned_upper(to_app(lhs), val);
|
||||
if (negated)
|
||||
update_unsigned_lower(to_app(lhs), val+numeral(1));
|
||||
else
|
||||
update_unsigned_upper(to_app(lhs), val);
|
||||
}
|
||||
else if (is_uninterp_const(rhs) && m_util.is_numeral(lhs, val, bv_sz)) {
|
||||
TRACE("bv_size_reduction", tout << (negated?"not ":"") << mk_ismt2_pp(f, m) << std::endl; );
|
||||
// k <= v
|
||||
if (negated) update_unsigned_upper(to_app(rhs), val-numeral(1));
|
||||
else update_unsigned_lower(to_app(rhs), val);
|
||||
if (negated)
|
||||
update_unsigned_upper(to_app(rhs), val-numeral(1));
|
||||
else
|
||||
update_unsigned_lower(to_app(rhs), val);
|
||||
}
|
||||
}
|
||||
else if (m.is_eq(f, lhs, rhs)) {
|
||||
if (match_bitmask(lhs, rhs))
|
||||
continue;
|
||||
if (match_bitmask(rhs, lhs))
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -185,33 +215,48 @@ public:
|
|||
mc = nullptr;
|
||||
m_mc = nullptr;
|
||||
unsigned num_reduced = 0;
|
||||
|
||||
{
|
||||
tactic_report report("reduce-bv-size", g);
|
||||
collect_bounds(g);
|
||||
|
||||
// create substitution
|
||||
expr_substitution subst(m);
|
||||
|
||||
auto insert_def = [&](app* k, expr* new_def, app* new_const) {
|
||||
if (!new_def)
|
||||
return;
|
||||
subst.insert(k, new_def);
|
||||
if (m_produce_models) {
|
||||
if (!m_mc)
|
||||
m_mc = alloc(bv_size_reduction_mc, m, "bv_size_reduction");
|
||||
m_mc->add(k, new_def);
|
||||
if (!m_fmc && new_const)
|
||||
m_fmc = alloc(generic_model_converter, m, "bv_size_reduction");
|
||||
if (new_const)
|
||||
m_fmc->hide(new_const);
|
||||
}
|
||||
num_reduced++;
|
||||
};
|
||||
|
||||
|
||||
if (!(m_signed_lowers.empty() || m_signed_uppers.empty())) {
|
||||
TRACE("bv_size_reduction",
|
||||
tout << "m_signed_lowers: " << std::endl;
|
||||
for (obj_map<app, numeral>::iterator it = m_signed_lowers.begin(); it != m_signed_lowers.end(); it++)
|
||||
tout << mk_ismt2_pp(it->m_key, m) << " >= " << it->m_value.to_string() << std::endl;
|
||||
tout << "m_signed_uppers: " << std::endl;
|
||||
for (obj_map<app, numeral>::iterator it = m_signed_uppers.begin(); it != m_signed_uppers.end(); it++)
|
||||
tout << mk_ismt2_pp(it->m_key, m) << " <= " << it->m_value.to_string() << std::endl;
|
||||
);
|
||||
tout << "m_signed_lowers: " << std::endl;
|
||||
for (auto const& [k, v] : m_signed_lowers)
|
||||
tout << mk_ismt2_pp(k, m) << " >= " << v.to_string() << std::endl;
|
||||
tout << "m_signed_uppers: " << std::endl;
|
||||
for (auto const& [k, v] : m_signed_uppers)
|
||||
tout << mk_ismt2_pp(k, m) << " <= " << v.to_string() << std::endl;
|
||||
);
|
||||
|
||||
obj_map<app, numeral>::iterator it = m_signed_lowers.begin();
|
||||
obj_map<app, numeral>::iterator end = m_signed_lowers.end();
|
||||
for (; it != end; ++it) {
|
||||
app * v = it->m_key;
|
||||
unsigned bv_sz = m_util.get_bv_size(v);
|
||||
numeral l = m_util.norm(it->m_value, bv_sz, true);
|
||||
obj_map<app, numeral>::obj_map_entry * entry = m_signed_uppers.find_core(v);
|
||||
for (auto& [k, val] : m_signed_lowers) {
|
||||
unsigned bv_sz = m_util.get_bv_size(k);
|
||||
numeral l = m_util.norm(val, bv_sz, true);
|
||||
obj_map<app, numeral>::obj_map_entry * entry = m_signed_uppers.find_core(k);
|
||||
if (entry != nullptr) {
|
||||
numeral u = m_util.norm(entry->get_data().m_value, bv_sz, true);
|
||||
TRACE("bv_size_reduction", tout << l << " <= " << v->get_decl()->get_name() << " <= " << u << "\n";);
|
||||
TRACE("bv_size_reduction", tout << l << " <= " << k->get_decl()->get_name() << " <= " << u << "\n";);
|
||||
expr * new_def = nullptr;
|
||||
app * new_const = nullptr;
|
||||
if (l > u) {
|
||||
|
@ -219,19 +264,19 @@ public:
|
|||
return;
|
||||
}
|
||||
else if (l == u) {
|
||||
new_def = m_util.mk_numeral(l, v->get_sort());
|
||||
new_def = m_util.mk_numeral(l, k->get_sort());
|
||||
}
|
||||
else {
|
||||
// l < u
|
||||
if (l.is_neg()) {
|
||||
unsigned l_nb = (-l).get_num_bits();
|
||||
unsigned v_nb = m_util.get_bv_size(v);
|
||||
unsigned v_nb = m_util.get_bv_size(k);
|
||||
|
||||
if (u.is_neg())
|
||||
{
|
||||
// l <= v <= u <= 0
|
||||
unsigned i_nb = l_nb;
|
||||
TRACE("bv_size_reduction", tout << " l <= " << v->get_decl()->get_name() << " <= u <= 0 " << " --> " << i_nb << " bits\n";);
|
||||
TRACE("bv_size_reduction", tout << " l <= " << k->get_decl()->get_name() << " <= u <= 0 " << " --> " << i_nb << " bits\n";);
|
||||
if (i_nb < v_nb) {
|
||||
new_const = m.mk_fresh_const(nullptr, m_util.mk_sort(i_nb));
|
||||
new_def = m_util.mk_concat(m_util.mk_numeral(numeral(-1), v_nb - i_nb), new_const);
|
||||
|
@ -241,7 +286,7 @@ public:
|
|||
// l <= v <= 0 <= u
|
||||
unsigned u_nb = u.get_num_bits();
|
||||
unsigned i_nb = ((l_nb > u_nb) ? l_nb : u_nb) + 1;
|
||||
TRACE("bv_size_reduction", tout << " l <= " << v->get_decl()->get_name() << " <= 0 <= u " << " --> " << i_nb << " bits\n";);
|
||||
TRACE("bv_size_reduction", tout << " l <= " << k->get_decl()->get_name() << " <= 0 <= u " << " --> " << i_nb << " bits\n";);
|
||||
if (i_nb < v_nb) {
|
||||
new_const = m.mk_fresh_const(nullptr, m_util.mk_sort(i_nb));
|
||||
new_def = m_util.mk_sign_extend(v_nb - i_nb, new_const);
|
||||
|
@ -251,31 +296,30 @@ public:
|
|||
else {
|
||||
// 0 <= l <= v <= u
|
||||
unsigned u_nb = u.get_num_bits();
|
||||
unsigned v_nb = m_util.get_bv_size(v);
|
||||
TRACE("bv_size_reduction", tout << l << " <= " << v->get_decl()->get_name() << " <= " << u << " --> " << u_nb << " bits\n";);
|
||||
unsigned v_nb = m_util.get_bv_size(k);
|
||||
TRACE("bv_size_reduction", tout << l << " <= " << k->get_decl()->get_name() << " <= " << u << " --> " << u_nb << " bits\n";);
|
||||
if (u_nb < v_nb) {
|
||||
new_const = m.mk_fresh_const(nullptr, m_util.mk_sort(u_nb));
|
||||
new_def = m_util.mk_concat(m_util.mk_numeral(numeral(0), v_nb - u_nb), new_const);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (new_def) {
|
||||
subst.insert(v, new_def);
|
||||
if (m_produce_models) {
|
||||
if (!m_mc)
|
||||
m_mc = alloc(bv_size_reduction_mc, m, "bv_size_reduction");
|
||||
m_mc->add(v, new_def);
|
||||
if (!m_fmc && new_const)
|
||||
m_fmc = alloc(generic_model_converter, m, "bv_size_reduction");
|
||||
if (new_const)
|
||||
m_fmc->hide(new_const);
|
||||
}
|
||||
num_reduced++;
|
||||
}
|
||||
|
||||
insert_def(k, new_def, new_const);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& [k, v] : m_unsigned_uppers) {
|
||||
unsigned shift;
|
||||
unsigned bv_sz = m_util.get_bv_size(k);
|
||||
numeral u = m_util.norm(v, bv_sz, true) + 1;
|
||||
if (u.is_power_of_two(shift) && shift < bv_sz) {
|
||||
app* new_const = m.mk_fresh_const(nullptr, m_util.mk_sort(shift));
|
||||
expr* new_def = m_util.mk_concat(m_util.mk_numeral(numeral(0), bv_sz - shift), new_const);
|
||||
insert_def(k, new_def, new_const);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!(m_unsigned_lowers.empty() && m_unsigned_uppers.empty())) {
|
||||
|
|
|
@ -424,10 +424,20 @@ tactic * or_else(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5
|
|||
return or_else(10, ts);
|
||||
}
|
||||
|
||||
class no_par_tactical : public tactic {
|
||||
public:
|
||||
char const* name() const override { return "par"; }
|
||||
void operator()(goal_ref const & in, goal_ref_buffer& result) override {
|
||||
throw default_exception("par_tactical is unavailable in single threaded mode");
|
||||
}
|
||||
tactic * translate(ast_manager & m) override { return nullptr; }
|
||||
void cleanup() override {}
|
||||
};
|
||||
|
||||
#ifdef SINGLE_THREAD
|
||||
|
||||
tactic * par(unsigned num, tactic * const * ts) {
|
||||
throw default_exception("par_tactical is unavailable in single threaded mode");
|
||||
return alloc(no_par_tactical);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -576,11 +586,23 @@ tactic * par(tactic * t1, tactic * t2, tactic * t3, tactic * t4) {
|
|||
return par(4, ts);
|
||||
}
|
||||
|
||||
class no_par_and_then_tactical : public tactic {
|
||||
public:
|
||||
char const* name() const override { return "par_then"; }
|
||||
void operator()(goal_ref const & in, goal_ref_buffer& result) override {
|
||||
throw default_exception("par_and_then is not available in single threaded mode");
|
||||
}
|
||||
tactic * translate(ast_manager & m) override { return nullptr; }
|
||||
void cleanup() override {}
|
||||
};
|
||||
|
||||
|
||||
#ifdef SINGLE_THREAD
|
||||
|
||||
tactic * par_and_then(tactic * t1, tactic * t2) {
|
||||
throw default_exception("par_and_then is not available in single threaded mode");
|
||||
return alloc(no_par_and_then_tactical);
|
||||
}
|
||||
|
||||
#else
|
||||
class par_and_then_tactical : public and_then_tactical {
|
||||
public:
|
||||
|
|
|
@ -593,6 +593,63 @@ public :
|
|||
SASSERT_EQ(coeff[2], 0);
|
||||
SASSERT_EQ(coeff[3], 3);
|
||||
}
|
||||
|
||||
static void factors() {
|
||||
pdd_manager m(3);
|
||||
pdd v0 = m.mk_var(0);
|
||||
pdd v1 = m.mk_var(1);
|
||||
pdd v2 = m.mk_var(2);
|
||||
pdd v3 = m.mk_var(3);
|
||||
pdd v4 = m.mk_var(4);
|
||||
pdd c1 = v0 * v1 * v2 + v2 * v0 + v1 + 1;
|
||||
{
|
||||
auto [vars, p] = c1.var_factors();
|
||||
VERIFY(p == c1 && vars.empty());
|
||||
}
|
||||
{
|
||||
auto q = c1 * v4;
|
||||
auto [vars, p] = q.var_factors();
|
||||
std::cout << p << " " << vars << "\n";
|
||||
VERIFY(p == c1 && vars.size() == 1 && vars[0] == 4);
|
||||
}
|
||||
for (unsigned i = 0; i < 5; ++i) {
|
||||
auto v = m.mk_var(i);
|
||||
auto q = c1 * v;
|
||||
std::cout << i << ": " << q << "\n";
|
||||
auto [vars, p] = q.var_factors();
|
||||
std::cout << p << " " << vars << "\n";
|
||||
VERIFY(p == c1 && vars.size() == 1 && vars[0] == i);
|
||||
}
|
||||
for (unsigned i = 0; i < 5; ++i) {
|
||||
for (unsigned j = 0; j < 5; ++j) {
|
||||
auto vi = m.mk_var(i);
|
||||
auto vj = m.mk_var(j);
|
||||
auto q = c1 * vi * vj;
|
||||
auto [vars, p] = q.var_factors();
|
||||
std::cout << p << " " << vars << "\n";
|
||||
VERIFY(p == c1 && vars.size() == 2);
|
||||
VERIFY(vars[0] == i || vars[1] == i);
|
||||
VERIFY(vars[0] == j || vars[1] == j);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < 5; ++i) {
|
||||
for (unsigned j = i; j < 5; ++j) {
|
||||
for (unsigned k = j; k < 5; ++k) {
|
||||
auto vi = m.mk_var(i);
|
||||
auto vj = m.mk_var(j);
|
||||
auto vk = m.mk_var(k);
|
||||
auto q = c1 * vi * vj * vk;
|
||||
auto [vars, p] = q.var_factors();
|
||||
std::cout << p << " " << vars << "\n";
|
||||
VERIFY(p == c1 && vars.size() == 3);
|
||||
VERIFY(vars[0] == i || vars[1] == i || vars[2] == i);
|
||||
VERIFY(vars[0] == j || vars[1] == j || vars[2] == j);
|
||||
VERIFY(vars[0] == k || vars[1] == k || vars[2] == k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -615,4 +672,5 @@ void tst_pdd() {
|
|||
dd::test::pow();
|
||||
dd::test::subst_val();
|
||||
dd::test::univariate();
|
||||
dd::test::factors();
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ private:
|
|||
}
|
||||
|
||||
void dec_ref(unsigned sz, value * vs) {
|
||||
if (C::ref_count)
|
||||
if (C::ref_count)
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
m_vmanager.dec_ref(vs[i]);
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ private:
|
|||
size_t new_capacity = curr_capacity == 0 ? 2 : (3 * curr_capacity + 1) >> 1;
|
||||
value * new_vs = allocate_values(new_capacity);
|
||||
if (curr_capacity > 0) {
|
||||
for (size_t i = 0; i < curr_capacity; i++)
|
||||
for (size_t i = 0; i < curr_capacity; i++)
|
||||
new_vs[i] = vs[i];
|
||||
deallocate_values(vs);
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ private:
|
|||
inc_ref(v);
|
||||
vs[sz] = v;
|
||||
sz++;
|
||||
}
|
||||
}
|
||||
|
||||
void rpush_back(cell * c, value const & v) {
|
||||
SASSERT(c->kind() == ROOT);
|
||||
|
@ -269,7 +269,7 @@ public:
|
|||
}
|
||||
|
||||
value_manager & manager() { return m_vmanager; }
|
||||
|
||||
|
||||
void mk(ref & r) {
|
||||
dec_ref(r.m_ref);
|
||||
cell * new_c = mk(ROOT);
|
||||
|
@ -283,12 +283,12 @@ public:
|
|||
r.m_ref = nullptr;
|
||||
r.m_updt_counter = 0;
|
||||
}
|
||||
|
||||
|
||||
void copy(ref const & s, ref & t) {
|
||||
inc_ref(s.m_ref);
|
||||
dec_ref(t.m_ref);
|
||||
t.m_ref = s.m_ref;
|
||||
t.m_updt_counter = 0;
|
||||
t.m_updt_counter = 0;
|
||||
}
|
||||
|
||||
unsigned size(ref const & r) const {
|
||||
|
@ -310,17 +310,15 @@ public:
|
|||
}
|
||||
|
||||
void check_size(cell* c) const {
|
||||
unsigned r;
|
||||
while (c) {
|
||||
switch (c->kind()) {
|
||||
case SET:
|
||||
break;
|
||||
case PUSH_BACK:
|
||||
r = size(c->next());
|
||||
// ? SASSERT(c->idx() == size(c->next()));
|
||||
break;
|
||||
case POP_BACK:
|
||||
r = size(c->next());
|
||||
SASSERT(c->idx() == r);
|
||||
SASSERT(c->idx() == size(c->next()));
|
||||
break;
|
||||
case ROOT:
|
||||
return;
|
||||
|
@ -333,7 +331,7 @@ public:
|
|||
|
||||
value const & get(ref const & r, unsigned i) const {
|
||||
SASSERT(i < size(r));
|
||||
|
||||
|
||||
unsigned trail_sz = 0;
|
||||
cell * c = r.m_ref;
|
||||
|
||||
|
@ -451,7 +449,7 @@ public:
|
|||
inc_ref(v);
|
||||
new_c->m_elem = v;
|
||||
new_c->m_next = r.m_ref;
|
||||
r.m_ref = new_c;
|
||||
r.m_ref = new_c;
|
||||
SASSERT(new_c->m_ref_count == 1);
|
||||
}
|
||||
|
||||
|
@ -536,7 +534,7 @@ public:
|
|||
r.m_updt_counter = 0;
|
||||
SASSERT(r.root());
|
||||
}
|
||||
|
||||
|
||||
void reroot(ref & r) {
|
||||
if (r.root())
|
||||
return;
|
||||
|
@ -545,7 +543,7 @@ public:
|
|||
unsigned r_sz = size(r);
|
||||
unsigned trail_split_idx = r_sz / C::factor;
|
||||
unsigned i = 0;
|
||||
cell * c = r.m_ref;
|
||||
cell * c = r.m_ref;
|
||||
while (c->kind() != ROOT && i < trail_split_idx) {
|
||||
cs.push_back(c);
|
||||
c = c->next();
|
||||
|
@ -556,7 +554,7 @@ public:
|
|||
unfold(c);
|
||||
}
|
||||
DEBUG_CODE(check_size(c););
|
||||
SASSERT(c->kind() == ROOT);
|
||||
SASSERT(c->kind() == ROOT);
|
||||
for (i = cs.size(); i-- > 0; ) {
|
||||
cell * p = cs[i];
|
||||
SASSERT(c->m_kind == ROOT);
|
||||
|
@ -574,7 +572,7 @@ public:
|
|||
case PUSH_BACK:
|
||||
c->m_kind = POP_BACK;
|
||||
if (sz == capacity(vs))
|
||||
expand(vs);
|
||||
expand(vs);
|
||||
vs[sz] = p->m_elem;
|
||||
++sz;
|
||||
c->m_idx = sz;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue