mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
Merge remote-tracking branch 'origin/master' into polysat
This commit is contained in:
commit
cd50f2ea88
378 changed files with 13563 additions and 7320 deletions
|
@ -220,7 +220,7 @@ if (MSVC)
|
|||
set(dll_module_exports_file "${CMAKE_CURRENT_BINARY_DIR}/api_dll.def")
|
||||
add_custom_command(OUTPUT "${dll_module_exports_file}"
|
||||
COMMAND
|
||||
"${PYTHON_EXECUTABLE}"
|
||||
"${Python3_EXECUTABLE}"
|
||||
"${PROJECT_SOURCE_DIR}/scripts/mk_def_file.py"
|
||||
"${dll_module_exports_file}"
|
||||
"libz3"
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/array_decl_plugin.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
|
||||
class ackr_helper {
|
||||
public:
|
||||
|
@ -40,10 +41,8 @@ public:
|
|||
inline bool is_uninterp_fn(app const * a) const {
|
||||
if (is_uninterp(a))
|
||||
return true;
|
||||
else {
|
||||
decl_plugin * p = m_bvutil.get_manager().get_plugin(a->get_family_id());
|
||||
return p->is_considered_uninterpreted(a->get_decl());
|
||||
}
|
||||
decl_plugin * p = m_bvutil.get_manager().get_plugin(a->get_family_id());
|
||||
return p->is_considered_uninterpreted(a->get_decl());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,9 +63,8 @@ public:
|
|||
}
|
||||
}
|
||||
else {
|
||||
for (expr* arg : *a) {
|
||||
for (expr* arg : *a)
|
||||
non_select.mark(arg, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +110,8 @@ public:
|
|||
}
|
||||
|
||||
void insert(fun2terms_map& f2t, sel2terms_map& s2t, app* a) {
|
||||
if (a->get_num_args() == 0) return;
|
||||
if (a->get_num_args() == 0)
|
||||
return;
|
||||
ast_manager& m = m_bvutil.get_manager();
|
||||
app_set* ts = nullptr;
|
||||
bool is_const_args = true;
|
||||
|
@ -129,21 +128,18 @@ public:
|
|||
ts = alloc(app_set);
|
||||
f2t.insert(fd, ts);
|
||||
}
|
||||
is_const_args = m.is_value(a->get_arg(0));
|
||||
is_const_args = m.is_unique_value(a->get_arg(0));
|
||||
}
|
||||
else {
|
||||
else
|
||||
return;
|
||||
}
|
||||
for (unsigned i = 1; is_const_args && i < a->get_num_args(); ++i) {
|
||||
is_const_args &= m.is_value(a->get_arg(i));
|
||||
}
|
||||
|
||||
if (is_const_args) {
|
||||
for (unsigned i = 1; is_const_args && i < a->get_num_args(); ++i)
|
||||
is_const_args &= m.is_unique_value(a->get_arg(i));
|
||||
|
||||
if (is_const_args)
|
||||
ts->const_args.insert(a);
|
||||
}
|
||||
else {
|
||||
else
|
||||
ts->var_args.insert(a);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "ackermannization/ackr_info.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "model/model_smt2_pp.h"
|
||||
|
||||
lackr::lackr(ast_manager& m, const params_ref& p, lackr_stats& st,
|
||||
|
@ -142,10 +144,10 @@ bool lackr::ackr(app * const t1, app * const t2) {
|
|||
// Introduce the ackermann lemma for each pair of terms.
|
||||
//
|
||||
void lackr::eager_enc() {
|
||||
TRACE("ackermannize", tout << "#funs: " << m_fun2terms.size() << "#sels: " << m_sel2terms.size() << std::endl;);
|
||||
for (auto const& kv : m_fun2terms) {
|
||||
TRACE("ackermannize", tout << "#funs: " << m_fun2terms.size() << " #sels: " << m_sel2terms.size() << std::endl;);
|
||||
for (auto const& [k,v] : m_fun2terms) {
|
||||
checkpoint();
|
||||
ackr(kv.get_value());
|
||||
ackr(v);
|
||||
}
|
||||
for (auto const& kv : m_sel2terms) {
|
||||
checkpoint();
|
||||
|
@ -172,14 +174,13 @@ void lackr::ackr(app_set const* ts) {
|
|||
}
|
||||
|
||||
void lackr::abstract_fun(fun2terms_map const& apps) {
|
||||
for (auto const& kv : apps) {
|
||||
func_decl* fd = kv.m_key;
|
||||
for (app * t : kv.m_value->var_args) {
|
||||
for (auto const& [fd, v] : apps) {
|
||||
for (app * t : v->var_args) {
|
||||
app * fc = m.mk_fresh_const(fd->get_name(), t->get_sort());
|
||||
SASSERT(t->get_decl() == fd);
|
||||
m_info->set_abstr(t, fc);
|
||||
}
|
||||
for (app * t : kv.m_value->const_args) {
|
||||
for (app * t : v->const_args) {
|
||||
app * fc = m.mk_fresh_const(fd->get_name(), t->get_sort());
|
||||
SASSERT(t->get_decl() == fd);
|
||||
m_info->set_abstr(t, fc);
|
||||
|
|
|
@ -18,7 +18,7 @@ foreach (gen_file ${generated_files})
|
|||
endforeach()
|
||||
|
||||
add_custom_command(OUTPUT ${generated_files}
|
||||
COMMAND "${PYTHON_EXECUTABLE}"
|
||||
COMMAND "${Python3_EXECUTABLE}"
|
||||
"${PROJECT_SOURCE_DIR}/scripts/update_api.py"
|
||||
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
|
||||
"--api_output_dir"
|
||||
|
|
|
@ -29,6 +29,7 @@ Revision History:
|
|||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/ast_smt_pp.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/polymorphism_util.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/rewriter/expr_safe_replace.h"
|
||||
|
@ -88,6 +89,16 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
Z3_sort Z3_API Z3_mk_type_variable(Z3_context c, Z3_symbol name) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_mk_type_variable(c, name);
|
||||
RESET_ERROR_CODE();
|
||||
sort* ty = mk_c(c)->m().mk_type_var(to_symbol(name));
|
||||
mk_c(c)->save_ast_trail(ty);
|
||||
RETURN_Z3(of_sort(ty));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
bool Z3_API Z3_is_eq_ast(Z3_context c, Z3_ast s1, Z3_ast s2) {
|
||||
RESET_ERROR_CODE();
|
||||
return s1 == s2;
|
||||
|
@ -180,7 +191,20 @@ extern "C" {
|
|||
arg_list.push_back(to_expr(args[i]));
|
||||
}
|
||||
func_decl* _d = reinterpret_cast<func_decl*>(d);
|
||||
app* a = mk_c(c)->m().mk_app(_d, num_args, arg_list.data());
|
||||
ast_manager& m = mk_c(c)->m();
|
||||
if (_d->is_polymorphic()) {
|
||||
polymorphism::util u(m);
|
||||
polymorphism::substitution sub(m);
|
||||
ptr_buffer<sort> domain;
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
if (!sub.match(_d->get_domain(i), arg_list[i]->get_sort()))
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, "failed to match argument of polymorphic function");
|
||||
domain.push_back(arg_list[i]->get_sort());
|
||||
}
|
||||
sort_ref range = sub(_d->get_range());
|
||||
_d = m.instantiate_polymorphic(_d, num_args, domain.data(), range);
|
||||
}
|
||||
app* a = m.mk_app(_d, num_args, arg_list.data());
|
||||
mk_c(c)->save_ast_trail(a);
|
||||
check_sorts(c, a);
|
||||
RETURN_Z3(of_ast(a));
|
||||
|
@ -728,6 +752,9 @@ extern "C" {
|
|||
else if (fid == mk_c(c)->get_char_fid() && k == CHAR_SORT) {
|
||||
return Z3_CHAR_SORT;
|
||||
}
|
||||
else if (fid == poly_family_id) {
|
||||
return Z3_TYPE_VAR;
|
||||
}
|
||||
else {
|
||||
return Z3_UNKNOWN_SORT;
|
||||
}
|
||||
|
|
|
@ -227,6 +227,9 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
|
|||
Z3_ast Z3_API Z3_mk_bvadd_no_underflow(Z3_context c, Z3_ast t1, Z3_ast t2) {
|
||||
Z3_TRY;
|
||||
RESET_ERROR_CODE();
|
||||
// l1 := t1 <s 0
|
||||
// l2 := t2 <s 0
|
||||
// l1 & l2 => t1 + t2 <s 0
|
||||
Z3_ast zero = Z3_mk_int(c, 0, Z3_get_sort(c, t1));
|
||||
Z3_inc_ref(c, zero);
|
||||
Z3_ast r = Z3_mk_bvadd(c, t1, t2);
|
||||
|
@ -255,6 +258,10 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
|
|||
Z3_ast Z3_API Z3_mk_bvsub_no_overflow(Z3_context c, Z3_ast t1, Z3_ast t2) {
|
||||
Z3_TRY;
|
||||
RESET_ERROR_CODE();
|
||||
// x := t2 = min_int
|
||||
// y := t1 <s 0
|
||||
// z := no_overflow(t1 + -t2)
|
||||
// if x y z
|
||||
Z3_ast minus_t2 = Z3_mk_bvneg(c, t2);
|
||||
Z3_inc_ref(c, minus_t2);
|
||||
Z3_sort s = Z3_get_sort(c, t2);
|
||||
|
@ -284,6 +291,9 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
|
|||
Z3_TRY;
|
||||
RESET_ERROR_CODE();
|
||||
if (is_signed) {
|
||||
// x := 0 <s -t2
|
||||
// y := no_underflow(x + -t2)
|
||||
// x => y
|
||||
Z3_ast zero = Z3_mk_int(c, 0, Z3_get_sort(c, t1));
|
||||
Z3_inc_ref(c, zero);
|
||||
Z3_ast minus_t2 = Z3_mk_bvneg(c, t2);
|
||||
|
|
|
@ -78,6 +78,11 @@ namespace api {
|
|||
m().dec_ref(a);
|
||||
}
|
||||
|
||||
// flush_objects can only be called in the main thread.
|
||||
// This ensures that the calls to m().dec_ref() and dealloc(o)
|
||||
// only happens in the main thread.
|
||||
// Calls to dec_ref are allowed in other threads when m_concurrent_dec_ref is
|
||||
// set to true.
|
||||
void context::flush_objects() {
|
||||
#ifndef SINGLE_THREAD
|
||||
if (!m_concurrent_dec_ref)
|
||||
|
@ -157,6 +162,9 @@ namespace api {
|
|||
flush_objects();
|
||||
for (auto& kv : m_allocated_objects) {
|
||||
api::object* val = kv.m_value;
|
||||
#ifdef SINGLE_THREAD
|
||||
# define m_concurrent_dec_ref false
|
||||
#endif
|
||||
DEBUG_CODE(if (!m_concurrent_dec_ref) warning_msg("Uncollected memory: %d: %s", kv.m_key, typeid(*val).name()););
|
||||
dealloc(val);
|
||||
}
|
||||
|
|
|
@ -241,6 +241,20 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
unsigned Z3_API Z3_constructor_num_fields(Z3_context c, Z3_constructor constr) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_constructor_num_fields(c, constr);
|
||||
RESET_ERROR_CODE();
|
||||
mk_c(c)->reset_last_result();
|
||||
if (!constr) {
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
|
||||
return 0;
|
||||
}
|
||||
constructor* c = reinterpret_cast<constructor*>(constr);
|
||||
return c->m_field_names.size();
|
||||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
void Z3_API Z3_query_constructor(Z3_context c,
|
||||
Z3_constructor constr,
|
||||
|
|
|
@ -29,13 +29,12 @@ bool is_numeral_sort(Z3_context c, Z3_sort ty) {
|
|||
if (!ty) return false;
|
||||
sort * _ty = to_sort(ty);
|
||||
family_id fid = _ty->get_family_id();
|
||||
if (fid != mk_c(c)->get_arith_fid() &&
|
||||
fid != mk_c(c)->get_bv_fid() &&
|
||||
fid != mk_c(c)->get_datalog_fid() &&
|
||||
fid != mk_c(c)->get_fpa_fid()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return
|
||||
fid == mk_c(c)->get_arith_fid() ||
|
||||
fid == mk_c(c)->get_bv_fid() ||
|
||||
fid == mk_c(c)->get_datalog_fid() ||
|
||||
fid == mk_c(c)->get_fpa_fid();
|
||||
|
||||
}
|
||||
|
||||
static bool check_numeral_sort(Z3_context c, Z3_sort ty) {
|
||||
|
@ -152,7 +151,7 @@ extern "C" {
|
|||
mk_c(c)->bvutil().is_numeral(e) ||
|
||||
mk_c(c)->fpautil().is_numeral(e) ||
|
||||
mk_c(c)->fpautil().is_rm_numeral(e) ||
|
||||
mk_c(c)->datalog_util().is_numeral_ext(e);
|
||||
mk_c(c)->datalog_util().is_numeral(e);
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -383,6 +383,36 @@ extern "C" {
|
|||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
Z3_symbol Z3_API Z3_get_quantifier_skolem_id(Z3_context c, Z3_ast a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_get_quantifier_skolem_id(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
ast * _a = to_ast(a);
|
||||
if (_a->get_kind() == AST_QUANTIFIER) {
|
||||
return of_symbol(to_quantifier(_a)->get_skid());
|
||||
}
|
||||
else {
|
||||
SET_ERROR_CODE(Z3_SORT_ERROR, nullptr);
|
||||
return of_symbol(symbol::null);
|
||||
}
|
||||
Z3_CATCH_RETURN(of_symbol(symbol::null));
|
||||
}
|
||||
|
||||
Z3_symbol Z3_API Z3_get_quantifier_id(Z3_context c, Z3_ast a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_get_quantifier_skolem_id(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
ast * _a = to_ast(a);
|
||||
if (_a->get_kind() == AST_QUANTIFIER) {
|
||||
return of_symbol(to_quantifier(_a)->get_qid());
|
||||
}
|
||||
else {
|
||||
SET_ERROR_CODE(Z3_SORT_ERROR, nullptr);
|
||||
return of_symbol(symbol::null);
|
||||
}
|
||||
Z3_CATCH_RETURN(of_symbol(symbol::null));
|
||||
}
|
||||
|
||||
unsigned Z3_API Z3_get_quantifier_num_patterns(Z3_context c, Z3_ast a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_get_quantifier_num_patterns(c, a);
|
||||
|
|
|
@ -17,7 +17,7 @@ Author:
|
|||
Leonardo de Moura (leonardo) 2012-01-05
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
--*/
|
||||
#include "api/z3.h"
|
||||
#include "api/api_log_macros.h"
|
||||
|
@ -32,12 +32,12 @@ static void reset_rcf_cancel(Z3_context c) {
|
|||
// no-op
|
||||
}
|
||||
|
||||
static Z3_rcf_num from_rcnumeral(rcnumeral a) {
|
||||
return reinterpret_cast<Z3_rcf_num>(a.data());
|
||||
static Z3_rcf_num from_rcnumeral(rcnumeral a) {
|
||||
return reinterpret_cast<Z3_rcf_num>(a.data());
|
||||
}
|
||||
|
||||
static rcnumeral to_rcnumeral(Z3_rcf_num a) {
|
||||
return rcnumeral::mk(a);
|
||||
static rcnumeral to_rcnumeral(Z3_rcf_num a) {
|
||||
return rcnumeral::mk(a);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
@ -179,7 +179,7 @@ extern "C" {
|
|||
RETURN_Z3(from_rcnumeral(r));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
|
||||
Z3_rcf_num Z3_API Z3_rcf_neg(Z3_context c, Z3_rcf_num a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_neg(c, a);
|
||||
|
@ -302,4 +302,139 @@ extern "C" {
|
|||
Z3_CATCH;
|
||||
}
|
||||
|
||||
bool Z3_API Z3_rcf_is_rational(Z3_context c, Z3_rcf_num a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_is_rational(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return rcfm(c).is_rational(to_rcnumeral(a));
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
bool Z3_API Z3_rcf_is_algebraic(Z3_context c, Z3_rcf_num a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_is_algebraic(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return rcfm(c).is_algebraic(to_rcnumeral(a));
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
bool Z3_API Z3_rcf_is_infinitesimal(Z3_context c, Z3_rcf_num a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_is_infinitesimal(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return rcfm(c).is_infinitesimal(to_rcnumeral(a));
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
bool Z3_API Z3_rcf_is_transcendental(Z3_context c, Z3_rcf_num a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_is_transcendental(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return rcfm(c).is_transcendental(to_rcnumeral(a));
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
unsigned Z3_API Z3_rcf_extension_index(Z3_context c, Z3_rcf_num a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_extension_index(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return rcfm(c).extension_index(to_rcnumeral(a));
|
||||
Z3_CATCH_RETURN(false);
|
||||
}
|
||||
|
||||
Z3_symbol Z3_API Z3_rcf_transcendental_name(Z3_context c, Z3_rcf_num a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_transcendental_name(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return of_symbol(rcfm(c).transcendental_name(to_rcnumeral(a)));
|
||||
Z3_CATCH_RETURN(of_symbol(symbol::null));
|
||||
}
|
||||
|
||||
Z3_symbol Z3_API Z3_rcf_infinitesimal_name(Z3_context c, Z3_rcf_num a) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_infinitesimal_name(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return of_symbol(rcfm(c).infinitesimal_name(to_rcnumeral(a)));
|
||||
Z3_CATCH_RETURN(of_symbol(symbol::null));
|
||||
}
|
||||
|
||||
unsigned Z3_API Z3_rcf_num_coefficients(Z3_context c, Z3_rcf_num a)
|
||||
{
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_num_coefficients(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return rcfm(c).num_coefficients(to_rcnumeral(a));
|
||||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
Z3_rcf_num Z3_API Z3_rcf_coefficient(Z3_context c, Z3_rcf_num a, unsigned i)
|
||||
{
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_coefficient(c, a, i);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return from_rcnumeral(rcfm(c).get_coefficient(to_rcnumeral(a), i));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
|
||||
int Z3_API Z3_rcf_interval(Z3_context c, Z3_rcf_num a, int * lower_is_inf, int * lower_is_open, Z3_rcf_num * lower, int * upper_is_inf, int * upper_is_open, Z3_rcf_num * upper) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_interval(c, a, lower_is_inf, lower_is_open, lower, upper_is_inf, upper_is_open, upper);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
rcnumeral r_lower, r_upper;
|
||||
bool r = rcfm(c).get_interval(to_rcnumeral(a), *lower_is_inf, *lower_is_open, r_lower, *upper_is_inf, *upper_is_open, r_upper);
|
||||
*lower = from_rcnumeral(r_lower);
|
||||
*upper = from_rcnumeral(r_upper);
|
||||
return r;
|
||||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
unsigned Z3_API Z3_rcf_num_sign_conditions(Z3_context c, Z3_rcf_num a)
|
||||
{
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_num_sign_conditions(c, a);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return rcfm(c).num_sign_conditions(to_rcnumeral(a));
|
||||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
int Z3_API Z3_rcf_sign_condition_sign(Z3_context c, Z3_rcf_num a, unsigned i)
|
||||
{
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_sign_condition_sign(c, a, i);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return rcfm(c).get_sign_condition_sign(to_rcnumeral(a), i);
|
||||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
unsigned Z3_API Z3_rcf_num_sign_condition_coefficients(Z3_context c, Z3_rcf_num a, unsigned i)
|
||||
{
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_num_sign_condition_coefficients(c, a, i);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return rcfm(c).num_sign_condition_coefficients(to_rcnumeral(a), i);
|
||||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
Z3_rcf_num Z3_API Z3_rcf_sign_condition_coefficient(Z3_context c, Z3_rcf_num a, unsigned i, unsigned j)
|
||||
{
|
||||
Z3_TRY;
|
||||
LOG_Z3_rcf_sign_condition_coefficient(c, a, i, j);
|
||||
RESET_ERROR_CODE();
|
||||
reset_rcf_cancel(c);
|
||||
return from_rcnumeral(rcfm(c).get_sign_condition_coefficient(to_rcnumeral(a), i, j));
|
||||
Z3_CATCH_RETURN(nullptr);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -984,14 +984,14 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
RESET_ERROR_CODE();
|
||||
init_solver(c, s);
|
||||
user_propagator::on_clause_eh_t _on_clause = [=](void* user_ctx, expr* proof, unsigned n, expr* const* _literals) {
|
||||
user_propagator::on_clause_eh_t _on_clause = [=](void* user_ctx, expr* proof, unsigned nd, unsigned const* deps, unsigned n, expr* const* _literals) {
|
||||
Z3_ast_vector_ref * literals = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
|
||||
mk_c(c)->save_object(literals);
|
||||
expr_ref pr(proof, mk_c(c)->m());
|
||||
scoped_ast_vector _sc(literals);
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
literals->m_ast_vector.push_back(_literals[i]);
|
||||
on_clause_eh(user_ctx, of_expr(pr.get()), of_ast_vector(literals));
|
||||
on_clause_eh(user_ctx, of_expr(pr.get()), nd, deps, of_ast_vector(literals));
|
||||
};
|
||||
to_solver_ref(s)->register_on_clause(user_context, _on_clause);
|
||||
auto& solver = *to_solver(s);
|
||||
|
|
|
@ -368,7 +368,7 @@ namespace z3 {
|
|||
func_decl recfun(char const * name, sort const & d1, sort const & d2, sort const & range);
|
||||
|
||||
/**
|
||||
* \brief add function definition body to declaration decl. decl needs to be declared using context::<recfun>.
|
||||
* \brief add function definition body to declaration decl. decl needs to be declared using context::recfun.
|
||||
* @param decl
|
||||
* @param args
|
||||
* @param body
|
||||
|
@ -4214,17 +4214,20 @@ namespace z3 {
|
|||
return expr(ctx(), r);
|
||||
}
|
||||
|
||||
typedef std::function<void(expr const& proof, expr_vector const& clause)> on_clause_eh_t;
|
||||
typedef std::function<void(expr const& proof, std::vector<unsigned> const& deps, expr_vector const& clause)> on_clause_eh_t;
|
||||
|
||||
class on_clause {
|
||||
context& c;
|
||||
on_clause_eh_t m_on_clause;
|
||||
|
||||
static void _on_clause_eh(void* _ctx, Z3_ast _proof, Z3_ast_vector _literals) {
|
||||
static void _on_clause_eh(void* _ctx, Z3_ast _proof, unsigned n, unsigned const* dep, Z3_ast_vector _literals) {
|
||||
on_clause* ctx = static_cast<on_clause*>(_ctx);
|
||||
expr_vector lits(ctx->c, _literals);
|
||||
expr proof(ctx->c, _proof);
|
||||
ctx->m_on_clause(proof, lits);
|
||||
std::vector<unsigned> deps;
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
deps.push_back(dep[i]);
|
||||
ctx->m_on_clause(proof, deps, lits);
|
||||
}
|
||||
public:
|
||||
on_clause(solver& s, on_clause_eh_t& on_clause_eh): c(s.ctx()) {
|
||||
|
|
|
@ -9,7 +9,7 @@ set(VER_TWEAK "${Z3_VERSION_TWEAK}")
|
|||
# Generate Native.cs
|
||||
set(Z3_DOTNET_NATIVE_FILE "${CMAKE_CURRENT_BINARY_DIR}/Native.cs")
|
||||
add_custom_command(OUTPUT "${Z3_DOTNET_NATIVE_FILE}"
|
||||
COMMAND "${PYTHON_EXECUTABLE}"
|
||||
COMMAND "${Python3_EXECUTABLE}"
|
||||
"${PROJECT_SOURCE_DIR}/scripts/update_api.py"
|
||||
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
|
||||
"--dotnet-output-dir"
|
||||
|
@ -25,7 +25,7 @@ add_custom_command(OUTPUT "${Z3_DOTNET_NATIVE_FILE}"
|
|||
# Generate Enumerations.cs
|
||||
set(Z3_DOTNET_CONST_FILE "${CMAKE_CURRENT_BINARY_DIR}/Enumerations.cs")
|
||||
add_custom_command(OUTPUT "${Z3_DOTNET_CONST_FILE}"
|
||||
COMMAND "${PYTHON_EXECUTABLE}"
|
||||
COMMAND "${Python3_EXECUTABLE}"
|
||||
"${PROJECT_SOURCE_DIR}/scripts/mk_consts_files.py"
|
||||
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
|
||||
"--dotnet-output-dir"
|
||||
|
|
|
@ -91,7 +91,13 @@ namespace Microsoft.Z3
|
|||
/// </summary>
|
||||
~Constructor()
|
||||
{
|
||||
Native.Z3_del_constructor(Context.nCtx, NativeObject);
|
||||
if (Context.nCtx != IntPtr.Zero) {
|
||||
lock (Context)
|
||||
{
|
||||
if (Context.nCtx != IntPtr.Zero)
|
||||
Native.Z3_del_constructor(Context.nCtx, NativeObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Internal
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
<AssemblyName>Microsoft.Z3</AssemblyName>
|
||||
<RootNamespace>Microsoft.Z3</RootNamespace>
|
||||
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
|
||||
<Title>Z3 .NET Interface</Title>
|
||||
<AssemblyTitle>Z3 .NET Interface</AssemblyTitle>
|
||||
|
||||
|
@ -15,8 +17,8 @@
|
|||
<Description>Z3 is a satisfiability modulo theories solver from Microsoft Research.</Description>
|
||||
<AssemblyDescription>.NET Interface to the Z3 Theorem Prover</AssemblyDescription>
|
||||
|
||||
<Copyright>Copyright (C) 2006-2019 Microsoft Corporation</Copyright>
|
||||
<AssemblyCopyright>Copyright (C) 2006-2019 Microsoft Corporation</AssemblyCopyright>
|
||||
<Copyright>Copyright (C) 2006- Microsoft Corporation</Copyright>
|
||||
<AssemblyCopyright>Copyright (C) 2006- Microsoft Corporation</AssemblyCopyright>
|
||||
|
||||
<Company>Microsoft Corporation</Company>
|
||||
<AssemblyCompany>Microsoft Corporation</AssemblyCompany>
|
||||
|
@ -65,6 +67,11 @@
|
|||
${Z3_DOTNET_COMPILE_ITEMS}
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Readme -->
|
||||
<ItemGroup>
|
||||
<None Include="${CMAKE_CURRENT_LIST_DIR}/README.md" Pack="true" PackagePath="\"/>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Legacy .NET framework native library helper routines -->
|
||||
<ItemGroup>
|
||||
<Content Include="${CMAKE_CURRENT_LIST_DIR}/Microsoft.Z3.props">
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace Microsoft.Z3
|
|||
using Z3_context = System.IntPtr;
|
||||
using Z3_solver = System.IntPtr;
|
||||
using voidp = System.IntPtr;
|
||||
using uintp = System.IntPtr;
|
||||
using Z3_ast = System.IntPtr;
|
||||
using Z3_ast_vector = System.IntPtr;
|
||||
|
||||
|
@ -60,7 +61,7 @@ namespace Microsoft.Z3
|
|||
|
||||
Native.Z3_on_clause_eh on_clause_eh;
|
||||
|
||||
static void _on_clause(voidp ctx, Z3_ast _proof_hint, Z3_ast_vector _clause)
|
||||
static void _on_clause(voidp ctx, Z3_ast _proof_hint, uint n, uint[] deps, Z3_ast_vector _clause)
|
||||
{
|
||||
var onc = (OnClause)GCHandle.FromIntPtr(ctx).Target;
|
||||
using var proof_hint = Expr.Create(onc.ctx, _proof_hint);
|
||||
|
|
|
@ -220,7 +220,7 @@ namespace Microsoft.Z3
|
|||
/// <summary>
|
||||
/// Check satisfiability of asserted constraints.
|
||||
/// Produce a model that (when the objectives are bounded and
|
||||
/// don't use strict inequalities) meets the objectives.
|
||||
/// don't use strict inequalities) is optimal.
|
||||
/// </summary>
|
||||
///
|
||||
public Status Check(params Expr[] assumptions)
|
||||
|
|
3
src/api/dotnet/README.md
Normal file
3
src/api/dotnet/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Z3 Nuget Package
|
||||
|
||||
For more information see [the Z3 github page](https://github.com/z3prover/z3.git)
|
|
@ -16,7 +16,7 @@ set(Z3_JAVA_PACKAGE_NAME "com.microsoft.z3")
|
|||
set(Z3_JAVA_NATIVE_JAVA "${CMAKE_CURRENT_BINARY_DIR}/Native.java")
|
||||
set(Z3_JAVA_NATIVE_CPP "${CMAKE_CURRENT_BINARY_DIR}/Native.cpp")
|
||||
add_custom_command(OUTPUT "${Z3_JAVA_NATIVE_JAVA}" "${Z3_JAVA_NATIVE_CPP}"
|
||||
COMMAND "${PYTHON_EXECUTABLE}"
|
||||
COMMAND "${Python3_EXECUTABLE}"
|
||||
"${PROJECT_SOURCE_DIR}/scripts/update_api.py"
|
||||
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
|
||||
"--java-input-dir"
|
||||
|
@ -74,7 +74,7 @@ foreach (enum_file ${Z3_JAVA_ENUMERATION_PACKAGE_FILES})
|
|||
)
|
||||
endforeach()
|
||||
add_custom_command(OUTPUT ${Z3_JAVA_ENUMERATION_PACKAGE_FILES_FULL_PATH}
|
||||
COMMAND "${PYTHON_EXECUTABLE}"
|
||||
COMMAND "${Python3_EXECUTABLE}"
|
||||
"${PROJECT_SOURCE_DIR}/scripts/mk_consts_files.py"
|
||||
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
|
||||
"--java-output-dir"
|
||||
|
|
|
@ -193,7 +193,7 @@ public class Optimize extends Z3Object {
|
|||
/**
|
||||
* Check satisfiability of asserted constraints.
|
||||
* Produce a model that (when the objectives are bounded and
|
||||
* don't use strict inequalities) meets the objectives.
|
||||
* don't use strict inequalities) is optimal.
|
||||
**/
|
||||
public Status Check(Expr<BoolSort>... assumptions)
|
||||
{
|
||||
|
|
164
src/api/js/package-lock.json
generated
164
src/api/js/package-lock.json
generated
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"name": "z3-solver",
|
||||
"requires": true,
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": {
|
||||
"version": "2.2.0",
|
||||
|
@ -109,25 +110,6 @@
|
|||
"integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/helper-function-name": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
|
||||
"integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/template": "^7.18.10",
|
||||
"@babel/types": "^7.19.0"
|
||||
}
|
||||
},
|
||||
"@babel/helper-hoist-variables": {
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
|
||||
"integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.18.6"
|
||||
}
|
||||
},
|
||||
"@babel/helper-module-imports": {
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
|
||||
|
@ -361,21 +343,141 @@
|
|||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.19.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.4.tgz",
|
||||
"integrity": "sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==",
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
||||
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.18.6",
|
||||
"@babel/generator": "^7.19.4",
|
||||
"@babel/helper-environment-visitor": "^7.18.9",
|
||||
"@babel/helper-function-name": "^7.19.0",
|
||||
"@babel/helper-hoist-variables": "^7.18.6",
|
||||
"@babel/helper-split-export-declaration": "^7.18.6",
|
||||
"@babel/parser": "^7.19.4",
|
||||
"@babel/types": "^7.19.4",
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/generator": "^7.23.0",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/types": "^7.23.0",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.22.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.22.13",
|
||||
"chalk": "^2.4.2"
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
||||
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.23.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"jsesc": "^2.5.1"
|
||||
}
|
||||
},
|
||||
"@babel/helper-environment-visitor": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/helper-function-name": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.23.0"
|
||||
}
|
||||
},
|
||||
"@babel/helper-hoist-variables": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"@babel/helper-split-export-declaration": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"@babel/helper-string-parser": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
||||
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
|
||||
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/template": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
||||
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/parser": "^7.22.15",
|
||||
"@babel/types": "^7.22.15"
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
|
|
|
@ -69,7 +69,7 @@ const fns = JSON.stringify(exportedFuncs());
|
|||
const methods = '["ccall","FS","allocate","UTF8ToString","intArrayFromString","ALLOC_NORMAL"]';
|
||||
const libz3a = path.normalize('../../../build/libz3.a');
|
||||
spawnSync(
|
||||
`emcc build/async-fns.cc ${libz3a} --std=c++20 --pre-js src/low-level/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=${methods} -s EXPORTED_FUNCTIONS=${fns} -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s DEMANGLE_SUPPORT=1 -s TOTAL_MEMORY=1GB -I z3/src/api/ -o build/z3-built.js`,
|
||||
`emcc build/async-fns.cc ${libz3a} --std=c++20 --pre-js src/low-level/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=${methods} -s EXPORTED_FUNCTIONS=${fns} -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s DEMANGLE_SUPPORT=1 -s TOTAL_MEMORY=1GB -s TOTAL_STACK=20MB -I z3/src/api/ -o build/z3-built.js`,
|
||||
);
|
||||
|
||||
fs.rmSync(ccWrapperPath);
|
||||
|
|
171
src/api/ml/z3.ml
171
src/api/ml/z3.ml
|
@ -26,7 +26,7 @@ struct
|
|||
let (major, minor, build, revision) = Z3native.get_version ()
|
||||
|
||||
let full_version : string = Z3native.get_full_version()
|
||||
|
||||
|
||||
let to_string =
|
||||
string_of_int major ^ "." ^
|
||||
string_of_int minor ^ "." ^
|
||||
|
@ -45,12 +45,12 @@ let mk_list f n =
|
|||
|
||||
let check_int32 v = v = Int32.to_int (Int32.of_int v)
|
||||
|
||||
let mk_int_expr ctx v ty =
|
||||
let mk_int_expr ctx v ty =
|
||||
if not (check_int32 v) then
|
||||
Z3native.mk_numeral ctx (string_of_int v) ty
|
||||
else
|
||||
Z3native.mk_int ctx v ty
|
||||
|
||||
|
||||
let mk_context (settings:(string * string) list) =
|
||||
let cfg = Z3native.mk_config () in
|
||||
let f e = Z3native.set_param_value cfg (fst e) (snd e) in
|
||||
|
@ -62,6 +62,9 @@ let mk_context (settings:(string * string) list) =
|
|||
Z3native.enable_concurrent_dec_ref res;
|
||||
res
|
||||
|
||||
let interrupt (ctx:context) =
|
||||
Z3native.interrupt ctx
|
||||
|
||||
module Symbol =
|
||||
struct
|
||||
type symbol = Z3native.symbol
|
||||
|
@ -721,7 +724,7 @@ struct
|
|||
let mk_exists = _internal_mk_quantifier ~universal:false
|
||||
let mk_exists_const = _internal_mk_quantifier_const ~universal:false
|
||||
let mk_lambda_const ctx bound body = Z3native.mk_lambda_const ctx (List.length bound) bound body
|
||||
let mk_lambda ctx bound body =
|
||||
let mk_lambda ctx bound body =
|
||||
let names = List.map (fun (x,_) -> x) bound in
|
||||
let sorts = List.map (fun (_,y) -> y) bound in
|
||||
Z3native.mk_lambda ctx (List.length bound) sorts names body
|
||||
|
@ -855,15 +858,6 @@ struct
|
|||
module Constructor =
|
||||
struct
|
||||
type constructor = Z3native.constructor
|
||||
|
||||
module FieldNumTable = Hashtbl.Make(struct
|
||||
type t = AST.ast
|
||||
let equal x y = AST.compare x y = 0
|
||||
let hash = AST.hash
|
||||
end)
|
||||
|
||||
let _field_nums = FieldNumTable.create 0
|
||||
|
||||
let create (ctx:context) (name:Symbol.symbol) (recognizer:Symbol.symbol) (field_names:Symbol.symbol list) (sorts:Sort.sort option list) (sort_refs:int list) =
|
||||
let n = List.length field_names in
|
||||
if n <> List.length sorts then
|
||||
|
@ -879,10 +873,9 @@ struct
|
|||
(let f x = match x with None -> Z3native.mk_null_ast ctx | Some s -> s in
|
||||
List.map f sorts)
|
||||
sort_refs in
|
||||
FieldNumTable.add _field_nums no n;
|
||||
no
|
||||
|
||||
let get_num_fields (x:constructor) = FieldNumTable.find _field_nums x
|
||||
let get_num_fields (x:constructor) = Z3native.constructor_num_fields (gc x) x
|
||||
|
||||
let get_constructor_decl (x:constructor) =
|
||||
let (a, _, _) = (Z3native.query_constructor (gc x) x (get_num_fields x)) in
|
||||
|
@ -917,10 +910,10 @@ struct
|
|||
|
||||
let mk_sort_s (ctx:context) (name:string) (constructors:Constructor.constructor list) =
|
||||
mk_sort ctx (Symbol.mk_string ctx name) constructors
|
||||
|
||||
|
||||
let mk_sort_ref (ctx: context) (name:Symbol.symbol) =
|
||||
Z3native.mk_datatype_sort ctx name
|
||||
|
||||
|
||||
let mk_sort_ref_s (ctx: context) (name: string) =
|
||||
mk_sort_ref ctx (Symbol.mk_string ctx name)
|
||||
|
||||
|
@ -1249,7 +1242,7 @@ end
|
|||
module Seq =
|
||||
struct
|
||||
let mk_seq_sort = Z3native.mk_seq_sort
|
||||
let is_seq_sort = Z3native.is_seq_sort
|
||||
let is_seq_sort = Z3native.is_seq_sort
|
||||
let mk_re_sort = Z3native.mk_re_sort
|
||||
let is_re_sort = Z3native.is_re_sort
|
||||
let mk_string_sort = Z3native.mk_string_sort
|
||||
|
@ -1264,7 +1257,7 @@ struct
|
|||
let mk_seq_concat ctx args = Z3native.mk_seq_concat ctx (List.length args) args
|
||||
let mk_seq_prefix = Z3native.mk_seq_prefix
|
||||
let mk_seq_suffix = Z3native.mk_seq_suffix
|
||||
let mk_seq_contains = Z3native.mk_seq_contains
|
||||
let mk_seq_contains = Z3native.mk_seq_contains
|
||||
let mk_seq_extract = Z3native.mk_seq_extract
|
||||
let mk_seq_replace = Z3native.mk_seq_replace
|
||||
let mk_seq_at = Z3native.mk_seq_at
|
||||
|
@ -1509,13 +1502,15 @@ struct
|
|||
in
|
||||
Z3native.apply_result_inc_ref (gc x) arn;
|
||||
let sg = Z3native.apply_result_get_num_subgoals (gc x) arn in
|
||||
let res = if sg = 0 then
|
||||
raise (Error "No subgoals")
|
||||
else
|
||||
Z3native.apply_result_get_subgoal (gc x) arn 0 in
|
||||
Z3native.apply_result_dec_ref (gc x) arn;
|
||||
Z3native.tactic_dec_ref (gc x) tn;
|
||||
res
|
||||
if sg = 0 then (
|
||||
Z3native.apply_result_dec_ref (gc x) arn;
|
||||
Z3native.tactic_dec_ref (gc x) tn;
|
||||
raise (Error "No subgoals"))
|
||||
else
|
||||
let res:goal = Z3native.apply_result_get_subgoal (gc x) arn 0 in
|
||||
Z3native.apply_result_dec_ref (gc x) arn;
|
||||
Z3native.tactic_dec_ref (gc x) tn;
|
||||
res
|
||||
|
||||
let mk_goal = Z3native.mk_goal
|
||||
|
||||
|
@ -1889,9 +1884,9 @@ struct
|
|||
| _ -> UNKNOWN
|
||||
|
||||
let get_model x =
|
||||
try
|
||||
try
|
||||
let q = Z3native.solver_get_model (gc x) x in
|
||||
if Z3native.is_null_model q then None else Some q
|
||||
if Z3native.is_null_model q then None else Some q
|
||||
with | _ -> None
|
||||
|
||||
let get_proof x =
|
||||
|
@ -1916,6 +1911,9 @@ struct
|
|||
let add_simplifier = Z3native.solver_add_simplifier
|
||||
let translate x = Z3native.solver_translate (gc x) x
|
||||
let to_string x = Z3native.solver_to_string (gc x) x
|
||||
|
||||
let interrupt (ctx:context) (s:solver) =
|
||||
Z3native.solver_interrupt ctx s
|
||||
end
|
||||
|
||||
|
||||
|
@ -2077,6 +2075,123 @@ struct
|
|||
end
|
||||
|
||||
|
||||
module RCF =
|
||||
struct
|
||||
type rcf_num = Z3native.rcf_num
|
||||
|
||||
let del (ctx:context) (a:rcf_num) = Z3native.rcf_del ctx a
|
||||
let del_list (ctx:context) (ns:rcf_num list) = List.iter (fun a -> Z3native.rcf_del ctx a) ns
|
||||
let mk_rational (ctx:context) (v:string) = Z3native.rcf_mk_rational ctx v
|
||||
let mk_small_int (ctx:context) (v:int) = Z3native.rcf_mk_small_int ctx v
|
||||
|
||||
let mk_pi (ctx:context) = Z3native.rcf_mk_pi ctx
|
||||
let mk_e (ctx:context) = Z3native.rcf_mk_e ctx
|
||||
let mk_infinitesimal (ctx:context) = Z3native.rcf_mk_infinitesimal ctx
|
||||
|
||||
let mk_roots (ctx:context) (a:rcf_num list) =
|
||||
let n, r = Z3native.rcf_mk_roots ctx (List.length a) a in
|
||||
List.init n (fun x -> List.nth r x)
|
||||
|
||||
let add (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_add ctx a b
|
||||
let sub (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_sub ctx a b
|
||||
let mul (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_mul ctx a b
|
||||
let div (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_div ctx a b
|
||||
|
||||
let neg (ctx:context) (a:rcf_num) = Z3native.rcf_neg ctx a
|
||||
let inv (ctx:context) (a:rcf_num) = Z3native.rcf_neg ctx a
|
||||
|
||||
let power (ctx:context) (a:rcf_num) (k:int) = Z3native.rcf_power ctx a k
|
||||
|
||||
let lt (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_lt ctx a b
|
||||
let gt (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_gt ctx a b
|
||||
let le (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_le ctx a b
|
||||
let ge (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_ge ctx a b
|
||||
let eq (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_eq ctx a b
|
||||
let neq (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_neq ctx a b
|
||||
|
||||
let num_to_string (ctx:context) (a:rcf_num) (compact:bool) (html:bool) = Z3native.rcf_num_to_string ctx a compact html
|
||||
let num_to_decimal_string (ctx:context) (a:rcf_num) (prec:int) = Z3native.rcf_num_to_decimal_string ctx a prec
|
||||
let get_numerator_denominator (ctx:context) (a:rcf_num) = Z3native.rcf_get_numerator_denominator ctx a
|
||||
|
||||
let is_rational (ctx:context) (a:rcf_num) = Z3native.rcf_is_rational ctx a
|
||||
let is_algebraic (ctx:context) (a:rcf_num) = Z3native.rcf_is_algebraic ctx a
|
||||
let is_infinitesimal (ctx:context) (a:rcf_num) = Z3native.rcf_is_infinitesimal ctx a
|
||||
let is_transcendental (ctx:context) (a:rcf_num) = Z3native.rcf_is_transcendental ctx a
|
||||
|
||||
let extension_index (ctx:context) (a:rcf_num) = Z3native.rcf_extension_index ctx a
|
||||
let transcendental_name (ctx:context) (a:rcf_num) = Z3native.rcf_transcendental_name ctx a
|
||||
let infinitesimal_name (ctx:context) (a:rcf_num) = Z3native.rcf_infinitesimal_name ctx a
|
||||
|
||||
let num_coefficients (ctx:context) (a:rcf_num) = Z3native.rcf_num_coefficients ctx a
|
||||
let get_coefficient (ctx:context) (a:rcf_num) (i:int) = Z3native.rcf_coefficient ctx a i
|
||||
|
||||
let coefficients (ctx:context) (a:rcf_num) =
|
||||
List.init (num_coefficients ctx a) (fun i -> Z3native.rcf_coefficient ctx a i)
|
||||
|
||||
type interval = {
|
||||
lower_is_inf : bool;
|
||||
lower_is_open : bool;
|
||||
lower : rcf_num;
|
||||
upper_is_inf : bool;
|
||||
upper_is_open : bool;
|
||||
upper : rcf_num;
|
||||
}
|
||||
|
||||
let root_interval (ctx:context) (a:rcf_num) =
|
||||
let ok, linf, lopen, l, uinf, uopen, u = Z3native.rcf_interval ctx a in
|
||||
let i:interval = {
|
||||
lower_is_inf = linf != 0;
|
||||
lower_is_open = lopen != 0;
|
||||
lower = l;
|
||||
upper_is_inf = uinf != 0;
|
||||
upper_is_open = uopen != 0;
|
||||
upper = u } in
|
||||
if ok != 0 then Some i else None
|
||||
|
||||
let sign_condition_sign (ctx:context) (a:rcf_num) (i:int) = Z3native.rcf_sign_condition_sign ctx a i
|
||||
|
||||
let sign_condition_coefficient (ctx:context) (a:rcf_num) (i:int) (j:int) = Z3native.rcf_sign_condition_coefficient ctx a i j
|
||||
|
||||
let num_sign_condition_coefficients (ctx:context) (a:rcf_num) (i:int) = Z3native.rcf_num_sign_condition_coefficients ctx a i
|
||||
|
||||
let sign_condition_coefficients (ctx:context) (a:rcf_num) (i:int) =
|
||||
let n = Z3native.rcf_num_sign_condition_coefficients ctx a i in
|
||||
List.init n (fun j -> Z3native.rcf_sign_condition_coefficient ctx a i j)
|
||||
|
||||
let sign_conditions (ctx:context) (a:rcf_num) =
|
||||
let n = Z3native.rcf_num_sign_conditions ctx a in
|
||||
List.init n (fun i ->
|
||||
(let nc = Z3native.rcf_num_sign_condition_coefficients ctx a i in
|
||||
List.init nc (fun j -> Z3native.rcf_sign_condition_coefficient ctx a i j)),
|
||||
Z3native.rcf_sign_condition_sign ctx a i)
|
||||
|
||||
type root = {
|
||||
obj : rcf_num;
|
||||
polynomial : rcf_num list;
|
||||
interval : interval option;
|
||||
sign_conditions : (rcf_num list * int) list;
|
||||
}
|
||||
|
||||
let roots (ctx:context) (a:rcf_num list) =
|
||||
let rs = mk_roots ctx a in
|
||||
List.map
|
||||
(fun r -> {
|
||||
obj = r;
|
||||
polynomial = coefficients ctx r;
|
||||
interval = root_interval ctx r;
|
||||
sign_conditions = sign_conditions ctx r})
|
||||
rs
|
||||
|
||||
let del_root (ctx:context) (r:root) =
|
||||
del ctx r.obj;
|
||||
List.iter (fun n -> del ctx n) r.polynomial;
|
||||
List.iter (fun (ns, _) -> del_list ctx ns) r.sign_conditions
|
||||
|
||||
let del_roots (ctx:context) (rs:root list) =
|
||||
List.iter (fun r -> del_root ctx r) rs
|
||||
end
|
||||
|
||||
|
||||
let set_global_param = Z3native.global_param_set
|
||||
|
||||
let get_global_param id =
|
||||
|
|
|
@ -48,6 +48,12 @@ type context
|
|||
*)
|
||||
val mk_context : (string * string) list -> context
|
||||
|
||||
(** Interrupt the execution of a Z3 procedure.
|
||||
|
||||
This procedure can be used to interrupt: solvers, simplifiers and tactics.
|
||||
Note: Tactic.interrupt is an alias for this. *)
|
||||
val interrupt: context -> unit
|
||||
|
||||
(** 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
|
||||
|
@ -1068,13 +1074,13 @@ sig
|
|||
if the corresponding sort reference is 0, then the value in sort_refs should be an index
|
||||
referring to one of the recursive datatypes that is declared. *)
|
||||
val mk_constructor_s : context -> string -> Symbol.symbol -> Symbol.symbol list -> Sort.sort option list -> int list -> Constructor.constructor
|
||||
|
||||
|
||||
(* Create a forward reference to a recursive datatype being declared.
|
||||
The forward reference can be used in a nested occurrence: the range of an array
|
||||
or as element sort of a sequence. The forward reference should only be used when
|
||||
used in an accessor for a recursive datatype that gets declared. *)
|
||||
val mk_sort_ref : context -> Symbol.symbol -> Sort.sort
|
||||
|
||||
|
||||
(* [mk_sort_ref_s ctx s] is [mk_sort_ref ctx (Symbol.mk_string ctx s)] *)
|
||||
val mk_sort_ref_s : context -> string -> Sort.sort
|
||||
|
||||
|
@ -1653,8 +1659,8 @@ sig
|
|||
|
||||
- The \c ceiling of [t1/t2] if \c t2 is different from zero, and [t1*t2 < 0].
|
||||
|
||||
If [t2] is zero, then the result is is not uniquely specified.
|
||||
It can be set to any value that satisfies the constraints
|
||||
If [t2] is zero, then the result is is not uniquely specified.
|
||||
It can be set to any value that satisfies the constraints
|
||||
where signed division is used.
|
||||
The arguments must have the same bit-vector sort. *)
|
||||
val mk_sdiv : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
@ -1662,8 +1668,8 @@ sig
|
|||
(** Unsigned remainder.
|
||||
|
||||
It is defined as [t1 - (t1 /u t2) * t2], where [/u] represents unsigned division.
|
||||
If [t2] is zero, then the result is not uniquely specified.
|
||||
It can be set to any value that satisfies the constraints
|
||||
If [t2] is zero, then the result is not uniquely specified.
|
||||
It can be set to any value that satisfies the constraints
|
||||
where unsigned remainder is used.
|
||||
The arguments must have the same bit-vector sort. *)
|
||||
val mk_urem : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
@ -1673,16 +1679,16 @@ sig
|
|||
It is defined as [t1 - (t1 /s t2) * t2], where [/s] represents signed division.
|
||||
The most significant bit (sign) of the result is equal to the most significant bit of \c t1.
|
||||
|
||||
If [t2] is zero, then the result is not uniquely specified.
|
||||
It can be set to any value that satisfies the constraints
|
||||
If [t2] is zero, then the result is not uniquely specified.
|
||||
It can be set to any value that satisfies the constraints
|
||||
where signed remainder is used.
|
||||
The arguments must have the same bit-vector sort. *)
|
||||
val mk_srem : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** Two's complement signed remainder (sign follows divisor).
|
||||
|
||||
If [t2] is zero, then the result is not uniquely specified.
|
||||
It can be set to any value that satisfies the constraints
|
||||
If [t2] is zero, then the result is not uniquely specified.
|
||||
It can be set to any value that satisfies the constraints
|
||||
where two's complement signed remainder is used.
|
||||
The arguments must have the same bit-vector sort. *)
|
||||
val mk_smod : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
@ -1864,7 +1870,7 @@ sig
|
|||
end
|
||||
|
||||
(** Sequences, Strings and Regular Expressions **)
|
||||
module Seq :
|
||||
module Seq :
|
||||
sig
|
||||
(** create a sequence sort *)
|
||||
val mk_seq_sort : context -> Sort.sort -> Sort.sort
|
||||
|
@ -1872,9 +1878,9 @@ sig
|
|||
(** test if sort is a sequence sort *)
|
||||
val is_seq_sort : context -> Sort.sort -> bool
|
||||
|
||||
(** create regular expression sorts over sequences of the argument sort *)
|
||||
(** create regular expression sorts over sequences of the argument sort *)
|
||||
val mk_re_sort : context -> Sort.sort -> Sort.sort
|
||||
|
||||
|
||||
(** test if sort is a regular expression sort *)
|
||||
val is_re_sort : context -> Sort.sort -> bool
|
||||
|
||||
|
@ -1885,7 +1891,7 @@ sig
|
|||
val mk_char_sort : context -> Sort.sort
|
||||
|
||||
(** test if sort is a string sort (a sequence of 8-bit bit-vectors) *)
|
||||
val is_string_sort : context -> Sort.sort -> bool
|
||||
val is_string_sort : context -> Sort.sort -> bool
|
||||
|
||||
(** test if sort is a char sort *)
|
||||
val is_char_sort : context -> Sort.sort -> bool
|
||||
|
@ -1894,51 +1900,51 @@ sig
|
|||
val mk_string : context -> string -> Expr.expr
|
||||
|
||||
(** test if expression is a string *)
|
||||
val is_string : context -> Expr.expr -> bool
|
||||
val is_string : context -> Expr.expr -> bool
|
||||
|
||||
(** retrieve string from string Expr.expr *)
|
||||
val get_string : context -> Expr.expr -> string
|
||||
val get_string : context -> Expr.expr -> string
|
||||
|
||||
(** the empty sequence over base sort *)
|
||||
val mk_seq_empty : context -> Sort.sort -> Expr.expr
|
||||
val mk_seq_empty : context -> Sort.sort -> Expr.expr
|
||||
|
||||
(** a unit sequence *)
|
||||
val mk_seq_unit : context -> Expr.expr -> Expr.expr
|
||||
val mk_seq_unit : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** sequence concatenation *)
|
||||
val mk_seq_concat : context -> Expr.expr list -> Expr.expr
|
||||
val mk_seq_concat : context -> Expr.expr list -> Expr.expr
|
||||
|
||||
(** predicate if the first argument is a prefix of the second *)
|
||||
val mk_seq_prefix : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
val mk_seq_prefix : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** predicate if the first argument is a suffix of the second *)
|
||||
val mk_seq_suffix : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
val mk_seq_suffix : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** predicate if the first argument contains the second *)
|
||||
val mk_seq_contains : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
val mk_seq_contains : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** extract sub-sequence starting at index given by second argument and of length provided by third argument *)
|
||||
val mk_seq_extract : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
val mk_seq_extract : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** replace first occurrence of second argument by third *)
|
||||
val mk_seq_replace : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
val mk_seq_replace : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** a unit sequence at index provided by second argument *)
|
||||
val mk_seq_at : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
val mk_seq_at : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** length of a sequence *)
|
||||
val mk_seq_length : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** [mk_seq_nth ctx s index] retrieves from [s] the element at position [index].
|
||||
val mk_seq_length : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** [mk_seq_nth ctx s index] retrieves from [s] the element at position [index].
|
||||
The function is under-specified if the index is out of bounds. *)
|
||||
val mk_seq_nth : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** index of the first occurrence of the second argument in the first *)
|
||||
val mk_seq_index : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
val mk_seq_index : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** [mk_seq_last_index ctx s substr] occurence of [substr] in the sequence [s] *)
|
||||
val mk_seq_last_index : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
|
||||
(** retrieve integer expression encoded in string *)
|
||||
val mk_str_to_int : context -> Expr.expr -> Expr.expr
|
||||
|
||||
|
@ -1950,7 +1956,7 @@ sig
|
|||
val mk_str_lt : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** convert an integer expression to a string *)
|
||||
val mk_int_to_str : context -> Expr.expr -> Expr.expr
|
||||
val mk_int_to_str : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** [mk_string_to_code ctx s] convert a unit length string [s] to integer code *)
|
||||
val mk_string_to_code : context -> Expr.expr -> Expr.expr
|
||||
|
@ -1965,43 +1971,43 @@ sig
|
|||
val mk_sbv_to_str : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** create regular expression that accepts the argument sequence *)
|
||||
val mk_seq_to_re : context -> Expr.expr -> Expr.expr
|
||||
val mk_seq_to_re : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** regular expression membership predicate *)
|
||||
val mk_seq_in_re : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
val mk_seq_in_re : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** regular expression plus *)
|
||||
val mk_re_plus : context -> Expr.expr -> Expr.expr
|
||||
val mk_re_plus : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** regular expression star *)
|
||||
val mk_re_star : context -> Expr.expr -> Expr.expr
|
||||
val mk_re_star : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** optional regular expression *)
|
||||
val mk_re_option : context -> Expr.expr -> Expr.expr
|
||||
val mk_re_option : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** union of regular expressions *)
|
||||
val mk_re_union : context -> Expr.expr list -> Expr.expr
|
||||
val mk_re_union : context -> Expr.expr list -> Expr.expr
|
||||
|
||||
(** concatenation of regular expressions *)
|
||||
val mk_re_concat : context -> Expr.expr list -> Expr.expr
|
||||
|
||||
val mk_re_concat : context -> Expr.expr list -> Expr.expr
|
||||
|
||||
(** regular expression for the range between two characters *)
|
||||
val mk_re_range : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
val mk_re_range : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** bounded loop regular expression *)
|
||||
val mk_re_loop : context -> Expr.expr -> int -> int -> Expr.expr
|
||||
|
||||
val mk_re_loop : context -> Expr.expr -> int -> int -> Expr.expr
|
||||
|
||||
(** intersection of regular expressions *)
|
||||
val mk_re_intersect : context -> Expr.expr list -> Expr.expr
|
||||
|
||||
(** the regular expression complement *)
|
||||
val mk_re_complement : context -> Expr.expr -> Expr.expr
|
||||
val mk_re_complement : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** the regular expression that accepts no sequences *)
|
||||
val mk_re_empty : context -> Sort.sort -> Expr.expr
|
||||
val mk_re_empty : context -> Sort.sort -> Expr.expr
|
||||
|
||||
(** the regular expression that accepts all sequences *)
|
||||
val mk_re_full : context -> Sort.sort -> Expr.expr
|
||||
val mk_re_full : context -> Sort.sort -> Expr.expr
|
||||
|
||||
(** [mk_char ctx i] converts an integer to a character *)
|
||||
val mk_char : context -> int -> Expr.expr
|
||||
|
@ -2339,7 +2345,7 @@ sig
|
|||
(** Retrieves the sign of a floating-point literal. *)
|
||||
val get_numeral_sign : context -> Expr.expr -> bool * int
|
||||
|
||||
(** Return the sign of a floating-point numeral as a bit-vector expression.
|
||||
(** Return the sign of a floating-point numeral as a bit-vector expression.
|
||||
Remark: NaN's do not have a bit-vector sign, so they are invalid arguments. *)
|
||||
val get_numeral_sign_bv : context -> Expr.expr -> Expr.expr
|
||||
|
||||
|
@ -2349,11 +2355,11 @@ sig
|
|||
(** Return the exponent value of a floating-point numeral as a signed integer *)
|
||||
val get_numeral_exponent_int : context -> Expr.expr -> bool -> bool * int64
|
||||
|
||||
(** Return the exponent of a floating-point numeral as a bit-vector expression.
|
||||
(** 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. *)
|
||||
val get_numeral_exponent_bv : context -> Expr.expr -> bool -> Expr.expr
|
||||
|
||||
(** Return the significand value of a floating-point numeral as a bit-vector expression.
|
||||
(** Return the significand value of a floating-point numeral as a bit-vector expression.
|
||||
Remark: NaN's do not have a bit-vector significand, so they are invalid arguments. *)
|
||||
val get_numeral_significand_bv : context -> Expr.expr -> Expr.expr
|
||||
|
||||
|
@ -2386,7 +2392,7 @@ sig
|
|||
|
||||
(** Indicates whether a floating-point numeral is negative. *)
|
||||
val is_numeral_negative : context -> Expr.expr -> bool
|
||||
|
||||
|
||||
(** Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. *)
|
||||
val mk_to_ieee_bv : context -> Expr.expr -> Expr.expr
|
||||
|
||||
|
@ -3260,7 +3266,7 @@ sig
|
|||
|
||||
(** Assert multiple constraints (cs) into the solver, and track them (in the
|
||||
unsat) core using the Boolean constants in ps.
|
||||
|
||||
|
||||
This API is an alternative to {!check} with assumptions for extracting unsat cores.
|
||||
Both APIs can be used in the same solver. The unsat core will contain a combination
|
||||
of the Boolean variables provided using {!assert_and_track} and the Boolean literals
|
||||
|
@ -3269,10 +3275,10 @@ sig
|
|||
|
||||
(** Assert a constraint (c) into the solver, and track it (in the unsat) core
|
||||
using the Boolean constant p.
|
||||
|
||||
This API is an alternative to {!check} with assumptions for extracting unsat cores.
|
||||
Both APIs can be used in the same solver. The unsat core will contain a combination
|
||||
of the Boolean variables provided using {!assert_and_track} and the Boolean literals
|
||||
|
||||
This API is an alternative to {!check} with assumptions for extracting unsat cores.
|
||||
Both APIs can be used in the same solver. The unsat core will contain a combination
|
||||
of the Boolean variables provided using {!assert_and_track} and the Boolean literals
|
||||
provided using {!check} with assumptions. *)
|
||||
val assert_and_track : solver -> Expr.expr -> Expr.expr -> unit
|
||||
|
||||
|
@ -3342,6 +3348,15 @@ sig
|
|||
|
||||
(** A string representation of the solver. *)
|
||||
val to_string : solver -> string
|
||||
|
||||
(** Solver local interrupt.
|
||||
|
||||
Normally you should use Z3_interrupt to cancel solvers because only
|
||||
one solver is enabled concurrently per context.
|
||||
However, per GitHub issue #1006, there are use cases where
|
||||
it is more convenient to cancel a specific solver. Solvers
|
||||
that are not selected for interrupts are left alone.*)
|
||||
val interrupt: context -> solver -> unit
|
||||
end
|
||||
|
||||
(** Fixedpoint solving *)
|
||||
|
@ -3466,7 +3481,7 @@ sig
|
|||
(** Add minimization objective. *)
|
||||
val minimize : optimize -> Expr.expr -> handle
|
||||
|
||||
(** Checks whether the assertions in the context are satisfiable and solves objectives. *)
|
||||
(** Check consistency and produce optimal values. *)
|
||||
val check : optimize -> Solver.status
|
||||
|
||||
(** Retrieve model from satisfiable context *)
|
||||
|
@ -3496,23 +3511,23 @@ sig
|
|||
val get_statistics : optimize -> Statistics.statistics
|
||||
|
||||
(** Parse an SMT-LIB2 file with assertions, soft constraints and optimization
|
||||
objectives. Add the parsed constraints and objectives to the optimization
|
||||
objectives. Add the parsed constraints and objectives to the optimization
|
||||
context. *)
|
||||
val from_file : optimize -> string -> unit
|
||||
|
||||
(** Parse an SMT-LIB2 string with assertions, soft constraints and optimization
|
||||
objectives. Add the parsed constraints and objectives to the optimization
|
||||
(** Parse an SMT-LIB2 string with assertions, soft constraints and optimization
|
||||
objectives. Add the parsed constraints and objectives to the optimization
|
||||
context. *)
|
||||
val from_string : optimize -> string -> unit
|
||||
|
||||
(** Return the set of asserted formulas on the optimization context. *)
|
||||
|
||||
(** Return the set of asserted formulas on the optimization context. *)
|
||||
val get_assertions : optimize -> Expr.expr list
|
||||
|
||||
(** Return objectives on the optimization context. If the objective function
|
||||
is a max-sat objective it is returned as a Pseudo-Boolean (minimization)
|
||||
sum of the form (+ (if f1 w1 0) (if f2 w2 0) ...). If the objective
|
||||
function is entered as a maximization objective, then return the
|
||||
corresponding minimization objective. In this way the resulting
|
||||
(** Return objectives on the optimization context. If the objective function
|
||||
is a max-sat objective it is returned as a Pseudo-Boolean (minimization)
|
||||
sum of the form (+ (if f1 w1 0) (if f2 w2 0) ...). If the objective
|
||||
function is entered as a maximization objective, then return the
|
||||
corresponding minimization objective. In this way the resulting
|
||||
objective function is always returned as a minimization objective. *)
|
||||
val get_objectives : optimize -> Expr.expr list
|
||||
end
|
||||
|
@ -3535,6 +3550,151 @@ sig
|
|||
val parse_smtlib2_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> AST.ASTVector.ast_vector
|
||||
end
|
||||
|
||||
(** Real closed field *)
|
||||
module RCF :
|
||||
sig
|
||||
type rcf_num
|
||||
|
||||
(** Delete a RCF numeral created using the RCF API. *)
|
||||
val del : context -> rcf_num -> unit
|
||||
|
||||
(** Delete RCF numerals created using the RCF API. *)
|
||||
val del_list : context -> rcf_num list -> unit
|
||||
|
||||
(** Return a RCF rational using the given string. *)
|
||||
val mk_rational : context -> string -> rcf_num
|
||||
|
||||
(** Return a RCF small integer. *)
|
||||
val mk_small_int : context -> int -> rcf_num
|
||||
|
||||
(** Return Pi *)
|
||||
val mk_pi : context -> rcf_num
|
||||
|
||||
(** Return e (Euler's constant) *)
|
||||
val mk_e : context -> rcf_num
|
||||
|
||||
(** Return a new infinitesimal that is smaller than all elements in the Z3 field. *)
|
||||
val mk_infinitesimal : context -> rcf_num
|
||||
|
||||
(** Extract the roots of a polynomial. Precondition: The input polynomial is not the zero polynomial. *)
|
||||
val mk_roots : context -> rcf_num list -> rcf_num list
|
||||
|
||||
(** Addition *)
|
||||
val add : context -> rcf_num -> rcf_num -> rcf_num
|
||||
|
||||
(** Subtraction *)
|
||||
val sub : context -> rcf_num -> rcf_num -> rcf_num
|
||||
|
||||
(** Multiplication *)
|
||||
val mul : context -> rcf_num -> rcf_num -> rcf_num
|
||||
|
||||
(** Division *)
|
||||
val div : context -> rcf_num -> rcf_num -> rcf_num
|
||||
|
||||
(** Negation *)
|
||||
val neg : context -> rcf_num -> rcf_num
|
||||
|
||||
(** Multiplicative Inverse *)
|
||||
val inv : context -> rcf_num -> rcf_num
|
||||
|
||||
(** Power *)
|
||||
val power : context -> rcf_num -> int -> rcf_num
|
||||
|
||||
(** less-than *)
|
||||
val lt : context -> rcf_num -> rcf_num -> bool
|
||||
|
||||
(** greater-than *)
|
||||
val gt : context -> rcf_num -> rcf_num -> bool
|
||||
|
||||
(** less-than or equal *)
|
||||
val le : context -> rcf_num -> rcf_num -> bool
|
||||
|
||||
(** greater-than or equal *)
|
||||
val ge : context -> rcf_num -> rcf_num -> bool
|
||||
|
||||
(** equality *)
|
||||
val eq : context -> rcf_num -> rcf_num -> bool
|
||||
|
||||
(** not equal *)
|
||||
val neq : context -> rcf_num -> rcf_num -> bool
|
||||
|
||||
(** Convert the RCF numeral into a string. *)
|
||||
val num_to_string : context -> rcf_num -> bool -> bool -> string
|
||||
|
||||
(** Convert the RCF numeral into a string in decimal notation. *)
|
||||
val num_to_decimal_string : context -> rcf_num -> int -> string
|
||||
|
||||
(** Extract the "numerator" and "denominator" of the given RCF numeral.
|
||||
We have that \ccode{a = n/d}, moreover \c n and \c d are not represented using rational functions. *)
|
||||
val get_numerator_denominator : context -> rcf_num -> (rcf_num * rcf_num)
|
||||
|
||||
(** Return \c true if \c a represents a rational number. *)
|
||||
val is_rational : context -> rcf_num -> bool
|
||||
|
||||
(** Return \c true if \c a represents an algebraic number. *)
|
||||
val is_algebraic : context -> rcf_num -> bool
|
||||
|
||||
(** Return \c true if \c a represents an infinitesimal. *)
|
||||
val is_infinitesimal : context -> rcf_num -> bool
|
||||
|
||||
(** Return \c true if \c a represents a transcendental number. *)
|
||||
val is_transcendental : context -> rcf_num -> bool
|
||||
|
||||
(** Return the index of a field extension. *)
|
||||
val extension_index : context -> rcf_num -> int
|
||||
|
||||
(** Return the name of a transcendental. *)
|
||||
val transcendental_name : context -> rcf_num -> Symbol.symbol
|
||||
|
||||
(** Return the name of an infinitesimal. *)
|
||||
val infinitesimal_name : context -> rcf_num -> Symbol.symbol
|
||||
|
||||
(** Return the number of coefficients in an algebraic number. *)
|
||||
val num_coefficients : context -> rcf_num -> int
|
||||
|
||||
(** Extract a coefficient from an algebraic number. *)
|
||||
val get_coefficient : context -> rcf_num -> int -> rcf_num
|
||||
|
||||
(** Extract the coefficients from an algebraic number. *)
|
||||
val coefficients : context -> rcf_num -> rcf_num list
|
||||
|
||||
(** Extract the sign of a sign condition from an algebraic number. *)
|
||||
val sign_condition_sign : context -> rcf_num -> int -> int
|
||||
|
||||
(** Return the size of a sign condition polynomial. *)
|
||||
val num_sign_condition_coefficients : context -> rcf_num -> int -> int
|
||||
|
||||
(** Extract a sign condition polynomial coefficient from an algebraic number. *)
|
||||
val sign_condition_coefficient : context -> rcf_num -> int -> int -> rcf_num
|
||||
|
||||
(** Extract sign conditions from an algebraic number. *)
|
||||
val sign_conditions : context -> rcf_num -> (rcf_num list * int) list
|
||||
|
||||
(** Extract the interval from an algebraic number. *)
|
||||
type interval = {
|
||||
lower_is_inf : bool;
|
||||
lower_is_open : bool;
|
||||
lower : rcf_num;
|
||||
upper_is_inf : bool;
|
||||
upper_is_open : bool;
|
||||
upper : rcf_num;
|
||||
}
|
||||
|
||||
val root_interval : context -> rcf_num -> interval option
|
||||
|
||||
type root = {
|
||||
obj : rcf_num;
|
||||
polynomial : rcf_num list;
|
||||
interval : interval option;
|
||||
sign_conditions : (rcf_num list * int) list;
|
||||
}
|
||||
|
||||
val roots : context -> rcf_num list -> root list
|
||||
|
||||
val del_root : context -> root -> unit
|
||||
|
||||
val del_roots : context -> root list -> unit
|
||||
end
|
||||
|
||||
(** Set a global (or module) parameter, which is shared by all Z3 contexts.
|
||||
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef __STDC_NO_ATOMICS__
|
||||
#include <stdatomic.h>
|
||||
#else
|
||||
#define _Atomic(T) T
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -118,7 +124,7 @@ int compare_pointers(void* pt1, void* pt2) {
|
|||
blocks that get copied. */
|
||||
typedef struct {
|
||||
Z3_context ctx;
|
||||
unsigned long obj_count;
|
||||
_Atomic(unsigned long) obj_count;
|
||||
} Z3_context_plus_data;
|
||||
|
||||
/* A context is wrapped to an OCaml value by storing a pointer
|
||||
|
|
|
@ -33,7 +33,7 @@ endforeach()
|
|||
|
||||
# Generate z3core.py
|
||||
add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3core.py"
|
||||
COMMAND "${PYTHON_EXECUTABLE}"
|
||||
COMMAND "${Python3_EXECUTABLE}"
|
||||
"${PROJECT_SOURCE_DIR}/scripts/update_api.py"
|
||||
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
|
||||
"--z3py-output-dir"
|
||||
|
@ -49,7 +49,7 @@ list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}
|
|||
|
||||
# Generate z3consts.py
|
||||
add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3consts.py"
|
||||
COMMAND "${PYTHON_EXECUTABLE}"
|
||||
COMMAND "${Python3_EXECUTABLE}"
|
||||
"${PROJECT_SOURCE_DIR}/scripts/mk_consts_files.py"
|
||||
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
|
||||
"--z3py-output-dir"
|
||||
|
@ -96,7 +96,7 @@ if (Z3_INSTALL_PYTHON_BINDINGS)
|
|||
if (NOT DEFINED CMAKE_INSTALL_PYTHON_PKG_DIR)
|
||||
message(STATUS "CMAKE_INSTALL_PYTHON_PKG_DIR not set. Trying to guess")
|
||||
execute_process(
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "-c"
|
||||
COMMAND "${Python3_EXECUTABLE}" "-c"
|
||||
"import sysconfig; print(sysconfig.get_path('purelib'))"
|
||||
RESULT_VARIABLE exit_code
|
||||
OUTPUT_VARIABLE CMAKE_INSTALL_PYTHON_PKG_DIR
|
||||
|
|
|
@ -18,7 +18,7 @@ from setuptools.command.bdist_egg import bdist_egg as _bdist_egg
|
|||
|
||||
build_env = dict(os.environ)
|
||||
build_env['PYTHON'] = sys.executable
|
||||
build_env['CXXFLAGS'] = build_env.get('CXXFLAGS', '') + " -std=c++11"
|
||||
build_env['CXXFLAGS'] = build_env.get('CXXFLAGS', '') + " -std=c++17"
|
||||
|
||||
# determine where we're building and where sources are
|
||||
ROOT_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
|
|
|
@ -683,6 +683,8 @@ def _to_sort_ref(s, ctx):
|
|||
return SeqSortRef(s, ctx)
|
||||
elif k == Z3_CHAR_SORT:
|
||||
return CharSortRef(s, ctx)
|
||||
elif k == Z3_TYPE_VAR:
|
||||
return TypeVarRef(s, ctx)
|
||||
return SortRef(s, ctx)
|
||||
|
||||
|
||||
|
@ -708,6 +710,26 @@ def DeclareSort(name, ctx=None):
|
|||
ctx = _get_ctx(ctx)
|
||||
return SortRef(Z3_mk_uninterpreted_sort(ctx.ref(), to_symbol(name, ctx)), ctx)
|
||||
|
||||
class TypeVarRef(SortRef):
|
||||
"""Type variable reference"""
|
||||
|
||||
def subsort(self, other):
|
||||
return True
|
||||
|
||||
def cast(self, val):
|
||||
return val
|
||||
|
||||
|
||||
def DeclareTypeVar(name, ctx=None):
|
||||
"""Create a new type variable named `name`.
|
||||
|
||||
If `ctx=None`, then the new sort is declared in the global Z3Py context.
|
||||
|
||||
"""
|
||||
ctx = _get_ctx(ctx)
|
||||
return TypeVarRef(Z3_mk_type_variable(ctx.ref(), to_symbol(name, ctx)), ctx)
|
||||
|
||||
|
||||
#########################################
|
||||
#
|
||||
# Function Declarations
|
||||
|
@ -1549,6 +1571,14 @@ class BoolRef(ExprRef):
|
|||
def sort(self):
|
||||
return BoolSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx)
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, BoolRef):
|
||||
other = If(other, 1, 0)
|
||||
return If(self, 1, 0) + other
|
||||
|
||||
def __radd__(self, other):
|
||||
return self + other
|
||||
|
||||
def __rmul__(self, other):
|
||||
return self * other
|
||||
|
||||
|
@ -1562,6 +1592,20 @@ class BoolRef(ExprRef):
|
|||
if isinstance(other, BoolRef):
|
||||
other = If(other, 1, 0)
|
||||
return If(self, other, 0)
|
||||
|
||||
def __and__(self, other):
|
||||
return And(self, other)
|
||||
|
||||
def __or__(self, other):
|
||||
return Or(self, other)
|
||||
|
||||
def __xor__(self, other):
|
||||
return Xor(self, other)
|
||||
|
||||
def __invert__(self):
|
||||
return Not(self)
|
||||
|
||||
|
||||
|
||||
|
||||
def is_bool(a):
|
||||
|
@ -2059,6 +2103,16 @@ class QuantifierRef(BoolRef):
|
|||
"""
|
||||
return int(Z3_get_quantifier_weight(self.ctx_ref(), self.ast))
|
||||
|
||||
def skolem_id(self):
|
||||
"""Return the skolem id of `self`.
|
||||
"""
|
||||
return _symbol2py(self.ctx, Z3_get_quantifier_skolem_id(self.ctx_ref(), self.ast))
|
||||
|
||||
def qid(self):
|
||||
"""Return the quantifier id of `self`.
|
||||
"""
|
||||
return _symbol2py(self.ctx, Z3_get_quantifier_id(self.ctx_ref(), self.ast))
|
||||
|
||||
def num_patterns(self):
|
||||
"""Return the number of patterns (i.e., quantifier instantiation hints) in `self`.
|
||||
|
||||
|
@ -6909,6 +6963,13 @@ class Solver(Z3PPObject):
|
|||
if self.solver is not None and self.ctx.ref() is not None and Z3_solver_dec_ref is not None:
|
||||
Z3_solver_dec_ref(self.ctx.ref(), self.solver)
|
||||
|
||||
def __enter__(self):
|
||||
self.push()
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc_info):
|
||||
self.pop()
|
||||
|
||||
def set(self, *args, **keys):
|
||||
"""Set a configuration option.
|
||||
The method `help()` return a string containing all available options.
|
||||
|
@ -7993,7 +8054,7 @@ class Optimize(Z3PPObject):
|
|||
Z3_optimize_pop(self.ctx.ref(), self.optimize)
|
||||
|
||||
def check(self, *assumptions):
|
||||
"""Check satisfiability while optimizing objective functions."""
|
||||
"""Check consistency and produce optimal values."""
|
||||
assumptions = _get_args(assumptions)
|
||||
num = len(assumptions)
|
||||
_assumptions = (Ast * num)()
|
||||
|
@ -11416,11 +11477,12 @@ def to_AstVectorObj(ptr,):
|
|||
# for UserPropagator we use a global dictionary, which isn't great code.
|
||||
|
||||
_my_hacky_class = None
|
||||
def on_clause_eh(ctx, p, clause):
|
||||
def on_clause_eh(ctx, p, n, dep, clause):
|
||||
onc = _my_hacky_class
|
||||
p = _to_expr_ref(to_Ast(p), onc.ctx)
|
||||
clause = AstVector(to_AstVectorObj(clause), onc.ctx)
|
||||
onc.on_clause(p, clause)
|
||||
deps = [dep[i] for i in range(n)]
|
||||
onc.on_clause(p, deps, clause)
|
||||
|
||||
_on_clause_eh = Z3_on_clause_eh(on_clause_eh)
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ Notes:
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "z3_macros.h"
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#pragma once
|
||||
|
||||
DEFINE_TYPE(Z3_symbol);
|
||||
DEFINE_TYPE(Z3_literals);
|
||||
DEFINE_TYPE(Z3_config);
|
||||
DEFINE_TYPE(Z3_context);
|
||||
DEFINE_TYPE(Z3_sort);
|
||||
|
@ -151,6 +150,7 @@ typedef enum
|
|||
Z3_SEQ_SORT,
|
||||
Z3_RE_SORT,
|
||||
Z3_CHAR_SORT,
|
||||
Z3_TYPE_VAR,
|
||||
Z3_UNKNOWN_SORT = 1000
|
||||
} Z3_sort_kind;
|
||||
|
||||
|
@ -1397,7 +1397,6 @@ typedef enum
|
|||
def_Type('FUNC_DECL', 'Z3_func_decl', 'FuncDecl')
|
||||
def_Type('PATTERN', 'Z3_pattern', 'Pattern')
|
||||
def_Type('MODEL', 'Z3_model', 'ModelObj')
|
||||
def_Type('LITERALS', 'Z3_literals', 'Literals')
|
||||
def_Type('CONSTRUCTOR', 'Z3_constructor', 'Constructor')
|
||||
def_Type('CONSTRUCTOR_LIST', 'Z3_constructor_list', 'ConstructorList')
|
||||
def_Type('SOLVER', 'Z3_solver', 'SolverObj')
|
||||
|
@ -1436,7 +1435,7 @@ Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as
|
|||
Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb));
|
||||
Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t));
|
||||
Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t, unsigned idx, bool phase));
|
||||
Z3_DECLARE_CLOSURE(Z3_on_clause_eh, void, (void* ctx, Z3_ast proof_hint, Z3_ast_vector literals));
|
||||
Z3_DECLARE_CLOSURE(Z3_on_clause_eh, void, (void* ctx, Z3_ast proof_hint, unsigned n, unsigned const* deps, Z3_ast_vector literals));
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1883,6 +1882,17 @@ extern "C" {
|
|||
*/
|
||||
Z3_sort Z3_API Z3_mk_uninterpreted_sort(Z3_context c, Z3_symbol s);
|
||||
|
||||
/**
|
||||
\brief Create a type variable.
|
||||
|
||||
Functions using type variables can be applied to instantiations that match the signature
|
||||
of the function. Assertions using type variables correspond to assertions over all possible
|
||||
instantiations.
|
||||
|
||||
def_API('Z3_mk_type_variable', SORT, (_in(CONTEXT), _in(SYMBOL)))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_type_variable(Z3_context c, Z3_symbol s);
|
||||
|
||||
/**
|
||||
\brief Create the Boolean type.
|
||||
|
||||
|
@ -2072,6 +2082,16 @@ extern "C" {
|
|||
unsigned sort_refs[]
|
||||
);
|
||||
|
||||
/**
|
||||
\brief Retrieve the number of fields of a constructor
|
||||
|
||||
\param c logical context.
|
||||
\param constr constructor.
|
||||
|
||||
def_API('Z3_constructor_num_fields', UINT, (_in(CONTEXT), _in(CONSTRUCTOR)))
|
||||
*/
|
||||
unsigned Z3_API Z3_constructor_num_fields(Z3_context c, Z3_constructor constr);
|
||||
|
||||
/**
|
||||
\brief Reclaim memory allocated to constructor.
|
||||
|
||||
|
@ -5186,6 +5206,24 @@ extern "C" {
|
|||
*/
|
||||
unsigned Z3_API Z3_get_quantifier_weight(Z3_context c, Z3_ast a);
|
||||
|
||||
/**
|
||||
\brief Obtain skolem id of quantifier.
|
||||
|
||||
\pre Z3_get_ast_kind(a) == Z3_QUANTIFIER_AST
|
||||
|
||||
def_API('Z3_get_quantifier_skolem_id', SYMBOL, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
Z3_symbol Z3_API Z3_get_quantifier_skolem_id(Z3_context c, Z3_ast a);
|
||||
|
||||
/**
|
||||
\brief Obtain id of quantifier.
|
||||
|
||||
\pre Z3_get_ast_kind(a) == Z3_QUANTIFIER_AST
|
||||
|
||||
def_API('Z3_get_quantifier_id', SYMBOL, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
Z3_symbol Z3_API Z3_get_quantifier_id(Z3_context c, Z3_ast a);
|
||||
|
||||
/**
|
||||
\brief Return number of patterns used in quantifier.
|
||||
|
||||
|
@ -5584,14 +5622,14 @@ extern "C" {
|
|||
void Z3_API Z3_add_const_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast a);
|
||||
|
||||
/**
|
||||
\brief Increment the reference counter of the given Z3_func_interp object.
|
||||
\brief Increment the reference counter of the given \c Z3_func_interp object.
|
||||
|
||||
def_API('Z3_func_interp_inc_ref', VOID, (_in(CONTEXT), _in(FUNC_INTERP)))
|
||||
*/
|
||||
void Z3_API Z3_func_interp_inc_ref(Z3_context c, Z3_func_interp f);
|
||||
|
||||
/**
|
||||
\brief Decrement the reference counter of the given Z3_func_interp object.
|
||||
\brief Decrement the reference counter of the given \c Z3_func_interp object.
|
||||
|
||||
def_API('Z3_func_interp_dec_ref', VOID, (_in(CONTEXT), _in(FUNC_INTERP)))
|
||||
*/
|
||||
|
|
256
src/api/z3_fpa.h
256
src/api/z3_fpa.h
|
@ -32,6 +32,12 @@ extern "C" {
|
|||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_away or Z3_mk_fpa_rna
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_even or Z3_mk_fpa_rne
|
||||
\sa Z3_mk_fpa_round_toward_negative or Z3_mk_fpa_rtn
|
||||
\sa Z3_mk_fpa_round_toward_positive or Z3_mk_fpa_rtp
|
||||
\sa Z3_mk_fpa_round_toward_zero or Z3_mk_fpa_rtz
|
||||
|
||||
def_API('Z3_mk_fpa_rounding_mode_sort', SORT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_rounding_mode_sort(Z3_context c);
|
||||
|
@ -39,8 +45,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_rne.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_away
|
||||
\sa Z3_mk_fpa_round_toward_negative
|
||||
\sa Z3_mk_fpa_round_toward_positive
|
||||
\sa Z3_mk_fpa_round_toward_zero
|
||||
|
||||
def_API('Z3_mk_fpa_round_nearest_ties_to_even', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_even(Z3_context c);
|
||||
|
@ -48,8 +62,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_round_nearest_ties_to_even.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_rna
|
||||
\sa Z3_mk_fpa_rtn
|
||||
\sa Z3_mk_fpa_rtp
|
||||
\sa Z3_mk_fpa_rtz
|
||||
|
||||
def_API('Z3_mk_fpa_rne', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_rne(Z3_context c);
|
||||
|
@ -57,8 +79,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_rna.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_even
|
||||
\sa Z3_mk_fpa_round_toward_negative
|
||||
\sa Z3_mk_fpa_round_toward_positive
|
||||
\sa Z3_mk_fpa_round_toward_zero
|
||||
|
||||
def_API('Z3_mk_fpa_round_nearest_ties_to_away', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_away(Z3_context c);
|
||||
|
@ -66,8 +96,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_round_nearest_ties_to_away.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_rne
|
||||
\sa Z3_mk_fpa_rtn
|
||||
\sa Z3_mk_fpa_rtp
|
||||
\sa Z3_mk_fpa_rtz
|
||||
|
||||
def_API('Z3_mk_fpa_rna', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_rna(Z3_context c);
|
||||
|
@ -75,8 +113,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the TowardPositive rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_rtp.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_away
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_even
|
||||
\sa Z3_mk_fpa_round_toward_negative
|
||||
\sa Z3_mk_fpa_round_toward_zero
|
||||
|
||||
def_API('Z3_mk_fpa_round_toward_positive', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_round_toward_positive(Z3_context c);
|
||||
|
@ -84,8 +130,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the TowardPositive rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_round_toward_positive.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_rna
|
||||
\sa Z3_mk_fpa_rne
|
||||
\sa Z3_mk_fpa_rtn
|
||||
\sa Z3_mk_fpa_rtz
|
||||
|
||||
def_API('Z3_mk_fpa_rtp', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_rtp(Z3_context c);
|
||||
|
@ -93,8 +147,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the TowardNegative rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_rtn.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_away
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_even
|
||||
\sa Z3_mk_fpa_round_toward_positive
|
||||
\sa Z3_mk_fpa_round_toward_zero
|
||||
|
||||
def_API('Z3_mk_fpa_round_toward_negative', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_round_toward_negative(Z3_context c);
|
||||
|
@ -102,8 +164,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the TowardNegative rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_round_toward_negative.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_rna
|
||||
\sa Z3_mk_fpa_rne
|
||||
\sa Z3_mk_fpa_rtp
|
||||
\sa Z3_mk_fpa_rtz
|
||||
|
||||
def_API('Z3_mk_fpa_rtn', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_rtn(Z3_context c);
|
||||
|
@ -111,8 +181,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the TowardZero rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_rtz.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_away
|
||||
\sa Z3_mk_fpa_round_nearest_ties_to_even
|
||||
\sa Z3_mk_fpa_round_toward_negative
|
||||
\sa Z3_mk_fpa_round_toward_positive
|
||||
|
||||
def_API('Z3_mk_fpa_round_toward_zero', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_round_toward_zero(Z3_context c);
|
||||
|
@ -120,8 +198,16 @@ extern "C" {
|
|||
/**
|
||||
\brief Create a numeral of RoundingMode sort which represents the TowardZero rounding mode.
|
||||
|
||||
This is the same as #Z3_mk_fpa_round_toward_zero.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_rounding_mode_sort
|
||||
\sa Z3_mk_fpa_rna
|
||||
\sa Z3_mk_fpa_rne
|
||||
\sa Z3_mk_fpa_rtn
|
||||
\sa Z3_mk_fpa_rtp
|
||||
|
||||
def_API('Z3_mk_fpa_rtz', AST, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_rtz(Z3_context c);
|
||||
|
@ -135,6 +221,11 @@ extern "C" {
|
|||
|
||||
\remark \c ebits must be larger than 1 and \c sbits must be larger than 2.
|
||||
|
||||
\sa Z3_mk_fpa_sort_half or Z3_mk_fpa_sort_16
|
||||
\sa Z3_mk_fpa_sort_single or Z3_mk_fpa_sort_32
|
||||
\sa Z3_mk_fpa_sort_double or Z3_mk_fpa_sort_64
|
||||
\sa Z3_mk_fpa_sort_quadruple or Z3_mk_fpa_sort_128
|
||||
|
||||
def_API('Z3_mk_fpa_sort', SORT, (_in(CONTEXT), _in(UINT), _in(UINT)))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_sort(Z3_context c, unsigned ebits, unsigned sbits);
|
||||
|
@ -142,8 +233,15 @@ extern "C" {
|
|||
/**
|
||||
\brief Create the half-precision (16-bit) FloatingPoint sort.
|
||||
|
||||
This is the same as #Z3_mk_fpa_sort_16.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_sort
|
||||
\sa Z3_mk_fpa_sort_single
|
||||
\sa Z3_mk_fpa_sort_double
|
||||
\sa Z3_mk_fpa_sort_quadruple
|
||||
|
||||
def_API('Z3_mk_fpa_sort_half', SORT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_sort_half(Z3_context c);
|
||||
|
@ -151,8 +249,15 @@ extern "C" {
|
|||
/**
|
||||
\brief Create the half-precision (16-bit) FloatingPoint sort.
|
||||
|
||||
This is the same as #Z3_mk_fpa_sort_half.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_sort
|
||||
\sa Z3_mk_fpa_sort_32
|
||||
\sa Z3_mk_fpa_sort_64
|
||||
\sa Z3_mk_fpa_sort_128
|
||||
|
||||
def_API('Z3_mk_fpa_sort_16', SORT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_sort_16(Z3_context c);
|
||||
|
@ -160,8 +265,15 @@ extern "C" {
|
|||
/**
|
||||
\brief Create the single-precision (32-bit) FloatingPoint sort.
|
||||
|
||||
This is the same as #Z3_mk_fpa_sort_32.
|
||||
|
||||
\param c logical context.
|
||||
|
||||
\sa Z3_mk_fpa_sort
|
||||
\sa Z3_mk_fpa_sort_half
|
||||
\sa Z3_mk_fpa_sort_double
|
||||
\sa Z3_mk_fpa_sort_quadruple
|
||||
|
||||
def_API('Z3_mk_fpa_sort_single', SORT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_sort_single(Z3_context c);
|
||||
|
@ -169,8 +281,15 @@ extern "C" {
|
|||
/**
|
||||
\brief Create the single-precision (32-bit) FloatingPoint sort.
|
||||
|
||||
This is the same as #Z3_mk_fpa_sort_single.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_sort
|
||||
\sa Z3_mk_fpa_sort_16
|
||||
\sa Z3_mk_fpa_sort_64
|
||||
\sa Z3_mk_fpa_sort_128
|
||||
|
||||
def_API('Z3_mk_fpa_sort_32', SORT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_sort_32(Z3_context c);
|
||||
|
@ -178,8 +297,15 @@ extern "C" {
|
|||
/**
|
||||
\brief Create the double-precision (64-bit) FloatingPoint sort.
|
||||
|
||||
This is the same as #Z3_mk_fpa_sort_64.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_sort
|
||||
\sa Z3_mk_fpa_sort_half
|
||||
\sa Z3_mk_fpa_sort_single
|
||||
\sa Z3_mk_fpa_sort_quadruple
|
||||
|
||||
def_API('Z3_mk_fpa_sort_double', SORT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_sort_double(Z3_context c);
|
||||
|
@ -187,8 +313,15 @@ extern "C" {
|
|||
/**
|
||||
\brief Create the double-precision (64-bit) FloatingPoint sort.
|
||||
|
||||
This is the same as #Z3_mk_fpa_sort_double.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_sort
|
||||
\sa Z3_mk_fpa_sort_16
|
||||
\sa Z3_mk_fpa_sort_32
|
||||
\sa Z3_mk_fpa_sort_128
|
||||
|
||||
def_API('Z3_mk_fpa_sort_64', SORT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_sort_64(Z3_context c);
|
||||
|
@ -196,8 +329,15 @@ extern "C" {
|
|||
/**
|
||||
\brief Create the quadruple-precision (128-bit) FloatingPoint sort.
|
||||
|
||||
This is the same as #Z3_mk_fpa_sort_128.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_sort
|
||||
\sa Z3_mk_fpa_sort_half
|
||||
\sa Z3_mk_fpa_sort_single
|
||||
\sa Z3_mk_fpa_sort_double
|
||||
|
||||
def_API('Z3_mk_fpa_sort_quadruple', SORT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_sort_quadruple(Z3_context c);
|
||||
|
@ -205,8 +345,15 @@ extern "C" {
|
|||
/**
|
||||
\brief Create the quadruple-precision (128-bit) FloatingPoint sort.
|
||||
|
||||
This is the same as #Z3_mk_fpa_sort_quadruple.
|
||||
|
||||
\param c logical context
|
||||
|
||||
\sa Z3_mk_fpa_sort
|
||||
\sa Z3_mk_fpa_sort_16
|
||||
\sa Z3_mk_fpa_sort_32
|
||||
\sa Z3_mk_fpa_sort_64
|
||||
|
||||
def_API('Z3_mk_fpa_sort_128', SORT, (_in(CONTEXT),))
|
||||
*/
|
||||
Z3_sort Z3_API Z3_mk_fpa_sort_128(Z3_context c);
|
||||
|
@ -218,6 +365,7 @@ extern "C" {
|
|||
\param s target sort
|
||||
|
||||
\sa Z3_mk_fpa_inf
|
||||
\sa Z3_mk_fpa_is_nan
|
||||
\sa Z3_mk_fpa_zero
|
||||
|
||||
def_API('Z3_mk_fpa_nan', AST, (_in(CONTEXT),_in(SORT)))
|
||||
|
@ -233,6 +381,7 @@ extern "C" {
|
|||
|
||||
When \c negative is \c true, -oo will be generated instead of +oo.
|
||||
|
||||
\sa Z3_mk_fpa_is_infinite
|
||||
\sa Z3_mk_fpa_nan
|
||||
\sa Z3_mk_fpa_zero
|
||||
|
||||
|
@ -250,6 +399,7 @@ extern "C" {
|
|||
When \c negative is \c true, -zero will be generated instead of +zero.
|
||||
|
||||
\sa Z3_mk_fpa_inf
|
||||
\sa Z3_mk_fpa_is_zero
|
||||
\sa Z3_mk_fpa_nan
|
||||
|
||||
def_API('Z3_mk_fpa_zero', AST, (_in(CONTEXT),_in(SORT),_in(BOOL)))
|
||||
|
@ -397,6 +547,10 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param t term of FloatingPoint sort
|
||||
|
||||
\sa Z3_mk_fpa_is_negative
|
||||
\sa Z3_mk_fpa_is_positive
|
||||
\sa Z3_mk_fpa_neg
|
||||
|
||||
def_API('Z3_mk_fpa_abs', AST, (_in(CONTEXT),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_abs(Z3_context c, Z3_ast t);
|
||||
|
@ -407,6 +561,10 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param t term of FloatingPoint sort
|
||||
|
||||
\sa Z3_mk_fpa_abs
|
||||
\sa Z3_mk_fpa_is_negative
|
||||
\sa Z3_mk_fpa_is_positive
|
||||
|
||||
def_API('Z3_mk_fpa_neg', AST, (_in(CONTEXT),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_neg(Z3_context c, Z3_ast t);
|
||||
|
@ -533,6 +691,8 @@ extern "C" {
|
|||
|
||||
\c t1, \c t2 must have the same FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_max
|
||||
|
||||
def_API('Z3_mk_fpa_min', AST, (_in(CONTEXT),_in(AST),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_min(Z3_context c, Z3_ast t1, Z3_ast t2);
|
||||
|
@ -546,6 +706,8 @@ extern "C" {
|
|||
|
||||
\c t1, \c t2 must have the same FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_min
|
||||
|
||||
def_API('Z3_mk_fpa_max', AST, (_in(CONTEXT),_in(AST),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_max(Z3_context c, Z3_ast t1, Z3_ast t2);
|
||||
|
@ -559,6 +721,11 @@ extern "C" {
|
|||
|
||||
\c t1 and \c t2 must have the same FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_eq
|
||||
\sa Z3_mk_fpa_geq
|
||||
\sa Z3_mk_fpa_gt
|
||||
\sa Z3_mk_fpa_lt
|
||||
|
||||
def_API('Z3_mk_fpa_leq', AST, (_in(CONTEXT),_in(AST),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_leq(Z3_context c, Z3_ast t1, Z3_ast t2);
|
||||
|
@ -572,6 +739,11 @@ extern "C" {
|
|||
|
||||
\c t1 and \c t2 must have the same FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_eq
|
||||
\sa Z3_mk_fpa_geq
|
||||
\sa Z3_mk_fpa_gt
|
||||
\sa Z3_mk_fpa_leq
|
||||
|
||||
def_API('Z3_mk_fpa_lt', AST, (_in(CONTEXT),_in(AST),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_lt(Z3_context c, Z3_ast t1, Z3_ast t2);
|
||||
|
@ -585,6 +757,11 @@ extern "C" {
|
|||
|
||||
\c t1 and \c t2 must have the same FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_eq
|
||||
\sa Z3_mk_fpa_gt
|
||||
\sa Z3_mk_fpa_leq
|
||||
\sa Z3_mk_fpa_lt
|
||||
|
||||
def_API('Z3_mk_fpa_geq', AST, (_in(CONTEXT),_in(AST),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_geq(Z3_context c, Z3_ast t1, Z3_ast t2);
|
||||
|
@ -598,6 +775,11 @@ extern "C" {
|
|||
|
||||
\c t1 and \c t2 must have the same FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_eq
|
||||
\sa Z3_mk_fpa_geq
|
||||
\sa Z3_mk_fpa_leq
|
||||
\sa Z3_mk_fpa_lt
|
||||
|
||||
def_API('Z3_mk_fpa_gt', AST, (_in(CONTEXT),_in(AST),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_gt(Z3_context c, Z3_ast t1, Z3_ast t2);
|
||||
|
@ -613,6 +795,11 @@ extern "C" {
|
|||
|
||||
\c t1 and \c t2 must have the same FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_geq
|
||||
\sa Z3_mk_fpa_gt
|
||||
\sa Z3_mk_fpa_leq
|
||||
\sa Z3_mk_fpa_lt
|
||||
|
||||
def_API('Z3_mk_fpa_eq', AST, (_in(CONTEXT),_in(AST),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_eq(Z3_context c, Z3_ast t1, Z3_ast t2);
|
||||
|
@ -625,6 +812,11 @@ extern "C" {
|
|||
|
||||
\c t must have FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_is_infinite
|
||||
\sa Z3_mk_fpa_is_nan
|
||||
\sa Z3_mk_fpa_is_subnormal
|
||||
\sa Z3_mk_fpa_is_zero
|
||||
|
||||
def_API('Z3_mk_fpa_is_normal', AST, (_in(CONTEXT),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_is_normal(Z3_context c, Z3_ast t);
|
||||
|
@ -637,6 +829,11 @@ extern "C" {
|
|||
|
||||
\c t must have FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_is_infinite
|
||||
\sa Z3_mk_fpa_is_nan
|
||||
\sa Z3_mk_fpa_is_normal
|
||||
\sa Z3_mk_fpa_is_zero
|
||||
|
||||
def_API('Z3_mk_fpa_is_subnormal', AST, (_in(CONTEXT),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_is_subnormal(Z3_context c, Z3_ast t);
|
||||
|
@ -649,6 +846,12 @@ extern "C" {
|
|||
|
||||
\c t must have FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_is_infinite
|
||||
\sa Z3_mk_fpa_is_nan
|
||||
\sa Z3_mk_fpa_is_normal
|
||||
\sa Z3_mk_fpa_is_subnormal
|
||||
\sa Z3_mk_fpa_zero
|
||||
|
||||
def_API('Z3_mk_fpa_is_zero', AST, (_in(CONTEXT),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_is_zero(Z3_context c, Z3_ast t);
|
||||
|
@ -661,6 +864,12 @@ extern "C" {
|
|||
|
||||
\c t must have FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_inf
|
||||
\sa Z3_mk_fpa_is_nan
|
||||
\sa Z3_mk_fpa_is_normal
|
||||
\sa Z3_mk_fpa_is_subnormal
|
||||
\sa Z3_mk_fpa_is_zero
|
||||
|
||||
def_API('Z3_mk_fpa_is_infinite', AST, (_in(CONTEXT),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_is_infinite(Z3_context c, Z3_ast t);
|
||||
|
@ -673,6 +882,12 @@ extern "C" {
|
|||
|
||||
\c t must have FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_is_infinite
|
||||
\sa Z3_mk_fpa_is_normal
|
||||
\sa Z3_mk_fpa_is_subnormal
|
||||
\sa Z3_mk_fpa_is_zero
|
||||
\sa Z3_mk_fpa_nan
|
||||
|
||||
def_API('Z3_mk_fpa_is_nan', AST, (_in(CONTEXT),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_is_nan(Z3_context c, Z3_ast t);
|
||||
|
@ -685,6 +900,10 @@ extern "C" {
|
|||
|
||||
\c t must have FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_abs
|
||||
\sa Z3_mk_fpa_is_positive
|
||||
\sa Z3_mk_fpa_neg
|
||||
|
||||
def_API('Z3_mk_fpa_is_negative', AST, (_in(CONTEXT),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_is_negative(Z3_context c, Z3_ast t);
|
||||
|
@ -697,6 +916,10 @@ extern "C" {
|
|||
|
||||
\c t must have FloatingPoint sort.
|
||||
|
||||
\sa Z3_mk_fpa_abs
|
||||
\sa Z3_mk_fpa_is_negative
|
||||
\sa Z3_mk_fpa_neg
|
||||
|
||||
def_API('Z3_mk_fpa_is_positive', AST, (_in(CONTEXT),_in(AST)))
|
||||
*/
|
||||
Z3_ast Z3_API Z3_mk_fpa_is_positive(Z3_context c, Z3_ast t);
|
||||
|
@ -848,6 +1071,8 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param s FloatingPoint sort
|
||||
|
||||
\sa Z3_fpa_get_sbits
|
||||
|
||||
def_API('Z3_fpa_get_ebits', UINT, (_in(CONTEXT),_in(SORT)))
|
||||
*/
|
||||
unsigned Z3_API Z3_fpa_get_ebits(Z3_context c, Z3_sort s);
|
||||
|
@ -858,6 +1083,8 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param s FloatingPoint sort
|
||||
|
||||
\sa Z3_fpa_get_ebits
|
||||
|
||||
def_API('Z3_fpa_get_sbits', UINT, (_in(CONTEXT),_in(SORT)))
|
||||
*/
|
||||
unsigned Z3_API Z3_fpa_get_sbits(Z3_context c, Z3_sort s);
|
||||
|
@ -868,6 +1095,11 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param t a floating-point numeral
|
||||
|
||||
\sa Z3_fpa_is_numeral_inf
|
||||
\sa Z3_fpa_is_numeral_normal
|
||||
\sa Z3_fpa_is_numeral_subnormal
|
||||
\sa Z3_fpa_is_numeral_zero
|
||||
|
||||
def_API('Z3_fpa_is_numeral_nan', BOOL, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t);
|
||||
|
@ -878,6 +1110,11 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param t a floating-point numeral
|
||||
|
||||
\sa Z3_fpa_is_numeral_nan
|
||||
\sa Z3_fpa_is_numeral_normal
|
||||
\sa Z3_fpa_is_numeral_subnormal
|
||||
\sa Z3_fpa_is_numeral_zero
|
||||
|
||||
def_API('Z3_fpa_is_numeral_inf', BOOL, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t);
|
||||
|
@ -888,6 +1125,11 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param t a floating-point numeral
|
||||
|
||||
\sa Z3_fpa_is_numeral_inf
|
||||
\sa Z3_fpa_is_numeral_nan
|
||||
\sa Z3_fpa_is_numeral_normal
|
||||
\sa Z3_fpa_is_numeral_subnormal
|
||||
|
||||
def_API('Z3_fpa_is_numeral_zero', BOOL, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t);
|
||||
|
@ -898,6 +1140,11 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param t a floating-point numeral
|
||||
|
||||
\sa Z3_fpa_is_numeral_inf
|
||||
\sa Z3_fpa_is_numeral_nan
|
||||
\sa Z3_fpa_is_numeral_subnormal
|
||||
\sa Z3_fpa_is_numeral_zero
|
||||
|
||||
def_API('Z3_fpa_is_numeral_normal', BOOL, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t);
|
||||
|
@ -908,6 +1155,11 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param t a floating-point numeral
|
||||
|
||||
\sa Z3_fpa_is_numeral_inf
|
||||
\sa Z3_fpa_is_numeral_nan
|
||||
\sa Z3_fpa_is_numeral_normal
|
||||
\sa Z3_fpa_is_numeral_zero
|
||||
|
||||
def_API('Z3_fpa_is_numeral_subnormal', BOOL, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t);
|
||||
|
@ -918,6 +1170,8 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param t a floating-point numeral
|
||||
|
||||
\sa Z3_fpa_is_numeral_negative
|
||||
|
||||
def_API('Z3_fpa_is_numeral_positive', BOOL, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t);
|
||||
|
@ -928,6 +1182,8 @@ extern "C" {
|
|||
\param c logical context
|
||||
\param t a floating-point numeral
|
||||
|
||||
\sa Z3_fpa_is_numeral_positive
|
||||
|
||||
def_API('Z3_fpa_is_numeral_negative', BOOL, (_in(CONTEXT), _in(AST)))
|
||||
*/
|
||||
bool Z3_API Z3_fpa_is_numeral_negative(Z3_context c, Z3_ast t);
|
||||
|
|
120
src/api/z3_rcf.h
120
src/api/z3_rcf.h
|
@ -193,8 +193,124 @@ extern "C" {
|
|||
We have that \ccode{a = n/d}, moreover \c n and \c d are not represented using rational functions.
|
||||
|
||||
def_API('Z3_rcf_get_numerator_denominator', VOID, (_in(CONTEXT), _in(RCF_NUM), _out(RCF_NUM), _out(RCF_NUM)))
|
||||
*/
|
||||
void Z3_API Z3_rcf_get_numerator_denominator(Z3_context c, Z3_rcf_num a, Z3_rcf_num * n, Z3_rcf_num * d);
|
||||
*/
|
||||
void Z3_API Z3_rcf_get_numerator_denominator(Z3_context c, Z3_rcf_num a, Z3_rcf_num * n, Z3_rcf_num * d);
|
||||
|
||||
/**
|
||||
\brief Return \c true if \c a represents a rational number.
|
||||
|
||||
def_API('Z3_rcf_is_rational', BOOL, (_in(CONTEXT), _in(RCF_NUM)))
|
||||
*/
|
||||
bool Z3_API Z3_rcf_is_rational(Z3_context c, Z3_rcf_num a);
|
||||
|
||||
/**
|
||||
\brief Return \c true if \c a represents an algebraic number.
|
||||
|
||||
def_API('Z3_rcf_is_algebraic', BOOL, (_in(CONTEXT), _in(RCF_NUM)))
|
||||
*/
|
||||
bool Z3_API Z3_rcf_is_algebraic(Z3_context c, Z3_rcf_num a);
|
||||
|
||||
/**
|
||||
\brief Return \c true if \c a represents an infinitesimal.
|
||||
|
||||
def_API('Z3_rcf_is_infinitesimal', BOOL, (_in(CONTEXT), _in(RCF_NUM)))
|
||||
*/
|
||||
bool Z3_API Z3_rcf_is_infinitesimal(Z3_context c, Z3_rcf_num a);
|
||||
|
||||
/**
|
||||
\brief Return \c true if \c a represents a transcendental number.
|
||||
|
||||
def_API('Z3_rcf_is_transcendental', BOOL, (_in(CONTEXT), _in(RCF_NUM)))
|
||||
*/
|
||||
bool Z3_API Z3_rcf_is_transcendental(Z3_context c, Z3_rcf_num a);
|
||||
|
||||
/**
|
||||
\brief Return the index of a field extension.
|
||||
|
||||
def_API('Z3_rcf_extension_index', UINT, (_in(CONTEXT), _in(RCF_NUM)))
|
||||
*/
|
||||
unsigned Z3_API Z3_rcf_extension_index(Z3_context c, Z3_rcf_num a);
|
||||
|
||||
/**
|
||||
\brief Return the name of a transcendental.
|
||||
|
||||
\pre Z3_rcf_is_transcendtal(ctx, a);
|
||||
|
||||
def_API('Z3_rcf_transcendental_name', SYMBOL, (_in(CONTEXT), _in(RCF_NUM)))
|
||||
*/
|
||||
Z3_symbol Z3_API Z3_rcf_transcendental_name(Z3_context c, Z3_rcf_num a);
|
||||
|
||||
/**
|
||||
\brief Return the name of an infinitesimal.
|
||||
|
||||
\pre Z3_rcf_is_infinitesimal(ctx, a);
|
||||
|
||||
def_API('Z3_rcf_infinitesimal_name', SYMBOL, (_in(CONTEXT), _in(RCF_NUM)))
|
||||
*/
|
||||
Z3_symbol Z3_API Z3_rcf_infinitesimal_name(Z3_context c, Z3_rcf_num a);
|
||||
|
||||
/**
|
||||
\brief Return the number of coefficients in an algebraic number.
|
||||
|
||||
\pre Z3_rcf_is_algebraic(ctx, a);
|
||||
|
||||
def_API('Z3_rcf_num_coefficients', UINT, (_in(CONTEXT), _in(RCF_NUM)))
|
||||
*/
|
||||
unsigned Z3_API Z3_rcf_num_coefficients(Z3_context c, Z3_rcf_num a);
|
||||
|
||||
/**
|
||||
\brief Extract a coefficient from an algebraic number.
|
||||
|
||||
\pre Z3_rcf_is_algebraic(ctx, a);
|
||||
|
||||
def_API('Z3_rcf_coefficient', RCF_NUM, (_in(CONTEXT), _in(RCF_NUM), _in(UINT)))
|
||||
*/
|
||||
Z3_rcf_num Z3_API Z3_rcf_coefficient(Z3_context c, Z3_rcf_num a, unsigned i);
|
||||
|
||||
/**
|
||||
\brief Extract an interval from an algebraic number.
|
||||
|
||||
\pre Z3_rcf_is_algebraic(ctx, a);
|
||||
|
||||
def_API('Z3_rcf_interval', INT, (_in(CONTEXT), _in(RCF_NUM), _out(INT), _out(INT), _out(RCF_NUM), _out(INT), _out(INT), _out(RCF_NUM)))
|
||||
*/
|
||||
int Z3_API Z3_rcf_interval(Z3_context c, Z3_rcf_num a, int * lower_is_inf, int * lower_is_open, Z3_rcf_num * lower, int * upper_is_inf, int * upper_is_open, Z3_rcf_num * upper);
|
||||
|
||||
/**
|
||||
\brief Return the number of sign conditions of an algebraic number.
|
||||
|
||||
\pre Z3_rcf_is_algebraic(ctx, a);
|
||||
|
||||
def_API('Z3_rcf_num_sign_conditions', UINT, (_in(CONTEXT), _in(RCF_NUM)))
|
||||
*/
|
||||
unsigned Z3_API Z3_rcf_num_sign_conditions(Z3_context c, Z3_rcf_num a);
|
||||
|
||||
/**
|
||||
\brief Extract the sign of a sign condition from an algebraic number.
|
||||
|
||||
\pre Z3_rcf_is_algebraic(ctx, a);
|
||||
|
||||
def_API('Z3_rcf_sign_condition_sign', INT, (_in(CONTEXT), _in(RCF_NUM), _in(UINT)))
|
||||
*/
|
||||
int Z3_API Z3_rcf_sign_condition_sign(Z3_context c, Z3_rcf_num a, unsigned i);
|
||||
|
||||
/**
|
||||
\brief Return the number of sign condition polynomial coefficients of an algebraic number.
|
||||
|
||||
\pre Z3_rcf_is_algebraic(ctx, a);
|
||||
|
||||
def_API('Z3_rcf_num_sign_condition_coefficients', UINT, (_in(CONTEXT), _in(RCF_NUM), _in(UINT)))
|
||||
*/
|
||||
unsigned Z3_API Z3_rcf_num_sign_condition_coefficients(Z3_context c, Z3_rcf_num a, unsigned i);
|
||||
|
||||
/**
|
||||
\brief Extract the j-th polynomial coefficient of the i-th sign condition.
|
||||
|
||||
\pre Z3_rcf_is_algebraic(ctx, a);
|
||||
|
||||
def_API('Z3_rcf_sign_condition_coefficient', RCF_NUM, (_in(CONTEXT), _in(RCF_NUM), _in(UINT), _in(UINT)))
|
||||
*/
|
||||
Z3_rcf_num Z3_API Z3_rcf_sign_condition_coefficient(Z3_context c, Z3_rcf_num a, unsigned i, unsigned j);
|
||||
|
||||
/**@}*/
|
||||
/**@}*/
|
||||
|
|
|
@ -3,6 +3,7 @@ z3_add_component(ast
|
|||
act_cache.cpp
|
||||
arith_decl_plugin.cpp
|
||||
array_decl_plugin.cpp
|
||||
array_peq.cpp
|
||||
ast.cpp
|
||||
ast_ll_pp.cpp
|
||||
ast_lt.cpp
|
||||
|
@ -37,6 +38,8 @@ z3_add_component(ast
|
|||
num_occurs.cpp
|
||||
occurs.cpp
|
||||
pb_decl_plugin.cpp
|
||||
polymorphism_inst.cpp
|
||||
polymorphism_util.cpp
|
||||
pp.cpp
|
||||
quantifier_stat.cpp
|
||||
recfun_decl_plugin.cpp
|
||||
|
|
|
@ -801,6 +801,29 @@ expr_ref arith_util::mk_add_simplify(unsigned sz, expr* const* args) {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool arith_util::is_considered_partially_interpreted(func_decl* f, unsigned n, expr* const* args, func_decl_ref& f_out) {
|
||||
if (is_decl_of(f, arith_family_id, OP_DIV) && n == 2 && !is_numeral(args[1])) {
|
||||
f_out = mk_div0();
|
||||
return true;
|
||||
}
|
||||
if (is_decl_of(f, arith_family_id, OP_IDIV) && n == 2 && !is_numeral(args[1])) {
|
||||
sort* rs[2] = { mk_int(), mk_int() };
|
||||
f_out = m_manager.mk_func_decl(arith_family_id, OP_IDIV0, 0, nullptr, 2, rs, mk_int());
|
||||
return true;
|
||||
}
|
||||
if (is_decl_of(f, arith_family_id, OP_MOD) && n == 2 && !is_numeral(args[1])) {
|
||||
sort* rs[2] = { mk_int(), mk_int() };
|
||||
f_out = m_manager.mk_func_decl(arith_family_id, OP_MOD0, 0, nullptr, 2, rs, mk_int());
|
||||
return true;
|
||||
}
|
||||
if (is_decl_of(f, arith_family_id, OP_REM) && n == 2 && !is_numeral(args[1])) {
|
||||
sort* rs[2] = { mk_int(), mk_int() };
|
||||
f_out = m_manager.mk_func_decl(arith_family_id, OP_MOD0, 0, nullptr, 2, rs, mk_int());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool arith_util::is_considered_uninterpreted(func_decl* f, unsigned n, expr* const* args, func_decl_ref& f_out) {
|
||||
rational r;
|
||||
if (is_decl_of(f, arith_family_id, OP_DIV) && n == 2 && is_numeral(args[1], r) && r.is_zero()) {
|
||||
|
|
|
@ -517,6 +517,8 @@ public:
|
|||
|
||||
bool is_considered_uninterpreted(func_decl* f, unsigned n, expr* const* args, func_decl_ref& f_out);
|
||||
|
||||
bool is_considered_partially_interpreted(func_decl* f, unsigned n, expr* const* args, func_decl_ref& f_out);
|
||||
|
||||
bool is_underspecified(expr* e) const;
|
||||
|
||||
bool is_bounded(expr* e) const;
|
||||
|
|
|
@ -633,6 +633,12 @@ bool array_decl_plugin::is_value(app * _e) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool array_decl_plugin::is_unique_value(app* _e) const {
|
||||
array_util u(*m_manager);
|
||||
expr* e = _e;
|
||||
return u.is_const(e, e) && m_manager->is_unique_value(e);
|
||||
}
|
||||
|
||||
|
||||
func_decl * array_recognizers::get_as_array_func_decl(expr * n) const {
|
||||
SASSERT(is_as_array(n));
|
||||
|
|
|
@ -137,6 +137,8 @@ class array_decl_plugin : public decl_plugin {
|
|||
|
||||
bool is_value(app * e) const override;
|
||||
|
||||
bool is_unique_value(app* e) const override;
|
||||
|
||||
};
|
||||
|
||||
class array_recognizers {
|
||||
|
@ -184,6 +186,21 @@ public:
|
|||
|
||||
bool is_store_ext(expr* e, expr_ref& a, expr_ref_vector& args, expr_ref& value);
|
||||
|
||||
|
||||
bool is_select1(expr* n) const { return is_select(n) && to_app(n)->get_num_args() == 2; }
|
||||
|
||||
bool is_select1(expr* n, expr*& a, expr*& i) const {
|
||||
return is_select1(n) && (a = to_app(n)->get_arg(0), i = to_app(n)->get_arg(1), true);
|
||||
}
|
||||
|
||||
bool is_store1(expr* n) const { return is_store(n) && to_app(n)->get_num_args() == 3; }
|
||||
|
||||
bool is_store1(expr* n, expr*& a, expr*& i, expr*& v) const {
|
||||
app* _n;
|
||||
return is_store1(n) && (_n = to_app(n), a = _n->get_arg(0), i = _n->get_arg(1), v = _n->get_arg(2), true);
|
||||
}
|
||||
|
||||
|
||||
MATCH_BINARY(is_subset);
|
||||
};
|
||||
|
||||
|
@ -211,6 +228,11 @@ public:
|
|||
return mk_store(args.size(), args.data());
|
||||
}
|
||||
|
||||
app * mk_select(expr* a, expr* i) const {
|
||||
expr* args[2] = { a, i };
|
||||
return mk_select(2, args);
|
||||
}
|
||||
|
||||
app * mk_select(unsigned num_args, expr * const * args) const {
|
||||
return m_manager.mk_app(m_fid, OP_SELECT, 0, nullptr, num_args, args);
|
||||
}
|
||||
|
|
107
src/ast/array_peq.cpp
Normal file
107
src/ast/array_peq.cpp
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*++
|
||||
Copyright (c) 2023 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
array_peq.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Partial equality for arrays
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-06-13
|
||||
Hari Govind V K
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "ast/array_peq.h"
|
||||
|
||||
#define PARTIAL_EQ "!partial_eq"
|
||||
bool is_partial_eq(const func_decl *f) {
|
||||
SASSERT(f);
|
||||
return f->get_name() == PARTIAL_EQ;
|
||||
}
|
||||
|
||||
bool is_partial_eq(const app *a) {
|
||||
SASSERT(a);
|
||||
return is_partial_eq(a->get_decl());
|
||||
}
|
||||
|
||||
app_ref mk_peq(expr *e0, expr *e1, vector<expr_ref_vector> const &indices,
|
||||
ast_manager &m) {
|
||||
peq p(e0, e1, indices, m);
|
||||
return p.mk_peq();
|
||||
}
|
||||
|
||||
app_ref peq::mk_eq(app_ref_vector &aux_consts, bool stores_on_rhs) {
|
||||
if (!m_eq) {
|
||||
expr_ref lhs(m_lhs, m), rhs(m_rhs, m);
|
||||
if (!stores_on_rhs) { std::swap(lhs, rhs); }
|
||||
// lhs = (...(store (store rhs i0 v0) i1 v1)...)
|
||||
sort *val_sort = get_array_range(lhs->get_sort());
|
||||
for (expr_ref_vector const &diff : m_diff_indices) {
|
||||
ptr_vector<expr> store_args;
|
||||
store_args.push_back(rhs);
|
||||
store_args.append(diff.size(), diff.data());
|
||||
app_ref val(m.mk_fresh_const("diff", val_sort), m);
|
||||
store_args.push_back(val);
|
||||
aux_consts.push_back(val);
|
||||
rhs = m_arr_u.mk_store(store_args);
|
||||
}
|
||||
m_eq = m.mk_eq(lhs, rhs);
|
||||
}
|
||||
return m_eq;
|
||||
}
|
||||
|
||||
app_ref peq::mk_peq() {
|
||||
if (!m_peq) {
|
||||
ptr_vector<expr> args;
|
||||
args.push_back(m_lhs);
|
||||
args.push_back(m_rhs);
|
||||
for (auto const &v : m_diff_indices) {
|
||||
args.append(v.size(), v.data());
|
||||
}
|
||||
m_peq = m.mk_app(m_decl, args.size(), args.data());
|
||||
}
|
||||
return m_peq;
|
||||
}
|
||||
|
||||
peq::peq(expr *lhs, expr *rhs, vector<expr_ref_vector> const &diff_indices,
|
||||
ast_manager &m)
|
||||
: m(m), m_lhs(lhs, m), m_rhs(rhs, m), m_diff_indices(diff_indices),
|
||||
m_decl(m), m_peq(m), m_eq(m), m_arr_u(m) {
|
||||
SASSERT(m_arr_u.is_array(lhs));
|
||||
SASSERT(m_arr_u.is_array(rhs));
|
||||
SASSERT(lhs->get_sort() == rhs->get_sort());
|
||||
ptr_vector<sort> sorts;
|
||||
sorts.push_back(m_lhs->get_sort());
|
||||
sorts.push_back(m_rhs->get_sort());
|
||||
|
||||
for (auto const &v : diff_indices) {
|
||||
SASSERT(v.size() == get_array_arity(m_lhs->get_sort()));
|
||||
for (expr *e : v) sorts.push_back(e->get_sort());
|
||||
}
|
||||
m_decl = m.mk_func_decl(symbol(PARTIAL_EQ), sorts.size(), sorts.data(),
|
||||
m.mk_bool_sort());
|
||||
}
|
||||
|
||||
peq::peq(app *p, ast_manager &m)
|
||||
: m(m), m_lhs(p->get_arg(0), m), m_rhs(p->get_arg(1), m),
|
||||
m_decl(p->get_decl(), m), m_peq(p, m), m_eq(m), m_arr_u(m),
|
||||
m_name(symbol(PARTIAL_EQ)) {
|
||||
SASSERT(is_partial_eq(p));
|
||||
|
||||
SASSERT(m_arr_u.is_array(m_lhs));
|
||||
SASSERT(m_arr_u.is_array(m_rhs));
|
||||
SASSERT(m_lhs->get_sort() == m_rhs->get_sort());
|
||||
unsigned arity = get_array_arity(m_lhs->get_sort());
|
||||
for (unsigned i = 2; i < p->get_num_args(); i += arity) {
|
||||
SASSERT(arity + i <= p->get_num_args());
|
||||
expr_ref_vector vec(m);
|
||||
vec.append(arity, p->get_args() + i);
|
||||
m_diff_indices.push_back(std::move(vec));
|
||||
}
|
||||
}
|
91
src/ast/array_peq.h
Normal file
91
src/ast/array_peq.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*++
|
||||
Copyright (c) 2023 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
array_peq.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Partial equality for arrays
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-06-13
|
||||
Hari Govind V K
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/array_decl_plugin.h"
|
||||
#include "ast/ast.h"
|
||||
|
||||
/**
|
||||
* \brief utility class for partial equalities
|
||||
*
|
||||
* A partial equality (a ==I b), for two arrays a, b and a finite set of indices
|
||||
* I holds iff (forall i :: i \not\in I => a[i] == b[i]). In other words, peq is
|
||||
* a restricted form of the extensionality axiom
|
||||
*
|
||||
* Using this class, we denote (a =I b) as f(a,b,i0,i1,...),
|
||||
* where f is an uninterpreted predicate with the name PARTIAL_EQ and
|
||||
* I = {i0,i1,...}
|
||||
*/
|
||||
|
||||
class peq {
|
||||
ast_manager &m;
|
||||
expr_ref m_lhs;
|
||||
expr_ref m_rhs;
|
||||
vector<expr_ref_vector> m_diff_indices;
|
||||
func_decl_ref m_decl; // the partial equality declaration
|
||||
app_ref m_peq; // partial equality application
|
||||
app_ref m_eq; // equivalent std equality using def. of partial eq
|
||||
array_util m_arr_u;
|
||||
symbol m_name;
|
||||
|
||||
public:
|
||||
peq(app *p, ast_manager &m);
|
||||
|
||||
peq(expr *lhs, expr *rhs, vector<expr_ref_vector> const &diff_indices,
|
||||
ast_manager &m);
|
||||
|
||||
expr_ref lhs() { return m_lhs; }
|
||||
|
||||
expr_ref rhs() { return m_rhs; }
|
||||
|
||||
void get_diff_indices(vector<expr_ref_vector> &result) {
|
||||
result.append(m_diff_indices);
|
||||
}
|
||||
|
||||
/** Convert peq into a peq expression */
|
||||
app_ref mk_peq();
|
||||
|
||||
/** Convert peq into an equality
|
||||
|
||||
For peq of the form (a =I b) returns (a = b[i0 := v0, i1 := v1, ...])
|
||||
where i0, i1 \in I, and v0, v1 are fresh skolem constants
|
||||
|
||||
Skolems are returned in aux_consts
|
||||
|
||||
The left and right hand arguments are reversed when stores_on_rhs is
|
||||
false
|
||||
*/
|
||||
app_ref mk_eq(app_ref_vector &aux_consts, bool stores_on_rhs = true);
|
||||
};
|
||||
|
||||
/**
|
||||
* mk (e0 ==indices e1)
|
||||
*
|
||||
* result has stores if either e0 or e1 or an index term has stores
|
||||
*/
|
||||
app_ref mk_peq(expr *e0, expr *e1, vector<expr_ref_vector> const &indices,
|
||||
ast_manager &m);
|
||||
|
||||
bool is_partial_eq(const func_decl *f);
|
||||
|
||||
bool is_partial_eq(const app *a);
|
||||
|
||||
inline bool is_peq(const func_decl *f) { return is_partial_eq(f); }
|
||||
inline bool is_peq(const app *a) { return is_partial_eq(a); }
|
168
src/ast/ast.cpp
168
src/ast/ast.cpp
|
@ -202,8 +202,7 @@ unsigned decl_info::hash() const {
|
|||
|
||||
bool decl_info::operator==(decl_info const & info) const {
|
||||
return m_family_id == info.m_family_id && m_kind == info.m_kind &&
|
||||
m_parameters.size() == info.m_parameters.size() &&
|
||||
compare_arrays<parameter>(m_parameters.begin(), info.m_parameters.begin(), m_parameters.size());
|
||||
m_parameters == info.m_parameters;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, decl_info const & info) {
|
||||
|
@ -255,7 +254,8 @@ func_decl_info::func_decl_info(family_id family_id, decl_kind k, unsigned num_pa
|
|||
m_injective(false),
|
||||
m_idempotent(false),
|
||||
m_skolem(false),
|
||||
m_lambda(false) {
|
||||
m_lambda(false),
|
||||
m_polymorphic(false) {
|
||||
}
|
||||
|
||||
bool func_decl_info::operator==(func_decl_info const & info) const {
|
||||
|
@ -283,6 +283,7 @@ std::ostream & operator<<(std::ostream & out, func_decl_info const & info) {
|
|||
if (info.is_idempotent()) out << " :idempotent ";
|
||||
if (info.is_skolem()) out << " :skolem ";
|
||||
if (info.is_lambda()) out << " :lambda ";
|
||||
if (info.is_polymorphic()) out << " :polymorphic ";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -447,7 +448,7 @@ bool compare_nodes(ast const * n1, ast const * n2) {
|
|||
if (to_sort(n1)->get_info() != nullptr && !(*to_sort(n1)->get_info() == *to_sort(n2)->get_info())) {
|
||||
return false;
|
||||
}
|
||||
return to_sort(n1)->get_name() == to_sort(n2)->get_name();
|
||||
return to_sort(n1)->get_name() == to_sort(n2)->get_name();
|
||||
case AST_FUNC_DECL:
|
||||
if ((to_func_decl(n1)->get_info() == nullptr) != (to_func_decl(n2)->get_info() == nullptr)) {
|
||||
return false;
|
||||
|
@ -477,15 +478,15 @@ bool compare_nodes(ast const * n1, ast const * n2) {
|
|||
return
|
||||
q1->get_kind() == q2->get_kind() &&
|
||||
q1->get_num_decls() == q2->get_num_decls() &&
|
||||
q1->get_expr() == q2->get_expr() &&
|
||||
q1->get_weight() == q2->get_weight() &&
|
||||
q1->get_num_patterns() == q2->get_num_patterns() &&
|
||||
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(),
|
||||
|
@ -540,22 +541,6 @@ inline unsigned ast_array_hash(T * const * array, unsigned size, unsigned init_v
|
|||
} }
|
||||
}
|
||||
|
||||
unsigned get_asts_hash(unsigned sz, ast * const* ns, unsigned init) {
|
||||
return ast_array_hash<ast>(ns, sz, init);
|
||||
}
|
||||
unsigned get_apps_hash(unsigned sz, app * const* ns, unsigned init) {
|
||||
return ast_array_hash<app>(ns, sz, init);
|
||||
}
|
||||
unsigned get_exprs_hash(unsigned sz, expr * const* ns, unsigned init) {
|
||||
return ast_array_hash<expr>(ns, sz, init);
|
||||
}
|
||||
unsigned get_sorts_hash(unsigned sz, sort * const* ns, unsigned init) {
|
||||
return ast_array_hash<sort>(ns, sz, init);
|
||||
}
|
||||
unsigned get_decl_hash(unsigned sz, func_decl* const* ns, unsigned init) {
|
||||
return ast_array_hash<func_decl>(ns, sz, init);
|
||||
}
|
||||
|
||||
unsigned get_node_hash(ast const * n) {
|
||||
unsigned a, b, c;
|
||||
|
||||
|
@ -1309,10 +1294,7 @@ ast_manager::ast_manager(proof_gen_mode m, char const * trace_file, bool is_form
|
|||
m_expr_array_manager(*this, m_alloc),
|
||||
m_expr_dependency_manager(*this, m_alloc),
|
||||
m_expr_dependency_array_manager(*this, m_alloc),
|
||||
m_proof_mode(m),
|
||||
m_trace_stream(nullptr),
|
||||
m_trace_stream_owner(false),
|
||||
m_lambda_def(":lambda-def") {
|
||||
m_proof_mode(m) {
|
||||
|
||||
if (trace_file) {
|
||||
m_trace_stream = alloc(std::fstream, trace_file, std::ios_base::out);
|
||||
|
@ -1333,9 +1315,7 @@ ast_manager::ast_manager(proof_gen_mode m, std::fstream * trace_stream, bool is_
|
|||
m_expr_dependency_manager(*this, m_alloc),
|
||||
m_expr_dependency_array_manager(*this, m_alloc),
|
||||
m_proof_mode(m),
|
||||
m_trace_stream(trace_stream),
|
||||
m_trace_stream_owner(false),
|
||||
m_lambda_def(":lambda-def") {
|
||||
m_trace_stream(trace_stream) {
|
||||
|
||||
if (!is_format_manager)
|
||||
m_format_manager = alloc(ast_manager, PGM_DISABLED, trace_stream, true);
|
||||
|
@ -1350,9 +1330,7 @@ ast_manager::ast_manager(ast_manager const & src, bool disable_proofs):
|
|||
m_expr_dependency_manager(*this, m_alloc),
|
||||
m_expr_dependency_array_manager(*this, m_alloc),
|
||||
m_proof_mode(disable_proofs ? PGM_DISABLED : src.m_proof_mode),
|
||||
m_trace_stream(src.m_trace_stream),
|
||||
m_trace_stream_owner(false),
|
||||
m_lambda_def(":lambda-def") {
|
||||
m_trace_stream(src.m_trace_stream) {
|
||||
SASSERT(!src.is_format_manager());
|
||||
m_format_manager = alloc(ast_manager, PGM_DISABLED, m_trace_stream, true);
|
||||
init();
|
||||
|
@ -1880,6 +1858,8 @@ void ast_manager::delete_node(ast * n) {
|
|||
break;
|
||||
case AST_FUNC_DECL: {
|
||||
func_decl* f = to_func_decl(n);
|
||||
if (f->is_polymorphic())
|
||||
m_poly_roots.erase(f);
|
||||
if (f->m_info != nullptr) {
|
||||
func_decl_info * info = f->get_info();
|
||||
if (info->is_lambda()) {
|
||||
|
@ -2020,10 +2000,6 @@ sort * ast_manager::mk_uninterpreted_sort(symbol const & name, unsigned num_para
|
|||
return plugin->mk_sort(kind, num_parameters, parameters);
|
||||
}
|
||||
|
||||
sort * ast_manager::mk_type_var(symbol const& name) {
|
||||
sort_info si(poly_family_id, 0);
|
||||
return mk_sort(name, &si);
|
||||
}
|
||||
|
||||
func_decl * ast_manager::mk_func_decl(symbol const & name, unsigned arity, sort * const * domain, sort * range,
|
||||
bool assoc, bool comm, bool inj) {
|
||||
|
@ -2035,13 +2011,30 @@ func_decl * ast_manager::mk_func_decl(symbol const & name, unsigned arity, sort
|
|||
}
|
||||
|
||||
func_decl * ast_manager::mk_func_decl(symbol const & name, unsigned arity, sort * const * domain, sort * range, func_decl_info * info) {
|
||||
SASSERT(arity == 1 || info == 0 || !info->is_injective());
|
||||
SASSERT(arity == 2 || info == 0 || !info->is_associative());
|
||||
SASSERT(arity == 2 || info == 0 || !info->is_commutative());
|
||||
SASSERT(arity == 1 || !info || !info->is_injective());
|
||||
SASSERT(arity == 2 || !info || !info->is_associative());
|
||||
SASSERT(arity == 2 || !info || !info->is_commutative());
|
||||
unsigned sz = func_decl::get_obj_size(arity);
|
||||
void * mem = allocate_node(sz);
|
||||
func_decl * new_node = new (mem) func_decl(name, arity, domain, range, info);
|
||||
return register_node(new_node);
|
||||
|
||||
// determine if function is a polymorphic root object.
|
||||
// instances of polymorphic functions are automatically tagged as polymorphic and
|
||||
// inserted into the m_poly_roots table.
|
||||
bool is_polymorphic_root = false;
|
||||
func_decl_info info0;
|
||||
if (has_type_var(arity, domain, range)) {
|
||||
if (!info)
|
||||
info = &info0;
|
||||
if (!info->is_polymorphic()) {
|
||||
info->set_polymorphic(true);
|
||||
is_polymorphic_root = true;
|
||||
}
|
||||
}
|
||||
func_decl* new_node = new (mem) func_decl(name, arity, domain, range, info);
|
||||
new_node = register_node(new_node);
|
||||
if (is_polymorphic_root)
|
||||
m_poly_roots.insert(new_node, new_node);
|
||||
return new_node;
|
||||
}
|
||||
|
||||
void ast_manager::check_sort(func_decl const * decl, unsigned num_args, expr * const * args) const {
|
||||
|
@ -2306,9 +2299,10 @@ func_decl * ast_manager::mk_fresh_func_decl(symbol const & prefix, symbol const
|
|||
func_decl_info info(null_family_id, null_decl_kind);
|
||||
info.m_skolem = skolem;
|
||||
SASSERT(skolem == info.is_skolem());
|
||||
func_decl_info* infop = skolem ? &info : nullptr;
|
||||
func_decl * d;
|
||||
if (prefix == symbol::null && suffix == symbol::null) {
|
||||
d = mk_func_decl(symbol(m_fresh_id), arity, domain, range, &info);
|
||||
d = mk_func_decl(symbol(m_fresh_id), arity, domain, range, infop);
|
||||
}
|
||||
else {
|
||||
string_buffer<64> buffer;
|
||||
|
@ -2320,10 +2314,10 @@ func_decl * ast_manager::mk_fresh_func_decl(symbol const & prefix, symbol const
|
|||
if (suffix != symbol::null)
|
||||
buffer << suffix << "!";
|
||||
buffer << m_fresh_id;
|
||||
d = mk_func_decl(symbol(buffer.c_str()), arity, domain, range, &info);
|
||||
d = mk_func_decl(symbol(buffer.c_str()), arity, domain, range, infop);
|
||||
}
|
||||
m_fresh_id++;
|
||||
SASSERT(d->get_info());
|
||||
SASSERT(!skolem || d->get_info());
|
||||
SASSERT(skolem == d->is_skolem());
|
||||
return d;
|
||||
}
|
||||
|
@ -2725,6 +2719,49 @@ bool ast_manager::is_fully_interp(sort * s) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
// Polymorphism
|
||||
// -----------------------------------------
|
||||
sort * ast_manager::mk_type_var(symbol const& name) {
|
||||
m_has_type_vars = true;
|
||||
sort_info si(poly_family_id, 0);
|
||||
return mk_sort(name, &si);
|
||||
}
|
||||
|
||||
bool ast_manager::has_type_var(sort* s) const {
|
||||
if (is_type_var(s))
|
||||
return true;
|
||||
for (parameter const& p : s->parameters())
|
||||
if (p.is_ast() && is_sort(p.get_ast()) && has_type_var(to_sort(p.get_ast())))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ast_manager::has_type_var(func_decl* f) const {
|
||||
return has_type_var(f->get_arity(), f->get_domain(), f->get_range());
|
||||
}
|
||||
|
||||
bool ast_manager::has_type_var(unsigned n, sort* const* domain, sort* range) const {
|
||||
if (!has_type_vars())
|
||||
return false;
|
||||
for (unsigned i = n; i-- > 0; )
|
||||
if (has_type_var(domain[i]))
|
||||
return true;
|
||||
return has_type_var(range);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief create an instantiation of polymorphic function f.
|
||||
*/
|
||||
|
||||
func_decl* ast_manager::instantiate_polymorphic(func_decl* f, unsigned arity, sort * const* domain, sort * range) {
|
||||
SASSERT(f->is_polymorphic());
|
||||
func_decl* g = mk_func_decl(f->get_name(), arity, domain, range, f->get_info());
|
||||
m_poly_roots.insert(g, f);
|
||||
// SASSERT(g->is_polymorphic());
|
||||
return g;
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// Proof generation
|
||||
|
@ -2847,29 +2884,40 @@ proof * ast_manager::mk_transitivity(proof * p1, proof * p2) {
|
|||
SASSERT(has_fact(p2));
|
||||
SASSERT(is_app(get_fact(p1)));
|
||||
SASSERT(is_app(get_fact(p2)));
|
||||
SASSERT(to_app(get_fact(p1))->get_num_args() == 2);
|
||||
SASSERT(to_app(get_fact(p2))->get_num_args() == 2);
|
||||
CTRACE("mk_transitivity", to_app(get_fact(p1))->get_decl() != to_app(get_fact(p2))->get_decl(),
|
||||
tout << mk_pp(get_fact(p1), *this) << "\n\n" << mk_pp(get_fact(p2), *this) << "\n";
|
||||
tout << mk_pp(to_app(get_fact(p1))->get_decl(), *this) << "\n";
|
||||
tout << mk_pp(to_app(get_fact(p2))->get_decl(), *this) << "\n";);
|
||||
SASSERT(to_app(get_fact(p1))->get_decl() == to_app(get_fact(p2))->get_decl() ||
|
||||
( (is_eq(get_fact(p1)) || is_oeq(get_fact(p1))) &&
|
||||
(is_eq(get_fact(p2)) || is_oeq(get_fact(p2)))));
|
||||
CTRACE("mk_transitivity", to_app(get_fact(p1))->get_arg(1) != to_app(get_fact(p2))->get_arg(0),
|
||||
tout << mk_pp(get_fact(p1), *this) << "\n\n" << mk_pp(get_fact(p2), *this) << "\n";
|
||||
app* fact1 = to_app(get_fact(p1));
|
||||
app* fact2 = to_app(get_fact(p2));
|
||||
SASSERT(fact1->get_num_args() == 2);
|
||||
SASSERT(fact2->get_num_args() == 2);
|
||||
CTRACE("mk_transitivity", fact1->get_decl() != fact2->get_decl(),
|
||||
tout << mk_pp(fact1, *this) << "\n\n" << mk_pp(fact2, *this) << "\n";
|
||||
tout << mk_pp(fact1->get_decl(), *this) << "\n";
|
||||
tout << mk_pp(fact2->get_decl(), *this) << "\n";);
|
||||
SASSERT(fact1->get_decl() == fact2->get_decl() ||
|
||||
( (is_eq(fact1) || is_oeq(fact1)) &&
|
||||
(is_eq(fact2) || is_oeq(fact2))));
|
||||
CTRACE("mk_transitivity", fact1->get_arg(1) != fact2->get_arg(0),
|
||||
tout << mk_pp(fact1, *this) << "\n\n" << mk_pp(fact2, *this) << "\n";
|
||||
tout << p1->get_id() << ": " << mk_bounded_pp(p1, *this, 5) << "\n\n";
|
||||
tout << p2->get_id() << ": " << mk_bounded_pp(p2, *this, 5) << "\n\n";
|
||||
);
|
||||
SASSERT(to_app(get_fact(p1))->get_arg(1) == to_app(get_fact(p2))->get_arg(0));
|
||||
if (is_reflexivity(p1))
|
||||
return p2;
|
||||
if (is_reflexivity(p2))
|
||||
return p1;
|
||||
// local fixup to admit inline simplifications of not(not(e)) to e
|
||||
expr* e;
|
||||
if (is_not(fact1->get_arg(1), e) && is_not(e, e) && e == fact2->get_arg(0))
|
||||
p1 = mk_transitivity(p1, mk_rewrite(fact1->get_arg(1), fact2->get_arg(0)));
|
||||
else if (is_not(fact2->get_arg(0), e) && is_not(e, e) && e == fact1->get_arg(1))
|
||||
p1 = mk_transitivity(p1, mk_rewrite(fact1->get_arg(1), fact2->get_arg(0)));
|
||||
else {
|
||||
SASSERT(fact1->get_arg(1) == fact2->get_arg(0));
|
||||
}
|
||||
// OEQ is compatible with EQ for transitivity.
|
||||
func_decl* f = to_app(get_fact(p1))->get_decl();
|
||||
if (is_oeq(get_fact(p2))) f = to_app(get_fact(p2))->get_decl();
|
||||
return mk_app(basic_family_id, PR_TRANSITIVITY, p1, p2, mk_app(f, to_app(get_fact(p1))->get_arg(0), to_app(get_fact(p2))->get_arg(1)));
|
||||
func_decl* f = fact1->get_decl();
|
||||
if (is_oeq(fact2))
|
||||
f = fact2->get_decl();
|
||||
return mk_app(basic_family_id, PR_TRANSITIVITY, p1, p2, mk_app(f, fact1->get_arg(0), fact2->get_arg(1)));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -400,6 +400,7 @@ struct func_decl_info : public decl_info {
|
|||
bool m_idempotent:1;
|
||||
bool m_skolem:1;
|
||||
bool m_lambda:1;
|
||||
bool m_polymorphic:1;
|
||||
|
||||
func_decl_info(family_id family_id = null_family_id, decl_kind k = null_decl_kind, unsigned num_parameters = 0, parameter const * parameters = nullptr);
|
||||
|
||||
|
@ -414,6 +415,7 @@ struct func_decl_info : public decl_info {
|
|||
bool is_idempotent() const { return m_idempotent; }
|
||||
bool is_skolem() const { return m_skolem; }
|
||||
bool is_lambda() const { return m_lambda; }
|
||||
bool is_polymorphic() const { return m_polymorphic; }
|
||||
|
||||
void set_associative(bool flag = true) { m_left_assoc = flag; m_right_assoc = flag; }
|
||||
void set_left_associative(bool flag = true) { m_left_assoc = flag; }
|
||||
|
@ -426,6 +428,7 @@ struct func_decl_info : public decl_info {
|
|||
void set_idempotent(bool flag = true) { m_idempotent = flag; }
|
||||
void set_skolem(bool flag = true) { m_skolem = flag; }
|
||||
void set_lambda(bool flag = true) { m_lambda = flag; }
|
||||
void set_polymorphic(bool flag = true) { m_polymorphic = flag; }
|
||||
|
||||
bool operator==(func_decl_info const & info) const;
|
||||
|
||||
|
@ -655,6 +658,7 @@ public:
|
|||
bool is_skolem() const { return get_info() != nullptr && get_info()->is_skolem(); }
|
||||
bool is_lambda() const { return get_info() != nullptr && get_info()->is_lambda(); }
|
||||
bool is_idempotent() const { return get_info() != nullptr && get_info()->is_idempotent(); }
|
||||
bool is_polymorphic() const { return get_info() != nullptr && get_info()->is_polymorphic(); }
|
||||
unsigned get_arity() const { return m_arity; }
|
||||
sort * get_domain(unsigned idx) const { SASSERT(idx < get_arity()); return m_domain[idx]; }
|
||||
sort * const * get_domain() const { return m_domain; }
|
||||
|
@ -966,11 +970,6 @@ inline quantifier const * to_quantifier(ast const * n) { SASSERT(is_quantifier(n
|
|||
unsigned get_node_hash(ast const * n);
|
||||
bool compare_nodes(ast const * n1, ast const * n2);
|
||||
unsigned get_node_size(ast const * n);
|
||||
unsigned get_asts_hash(unsigned sz, ast * const* ns, unsigned init);
|
||||
unsigned get_apps_hash(unsigned sz, app * const* ns, unsigned init);
|
||||
unsigned get_exprs_hash(unsigned sz, expr * const* ns, unsigned init);
|
||||
unsigned get_sorts_hash(unsigned sz, sort * const* ns, unsigned init);
|
||||
unsigned get_decl_hash(unsigned sz, func_decl* const* ns, unsigned init);
|
||||
|
||||
// This is the internal comparison functor for hash-consing AST nodes.
|
||||
struct ast_eq_proc {
|
||||
|
@ -1511,13 +1510,15 @@ protected:
|
|||
unsigned m_fresh_id;
|
||||
bool m_debug_ref_count;
|
||||
u_map<unsigned> m_debug_free_indices;
|
||||
std::fstream* m_trace_stream;
|
||||
bool m_trace_stream_owner;
|
||||
std::fstream* m_trace_stream = nullptr;
|
||||
bool m_trace_stream_owner = false;
|
||||
bool m_has_type_vars = false;
|
||||
#ifdef Z3DEBUG
|
||||
bool slow_not_contains(ast const * n);
|
||||
#endif
|
||||
ast_manager * m_format_manager; // hack for isolating format objects in a different manager.
|
||||
symbol m_lambda_def;
|
||||
symbol m_lambda_def = symbol(":lambda-def");
|
||||
obj_map<func_decl, func_decl*> m_poly_roots;
|
||||
|
||||
void init();
|
||||
|
||||
|
@ -1734,12 +1735,27 @@ public:
|
|||
|
||||
bool is_uninterp(sort const * s) const { return s->get_family_id() == null_family_id || s->get_family_id() == user_sort_family_id; }
|
||||
|
||||
bool is_type_var(sort const* s) const { return s->get_family_id() == poly_family_id; }
|
||||
|
||||
bool has_type_vars() const { return m_has_type_vars; }
|
||||
|
||||
func_decl* poly_root(func_decl* f) const { SASSERT(f->is_polymorphic()); return m_poly_roots[f]; }
|
||||
|
||||
|
||||
func_decl* instantiate_polymorphic(func_decl* f, unsigned arity, sort * const* domain, sort * range);
|
||||
|
||||
/**
|
||||
\brief A sort is "fully" interpreted if it is interpreted,
|
||||
and doesn't depend on other uninterpreted sorts.
|
||||
*/
|
||||
bool is_fully_interp(sort * s) const;
|
||||
|
||||
bool has_type_var(sort* s) const;
|
||||
|
||||
bool has_type_var(func_decl* f) const;
|
||||
|
||||
bool has_type_var(unsigned n, sort* const* domain, sort* range) const;
|
||||
|
||||
func_decl * mk_func_decl(family_id fid, decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range = nullptr);
|
||||
|
||||
|
|
|
@ -65,6 +65,13 @@ void ast_translation::collect_decl_extra_children(decl * d) {
|
|||
}
|
||||
|
||||
void ast_translation::push_frame(ast * n) {
|
||||
// ensure poly roots are pushed first.
|
||||
if (m_from_manager.has_type_vars() && n->get_kind() == AST_FUNC_DECL && to_func_decl(n)->is_polymorphic()) {
|
||||
func_decl* g = m_from_manager.poly_root(to_func_decl(n));
|
||||
if (n != g && m_cache.contains(g)) {
|
||||
m_frame_stack.push_back(frame(n, 0, m_extra_children_stack.size(), m_result_stack.size()));
|
||||
}
|
||||
}
|
||||
m_frame_stack.push_back(frame(n, 0, m_extra_children_stack.size(), m_result_stack.size()));
|
||||
switch (n->get_kind()) {
|
||||
case AST_SORT:
|
||||
|
@ -153,6 +160,10 @@ void ast_translation::mk_func_decl(func_decl * f, frame & fr) {
|
|||
new_domain,
|
||||
new_range);
|
||||
}
|
||||
else if (f->is_polymorphic() && m_from_manager.poly_root(f) != f) {
|
||||
func_decl* fr = to_func_decl(m_cache[m_from_manager.poly_root(f)]);
|
||||
new_f = m_to_manager.instantiate_polymorphic(fr, f->get_arity(), new_domain, new_range);
|
||||
}
|
||||
else {
|
||||
buffer<parameter> ps;
|
||||
copy_params(f, fr.m_rpos, ps);
|
||||
|
|
|
@ -24,7 +24,8 @@ Notes:
|
|||
* Add or overwrite value in model.
|
||||
*/
|
||||
void model_converter::display_add(std::ostream& out, smt2_pp_environment& env, ast_manager& m, func_decl* f, expr* e) {
|
||||
VERIFY(e);
|
||||
if (!e)
|
||||
return;
|
||||
VERIFY(f->get_range() == e->get_sort());
|
||||
ast_smt2_pp_rev(out, f, e, env, params_ref(), 0, "model-add") << "\n";
|
||||
}
|
||||
|
|
|
@ -39,8 +39,10 @@ namespace euf {
|
|||
}
|
||||
m_expr2enode.setx(f->get_id(), n, nullptr);
|
||||
push_node(n);
|
||||
for (unsigned i = 0; i < num_args; ++i)
|
||||
set_cgc_enabled(args[i], true);
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
set_cgc_enabled(args[i], true);
|
||||
args[i]->get_root()->set_is_shared(l_undef);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -70,7 +72,7 @@ namespace euf {
|
|||
}
|
||||
|
||||
enode_bool_pair egraph::insert_table(enode* p) {
|
||||
TRACE("euf", tout << bpp(p) << "\n");
|
||||
TRACE("euf", tout << "insert_table " << bpp(p) << "\n");
|
||||
//SASSERT(!m_table.contains_ptr(p));
|
||||
auto rc = m_table.insert(p);
|
||||
p->m_cg = rc.first;
|
||||
|
@ -82,9 +84,14 @@ namespace euf {
|
|||
}
|
||||
|
||||
void egraph::reinsert_equality(enode* p) {
|
||||
SASSERT(p->is_equality());
|
||||
SASSERT(p->is_equality());
|
||||
if (p->value() != l_true && p->get_arg(0)->get_root() == p->get_arg(1)->get_root())
|
||||
add_literal(p, nullptr);
|
||||
queue_literal(p, nullptr);
|
||||
}
|
||||
|
||||
void egraph::queue_literal(enode* p, enode* ante) {
|
||||
if (m_on_propagate_literal)
|
||||
m_to_merge.push_back(to_merge(p, ante));
|
||||
}
|
||||
|
||||
void egraph::force_push() {
|
||||
|
@ -128,9 +135,8 @@ namespace euf {
|
|||
if (n2 == n)
|
||||
update_children(n);
|
||||
else
|
||||
push_merge(n, n2, justification::congruence(comm, 0));
|
||||
// merge(n, n2, justification::congruence(comm, m_congruence_timestamp++));
|
||||
|
||||
push_merge(n, n2, comm);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -145,18 +151,9 @@ namespace euf {
|
|||
memory::deallocate(m_tmp_node);
|
||||
}
|
||||
|
||||
void egraph::add_plugins() {
|
||||
if (!m_plugins.empty())
|
||||
return;
|
||||
|
||||
auto insert = [&](plugin* p) {
|
||||
m_plugins.reserve(p->get_id() + 1);
|
||||
m_plugins.set(p->get_id(), p);
|
||||
};
|
||||
|
||||
insert(alloc(bv_plugin, *this));
|
||||
insert(alloc(arith_plugin, *this));
|
||||
insert(alloc(specrel_plugin, *this));
|
||||
void egraph::add_plugin(plugin* p) {
|
||||
m_plugins.reserve(p->get_id() + 1);
|
||||
m_plugins.set(p->get_id(), p);
|
||||
}
|
||||
|
||||
void egraph::propagate_plugins() {
|
||||
|
@ -188,25 +185,21 @@ namespace euf {
|
|||
}
|
||||
|
||||
void egraph::add_literal(enode* n, enode* ante) {
|
||||
TRACE("euf", tout << "propagate " << bpp(n) << " " << bpp(ante) << "\n");
|
||||
if (!m_on_propagate_literal)
|
||||
return;
|
||||
if (!ante) ++m_stats.m_num_eqs; else ++m_stats.m_num_lits;
|
||||
if (!ante)
|
||||
m_on_propagate_literal(n, ante);
|
||||
else if (m.is_true(ante->get_expr()) || m.is_false(ante->get_expr())) {
|
||||
for (enode* k : enode_class(n)) {
|
||||
if (k != ante) {
|
||||
//verbose_stream() << "eq: " << k->value() << " " <<ante->value() << "\n";
|
||||
m_on_propagate_literal(k, ante);
|
||||
}
|
||||
}
|
||||
for (enode* k : enode_class(n))
|
||||
if (k != ante)
|
||||
m_on_propagate_literal(k, ante);
|
||||
}
|
||||
else {
|
||||
for (enode* k : enode_class(n)) {
|
||||
if (k->value() != ante->value()) {
|
||||
//verbose_stream() << "eq: " << k->value() << " " <<ante->value() << "\n";
|
||||
m_on_propagate_literal(k, ante);
|
||||
}
|
||||
if (k->value() != ante->value())
|
||||
m_on_propagate_literal(k, ante);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -516,6 +509,7 @@ namespace euf {
|
|||
c->m_root = r2;
|
||||
std::swap(r1->m_next, r2->m_next);
|
||||
r2->inc_class_size(r1->class_size());
|
||||
r2->set_is_shared(l_undef);
|
||||
merge_th_eq(r1, r2, j);
|
||||
reinsert_parents(r1, r2);
|
||||
if (j.is_congruence() && (m.is_false(r2->get_expr()) || m.is_true(r2->get_expr())))
|
||||
|
@ -532,6 +526,7 @@ namespace euf {
|
|||
|
||||
void egraph::remove_parents(enode* r) {
|
||||
TRACE("euf", tout << bpp(r) << "\n");
|
||||
SASSERT(all_of(enode_parents(r), [&](enode* p) { return !p->is_marked1(); }));
|
||||
for (enode* p : enode_parents(r)) {
|
||||
if (p->is_marked1())
|
||||
continue;
|
||||
|
@ -558,7 +553,7 @@ namespace euf {
|
|||
if (p->cgc_enabled()) {
|
||||
auto [p_other, comm] = insert_table(p);
|
||||
SASSERT(m_table.contains_ptr(p) == (p_other == p));
|
||||
TRACE("euf", tout << "other " << bpp(p_other) << "\n";);
|
||||
CTRACE("euf", p_other != p, tout << "reinsert " << bpp(p) << " == " << bpp(p_other) << " " << p->value() << " " << p_other->value() << "\n");
|
||||
if (p_other != p)
|
||||
m_to_merge.push_back(to_merge(p_other, p, comm));
|
||||
else
|
||||
|
@ -594,6 +589,7 @@ namespace euf {
|
|||
enode* r2 = r1->get_root();
|
||||
TRACE("euf", tout << "undo-eq old-root: " << bpp(r1) << " current-root " << bpp(r2) << " node: " << bpp(n1) << "\n";);
|
||||
r2->dec_class_size(r1->class_size());
|
||||
r2->set_is_shared(l_undef);
|
||||
std::swap(r1->m_next, r2->m_next);
|
||||
auto begin = r2->begin_parents() + r2_num_parents, end = r2->end_parents();
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
|
@ -615,18 +611,29 @@ namespace euf {
|
|||
unmerge_justification(n1);
|
||||
}
|
||||
|
||||
bool egraph::propagate() {
|
||||
|
||||
bool egraph::propagate() {
|
||||
force_push();
|
||||
propagate_plugins();
|
||||
for (unsigned i = 0; i < m_to_merge.size() && m.limit().inc() && !inconsistent(); ++i) {
|
||||
auto const& w = m_to_merge[i];
|
||||
if (w.j.is_congruence())
|
||||
merge(w.a, w.b, justification::congruence(w.j.is_commutative(), m_congruence_timestamp++));
|
||||
else
|
||||
merge(w.a, w.b, w.j);
|
||||
|
||||
if (i + 1 == m_to_merge.size())
|
||||
propagate_plugins();
|
||||
unsigned i = 0;
|
||||
bool change = true;
|
||||
while (change) {
|
||||
change = false;
|
||||
propagate_plugins();
|
||||
for (; i < m_to_merge.size() && m.limit().inc() && !inconsistent(); ++i) {
|
||||
auto const& w = m_to_merge[i];
|
||||
switch (w.t) {
|
||||
case to_merge_plain:
|
||||
case to_merge_comm:
|
||||
merge(w.a, w.b, justification::congruence(w.commutativity(), m_congruence_timestamp++));
|
||||
break;
|
||||
case to_justified:
|
||||
merge(w.a, w.b, w.j);
|
||||
break;
|
||||
case to_add_literal:
|
||||
add_literal(w.a, w.b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_to_merge.reset();
|
||||
return
|
||||
|
@ -642,7 +649,7 @@ namespace euf {
|
|||
m_updates.push_back(update_record(false, update_record::inconsistent()));
|
||||
m_n1 = n1;
|
||||
m_n2 = n2;
|
||||
TRACE("euf", tout << "conflict " << bpp(n1) << " " << bpp(n2) << " " << j << "\n");
|
||||
TRACE("euf", tout << "conflict " << bpp(n1) << " " << bpp(n2) << " " << j << " " << n1->get_root()->value() << " " << n2->get_root()->value() << "\n");
|
||||
m_justification = j;
|
||||
}
|
||||
|
||||
|
@ -920,7 +927,7 @@ namespace euf {
|
|||
for (enode* n : m_nodes)
|
||||
max_args = std::max(max_args, n->num_args());
|
||||
for (enode* n : m_nodes)
|
||||
display(out, max_args, n);
|
||||
display(out, max_args, n);
|
||||
for (auto* p : m_plugins)
|
||||
if (p)
|
||||
p->display(out);
|
||||
|
|
|
@ -88,11 +88,15 @@ namespace euf {
|
|||
|
||||
typedef ptr_vector<trail> trail_stack;
|
||||
|
||||
enum to_merge_t { to_merge_plain, to_merge_comm, to_justified, to_add_literal };
|
||||
struct to_merge {
|
||||
enode* a, * b;
|
||||
to_merge_t t;
|
||||
justification j;
|
||||
to_merge(enode* a, enode* b, bool c) : a(a), b(b), j(justification::congruence(c, 0)) {}
|
||||
to_merge(enode* a, enode* b, justification j) : a(a), b(b), j(j) {}
|
||||
bool commutativity() const { return t == to_merge_comm; }
|
||||
to_merge(enode* a, enode* b, bool c) : a(a), b(b), t(c ? to_merge_comm : to_merge_plain) {}
|
||||
to_merge(enode* a, enode* b, justification j): a(a), b(b), t(to_justified), j(j) {}
|
||||
to_merge(enode* p, enode* ante): a(p), b(ante), t(to_add_literal) {}
|
||||
};
|
||||
|
||||
struct stats {
|
||||
|
@ -215,6 +219,7 @@ namespace euf {
|
|||
// plugin related methods
|
||||
void push_plugin_undo(unsigned th_id) { m_updates.push_back(update_record(th_id, update_record::plugin_undo())); }
|
||||
void push_merge(enode* a, enode* b, justification j) { m_to_merge.push_back({ a, b, j }); }
|
||||
void push_merge(enode* a, enode* b, bool comm) { m_to_merge.push_back({ a, b, comm }); }
|
||||
void propagate_plugins();
|
||||
|
||||
void add_th_eq(theory_id id, theory_var v1, theory_var v2, enode* c, enode* r);
|
||||
|
@ -222,6 +227,7 @@ namespace euf {
|
|||
void add_th_diseqs(theory_id id, theory_var v1, enode* r);
|
||||
bool th_propagates_diseqs(theory_id id) const;
|
||||
void add_literal(enode* n, enode* ante);
|
||||
void queue_literal(enode* n, enode* ante);
|
||||
void undo_eq(enode* r1, enode* n1, unsigned r2_num_parents);
|
||||
void undo_add_th_var(enode* n, theory_id id);
|
||||
enode* mk_enode(expr* f, unsigned generation, unsigned num_args, enode * const* args);
|
||||
|
@ -256,8 +262,10 @@ namespace euf {
|
|||
public:
|
||||
egraph(ast_manager& m);
|
||||
~egraph();
|
||||
void add_plugins();
|
||||
|
||||
void add_plugin(plugin* p);
|
||||
plugin* get_plugin(family_id fid) const { return m_plugins.get(fid, nullptr); }
|
||||
|
||||
enode* find(expr* f) const { return m_expr2enode.get(f->get_id(), nullptr); }
|
||||
enode* find(expr* f, unsigned n, enode* const* args);
|
||||
enode* mk(expr* f, unsigned generation, unsigned n, enode *const* args);
|
||||
|
@ -284,6 +292,7 @@ namespace euf {
|
|||
of new equalities.
|
||||
*/
|
||||
bool propagate();
|
||||
bool can_propagate() const { return !m_to_merge.empty(); }
|
||||
bool inconsistent() const { return m_inconsistent; }
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace euf {
|
|||
bool m_merge_tf_enabled = false;
|
||||
bool m_is_equality = false; // Does the expression represent an equality
|
||||
bool m_is_relevant = false;
|
||||
lbool m_is_shared = l_undef;
|
||||
lbool m_value = l_undef; // Assignment by SAT solver for Boolean node
|
||||
sat::bool_var m_bool_var = sat::null_bool_var; // SAT solver variable associated with Boolean node
|
||||
unsigned m_class_size = 1; // Size of the equivalence class if the enode is the root.
|
||||
|
@ -96,6 +97,7 @@ namespace euf {
|
|||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
SASSERT(to_app(f)->get_arg(i) == args[i]->get_expr());
|
||||
n->m_args[i] = args[i];
|
||||
n->m_args[i]->get_root()->set_is_shared(l_undef);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
@ -181,6 +183,9 @@ namespace euf {
|
|||
void unmark3() { m_mark3 = false; }
|
||||
bool is_marked3() { return m_mark3; }
|
||||
|
||||
lbool is_shared() const { return m_is_shared; }
|
||||
void set_is_shared(lbool s) { m_is_shared = s; }
|
||||
|
||||
template<bool m> void mark1_targets() {
|
||||
enode* n = this;
|
||||
while (n) {
|
||||
|
|
|
@ -237,6 +237,8 @@ namespace euf {
|
|||
UNTAG(table*, t)->erase(n);
|
||||
break;
|
||||
}
|
||||
CTRACE("euf", contains_ptr(n), display(tout));
|
||||
SASSERT(!contains_ptr(n));
|
||||
}
|
||||
|
||||
bool etable::contains(enode* n) const {
|
||||
|
|
|
@ -109,9 +109,9 @@ bool has_skolem_functions(expr * n) {
|
|||
|
||||
subterms::subterms(expr_ref_vector const& es, bool include_bound, ptr_vector<expr>* esp, expr_mark* vp): m_include_bound(include_bound), m_es(es), m_esp(esp), m_vp(vp) {}
|
||||
subterms::subterms(expr_ref const& e, bool include_bound, ptr_vector<expr>* esp, expr_mark* vp) : m_include_bound(include_bound), m_es(e.m()), m_esp(esp), m_vp(vp) { if (e) m_es.push_back(e); }
|
||||
subterms::iterator subterms::begin() { return iterator(* this, m_esp, m_vp, true); }
|
||||
subterms::iterator subterms::end() { return iterator(*this, nullptr, nullptr, false); }
|
||||
subterms::iterator::iterator(subterms& f, ptr_vector<expr>* esp, expr_mark* vp, bool start): m_include_bound(f.m_include_bound), m_esp(esp), m_visitedp(vp) {
|
||||
subterms::iterator subterms::begin() const { return iterator(* this, m_esp, m_vp, true); }
|
||||
subterms::iterator subterms::end() const { return iterator(*this, nullptr, nullptr, false); }
|
||||
subterms::iterator::iterator(subterms const& f, ptr_vector<expr>* esp, expr_mark* vp, bool start): m_include_bound(f.m_include_bound), m_esp(esp), m_visitedp(vp) {
|
||||
if (!esp)
|
||||
m_esp = &m_es;
|
||||
else
|
||||
|
|
|
@ -186,7 +186,7 @@ public:
|
|||
expr_mark m_visited;
|
||||
expr_mark* m_visitedp = nullptr;
|
||||
public:
|
||||
iterator(subterms& f, ptr_vector<expr>* esp, expr_mark* vp, bool start);
|
||||
iterator(subterms const& f, ptr_vector<expr>* esp, expr_mark* vp, bool start);
|
||||
expr* operator*();
|
||||
iterator operator++(int);
|
||||
iterator& operator++();
|
||||
|
@ -198,8 +198,8 @@ public:
|
|||
static subterms ground(expr_ref const& e, ptr_vector<expr>* esp = nullptr, expr_mark* vp = nullptr) { return subterms(e, false, esp, vp); }
|
||||
static subterms all(expr_ref_vector const& e, ptr_vector<expr>* esp = nullptr, expr_mark* vp = nullptr) { return subterms(e, true, esp, vp); }
|
||||
static subterms ground(expr_ref_vector const& e, ptr_vector<expr>* esp = nullptr, expr_mark* vp = nullptr) { return subterms(e, false, esp, vp); }
|
||||
iterator begin();
|
||||
iterator end();
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
};
|
||||
|
||||
class subterms_postorder {
|
||||
|
|
|
@ -324,7 +324,7 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl *
|
|||
expr_ref else_value(m.mk_app(to_bv_i, dom.size(), dom.data()), m);
|
||||
result->set_else(else_value);
|
||||
}
|
||||
else if (m_fpa_util.is_to_real(f)) {
|
||||
else if (m_fpa_util.is_to_real(f)) {
|
||||
SASSERT(dom.size() == 1);
|
||||
func_decl_ref to_real_i(m.mk_func_decl(fid, OP_FPA_TO_REAL_I, 0, nullptr, dom.size(), dom.data()), m);
|
||||
expr_ref else_value(m.mk_app(to_real_i, dom.size(), dom.data()), m);
|
||||
|
@ -508,7 +508,7 @@ void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_mode
|
|||
}
|
||||
}
|
||||
|
||||
TRACE("bv2fpa", tout << "Target model: " << *target_model; );
|
||||
TRACE("bv2fpa", tout << "Target model: " << *target_model << std::endl; );
|
||||
}
|
||||
|
||||
void bv2fpa_converter::display(std::ostream & out) {
|
||||
|
|
|
@ -147,36 +147,11 @@ void fpa2bv_converter::mk_distinct(func_decl * f, unsigned num, expr * const * a
|
|||
|
||||
void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 0);
|
||||
sort* s = f->get_range();
|
||||
if (f->get_num_parameters() == 1) {
|
||||
SASSERT(f->get_parameter(0).is_external());
|
||||
unsigned p_id = f->get_parameter(0).get_ext_id();
|
||||
mpf const& v = m_plugin->get_value(p_id);
|
||||
mk_numeral(s, v, result);
|
||||
return;
|
||||
}
|
||||
scoped_mpf v(m_mpf_manager);
|
||||
unsigned ebits = m_util.get_ebits(s), sbits = m_util.get_sbits(s);
|
||||
switch (f->get_decl_kind()) {
|
||||
case OP_FPA_PLUS_INF:
|
||||
m_util.fm().mk_pinf(ebits, sbits, v);
|
||||
break;
|
||||
case OP_FPA_MINUS_INF:
|
||||
m_util.fm().mk_ninf(ebits, sbits, v);
|
||||
break;
|
||||
case OP_FPA_NAN:
|
||||
m_util.fm().mk_nan(ebits, sbits, v);
|
||||
break;
|
||||
case OP_FPA_PLUS_ZERO:
|
||||
m_util.fm().mk_pzero(ebits, sbits, v);
|
||||
break;
|
||||
case OP_FPA_MINUS_ZERO:
|
||||
m_util.fm().mk_nzero(ebits, sbits, v);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
mk_numeral(s, v, result);
|
||||
scoped_mpf v(m_mpf_manager);
|
||||
expr_ref a(m);
|
||||
a = m.mk_app(f, num, args);
|
||||
m_util.is_numeral(a, v);
|
||||
mk_numeral(f->get_range(), v, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_numeral(sort * s, mpf const & v, expr_ref & result) {
|
||||
|
@ -941,8 +916,8 @@ void fpa2bv_converter::mk_div(sort * s, expr_ref & rm, expr_ref & x, expr_ref &
|
|||
dbg_decouple("fpa2bv_div_y_is_pos", y_is_pos);
|
||||
dbg_decouple("fpa2bv_div_y_is_inf", y_is_inf);
|
||||
|
||||
expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m), c7(m);
|
||||
expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m), v8(m);
|
||||
expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m), c7(m), c8(m);
|
||||
expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m), v8(m), v9(m);
|
||||
|
||||
// (x is NaN) || (y is NaN) -> NaN
|
||||
m_simp.mk_or(x_is_nan, y_is_nan, c1);
|
||||
|
@ -998,6 +973,9 @@ void fpa2bv_converter::mk_div(sort * s, expr_ref & rm, expr_ref & x, expr_ref &
|
|||
a_sig_ext = m_bv_util.mk_concat(a_sig, m_bv_util.mk_numeral(0, sbits + extra_bits));
|
||||
b_sig_ext = m_bv_util.mk_zero_extend(sbits + extra_bits, b_sig);
|
||||
|
||||
dbg_decouple("fpa2bv_div_a_sig_ext", a_sig_ext);
|
||||
dbg_decouple("fpa2bv_div_b_sig_ext", b_sig_ext);
|
||||
|
||||
expr_ref a_exp_ext(m), b_exp_ext(m);
|
||||
a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp);
|
||||
b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp);
|
||||
|
@ -1017,14 +995,21 @@ void fpa2bv_converter::mk_div(sort * s, expr_ref & rm, expr_ref & x, expr_ref &
|
|||
expr_ref quotient(m);
|
||||
// b_sig_ext can't be 0 here, so it's safe to use OP_BUDIV_I
|
||||
quotient = m.mk_app(m_bv_util.get_fid(), OP_BUDIV_I, a_sig_ext, b_sig_ext);
|
||||
|
||||
dbg_decouple("fpa2bv_div_quotient", quotient);
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(quotient) == (sbits + sbits + extra_bits));
|
||||
|
||||
expr_ref sticky(m);
|
||||
expr_ref sticky(m), upper(m), upper_reduced(m), too_large(m);
|
||||
sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(extra_bits-2, 0, quotient));
|
||||
res_sig = m_bv_util.mk_concat(m_bv_util.mk_extract(extra_bits+sbits+1, extra_bits-1, quotient), sticky);
|
||||
upper = m_bv_util.mk_extract(sbits + sbits + extra_bits-1, extra_bits+sbits+2, quotient);
|
||||
upper_reduced = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, upper.get());
|
||||
too_large = m.mk_eq(upper_reduced, m_bv_util.mk_numeral(1, 1));
|
||||
c8 = too_large;
|
||||
mk_ite(signs_xor, ninf, pinf, v8);
|
||||
dbg_decouple("fpa2bv_div_res_sig_p4", res_sig);
|
||||
dbg_decouple("fpa2bv_div_upper", upper);
|
||||
dbg_decouple("fpa2bv_div_too_large", too_large);
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(res_sig) == (sbits + 4));
|
||||
|
||||
|
@ -1042,10 +1027,14 @@ void fpa2bv_converter::mk_div(sort * s, expr_ref & rm, expr_ref & x, expr_ref &
|
|||
m_simp.mk_ite(shift_cond, res_sig, res_sig_shifted, res_sig);
|
||||
m_simp.mk_ite(shift_cond, res_exp, res_exp_shifted, res_exp);
|
||||
|
||||
round(s, rm, res_sgn, res_sig, res_exp, v8);
|
||||
dbg_decouple("fpa2bv_div_res_sig", res_sig);
|
||||
dbg_decouple("fpa2bv_div_res_exp", res_exp);
|
||||
|
||||
round(s, rm, res_sgn, res_sig, res_exp, v9);
|
||||
|
||||
// And finally, we tie them together.
|
||||
mk_ite(c7, v7, v8, result);
|
||||
mk_ite(c8, v8, v9, result);
|
||||
mk_ite(c7, v7, result, result);
|
||||
mk_ite(c6, v6, result, result);
|
||||
mk_ite(c5, v5, result, result);
|
||||
mk_ite(c4, v4, result, result);
|
||||
|
@ -2809,8 +2798,46 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr *
|
|||
|
||||
expr * e = m.mk_eq(m_util.mk_to_real(result), x);
|
||||
m_extra_assertions.push_back(e);
|
||||
// x = 0 -> result = 0+
|
||||
m_extra_assertions.push_back(m.mk_implies(m.mk_eq(x, zero), m.mk_eq(result, m_util.mk_pzero(result->get_sort()))));
|
||||
|
||||
expr_ref r_is_nan(m);
|
||||
mk_is_nan(result, r_is_nan);
|
||||
m_extra_assertions.push_back(m.mk_not(r_is_nan));
|
||||
|
||||
rational min_real, max_real;
|
||||
const mpz& max_exp_z = m_mpf_manager.m_powers2.m1(ebits-1);
|
||||
SASSERT(m_mpz_manager.is_uint(max_exp_z));
|
||||
unsigned max_exp = m_mpz_manager.get_uint(max_exp_z);
|
||||
rational max_sig = m_mpf_manager.m_powers2.m1(sbits) / m_mpf_manager.m_powers2(sbits-1);
|
||||
max_real = max_sig * rational(m_mpf_manager.m_powers2(max_exp));
|
||||
TRACE("fpa2bv_to_real", tout << "max exp: " << max_exp << " max real: " << max_real << std::endl;);
|
||||
|
||||
expr_ref r_is_pinf(m), r_is_ninf(m);
|
||||
mk_is_pinf(result, r_is_pinf);
|
||||
mk_is_ninf(result, r_is_ninf);
|
||||
|
||||
expr_ref e_max_real(m), e_max_real_neg(m);
|
||||
e_max_real = m_arith_util.mk_numeral(max_real, false);
|
||||
e_max_real_neg = m_arith_util.mk_numeral(-max_real, false);
|
||||
|
||||
expr_ref rm_nta(m), rm_nte(m), rm_tp(m), rm_tn(m), rm_tz(m);
|
||||
mk_is_rm(bv_rm, BV_RM_TIES_TO_AWAY, rm_nta);
|
||||
mk_is_rm(bv_rm, BV_RM_TIES_TO_EVEN, rm_nte);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_POSITIVE, rm_tp);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_NEGATIVE, rm_tn);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_ZERO, rm_tz);
|
||||
|
||||
expr_ref implies_gt_max_real(m), implies_lt_min_real(m);
|
||||
implies_gt_max_real = m.mk_implies(r_is_pinf, m.mk_and(rm_tp, m_arith_util.mk_gt(x, e_max_real)));
|
||||
implies_lt_min_real = m.mk_implies(r_is_ninf, m.mk_and(rm_tn, m_arith_util.mk_lt(x, e_max_real_neg)));
|
||||
|
||||
m_extra_assertions.push_back(implies_gt_max_real);
|
||||
m_extra_assertions.push_back(implies_lt_min_real);
|
||||
|
||||
// x = 0 -> result = +0/-0
|
||||
expr_ref pzero(m), nzero(m);
|
||||
mk_pzero(result->get_sort(), pzero);
|
||||
mk_nzero(result->get_sort(), nzero);
|
||||
m_extra_assertions.push_back(m.mk_implies(m.mk_eq(x, zero), m.mk_or(m.mk_eq(result, pzero), m.mk_eq(result, nzero))));
|
||||
}
|
||||
|
||||
SASSERT(is_well_sorted(m, result));
|
||||
|
@ -2854,19 +2881,13 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con
|
|||
m_mpf_manager.set(tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, e.to_mpq().numerator(), q.to_mpq());
|
||||
m_mpf_manager.set(tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, e.to_mpq().numerator(), q.to_mpq());
|
||||
|
||||
app_ref a_nte(m), a_nta(m), a_tp(m), a_tn(m), a_tz(m);
|
||||
a_nte = m_plugin->mk_numeral(nte);
|
||||
a_nta = m_plugin->mk_numeral(nta);
|
||||
a_tp = m_plugin->mk_numeral(tp);
|
||||
a_tn = m_plugin->mk_numeral(tn);
|
||||
a_tz = m_plugin->mk_numeral(tz);
|
||||
|
||||
expr_ref bv_nte(m), bv_nta(m), bv_tp(m), bv_tn(m), bv_tz(m);
|
||||
mk_numeral(a_nte->get_decl(), 0, nullptr, bv_nte);
|
||||
mk_numeral(a_nta->get_decl(), 0, nullptr, bv_nta);
|
||||
mk_numeral(a_tp->get_decl(), 0, nullptr, bv_tp);
|
||||
mk_numeral(a_tn->get_decl(), 0, nullptr, bv_tn);
|
||||
mk_numeral(a_tz->get_decl(), 0, nullptr, bv_tz);
|
||||
sort *s = f->get_range();
|
||||
mk_numeral(s, nte, bv_nte);
|
||||
mk_numeral(s, nta, bv_nta);
|
||||
mk_numeral(s, tp, bv_tp);
|
||||
mk_numeral(s, tn, bv_tn);
|
||||
mk_numeral(s, tz, bv_tz);
|
||||
|
||||
expr_ref c1(m), c2(m), c3(m), c4(m);
|
||||
c1 = m.mk_eq(bv_rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3));
|
||||
|
@ -3003,27 +3024,34 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const
|
|||
unsigned bv_sz = m_bv_util.get_bv_size(x);
|
||||
SASSERT(m_bv_util.get_bv_size(rm) == 3);
|
||||
|
||||
expr_ref rm_is_to_neg(m);
|
||||
mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
|
||||
expr_ref bv1_1(m), bv0_sz(m);
|
||||
bv1_1 = m_bv_util.mk_numeral(1, 1);
|
||||
bv0_sz = m_bv_util.mk_numeral(0, bv_sz);
|
||||
|
||||
expr_ref is_zero(m), pzero(m);
|
||||
expr_ref is_zero(m), pzero(m), nzero(m);
|
||||
is_zero = m.mk_eq(x, bv0_sz);
|
||||
mk_pzero(f, pzero);
|
||||
mk_nzero(f, nzero);
|
||||
|
||||
// Special case: x == 0 -> p/n zero
|
||||
// Special case: x == 0 -> +zero
|
||||
expr_ref c1(m), v1(m);
|
||||
c1 = is_zero;
|
||||
v1 = pzero;
|
||||
v1 = pzero; // No -zero (IEEE754)
|
||||
|
||||
// Special case: x != 0
|
||||
expr_ref is_neg_bit(m), exp_too_large(m), sig_4(m), exp_2(m);
|
||||
expr_ref sign_bit(m), exp_too_large(m), sig_4(m), exp_2(m), rest(m);
|
||||
expr_ref is_neg(m), x_abs(m), neg_x(m);
|
||||
is_neg_bit = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, x);
|
||||
is_neg = m.mk_eq(is_neg_bit, bv1_1);
|
||||
neg_x = m_bv_util.mk_bv_neg(x); // overflow problem?
|
||||
sign_bit = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, x);
|
||||
rest = m_bv_util.mk_extract(bv_sz - 2, 0, x);
|
||||
dbg_decouple("fpa2bv_to_fp_signed_rest", rest);
|
||||
is_neg = m.mk_eq(sign_bit, bv1_1);
|
||||
neg_x = m_bv_util.mk_bv_neg(x); // overflow ok, x_abs is now unsigned.
|
||||
x_abs = m.mk_ite(is_neg, neg_x, x);
|
||||
dbg_decouple("fpa2bv_to_fp_signed_is_neg", is_neg);
|
||||
dbg_decouple("fpa2bv_to_fp_signed_x_abs", x_abs);
|
||||
// x_abs has an extra bit in the front.
|
||||
// x_abs is [bv_sz-1, bv_sz-2] . [bv_sz-3 ... 0] * 2^(bv_sz-2)
|
||||
// bv_sz-2 is the "1.0" bit for the rounder.
|
||||
|
@ -3075,7 +3103,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const
|
|||
|
||||
TRACE("fpa2bv_to_fp_signed", tout << "exp worst case sz: " << exp_worst_case_sz << std::endl;);
|
||||
|
||||
if (exp_sz < exp_worst_case_sz) {
|
||||
if (exp_sz <= exp_worst_case_sz) {
|
||||
// exp_sz < exp_worst_case_sz and exp >= 0.
|
||||
// Take the maximum legal exponent; this
|
||||
// allows us to keep the most precision.
|
||||
|
@ -3093,7 +3121,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const
|
|||
dbg_decouple("fpa2bv_to_fp_signed_exp_too_large", exp_too_large);
|
||||
|
||||
expr_ref sgn(m), sig(m), exp(m);
|
||||
sgn = is_neg_bit;
|
||||
sgn = sign_bit;
|
||||
sig = sig_4;
|
||||
exp = exp_2;
|
||||
|
||||
|
@ -3132,6 +3160,9 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con
|
|||
rm = to_app(args[0])->get_arg(0);
|
||||
x = args[1];
|
||||
|
||||
expr_ref rm_is_to_neg(m);
|
||||
mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
|
||||
dbg_decouple("fpa2bv_to_fp_unsigned_x", x);
|
||||
|
||||
unsigned ebits = m_util.get_ebits(f->get_range());
|
||||
|
@ -3143,14 +3174,15 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con
|
|||
bv0_1 = m_bv_util.mk_numeral(0, 1);
|
||||
bv0_sz = m_bv_util.mk_numeral(0, bv_sz);
|
||||
|
||||
expr_ref is_zero(m), pzero(m);
|
||||
expr_ref is_zero(m), pzero(m), nzero(m);
|
||||
is_zero = m.mk_eq(x, bv0_sz);
|
||||
mk_pzero(f, pzero);
|
||||
mk_nzero(f, nzero);
|
||||
|
||||
// Special case: x == 0 -> p/n zero
|
||||
// Special case: x == 0 -> +zero
|
||||
expr_ref c1(m), v1(m);
|
||||
c1 = is_zero;
|
||||
v1 = pzero;
|
||||
v1 = pzero; // No -zero (IEEE754)
|
||||
|
||||
// Special case: x != 0
|
||||
expr_ref exp_too_large(m), sig_4(m), exp_2(m);
|
||||
|
@ -3194,7 +3226,7 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con
|
|||
unsigned exp_sz = ebits + 2; // (+2 for rounder)
|
||||
exp_2 = m_bv_util.mk_extract(exp_sz - 1, 0, s_exp);
|
||||
// the remaining bits are 0 if ebits is large enough.
|
||||
exp_too_large = m.mk_false(); // This is always in range.
|
||||
exp_too_large = m.mk_false();
|
||||
|
||||
// The exponent is at most bv_sz, i.e., we need ld(bv_sz)+1 ebits.
|
||||
// exp < bv_sz (+sign bit which is [0])
|
||||
|
|
|
@ -208,6 +208,7 @@ protected:
|
|||
|
||||
private:
|
||||
void mk_nan(sort * s, expr_ref & result);
|
||||
|
||||
void mk_nzero(sort * s, expr_ref & result);
|
||||
void mk_pzero(sort * s, expr_ref & result);
|
||||
void mk_zero(sort * s, expr_ref & sgn, expr_ref & result);
|
||||
|
|
|
@ -18,6 +18,7 @@ Revision History:
|
|||
--*/
|
||||
#include "ast/normal_forms/elim_term_ite.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
|
||||
br_status elim_term_ite_cfg::reduce_app(func_decl* f, unsigned n, expr * const* args, expr_ref& result, proof_ref& result_pr) {
|
||||
if (!m.is_term_ite(f)) {
|
||||
|
@ -38,3 +39,4 @@ br_status elim_term_ite_cfg::reduce_app(func_decl* f, unsigned n, expr * const*
|
|||
return BR_DONE;
|
||||
}
|
||||
|
||||
template class rewriter_tpl<elim_term_ite_cfg>;
|
||||
|
|
|
@ -28,6 +28,7 @@ Notes:
|
|||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/normal_forms/name_exprs.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include <array>
|
||||
|
||||
/**
|
||||
|
@ -149,7 +150,7 @@ class skolemizer {
|
|||
p = nullptr;
|
||||
if (m_proofs_enabled) {
|
||||
if (q->get_kind() == forall_k)
|
||||
p = m.mk_skolemization(mk_not(m, q), m.mk_not(r));
|
||||
p = m.mk_skolemization(mk_not(m, q), mk_not(m, r));
|
||||
else
|
||||
p = m.mk_skolemization(q, r);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ Revision History:
|
|||
#include "ast/occurs.h"
|
||||
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/for_each_ast.h"
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
|
@ -49,6 +50,15 @@ namespace {
|
|||
void operator()(quantifier const * n) { }
|
||||
};
|
||||
|
||||
|
||||
struct sort_proc {
|
||||
sort* m_s;
|
||||
sort_proc(sort* s) :m_s(s) {}
|
||||
void operator()(sort const* s2) { if (m_s == s2) throw found(); }
|
||||
void operator()(ast*) {}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Return true if n1 occurs in n2
|
||||
|
@ -74,6 +84,17 @@ bool occurs(func_decl * d, expr * n) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool occurs(sort* s1, sort* s2) {
|
||||
sort_proc p(s1);
|
||||
try {
|
||||
for_each_ast(p, s2, true);
|
||||
}
|
||||
catch (const found&) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void mark_occurs(ptr_vector<expr>& to_check, expr* v, expr_mark& occ) {
|
||||
expr_fast_mark2 visited;
|
||||
occ.mark(v, true);
|
||||
|
@ -116,4 +137,4 @@ void mark_occurs(ptr_vector<expr>& to_check, expr* v, expr_mark& occ) {
|
|||
to_check.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,11 @@ bool occurs(expr * n1, expr * n2);
|
|||
*/
|
||||
bool occurs(func_decl * d, expr * n);
|
||||
|
||||
/**
|
||||
* \brief Return true if s1 occurs in s2
|
||||
*/
|
||||
bool occurs(sort* s1, sort* s2);
|
||||
|
||||
/**
|
||||
* \brief Mark sub-expressions of to_check by whether v occurs in these.
|
||||
*/
|
||||
|
|
|
@ -7,7 +7,7 @@ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/database.h")
|
|||
endif()
|
||||
|
||||
add_custom_command(OUTPUT "database.h"
|
||||
COMMAND "${PYTHON_EXECUTABLE}"
|
||||
COMMAND "${Python3_EXECUTABLE}"
|
||||
"${PROJECT_SOURCE_DIR}/scripts/mk_pat_db.py"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/database.smt2"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/database.h"
|
||||
|
|
|
@ -624,9 +624,11 @@ bool pattern_inference_cfg::reduce_quantifier(
|
|||
proof_ref & result_pr) {
|
||||
|
||||
TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
|
||||
if (!is_forall(q)) {
|
||||
if (!m_params.m_pi_enabled)
|
||||
return false;
|
||||
|
||||
if (!is_forall(q))
|
||||
return false;
|
||||
}
|
||||
|
||||
int weight = q->get_weight();
|
||||
|
||||
|
@ -653,9 +655,8 @@ bool pattern_inference_cfg::reduce_quantifier(
|
|||
}
|
||||
}
|
||||
|
||||
if (q->get_num_patterns() > 0) {
|
||||
if (q->get_num_patterns() > 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_params.m_pi_nopat_weight >= 0)
|
||||
weight = m_params.m_pi_nopat_weight;
|
||||
|
|
139
src/ast/polymorphism_inst.cpp
Normal file
139
src/ast/polymorphism_inst.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*++
|
||||
Copyright (c) 2023 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
polymorphism_inst.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Utilities for instantiating polymorphic assertions.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2023-7-8
|
||||
|
||||
|
||||
--*/
|
||||
#include "ast/polymorphism_inst.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
namespace polymorphism {
|
||||
|
||||
void inst::add(expr* e) {
|
||||
if (!m.has_type_vars())
|
||||
return;
|
||||
|
||||
if (m_from_instantiation.contains(e))
|
||||
return;
|
||||
|
||||
instances inst;
|
||||
u.collect_poly_instances(e, inst.m_poly_fns);
|
||||
if (inst.m_poly_fns.empty())
|
||||
return;
|
||||
if (m_instances.contains(e))
|
||||
return;
|
||||
|
||||
add_instantiations(e, inst.m_poly_fns);
|
||||
|
||||
if (!u.has_type_vars(e))
|
||||
return;
|
||||
|
||||
// insert e into the occurs list for polymorphic roots
|
||||
ast_mark seen;
|
||||
for (auto* f : inst.m_poly_fns) {
|
||||
f = m.poly_root(f);
|
||||
if (seen.is_marked(f))
|
||||
continue;
|
||||
seen.mark(f, true);
|
||||
if (!m_occurs.contains(f)) {
|
||||
m_occurs.insert(f, ptr_vector<expr>());
|
||||
t.push(insert_map(m_occurs, f));
|
||||
}
|
||||
auto& es = m_occurs.find(f);
|
||||
es.push_back(e);
|
||||
t.push(remove_back(m_occurs, f));
|
||||
}
|
||||
m_assertions.push_back(e);
|
||||
t.push(push_back_vector(m_assertions));
|
||||
u.collect_type_vars(e, inst.m_tvs);
|
||||
inst.m_subst = alloc(substitutions);
|
||||
inst.m_subst->insert(alloc(substitution, m));
|
||||
m_instances.insert(e, inst);
|
||||
t.push(new_obj_trail(inst.m_subst));
|
||||
t.push(insert_map(m_instances, e));
|
||||
}
|
||||
|
||||
void inst::collect_instantiations(expr* e) {
|
||||
ptr_vector<func_decl> instances;
|
||||
u.collect_poly_instances(e, instances);
|
||||
add_instantiations(e, instances);
|
||||
}
|
||||
|
||||
void inst::add_instantiations(expr* e, ptr_vector<func_decl> const& instances) {
|
||||
for (auto* f : instances) {
|
||||
if (m_in_decl_queue.is_marked(f))
|
||||
continue;
|
||||
m_in_decl_queue.mark(f, true);
|
||||
m_decl_queue.push_back(f);
|
||||
t.push(add_decl_queue(*this));
|
||||
}
|
||||
}
|
||||
|
||||
void inst::instantiate(vector<instantiation>& instances) {
|
||||
unsigned num_decls = m_decl_queue.size();
|
||||
if (m_assertions_qhead < m_assertions.size()) {
|
||||
t.push(value_trail(m_assertions_qhead));
|
||||
for (; m_assertions_qhead < m_assertions.size(); ++m_assertions_qhead) {
|
||||
expr* e = m_assertions.get(m_assertions_qhead);
|
||||
for (unsigned i = 0; i < num_decls; ++i)
|
||||
instantiate(m_decl_queue.get(i), e, instances);
|
||||
}
|
||||
}
|
||||
if (m_decl_qhead < num_decls) {
|
||||
t.push(value_trail(m_decl_qhead));
|
||||
for (; m_decl_qhead < num_decls; ++m_decl_qhead) {
|
||||
func_decl* p = m_decl_queue.get(m_decl_qhead);
|
||||
for (expr* e : m_occurs[m.poly_root(p)])
|
||||
instantiate(p, e, instances);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void inst::instantiate(func_decl* f1, expr* e, vector<instantiation>& instances) {
|
||||
auto const& [tv, fns, substs] = m_instances[e];
|
||||
|
||||
for (auto* f2 : fns) {
|
||||
substitution sub1(m), new_sub(m);
|
||||
if (!u.unify(f1, f2, sub1))
|
||||
continue;
|
||||
if (substs->contains(&sub1))
|
||||
continue;
|
||||
substitutions new_substs;
|
||||
for (auto* sub2 : *substs) {
|
||||
if (!u.unify(sub1, *sub2, new_sub))
|
||||
continue;
|
||||
if (substs->contains(&new_sub))
|
||||
continue;
|
||||
if (new_substs.contains(&new_sub))
|
||||
continue;
|
||||
expr_ref e_inst = new_sub(e);
|
||||
if (!m_from_instantiation.contains(e_inst)) {
|
||||
collect_instantiations(e_inst);
|
||||
auto* new_sub1 = alloc(substitution, new_sub);
|
||||
instances.push_back(instantiation(e, e_inst, new_sub1));
|
||||
new_substs.insert(new_sub1);
|
||||
m_from_instantiation.insert(e_inst);
|
||||
m.inc_ref(e_inst);
|
||||
t.push(insert_ref_map(m, m_from_instantiation, e_inst));
|
||||
}
|
||||
}
|
||||
for (auto* sub2 : new_substs) {
|
||||
SASSERT(!substs->contains(sub2));
|
||||
substs->insert(sub2);
|
||||
t.push(new_obj_trail(sub2));
|
||||
t.push(insert_map(*substs, sub2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
91
src/ast/polymorphism_inst.h
Normal file
91
src/ast/polymorphism_inst.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*++
|
||||
Copyright (c) 2023 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
polymorphism_inst.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Utilities for instantiating polymorphic assertions.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2023-7-8
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/trail.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/polymorphism_util.h"
|
||||
|
||||
namespace polymorphism {
|
||||
|
||||
struct instantiation {
|
||||
expr* orig;
|
||||
expr_ref inst;
|
||||
substitution* sub;
|
||||
instantiation(expr* orig, expr_ref& inst, substitution* s):
|
||||
orig(orig), inst(inst), sub(s) {}
|
||||
};
|
||||
|
||||
class inst {
|
||||
ast_manager& m;
|
||||
trail_stack& t;
|
||||
util u;
|
||||
|
||||
struct instances {
|
||||
ptr_vector<sort> m_tvs;
|
||||
ptr_vector<func_decl> m_poly_fns;
|
||||
substitutions* m_subst = nullptr;
|
||||
};
|
||||
|
||||
func_decl_ref_vector m_poly_roots;
|
||||
obj_map<func_decl, ptr_vector<expr>> m_occurs;
|
||||
obj_map<expr, instances> m_instances;
|
||||
func_decl_ref_vector m_decl_queue;
|
||||
unsigned m_decl_qhead = 0;
|
||||
ast_mark m_in_decl_queue;
|
||||
expr_ref_vector m_assertions;
|
||||
unsigned m_assertions_qhead = 0;
|
||||
obj_hashtable<expr> m_from_instantiation;
|
||||
|
||||
struct add_decl_queue : public trail {
|
||||
inst& i;
|
||||
add_decl_queue(inst& i): i(i) {}
|
||||
void undo() override {
|
||||
i.m_in_decl_queue.mark(i.m_decl_queue.back(), false);
|
||||
i.m_decl_queue.pop_back();
|
||||
};
|
||||
};
|
||||
|
||||
struct remove_back : public trail {
|
||||
obj_map<func_decl, ptr_vector<expr>>& occ;
|
||||
func_decl* f;
|
||||
remove_back(obj_map<func_decl, ptr_vector<expr>>& occ, func_decl* f):
|
||||
occ(occ), f(f) {}
|
||||
void undo() override {
|
||||
occ.find(f).pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
void instantiate(func_decl* p, expr* e, vector<instantiation>& instances);
|
||||
|
||||
void collect_instantiations(expr* e);
|
||||
|
||||
void add_instantiations(expr* e, ptr_vector<func_decl> const& insts);
|
||||
|
||||
public:
|
||||
inst(ast_manager& m, trail_stack& t):
|
||||
m(m), t(t), u(m), m_poly_roots(m), m_decl_queue(m), m_assertions(m) {}
|
||||
|
||||
void add(expr* e);
|
||||
|
||||
void instantiate(vector<instantiation>& instances);
|
||||
|
||||
bool pending() const { return m_decl_qhead < m_decl_queue.size() || m_assertions_qhead < m_assertions.size(); }
|
||||
|
||||
};
|
||||
}
|
353
src/ast/polymorphism_util.cpp
Normal file
353
src/ast/polymorphism_util.cpp
Normal file
|
@ -0,0 +1,353 @@
|
|||
/*++
|
||||
Copyright (c) 2023 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
polymorphism_util.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Utilities for supporting polymorphic type signatures.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2023-7-8
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast/polymorphism_util.h"
|
||||
#include "ast/for_each_ast.h"
|
||||
#include "ast/occurs.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
namespace polymorphism {
|
||||
|
||||
sort_ref_vector substitution::operator()(sort_ref_vector const& s) {
|
||||
sort_ref_vector r(m);
|
||||
for (auto* srt : s)
|
||||
r.push_back((*this)(srt));
|
||||
return r;
|
||||
}
|
||||
|
||||
sort_ref substitution::operator()(sort* s) {
|
||||
if (!m.has_type_var(s))
|
||||
return sort_ref(s, m);
|
||||
if (s->is_type_var()) {
|
||||
if (m_sub.find(s, s))
|
||||
return (*this)(s);
|
||||
return sort_ref(s, m);
|
||||
}
|
||||
unsigned n = s->get_num_parameters();
|
||||
vector<parameter> ps;
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
auto p = s->get_parameter(i);
|
||||
if (p.is_ast() && is_sort(p.get_ast())) {
|
||||
sort_ref s = (*this)(to_sort(p.get_ast()));
|
||||
ps.push_back(parameter(s.get()));
|
||||
}
|
||||
else
|
||||
ps.push_back(p);
|
||||
}
|
||||
sort_info si(s->get_family_id(), s->get_decl_kind(), n, ps.data(), s->private_parameters());
|
||||
return sort_ref(m.mk_sort(s->get_name(), si), m);
|
||||
}
|
||||
|
||||
expr_ref substitution::operator()(expr* e) {
|
||||
ptr_vector<expr> todo;
|
||||
expr_ref_vector result(m);
|
||||
todo.push_back(e);
|
||||
auto in_cache = [&](expr* a) {
|
||||
return result.size() > a->get_id() && result.get(a->get_id());
|
||||
};
|
||||
ptr_buffer<expr> args;
|
||||
sort_ref_buffer domain(m);
|
||||
while (!todo.empty()) {
|
||||
expr* a = todo.back();
|
||||
if (in_cache(a)) {
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
if (is_var(a)) {
|
||||
if (m.has_type_var(a->get_sort()))
|
||||
result.setx(a->get_id(), m.mk_var(to_var(a)->get_idx(), (*this)(a->get_sort())));
|
||||
else
|
||||
result.setx(a->get_id(), a);
|
||||
todo.pop_back();
|
||||
}
|
||||
else if (is_quantifier(a)) {
|
||||
quantifier* q = to_quantifier(a);
|
||||
bool pending = false;
|
||||
if (!in_cache(q->get_expr())) {
|
||||
todo.push_back(q->get_expr());
|
||||
pending = true;
|
||||
}
|
||||
ptr_buffer<expr> patterns, no_patterns;
|
||||
unsigned np = q->get_num_patterns();
|
||||
for (unsigned i = 0; i < np; ++i) {
|
||||
if (!in_cache(q->get_pattern(i))) {
|
||||
todo.push_back(q->get_pattern(i));
|
||||
pending = true;
|
||||
}
|
||||
else
|
||||
patterns.push_back(result.get(q->get_pattern(i)->get_id()));
|
||||
}
|
||||
np = q->get_num_no_patterns();
|
||||
for (unsigned i = 0; i < np; ++i) {
|
||||
if (!in_cache(q->get_no_pattern(i))) {
|
||||
todo.push_back(q->get_no_pattern(i));
|
||||
pending = true;
|
||||
}
|
||||
else
|
||||
no_patterns.push_back(result.get(q->get_no_pattern(i)->get_id()));
|
||||
}
|
||||
if (pending)
|
||||
continue;
|
||||
todo.pop_back();
|
||||
domain.reset();
|
||||
for (unsigned i = 0; i < q->get_num_decls(); ++i)
|
||||
domain.push_back((*this)(q->get_decl_sort(i)));
|
||||
quantifier* q2 =
|
||||
m.mk_quantifier(q->get_kind(), q->get_num_decls(), domain.data(), q->get_decl_names(), result.get(q->get_expr()->get_id()),
|
||||
q->get_weight(),
|
||||
q->get_qid(), q->get_skid(),
|
||||
q->get_num_patterns(), patterns.data(), q->get_num_no_patterns(), no_patterns.data()
|
||||
);
|
||||
result.setx(q->get_id(), q2);
|
||||
}
|
||||
else if (is_app(a)) {
|
||||
args.reset();
|
||||
unsigned n = todo.size();
|
||||
for (expr* arg : *to_app(a)) {
|
||||
if (!in_cache(arg))
|
||||
todo.push_back(arg);
|
||||
else
|
||||
args.push_back(result.get(arg->get_id()));
|
||||
}
|
||||
if (n < todo.size())
|
||||
continue;
|
||||
func_decl* f = to_app(a)->get_decl();
|
||||
if (f->is_polymorphic()) {
|
||||
domain.reset();
|
||||
for (unsigned i = 0; i < f->get_arity(); ++i)
|
||||
domain.push_back((*this)(f->get_domain(i)));
|
||||
sort_ref range = (*this)(f->get_range());
|
||||
f = m.instantiate_polymorphic(f, f->get_arity(), domain.data(), range);
|
||||
}
|
||||
result.setx(a->get_id(), m.mk_app(f, args));
|
||||
todo.pop_back();
|
||||
}
|
||||
}
|
||||
return expr_ref(result.get(e->get_id()), m);
|
||||
}
|
||||
|
||||
bool substitution::unify(sort* s1, sort* s2) {
|
||||
if (s1 == s2)
|
||||
return true;
|
||||
if (s1->is_type_var() && m_sub.find(s1, s1))
|
||||
return unify(s1, s2);
|
||||
if (s2->is_type_var() && m_sub.find(s2, s2))
|
||||
return unify(s1, s2);
|
||||
if (s2->is_type_var() && !s1->is_type_var())
|
||||
std::swap(s1, s2);
|
||||
if (s1->is_type_var()) {
|
||||
auto s22 = (*this)(s2);
|
||||
if (occurs(s1, s22))
|
||||
return false;
|
||||
m_trail.push_back(s22);
|
||||
m_trail.push_back(s1);
|
||||
m_sub.insert(s1, s22);
|
||||
return true;
|
||||
}
|
||||
if (s1->get_family_id() != s2->get_family_id())
|
||||
return false;
|
||||
if (s1->get_decl_kind() != s2->get_decl_kind())
|
||||
return false;
|
||||
if (s1->get_name() != s2->get_name())
|
||||
return false;
|
||||
if (s1->get_num_parameters() != s2->get_num_parameters())
|
||||
return false;
|
||||
for (unsigned i = s1->get_num_parameters(); i-- > 0;) {
|
||||
auto p1 = s1->get_parameter(i);
|
||||
auto p2 = s2->get_parameter(i);
|
||||
if (p1.is_ast() && is_sort(p1.get_ast())) {
|
||||
if (!p2.is_ast())
|
||||
return false;
|
||||
if (!is_sort(p2.get_ast()))
|
||||
return false;
|
||||
if (!unify(to_sort(p1.get_ast()), to_sort(p2.get_ast())))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
if (p1 != p2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool substitution::match(sort* s1, sort* s2) {
|
||||
if (s1 == s2)
|
||||
return true;
|
||||
if (s1->is_type_var() && m_sub.find(s1, s1))
|
||||
return match(s1, s2);
|
||||
if (s1->is_type_var()) {
|
||||
m_trail.push_back(s2);
|
||||
m_trail.push_back(s1);
|
||||
m_sub.insert(s1, s2);
|
||||
return true;
|
||||
}
|
||||
if (s1->get_family_id() != s2->get_family_id())
|
||||
return false;
|
||||
if (s1->get_decl_kind() != s2->get_decl_kind())
|
||||
return false;
|
||||
if (s1->get_name() != s2->get_name())
|
||||
return false;
|
||||
if (s1->get_num_parameters() != s2->get_num_parameters())
|
||||
return false;
|
||||
for (unsigned i = s1->get_num_parameters(); i-- > 0;) {
|
||||
auto p1 = s1->get_parameter(i);
|
||||
auto p2 = s2->get_parameter(i);
|
||||
if (p1.is_ast() && is_sort(p1.get_ast())) {
|
||||
if (!p2.is_ast())
|
||||
return false;
|
||||
if (!is_sort(p2.get_ast()))
|
||||
return false;
|
||||
if (!match(to_sort(p1.get_ast()), to_sort(p2.get_ast())))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
if (p1 != p2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// util
|
||||
bool util::unify(sort* s1, sort* s2, substitution& sub) {
|
||||
return sub.unify(s1, s2);
|
||||
}
|
||||
|
||||
bool util::unify(func_decl* f1, func_decl* f2, substitution& sub) {
|
||||
if (f1 == f2)
|
||||
return true;
|
||||
if (!f1->is_polymorphic() || !f2->is_polymorphic())
|
||||
return false;
|
||||
if (m.poly_root(f1) != m.poly_root(f2))
|
||||
return false;
|
||||
for (unsigned i = f1->get_arity(); i-- > 0; )
|
||||
if (!sub.unify(fresh(f1->get_domain(i)), f2->get_domain(i)))
|
||||
return false;
|
||||
return sub.unify(fresh(f1->get_range()), f2->get_range());
|
||||
}
|
||||
|
||||
bool util::unify(substitution const& s1, substitution const& s2,
|
||||
substitution& sub) {
|
||||
sort* v2;
|
||||
for (auto const& [k, v] : s1)
|
||||
sub.insert(k, v);
|
||||
for (auto const& [k, v] : s2) {
|
||||
if (sub.find(k, v2)) {
|
||||
if (!sub.unify(sub(v), v2))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
sub.insert(k, sub(v));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool util::match(substitution& sub, sort* s1, sort* s_ground) {
|
||||
return sub.match(s1, s_ground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create fresh variables, but with caching.
|
||||
* So "fresh" variables are not truly fresh globally.
|
||||
* This can block some unifications and therefore block some instantiations of
|
||||
* polymorphic assertions. A different caching scheme could be created to
|
||||
* ensure that fresh variables are introduced at the right time, or use other
|
||||
* tricks such as creating variable/offset pairs to distinguish name spaces without
|
||||
* incurring costs.
|
||||
*/
|
||||
sort_ref util::fresh(sort* s) {
|
||||
sort* s1;
|
||||
if (m_fresh.find(s, s1))
|
||||
return sort_ref(s1, m);
|
||||
|
||||
if (m.is_type_var(s)) {
|
||||
s1 = m.mk_type_var(symbol("fresh!" + std::to_string(m_counter)));
|
||||
m_trail.push_back(s1);
|
||||
m_trail.push_back(s);
|
||||
m_fresh.insert(s, s1);
|
||||
return sort_ref(s1, m);
|
||||
}
|
||||
vector<parameter> params;
|
||||
for (unsigned i = 0; i < s->get_num_parameters(); ++i) {
|
||||
parameter p = s->get_parameter(i);
|
||||
if (p.is_ast() && is_sort(p.get_ast())) {
|
||||
sort_ref fs = fresh(to_sort(p.get_ast()));
|
||||
params.push_back(parameter(fs.get()));
|
||||
}
|
||||
else
|
||||
params.push_back(p);
|
||||
}
|
||||
sort_info info(s->get_family_id(), s->get_decl_kind(), params.size(), params.data(), s->private_parameters());
|
||||
s1 = m.mk_sort(s->get_name(), info);
|
||||
m_trail.push_back(s1);
|
||||
m_trail.push_back(s);
|
||||
m_fresh.insert(s, s1);
|
||||
return sort_ref(s1, m);
|
||||
}
|
||||
|
||||
sort_ref_vector util::fresh(unsigned n, sort* const* s) {
|
||||
sort_ref_vector r(m);
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
r.push_back(fresh(s[i]));
|
||||
return r;
|
||||
}
|
||||
|
||||
void util::collect_poly_instances(expr* e, ptr_vector<func_decl>& instances) {
|
||||
struct proc {
|
||||
ast_manager& m;
|
||||
ptr_vector<func_decl>& instances;
|
||||
proc(ast_manager& m, ptr_vector<func_decl>& instances) : m(m), instances(instances) {}
|
||||
void operator()(func_decl* f) {
|
||||
if (f->is_polymorphic() && !m.is_eq(f) && !is_decl_of(f, pattern_family_id, OP_PATTERN))
|
||||
instances.push_back(f);
|
||||
}
|
||||
void operator()(ast* a) {}
|
||||
};
|
||||
proc proc(m, instances);
|
||||
for_each_ast(proc, e, false);
|
||||
}
|
||||
|
||||
bool util::has_type_vars(expr* e) {
|
||||
struct proc {
|
||||
ast_manager& m;
|
||||
bool found = false;
|
||||
proc(ast_manager& m) : m(m) {}
|
||||
void operator()(sort* f) {
|
||||
if (m.has_type_var(f))
|
||||
found = true;
|
||||
}
|
||||
void operator()(ast* a) {}
|
||||
};
|
||||
proc proc(m);
|
||||
for_each_ast(proc, e, false);
|
||||
return proc.found;
|
||||
}
|
||||
|
||||
void util::collect_type_vars(expr* e, ptr_vector<sort>& tvs) {
|
||||
struct proc {
|
||||
ast_manager& m;
|
||||
ptr_vector<sort>& tvs;
|
||||
proc(ast_manager& m, ptr_vector<sort>& tvs) : m(m), tvs(tvs) {}
|
||||
void operator()(sort* s) {
|
||||
if (m.is_type_var(s))
|
||||
tvs.push_back(s);
|
||||
}
|
||||
void operator()(ast* a) {}
|
||||
};
|
||||
proc proc(m, tvs);
|
||||
for_each_ast(proc, e, true);
|
||||
}
|
||||
}
|
112
src/ast/polymorphism_util.h
Normal file
112
src/ast/polymorphism_util.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*++
|
||||
Copyright (c) 2023 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
polymorphism_util.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Utilities for supporting polymorphic type signatures.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2023-7-8
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "util/hashtable.h"
|
||||
|
||||
namespace polymorphism {
|
||||
|
||||
class substitution {
|
||||
ast_manager& m;
|
||||
obj_map<sort, sort*> m_sub;
|
||||
sort_ref_vector m_trail;
|
||||
public:
|
||||
substitution(ast_manager& m): m(m), m_trail(m) {}
|
||||
|
||||
sort_ref_vector operator()(sort_ref_vector const& s);
|
||||
|
||||
sort_ref operator()(sort* s);
|
||||
|
||||
expr_ref operator()(expr* e);
|
||||
|
||||
bool unify(sort* s1, sort* s2);
|
||||
|
||||
bool match(sort* s1, sort* s_ground);
|
||||
|
||||
obj_map<sort, sort*>::iterator begin() const { return m_sub.begin(); }
|
||||
obj_map<sort, sort*>::iterator end() const { return m_sub.end(); }
|
||||
|
||||
void insert(sort* v, sort* t) { m_trail.push_back(v).push_back(t); m_sub.insert(v, t); }
|
||||
|
||||
bool find(sort* v, sort*& t) const { return m_sub.find(v, t); }
|
||||
|
||||
unsigned size() const { return m_sub.size(); }
|
||||
|
||||
/**
|
||||
* weak equality: strong equality considers applying substitutions recursively in range
|
||||
* because substitutions may be in triangular form.
|
||||
*/
|
||||
struct eq {
|
||||
bool operator()(substitution const* s1, substitution const* s2) const {
|
||||
if (s1->size() != s2->size())
|
||||
return false;
|
||||
sort* v2;
|
||||
for (auto const& [k, v] : *s1) {
|
||||
if (!s2->find(k, v2))
|
||||
return false;
|
||||
if (v != v2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct hash {
|
||||
unsigned operator()(substitution const* s) const {
|
||||
unsigned hash = 0xfabc1234 + s->size();
|
||||
for (auto const& [k, v] : *s)
|
||||
hash ^= k->hash() + 2 * v->hash();
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
typedef hashtable<substitution*, substitution::hash, substitution::eq> substitutions;
|
||||
|
||||
class util {
|
||||
ast_manager& m;
|
||||
sort_ref_vector m_trail;
|
||||
obj_map<sort, sort*> m_fresh;
|
||||
unsigned m_counter = 0;
|
||||
|
||||
sort_ref fresh(sort* s);
|
||||
|
||||
sort_ref_vector fresh(unsigned n, sort* const* s);
|
||||
|
||||
public:
|
||||
util(ast_manager& m): m(m), m_trail(m) {}
|
||||
|
||||
bool unify(sort* s1, sort* s2, substitution& sub);
|
||||
|
||||
bool unify(func_decl* f1, func_decl* f2, substitution& sub);
|
||||
|
||||
bool unify(substitution const& s1, substitution const& s2,
|
||||
substitution& sub);
|
||||
|
||||
bool match(substitution& sub, sort* s1, sort* s_ground);
|
||||
|
||||
// collect instantiations of polymorphic functions
|
||||
void collect_poly_instances(expr* e, ptr_vector<func_decl>& instances);
|
||||
|
||||
// test if expression contains polymorphic variable.
|
||||
bool has_type_vars(expr* e);
|
||||
|
||||
void collect_type_vars(expr* e, ptr_vector<sort>& tvs);
|
||||
|
||||
};
|
||||
}
|
|
@ -23,7 +23,6 @@ z3_add_component(rewriter
|
|||
factor_rewriter.cpp
|
||||
fpa_rewriter.cpp
|
||||
func_decl_replace.cpp
|
||||
hoist_rewriter.cpp
|
||||
inj_axiom.cpp
|
||||
label_rewriter.cpp
|
||||
macro_replacer.cpp
|
||||
|
|
|
@ -551,25 +551,10 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
|
|||
}
|
||||
|
||||
if (m_anum_simp) {
|
||||
if (is_numeral(arg1, a1) && m_util.is_irrational_algebraic_numeral(arg2)) {
|
||||
anum_manager & am = m_util.am();
|
||||
scoped_anum v1(am);
|
||||
am.set(v1, a1.to_mpq());
|
||||
anum const & v2 = m_util.to_irrational_algebraic_numeral(arg2);
|
||||
ANUM_LE_GE_EQ();
|
||||
}
|
||||
if (m_util.is_irrational_algebraic_numeral(arg1) && is_numeral(arg2, a2)) {
|
||||
anum_manager & am = m_util.am();
|
||||
anum const & v1 = m_util.to_irrational_algebraic_numeral(arg1);
|
||||
scoped_anum v2(am);
|
||||
am.set(v2, a2.to_mpq());
|
||||
ANUM_LE_GE_EQ();
|
||||
}
|
||||
if (m_util.is_irrational_algebraic_numeral(arg1) && m_util.is_irrational_algebraic_numeral(arg2)) {
|
||||
anum_manager & am = m_util.am();
|
||||
anum const & v1 = m_util.to_irrational_algebraic_numeral(arg1);
|
||||
anum const & v2 = m_util.to_irrational_algebraic_numeral(arg2);
|
||||
ANUM_LE_GE_EQ();
|
||||
auto& am = m_util.am();
|
||||
scoped_anum v1(am), v2(am);
|
||||
if (is_algebraic_numeral(arg1, v1) && is_algebraic_numeral(arg2, v2)) {
|
||||
ANUM_LE_GE_EQ();
|
||||
}
|
||||
}
|
||||
br_status st1 = is_separated(arg1, arg2, kind, result);
|
||||
|
@ -669,6 +654,7 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
|
|||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
||||
br_status arith_rewriter::mk_le_core(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
return mk_le_ge_eq_core(arg1, arg2, LE, result);
|
||||
}
|
||||
|
@ -744,18 +730,26 @@ bool arith_rewriter::mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result) {
|
|||
if (g == 1) {
|
||||
expr_ref nb(m_util.mk_numeral(b, true), m);
|
||||
result = m.mk_eq(m_util.mk_mod(u, y),
|
||||
m_util.mk_mod(m_util.mk_mul(nb, arg2), y));
|
||||
m_util.mk_mod(m_util.mk_mul(nb, arg2), y));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
expr_ref arith_rewriter::neg_monomial(expr* e) const {
|
||||
expr_ref arith_rewriter::neg_monomial(expr* e) {
|
||||
expr_ref_vector args(m);
|
||||
rational a1;
|
||||
if (m_util.is_numeral(e, a1))
|
||||
args.push_back(m_util.mk_numeral(-a1, e->get_sort()));
|
||||
else if (m_util.is_irrational_algebraic_numeral(e)) {
|
||||
auto& n = m_util.to_irrational_algebraic_numeral(e);
|
||||
auto& am = m_util.am();
|
||||
scoped_anum new_n(am);
|
||||
am.set(new_n, n);
|
||||
am.neg(new_n);
|
||||
args.push_back(m_util.mk_numeral(am, new_n, m_util.is_int(e)));
|
||||
}
|
||||
else if (is_app(e) && m_util.is_mul(e)) {
|
||||
if (is_numeral(to_app(e)->get_arg(0), a1)) {
|
||||
if (!a1.is_minus_one()) {
|
||||
|
@ -780,7 +774,7 @@ expr_ref arith_rewriter::neg_monomial(expr* e) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool arith_rewriter::is_neg_poly(expr* t, expr_ref& neg) const {
|
||||
bool arith_rewriter::is_neg_poly(expr* t, expr_ref& neg) {
|
||||
rational r;
|
||||
if (m_util.is_mul(t) && is_numeral(to_app(t)->get_arg(0), r) && r.is_neg()) {
|
||||
neg = neg_monomial(t);
|
||||
|
@ -824,6 +818,36 @@ bool arith_rewriter::is_anum_simp_target(unsigned num_args, expr * const * args)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool arith_rewriter::is_algebraic_numeral(expr* n, scoped_anum& a) {
|
||||
auto& am = m_util.am();
|
||||
expr* x, *y;
|
||||
rational r;
|
||||
if (m_util.is_mul(n, x, y)) {
|
||||
scoped_anum ax(am), ay(am);
|
||||
if (is_algebraic_numeral(x, ax) && is_algebraic_numeral(y, ay)) {
|
||||
am.mul(ax, ay, a);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (m_util.is_add(n, x, y)) {
|
||||
scoped_anum ax(am), ay(am);
|
||||
if (is_algebraic_numeral(x, ax) && is_algebraic_numeral(y, ay)) {
|
||||
am.add(ax, ay, a);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (m_util.is_numeral(n, r)) {
|
||||
am.set(a, r.to_mpq());
|
||||
return true;
|
||||
}
|
||||
else if (m_util.is_irrational_algebraic_numeral(n)) {
|
||||
am.set(a, m_util.to_irrational_algebraic_numeral(n));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
br_status arith_rewriter::mk_add_core(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
if (is_anum_simp_target(num_args, args)) {
|
||||
expr_ref_buffer new_args(m);
|
||||
|
|
|
@ -21,6 +21,7 @@ Notes:
|
|||
#include "ast/rewriter/poly_rewriter.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/seq_decl_plugin.h"
|
||||
#include "math/polynomial/algebraic_numbers.h"
|
||||
|
||||
class arith_rewriter_core {
|
||||
protected:
|
||||
|
@ -80,6 +81,7 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
|
|||
void updt_local_params(params_ref const & p);
|
||||
|
||||
bool is_anum_simp_target(unsigned num_args, expr * const * args);
|
||||
bool is_algebraic_numeral(expr* n, scoped_anum& a);
|
||||
|
||||
br_status mk_div_irrat_rat(expr * arg1, expr * arg2, expr_ref & result);
|
||||
br_status mk_div_rat_irrat(expr * arg1, expr * arg2, expr_ref & result);
|
||||
|
@ -97,8 +99,8 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
|
|||
bool is_2_pi_integer_offset(expr * t, expr * & m);
|
||||
bool is_pi_integer(expr * t);
|
||||
bool is_pi_integer_offset(expr * t, expr * & m);
|
||||
bool is_neg_poly(expr* e, expr_ref& neg) const;
|
||||
expr_ref neg_monomial(expr * e) const;
|
||||
bool is_neg_poly(expr* e, expr_ref& neg);
|
||||
expr_ref neg_monomial(expr * e);
|
||||
expr * mk_sin_value(rational const & k);
|
||||
app * mk_sqrt(rational const & k);
|
||||
bool divides(expr* d, expr* n, expr_ref& result);
|
||||
|
|
|
@ -24,6 +24,7 @@ Notes:
|
|||
#include "ast/rewriter/var_subst.h"
|
||||
#include "params/array_rewriter_params.hpp"
|
||||
#include "util/util.h"
|
||||
#include "ast/array_peq.h"
|
||||
|
||||
void array_rewriter::updt_params(params_ref const & _p) {
|
||||
array_rewriter_params p(_p);
|
||||
|
@ -40,8 +41,48 @@ void array_rewriter::get_param_descrs(param_descrs & r) {
|
|||
}
|
||||
|
||||
br_status array_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
br_status st = BR_FAILED;
|
||||
|
||||
// BEGIN: rewrite rules for PEQs
|
||||
if (is_partial_eq(f)) {
|
||||
SASSERT(num_args >= 2);
|
||||
expr *e0, *e1;
|
||||
e0 = args[0];
|
||||
e1 = args[1];
|
||||
|
||||
expr_ref a(m()), val(m());
|
||||
expr_ref_vector vindex(m());
|
||||
|
||||
if (e0 == e1) {
|
||||
// t peq t --> true
|
||||
result = m().mk_true();
|
||||
st = BR_DONE;
|
||||
}
|
||||
else if (m_util.is_store_ext(e0, a, vindex, val)) {
|
||||
if (num_args == 2 && a == e1) {
|
||||
// (a[i := x] peq_{\emptyset} a) ---> a[i] == x
|
||||
mk_select(vindex.size(), vindex.data(), result);
|
||||
result = m().mk_eq(result, val);
|
||||
st = BR_REWRITE_FULL;
|
||||
}
|
||||
else if (a == e1 && vindex.size() == num_args + 2) {
|
||||
// a [i: = x] peq_{i} a -- > true
|
||||
bool all_eq = true;
|
||||
for (unsigned i = 0, sz = vindex.size(); all_eq && i < sz;
|
||||
++i) {
|
||||
all_eq &= vindex.get(i) == args[2+i];
|
||||
}
|
||||
if (all_eq) {
|
||||
result = m().mk_true();
|
||||
st = BR_DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return st;
|
||||
}
|
||||
// END: rewrite rules for PEQs
|
||||
|
||||
SASSERT(f->get_family_id() == get_fid());
|
||||
br_status st;
|
||||
switch (f->get_decl_kind()) {
|
||||
case OP_SELECT:
|
||||
st = mk_select_core(num_args, args, result);
|
||||
|
|
|
@ -21,6 +21,7 @@ Notes:
|
|||
#include "ast/rewriter/bit_blaster/bit_blaster_tpl_def.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "util/ref_util.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
|
@ -549,10 +550,19 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend);
|
|||
case OP_INT2BV:
|
||||
case OP_BV2INT:
|
||||
return BR_FAILED;
|
||||
default:
|
||||
default:
|
||||
TRACE("bit_blaster", tout << "non-supported operator: " << f->get_name() << "\n";
|
||||
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
|
||||
{
|
||||
expr_ref r(m().mk_app(f, num, args), m());
|
||||
result = r;
|
||||
th_rewriter rw(m());
|
||||
rw(result);
|
||||
if (!is_app(result) || to_app(result)->get_decl() != f)
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
throw_unsupported(f);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ void bool_rewriter::updt_params(params_ref const & _p) {
|
|||
m_blast_distinct = p.blast_distinct();
|
||||
m_blast_distinct_threshold = p.blast_distinct_threshold();
|
||||
m_ite_extra_rules = p.ite_extra_rules();
|
||||
m_hoist.set_elim_and(m_elim_and);
|
||||
}
|
||||
|
||||
void bool_rewriter::get_param_descrs(param_descrs & r) {
|
||||
|
@ -270,28 +269,6 @@ br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args
|
|||
return BR_DONE;
|
||||
}
|
||||
|
||||
#if 1
|
||||
br_status st;
|
||||
expr_ref r(m());
|
||||
st = m_hoist.mk_or(buffer.size(), buffer.data(), r);
|
||||
if (st != BR_FAILED) {
|
||||
m_counts1.reserve(m().get_num_asts() + 1);
|
||||
m_counts2.reserve(m().get_num_asts() + 1);
|
||||
get_num_internal_exprs(m_counts1, m_todo1, r);
|
||||
for (unsigned i = 0; i < num_args; ++i)
|
||||
get_num_internal_exprs(m_counts2, m_todo2, args[i]);
|
||||
unsigned count1 = count_internal_nodes(m_counts1, m_todo1);
|
||||
unsigned count2 = count_internal_nodes(m_counts2, m_todo2);
|
||||
if (count1 > count2)
|
||||
st = BR_FAILED;
|
||||
}
|
||||
if (st != BR_FAILED)
|
||||
result = r;
|
||||
if (st == BR_DONE)
|
||||
return BR_REWRITE1;
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
#endif
|
||||
if (s) {
|
||||
if (m_sort_disjunctions) {
|
||||
ast_lt lt;
|
||||
|
|
|
@ -20,7 +20,6 @@ Notes:
|
|||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/rewriter/hoist_rewriter.h"
|
||||
#include "util/params.h"
|
||||
|
||||
/**
|
||||
|
@ -51,7 +50,6 @@ Notes:
|
|||
*/
|
||||
class bool_rewriter {
|
||||
ast_manager & m_manager;
|
||||
hoist_rewriter m_hoist;
|
||||
bool m_flat_and_or = false;
|
||||
bool m_sort_disjunctions = true;
|
||||
bool m_local_ctx = false;
|
||||
|
@ -84,7 +82,7 @@ class bool_rewriter {
|
|||
void push_new_arg(expr* arg, expr_ref_vector& new_args, expr_fast_mark1& neg_lits, expr_fast_mark2& pos_lits);
|
||||
|
||||
public:
|
||||
bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_hoist(m), m_local_ctx_cost(0) {
|
||||
bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_local_ctx_cost(0) {
|
||||
updt_params(p);
|
||||
}
|
||||
ast_manager & m() const { return m_manager; }
|
||||
|
|
|
@ -217,7 +217,7 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
|||
case OP_BUSUB_OVFL:
|
||||
return mk_bvusub_underflow(num_args, args, result);
|
||||
case OP_BSSUB_OVFL:
|
||||
return mk_bvssub_overflow(num_args, args, result);
|
||||
return mk_bvssub_under_overflow(num_args, args, result);
|
||||
default:
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
@ -3085,19 +3085,29 @@ br_status bv_rewriter::mk_bvusub_underflow(unsigned num, expr * const * args, ex
|
|||
return status;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvssub_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
//
|
||||
// no_overflow := if t2 = min_int then t1 <s 0 else no_overflow(t1 + -t2)
|
||||
// no_underflow := 0 <s -t2 => no_underflow(t1 + -t2)
|
||||
// over_underflow := 0 <s -t2 & under_overflow+(t1 + -t2) || t2 = min_int & t1 >=s 0 || t2 != min_int & under_overflow+(t1 + -t2)
|
||||
// := if t2 == min_int then t1 >=s 0 else under_overflow+(t1 + -t2)
|
||||
// because when 0 <s min_int = false
|
||||
//
|
||||
br_status bv_rewriter::mk_bvssub_under_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
auto sz = get_bv_size(args[0]);
|
||||
auto minSigned = mk_numeral(rational::power_of_two(sz-1), sz);
|
||||
expr_ref bvsaddo {m};
|
||||
expr * args2[2] = { args[0], m_util.mk_bv_neg(args[1]) };
|
||||
auto bvsaddo_stat = mk_bvsadd_overflow(2, args2, bvsaddo);
|
||||
auto bvsaddo_stat = mk_bvsadd_over_underflow(2, args2, bvsaddo);
|
||||
SASSERT(bvsaddo_stat != BR_FAILED); (void)bvsaddo_stat;
|
||||
auto first_arg_ge_zero = m_util.mk_sle(mk_zero(sz), args[0]);
|
||||
result = m.mk_ite(m.mk_eq(args[1], minSigned), first_arg_ge_zero, bvsaddo);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
//br_status bv_rewriter::mk_bvssub_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
//}
|
||||
br_status bv_rewriter::mk_bvsdiv_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
|
|
|
@ -153,7 +153,8 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
|
|||
br_status mk_bvsadd_over_underflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
br_status mk_bvusub_underflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
br_status mk_bvssub_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
// br_status mk_bvssub_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
br_status mk_bvssub_under_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
bool is_minus_one_times_t(expr * arg);
|
||||
void mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & result);
|
||||
|
|
|
@ -21,7 +21,8 @@ Notes:
|
|||
br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
SASSERT(f->get_family_id() == get_fid());
|
||||
switch(f->get_decl_kind()) {
|
||||
case OP_DT_CONSTRUCTOR: return BR_FAILED;
|
||||
case OP_DT_CONSTRUCTOR:
|
||||
return BR_FAILED;
|
||||
case OP_DT_RECOGNISER:
|
||||
SASSERT(num_args == 1);
|
||||
result = m_util.mk_is(m_util.get_recognizer_constructor(f), args[0]);
|
||||
|
|
|
@ -17,8 +17,6 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#ifndef ELIM_BOUNDS_H_
|
||||
#define ELIM_BOUNDS_H_
|
||||
|
||||
#include "ast/used_vars.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
|
@ -201,4 +199,3 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q,
|
|||
return true;
|
||||
}
|
||||
|
||||
#endif /* ELIM_BOUNDS_H_ */
|
||||
|
|
|
@ -1,248 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2019 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
hoist_rewriter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Hoist predicates over disjunctions
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2019-2-4
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "ast/rewriter/hoist_rewriter.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
|
||||
hoist_rewriter::hoist_rewriter(ast_manager & m, params_ref const & p):
|
||||
m(m), m_args1(m), m_args2(m), m_refs(m), m_subst(m) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
expr_ref hoist_rewriter::mk_and(expr_ref_vector const& args) {
|
||||
if (m_elim_and) {
|
||||
expr_ref_vector negs(m);
|
||||
for (expr* a : args)
|
||||
if (m.is_false(a))
|
||||
return expr_ref(m.mk_false(), m);
|
||||
else if (m.is_true(a))
|
||||
continue;
|
||||
else
|
||||
negs.push_back(::mk_not(m, a));
|
||||
return ::mk_not(mk_or(negs));
|
||||
}
|
||||
else
|
||||
return ::mk_and(args);
|
||||
}
|
||||
|
||||
expr_ref hoist_rewriter::mk_or(expr_ref_vector const& args) {
|
||||
return ::mk_or(args);
|
||||
}
|
||||
|
||||
br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & result) {
|
||||
if (num_args < 2)
|
||||
return BR_FAILED;
|
||||
|
||||
for (unsigned i = 0; i < num_args; ++i)
|
||||
if (!is_and(es[i], nullptr))
|
||||
return BR_FAILED;
|
||||
|
||||
bool turn = false;
|
||||
m_preds1.reset();
|
||||
m_preds2.reset();
|
||||
m_uf1.reset();
|
||||
m_uf2.reset();
|
||||
m_expr2var.reset();
|
||||
m_var2expr.reset();
|
||||
basic_union_find* uf[2] = { &m_uf1, &m_uf2 };
|
||||
obj_hashtable<expr>* preds[2] = { &m_preds1, &m_preds2 };
|
||||
expr_ref_vector* args[2] = { &m_args1, &m_args2 };
|
||||
VERIFY(is_and(es[0], args[turn]));
|
||||
expr* e1, *e2;
|
||||
for (expr* e : *(args[turn])) {
|
||||
if (m.is_eq(e, e1, e2))
|
||||
(*uf)[turn].merge(mk_var(e1), mk_var(e2));
|
||||
else
|
||||
(*preds)[turn].insert(e);
|
||||
}
|
||||
unsigned round = 0;
|
||||
for (unsigned j = 1; j < num_args; ++j) {
|
||||
++round;
|
||||
m_es.reset();
|
||||
m_mark.reset();
|
||||
|
||||
bool last = turn;
|
||||
turn = !turn;
|
||||
(*preds)[turn].reset();
|
||||
reset(m_uf0);
|
||||
VERIFY(is_and(es[j], args[turn]));
|
||||
|
||||
for (expr* e : *args[turn]) {
|
||||
if (m.is_eq(e, e1, e2)) {
|
||||
m_es.push_back(e1);
|
||||
m_uf0.merge(mk_var(e1), mk_var(e2));
|
||||
}
|
||||
else if ((*preds)[last].contains(e))
|
||||
(*preds)[turn].insert(e);
|
||||
}
|
||||
|
||||
if ((*preds)[turn].empty() && m_es.empty())
|
||||
return BR_FAILED;
|
||||
|
||||
m_eqs.reset();
|
||||
for (expr* e : m_es) {
|
||||
if (m_mark.is_marked(e))
|
||||
continue;
|
||||
unsigned u = mk_var(e);
|
||||
unsigned v = u;
|
||||
m_roots.reset();
|
||||
do {
|
||||
m_mark.mark(e);
|
||||
unsigned r = (*uf)[last].find(v);
|
||||
if (m_roots.find(r, e2))
|
||||
m_eqs.push_back({e, e2});
|
||||
else
|
||||
m_roots.insert(r, e);
|
||||
v = m_uf0.next(v);
|
||||
e = mk_expr(v);
|
||||
}
|
||||
while (u != v);
|
||||
}
|
||||
reset((*uf)[turn]);
|
||||
for (auto const& [e1, e2] : m_eqs)
|
||||
(*uf)[turn].merge(mk_var(e1), mk_var(e2));
|
||||
if ((*preds)[turn].empty() && m_eqs.empty())
|
||||
return BR_FAILED;
|
||||
}
|
||||
if (m_eqs.empty()) {
|
||||
result = hoist_predicates((*preds)[turn], num_args, es);
|
||||
return BR_DONE;
|
||||
}
|
||||
// p & eqs & (or fmls)
|
||||
expr_ref_vector fmls(m);
|
||||
m_subst.reset();
|
||||
for (expr * p : (*preds)[turn]) {
|
||||
expr* q = nullptr;
|
||||
if (m.is_not(p, q))
|
||||
m_subst.insert(q, m.mk_false());
|
||||
else
|
||||
m_subst.insert(p, m.mk_true());
|
||||
fmls.push_back(p);
|
||||
}
|
||||
for (auto& p : m_eqs) {
|
||||
if (m.is_value(p.first))
|
||||
std::swap(p.first, p.second);
|
||||
m_subst.insert(p.first, p.second);
|
||||
fmls.push_back(m.mk_eq(p.first, p.second));
|
||||
}
|
||||
expr_ref ors(::mk_or(m, num_args, es), m);
|
||||
m_subst(ors);
|
||||
fmls.push_back(ors);
|
||||
result = mk_and(fmls);
|
||||
TRACE("hoist", tout << ors << " => " << result << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
unsigned hoist_rewriter::mk_var(expr* e) {
|
||||
unsigned v = 0;
|
||||
if (m_expr2var.find(e, v))
|
||||
return v;
|
||||
m_uf1.mk_var();
|
||||
v = m_uf2.mk_var();
|
||||
SASSERT(v == m_var2expr.size());
|
||||
m_expr2var.insert(e, v);
|
||||
m_var2expr.push_back(e);
|
||||
return v;
|
||||
}
|
||||
|
||||
expr_ref hoist_rewriter::hoist_predicates(obj_hashtable<expr> const& preds, unsigned num_args, expr* const* es) {
|
||||
expr_ref_vector args(m), args1(m), fmls(m);
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
VERIFY(is_and(es[i], &args1));
|
||||
fmls.reset();
|
||||
for (expr* e : args1)
|
||||
if (!preds.contains(e))
|
||||
fmls.push_back(e);
|
||||
args.push_back(mk_and(fmls));
|
||||
}
|
||||
fmls.reset();
|
||||
fmls.push_back(mk_or(args));
|
||||
for (auto* p : preds)
|
||||
fmls.push_back(p);
|
||||
return mk_and(fmls);
|
||||
}
|
||||
|
||||
|
||||
br_status hoist_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
switch (f->get_decl_kind()) {
|
||||
case OP_OR:
|
||||
return mk_or(num_args, args, result);
|
||||
default:
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) {
|
||||
#if 0
|
||||
if (!args)
|
||||
return m.is_and(e) || (m.is_not(e, e) && m.is_or(e));
|
||||
expr_fast_mark1 visited;
|
||||
args->reset();
|
||||
args->push_back(e);
|
||||
m_refs.reset();
|
||||
for (unsigned i = 0; i < args->size(); ++i) {
|
||||
e = args->get(i);
|
||||
if (visited.is_marked(e))
|
||||
goto drop;
|
||||
m_refs.push_back(e);
|
||||
visited.mark(e, true);
|
||||
if (m.is_and(e))
|
||||
args->append(to_app(e)->get_num_args(), to_app(e)->get_args());
|
||||
else if (m.is_not(e, e) && m.is_or(e))
|
||||
for (expr* arg : *to_app(e))
|
||||
args->push_back(::mk_not(m, arg));
|
||||
else
|
||||
continue;
|
||||
drop:
|
||||
(*args)[i] = args->back();
|
||||
args->pop_back();
|
||||
--i;
|
||||
}
|
||||
return args->size() > 1;
|
||||
#else
|
||||
if (m.is_and(e)) {
|
||||
if (args) {
|
||||
args->reset();
|
||||
args->append(to_app(e)->get_num_args(), to_app(e)->get_args());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (m.is_not(e, e) && m.is_or(e)) {
|
||||
if (args) {
|
||||
args->reset();
|
||||
for (expr* arg : *to_app(e))
|
||||
args->push_back(::mk_not(m, arg));
|
||||
TRACE("hoist", tout << args << " " << * args << "\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void hoist_rewriter::reset(basic_union_find& uf) {
|
||||
uf.reset();
|
||||
for (expr* e : m_var2expr) {
|
||||
(void)e;
|
||||
uf.mk_var();
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2019 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
hoist_rewriter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Hoist predicates over disjunctions
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2019-2-4
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/rewriter/expr_safe_replace.h"
|
||||
#include "util/params.h"
|
||||
#include "util/union_find.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
|
||||
class bool_rewriter;
|
||||
|
||||
class hoist_rewriter {
|
||||
ast_manager & m;
|
||||
expr_ref_vector m_args1, m_args2, m_refs;
|
||||
obj_hashtable<expr> m_preds1, m_preds2;
|
||||
basic_union_find m_uf1, m_uf2, m_uf0;
|
||||
ptr_vector<expr> m_es;
|
||||
svector<std::pair<expr*,expr*>> m_eqs;
|
||||
u_map<expr*> m_roots;
|
||||
expr_safe_replace m_subst;
|
||||
obj_map<expr, unsigned> m_expr2var;
|
||||
ptr_vector<expr> m_var2expr;
|
||||
expr_mark m_mark;
|
||||
bool m_elim_and = false;
|
||||
|
||||
bool is_and(expr* e, expr_ref_vector* args);
|
||||
expr_ref mk_and(expr_ref_vector const& args);
|
||||
expr_ref mk_or(expr_ref_vector const& args);
|
||||
|
||||
bool is_var(expr* e) { return m_expr2var.contains(e); }
|
||||
expr* mk_expr(unsigned v) { return m_var2expr[v]; }
|
||||
unsigned mk_var(expr* e);
|
||||
|
||||
void reset(basic_union_find& uf);
|
||||
|
||||
expr_ref hoist_predicates(obj_hashtable<expr> const& p, unsigned num_args, expr* const* args);
|
||||
|
||||
|
||||
public:
|
||||
hoist_rewriter(ast_manager & m, params_ref const & p = params_ref());
|
||||
family_id get_fid() const { return m.get_basic_family_id(); }
|
||||
bool is_eq(expr * t) const { return m.is_eq(t); }
|
||||
void updt_params(params_ref const & p) {}
|
||||
static void get_param_descrs(param_descrs & r) {}
|
||||
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
void set_elim_and(bool b) { m_elim_and = b; }
|
||||
};
|
||||
|
||||
struct hoist_rewriter_cfg : public default_rewriter_cfg {
|
||||
hoist_rewriter m_r;
|
||||
bool rewrite_patterns() const { return false; }
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
result_pr = nullptr;
|
||||
if (f->get_family_id() != m_r.get_fid())
|
||||
return BR_FAILED;
|
||||
return m_r.mk_app_core(f, num, args, result);
|
||||
}
|
||||
hoist_rewriter_cfg(ast_manager & m, params_ref const & p):m_r(m, p) {}
|
||||
};
|
||||
|
||||
class hoist_rewriter_star : public rewriter_tpl<hoist_rewriter_cfg> {
|
||||
hoist_rewriter_cfg m_cfg;
|
||||
public:
|
||||
hoist_rewriter_star(ast_manager & m, params_ref const & p = params_ref()):
|
||||
rewriter_tpl<hoist_rewriter_cfg>(m, false, m_cfg),
|
||||
m_cfg(m, p) {}
|
||||
};
|
||||
|
|
@ -17,6 +17,8 @@ Notes:
|
|||
|
||||
--*/
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/rewriter/push_app_ite.h"
|
||||
#include "ast/rewriter/elim_bounds.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
@ -417,3 +419,6 @@ void inv_var_shifter::process_var(var * v) {
|
|||
}
|
||||
|
||||
template class rewriter_tpl<beta_reducer_cfg>;
|
||||
template class rewriter_tpl<ng_push_app_ite_cfg>;
|
||||
template class rewriter_tpl<push_app_ite_cfg>;
|
||||
template class rewriter_tpl<elim_bounds_cfg>;
|
||||
|
|
|
@ -33,6 +33,18 @@ enum br_status {
|
|||
BR_FAILED // no builtin rewrite is available
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, br_status st) {
|
||||
switch (st) {
|
||||
case BR_REWRITE1: return out << "rewrite1";
|
||||
case BR_REWRITE2: return out << "rewrite2";
|
||||
case BR_REWRITE3: return out << "rewrite3";
|
||||
case BR_REWRITE_FULL: return out << "rewrite_full";
|
||||
case BR_DONE: return out << "done";
|
||||
case BR_FAILED: return out << "failed";
|
||||
default: return out << "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#define RW_UNBOUNDED_DEPTH 3
|
||||
inline br_status unsigned2br_status(unsigned u) {
|
||||
br_status r = u >= RW_UNBOUNDED_DEPTH ? BR_REWRITE_FULL : static_cast<br_status>(u);
|
||||
|
|
|
@ -538,6 +538,7 @@ namespace seq {
|
|||
expr_ref t_eq_empty = mk_eq_empty(t);
|
||||
expr_ref xsy = mk_concat(x, s, y);
|
||||
|
||||
// add_clause(~mk_eq(t, s), i_eq_0);
|
||||
add_clause(cnt, i_eq_m1);
|
||||
add_clause(~t_eq_empty, s_eq_empty, i_eq_m1);
|
||||
add_clause(~s_eq_empty, mk_eq(i, mk_len(t)));
|
||||
|
|
|
@ -828,6 +828,7 @@ br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) {
|
|||
|
||||
br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) {
|
||||
zstring b;
|
||||
rational r;
|
||||
m_es.reset();
|
||||
str().get_concat(a, m_es);
|
||||
unsigned len = 0;
|
||||
|
@ -867,6 +868,16 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) {
|
|||
result = str().mk_length(z);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
// len(extract(x, 0, z)) = min(z, len(x))
|
||||
if (str().is_extract(a, x, y, z) &&
|
||||
m_autil.is_numeral(y, r) && r.is_zero() &&
|
||||
m_autil.is_numeral(z, r) && r >= 0) {
|
||||
expr* len_x = str().mk_length(x);
|
||||
result = m().mk_ite(m_autil.mk_le(len_x, z), len_x, z);
|
||||
// expr* zero = m_autil.mk_int(0);
|
||||
// result = m().mk_ite(m_autil.mk_le(z, zero), zero, result);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
#if 0
|
||||
expr* s = nullptr, *offset = nullptr, *length = nullptr;
|
||||
if (str().is_extract(a, s, offset, length)) {
|
||||
|
@ -1209,6 +1220,11 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
|
|||
constantPos &= pos.is_unsigned();
|
||||
constantLen &= len.is_unsigned();
|
||||
|
||||
if (constantPos && constantLen && len == 1) {
|
||||
result = str().mk_at(a, b);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
|
||||
if (constantPos && constantLen && constantBase) {
|
||||
unsigned _pos = pos.get_unsigned();
|
||||
unsigned _len = len.get_unsigned();
|
||||
|
@ -1245,6 +1261,15 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
|
|||
result = str().mk_substr(a1, m_autil.mk_add(b1, b), m_autil.mk_sub(c1, b));
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
rational r1, r2;
|
||||
if (str().is_extract(a, a1, b1, c1) &&
|
||||
m_autil.is_numeral(b1, r1) && r1.is_unsigned() &&
|
||||
m_autil.is_numeral(c1, r2) && r2.is_unsigned() &&
|
||||
constantPos && constantLen &&
|
||||
r1 == 0 && r2 >= pos + len) {
|
||||
result = str().mk_substr(a1, b, c);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
|
||||
if (str().is_extract(a, a1, b1, c1) &&
|
||||
is_prefix(a1, b1, c1) && is_prefix(a, b, c)) {
|
||||
|
@ -1539,9 +1564,17 @@ bool seq_rewriter::reduce_by_char(expr_ref& r, expr* ch, unsigned depth) {
|
|||
*/
|
||||
br_status seq_rewriter::mk_seq_at(expr* a, expr* b, expr_ref& result) {
|
||||
zstring c;
|
||||
rational r;
|
||||
rational r, offset_r, len_r;
|
||||
expr* offset, *a1, *len;
|
||||
expr_ref_vector lens(m());
|
||||
sort* sort_a = a->get_sort();
|
||||
if (str().is_extract(a, a1, offset, len) &&
|
||||
m_autil.is_numeral(offset, offset_r) && offset_r.is_zero() &&
|
||||
m_autil.is_numeral(len, len_r) && m_autil.is_numeral(b, r) &&
|
||||
r < len_r) {
|
||||
result = str().mk_at(a1, b);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
if (!get_lengths(b, lens, r)) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
@ -1716,6 +1749,10 @@ br_status seq_rewriter::mk_seq_last_index(expr* a, expr* b, expr_ref& result) {
|
|||
result = m_autil.mk_numeral(rational(idx), true);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (a == b) {
|
||||
result = m_autil.mk_int(0);
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ Notes:
|
|||
#include "ast/ast_util.h"
|
||||
#include "ast/well_sorted.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/array_peq.h"
|
||||
|
||||
namespace {
|
||||
struct th_rewriter_cfg : public default_rewriter_cfg {
|
||||
|
@ -75,6 +76,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
bool m_ignore_patterns_on_ground_qbody = true;
|
||||
bool m_rewrite_patterns = true;
|
||||
bool m_enable_der = true;
|
||||
bool m_nested_der = false;
|
||||
|
||||
|
||||
ast_manager & m() const { return m_b_rw.m(); }
|
||||
|
@ -91,6 +93,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
m_ignore_patterns_on_ground_qbody = p.ignore_patterns_on_ground_qbody();
|
||||
m_rewrite_patterns = p.rewrite_patterns();
|
||||
m_enable_der = p.enable_der();
|
||||
m_nested_der = _p.get_bool("nested_der", false);
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
|
@ -644,6 +647,10 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
else
|
||||
st = pull_ite(result);
|
||||
}
|
||||
if (st == BR_FAILED && f->get_family_id() == null_family_id && is_partial_eq(f)) {
|
||||
st = m_ar_rw.mk_app_core(f, num, args, result);
|
||||
}
|
||||
|
||||
CTRACE("th_rewriter_step", st != BR_FAILED,
|
||||
tout << f->get_name() << "\n";
|
||||
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";
|
||||
|
@ -838,8 +845,11 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
result = r;
|
||||
}
|
||||
|
||||
if (der_change) {
|
||||
if (der_change && !m_nested_der) {
|
||||
th_rewriter rw(m());
|
||||
params_ref p;
|
||||
p.set_bool("nested_der", true);
|
||||
rw.updt_params(p);
|
||||
rw(result, r, p2);
|
||||
if (m().proofs_enabled() && result.get() != r.get())
|
||||
result_pr = m().mk_transitivity(result_pr, p2);
|
||||
|
|
|
@ -37,6 +37,7 @@ class bound_simplifier : public dependent_expr_simplifier {
|
|||
unsynch_mpq_manager nm;
|
||||
small_object_allocator m_alloc;
|
||||
bound_propagator bp;
|
||||
u_dependency_manager m_dep_manager;
|
||||
dep_intervals m_interval;
|
||||
ptr_vector<expr> m_var2expr;
|
||||
unsigned_vector m_expr2var;
|
||||
|
@ -105,7 +106,7 @@ public:
|
|||
a(m),
|
||||
m_rewriter(m),
|
||||
bp(nm, m_alloc, p),
|
||||
m_interval(m.limit()),
|
||||
m_interval(m_dep_manager, m.limit()),
|
||||
m_trail(m),
|
||||
m_num_buffer(nm) {
|
||||
updt_params(p);
|
||||
|
|
|
@ -74,6 +74,8 @@ public:
|
|||
virtual bool inconsistent() = 0;
|
||||
virtual model_reconstruction_trail& model_trail() = 0;
|
||||
virtual void flatten_suffix() {}
|
||||
virtual bool updated() = 0;
|
||||
virtual void reset_updated() = 0;
|
||||
|
||||
trail_stack m_trail;
|
||||
void push() {
|
||||
|
@ -109,6 +111,9 @@ public:
|
|||
virtual void add(dependent_expr const& j) { throw default_exception("unexpected addition"); }
|
||||
virtual bool inconsistent() { return false; }
|
||||
virtual model_reconstruction_trail& model_trail() { throw default_exception("unexpected access to model reconstruction"); }
|
||||
virtual bool updated() { return false; }
|
||||
virtual void reset_updated() {}
|
||||
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, dependent_expr_state& st) {
|
||||
|
@ -147,7 +152,7 @@ protected:
|
|||
index_set indices() { return index_set(*this); }
|
||||
|
||||
proof* mp(proof* a, proof* b) { return (a && b) ? m.mk_modus_ponens(a, b) : nullptr; }
|
||||
|
||||
proof* tr(proof* a, proof* b) { return m.mk_transitivity(a, b); }
|
||||
public:
|
||||
dependent_expr_simplifier(ast_manager& m, dependent_expr_state& s) : m(m), m_fmls(s), m_trail(s.m_trail) {}
|
||||
virtual ~dependent_expr_simplifier() {}
|
||||
|
|
|
@ -243,8 +243,8 @@ namespace euf {
|
|||
|
||||
void solve_context_eqs::collect_nested_equalities(dependent_expr const& df, expr_mark& visited, dep_eq_vector& eqs) {
|
||||
|
||||
svector<std::tuple<bool,unsigned,expr*>> todo;
|
||||
todo.push_back({ false, 0, df.fml()});
|
||||
svector<std::tuple<bool,unsigned,expr*, unsigned>> todo;
|
||||
todo.push_back({ false, 0, df.fml(), 0});
|
||||
|
||||
// even depth is conjunctive context, odd is disjunctive
|
||||
// when alternating between conjunctive and disjunctive context, increment depth.
|
||||
|
@ -255,37 +255,85 @@ namespace euf {
|
|||
return (0 == depth % 2) ? depth : depth + 1;
|
||||
};
|
||||
|
||||
while (!todo.empty()) {
|
||||
auto [s, depth, f] = todo.back();
|
||||
todo.pop_back();
|
||||
for (unsigned i = 0; i < todo.size(); ++i) {
|
||||
auto [s, depth, f, p] = todo[i];
|
||||
if (visited.is_marked(f))
|
||||
continue;
|
||||
visited.mark(f, true);
|
||||
if (s && m.is_and(f)) {
|
||||
for (auto* arg : *to_app(f))
|
||||
todo.push_back({ s, inc_or(depth), arg });
|
||||
todo.push_back({ s, inc_or(depth), arg, i });
|
||||
}
|
||||
else if (!s && m.is_or(f)) {
|
||||
for (auto* arg : *to_app(f))
|
||||
todo.push_back({ s, inc_or(depth), arg });
|
||||
todo.push_back({ s, inc_or(depth), arg, i });
|
||||
}
|
||||
if (!s && m.is_and(f)) {
|
||||
for (auto* arg : *to_app(f))
|
||||
todo.push_back({ s, inc_and(depth), arg });
|
||||
todo.push_back({ s, inc_and(depth), arg, i });
|
||||
}
|
||||
else if (s && m.is_or(f)) {
|
||||
for (auto* arg : *to_app(f))
|
||||
todo.push_back({ s, inc_and(depth), arg });
|
||||
todo.push_back({ s, inc_and(depth), arg, i });
|
||||
}
|
||||
else if (m.is_not(f, f))
|
||||
todo.push_back({ !s, depth, f });
|
||||
todo.push_back({ !s, depth, f, i });
|
||||
else if (!s && 1 <= depth) {
|
||||
unsigned sz = eqs.size();
|
||||
for (extract_eq* ex : m_solve_eqs.m_extract_plugins) {
|
||||
ex->set_allow_booleans(false);
|
||||
ex->get_eqs(dependent_expr(m, f, nullptr, df.dep()), eqs);
|
||||
ex->set_allow_booleans(true);
|
||||
}
|
||||
// prune eqs for solutions that are not safe in df.fml()
|
||||
for (; sz < eqs.size(); ++sz) {
|
||||
if (!is_safe_var(eqs[sz].var, i, df.fml(), todo)) {
|
||||
eqs[sz] = eqs.back();
|
||||
--sz;
|
||||
eqs.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool solve_context_eqs::is_safe_var(expr* x, unsigned i, expr* f, svector<std::tuple<bool,unsigned,expr*,unsigned>> const& todo) {
|
||||
m_contains_v.reset();
|
||||
m_todo.push_back(f);
|
||||
mark_occurs(m_todo, x, m_contains_v);
|
||||
SASSERT(m_todo.empty());
|
||||
|
||||
auto is_parent = [&](unsigned p, unsigned i) {
|
||||
while (p != i && i != 0) {
|
||||
auto [_s,_depth, _f, _p] = todo[i];
|
||||
i = _p;
|
||||
}
|
||||
return p == i;
|
||||
};
|
||||
|
||||
// retrieve oldest parent of i within the same alternation of and
|
||||
unsigned pi = i;
|
||||
auto [_s, _depth, _f, _p] = todo[i];
|
||||
while (pi != 0) {
|
||||
auto [s, depth, f, p] = todo[pi];
|
||||
if (depth != _depth)
|
||||
break;
|
||||
pi = p;
|
||||
}
|
||||
|
||||
// determine if j and j have common conjunctive parent
|
||||
// for every j in todo.
|
||||
for (unsigned j = 0; j < todo.size(); ++j) {
|
||||
auto [s, depth, f, p] = todo[j];
|
||||
if (i == j || !m_contains_v.is_marked(f))
|
||||
continue;
|
||||
if (is_parent(j, i)) // j is a parent if i
|
||||
continue;
|
||||
if (is_parent(pi, j)) // pi is a parent of j
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,7 +45,9 @@ namespace euf {
|
|||
bool contains_conjunctively(expr* f, bool sign, expr* e, signed_expressions& conjuncts);
|
||||
bool is_conjunction(bool sign, expr* f) const;
|
||||
|
||||
void collect_nested_equalities(dependent_expr const& f, expr_mark& visited, dep_eq_vector& eqs);
|
||||
void collect_nested_equalities(dependent_expr const& f, expr_mark& visited, dep_eq_vector& eqs);
|
||||
|
||||
bool is_safe_var(expr* x, unsigned i, expr* f, svector<std::tuple<bool,unsigned,expr*,unsigned>> const& todo);
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -212,12 +212,13 @@ namespace euf {
|
|||
auto [f, p, d] = m_fmls[i]();
|
||||
auto [new_f, new_dep] = rp->replace_with_dep(f);
|
||||
proof_ref new_pr(m);
|
||||
m_rewriter(new_f, new_f, new_pr);
|
||||
if (new_f == f)
|
||||
expr_ref tmp(m);
|
||||
m_rewriter(new_f, tmp, new_pr);
|
||||
if (tmp == f)
|
||||
continue;
|
||||
new_dep = m.mk_join(d, new_dep);
|
||||
old_fmls.push_back(m_fmls[i]);
|
||||
m_fmls.update(i, dependent_expr(m, new_f, mp(p, new_pr), new_dep));
|
||||
m_fmls.update(i, dependent_expr(m, tmp, mp(p, new_pr), new_dep));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@ class then_simplifier : public dependent_expr_simplifier {
|
|||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
bool m_bail_on_no_change = false;
|
||||
|
||||
public:
|
||||
|
||||
then_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls):
|
||||
|
@ -72,9 +76,17 @@ public:
|
|||
break;
|
||||
s->reset_statistics();
|
||||
collect_stats _cs(*s);
|
||||
s->reduce();
|
||||
m_fmls.flatten_suffix();
|
||||
m_fmls.reset_updated();
|
||||
try {
|
||||
s->reduce();
|
||||
m_fmls.flatten_suffix();
|
||||
}
|
||||
catch (rewriter_exception &) {
|
||||
break;
|
||||
}
|
||||
TRACE("simplifier", tout << s->name() << "\n" << m_fmls);
|
||||
if (m_bail_on_no_change && !m_fmls.updated())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,3 +120,14 @@ public:
|
|||
s->pop(n);
|
||||
}
|
||||
};
|
||||
|
||||
class if_change_simplifier : public then_simplifier {
|
||||
public:
|
||||
if_change_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls):
|
||||
then_simplifier(m, p, fmls) {
|
||||
m_bail_on_no_change = true;
|
||||
}
|
||||
|
||||
char const* name() const override { return "if-change-then"; }
|
||||
|
||||
};
|
||||
|
|
|
@ -42,6 +42,7 @@ Notes:
|
|||
#include "ast/for_each_expr.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "ast/rewriter/recfun_replace.h"
|
||||
#include "ast/polymorphism_util.h"
|
||||
#include "model/model_evaluator.h"
|
||||
#include "model/model_smt2_pp.h"
|
||||
#include "model/model_v2_pp.h"
|
||||
|
@ -223,12 +224,48 @@ bool func_decls::check_signature(ast_manager& m, func_decl* f, unsigned arity, s
|
|||
return true;
|
||||
}
|
||||
|
||||
func_decl * func_decls::find(ast_manager& m, unsigned arity, sort * const * domain, sort * range) const {
|
||||
bool func_decls::check_poly_signature(ast_manager& m, func_decl* f, unsigned arity, sort* const* domain, sort* range, func_decl*& g) {
|
||||
polymorphism::substitution sub(m);
|
||||
arith_util au(m);
|
||||
sort_ref range_ref(range, m);
|
||||
if (range != nullptr && !sub.match(f->get_range(), range))
|
||||
return false;
|
||||
if (f->get_arity() != arity)
|
||||
return false;
|
||||
for (unsigned i = 0; i < arity; i++)
|
||||
if (!sub.match(f->get_domain(i), domain[i]))
|
||||
return false;
|
||||
if (!range)
|
||||
range_ref = sub(f->get_range());
|
||||
|
||||
recfun::util u(m);
|
||||
auto& p = u.get_plugin();
|
||||
if (!u.has_def(f)) {
|
||||
g = m.instantiate_polymorphic(f, arity, domain, range_ref);
|
||||
return true;
|
||||
}
|
||||
// this is an instantiation of a recursive polymorphic function.
|
||||
// create a self-contained polymorphic definition for the instantiation.
|
||||
auto def = u.get_def(f);
|
||||
auto promise_def = p.mk_def(f->get_name(), arity, domain, range_ref, false);
|
||||
recfun_replace replace(m);
|
||||
expr_ref tt = sub(def.get_rhs());
|
||||
p.set_definition(replace, promise_def, def.is_macro(), def.get_vars().size(), def.get_vars().data(), tt);
|
||||
g = promise_def.get_def()->get_decl();
|
||||
insert(m, g);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
func_decl * func_decls::find(ast_manager& m, unsigned arity, sort * const * domain, sort * range) {
|
||||
bool coerced = false;
|
||||
func_decl* g = nullptr;
|
||||
if (!more_than_one()) {
|
||||
func_decl* f = first();
|
||||
if (check_signature(m, f, arity, domain, range, coerced))
|
||||
return f;
|
||||
return f;
|
||||
if (check_poly_signature(m, f, arity, domain, range, g))
|
||||
return g;
|
||||
return nullptr;
|
||||
}
|
||||
func_decl_set * fs = UNTAG(func_decl_set *, m_decls);
|
||||
|
@ -241,10 +278,15 @@ func_decl * func_decls::find(ast_manager& m, unsigned arity, sort * const * doma
|
|||
return f;
|
||||
}
|
||||
}
|
||||
return best_f;
|
||||
if (best_f != nullptr)
|
||||
return best_f;
|
||||
for (func_decl* f : *fs)
|
||||
if (check_poly_signature(m, f, arity, domain, range, g))
|
||||
return g;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
func_decl * func_decls::find(ast_manager & m, unsigned num_args, expr * const * args, sort * range) const {
|
||||
func_decl * func_decls::find(ast_manager & m, unsigned num_args, expr * const * args, sort * range) {
|
||||
if (!more_than_one())
|
||||
first();
|
||||
ptr_buffer<sort> sorts;
|
||||
|
@ -376,12 +418,13 @@ void cmd_context::erase_macro(symbol const& s) {
|
|||
decls.erase_last(m());
|
||||
}
|
||||
|
||||
bool cmd_context::macros_find(symbol const& s, unsigned n, expr*const* args, expr_ref_vector& coerced_args, expr*& t) const {
|
||||
bool cmd_context::macros_find(symbol const& s, unsigned n, expr*const* args, expr_ref_vector& coerced_args, expr_ref& t) {
|
||||
macro_decls decls;
|
||||
if (!m_macros.find(s, decls))
|
||||
return false;
|
||||
for (macro_decl const& d : decls) {
|
||||
if (d.m_domain.size() != n) continue;
|
||||
if (d.m_domain.size() != n)
|
||||
continue;
|
||||
bool eq = true;
|
||||
coerced_args.reset();
|
||||
for (unsigned i = 0; eq && i < n; ++i) {
|
||||
|
@ -406,6 +449,26 @@ bool cmd_context::macros_find(symbol const& s, unsigned n, expr*const* args, exp
|
|||
return true;
|
||||
}
|
||||
}
|
||||
for (macro_decl const& d : decls) {
|
||||
if (d.m_domain.size() != n)
|
||||
continue;
|
||||
polymorphism::substitution sub(m());
|
||||
bool eq = true;
|
||||
for (unsigned i = 0; eq && i < n; ++i) {
|
||||
if (!sub.match(d.m_domain[i], args[i]->get_sort()))
|
||||
eq = false;
|
||||
}
|
||||
if (eq) {
|
||||
t = d.m_body;
|
||||
t = sub(t);
|
||||
verbose_stream() << "macro " << t << "\n";
|
||||
ptr_buffer<sort> domain;
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
domain.push_back(args[i]->get_sort());
|
||||
insert_macro(s, n, domain.data(), t);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -939,18 +1002,16 @@ void cmd_context::insert(cmd * c) {
|
|||
void cmd_context::insert_user_tactic(symbol const & s, sexpr * d) {
|
||||
sm().inc_ref(d);
|
||||
sexpr * old_d;
|
||||
if (m_user_tactic_decls.find(s, old_d)) {
|
||||
sm().dec_ref(old_d);
|
||||
}
|
||||
if (m_user_tactic_decls.find(s, old_d))
|
||||
sm().dec_ref(old_d);
|
||||
m_user_tactic_decls.insert(s, d);
|
||||
}
|
||||
|
||||
void cmd_context::insert(symbol const & s, object_ref * r) {
|
||||
r->inc_ref(*this);
|
||||
object_ref * old_r = nullptr;
|
||||
if (m_object_refs.find(s, old_r)) {
|
||||
old_r->dec_ref(*this);
|
||||
}
|
||||
if (m_object_refs.find(s, old_r))
|
||||
old_r->dec_ref(*this);
|
||||
m_object_refs.insert(s, r);
|
||||
}
|
||||
|
||||
|
@ -1054,16 +1115,17 @@ static builtin_decl const & peek_builtin_decl(builtin_decl const & first, family
|
|||
}
|
||||
|
||||
func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices,
|
||||
unsigned arity, sort * const * domain, sort * range) const {
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
|
||||
if (domain && contains_macro(s, arity, domain))
|
||||
throw cmd_exception("invalid function declaration reference, named expressions (aka macros) cannot be referenced ", s);
|
||||
|
||||
func_decl * f = nullptr;
|
||||
func_decls fs;
|
||||
if (num_indices == 0 && m_func_decls.find(s, fs))
|
||||
if (num_indices == 0 && m_func_decls.contains(s)) {
|
||||
auto& fs = m_func_decls.find(s);
|
||||
f = fs.find(m(), arity, domain, range);
|
||||
if (f)
|
||||
}
|
||||
if (f)
|
||||
return f;
|
||||
builtin_decl d;
|
||||
if ((arity == 0 || domain) && m_builtin_decls.find(s, d)) {
|
||||
|
@ -1089,11 +1151,12 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices,
|
|||
throw cmd_exception("invalid function declaration reference, invalid builtin reference ", s);
|
||||
return f;
|
||||
}
|
||||
if (num_indices > 0 && m_func_decls.find(s, fs))
|
||||
if (num_indices > 0 && m_func_decls.contains(s)) {
|
||||
auto& fs = m_func_decls.find(s);
|
||||
f = fs.find(m(), arity, domain, range);
|
||||
if (f)
|
||||
}
|
||||
if (f)
|
||||
return f;
|
||||
|
||||
throw cmd_exception("invalid function declaration reference, unknown indexed function ", s);
|
||||
}
|
||||
|
||||
|
@ -1125,7 +1188,7 @@ object_ref * cmd_context::find_object_ref(symbol const & s) const {
|
|||
|
||||
#define CHECK_SORT(T) if (well_sorted_check_enabled()) m().check_sorts_core(T)
|
||||
|
||||
void cmd_context::mk_const(symbol const & s, expr_ref & result) const {
|
||||
void cmd_context::mk_const(symbol const & s, expr_ref & result) {
|
||||
mk_app(s, 0, nullptr, 0, nullptr, nullptr, result);
|
||||
}
|
||||
|
||||
|
@ -1153,9 +1216,10 @@ bool cmd_context::try_mk_builtin_app(symbol const & s, unsigned num_args, expr *
|
|||
|
||||
bool cmd_context::try_mk_declared_app(symbol const & s, unsigned num_args, expr * const * args,
|
||||
unsigned num_indices, parameter const * indices, sort * range,
|
||||
func_decls& fs, expr_ref & result) const {
|
||||
if (!m_func_decls.find(s, fs))
|
||||
expr_ref & result) {
|
||||
if (!m_func_decls.contains(s))
|
||||
return false;
|
||||
func_decls& fs = m_func_decls.find(s);
|
||||
|
||||
if (num_args == 0 && !range) {
|
||||
if (fs.more_than_one())
|
||||
|
@ -1180,8 +1244,8 @@ bool cmd_context::try_mk_declared_app(symbol const & s, unsigned num_args, expr
|
|||
|
||||
bool cmd_context::try_mk_macro_app(symbol const & s, unsigned num_args, expr * const * args,
|
||||
unsigned num_indices, parameter const * indices, sort * range,
|
||||
expr_ref & result) const {
|
||||
expr* _t;
|
||||
expr_ref & result) {
|
||||
expr_ref _t(m());
|
||||
expr_ref_vector coerced_args(m());
|
||||
if (macros_find(s, num_args, args, coerced_args, _t)) {
|
||||
TRACE("macro_bug", tout << "well_sorted_check_enabled(): " << well_sorted_check_enabled() << "\n";
|
||||
|
@ -1256,19 +1320,21 @@ bool cmd_context::try_mk_pdecl_app(symbol const & s, unsigned num_args, expr * c
|
|||
|
||||
void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * args,
|
||||
unsigned num_indices, parameter const * indices, sort * range,
|
||||
expr_ref & result) const {
|
||||
expr_ref & result) {
|
||||
|
||||
func_decls fs;
|
||||
|
||||
|
||||
if (try_mk_macro_app(s, num_args, args, num_indices, indices, range, result))
|
||||
return;
|
||||
if (try_mk_declared_app(s, num_args, args, num_indices, indices, range, fs, result))
|
||||
return;
|
||||
if (try_mk_declared_app(s, num_args, args, num_indices, indices, range, result))
|
||||
return;
|
||||
if (try_mk_builtin_app(s, num_args, args, num_indices, indices, range, result))
|
||||
return;
|
||||
if (!range && try_mk_pdecl_app(s, num_args, args, num_indices, indices, result))
|
||||
return;
|
||||
|
||||
func_decls fs;
|
||||
m_func_decls.find(s, fs);
|
||||
std::ostringstream buffer;
|
||||
buffer << "unknown constant " << s;
|
||||
if (num_args > 0) {
|
||||
|
@ -1612,6 +1678,8 @@ void cmd_context::restore_assertions(unsigned old_sz) {
|
|||
SASSERT(m_assertions.empty());
|
||||
return;
|
||||
}
|
||||
if (m_assertions.empty())
|
||||
return;
|
||||
if (old_sz == m_assertions.size())
|
||||
return;
|
||||
SASSERT(old_sz < m_assertions.size());
|
||||
|
@ -2230,6 +2298,8 @@ vector<std::pair<expr*,expr*>> cmd_context::tracked_assertions() {
|
|||
}
|
||||
|
||||
void cmd_context::reset_tracked_assertions() {
|
||||
for (expr* a : m_assertion_names)
|
||||
m().dec_ref(a);
|
||||
m_assertion_names.reset();
|
||||
for (expr* a : m_assertions)
|
||||
m().dec_ref(a);
|
||||
|
|
|
@ -58,11 +58,12 @@ public:
|
|||
bool clash(func_decl * f) const;
|
||||
bool empty() const { return m_decls == nullptr; }
|
||||
func_decl * first() const;
|
||||
func_decl * find(ast_manager & m, unsigned arity, sort * const * domain, sort * range) const;
|
||||
func_decl * find(ast_manager & m, unsigned arity, expr * const * args, sort * range) const;
|
||||
func_decl * find(ast_manager & m, unsigned arity, sort * const * domain, sort * range);
|
||||
func_decl * find(ast_manager & m, unsigned arity, expr * const * args, sort * range);
|
||||
unsigned get_num_entries() const;
|
||||
func_decl * get_entry(unsigned inx);
|
||||
bool check_signature(ast_manager& m, func_decl* f, unsigned arityh, sort * const* domain, sort * range, bool& coerced) const;
|
||||
bool check_poly_signature(ast_manager& m, func_decl* f, unsigned arity, sort* const* domain, sort* range, func_decl*& g);
|
||||
};
|
||||
|
||||
struct macro_decl {
|
||||
|
@ -355,7 +356,7 @@ protected:
|
|||
bool contains_macro(symbol const& s, unsigned arity, sort *const* domain) const;
|
||||
void insert_macro(symbol const& s, unsigned arity, sort*const* domain, expr* t);
|
||||
void erase_macro(symbol const& s);
|
||||
bool macros_find(symbol const& s, unsigned n, expr*const* args, expr_ref_vector& coerced_args, expr*& t) const;
|
||||
bool macros_find(symbol const& s, unsigned n, expr*const* args, expr_ref_vector& coerced_args, expr_ref& t);
|
||||
|
||||
recfun::decl::plugin& get_recfun_plugin();
|
||||
|
||||
|
@ -449,22 +450,22 @@ public:
|
|||
void insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector<symbol> const& ids, expr* e);
|
||||
func_decl * find_func_decl(symbol const & s) const;
|
||||
func_decl * find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices,
|
||||
unsigned arity, sort * const * domain, sort * range) const;
|
||||
unsigned arity, sort * const * domain, sort * range);
|
||||
recfun::promise_def decl_rec_fun(const symbol &name, unsigned int arity, sort *const *domain, sort *range);
|
||||
psort_decl * find_psort_decl(symbol const & s) const;
|
||||
cmd * find_cmd(symbol const & s) const;
|
||||
sexpr * find_user_tactic(symbol const & s) const;
|
||||
object_ref * find_object_ref(symbol const & s) const;
|
||||
void mk_const(symbol const & s, expr_ref & result) const;
|
||||
void mk_const(symbol const & s, expr_ref & result);
|
||||
void mk_app(symbol const & s, unsigned num_args, expr * const * args, unsigned num_indices, parameter const * indices, sort * range,
|
||||
expr_ref & r) const;
|
||||
expr_ref & r);
|
||||
bool try_mk_macro_app(symbol const & s, unsigned num_args, expr * const * args, unsigned num_indices, parameter const * indices, sort * range,
|
||||
expr_ref & r) const;
|
||||
expr_ref & r);
|
||||
bool try_mk_builtin_app(symbol const & s, unsigned num_args, expr * const * args, unsigned num_indices, parameter const * indices, sort * range,
|
||||
expr_ref & r) const;
|
||||
bool try_mk_declared_app(symbol const & s, unsigned num_args, expr * const * args,
|
||||
unsigned num_indices, parameter const * indices, sort * range,
|
||||
func_decls& fs, expr_ref & result) const;
|
||||
expr_ref & result);
|
||||
bool try_mk_pdecl_app(symbol const & s, unsigned num_args, expr * const * args, unsigned num_indices, parameter const * indices, expr_ref & r) const;
|
||||
void erase_cmd(symbol const & s);
|
||||
void erase_func_decl(symbol const & s);
|
||||
|
|
|
@ -16,6 +16,7 @@ Notes:
|
|||
|
||||
--*/
|
||||
#include<iomanip>
|
||||
#include "ast/ast.h"
|
||||
#include "cmd_context/cmd_context.h"
|
||||
#include "cmd_context/cmd_util.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
|
@ -34,7 +35,9 @@ Notes:
|
|||
#include "qe/qe_mbp.h"
|
||||
#include "qe/qe_mbi.h"
|
||||
#include "qe/mbp/mbp_term_graph.h"
|
||||
|
||||
#include "qe/mbp/mbp_qel.h"
|
||||
#include "qe/lite/qe_lite_tactic.h"
|
||||
#include "qe/lite/qel.h"
|
||||
|
||||
BINARY_SYM_CMD(get_quantifier_body_cmd,
|
||||
"dbg-get-qbody",
|
||||
|
@ -369,7 +372,7 @@ public:
|
|||
}
|
||||
vars.push_back(to_app(v));
|
||||
}
|
||||
qe::mbproj mbp(m);
|
||||
qe::mbproj mbp(m, gparams::get_module("smt"));
|
||||
expr_ref fml(m_fml, m);
|
||||
mbp.spacer(vars, *mdl.get(), fml);
|
||||
ctx.regular_stream() << fml << "\n";
|
||||
|
@ -572,8 +575,192 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class mbp_qel_cmd : public cmd {
|
||||
unsigned m_arg_index;
|
||||
ptr_vector<expr> m_lits;
|
||||
ptr_vector<expr> m_vars;
|
||||
|
||||
void install_dbg_cmds(cmd_context & ctx) {
|
||||
public:
|
||||
mbp_qel_cmd() : cmd("mbp-qel"){};
|
||||
char const *get_usage() const override { return "(exprs) (vars)"; }
|
||||
char const *get_descr(cmd_context &ctx) const override {
|
||||
return "Model based projection using e-graphs";
|
||||
}
|
||||
unsigned get_arity() const override { return 2; }
|
||||
cmd_arg_kind next_arg_kind(cmd_context &ctx) const override {
|
||||
return CPK_EXPR_LIST;
|
||||
}
|
||||
void set_next_arg(cmd_context &ctx, unsigned num,
|
||||
expr *const *args) override {
|
||||
if (m_arg_index == 0) {
|
||||
m_lits.append(num, args);
|
||||
m_arg_index = 1;
|
||||
}
|
||||
else { m_vars.append(num, args); }
|
||||
}
|
||||
void prepare(cmd_context &ctx) override {
|
||||
m_arg_index = 0;
|
||||
m_lits.reset();
|
||||
m_vars.reset();
|
||||
}
|
||||
void execute(cmd_context &ctx) override {
|
||||
ast_manager &m = ctx.m();
|
||||
app_ref_vector vars(m);
|
||||
expr_ref fml(m);
|
||||
expr_ref_vector lits(m);
|
||||
for (expr *v : m_vars) vars.push_back(to_app(v));
|
||||
for (expr *e : m_lits) lits.push_back(e);
|
||||
fml = mk_and(lits);
|
||||
solver_factory &sf = ctx.get_solver_factory();
|
||||
params_ref pa;
|
||||
solver_ref s = sf(m, pa, false, true, true, symbol::null);
|
||||
s->assert_expr(fml);
|
||||
lbool r = s->check_sat();
|
||||
if (r != l_true) return;
|
||||
model_ref mdl;
|
||||
s->get_model(mdl);
|
||||
mbp::mbp_qel mbptg(m, pa);
|
||||
mbptg(vars, fml, *mdl.get());
|
||||
|
||||
ctx.regular_stream() << "------------------------------ " << std::endl;
|
||||
ctx.regular_stream() << "Orig tg: " << mk_and(lits) << std::endl;
|
||||
ctx.regular_stream() << "To elim: ";
|
||||
for (expr *v : m_vars) {
|
||||
ctx.regular_stream() << to_app(v)->get_decl()->get_name() << " ";
|
||||
}
|
||||
ctx.regular_stream() << std::endl;
|
||||
ctx.regular_stream() << "output " << fml << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
class qel_cmd : public cmd {
|
||||
unsigned m_arg_index;
|
||||
ptr_vector<expr> m_lits;
|
||||
ptr_vector<func_decl> m_vars;
|
||||
|
||||
public:
|
||||
qel_cmd() : cmd("qel"){};
|
||||
char const *get_usage() const override { return "(lits) (vars)"; }
|
||||
char const *get_descr(cmd_context &ctx) const override {
|
||||
return "QE lite over e-graphs";
|
||||
}
|
||||
unsigned get_arity() const override { return 2; }
|
||||
cmd_arg_kind next_arg_kind(cmd_context &ctx) const override {
|
||||
if (m_arg_index == 0) return CPK_EXPR_LIST;
|
||||
return CPK_FUNC_DECL_LIST;
|
||||
}
|
||||
void set_next_arg(cmd_context &ctx, unsigned num,
|
||||
expr *const *args) override {
|
||||
m_lits.append(num, args);
|
||||
m_arg_index = 1;
|
||||
}
|
||||
void set_next_arg(cmd_context &ctx, unsigned num,
|
||||
func_decl *const *ts) override {
|
||||
m_vars.append(num, ts);
|
||||
}
|
||||
void prepare(cmd_context &ctx) override {
|
||||
m_arg_index = 0;
|
||||
m_lits.reset();
|
||||
m_vars.reset();
|
||||
}
|
||||
void execute(cmd_context &ctx) override {
|
||||
ast_manager &m = ctx.m();
|
||||
func_decl_ref_vector vars(m);
|
||||
app_ref_vector vars_apps(m);
|
||||
expr_ref_vector lits(m);
|
||||
|
||||
ctx.regular_stream() << "------------------------------ " << std::endl;
|
||||
|
||||
for (func_decl *v : m_vars) {
|
||||
vars.push_back(v);
|
||||
vars_apps.push_back(m.mk_const(v));
|
||||
}
|
||||
for (expr *e : m_lits) lits.push_back(e);
|
||||
|
||||
expr_ref fml(m.mk_and(lits), m);
|
||||
ctx.regular_stream() << "[tg] Before: " << fml << std::endl
|
||||
<< "[tg] Vars: ";
|
||||
for (app *a : vars_apps) ctx.regular_stream() << app_ref(a, m) << " ";
|
||||
|
||||
ctx.regular_stream() << std::endl;
|
||||
|
||||
params_ref pa;
|
||||
|
||||
// the following is the same code as in qe_mbp in spacer
|
||||
qel qe(m, pa);
|
||||
qe(vars_apps, fml);
|
||||
ctx.regular_stream() << "[tg] After: " << fml << std::endl
|
||||
<< "[tg] Vars: ";
|
||||
for (app *a : vars_apps) ctx.regular_stream() << app_ref(a, m) << " ";
|
||||
|
||||
ctx.regular_stream() << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
class qe_lite_cmd : public cmd {
|
||||
unsigned m_arg_index;
|
||||
ptr_vector<expr> m_lits;
|
||||
ptr_vector<func_decl> m_vars;
|
||||
|
||||
public:
|
||||
qe_lite_cmd() : cmd("qe-lite"){};
|
||||
char const *get_usage() const override { return "(lits) (vars)"; }
|
||||
char const *get_descr(cmd_context &ctx) const override {
|
||||
return "QE lite over e-graphs";
|
||||
}
|
||||
unsigned get_arity() const override { return 2; }
|
||||
cmd_arg_kind next_arg_kind(cmd_context &ctx) const override {
|
||||
if (m_arg_index == 0) return CPK_EXPR_LIST;
|
||||
return CPK_FUNC_DECL_LIST;
|
||||
}
|
||||
void set_next_arg(cmd_context &ctx, unsigned num,
|
||||
expr *const *args) override {
|
||||
m_lits.append(num, args);
|
||||
m_arg_index = 1;
|
||||
}
|
||||
void set_next_arg(cmd_context &ctx, unsigned num,
|
||||
func_decl *const *ts) override {
|
||||
m_vars.append(num, ts);
|
||||
}
|
||||
void prepare(cmd_context &ctx) override {
|
||||
m_arg_index = 0;
|
||||
m_lits.reset();
|
||||
m_vars.reset();
|
||||
}
|
||||
void execute(cmd_context &ctx) override {
|
||||
ast_manager &m = ctx.m();
|
||||
func_decl_ref_vector vars(m);
|
||||
app_ref_vector vars_apps(m);
|
||||
expr_ref_vector lits(m);
|
||||
|
||||
ctx.regular_stream() << "------------------------------ " << std::endl;
|
||||
|
||||
for (func_decl *v : m_vars) {
|
||||
vars.push_back(v);
|
||||
vars_apps.push_back(m.mk_const(v));
|
||||
}
|
||||
for (expr *e : m_lits) lits.push_back(e);
|
||||
|
||||
expr_ref fml(m.mk_and(lits), m);
|
||||
ctx.regular_stream() << "[der] Before: " << fml << std::endl
|
||||
<< "[der] Vars: ";
|
||||
for (app *a : vars_apps) ctx.regular_stream() << app_ref(a, m) << " ";
|
||||
|
||||
ctx.regular_stream() << std::endl;
|
||||
|
||||
params_ref pa;
|
||||
// the following is the same code as in qe_mbp in spacer
|
||||
qe_lite qe(m, pa, false);
|
||||
qe(vars_apps, fml);
|
||||
ctx.regular_stream() << "[der] After: " << fml << std::endl
|
||||
<< "[der] Vars: ";
|
||||
for (app *a : vars_apps) ctx.regular_stream() << app_ref(a, m) << " ";
|
||||
|
||||
ctx.regular_stream() << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
void install_dbg_cmds(cmd_context &ctx) {
|
||||
ctx.insert(alloc(print_dimacs_cmd));
|
||||
ctx.insert(alloc(get_quantifier_body_cmd));
|
||||
ctx.insert(alloc(set_cmd));
|
||||
|
@ -598,7 +785,10 @@ void install_dbg_cmds(cmd_context & ctx) {
|
|||
ctx.insert(alloc(set_next_id));
|
||||
ctx.insert(alloc(get_interpolant_cmd));
|
||||
ctx.insert(alloc(mbp_cmd));
|
||||
ctx.insert(alloc(mbp_qel_cmd));
|
||||
ctx.insert(alloc(mbi_cmd));
|
||||
ctx.insert(alloc(euf_project_cmd));
|
||||
ctx.insert(alloc(eufi_cmd));
|
||||
ctx.insert(alloc(qel_cmd));
|
||||
ctx.insert(alloc(qe_lite_cmd));
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ public:
|
|||
if (m_empty)
|
||||
return;
|
||||
|
||||
if (hint && !is_rup(hint) && m_checker.check(hint)) {
|
||||
if (hint && !is_rup(hint)) {
|
||||
auto clause1 = m_checker.clause(hint);
|
||||
if (clause1.size() != clause.size()) {
|
||||
mk_clause(clause1);
|
||||
|
@ -239,8 +239,10 @@ public:
|
|||
class proof_cmds_imp : public proof_cmds {
|
||||
cmd_context& ctx;
|
||||
ast_manager& m;
|
||||
arith_util m_arith;
|
||||
expr_ref_vector m_lits;
|
||||
app_ref m_proof_hint;
|
||||
unsigned_vector m_deps;
|
||||
bool m_check = true;
|
||||
bool m_save = false;
|
||||
bool m_trim = false;
|
||||
|
@ -266,11 +268,24 @@ class proof_cmds_imp : public proof_cmds {
|
|||
m_del = m.mk_app(symbol("del"), 0, nullptr, m.mk_proof_sort());
|
||||
return m_del;
|
||||
}
|
||||
|
||||
bool is_dep(expr* e) {
|
||||
return m.is_proof(e) && symbol("deps") == to_app(e)->get_name();
|
||||
}
|
||||
|
||||
void get_deps(expr* e) {
|
||||
rational n;
|
||||
bool is_int = false;
|
||||
for (expr* arg : *to_app(e))
|
||||
if (m_arith.is_numeral(arg, n, is_int) && n.is_unsigned())
|
||||
m_deps.push_back(n.get_unsigned());
|
||||
}
|
||||
|
||||
public:
|
||||
proof_cmds_imp(cmd_context& ctx):
|
||||
ctx(ctx),
|
||||
m(ctx.m()),
|
||||
m(ctx.m()),
|
||||
m_arith(m),
|
||||
m_lits(m),
|
||||
m_proof_hint(m),
|
||||
m_assumption(m),
|
||||
|
@ -280,7 +295,9 @@ public:
|
|||
|
||||
void add_literal(expr* e) override {
|
||||
if (m.is_proof(e)) {
|
||||
if (!m_proof_hint)
|
||||
if (is_dep(e))
|
||||
get_deps(e);
|
||||
else if (!m_proof_hint)
|
||||
m_proof_hint = to_app(e);
|
||||
}
|
||||
else if (!m.is_bool(e))
|
||||
|
@ -297,9 +314,10 @@ public:
|
|||
if (m_trim)
|
||||
trim().assume(m_lits);
|
||||
if (m_on_clause_eh)
|
||||
m_on_clause_eh(m_on_clause_ctx, assumption(), m_lits.size(), m_lits.data());
|
||||
m_on_clause_eh(m_on_clause_ctx, assumption(), m_deps.size(), m_deps.data(), m_lits.size(), m_lits.data());
|
||||
m_lits.reset();
|
||||
m_proof_hint.reset();
|
||||
m_deps.reset();
|
||||
}
|
||||
|
||||
void end_infer() override {
|
||||
|
@ -310,9 +328,10 @@ public:
|
|||
if (m_trim)
|
||||
trim().infer(m_lits, m_proof_hint);
|
||||
if (m_on_clause_eh)
|
||||
m_on_clause_eh(m_on_clause_ctx, m_proof_hint, m_lits.size(), m_lits.data());
|
||||
m_on_clause_eh(m_on_clause_ctx, m_proof_hint, m_deps.size(), m_deps.data(), m_lits.size(), m_lits.data());
|
||||
m_lits.reset();
|
||||
m_proof_hint.reset();
|
||||
m_deps.reset();
|
||||
}
|
||||
|
||||
void end_deleted() override {
|
||||
|
@ -323,16 +342,17 @@ public:
|
|||
if (m_trim)
|
||||
trim().del(m_lits);
|
||||
if (m_on_clause_eh)
|
||||
m_on_clause_eh(m_on_clause_ctx, del(), m_lits.size(), m_lits.data());
|
||||
m_on_clause_eh(m_on_clause_ctx, del(), m_deps.size(), m_deps.data(), m_lits.size(), m_lits.data());
|
||||
m_lits.reset();
|
||||
m_proof_hint.reset();
|
||||
m_deps.reset();
|
||||
}
|
||||
|
||||
void updt_params(params_ref const& p) override {
|
||||
solver_params sp(p);
|
||||
m_check = sp.proof_check();
|
||||
m_save = sp.proof_save();
|
||||
m_trim = sp.proof_trim();
|
||||
m_check = sp.proof_check() && !m_trim && !m_save && !m_on_clause_eh;
|
||||
if (m_trim)
|
||||
trim().updt_params(p);
|
||||
}
|
||||
|
@ -340,6 +360,8 @@ public:
|
|||
void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause_eh) override {
|
||||
m_on_clause_ctx = ctx;
|
||||
m_on_clause_eh = on_clause_eh;
|
||||
if (m_on_clause_eh)
|
||||
m_check = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -838,14 +838,18 @@ struct pdecl_manager::app_sort_info : public pdecl_manager::sort_info {
|
|||
}
|
||||
|
||||
format * pp(smt2_pp_environment& env, pdecl_manager const & m) const override {
|
||||
symbol s = m_decl->get_name();
|
||||
std::string name = s.str();
|
||||
if (is_smt2_quoted_symbol(s))
|
||||
name = mk_smt2_quoted_symbol(s);
|
||||
if (m_args.empty()) {
|
||||
return mk_string(m.m(), m_decl->get_name().str());
|
||||
return mk_string(m.m(), name);
|
||||
}
|
||||
else {
|
||||
ptr_buffer<format> b;
|
||||
for (auto arg : m_args)
|
||||
b.push_back(m.pp(env, arg));
|
||||
return mk_seq1(m.m(), b.begin(), b.end(), f2f(), m_decl->get_name().str());
|
||||
return mk_seq1(m.m(), b.begin(), b.end(), f2f(), name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -874,12 +878,17 @@ struct pdecl_manager::indexed_sort_info : public pdecl_manager::sort_info {
|
|||
}
|
||||
|
||||
format * pp(smt2_pp_environment& env, pdecl_manager const & m) const override {
|
||||
symbol s = m_decl->get_name();
|
||||
std::string name = s.str();
|
||||
if (is_smt2_quoted_symbol(s))
|
||||
name = mk_smt2_quoted_symbol(s);
|
||||
|
||||
if (m_indices.empty()) {
|
||||
return mk_string(m.m(), m_decl->get_name().str());
|
||||
return mk_string(m.m(), name);
|
||||
}
|
||||
else {
|
||||
ptr_buffer<format> b;
|
||||
b.push_back(mk_string(m.m(), m_decl->get_name().str()));
|
||||
b.push_back(mk_string(m.m(), name));
|
||||
for (auto idx : m_indices)
|
||||
b.push_back(mk_unsigned(m.m(), idx));
|
||||
return mk_seq1(m.m(), b.begin(), b.end(), f2f(), "_");
|
||||
|
|
|
@ -62,6 +62,10 @@ namespace dd {
|
|||
init_nodes(level2var);
|
||||
}
|
||||
|
||||
void pdd_manager::set_max_num_nodes(unsigned n) {
|
||||
m_max_num_nodes = n + m_level2var.size();
|
||||
}
|
||||
|
||||
void pdd_manager::init_nodes(unsigned_vector const& l2v) {
|
||||
// add dummy nodes for operations, and 0, 1 pdds.
|
||||
for (unsigned i = 0; i < pdd_no_op; ++i) {
|
||||
|
@ -1614,7 +1618,8 @@ namespace dd {
|
|||
for (unsigned i = m_nodes.size(); i-- > pdd_no_op; ) {
|
||||
if (!reachable[i]) {
|
||||
if (is_val(i)) {
|
||||
if (m_freeze_value == val(i)) continue;
|
||||
if (m_freeze_value == val(i))
|
||||
continue;
|
||||
m_free_values.push_back(m_mpq_table.find(val(i)).m_value_index);
|
||||
m_mpq_table.remove(val(i));
|
||||
}
|
||||
|
@ -1629,20 +1634,17 @@ namespace dd {
|
|||
|
||||
ptr_vector<op_entry> to_delete, to_keep;
|
||||
for (auto* e : m_op_cache) {
|
||||
if (e->m_result != null_pdd) {
|
||||
to_delete.push_back(e);
|
||||
}
|
||||
else {
|
||||
to_keep.push_back(e);
|
||||
}
|
||||
if (e->m_result != null_pdd)
|
||||
to_delete.push_back(e);
|
||||
else
|
||||
to_keep.push_back(e);
|
||||
}
|
||||
m_op_cache.reset();
|
||||
for (op_entry* e : to_delete) {
|
||||
for (op_entry* e : to_delete)
|
||||
m_alloc.deallocate(sizeof(*e), e);
|
||||
}
|
||||
for (op_entry* e : to_keep) {
|
||||
m_op_cache.insert(e);
|
||||
}
|
||||
|
||||
for (op_entry* e : to_keep)
|
||||
m_op_cache.insert(e);
|
||||
|
||||
m_factor_cache.reset();
|
||||
|
||||
|
|
|
@ -327,8 +327,9 @@ namespace dd {
|
|||
semantics get_semantics() const { return m_semantics; }
|
||||
|
||||
void reset(unsigned_vector const& level2var);
|
||||
void set_max_num_nodes(unsigned n) { m_max_num_nodes = n; }
|
||||
void set_max_num_nodes(unsigned n);
|
||||
unsigned_vector const& get_level2var() const { return m_level2var; }
|
||||
unsigned num_nodes() const { return m_nodes.size() - m_free_nodes.size(); }
|
||||
|
||||
pdd mk_var(unsigned i);
|
||||
pdd mk_val(rational const& r);
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace dd {
|
|||
}
|
||||
}
|
||||
catch (pdd_manager::mem_out) {
|
||||
IF_VERBOSE(2, verbose_stream() << "simplifier memout\n");
|
||||
IF_VERBOSE(1, verbose_stream() << "simplifier memout\n");
|
||||
// done reduce
|
||||
DEBUG_CODE(s.invariant(););
|
||||
}
|
||||
|
@ -89,12 +89,13 @@ namespace dd {
|
|||
|
||||
bool simplifier::simplify_linear_step(bool binary) {
|
||||
TRACE("dd.solver", tout << "binary " << binary << "\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "binary " << binary << "\n");
|
||||
IF_VERBOSE(3, verbose_stream() << "binary " << binary << "\n");
|
||||
equation_vector linear;
|
||||
for (equation* e : s.m_to_simplify) {
|
||||
pdd p = e->poly();
|
||||
if (binary) {
|
||||
if (p.is_binary()) linear.push_back(e);
|
||||
if (p.is_binary())
|
||||
linear.push_back(e);
|
||||
}
|
||||
else if (p.is_linear()) {
|
||||
linear.push_back(e);
|
||||
|
@ -112,29 +113,33 @@ namespace dd {
|
|||
use_list_t use_list = get_use_list();
|
||||
compare_top_var ctv;
|
||||
std::stable_sort(linear.begin(), linear.end(), ctv);
|
||||
equation_vector trivial;
|
||||
struct trivial {
|
||||
solver& s;
|
||||
equation_vector elems;
|
||||
trivial(solver& s) : s(s) {}
|
||||
~trivial () {
|
||||
for (auto* e : elems)
|
||||
s.del_equation(e);
|
||||
}
|
||||
};
|
||||
trivial trivial(s);
|
||||
unsigned j = 0;
|
||||
bool has_conflict = false;
|
||||
for (equation* src : linear) {
|
||||
if (has_conflict) {
|
||||
break;
|
||||
}
|
||||
if (s.is_trivial(*src)) {
|
||||
continue;
|
||||
}
|
||||
if (has_conflict)
|
||||
break;
|
||||
if (s.is_trivial(*src))
|
||||
continue;
|
||||
unsigned v = src->poly().var();
|
||||
equation_vector const& uses = use_list[v];
|
||||
TRACE("dd.solver",
|
||||
s.display(tout << "uses of: ", *src) << "\n";
|
||||
for (equation* e : uses) {
|
||||
s.display(tout, *e) << "\n";
|
||||
});
|
||||
for (equation* e : uses) s.display(tout, *e) << "\n";);
|
||||
bool changed_leading_term;
|
||||
bool all_reduced = true;
|
||||
for (equation* dst : uses) {
|
||||
if (src == dst || s.is_trivial(*dst)) {
|
||||
continue;
|
||||
}
|
||||
if (src == dst || s.is_trivial(*dst))
|
||||
continue;
|
||||
pdd q = dst->poly();
|
||||
if (!src->poly().is_binary() && !q.is_linear()) {
|
||||
all_reduced = false;
|
||||
|
@ -142,9 +147,8 @@ namespace dd {
|
|||
}
|
||||
remove_from_use(dst, use_list, v);
|
||||
s.simplify_using(*dst, *src, changed_leading_term);
|
||||
if (s.is_trivial(*dst)) {
|
||||
trivial.push_back(dst);
|
||||
}
|
||||
if (s.is_trivial(*dst))
|
||||
trivial.elems.push_back(dst);
|
||||
else if (s.is_conflict(dst)) {
|
||||
s.pop_equation(dst);
|
||||
s.set_conflict(dst);
|
||||
|
@ -158,9 +162,8 @@ namespace dd {
|
|||
// SASSERT(!dst->poly().free_vars().contains(v));
|
||||
add_to_use(dst, use_list);
|
||||
}
|
||||
if (all_reduced) {
|
||||
linear[j++] = src;
|
||||
}
|
||||
if (all_reduced)
|
||||
linear[j++] = src;
|
||||
}
|
||||
if (!has_conflict) {
|
||||
linear.shrink(j);
|
||||
|
@ -169,9 +172,7 @@ namespace dd {
|
|||
s.push_equation(solver::solved, src);
|
||||
}
|
||||
}
|
||||
for (equation* e : trivial) {
|
||||
s.del_equation(e);
|
||||
}
|
||||
|
||||
DEBUG_CODE(s.invariant(););
|
||||
return j > 0 || has_conflict;
|
||||
}
|
||||
|
@ -184,11 +185,12 @@ namespace dd {
|
|||
*/
|
||||
bool simplifier::simplify_cc_step() {
|
||||
TRACE("dd.solver", tout << "cc\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "cc\n");
|
||||
IF_VERBOSE(3, verbose_stream() << "cc\n");
|
||||
u_map<equation*> los;
|
||||
bool reduced = false;
|
||||
unsigned j = 0;
|
||||
for (equation* eq1 : s.m_to_simplify) {
|
||||
solver::scoped_update sc(s.m_to_simplify);
|
||||
for (; sc.i < sc.sz; ++sc.i) {
|
||||
auto* eq1 = sc.get();
|
||||
SASSERT(eq1->state() == solver::to_simplify);
|
||||
pdd p = eq1->poly();
|
||||
equation* eq2 = los.insert_if_not_there(p.lo().index(), eq1);
|
||||
|
@ -201,14 +203,11 @@ namespace dd {
|
|||
s.retire(eq1);
|
||||
continue;
|
||||
}
|
||||
else if (s.check_conflict(*eq1)) {
|
||||
continue;
|
||||
}
|
||||
else if (s.check_conflict(*eq1))
|
||||
continue;
|
||||
}
|
||||
s.m_to_simplify[j] = eq1;
|
||||
eq1->set_index(j++);
|
||||
sc.nextj();
|
||||
}
|
||||
s.m_to_simplify.shrink(j);
|
||||
return reduced;
|
||||
}
|
||||
|
||||
|
@ -217,7 +216,7 @@ namespace dd {
|
|||
*/
|
||||
bool simplifier::simplify_leaf_step() {
|
||||
TRACE("dd.solver", tout << "leaf\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "leaf\n");
|
||||
IF_VERBOSE(3, verbose_stream() << "leaf\n");
|
||||
use_list_t use_list = get_use_list();
|
||||
equation_vector leaves;
|
||||
for (unsigned i = 0; i < s.m_to_simplify.size(); ++i) {
|
||||
|
@ -225,15 +224,12 @@ namespace dd {
|
|||
pdd p = e->poly();
|
||||
if (p.is_val())
|
||||
continue;
|
||||
if (!p.hi().is_val()) {
|
||||
continue;
|
||||
}
|
||||
if (!p.hi().is_val())
|
||||
continue;
|
||||
leaves.reset();
|
||||
for (equation* e2 : use_list[p.var()]) {
|
||||
if (e != e2 && e2->poly().var_is_leaf(p.var())) {
|
||||
leaves.push_back(e2);
|
||||
}
|
||||
}
|
||||
for (equation* e2 : use_list[p.var()])
|
||||
if (e != e2 && e2->poly().var_is_leaf(p.var()))
|
||||
leaves.push_back(e2);
|
||||
for (equation* e2 : leaves) {
|
||||
bool changed_leading_term;
|
||||
remove_from_use(e2, use_list);
|
||||
|
@ -262,24 +258,21 @@ namespace dd {
|
|||
*/
|
||||
bool simplifier::simplify_elim_pure_step() {
|
||||
TRACE("dd.solver", tout << "pure\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "pure\n");
|
||||
use_list_t use_list = get_use_list();
|
||||
unsigned j = 0;
|
||||
for (equation* e : s.m_to_simplify) {
|
||||
IF_VERBOSE(3, verbose_stream() << "pure\n");
|
||||
use_list_t use_list = get_use_list();
|
||||
solver::scoped_update sc(s.m_to_simplify);
|
||||
bool has_solved = false;
|
||||
for (; sc.i < sc.sz; ++sc.i) {
|
||||
equation* e = sc.get();
|
||||
pdd p = e->poly();
|
||||
if (!p.is_val() && p.hi().is_val() && use_list[p.var()].size() == 1) {
|
||||
s.push_equation(solver::solved, e);
|
||||
has_solved = true;
|
||||
}
|
||||
else {
|
||||
s.m_to_simplify[j] = e;
|
||||
e->set_index(j++);
|
||||
}
|
||||
else
|
||||
sc.nextj();
|
||||
}
|
||||
if (j != s.m_to_simplify.size()) {
|
||||
s.m_to_simplify.shrink(j);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return has_solved;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -288,63 +281,59 @@ namespace dd {
|
|||
*/
|
||||
bool simplifier::simplify_elim_dual_step() {
|
||||
use_list_t use_list = get_use_list();
|
||||
unsigned j = 0;
|
||||
bool reduced = false;
|
||||
for (unsigned i = 0; i < s.m_to_simplify.size(); ++i) {
|
||||
equation* e = s.m_to_simplify[i];
|
||||
pdd p = e->poly();
|
||||
// check that e is linear in top variable.
|
||||
if (e->state() != solver::to_simplify) {
|
||||
reduced = true;
|
||||
}
|
||||
else if (!s.done() && !s.is_trivial(*e) && p.hi().is_val() && use_list[p.var()].size() == 2) {
|
||||
for (equation* e2 : use_list[p.var()]) {
|
||||
if (e2 == e) continue;
|
||||
bool changed_leading_term;
|
||||
|
||||
remove_from_use(e2, use_list);
|
||||
s.simplify_using(*e2, *e, changed_leading_term);
|
||||
if (s.is_conflict(e2)) {
|
||||
s.pop_equation(e2);
|
||||
s.set_conflict(e2);
|
||||
}
|
||||
// when e2 is trivial, leading term is changed
|
||||
SASSERT(!s.is_trivial(*e2) || changed_leading_term);
|
||||
if (changed_leading_term) {
|
||||
s.pop_equation(e2);
|
||||
s.push_equation(solver::to_simplify, e2);
|
||||
}
|
||||
add_to_use(e2, use_list);
|
||||
break;
|
||||
{
|
||||
solver::scoped_update sc(s.m_to_simplify);
|
||||
for (; sc.i < sc.sz; ++sc.i) {
|
||||
equation* e = sc.get();
|
||||
pdd p = e->poly();
|
||||
// check that e is linear in top variable.
|
||||
if (e->state() != solver::to_simplify) {
|
||||
reduced = true;
|
||||
}
|
||||
reduced = true;
|
||||
s.push_equation(solver::solved, e);
|
||||
}
|
||||
else {
|
||||
s.m_to_simplify[j] = e;
|
||||
e->set_index(j++);
|
||||
else if (!s.done() && !s.is_trivial(*e) && p.hi().is_val() && use_list[p.var()].size() == 2) {
|
||||
for (equation* e2 : use_list[p.var()]) {
|
||||
if (e2 == e)
|
||||
continue;
|
||||
bool changed_leading_term;
|
||||
|
||||
remove_from_use(e2, use_list);
|
||||
s.simplify_using(*e2, *e, changed_leading_term);
|
||||
if (s.is_conflict(e2)) {
|
||||
s.pop_equation(e2);
|
||||
s.set_conflict(e2);
|
||||
}
|
||||
// when e2 is trivial, leading term is changed
|
||||
SASSERT(!s.is_trivial(*e2) || changed_leading_term);
|
||||
if (changed_leading_term) {
|
||||
s.pop_equation(e2);
|
||||
s.push_equation(solver::to_simplify, e2);
|
||||
}
|
||||
add_to_use(e2, use_list);
|
||||
break;
|
||||
}
|
||||
reduced = true;
|
||||
s.push_equation(solver::solved, e);
|
||||
}
|
||||
else
|
||||
sc.nextj();
|
||||
}
|
||||
}
|
||||
if (reduced) {
|
||||
// clean up elements in s.m_to_simplify
|
||||
// they may have moved.
|
||||
s.m_to_simplify.shrink(j);
|
||||
j = 0;
|
||||
for (equation* e : s.m_to_simplify) {
|
||||
if (s.is_trivial(*e)) {
|
||||
s.retire(e);
|
||||
}
|
||||
else if (e->state() == solver::to_simplify) {
|
||||
s.m_to_simplify[j] = e;
|
||||
e->set_index(j++);
|
||||
}
|
||||
solver::scoped_update sc(s.m_to_simplify);
|
||||
for (; sc.i < sc.sz; ++sc.i) {
|
||||
equation* e = sc.get();
|
||||
if (s.is_trivial(*e))
|
||||
s.retire(e);
|
||||
else if (e->state() == solver::to_simplify)
|
||||
sc.nextj();
|
||||
}
|
||||
s.m_to_simplify.shrink(j);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void simplifier::add_to_use(equation* e, use_list_t& use_list) {
|
||||
|
|
|
@ -59,9 +59,10 @@ namespace dd {
|
|||
|
||||
*/
|
||||
|
||||
solver::solver(reslimit& lim, pdd_manager& m) :
|
||||
solver::solver(reslimit& lim, u_dependency_manager& dm, pdd_manager& m) :
|
||||
m(m),
|
||||
m_limit(lim)
|
||||
m_limit(lim),
|
||||
m_dep_manager(dm)
|
||||
{}
|
||||
|
||||
solver::~solver() {
|
||||
|
@ -89,11 +90,9 @@ namespace dd {
|
|||
|
||||
}
|
||||
void solver::saturate() {
|
||||
simplify();
|
||||
if (done()) {
|
||||
return;
|
||||
}
|
||||
init_saturate();
|
||||
if (done())
|
||||
return;
|
||||
init_saturate();
|
||||
TRACE("dd.solver", display(tout););
|
||||
try {
|
||||
while (!done() && step()) {
|
||||
|
@ -104,7 +103,7 @@ namespace dd {
|
|||
DEBUG_CODE(invariant(););
|
||||
}
|
||||
catch (pdd_manager::mem_out) {
|
||||
IF_VERBOSE(2, verbose_stream() << "mem-out\n");
|
||||
IF_VERBOSE(1, verbose_stream() << "mem-out saturate\n");
|
||||
// don't reduce further
|
||||
}
|
||||
}
|
||||
|
@ -123,8 +122,7 @@ namespace dd {
|
|||
|
||||
solver::scoped_process::~scoped_process() {
|
||||
if (e) {
|
||||
pdd p = e->poly();
|
||||
SASSERT(!p.is_val());
|
||||
SASSERT(!e->poly().is_val());
|
||||
g.push_equation(processed, e);
|
||||
}
|
||||
}
|
||||
|
@ -136,9 +134,8 @@ namespace dd {
|
|||
|
||||
|
||||
void solver::superpose(equation const & eq) {
|
||||
for (equation* target : m_processed) {
|
||||
superpose(eq, *target);
|
||||
}
|
||||
for (equation* target : m_processed)
|
||||
superpose(eq, *target);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -165,32 +162,28 @@ namespace dd {
|
|||
TRACE("dd.solver", display(tout << "simplification result: ", eq););
|
||||
}
|
||||
|
||||
void solver::well_formed() {
|
||||
auto& set = m_to_simplify;
|
||||
for (unsigned k = 0; k < set.size(); ++k)
|
||||
for (unsigned l = k + 1; l < set.size(); ++l) {
|
||||
if (!set[l] || !set[k] || set[k] != set[l])
|
||||
continue;
|
||||
verbose_stream() << k << " " << l << " " << set[k] << "\n";
|
||||
for (auto* s : set)
|
||||
verbose_stream() << s->idx() << "\n";
|
||||
VERIFY(set[k] != set[l]);
|
||||
}
|
||||
}
|
||||
/*
|
||||
Use the given equation to simplify equations in set
|
||||
*/
|
||||
void solver::simplify_using(equation_vector& set, std::function<bool(equation&, bool&)>& simplifier) {
|
||||
struct scoped_update {
|
||||
equation_vector& set;
|
||||
unsigned i, j, sz;
|
||||
scoped_update(equation_vector& set): set(set), i(0), j(0), sz(set.size()) {}
|
||||
void nextj() {
|
||||
set[j] = set[i];
|
||||
set[i]->set_index(j++);
|
||||
}
|
||||
~scoped_update() {
|
||||
for (; i < sz; ++i)
|
||||
nextj();
|
||||
set.shrink(j);
|
||||
}
|
||||
};
|
||||
|
||||
void solver::simplify_using(equation_vector& set, std::function<bool(equation&, bool&)>& simplifier) {
|
||||
scoped_update sr(set);
|
||||
for (; sr.i < sr.sz; ++sr.i) {
|
||||
equation& target = *set[sr.i];
|
||||
bool changed_leading_term = false;
|
||||
bool simplified = true;
|
||||
simplified = !done() && simplifier(target, changed_leading_term);
|
||||
|
||||
|
||||
if (simplified && is_trivial(target))
|
||||
retire(&target);
|
||||
|
@ -285,21 +278,32 @@ namespace dd {
|
|||
m_stats.m_compute_steps++;
|
||||
IF_VERBOSE(3, if (m_stats.m_compute_steps % 100 == 0) verbose_stream() << "compute steps = " << m_stats.m_compute_steps << "\n";);
|
||||
equation* e = pick_next();
|
||||
if (!e) return false;
|
||||
if (!e)
|
||||
return false;
|
||||
scoped_process sd(*this, e);
|
||||
equation& eq = *e;
|
||||
SASSERT(eq.state() == to_simplify);
|
||||
simplify_using(eq, m_processed);
|
||||
if (is_trivial(eq)) { sd.e = nullptr; retire(e); return true; }
|
||||
if (check_conflict(eq)) { sd.e = nullptr; return false; }
|
||||
if (is_trivial(eq)) {
|
||||
sd.e = nullptr;
|
||||
retire(e);
|
||||
return true;
|
||||
}
|
||||
if (check_conflict(eq)) {
|
||||
sd.e = nullptr;
|
||||
return false;
|
||||
}
|
||||
m_too_complex = false;
|
||||
simplify_using(m_processed, eq);
|
||||
if (done()) return false;
|
||||
if (done())
|
||||
return false;
|
||||
TRACE("dd.solver", display(tout << "eq = ", eq););
|
||||
superpose(eq);
|
||||
simplify_using(m_to_simplify, eq);
|
||||
if (done()) return false;
|
||||
if (!m_too_complex) sd.done();
|
||||
if (done())
|
||||
return false;
|
||||
if (!m_too_complex)
|
||||
sd.done();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -344,9 +348,9 @@ namespace dd {
|
|||
}
|
||||
|
||||
void solver::reset() {
|
||||
for (equation* e : m_solved) dealloc(e);
|
||||
for (equation* e : m_to_simplify) dealloc(e);
|
||||
for (equation* e : m_processed) dealloc(e);
|
||||
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();
|
||||
|
@ -444,7 +448,6 @@ namespace dd {
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
void solver::pop_equation(equation& eq) {
|
||||
equation_vector& v = get_queue(eq);
|
||||
unsigned idx = eq.idx();
|
||||
|
|
|
@ -49,30 +49,17 @@ public:
|
|||
};
|
||||
|
||||
struct config {
|
||||
unsigned m_eqs_threshold;
|
||||
unsigned m_expr_size_limit;
|
||||
unsigned m_expr_degree_limit;
|
||||
unsigned m_max_steps;
|
||||
unsigned m_max_simplified;
|
||||
unsigned m_random_seed;
|
||||
bool m_enable_exlin;
|
||||
unsigned m_eqs_growth;
|
||||
unsigned m_expr_size_growth;
|
||||
unsigned m_expr_degree_growth;
|
||||
unsigned m_number_of_conflicts_to_report;
|
||||
config() :
|
||||
m_eqs_threshold(UINT_MAX),
|
||||
m_expr_size_limit(UINT_MAX),
|
||||
m_expr_degree_limit(UINT_MAX),
|
||||
m_max_steps(UINT_MAX),
|
||||
m_max_simplified(UINT_MAX),
|
||||
m_random_seed(0),
|
||||
m_enable_exlin(false),
|
||||
m_eqs_growth(10),
|
||||
m_expr_size_growth(10),
|
||||
m_expr_degree_growth(5),
|
||||
m_number_of_conflicts_to_report(1)
|
||||
{}
|
||||
unsigned m_eqs_threshold = UINT_MAX;
|
||||
unsigned m_expr_size_limit = UINT_MAX;
|
||||
unsigned m_expr_degree_limit = UINT_MAX;
|
||||
unsigned m_max_steps = UINT_MAX;
|
||||
unsigned m_max_simplified = UINT_MAX;
|
||||
unsigned m_random_seed = 0;
|
||||
bool m_enable_exlin = false;
|
||||
unsigned m_eqs_growth = 10;
|
||||
unsigned m_expr_size_growth = 10;
|
||||
unsigned m_expr_degree_growth = 5;
|
||||
unsigned m_number_of_conflicts_to_report = 1;
|
||||
};
|
||||
|
||||
enum eq_state {
|
||||
|
@ -82,18 +69,14 @@ public:
|
|||
};
|
||||
|
||||
class equation {
|
||||
eq_state m_state;
|
||||
unsigned m_idx; //!< unique index
|
||||
eq_state m_state = to_simplify;
|
||||
unsigned m_idx = 0; //!< unique index
|
||||
pdd m_poly; //!< polynomial in pdd form
|
||||
u_dependency * m_dep; //!< justification for the equality
|
||||
public:
|
||||
equation(pdd const& p, u_dependency* d):
|
||||
m_state(to_simplify),
|
||||
m_idx(0),
|
||||
m_poly(p),
|
||||
m_dep(d)
|
||||
{
|
||||
|
||||
m_dep(d) {
|
||||
}
|
||||
|
||||
const pdd& poly() const { return m_poly; }
|
||||
|
@ -105,13 +88,38 @@ public:
|
|||
void set_state(eq_state st) { m_state = st; }
|
||||
void set_index(unsigned idx) { m_idx = idx; }
|
||||
};
|
||||
private:
|
||||
|
||||
typedef ptr_vector<equation> equation_vector;
|
||||
|
||||
struct scoped_update {
|
||||
equation_vector& set;
|
||||
unsigned i = 0;
|
||||
unsigned j = 0;
|
||||
unsigned sz;
|
||||
scoped_update(equation_vector& set) :
|
||||
set(set), sz(set.size()) {
|
||||
}
|
||||
~scoped_update() {
|
||||
for (; i < sz; ++i)
|
||||
nextj();
|
||||
set.shrink(j);
|
||||
}
|
||||
equation* get() { return set[i]; }
|
||||
|
||||
void nextj() {
|
||||
set[j] = set[i];
|
||||
set[i]->set_index(j++);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
|
||||
typedef std::function<void (u_dependency* d, std::ostream& out)> print_dep_t;
|
||||
|
||||
pdd_manager& m;
|
||||
reslimit& m_limit;
|
||||
u_dependency_manager& m_dep_manager;
|
||||
stats m_stats;
|
||||
config m_config;
|
||||
print_dep_t m_print_dep;
|
||||
|
@ -119,12 +127,11 @@ private:
|
|||
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 = nullptr;
|
||||
bool m_too_complex;
|
||||
public:
|
||||
solver(reslimit& lim, pdd_manager& m);
|
||||
solver(reslimit& lim, u_dependency_manager& dm, pdd_manager& m);
|
||||
~solver();
|
||||
|
||||
pdd_manager& get_manager() { return m; }
|
||||
|
@ -144,7 +151,6 @@ public:
|
|||
void saturate();
|
||||
|
||||
equation_vector const& equations();
|
||||
u_dependency_manager& dep() const { return m_dep_manager; }
|
||||
|
||||
void collect_statistics(statistics & st) const;
|
||||
std::ostream& display(std::ostream& out, const equation& eq) const;
|
||||
|
@ -192,6 +198,7 @@ private:
|
|||
void push_equation(eq_state st, equation& eq);
|
||||
void push_equation(eq_state st, equation* eq) { push_equation(st, *eq); }
|
||||
|
||||
void well_formed();
|
||||
void invariant() const;
|
||||
struct scoped_process {
|
||||
solver& g;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "math/interval/interval.h"
|
||||
|
||||
class dep_intervals {
|
||||
|
||||
public:
|
||||
enum with_deps_t { with_deps, without_deps };
|
||||
|
||||
|
@ -142,8 +143,9 @@ private:
|
|||
public:
|
||||
typedef interval_manager<im_config>::interval interval;
|
||||
|
||||
u_dependency_manager& m_dep_manager;
|
||||
mutable unsynch_mpq_manager m_num_manager;
|
||||
mutable u_dependency_manager m_dep_manager;
|
||||
|
||||
im_config m_config;
|
||||
mutable interval_manager<im_config> m_imanager;
|
||||
|
||||
|
@ -158,9 +160,10 @@ public:
|
|||
public:
|
||||
u_dependency_manager& dep_manager() { return m_dep_manager; }
|
||||
|
||||
dep_intervals(reslimit& lim) :
|
||||
m_config(m_num_manager, m_dep_manager),
|
||||
m_imanager(lim, im_config(m_num_manager, m_dep_manager))
|
||||
dep_intervals(u_dependency_manager& dm, reslimit& lim) :
|
||||
m_dep_manager(dm),
|
||||
m_config(m_num_manager, dm),
|
||||
m_imanager(lim, im_config(m_num_manager, dm))
|
||||
{}
|
||||
|
||||
std::ostream& display(std::ostream& out, const interval& i) const;
|
||||
|
@ -172,6 +175,8 @@ public:
|
|||
void set_upper_is_inf(interval& a, bool inf) const { m_config.set_upper_is_inf(a, inf); }
|
||||
void set_lower_dep(interval& a, u_dependency* d) const { m_config.set_lower_dep(a, d); }
|
||||
void set_upper_dep(interval& a, u_dependency* d) const { m_config.set_upper_dep(a, d); }
|
||||
u_dependency* get_lower_dep(interval const& a) const { return a.m_lower_dep; }
|
||||
u_dependency* get_upper_dep(interval const& a) const { return a.m_upper_dep; }
|
||||
void reset(interval& a) const { set_lower_is_inf(a, true); set_upper_is_inf(a, true); }
|
||||
void set_value(interval& a, rational const& n) const {
|
||||
set_lower(a, n);
|
||||
|
@ -335,15 +340,17 @@ public:
|
|||
|
||||
bool is_empty(interval const& a) const;
|
||||
void set_interval_for_scalar(interval&, const rational&);
|
||||
|
||||
template <typename T>
|
||||
void linearize(u_dependency* dep, T& expl) const {
|
||||
vector<unsigned, false> v;
|
||||
m_dep_manager.linearize(dep, v);
|
||||
for (unsigned ci: v)
|
||||
for (auto ci: v)
|
||||
expl.push_back(ci);
|
||||
}
|
||||
|
||||
void reset() { m_dep_manager.reset(); }
|
||||
|
||||
void reset() { }
|
||||
|
||||
void del(interval& i) { m_imanager.del(i); }
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 0
|
||||
NamespaceIndentation: All
|
||||
NamespaceIndentation: All
|
||||
BreakBeforeBraces: Stroustrup
|
|
@ -19,7 +19,6 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
|
||||
#include "util/vector.h"
|
||||
|
@ -27,6 +26,8 @@ Revision History:
|
|||
#include "math/lp/test_bound_analyzer.h"
|
||||
|
||||
namespace lp {
|
||||
|
||||
|
||||
template <typename C, typename B> // C plays a role of a container, B - lp_bound_propagator
|
||||
class bound_analyzer_on_row {
|
||||
const C& m_row;
|
||||
|
@ -92,39 +93,17 @@ private:
|
|||
}
|
||||
|
||||
bool bound_is_available(unsigned j, bool lower_bound) {
|
||||
return (lower_bound && lower_bound_is_available(j)) ||
|
||||
(!lower_bound && upper_bound_is_available(j));
|
||||
}
|
||||
|
||||
bool upper_bound_is_available(unsigned j) const {
|
||||
switch (m_bp.get_column_type(j)) {
|
||||
case column_type::fixed:
|
||||
case column_type::boxed:
|
||||
case column_type::upper_bound:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool lower_bound_is_available(unsigned j) const {
|
||||
switch (m_bp.get_column_type(j)) {
|
||||
case column_type::fixed:
|
||||
case column_type::boxed:
|
||||
case column_type::lower_bound:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return (lower_bound && m_bp.lower_bound_is_available(j)) ||
|
||||
(!lower_bound && m_bp.upper_bound_is_available(j));
|
||||
}
|
||||
|
||||
const impq & ub(unsigned j) const {
|
||||
lp_assert(upper_bound_is_available(j));
|
||||
lp_assert(m_bp.upper_bound_is_available(j));
|
||||
return m_bp.get_upper_bound(j);
|
||||
}
|
||||
|
||||
const impq & lb(unsigned j) const {
|
||||
lp_assert(lower_bound_is_available(j));
|
||||
lp_assert(m_bp.lower_bound_is_available(j));
|
||||
return m_bp.get_lower_bound(j);
|
||||
}
|
||||
|
||||
|
@ -302,10 +281,33 @@ private:
|
|||
// */
|
||||
// }
|
||||
|
||||
void limit_j(unsigned j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){
|
||||
m_bp.try_add_bound(u, j, is_lower_bound, coeff_before_j_is_pos, m_row_index, strict);
|
||||
void limit_j(unsigned bound_j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict)
|
||||
{
|
||||
unsigned row_index = this->m_row_index;
|
||||
auto* lar = &m_bp.lp();
|
||||
auto explain = [bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index, lar]() {
|
||||
(void) strict;
|
||||
TRACE("bound_analyzer", tout << "explain_bound_on_var_on_coeff, bound_j = " << bound_j << ", coeff_before_j_is_pos = " << coeff_before_j_is_pos << ", is_lower_bound = " << is_lower_bound << ", strict = " << strict << ", row_index = " << row_index << "\n";);
|
||||
int bound_sign = (is_lower_bound ? 1 : -1);
|
||||
int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign;
|
||||
|
||||
SASSERT(!tv::is_term(bound_j));
|
||||
u_dependency* ret = nullptr;
|
||||
for (auto const& r : lar->get_row(row_index)) {
|
||||
unsigned j = r.var();
|
||||
if (j == bound_j)
|
||||
continue;
|
||||
mpq const& a = r.coeff();
|
||||
int a_sign = is_pos(a) ? 1 : -1;
|
||||
int sign = j_sign * a_sign;
|
||||
u_dependency* witness = sign > 0 ? lar->get_column_upper_bound_witness(j) : lar->get_column_lower_bound_witness(j);
|
||||
ret = lar->join_deps(ret, witness);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
m_bp.add_bound(u, bound_j, is_lower_bound, strict, explain);
|
||||
}
|
||||
|
||||
|
||||
void advance_u(unsigned j) {
|
||||
m_column_of_u = (m_column_of_u == -1) ? j : -2;
|
||||
}
|
||||
|
@ -336,6 +338,9 @@ private:
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue