mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 17:45:32 +00:00
Merge branch 'master' of https://github.com/Z3Prover/z3 into new-ml-api
This commit is contained in:
commit
b178420797
174 changed files with 9762 additions and 2502 deletions
|
@ -38,6 +38,7 @@ public:
|
|||
tactic_report report("ackermannize", *g);
|
||||
fail_if_unsat_core_generation("ackermannize", g);
|
||||
fail_if_proof_generation("ackermannize", g);
|
||||
TRACE("ackermannize", g->display(tout << "in\n"););
|
||||
|
||||
expr_ref_vector flas(m);
|
||||
const unsigned sz = g->size();
|
||||
|
@ -48,6 +49,7 @@ public:
|
|||
goal_ref resg(alloc(goal, *g, true));
|
||||
const bool success = lackr.mk_ackermann(resg, m_lemma_limit);
|
||||
if (!success) { // Just pass on the input unchanged
|
||||
TRACE("ackermannize", tout << "ackermannize not run due to limit" << std::endl;);
|
||||
result.reset();
|
||||
result.push_back(g.get());
|
||||
mc = 0;
|
||||
|
@ -62,7 +64,7 @@ public:
|
|||
}
|
||||
|
||||
resg->inc_depth();
|
||||
TRACE("ackermannize", resg->display(tout););
|
||||
TRACE("ackermannize", resg->display(tout << "out\n"););
|
||||
SASSERT(resg->is_well_sorted());
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ lackr::~lackr() {
|
|||
|
||||
lbool lackr::operator() () {
|
||||
SASSERT(m_sat);
|
||||
init();
|
||||
if (!init()) return l_undef;
|
||||
const lbool rv = m_eager ? eager() : lazy();
|
||||
if (rv == l_true) m_sat->get_model(m_model);
|
||||
CTRACE("lackr", rv == l_true,
|
||||
|
@ -63,7 +63,7 @@ lbool lackr::operator() () {
|
|||
|
||||
bool lackr::mk_ackermann(/*out*/goal_ref& g, double lemmas_upper_bound) {
|
||||
if (lemmas_upper_bound <= 0) return false;
|
||||
init();
|
||||
if (!init()) return false;
|
||||
if (lemmas_upper_bound != std::numeric_limits<double>::infinity()) {
|
||||
const double lemmas_bound = ackr_helper::calculate_lemma_bound(m_fun2terms);
|
||||
if (lemmas_bound > lemmas_upper_bound) return false;
|
||||
|
@ -74,14 +74,15 @@ bool lackr::mk_ackermann(/*out*/goal_ref& g, double lemmas_upper_bound) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void lackr::init() {
|
||||
SASSERT(!m_is_init);
|
||||
m_is_init = true;
|
||||
bool lackr::init() {
|
||||
SASSERT(!m_is_init);
|
||||
params_ref simp_p(m_p);
|
||||
m_simp.updt_params(simp_p);
|
||||
m_info = alloc(ackr_info, m_m);
|
||||
collect_terms();
|
||||
if (!collect_terms()) return false;
|
||||
abstract();
|
||||
m_is_init = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -96,10 +97,8 @@ bool lackr::ackr(app * const t1, app * const t2) {
|
|||
for (unsigned i = 0; i < sz; ++i) {
|
||||
expr * const arg1 = t1->get_arg(i);
|
||||
expr * const arg2 = t2->get_arg(i);
|
||||
if (arg1 == arg2) continue; // quickly skip syntactically equal
|
||||
if (m_ackr_helper.bvutil().is_numeral(arg1) && m_ackr_helper.bvutil().is_numeral(arg2)) {
|
||||
// quickly abort if there are two distinct numerals
|
||||
SASSERT(arg1 != arg2);
|
||||
if (m_m.are_equal(arg1, arg2)) continue; // quickly skip syntactically equal
|
||||
if (m_m.are_distinct(arg1, arg2)){ // quickly abort if there are two distinct (e.g. numerals)
|
||||
TRACE("lackr", tout << "never eq\n";);
|
||||
return false;
|
||||
}
|
||||
|
@ -110,7 +109,8 @@ bool lackr::ackr(app * const t1, app * const t2) {
|
|||
SASSERT(a1 && a2);
|
||||
TRACE("lackr", tout << "abstr1 " << mk_ismt2_pp(a1, m_m, 2) << "\n";);
|
||||
TRACE("lackr", tout << "abstr2 " << mk_ismt2_pp(a2, m_m, 2) << "\n";);
|
||||
expr_ref lhs(m_m.mk_and(eqs.size(), eqs.c_ptr()), m_m);
|
||||
expr_ref lhs(m_m);
|
||||
lhs = (eqs.size() == 1) ? eqs.get(0) : m_m.mk_and(eqs.size(), eqs.c_ptr());
|
||||
TRACE("lackr", tout << "ackr constr lhs" << mk_ismt2_pp(lhs, m_m, 2) << "\n";);
|
||||
expr_ref rhs(m_m.mk_eq(a1, a2),m_m);
|
||||
TRACE("lackr", tout << "ackr constr rhs" << mk_ismt2_pp(rhs, m_m, 2) << "\n";);
|
||||
|
@ -203,6 +203,7 @@ void lackr::push_abstraction() {
|
|||
}
|
||||
|
||||
lbool lackr::eager() {
|
||||
SASSERT(m_is_init);
|
||||
push_abstraction();
|
||||
TRACE("lackr", tout << "run sat 0\n"; );
|
||||
const lbool rv0 = m_sat->check_sat(0, 0);
|
||||
|
@ -217,6 +218,7 @@ lbool lackr::eager() {
|
|||
}
|
||||
|
||||
lbool lackr::lazy() {
|
||||
SASSERT(m_is_init);
|
||||
lackr_model_constructor mc(m_m, m_info);
|
||||
push_abstraction();
|
||||
unsigned ackr_head = 0;
|
||||
|
@ -247,7 +249,7 @@ lbool lackr::lazy() {
|
|||
//
|
||||
// Collect all uninterpreted terms, skipping 0-arity.
|
||||
//
|
||||
void lackr::collect_terms() {
|
||||
bool lackr::collect_terms() {
|
||||
ptr_vector<expr> stack;
|
||||
expr * curr;
|
||||
expr_mark visited;
|
||||
|
@ -279,12 +281,11 @@ void lackr::collect_terms() {
|
|||
}
|
||||
break;
|
||||
case AST_QUANTIFIER:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
return false; // quantifiers not supported
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
visited.reset();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ class lackr {
|
|||
lackr_stats& m_st;
|
||||
bool m_is_init;
|
||||
|
||||
void init();
|
||||
bool init();
|
||||
lbool eager();
|
||||
lbool lazy();
|
||||
|
||||
|
@ -118,6 +118,6 @@ class lackr {
|
|||
//
|
||||
// Collect all uninterpreted terms, skipping 0-arity.
|
||||
//
|
||||
void collect_terms();
|
||||
bool collect_terms();
|
||||
};
|
||||
#endif /* LACKR_H_ */
|
||||
|
|
|
@ -34,11 +34,13 @@ struct lackr_model_constructor::imp {
|
|||
, m_conflicts(conflicts)
|
||||
, m_b_rw(m)
|
||||
, m_bv_rw(m)
|
||||
, m_evaluator(NULL)
|
||||
, m_empty_model(m)
|
||||
, m_ackr_helper(m)
|
||||
{}
|
||||
|
||||
~imp() {
|
||||
if (m_evaluator) dealloc(m_evaluator);
|
||||
{
|
||||
values2val_t::iterator i = m_values2val.begin();
|
||||
const values2val_t::iterator e = m_values2val.end();
|
||||
|
@ -60,15 +62,17 @@ struct lackr_model_constructor::imp {
|
|||
|
||||
//
|
||||
// Returns true iff model was successfully constructed.
|
||||
// Conflicts are saved as a side effect.
|
||||
//
|
||||
bool check() {
|
||||
bool retv = true;
|
||||
for (unsigned i = 0; i < m_abstr_model->get_num_constants(); i++) {
|
||||
func_decl * const c = m_abstr_model->get_constant(i);
|
||||
app * const term = m_info->find_term(c);
|
||||
if (term) m_stack.push_back(term);
|
||||
else m_stack.push_back(m_m.mk_const(c));
|
||||
app * const _term = m_info->find_term(c);
|
||||
expr * const term = _term ? _term : m_m.mk_const(c);
|
||||
if (!check_term(term)) retv = false;
|
||||
}
|
||||
return run();
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,7 +138,7 @@ struct lackr_model_constructor::imp {
|
|||
conflict_list& m_conflicts;
|
||||
bool_rewriter m_b_rw;
|
||||
bv_rewriter m_bv_rw;
|
||||
scoped_ptr<model_evaluator> m_evaluator;
|
||||
model_evaluator * m_evaluator;
|
||||
model m_empty_model;
|
||||
private:
|
||||
struct val_info { expr * value; app * source_term; };
|
||||
|
@ -144,6 +148,7 @@ struct lackr_model_constructor::imp {
|
|||
app2val_t m_app2val;
|
||||
ptr_vector<expr> m_stack;
|
||||
ackr_helper m_ackr_helper;
|
||||
expr_mark m_visited;
|
||||
|
||||
static inline val_info mk_val_info(expr* value, app* source_term) {
|
||||
val_info rv;
|
||||
|
@ -152,17 +157,23 @@ struct lackr_model_constructor::imp {
|
|||
return rv;
|
||||
}
|
||||
|
||||
//
|
||||
// Performs congruence check on a given term.
|
||||
bool check_term(expr * term) {
|
||||
m_stack.push_back(term);
|
||||
const bool rv = _check_stack();
|
||||
m_stack.reset();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Performs congruence check on terms on the stack.
|
||||
// (Currently stops upon the first failure).
|
||||
// Returns true if and only if congruence check succeeded.
|
||||
bool run() {
|
||||
m_evaluator = alloc(model_evaluator, m_empty_model);
|
||||
expr_mark visited;
|
||||
// Stops upon the first failure.
|
||||
// Returns true if and only if all congruence checks succeeded.
|
||||
bool _check_stack() {
|
||||
if (m_evaluator == NULL) m_evaluator = alloc(model_evaluator, m_empty_model);
|
||||
expr * curr;
|
||||
while (!m_stack.empty()) {
|
||||
curr = m_stack.back();
|
||||
if (visited.is_marked(curr)) {
|
||||
if (m_visited.is_marked(curr)) {
|
||||
m_stack.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
@ -173,8 +184,8 @@ struct lackr_model_constructor::imp {
|
|||
return false;
|
||||
case AST_APP: {
|
||||
app * a = to_app(curr);
|
||||
if (for_each_expr_args(m_stack, visited, a->get_num_args(), a->get_args())) {
|
||||
visited.mark(a, true);
|
||||
if (for_each_expr_args(m_stack, m_visited, a->get_num_args(), a->get_args())) {
|
||||
m_visited.mark(a, true);
|
||||
m_stack.pop_back();
|
||||
if (!mk_value(a)) return false;
|
||||
}
|
||||
|
@ -212,7 +223,11 @@ struct lackr_model_constructor::imp {
|
|||
for (unsigned i = 0; i < num; ++i) {
|
||||
expr * val;
|
||||
const bool b = eval_cached(to_app(args[i]), val); // TODO: OK conversion to_app?
|
||||
CTRACE("model_constructor", !b, tout << "fail arg val(\n" << mk_ismt2_pp(args[i], m_m, 2); );
|
||||
CTRACE("model_constructor", m_conflicts.empty() && !b, tout << "fail arg val(\n" << mk_ismt2_pp(args[i], m_m, 2) << '\n'; );
|
||||
if (!b) {
|
||||
// bailing out because args eval failed previously
|
||||
return false;
|
||||
}
|
||||
TRACE("model_constructor", tout <<
|
||||
"arg val " << i << "(\n" << mk_ismt2_pp(args[i], m_m, 2)
|
||||
<< " : " << mk_ismt2_pp(val, m_m, 2) << '\n'; );
|
||||
|
|
|
@ -1129,7 +1129,7 @@ extern "C" {
|
|||
case Z3_OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX;
|
||||
case Z3_OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE;
|
||||
case Z3_OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE;
|
||||
|
||||
|
||||
case Z3_OP_RE_PLUS: return Z3_OP_RE_PLUS;
|
||||
case Z3_OP_RE_STAR: return Z3_OP_RE_STAR;
|
||||
case Z3_OP_RE_OPTION: return Z3_OP_RE_OPTION;
|
||||
|
@ -1186,9 +1186,14 @@ extern "C" {
|
|||
case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV;
|
||||
case OP_FPA_INTERNAL_BVWRAP:
|
||||
case OP_FPA_INTERNAL_BVUNWRAP:
|
||||
case OP_FPA_INTERNAL_MIN_I:
|
||||
case OP_FPA_INTERNAL_MAX_I:
|
||||
case OP_FPA_INTERNAL_MIN_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_MAX_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
|
||||
return Z3_OP_UNINTERPRETED;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -604,8 +604,16 @@ namespace z3 {
|
|||
|
||||
/**
|
||||
\brief Return true if this expression is a numeral.
|
||||
Specialized functions also return representations for the numerals as
|
||||
small integers, 64 bit integers or rational or decimal strings.
|
||||
*/
|
||||
bool is_numeral() const { return kind() == Z3_NUMERAL_AST; }
|
||||
bool is_numeral_i64(__int64& i) const { bool r = 0 != Z3_get_numeral_int64(ctx(), m_ast, &i); check_error(); return r;}
|
||||
bool is_numeral_u64(__uint64& i) const { bool r = 0 != Z3_get_numeral_uint64(ctx(), m_ast, &i); check_error(); return r;}
|
||||
bool is_numeral_i(int& i) const { bool r = 0 != Z3_get_numeral_int(ctx(), m_ast, &i); check_error(); return r;}
|
||||
bool is_numeral_u(unsigned& i) const { bool r = 0 != Z3_get_numeral_uint(ctx(), m_ast, &i); check_error(); return r;}
|
||||
bool is_numeral(std::string& s) const { if (!is_numeral()) return false; s = Z3_get_numeral_string(ctx(), m_ast); check_error(); return true; }
|
||||
bool is_numeral(std::string& s, unsigned precision) const { if (!is_numeral()) return false; s = Z3_get_numeral_decimal_string(ctx(), m_ast, precision); check_error(); return true; }
|
||||
/**
|
||||
\brief Return true if this expression is an application.
|
||||
*/
|
||||
|
@ -622,11 +630,86 @@ namespace z3 {
|
|||
\brief Return true if this expression is a variable.
|
||||
*/
|
||||
bool is_var() const { return kind() == Z3_VAR_AST; }
|
||||
/**
|
||||
\brief Return true if expression is an algebraic number.
|
||||
*/
|
||||
bool is_algebraic() const { return 0 != Z3_is_algebraic_number(ctx(), m_ast); }
|
||||
|
||||
/**
|
||||
\brief Return true if this expression is well sorted (aka type correct).
|
||||
*/
|
||||
bool is_well_sorted() const { bool r = Z3_is_well_sorted(ctx(), m_ast) != 0; check_error(); return r; }
|
||||
|
||||
/**
|
||||
\brief Return string representation of numeral or algebraic number
|
||||
This method assumes the expression is numeral or algebraic
|
||||
|
||||
\pre is_numeral() || is_algebraic()
|
||||
*/
|
||||
std::string get_decimal_string(int precision) const {
|
||||
assert(is_numeral() || is_algebraic());
|
||||
return std::string(Z3_get_numeral_decimal_string(ctx(), m_ast, precision));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return int value of numeral, throw if result cannot fit in
|
||||
machine int
|
||||
|
||||
\pre is_numeral()
|
||||
*/
|
||||
int get_numeral_int() const {
|
||||
int result;
|
||||
if (!is_numeral_i(result)) {
|
||||
throw exception("numeral does not fit in machine int");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return uint value of numeral, throw if result cannot fit in
|
||||
machine uint
|
||||
|
||||
\pre is_numeral()
|
||||
*/
|
||||
unsigned get_numeral_uint() const {
|
||||
assert(is_numeral());
|
||||
unsigned result;
|
||||
if (!is_numeral_u(result)) {
|
||||
throw exception("numeral does not fit in machine uint");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return __int64 value of numeral, throw if result cannot fit in
|
||||
__int64
|
||||
|
||||
\pre is_numeral()
|
||||
*/
|
||||
__int64 get_numeral_int64() const {
|
||||
assert(is_numeral());
|
||||
__int64 result;
|
||||
if (!is_numeral_i64(result)) {
|
||||
throw exception("numeral does not fit in machine __int64");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return __uint64 value of numeral, throw if result cannot fit in
|
||||
__uint64
|
||||
|
||||
\pre is_numeral()
|
||||
*/
|
||||
__uint64 get_numeral_uint64() const {
|
||||
assert(is_numeral());
|
||||
__uint64 result;
|
||||
if (!is_numeral_u64(result)) {
|
||||
throw exception("numeral does not fit in machine __uint64");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
operator Z3_app() const { assert(is_app()); return reinterpret_cast<Z3_app>(m_ast); }
|
||||
|
||||
|
|
|
@ -3940,7 +3940,7 @@ class ArraySortRef(SortRef):
|
|||
>>> A.range()
|
||||
Bool
|
||||
"""
|
||||
return _to_sort_ref(Z3_get_array_sort_range(self.ctx_ref(), self.ast), self.ctx)
|
||||
return _to_sort_ref(Z3_get_array_sort_range(self.ctx_ref(), self.ast), self.ctx)
|
||||
|
||||
class ArrayRef(ExprRef):
|
||||
"""Array expressions. """
|
||||
|
@ -4162,6 +4162,7 @@ def Select(a, i):
|
|||
_z3_assert(is_array(a), "First argument must be a Z3 array expression")
|
||||
return a[i]
|
||||
|
||||
|
||||
def Map(f, *args):
|
||||
"""Return a Z3 map array expression.
|
||||
|
||||
|
@ -8178,8 +8179,13 @@ class FPRef(ExprRef):
|
|||
return self
|
||||
|
||||
def __neg__(self):
|
||||
"""Create the Z3 expression `-self`."""
|
||||
return FPRef(fpNeg(self))
|
||||
"""Create the Z3 expression `-self`.
|
||||
|
||||
>>> x = FP('x', Float32())
|
||||
>>> -x
|
||||
-x
|
||||
"""
|
||||
return fpNeg(self)
|
||||
|
||||
def __div__(self, other):
|
||||
"""Create the Z3 expression `self / other`.
|
||||
|
|
|
@ -664,3 +664,45 @@ algebraic_numbers::anum const & arith_util::to_irrational_algebraic_numeral(expr
|
|||
SASSERT(is_irrational_algebraic_numeral(n));
|
||||
return plugin().aw().to_anum(to_app(n)->get_decl());
|
||||
}
|
||||
|
||||
expr_ref arith_util::mk_mul_simplify(expr_ref_vector const& args) {
|
||||
return mk_mul_simplify(args.size(), args.c_ptr());
|
||||
|
||||
}
|
||||
expr_ref arith_util::mk_mul_simplify(unsigned sz, expr* const* args) {
|
||||
expr_ref result(m_manager);
|
||||
|
||||
switch (sz) {
|
||||
case 0:
|
||||
result = mk_numeral(rational(1), true);
|
||||
break;
|
||||
case 1:
|
||||
result = args[0];
|
||||
break;
|
||||
default:
|
||||
result = mk_mul(sz, args);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref arith_util::mk_add_simplify(expr_ref_vector const& args) {
|
||||
return mk_add_simplify(args.size(), args.c_ptr());
|
||||
|
||||
}
|
||||
expr_ref arith_util::mk_add_simplify(unsigned sz, expr* const* args) {
|
||||
expr_ref result(m_manager);
|
||||
|
||||
switch (sz) {
|
||||
case 0:
|
||||
result = mk_numeral(rational(0), true);
|
||||
break;
|
||||
case 1:
|
||||
result = args[0];
|
||||
break;
|
||||
default:
|
||||
result = mk_add(sz, args);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -149,7 +149,6 @@ protected:
|
|||
func_decl * m_mod_0_decl;
|
||||
func_decl * m_u_asin_decl;
|
||||
func_decl * m_u_acos_decl;
|
||||
|
||||
ptr_vector<app> m_small_ints;
|
||||
ptr_vector<app> m_small_reals;
|
||||
|
||||
|
@ -416,6 +415,11 @@ public:
|
|||
return m_manager.mk_eq(lhs, rhs);
|
||||
}
|
||||
|
||||
expr_ref mk_mul_simplify(expr_ref_vector const& args);
|
||||
expr_ref mk_mul_simplify(unsigned sz, expr* const* args);
|
||||
|
||||
expr_ref mk_add_simplify(expr_ref_vector const& args);
|
||||
expr_ref mk_add_simplify(unsigned sz, expr* const* args);
|
||||
};
|
||||
|
||||
#endif /* ARITH_DECL_PLUGIN_H_ */
|
||||
|
|
|
@ -1560,6 +1560,9 @@ bool ast_manager::is_unique_value(expr* e) const {
|
|||
}
|
||||
|
||||
bool ast_manager::are_equal(expr * a, expr * b) const {
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
if (is_app(a) && is_app(b)) {
|
||||
app* ap = to_app(a), *bp = to_app(b);
|
||||
decl_plugin const * p = get_plugin(ap->get_family_id());
|
||||
|
|
|
@ -87,10 +87,10 @@ bool smt2_pp_environment::is_indexed_fdecl(func_decl * f) const {
|
|||
}
|
||||
|
||||
bool smt2_pp_environment::is_sort_param(func_decl * f) const {
|
||||
return
|
||||
return
|
||||
f->get_family_id() != null_family_id &&
|
||||
f->get_num_parameters() == 1 &&
|
||||
f->get_parameter(0).is_ast() &&
|
||||
f->get_num_parameters() == 1 &&
|
||||
f->get_parameter(0).is_ast() &&
|
||||
is_sort(f->get_parameter(0).get_ast()) &&
|
||||
f->get_range() == to_sort(f->get_parameter(0).get_ast());
|
||||
}
|
||||
|
@ -107,8 +107,8 @@ format * smt2_pp_environment::pp_fdecl_params(format * fname, func_decl * f) {
|
|||
ptr_buffer<format> fs;
|
||||
fs.push_back(fname);
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
SASSERT(f->get_parameter(i).is_int() ||
|
||||
f->get_parameter(i).is_rational() ||
|
||||
SASSERT(f->get_parameter(i).is_int() ||
|
||||
f->get_parameter(i).is_rational() ||
|
||||
(f->get_parameter(i).is_ast() && is_func_decl(f->get_parameter(i).get_ast())));
|
||||
if (f->get_parameter(i).is_int())
|
||||
fs.push_back(mk_int(get_manager(), f->get_parameter(i).get_int()));
|
||||
|
@ -122,7 +122,7 @@ format * smt2_pp_environment::pp_fdecl_params(format * fname, func_decl * f) {
|
|||
|
||||
format * smt2_pp_environment::pp_fdecl(func_decl * f, unsigned & len) {
|
||||
format * fname = pp_fdecl_name(f, len);
|
||||
if (f->get_family_id() == null_family_id)
|
||||
if (f->get_family_id() == null_family_id)
|
||||
return fname;
|
||||
if (is_sort_param(f)) {
|
||||
len = UINT_MAX;
|
||||
|
@ -247,7 +247,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u
|
|||
buf << "(_ -oo " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
|
||||
return mk_string(m, buf.c_str());
|
||||
}
|
||||
else if (fm.is_pzero(v)) {
|
||||
else if (fm.is_pzero(v)) {
|
||||
buf << "(_ +zero " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
|
||||
return mk_string(m, buf.c_str());
|
||||
}
|
||||
|
@ -257,9 +257,9 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u
|
|||
}
|
||||
else if (use_float_real_lits)
|
||||
{
|
||||
buf << "((_ to_fp " << v.get().get_ebits() << " " <<
|
||||
v.get().get_sbits() << ") RTZ " <<
|
||||
fm.to_string(v).c_str() << ")";
|
||||
buf << "((_ to_fp " << v.get().get_ebits() << " " <<
|
||||
v.get().get_sbits() << ") RTZ " <<
|
||||
fm.to_string(v).c_str() << ")";
|
||||
return mk_string(m, buf.c_str());
|
||||
}
|
||||
else {
|
||||
|
@ -283,7 +283,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u
|
|||
app_ref e_sig(m);
|
||||
e_sig = get_bvutil().mk_numeral(rational(sig), v.get().get_sbits() - 1);
|
||||
body = mk_compose(m, body, pp_bv_literal(e_sig, use_bv_lits, false));
|
||||
|
||||
|
||||
body = mk_compose(m, body, mk_string(m, ")"));
|
||||
return body;
|
||||
}
|
||||
|
@ -356,7 +356,7 @@ format * smt2_pp_environment::pp_arith_literal(app * t, bool decimal, unsigned d
|
|||
am.display_decimal(buffer, abs_val, decimal_prec);
|
||||
}
|
||||
else {
|
||||
am.display_root_smt2(buffer, val2);
|
||||
am.display_root_smt2(buffer, val2);
|
||||
}
|
||||
vf = mk_string(get_manager(), buffer.str().c_str());
|
||||
return is_neg ? mk_neg(vf) : vf;
|
||||
|
@ -378,7 +378,7 @@ format * smt2_pp_environment::pp_string_literal(app * t) {
|
|||
buffer << encs[i];
|
||||
}
|
||||
}
|
||||
buffer << "\"";
|
||||
buffer << "\"";
|
||||
return mk_string(get_manager(), buffer.str().c_str());
|
||||
}
|
||||
|
||||
|
@ -395,7 +395,7 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) {
|
|||
// This method is redefined in cmd_context::pp_env: support for parametric sorts.
|
||||
// Here, we just pretty print builtin sorts: Bool, Int, Real, BitVec and Array.
|
||||
ast_manager & m = get_manager();
|
||||
if (m.is_bool(s))
|
||||
if (m.is_bool(s))
|
||||
return mk_string(m, "Bool");
|
||||
if (get_autil().is_int(s))
|
||||
return mk_string(m, "Int");
|
||||
|
@ -431,7 +431,7 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) {
|
|||
fs.push_back(pp_sort(to_sort(s->get_parameter(0).get_ast())));
|
||||
return mk_seq1(m, fs.begin(), fs.end(), f2f(), get_sutil().is_seq(s)?"Seq":"Re");
|
||||
}
|
||||
return format_ns::mk_string(get_manager(), s->get_name().str().c_str());
|
||||
return format_ns::mk_string(get_manager(), s->get_name().str().c_str());
|
||||
}
|
||||
|
||||
typedef app_ref_vector format_ref_vector;
|
||||
|
@ -449,8 +449,8 @@ class smt2_printer {
|
|||
expr2alias * m_expr2alias; // expr -> position @ m_aliased_exprs, m_aliased_pps, m_aliased_lvls_names.
|
||||
ptr_vector<expr> m_aliased_exprs;
|
||||
format_ref_vector m_aliased_pps;
|
||||
svector<std::pair<unsigned, symbol> > m_aliased_lvls_names;
|
||||
unsigned m_next_alias_idx;
|
||||
svector<std::pair<unsigned, symbol> > m_aliased_lvls_names;
|
||||
unsigned m_next_alias_idx;
|
||||
struct scope {
|
||||
unsigned m_aliased_exprs_lim;
|
||||
unsigned m_old_next_alias_idx;
|
||||
|
@ -461,7 +461,7 @@ class smt2_printer {
|
|||
svector<symbol> m_var_names;
|
||||
typedef hashtable<symbol, symbol_hash_proc, symbol_eq_proc> symbol_set;
|
||||
symbol_set m_var_names_set;
|
||||
|
||||
|
||||
struct frame {
|
||||
expr * m_curr;
|
||||
unsigned m_idx;
|
||||
|
@ -469,7 +469,7 @@ class smt2_printer {
|
|||
bool m_use_alias; // if new aliases can be created
|
||||
frame(expr * c, unsigned i, unsigned s, bool use_alias):m_curr(c), m_idx(i), m_spos(s), m_use_alias(use_alias) {}
|
||||
};
|
||||
|
||||
|
||||
svector<frame> m_frame_stack;
|
||||
format_ref_vector m_format_stack;
|
||||
struct info {
|
||||
|
@ -517,7 +517,7 @@ class smt2_printer {
|
|||
SASSERT(m_aliased_exprs.size() == m_aliased_pps.size());
|
||||
SASSERT(m_aliased_exprs.size() == m_aliased_lvls_names.size());
|
||||
unsigned idx = m_aliased_exprs.size();
|
||||
m_expr2alias->insert(n, idx);
|
||||
m_expr2alias->insert(n, idx);
|
||||
m_aliased_exprs.push_back(n);
|
||||
m_aliased_pps.push_back(nf);
|
||||
m_aliased_lvls_names.push_back(std::make_pair(lvl, name));
|
||||
|
@ -567,12 +567,12 @@ class smt2_printer {
|
|||
buf.append(")");
|
||||
f = mk_string(m(), buf.c_str());
|
||||
}
|
||||
m_format_stack.push_back(f);
|
||||
m_format_stack.push_back(f);
|
||||
m_info_stack.push_back(info(0, 1, 1));
|
||||
}
|
||||
|
||||
format * pp_attribute(char const * attr, format * f) {
|
||||
return mk_compose(m(),
|
||||
return mk_compose(m(),
|
||||
mk_string(m(), attr),
|
||||
mk_indent(m(), static_cast<unsigned>(strlen(attr)), f));
|
||||
}
|
||||
|
@ -639,7 +639,7 @@ class smt2_printer {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void process_var(var * v) {
|
||||
pp_var(v);
|
||||
pop_frame();
|
||||
|
@ -651,7 +651,7 @@ class smt2_printer {
|
|||
expr * arg = t->get_arg(fr.m_idx);
|
||||
fr.m_idx++;
|
||||
if (pp_aliased(arg))
|
||||
continue;
|
||||
continue;
|
||||
switch (arg->get_kind()) {
|
||||
case AST_VAR:
|
||||
pp_var(to_var(arg));
|
||||
|
@ -679,11 +679,11 @@ class smt2_printer {
|
|||
m_format_stack.shrink(fr.m_spos);
|
||||
m_info_stack.shrink(fr.m_spos);
|
||||
if (fr.m_use_alias && m_root != t &&
|
||||
((f_info.m_depth >= m_pp_max_depth) ||
|
||||
((f_info.m_depth >= m_pp_max_depth) ||
|
||||
((f_info.m_weight >= m_pp_min_alias_size || is_quantifier(t)) && m_soccs.is_shared(t)))) {
|
||||
symbol a = next_alias();
|
||||
TRACE("smt2_pp", tout << "a: " << a << " depth: " << f_info.m_depth << ", weight: " << f_info.m_weight
|
||||
<< ", lvl: " << f_info.m_lvl << " t: #" << t->get_id() << "\n" << mk_ll_pp(t, m())
|
||||
TRACE("smt2_pp", tout << "a: " << a << " depth: " << f_info.m_depth << ", weight: " << f_info.m_weight
|
||||
<< ", lvl: " << f_info.m_lvl << " t: #" << t->get_id() << "\n" << mk_ll_pp(t, m())
|
||||
<< ", is-shared: " << m_soccs.is_shared(t) << "\n";);
|
||||
register_alias(t, f, f_info.m_lvl, a);
|
||||
m_format_stack.push_back(mk_string(m(), a.str().c_str()));
|
||||
|
@ -745,7 +745,7 @@ class smt2_printer {
|
|||
f = mk_group(m(), mk_compose(m(),
|
||||
mk_indent(m(), 1, mk_compose(m(), mk_string(m(), "("), fname)),
|
||||
mk_indent(m(), SMALL_INDENT, mk_compose(m(),
|
||||
mk_seq<format**, f2f>(m(), it, end, f2f()),
|
||||
mk_seq<format**, f2f>(m(), it, end, f2f()),
|
||||
mk_string(m(), ")")))));
|
||||
}
|
||||
else {
|
||||
|
@ -756,7 +756,7 @@ class smt2_printer {
|
|||
mk_indent(m(), len + 2, mk_compose(m(),
|
||||
mk_string(m(), " "),
|
||||
first,
|
||||
mk_seq<format**, f2f>(m(), it, end, f2f()),
|
||||
mk_seq<format**, f2f>(m(), it, end, f2f()),
|
||||
mk_string(m(), ")")))));
|
||||
}
|
||||
}
|
||||
|
@ -832,7 +832,7 @@ class smt2_printer {
|
|||
m_expr2alias = m_expr2alias_stack[lvl];
|
||||
m_next_alias_idx = 1;
|
||||
}
|
||||
|
||||
|
||||
void end_scope() {
|
||||
TRACE("pp_scope", tout << "[end-scope] before sz: " << m_aliased_exprs.size() << ", m_root: " << m_root << "\n";);
|
||||
m_expr2alias->reset();
|
||||
|
@ -853,7 +853,7 @@ class smt2_printer {
|
|||
void register_var_names(quantifier * q) {
|
||||
unsigned num_decls = q->get_num_decls();
|
||||
for (unsigned i = 0; i < num_decls; i++) {
|
||||
symbol name = ensure_quote_sym(q->get_decl_name(i));
|
||||
symbol name = ensure_quote_sym(q->get_decl_name(i));
|
||||
if (name.is_numerical()) {
|
||||
unsigned idx = 1;
|
||||
name = next_name("x", idx);
|
||||
|
@ -914,7 +914,7 @@ class smt2_printer {
|
|||
format * f_body = pp_let(m_format_stack.back(), num_lets);
|
||||
// The current SMT2 frontend uses weight 1 as default.
|
||||
#define MIN_WEIGHT 1
|
||||
if (q->has_patterns() || q->get_weight() > MIN_WEIGHT ||
|
||||
if (q->has_patterns() || q->get_weight() > MIN_WEIGHT ||
|
||||
q->get_skid() != symbol::null || (q->get_qid() != symbol::null && !q->get_qid().is_numerical())) {
|
||||
ptr_buffer<format> buf;
|
||||
buf.push_back(f_body);
|
||||
|
@ -952,12 +952,12 @@ class smt2_printer {
|
|||
format * fs[2] = { f_decls, f_body };
|
||||
char const * header = q->is_forall() ? "forall" : "exists";
|
||||
format * f = mk_seq3<format**, f2f>(m(), fs, fs+2, f2f(), header, 1, SMALL_INDENT);
|
||||
|
||||
|
||||
info f_info = m_info_stack.back();
|
||||
f_info.m_lvl = 0; // quantifiers don't depend on any let-decls, pp_let added all dependencies for the body.
|
||||
f_info.m_depth++;
|
||||
f_info.m_weight += q->get_num_decls()*2 + num_lets*8;
|
||||
|
||||
|
||||
unregister_var_names(q);
|
||||
end_scope();
|
||||
|
||||
|
@ -1002,7 +1002,7 @@ class smt2_printer {
|
|||
reset_stacks();
|
||||
SASSERT(&(r.get_manager()) == &(fm()));
|
||||
m_soccs(n);
|
||||
TRACE("smt2_pp_shared",
|
||||
TRACE("smt2_pp_shared",
|
||||
tout << "shared terms for:\n" << mk_pp(n, m()) << "\n";
|
||||
tout << "------>\n";
|
||||
shared_occs::iterator it = m_soccs.begin_shared();
|
||||
|
@ -1043,7 +1043,7 @@ public:
|
|||
m_env(env),
|
||||
m_soccs(m_manager),
|
||||
m_root(0),
|
||||
m_aliased_pps(fm()),
|
||||
m_aliased_pps(fm()),
|
||||
m_next_alias_idx(1),
|
||||
m_format_stack(fm()) {
|
||||
init_expr2alias_stack();
|
||||
|
@ -1108,7 +1108,7 @@ public:
|
|||
|
||||
};
|
||||
|
||||
void mk_smt2_format(expr * n, smt2_pp_environment & env, params_ref const & p,
|
||||
void mk_smt2_format(expr * n, smt2_pp_environment & env, params_ref const & p,
|
||||
unsigned num_vars, char const * var_prefix,
|
||||
format_ref & r, sbuffer<symbol> & var_names) {
|
||||
smt2_printer pr(env, p);
|
||||
|
@ -1125,13 +1125,13 @@ void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const &
|
|||
pr(f, r);
|
||||
}
|
||||
|
||||
std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & env, params_ref const & p, unsigned indent,
|
||||
std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & env, params_ref const & p, unsigned indent,
|
||||
unsigned num_vars, char const * var_prefix) {
|
||||
ast_manager & m = env.get_manager();
|
||||
format_ref r(fm(m));
|
||||
sbuffer<symbol> var_names;
|
||||
mk_smt2_format(n, env, p, num_vars, var_prefix, r, var_names);
|
||||
if (indent > 0)
|
||||
if (indent > 0)
|
||||
r = mk_indent(m, indent, r.get());
|
||||
pp(out, r.get(), m, p);
|
||||
return out;
|
||||
|
@ -1142,7 +1142,7 @@ std::ostream & ast_smt2_pp(std::ostream & out, sort * s, smt2_pp_environment & e
|
|||
format_ref r(fm(m));
|
||||
sbuffer<symbol> var_names;
|
||||
mk_smt2_format(s, env, p, r);
|
||||
if (indent > 0)
|
||||
if (indent > 0)
|
||||
r = mk_indent(m, indent, r.get());
|
||||
pp(out, r.get(), m, p);
|
||||
return out;
|
||||
|
@ -1153,7 +1153,7 @@ std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environmen
|
|||
format_ref r(fm(m));
|
||||
sbuffer<symbol> var_names;
|
||||
mk_smt2_format(f, env, p, r);
|
||||
if (indent > 0)
|
||||
if (indent > 0)
|
||||
r = mk_indent(m, indent, r.get());
|
||||
pp(out, r.get(), m, p);
|
||||
return out;
|
||||
|
@ -1200,6 +1200,14 @@ std::ostream& operator<<(std::ostream& out, app_ref const& e) {
|
|||
return out << mk_ismt2_pp(e.get(), e.get_manager());
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, func_decl_ref const& e) {
|
||||
return out << mk_ismt2_pp(e.get(), e.get_manager());
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, sort_ref const& e) {
|
||||
return out << mk_ismt2_pp(e.get(), e.get_manager());
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e) {
|
||||
for (unsigned i = 0; i < e.size(); ++i) {
|
||||
out << mk_ismt2_pp(e[i], e.get_manager());
|
||||
|
@ -1216,6 +1224,18 @@ std::ostream& operator<<(std::ostream& out, app_ref_vector const& e) {
|
|||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e) {
|
||||
for (unsigned i = 0; i < e.size(); ++i)
|
||||
out << mk_ismt2_pp(e[i], e.get_manager()) << "\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, sort_ref_vector const& e) {
|
||||
for (unsigned i = 0; i < e.size(); ++i)
|
||||
out << mk_ismt2_pp(e[i], e.get_manager()) << "\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
void pp(expr const * n, ast_manager & m) {
|
||||
std::cout << mk_ismt2_pp(const_cast<expr*>(n), m) << std::endl;
|
||||
|
|
|
@ -117,8 +117,13 @@ std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p);
|
|||
|
||||
std::ostream& operator<<(std::ostream& out, expr_ref const& e);
|
||||
std::ostream& operator<<(std::ostream& out, app_ref const& e);
|
||||
std::ostream& operator<<(std::ostream& out, func_decl_ref const& e);
|
||||
std::ostream& operator<<(std::ostream& out, sort_ref const& e);
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e);
|
||||
std::ostream& operator<<(std::ostream& out, app_ref_vector const& e);
|
||||
std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e);
|
||||
std::ostream& operator<<(std::ostream& out, sort_ref_vector const& e);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,6 +26,7 @@ Revision History:
|
|||
#include"bv_decl_plugin.h"
|
||||
#include"array_decl_plugin.h"
|
||||
#include"datatype_decl_plugin.h"
|
||||
#include"fpa_decl_plugin.h"
|
||||
#include"vector.h"
|
||||
#include"for_each_ast.h"
|
||||
#include"decl_collector.h"
|
||||
|
@ -43,7 +44,7 @@ static const char m_predef_names[][8] = {
|
|||
symbol smt_renaming::fix_symbol(symbol s, int k) {
|
||||
std::ostringstream buffer;
|
||||
char const * data = s.is_numerical() ? "" : s.bare_str();
|
||||
|
||||
|
||||
if (data[0] && !data[1]) {
|
||||
switch (data[0]) {
|
||||
case '/': data = "op_div"; break;
|
||||
|
@ -51,7 +52,7 @@ symbol smt_renaming::fix_symbol(symbol s, int k) {
|
|||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (k == 0 && *data) {
|
||||
if (s.is_numerical()) {
|
||||
return s;
|
||||
|
@ -63,10 +64,10 @@ symbol smt_renaming::fix_symbol(symbol s, int k) {
|
|||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (s.is_numerical()) {
|
||||
buffer << s << k;
|
||||
return symbol(buffer.str().c_str());
|
||||
return symbol(buffer.str().c_str());
|
||||
}
|
||||
|
||||
if (is_smt2_quoted_symbol(s)) {
|
||||
|
@ -78,12 +79,12 @@ symbol smt_renaming::fix_symbol(symbol s, int k) {
|
|||
if (k > 0) {
|
||||
buffer << k;
|
||||
}
|
||||
|
||||
|
||||
return symbol(buffer.str().c_str());
|
||||
}
|
||||
|
||||
bool smt_renaming::is_legal(char c) {
|
||||
return c == '.' || c == '_' || c == '\''
|
||||
return c == '.' || c == '_' || c == '\''
|
||||
|| c == '?' || c == '!' || isalnum(c);
|
||||
}
|
||||
|
||||
|
@ -134,11 +135,11 @@ symbol smt_renaming::get_symbol(symbol s0) {
|
|||
if (m_translate.find(s0, s)) {
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int k = 0;
|
||||
do {
|
||||
s = fix_symbol(s0, k++);
|
||||
}
|
||||
}
|
||||
while (m_rev_translate.contains(s));
|
||||
m_translate.insert(s0, s);
|
||||
m_rev_translate.insert(s, s0);
|
||||
|
@ -162,11 +163,13 @@ class smt_printer {
|
|||
arith_util m_autil;
|
||||
bv_util m_bvutil;
|
||||
seq_util m_sutil;
|
||||
fpa_util m_futil;
|
||||
family_id m_basic_fid;
|
||||
family_id m_bv_fid;
|
||||
family_id m_arith_fid;
|
||||
family_id m_array_fid;
|
||||
family_id m_dt_fid;
|
||||
family_id m_fpa_fid;
|
||||
family_id m_label_fid;
|
||||
symbol m_logic;
|
||||
symbol m_AUFLIRA;
|
||||
|
@ -176,7 +179,7 @@ class smt_printer {
|
|||
expr* m_top;
|
||||
|
||||
bool is_bool(sort* s) {
|
||||
return
|
||||
return
|
||||
m_basic_fid == s->get_family_id() &&
|
||||
s->get_decl_kind() == BOOL_SORT;
|
||||
}
|
||||
|
@ -186,13 +189,13 @@ class smt_printer {
|
|||
}
|
||||
|
||||
bool is_proof(sort* s) {
|
||||
return
|
||||
return
|
||||
m_basic_fid == s->get_family_id() &&
|
||||
s->get_decl_kind() == PROOF_SORT;
|
||||
s->get_decl_kind() == PROOF_SORT;
|
||||
}
|
||||
|
||||
bool is_proof(expr* e) {
|
||||
return is_proof(m_manager.get_sort(e));
|
||||
bool is_proof(expr* e) {
|
||||
return is_proof(m_manager.get_sort(e));
|
||||
}
|
||||
|
||||
void pp_id(expr* n) {
|
||||
|
@ -236,8 +239,8 @@ class smt_printer {
|
|||
}
|
||||
|
||||
bool is_sort_param(unsigned num_params, parameter const* params) {
|
||||
return
|
||||
num_params == 1 &&
|
||||
return
|
||||
num_params == 1 &&
|
||||
params[0].is_ast() &&
|
||||
is_sort(params[0].get_ast());
|
||||
}
|
||||
|
@ -253,14 +256,17 @@ class smt_printer {
|
|||
m_out << "String";
|
||||
return;
|
||||
}
|
||||
if (is_sort_symbol && sym != symbol("BitVec")) {
|
||||
m_out << "(" << sym << " ";
|
||||
if (is_sort_symbol &&
|
||||
sym != symbol("BitVec") &&
|
||||
sym != symbol("FloatingPoint") &&
|
||||
sym != symbol("RoundingMode")) {
|
||||
m_out << "(" << sym << " ";
|
||||
}
|
||||
else if (!is_sort_symbol && is_sort_param(num_params, params)) {
|
||||
m_out << "(as " << sym << " ";
|
||||
}
|
||||
else {
|
||||
m_out << "(_ " << sym << " ";
|
||||
m_out << "(_ " << sym << " ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -302,13 +308,13 @@ class smt_printer {
|
|||
m_out << "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool is_auflira() const {
|
||||
return m_logic == m_AUFLIRA;
|
||||
}
|
||||
|
||||
void visit_sort(sort* s, bool bool2int = false) {
|
||||
symbol sym;
|
||||
symbol sym;
|
||||
if (bool2int && is_bool(s) && !m_is_smt2) {
|
||||
sym = symbol("Int");
|
||||
} else if (s->is_sort_of(m_bv_fid, BV_SORT)) {
|
||||
|
@ -326,7 +332,7 @@ class smt_printer {
|
|||
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && m_is_smt2) {
|
||||
sym = "Array";
|
||||
}
|
||||
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && !m_is_smt2) {
|
||||
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && !m_is_smt2) {
|
||||
unsigned num_params = s->get_num_parameters();
|
||||
SASSERT(num_params >= 2);
|
||||
if (is_auflira()) {
|
||||
|
@ -341,12 +347,12 @@ class smt_printer {
|
|||
}
|
||||
sort* s1 = to_sort(s->get_parameter(0).get_ast());
|
||||
sort* s2 = to_sort(s->get_parameter(1).get_ast());
|
||||
if (num_params == 2 &&
|
||||
if (num_params == 2 &&
|
||||
s1->is_sort_of(m_bv_fid, BV_SORT) &&
|
||||
s2->is_sort_of(m_bv_fid, BV_SORT)) {
|
||||
m_out << "Array";
|
||||
m_out << "[" << s1->get_parameter(0).get_int();
|
||||
m_out << ":" << s2->get_parameter(0).get_int() << "]";
|
||||
m_out << ":" << s2->get_parameter(0).get_int() << "]";
|
||||
return;
|
||||
}
|
||||
m_out << "(Array ";
|
||||
|
@ -379,7 +385,7 @@ class smt_printer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void pp_arg(expr *arg, app *parent)
|
||||
{
|
||||
if (!m_is_smt2 && is_bool(arg) && is_var(arg) && parent->get_family_id() == m_basic_fid) {
|
||||
|
@ -387,7 +393,7 @@ class smt_printer {
|
|||
pp_marked_expr(arg);
|
||||
m_out << " 0))";
|
||||
} else if (!m_is_smt2 && is_bool(arg) && !is_var(arg) &&
|
||||
parent->get_family_id() != m_basic_fid &&
|
||||
parent->get_family_id() != m_basic_fid &&
|
||||
parent->get_family_id() != m_dt_fid) {
|
||||
|
||||
m_out << "(ite ";
|
||||
|
@ -403,9 +409,10 @@ class smt_printer {
|
|||
bool is_int, pos;
|
||||
buffer<symbol> names;
|
||||
unsigned bv_size;
|
||||
zstring s;
|
||||
zstring s;
|
||||
unsigned num_args = n->get_num_args();
|
||||
func_decl* decl = n->get_decl();
|
||||
scoped_mpf float_val(m_futil.fm());
|
||||
if (m_autil.is_numeral(n, val, is_int)) {
|
||||
if (val.is_neg()) {
|
||||
val.neg();
|
||||
|
@ -433,7 +440,7 @@ class smt_printer {
|
|||
m_out << encs[i];
|
||||
}
|
||||
}
|
||||
m_out << "\"";
|
||||
m_out << "\"";
|
||||
}
|
||||
else if (m_bvutil.is_numeral(n, val, bv_size)) {
|
||||
if (m_is_smt2) {
|
||||
|
@ -443,7 +450,13 @@ class smt_printer {
|
|||
m_out << "bv" << val << "[" << bv_size << "]";
|
||||
}
|
||||
}
|
||||
else if (m_bvutil.is_bit2bool(n)) {
|
||||
else if (m_futil.is_numeral(n, float_val)) {
|
||||
m_out << "((_ to_fp " <<
|
||||
float_val.get().get_ebits() << " " <<
|
||||
float_val.get().get_sbits() << ") RTZ " <<
|
||||
m_futil.fm().to_string(float_val).c_str() << ")";
|
||||
}
|
||||
else if (m_bvutil.is_bit2bool(n)) {
|
||||
unsigned bit = n->get_decl()->get_parameter(0).get_int();
|
||||
if (m_is_smt2) {
|
||||
m_out << "(= ((_ extract " << bit << " " << bit << ") ";
|
||||
|
@ -458,14 +471,14 @@ class smt_printer {
|
|||
}
|
||||
else if (m_manager.is_label(n, pos, names) && names.size() >= 1) {
|
||||
if (m_is_smt2) {
|
||||
m_out << "(! ";
|
||||
m_out << "(! ";
|
||||
pp_marked_expr(n->get_arg(0));
|
||||
m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0]) << ")";
|
||||
}
|
||||
else {
|
||||
m_out << "(" << (pos?"lblpos":"lblneg") << " " << m_renaming.get_symbol(names[0]) << " ";
|
||||
expr* ch = n->get_arg(0);
|
||||
pp_marked_expr(ch);
|
||||
pp_marked_expr(ch);
|
||||
m_out << ")";
|
||||
}
|
||||
}
|
||||
|
@ -547,13 +560,13 @@ class smt_printer {
|
|||
m_out << " ";
|
||||
}
|
||||
}
|
||||
m_out << ")";
|
||||
m_out << ")";
|
||||
}
|
||||
}
|
||||
|
||||
void print_no_lets(expr *e)
|
||||
{
|
||||
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_is_smt2, m_indent, m_num_var_names, m_var_names);
|
||||
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_is_smt2, m_indent, m_num_var_names, m_var_names);
|
||||
p(e);
|
||||
}
|
||||
|
||||
|
@ -565,7 +578,7 @@ class smt_printer {
|
|||
}
|
||||
|
||||
void visit_quantifier(quantifier* q) {
|
||||
m_qlists.push_back(q);
|
||||
m_qlists.push_back(q);
|
||||
|
||||
m_out << "(";
|
||||
if (q->is_forall()) {
|
||||
|
@ -588,12 +601,12 @@ class smt_printer {
|
|||
if (m_is_smt2) {
|
||||
m_out << ")";
|
||||
}
|
||||
|
||||
|
||||
if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
|
||||
m_out << "(! ";
|
||||
}
|
||||
{
|
||||
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, m_is_smt2, m_simplify_implies, m_indent, m_num_var_names, m_var_names);
|
||||
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, m_is_smt2, m_simplify_implies, m_indent, m_num_var_names, m_var_names);
|
||||
p(q->get_expr());
|
||||
}
|
||||
|
||||
|
@ -644,7 +657,7 @@ class smt_printer {
|
|||
void newline() {
|
||||
unsigned i = m_indent;
|
||||
m_out << "\n";
|
||||
while (i > 0) { m_out << " "; --i; }
|
||||
while (i > 0) { m_out << " "; --i; }
|
||||
}
|
||||
|
||||
void visit_var(var* v) {
|
||||
|
@ -685,15 +698,15 @@ class smt_printer {
|
|||
case AST_QUANTIFIER:
|
||||
visit_quantifier(to_quantifier(n));
|
||||
break;
|
||||
case AST_APP:
|
||||
case AST_APP:
|
||||
visit_app(to_app(n));
|
||||
break;
|
||||
case AST_VAR:
|
||||
case AST_VAR:
|
||||
visit_var(to_var(n));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void visit_expr(expr* n) {
|
||||
|
@ -714,7 +727,7 @@ class smt_printer {
|
|||
}
|
||||
m_out << ")";
|
||||
newline();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_unit(expr* n) {
|
||||
if (n->get_ref_count() <= 2 && is_small(n)) {
|
||||
|
@ -724,9 +737,9 @@ class smt_printer {
|
|||
return true;
|
||||
}
|
||||
switch(n->get_kind()) {
|
||||
case AST_VAR:
|
||||
case AST_VAR:
|
||||
return true;
|
||||
case AST_APP:
|
||||
case AST_APP:
|
||||
return to_app(n)->get_num_args() == 0;
|
||||
default:
|
||||
return false;
|
||||
|
@ -749,9 +762,9 @@ class smt_printer {
|
|||
return sz <= m_line_length;
|
||||
}
|
||||
switch(n->get_kind()) {
|
||||
case AST_QUANTIFIER:
|
||||
case AST_QUANTIFIER:
|
||||
return false;
|
||||
case AST_VAR:
|
||||
case AST_VAR:
|
||||
sz += 5;
|
||||
return sz <= m_line_length;
|
||||
case AST_APP: {
|
||||
|
@ -777,14 +790,14 @@ class smt_printer {
|
|||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool visit_children(expr* n) {
|
||||
unsigned todo_size = m_todo.size();
|
||||
switch(n->get_kind()) {
|
||||
case AST_QUANTIFIER:
|
||||
case AST_VAR:
|
||||
case AST_QUANTIFIER:
|
||||
case AST_VAR:
|
||||
break;
|
||||
case AST_APP: {
|
||||
app* a = to_app(n);
|
||||
|
@ -805,9 +818,9 @@ class smt_printer {
|
|||
}
|
||||
|
||||
public:
|
||||
smt_printer(std::ostream& out, ast_manager& m, ptr_vector<quantifier>& ql, smt_renaming& rn,
|
||||
smt_printer(std::ostream& out, ast_manager& m, ptr_vector<quantifier>& ql, smt_renaming& rn,
|
||||
symbol logic, bool no_lets, bool is_smt2, bool simplify_implies, unsigned indent, unsigned num_var_names = 0, char const* const* var_names = 0) :
|
||||
m_out(out),
|
||||
m_out(out),
|
||||
m_manager(m),
|
||||
m_qlists(ql),
|
||||
m_renaming(rn),
|
||||
|
@ -818,6 +831,7 @@ public:
|
|||
m_autil(m),
|
||||
m_bvutil(m),
|
||||
m_sutil(m),
|
||||
m_futil(m),
|
||||
m_logic(logic),
|
||||
m_AUFLIRA("AUFLIRA"),
|
||||
// It's much easier to read those testcases with that.
|
||||
|
@ -831,8 +845,9 @@ public:
|
|||
m_arith_fid = m.mk_family_id("arith");
|
||||
m_array_fid = m.mk_family_id("array");
|
||||
m_dt_fid = m.mk_family_id("datatype");
|
||||
m_fpa_fid = m.mk_family_id("fpa");
|
||||
}
|
||||
|
||||
|
||||
void operator()(expr* n) {
|
||||
m_top = n;
|
||||
if (!m_no_lets) {
|
||||
|
@ -842,7 +857,7 @@ public:
|
|||
m_todo.push_back(to_app(n)->get_arg(i));
|
||||
}
|
||||
break;
|
||||
// Don't do this for quantifiers -- they need to have the body be
|
||||
// Don't do this for quantifiers -- they need to have the body be
|
||||
// visited when the m_qlist contains the relevant quantifier.
|
||||
default:
|
||||
break;
|
||||
|
@ -867,7 +882,7 @@ public:
|
|||
|
||||
pp_marked_expr(n);
|
||||
for (unsigned i = 0; i < m_num_lets; ++i) {
|
||||
m_out << ")";
|
||||
m_out << ")";
|
||||
}
|
||||
m_mark.reset();
|
||||
m_num_lets = 0;
|
||||
|
@ -880,7 +895,7 @@ public:
|
|||
ptr_vector<func_decl> const* decls;
|
||||
ptr_vector<sort> rec_sorts;
|
||||
|
||||
rec_sorts.push_back(s);
|
||||
rec_sorts.push_back(s);
|
||||
mark.mark(s, true);
|
||||
|
||||
// collect siblings and sorts that have not already been printed.
|
||||
|
@ -905,20 +920,20 @@ public:
|
|||
}
|
||||
else {
|
||||
pp_sort_decl(mark, s2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_is_smt2) {
|
||||
// TBD: datatypes may be declared parametrically.
|
||||
// TBD: datatypes may be declared parametrically.
|
||||
// get access to parametric generalization, or print
|
||||
// monomorphic specialization with a tag that gets reused at use-point.
|
||||
m_out << "(declare-datatypes () (";
|
||||
}
|
||||
else {
|
||||
m_out << ":datatypes (";
|
||||
m_out << ":datatypes (";
|
||||
}
|
||||
for (unsigned si = 0; si < rec_sorts.size(); ++si) {
|
||||
s = rec_sorts[si];
|
||||
|
@ -928,7 +943,7 @@ public:
|
|||
decls = util.get_datatype_constructors(s);
|
||||
|
||||
for (unsigned i = 0; i < decls->size(); ++i) {
|
||||
func_decl* f = (*decls)[i];
|
||||
func_decl* f = (*decls)[i];
|
||||
ptr_vector<func_decl> const& accs = *util.get_constructor_accessors(f);
|
||||
if (m_is_smt2 || accs.size() > 0) {
|
||||
m_out << "(";
|
||||
|
@ -937,7 +952,7 @@ public:
|
|||
if (!accs.empty() || !m_is_smt2) {
|
||||
m_out << " ";
|
||||
}
|
||||
for (unsigned j = 0; j < accs.size(); ++j) {
|
||||
for (unsigned j = 0; j < accs.size(); ++j) {
|
||||
func_decl* a = accs[j];
|
||||
m_out << "(" << m_renaming.get_symbol(a->get_name()) << " ";
|
||||
visit_sort(a->get_range());
|
||||
|
@ -1081,7 +1096,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
|
|||
ptr_vector<quantifier> ql;
|
||||
ast_manager& m = m_manager;
|
||||
decl_collector decls(m);
|
||||
smt_renaming rn;
|
||||
smt_renaming rn;
|
||||
|
||||
for (unsigned i = 0; i < m_assumptions.size(); ++i) {
|
||||
decls.visit(m_assumptions[i].get());
|
||||
|
@ -1089,7 +1104,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
|
|||
for (unsigned i = 0; i < m_assumptions_star.size(); ++i) {
|
||||
decls.visit(m_assumptions_star[i].get());
|
||||
}
|
||||
decls.visit(n);
|
||||
decls.visit(n);
|
||||
|
||||
if (m.is_proof(n)) {
|
||||
strm << "(";
|
||||
|
@ -1099,7 +1114,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
|
|||
}
|
||||
if (m_source_info != symbol::null && m_source_info != symbol("")) {
|
||||
strm << "; :source { " << m_source_info << " }\n";
|
||||
}
|
||||
}
|
||||
if (m.is_bool(n)) {
|
||||
strm << "(set-info :status " << m_status << ")\n";
|
||||
}
|
||||
|
@ -1119,7 +1134,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
|
|||
if (!(*m_is_declared)(s)) {
|
||||
smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0);
|
||||
p.pp_sort_decl(sort_mark, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < decls.get_num_decls(); ++i) {
|
||||
|
@ -1147,7 +1162,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
|
|||
strm << ")\n";
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m_assumptions_star.size(); ++i) {
|
||||
for (unsigned i = 0; i < m_assumptions_star.size(); ++i) {
|
||||
smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1);
|
||||
strm << "(assert\n ";
|
||||
p(m_assumptions_star[i].get());
|
||||
|
@ -1170,13 +1185,13 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
|
|||
}
|
||||
else {
|
||||
p(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ast_smt_pp::display(std::ostream& strm, expr* n) {
|
||||
ptr_vector<quantifier> ql;
|
||||
decl_collector decls(m_manager);
|
||||
smt_renaming rn;
|
||||
smt_renaming rn;
|
||||
|
||||
for (unsigned i = 0; i < m_assumptions.size(); ++i) {
|
||||
decls.visit(m_assumptions[i].get());
|
||||
|
@ -1185,7 +1200,7 @@ void ast_smt_pp::display(std::ostream& strm, expr* n) {
|
|||
decls.visit(m_assumptions_star[i].get());
|
||||
}
|
||||
decls.visit(n);
|
||||
|
||||
|
||||
strm << "(benchmark ";
|
||||
|
||||
if (m_benchmark_name != symbol::null) {
|
||||
|
@ -1214,8 +1229,8 @@ void ast_smt_pp::display(std::ostream& strm, expr* n) {
|
|||
sort* s = decls.get_sorts()[i];
|
||||
if (!(*m_is_declared)(s)) {
|
||||
smt_printer p(strm, m_manager, ql, rn, m_logic, true, false, m_simplify_implies, 0);
|
||||
p.pp_sort_decl(sort_mark, s);
|
||||
}
|
||||
p.pp_sort_decl(sort_mark, s);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < decls.get_num_decls(); ++i) {
|
||||
|
@ -1242,14 +1257,14 @@ void ast_smt_pp::display(std::ostream& strm, expr* n) {
|
|||
expr * e = m_assumptions[i].get();
|
||||
strm << ":assumption\n";
|
||||
smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0);
|
||||
p(e);
|
||||
strm << "\n";
|
||||
p(e);
|
||||
strm << "\n";
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m_assumptions_star.size(); ++i) {
|
||||
strm << ":assumption-core\n";
|
||||
smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0);
|
||||
p(m_assumptions_star[i].get());
|
||||
p(m_assumptions_star[i].get());
|
||||
strm << "\n";
|
||||
}
|
||||
|
||||
|
|
|
@ -170,7 +170,6 @@ app* mk_and(ast_manager & m, unsigned num_args, app * const * args) {
|
|||
return to_app(mk_and(m, num_args, (expr* const*) args));
|
||||
}
|
||||
|
||||
|
||||
expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args) {
|
||||
if (num_args == 0)
|
||||
return m.mk_false();
|
||||
|
@ -188,10 +187,43 @@ expr * mk_not(ast_manager & m, expr * arg) {
|
|||
expr * atom;
|
||||
if (m.is_not(arg, atom))
|
||||
return atom;
|
||||
else if (m.is_true(arg))
|
||||
return m.mk_false();
|
||||
else if (m.is_false(arg))
|
||||
return m.mk_true();
|
||||
else
|
||||
return m.mk_not(arg);
|
||||
}
|
||||
|
||||
expr_ref push_not(const expr_ref& e) {
|
||||
ast_manager& m = e.get_manager();
|
||||
if (!is_app(e)) {
|
||||
return expr_ref(m.mk_not(e), m);
|
||||
}
|
||||
app* a = to_app(e);
|
||||
if (m.is_and(a)) {
|
||||
if (a->get_num_args() == 0) {
|
||||
return expr_ref(m.mk_false(), m);
|
||||
}
|
||||
expr_ref_vector args(m);
|
||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||
args.push_back(push_not(expr_ref(a->get_arg(i), m)));
|
||||
}
|
||||
return mk_or(args);
|
||||
}
|
||||
if (m.is_or(a)) {
|
||||
if (a->get_num_args() == 0) {
|
||||
return expr_ref(m.mk_true(), m);
|
||||
}
|
||||
expr_ref_vector args(m);
|
||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||
args.push_back(push_not(expr_ref(a->get_arg(i), m)));
|
||||
}
|
||||
return mk_and(args);
|
||||
}
|
||||
return expr_ref(mk_not(m, e), m);
|
||||
}
|
||||
|
||||
expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args) {
|
||||
expr_ref_buffer new_diseqs(m);
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
|
@ -201,6 +233,24 @@ expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args)
|
|||
return mk_and(m, new_diseqs.size(), new_diseqs.c_ptr());
|
||||
}
|
||||
|
||||
expr* mk_distinct(ast_manager& m, unsigned num_args, expr * const * args) {
|
||||
switch (num_args) {
|
||||
case 0:
|
||||
case 1:
|
||||
return m.mk_true();
|
||||
case 2:
|
||||
return m.mk_not(m.mk_eq(args[0], args[1]));
|
||||
default:
|
||||
return m.mk_distinct(num_args, args);
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref mk_distinct(expr_ref_vector const& args) {
|
||||
ast_manager& m = args.get_manager();
|
||||
return expr_ref(mk_distinct(m, args.size(), args.c_ptr()), m);
|
||||
}
|
||||
|
||||
|
||||
void flatten_and(expr_ref_vector& result) {
|
||||
ast_manager& m = result.get_manager();
|
||||
expr* e1, *e2, *e3;
|
||||
|
|
|
@ -121,18 +121,29 @@ app * mk_or(ast_manager & m, unsigned num_args, app * const * args);
|
|||
inline app_ref mk_or(app_ref_vector const& args) { return app_ref(mk_or(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); }
|
||||
inline expr_ref mk_or(expr_ref_vector const& args) { return expr_ref(mk_or(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); }
|
||||
|
||||
|
||||
/**
|
||||
Return a if arg = (not a)
|
||||
Retur (not arg) otherwise
|
||||
*/
|
||||
expr * mk_not(ast_manager & m, expr * arg);
|
||||
|
||||
/**
|
||||
Negate and push over conjunction or disjunction.
|
||||
*/
|
||||
expr_ref push_not(const expr_ref& arg);
|
||||
|
||||
/**
|
||||
Return the expression (and (not (= args[0] args[1])) (not (= args[0] args[2])) ... (not (= args[num_args-2] args[num_args-1])))
|
||||
*/
|
||||
expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args);
|
||||
|
||||
/**
|
||||
Create simplified distinct term. Binary distinct becomes a single disequality.
|
||||
*/
|
||||
expr * mk_distinct(ast_manager& m, unsigned num_args, expr * const * args);
|
||||
|
||||
expr_ref mk_distinct(expr_ref_vector const& args);
|
||||
|
||||
/**
|
||||
\brief Collect top-level conjunctions and disjunctions.
|
||||
*/
|
||||
|
|
|
@ -865,6 +865,12 @@ sort * bv_util::mk_sort(unsigned bv_size) {
|
|||
return m_manager.mk_sort(get_fid(), BV_SORT, 1, p);
|
||||
}
|
||||
|
||||
unsigned bv_util::get_int2bv_size(parameter const& p) {
|
||||
int sz;
|
||||
VERIFY(m_plugin->get_int2bv_size(1, &p, sz));
|
||||
return static_cast<unsigned>(sz);
|
||||
}
|
||||
|
||||
app * bv_util::mk_bv2int(expr* e) {
|
||||
sort* s = m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT);
|
||||
parameter p(s);
|
||||
|
|
|
@ -234,7 +234,6 @@ protected:
|
|||
|
||||
func_decl * mk_mkbv(unsigned arity, sort * const * domain);
|
||||
|
||||
bool get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result);
|
||||
|
||||
func_decl * mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity);
|
||||
|
||||
|
@ -267,6 +266,8 @@ public:
|
|||
|
||||
virtual expr * get_some_value(sort * s);
|
||||
|
||||
bool get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result);
|
||||
|
||||
virtual bool is_considered_uninterpreted(func_decl * f) {
|
||||
if (f->get_family_id() != get_family_id())
|
||||
return false;
|
||||
|
@ -390,6 +391,8 @@ public:
|
|||
return static_cast<unsigned>(s->get_parameter(0).get_int());
|
||||
}
|
||||
unsigned get_bv_size(expr const * n) const { return get_bv_size(m_manager.get_sort(n)); }
|
||||
unsigned get_int2bv_size(parameter const& p);
|
||||
|
||||
|
||||
app * mk_ule(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_ULEQ, arg1, arg2); }
|
||||
app * mk_sle(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_SLEQ, arg1, arg2); }
|
||||
|
@ -427,6 +430,7 @@ public:
|
|||
app * mk_bvumul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_NO_OVFL, n, m); }
|
||||
|
||||
app * mk_bv(unsigned n, expr* const* es) { return m_manager.mk_app(get_fid(), OP_MKBV, n, es); }
|
||||
|
||||
};
|
||||
|
||||
#endif /* BV_DECL_PLUGIN_H_ */
|
||||
|
|
|
@ -1000,3 +1000,25 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
bool datatype_util::is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f) {
|
||||
bool eq =
|
||||
f->get_decl_kind() == k &&
|
||||
f->get_family_id() == m_family_id &&
|
||||
f->get_num_parameters() == num_params;
|
||||
for (unsigned i = 0; eq && i < num_params; ++i) {
|
||||
eq = params[i] == f->get_parameter(i);
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
|
||||
bool datatype_util::is_constructor_of(unsigned num_params, parameter const* params, func_decl* f) {
|
||||
return
|
||||
num_params == 2 &&
|
||||
m_family_id == f->get_family_id() &&
|
||||
OP_DT_CONSTRUCTOR == f->get_decl_kind() &&
|
||||
2 == f->get_num_parameters() &&
|
||||
params[0] == f->get_parameter(0) &&
|
||||
params[1] == f->get_parameter(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,8 @@ public:
|
|||
func_decl * get_recognizer_constructor(func_decl * recognizer);
|
||||
family_id get_family_id() const { return m_family_id; }
|
||||
bool are_siblings(sort * s1, sort * s2);
|
||||
bool is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f);
|
||||
bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f);
|
||||
void reset();
|
||||
void display_datatype(sort *s, std::ostream& strm);
|
||||
|
||||
|
|
|
@ -22,6 +22,10 @@ Notes:
|
|||
|
||||
void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
|
||||
|
||||
if (num_bound == 0) {
|
||||
result = n;
|
||||
return;
|
||||
}
|
||||
expr * curr = 0, *b = 0;
|
||||
SASSERT(n->get_ref_count() > 0);
|
||||
|
||||
|
@ -106,3 +110,27 @@ void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* cons
|
|||
expr_abstractor abs(m);
|
||||
abs(base, num_bound, bound, n, result);
|
||||
}
|
||||
|
||||
expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
|
||||
expr_ref result(m);
|
||||
expr_abstract(m, 0, num_bound, (expr* const*)bound, n, result);
|
||||
if (num_bound > 0) {
|
||||
ptr_vector<sort> sorts;
|
||||
svector<symbol> names;
|
||||
for (unsigned i = 0; i < num_bound; ++i) {
|
||||
sorts.push_back(m.get_sort(bound[i]));
|
||||
names.push_back(bound[i]->get_decl()->get_name());
|
||||
}
|
||||
result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
expr_ref mk_forall(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
|
||||
return mk_quantifier(true, m, num_bound, bound, n);
|
||||
}
|
||||
|
||||
expr_ref mk_exists(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
|
||||
return mk_quantifier(false, m, num_bound, bound, n);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
};
|
||||
|
||||
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result);
|
||||
expr_ref mk_forall(ast_manager& m, unsigned num_bound, app* const* bound, expr* n);
|
||||
expr_ref mk_exists(ast_manager& m, unsigned num_bound, app* const* bound, expr* n);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -980,6 +980,9 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
|
|||
x = args[0];
|
||||
y = args[1];
|
||||
|
||||
TRACE("fpa2bv_rem", tout << "X = " << mk_ismt2_pp(x, m) << std::endl;
|
||||
tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;);
|
||||
|
||||
expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m);
|
||||
mk_nan(f, nan);
|
||||
mk_nzero(f, nzero);
|
||||
|
@ -1039,6 +1042,15 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
|
|||
unpack(x, a_sgn, a_sig, a_exp, a_lz, true);
|
||||
unpack(y, b_sgn, b_sig, b_exp, b_lz, true);
|
||||
|
||||
dbg_decouple("fpa2bv_rem_a_sgn", a_sgn);
|
||||
dbg_decouple("fpa2bv_rem_a_sig", a_sig);
|
||||
dbg_decouple("fpa2bv_rem_a_exp", a_exp);
|
||||
dbg_decouple("fpa2bv_rem_a_lz", a_lz);
|
||||
dbg_decouple("fpa2bv_rem_b_sgn", b_sgn);
|
||||
dbg_decouple("fpa2bv_rem_b_sig", b_sig);
|
||||
dbg_decouple("fpa2bv_rem_b_exp", b_exp);
|
||||
dbg_decouple("fpa2bv_rem_b_lz", b_lz);
|
||||
|
||||
BVSLT(a_exp, b_exp, c6);
|
||||
v6 = x;
|
||||
|
||||
|
@ -1052,15 +1064,25 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
|
|||
unsigned int max_exp_diff_ui = (unsigned int)m_mpz_manager.get_uint64(max_exp_diff);
|
||||
m_mpz_manager.del(max_exp_diff);
|
||||
|
||||
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);
|
||||
|
||||
expr_ref a_lz_ext(m), b_lz_ext(m);
|
||||
a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz);
|
||||
b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz);
|
||||
|
||||
expr_ref exp_diff(m);
|
||||
exp_diff = m_bv_util.mk_bv_sub(a_exp, b_exp);
|
||||
exp_diff = m_bv_util.mk_bv_sub(
|
||||
m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext),
|
||||
m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext));
|
||||
dbg_decouple("fpa2bv_rem_exp_diff", exp_diff);
|
||||
|
||||
// CMW: This creates _huge_ bit-vectors, which is potentially sub-optimal,
|
||||
// but calculating this via rem = x - y * nearest(x/y) creates huge circuits.
|
||||
expr_ref huge_sig(m), shifted_sig(m), huge_rem(m);
|
||||
huge_sig = m_bv_util.mk_zero_extend(max_exp_diff_ui, a_sig);
|
||||
shifted_sig = m_bv_util.mk_bv_shl(huge_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - ebits, exp_diff));
|
||||
shifted_sig = m_bv_util.mk_bv_shl(huge_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - ebits - 2, exp_diff));
|
||||
huge_rem = m_bv_util.mk_bv_urem(shifted_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui, b_sig));
|
||||
dbg_decouple("fpa2bv_rem_huge_rem", huge_rem);
|
||||
|
||||
|
@ -1068,7 +1090,8 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
|
|||
res_sgn = a_sgn;
|
||||
res_sig = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits, 0, huge_rem),
|
||||
m_bv_util.mk_numeral(0, 3));
|
||||
res_exp = m_bv_util.mk_sign_extend(2, b_exp);
|
||||
|
||||
res_exp = m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext);
|
||||
|
||||
// CMW: Actual rounding is not necessary here, this is
|
||||
// just convenience to get rid of the extra bits.
|
||||
|
@ -1155,38 +1178,34 @@ expr_ref fpa2bv_converter::mk_min_unspecified(func_decl * f, expr * x, expr * y)
|
|||
expr_ref res(m);
|
||||
|
||||
// The only cases in which min is unspecified for is when the arguments are +0.0 and -0.0.
|
||||
// There is no "hardware interpretation" for fp.min.
|
||||
|
||||
if (m_hi_fp_unspecified)
|
||||
// The hardware interpretation is -0.0.
|
||||
mk_nzero(f, res);
|
||||
else {
|
||||
std::pair<app*, app*> decls(0, 0);
|
||||
if (!m_specials.find(f, decls)) {
|
||||
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
|
||||
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
|
||||
m_specials.insert(f, decls);
|
||||
m.inc_ref(f);
|
||||
m.inc_ref(decls.first);
|
||||
m.inc_ref(decls.second);
|
||||
}
|
||||
|
||||
expr_ref pn(m), np(m);
|
||||
mk_fp(decls.first,
|
||||
m_bv_util.mk_numeral(0, ebits),
|
||||
m_bv_util.mk_numeral(0, sbits - 1),
|
||||
pn);
|
||||
mk_fp(decls.second,
|
||||
m_bv_util.mk_numeral(0, ebits),
|
||||
m_bv_util.mk_numeral(0, sbits - 1),
|
||||
np);
|
||||
|
||||
expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m);
|
||||
mk_is_pzero(x, x_is_pzero);
|
||||
mk_is_nzero(y, x_is_nzero);
|
||||
m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero);
|
||||
mk_ite(xyzero, pn, np, res);
|
||||
std::pair<app*, app*> decls(0, 0);
|
||||
if (!m_specials.find(f, decls)) {
|
||||
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
|
||||
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
|
||||
m_specials.insert(f, decls);
|
||||
m.inc_ref(f);
|
||||
m.inc_ref(decls.first);
|
||||
m.inc_ref(decls.second);
|
||||
}
|
||||
|
||||
expr_ref pn(m), np(m);
|
||||
mk_fp(decls.first,
|
||||
m_bv_util.mk_numeral(0, ebits),
|
||||
m_bv_util.mk_numeral(0, sbits - 1),
|
||||
pn);
|
||||
mk_fp(decls.second,
|
||||
m_bv_util.mk_numeral(0, ebits),
|
||||
m_bv_util.mk_numeral(0, sbits - 1),
|
||||
np);
|
||||
|
||||
expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m);
|
||||
mk_is_pzero(x, x_is_pzero);
|
||||
mk_is_nzero(y, x_is_nzero);
|
||||
m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero);
|
||||
mk_ite(xyzero, pn, np, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1244,38 +1263,34 @@ expr_ref fpa2bv_converter::mk_max_unspecified(func_decl * f, expr * x, expr * y)
|
|||
expr_ref res(m);
|
||||
|
||||
// The only cases in which max is unspecified for is when the arguments are +0.0 and -0.0.
|
||||
// There is no "hardware interpretation" for fp.max.
|
||||
|
||||
if (m_hi_fp_unspecified)
|
||||
// The hardware interpretation is +0.0.
|
||||
mk_pzero(f, res);
|
||||
else {
|
||||
std::pair<app*, app*> decls(0, 0);
|
||||
if (!m_specials.find(f, decls)) {
|
||||
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
|
||||
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
|
||||
m_specials.insert(f, decls);
|
||||
m.inc_ref(f);
|
||||
m.inc_ref(decls.first);
|
||||
m.inc_ref(decls.second);
|
||||
}
|
||||
|
||||
expr_ref pn(m), np(m);
|
||||
mk_fp(decls.first,
|
||||
m_bv_util.mk_numeral(0, ebits),
|
||||
m_bv_util.mk_numeral(0, sbits - 1),
|
||||
pn);
|
||||
mk_fp(decls.second,
|
||||
m_bv_util.mk_numeral(0, ebits),
|
||||
m_bv_util.mk_numeral(0, sbits - 1),
|
||||
np);
|
||||
|
||||
expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m);
|
||||
mk_is_pzero(x, x_is_pzero);
|
||||
mk_is_nzero(y, x_is_nzero);
|
||||
m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero);
|
||||
mk_ite(xyzero, pn, np, res);
|
||||
std::pair<app*, app*> decls(0, 0);
|
||||
if (!m_specials.find(f, decls)) {
|
||||
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
|
||||
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
|
||||
m_specials.insert(f, decls);
|
||||
m.inc_ref(f);
|
||||
m.inc_ref(decls.first);
|
||||
m.inc_ref(decls.second);
|
||||
}
|
||||
|
||||
expr_ref pn(m), np(m);
|
||||
mk_fp(decls.first,
|
||||
m_bv_util.mk_numeral(0, ebits),
|
||||
m_bv_util.mk_numeral(0, sbits - 1),
|
||||
pn);
|
||||
mk_fp(decls.second,
|
||||
m_bv_util.mk_numeral(0, ebits),
|
||||
m_bv_util.mk_numeral(0, sbits - 1),
|
||||
np);
|
||||
|
||||
expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m);
|
||||
mk_is_pzero(x, x_is_pzero);
|
||||
mk_is_nzero(y, x_is_nzero);
|
||||
m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero);
|
||||
mk_ite(xyzero, pn, np, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -2366,7 +2381,7 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr *
|
|||
|
||||
void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result) {
|
||||
TRACE("fpa2bv_to_fp_real", tout << "rm: " << mk_ismt2_pp(rm, m) << std::endl <<
|
||||
"x: " << mk_ismt2_pp(x, m) << std::endl;);
|
||||
"x: " << mk_ismt2_pp(x, m) << std::endl;);
|
||||
SASSERT(m_util.is_float(s));
|
||||
SASSERT(au().is_real(x) || au().is_int(x));
|
||||
SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
|
@ -2632,8 +2647,8 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar
|
|||
tout << "exp2 = " << mk_ismt2_pp(exp2, m) << std::endl;);
|
||||
|
||||
result = m.mk_ite(x_is_zero, zero, res);
|
||||
result = m.mk_ite(x_is_inf, mk_to_real_unspecified(), result);
|
||||
result = m.mk_ite(x_is_nan, mk_to_real_unspecified(), result);
|
||||
result = m.mk_ite(x_is_inf, mk_to_real_unspecified(ebits, sbits), result);
|
||||
result = m.mk_ite(x_is_nan, mk_to_real_unspecified(ebits, sbits), result);
|
||||
|
||||
SASSERT(is_well_sorted(m, result));
|
||||
}
|
||||
|
@ -2912,9 +2927,29 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con
|
|||
|
||||
void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 1);
|
||||
expr_ref x(m), x_is_nan(m);
|
||||
expr * sgn, * s, * e;
|
||||
split_fp(args[0], sgn, e, s);
|
||||
result = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s);
|
||||
x = args[0];
|
||||
split_fp(x, sgn, e, s);
|
||||
mk_is_nan(x, x_is_nan);
|
||||
|
||||
sort * fp_srt = m.get_sort(x);
|
||||
unsigned ebits = m_util.get_ebits(fp_srt);
|
||||
unsigned sbits = m_util.get_sbits(fp_srt);
|
||||
|
||||
expr_ref nanv(m);
|
||||
if (m_hi_fp_unspecified)
|
||||
// The "hardware interpretation" is 01...10...01.
|
||||
nanv = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1),
|
||||
m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits),
|
||||
m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2),
|
||||
m_bv_util.mk_numeral(1, 1))));
|
||||
else
|
||||
nanv = mk_to_ieee_bv_unspecified(ebits, sbits);
|
||||
|
||||
result = m.mk_ite(x_is_nan, nanv, m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s));
|
||||
|
||||
SASSERT(is_well_sorted(m, result));
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result) {
|
||||
|
@ -2950,7 +2985,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
|
|||
c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero)));
|
||||
else
|
||||
c1 = m.mk_or(x_is_nan, x_is_inf);
|
||||
v1 = mk_to_ubv_unspecified(bv_sz);
|
||||
v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz);
|
||||
dbg_decouple("fpa2bv_to_bv_c1", c1);
|
||||
|
||||
// +-Zero -> 0
|
||||
|
@ -3049,8 +3084,8 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
|
|||
|
||||
dbg_decouple("fpa2bv_to_bv_rnd", rnd);
|
||||
|
||||
result = m.mk_ite(rnd_has_overflown, mk_to_ubv_unspecified(bv_sz), rnd);
|
||||
result = m.mk_ite(c_in_limits, result, mk_to_ubv_unspecified(bv_sz));
|
||||
result = m.mk_ite(rnd_has_overflown, mk_to_ubv_unspecified(ebits, sbits, bv_sz), rnd);
|
||||
result = m.mk_ite(c_in_limits, result, mk_to_ubv_unspecified(ebits, sbits, bv_sz));
|
||||
result = m.mk_ite(c2, v2, result);
|
||||
result = m.mk_ite(c1, v1, result);
|
||||
|
||||
|
@ -3069,25 +3104,100 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg
|
|||
mk_to_bv(f, num, args, true, result);
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned width) {
|
||||
expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
|
||||
expr_ref result(m);
|
||||
if (m_hi_fp_unspecified)
|
||||
return expr_ref(m_bv_util.mk_numeral(0, width), m);
|
||||
else
|
||||
return expr_ref(m_util.mk_internal_to_ubv_unspecified(width), m);
|
||||
result = m_bv_util.mk_numeral(0, width);
|
||||
else {
|
||||
app_ref unspec(m);
|
||||
unspec = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
|
||||
func_decl * unspec_fd = unspec->get_decl();
|
||||
func_decl * fd;
|
||||
if (!m_uf2bvuf.find(unspec_fd, fd)) {
|
||||
app_ref bvc(m);
|
||||
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
|
||||
fd = bvc->get_decl();
|
||||
m_uf2bvuf.insert(unspec_fd, fd);
|
||||
m.inc_ref(unspec_fd);
|
||||
m.inc_ref(fd);
|
||||
}
|
||||
result = m.mk_const(fd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned width) {
|
||||
expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
|
||||
expr_ref result(m);
|
||||
if (m_hi_fp_unspecified)
|
||||
return expr_ref(m_bv_util.mk_numeral(0, width), m);
|
||||
else
|
||||
return expr_ref(m_util.mk_internal_to_sbv_unspecified(width), m);
|
||||
result = m_bv_util.mk_numeral(0, width);
|
||||
else {
|
||||
app_ref unspec(m);
|
||||
unspec = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
|
||||
func_decl * unspec_fd = unspec->get_decl();
|
||||
func_decl * fd;
|
||||
if (!m_uf2bvuf.find(unspec_fd, fd)) {
|
||||
app_ref bvc(m);
|
||||
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
|
||||
fd = bvc->get_decl();
|
||||
m_uf2bvuf.insert(unspec_fd, fd);
|
||||
m.inc_ref(unspec_fd);
|
||||
m.inc_ref(fd);
|
||||
}
|
||||
result = m.mk_const(fd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_to_real_unspecified() {
|
||||
expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) {
|
||||
expr_ref result(m);
|
||||
if (m_hi_fp_unspecified)
|
||||
return expr_ref(m_arith_util.mk_numeral(rational(0), false), m);
|
||||
else
|
||||
return expr_ref(m_util.mk_internal_to_real_unspecified(), m);
|
||||
result = m_arith_util.mk_numeral(rational(0), false);
|
||||
else {
|
||||
app_ref unspec(m);
|
||||
unspec = m_util.mk_internal_to_real_unspecified(ebits, sbits);
|
||||
func_decl * unspec_fd = unspec->get_decl();
|
||||
func_decl * fd;
|
||||
if (!m_uf2bvuf.find(unspec_fd, fd)) {
|
||||
app_ref bvc(m);
|
||||
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
|
||||
fd = bvc->get_decl();
|
||||
m_uf2bvuf.insert(unspec_fd, fd);
|
||||
m.inc_ref(unspec_fd);
|
||||
m.inc_ref(fd);
|
||||
}
|
||||
result = m.mk_const(fd);
|
||||
result = unspec;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) {
|
||||
expr_ref result(m);
|
||||
|
||||
app_ref unspec(m);
|
||||
unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits);
|
||||
func_decl * unspec_fd = unspec->get_decl();
|
||||
func_decl * fd;
|
||||
if (!m_uf2bvuf.find(unspec_fd, fd)) {
|
||||
app_ref bvc(m);
|
||||
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
|
||||
fd = bvc->get_decl();
|
||||
m_uf2bvuf.insert(unspec_fd, fd);
|
||||
m.inc_ref(unspec_fd);
|
||||
m.inc_ref(fd);
|
||||
}
|
||||
result = m.mk_const(fd);
|
||||
|
||||
app_ref mask(m), extra(m);
|
||||
mask = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1),
|
||||
m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits),
|
||||
m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2),
|
||||
m_bv_util.mk_numeral(1, 1))));
|
||||
expr * args[2] = { result, mask };
|
||||
extra = m.mk_eq(m.mk_app(m_bv_util.get_fid(), OP_BAND, 2, args), mask);
|
||||
m_extra_assertions.push_back(extra);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_rm(expr * bv3, expr_ref & result) {
|
||||
|
|
|
@ -134,9 +134,10 @@ public:
|
|||
void mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
virtual expr_ref mk_max_unspecified(func_decl * f, expr * x, expr * y);
|
||||
|
||||
expr_ref mk_to_ubv_unspecified(unsigned width);
|
||||
expr_ref mk_to_sbv_unspecified(unsigned width);
|
||||
expr_ref mk_to_real_unspecified();
|
||||
expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
|
||||
expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
|
||||
expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits);
|
||||
expr_ref mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits);
|
||||
|
||||
void reset(void);
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ fpa2bv_rewriter_cfg::fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c,
|
|||
m_manager(m),
|
||||
m_out(m),
|
||||
m_conv(c),
|
||||
m_bindings(m)
|
||||
m_bindings(m)
|
||||
{
|
||||
updt_params(p);
|
||||
// We need to make sure that the mananger has the BV plugin loaded.
|
||||
|
@ -49,7 +49,7 @@ void fpa2bv_rewriter_cfg::updt_params(params_ref const & p) {
|
|||
updt_local_params(p);
|
||||
}
|
||||
|
||||
bool fpa2bv_rewriter_cfg::max_steps_exceeded(unsigned num_steps) const {
|
||||
bool fpa2bv_rewriter_cfg::max_steps_exceeded(unsigned num_steps) const {
|
||||
cooperate("fpa2bv");
|
||||
return num_steps > m_max_steps;
|
||||
}
|
||||
|
@ -57,22 +57,22 @@ bool fpa2bv_rewriter_cfg::max_steps_exceeded(unsigned num_steps) const {
|
|||
|
||||
br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
TRACE("fpa2bv_rw", tout << "APP: " << f->get_name() << std::endl; );
|
||||
|
||||
|
||||
if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_float(f->get_range())) {
|
||||
m_conv.mk_const(f, result);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
|
||||
if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_rm(f->get_range())) {
|
||||
m_conv.mk_rm_const(f, result);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
|
||||
if (m().is_eq(f)) {
|
||||
SASSERT(num == 2);
|
||||
TRACE("fpa2bv_rw", tout << "(= " << mk_ismt2_pp(args[0], m()) << " " <<
|
||||
TRACE("fpa2bv_rw", tout << "(= " << mk_ismt2_pp(args[0], m()) << " " <<
|
||||
mk_ismt2_pp(args[1], m()) << ")" << std::endl;);
|
||||
SASSERT(m().get_sort(args[0]) == m().get_sort(args[1]));
|
||||
SASSERT(m().get_sort(args[0]) == m().get_sort(args[1]));
|
||||
sort * ds = f->get_domain()[0];
|
||||
if (m_conv.is_float(ds)) {
|
||||
m_conv.mk_eq(args[0], args[1], result);
|
||||
|
@ -100,7 +100,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
|
|||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
||||
if (m_conv.is_float_family(f)) {
|
||||
switch (f->get_decl_kind()) {
|
||||
case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
|
||||
|
@ -108,7 +108,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
|
|||
case OP_FPA_RM_TOWARD_NEGATIVE:
|
||||
case OP_FPA_RM_TOWARD_POSITIVE:
|
||||
case OP_FPA_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE;
|
||||
case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_PLUS_INF: m_conv.mk_pinf(f, result); return BR_DONE;
|
||||
case OP_FPA_MINUS_INF: m_conv.mk_ninf(f, result); return BR_DONE;
|
||||
case OP_FPA_PLUS_ZERO: m_conv.mk_pzero(f, result); return BR_DONE;
|
||||
|
@ -120,7 +120,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
|
|||
case OP_FPA_MUL: m_conv.mk_mul(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE;
|
||||
|
@ -129,7 +129,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
|
|||
case OP_FPA_GT: m_conv.mk_float_gt(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_LE: m_conv.mk_float_le(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_GE: m_conv.mk_float_ge(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_IS_NAN: m_conv.mk_is_nan(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE;
|
||||
|
@ -143,21 +143,23 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
|
|||
case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE;
|
||||
|
||||
|
||||
case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL;
|
||||
case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL;
|
||||
|
||||
|
||||
case OP_FPA_INTERNAL_MIN_UNSPECIFIED: result = m_conv.mk_min_unspecified(f, args[0], args[1]); return BR_DONE;
|
||||
case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_max_unspecified(f, args[0], args[1]); return BR_DONE;
|
||||
case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE;
|
||||
case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE;
|
||||
|
||||
|
||||
case OP_FPA_INTERNAL_RM:
|
||||
case OP_FPA_INTERNAL_BVWRAP:
|
||||
case OP_FPA_INTERNAL_BVUNWRAP:
|
||||
case OP_FPA_INTERNAL_BVWRAP:
|
||||
case OP_FPA_INTERNAL_BVUNWRAP:
|
||||
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: return BR_FAILED;
|
||||
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
|
||||
return BR_FAILED;
|
||||
default:
|
||||
TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n";
|
||||
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
|
||||
|
@ -167,27 +169,27 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
|
|||
else {
|
||||
SASSERT(!m_conv.is_float_family(f));
|
||||
bool is_float_uf = m_conv.is_float(f->get_range()) || m_conv.is_rm(f->get_range());
|
||||
|
||||
|
||||
for (unsigned i = 0; i < f->get_arity(); i++) {
|
||||
sort * di = f->get_domain()[i];
|
||||
is_float_uf |= m_conv.is_float(di) || m_conv.is_rm(di);
|
||||
}
|
||||
|
||||
|
||||
if (is_float_uf) {
|
||||
m_conv.mk_uninterpreted_function(f, num, args, result);
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
bool fpa2bv_rewriter_cfg::pre_visit(expr * t)
|
||||
{
|
||||
TRACE("fpa2bv", tout << "pre_visit: " << mk_ismt2_pp(t, m()) << std::endl;);
|
||||
|
||||
if (is_quantifier(t)) {
|
||||
quantifier * q = to_quantifier(t);
|
||||
|
||||
if (is_quantifier(t)) {
|
||||
quantifier * q = to_quantifier(t);
|
||||
TRACE("fpa2bv", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;);
|
||||
sort_ref_vector new_bindings(m_manager);
|
||||
for (unsigned i = 0 ; i < q->get_num_decls(); i++)
|
||||
|
@ -199,9 +201,9 @@ bool fpa2bv_rewriter_cfg::pre_visit(expr * t)
|
|||
}
|
||||
|
||||
|
||||
bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
|
||||
expr * new_body,
|
||||
expr * const * new_patterns,
|
||||
bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
|
||||
expr * new_body,
|
||||
expr * const * new_patterns,
|
||||
expr * const * new_no_patterns,
|
||||
expr_ref & result,
|
||||
proof_ref & result_pr) {
|
||||
|
@ -221,7 +223,7 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
|
|||
name_buffer.reset();
|
||||
name_buffer << n << ".bv";
|
||||
new_decl_names.push_back(symbol(name_buffer.c_str()));
|
||||
new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits+ebits));
|
||||
new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits+ebits));
|
||||
}
|
||||
else {
|
||||
new_decl_sorts.push_back(s);
|
||||
|
@ -232,19 +234,19 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
|
|||
new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
|
||||
old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
|
||||
result_pr = 0;
|
||||
m_bindings.shrink(old_sz);
|
||||
TRACE("fpa2bv", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " <<
|
||||
m_bindings.shrink(old_sz);
|
||||
TRACE("fpa2bv", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " <<
|
||||
mk_ismt2_pp(old_q->get_expr(), m()) << std::endl <<
|
||||
" new body: " << mk_ismt2_pp(new_body, m()) << std::endl;
|
||||
tout << "result = " << mk_ismt2_pp(result, m()) << std::endl;);
|
||||
tout << "result = " << mk_ismt2_pp(result, m()) << std::endl;);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & result_pr) {
|
||||
bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & result_pr) {
|
||||
if (t->get_idx() >= m_bindings.size())
|
||||
return false;
|
||||
// unsigned inx = m_bindings.size() - t->get_idx() - 1;
|
||||
|
||||
// unsigned inx = m_bindings.size() - t->get_idx() - 1;
|
||||
|
||||
expr_ref new_exp(m());
|
||||
sort * s = t->get_sort();
|
||||
if (m_conv.is_float(s))
|
||||
|
@ -255,14 +257,14 @@ bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & res
|
|||
new_var = m().mk_var(t->get_idx(), m_conv.bu().mk_sort(sbits+ebits));
|
||||
m_conv.mk_fp(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var),
|
||||
m_conv.bu().mk_extract(ebits - 1, 0, new_var),
|
||||
m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var),
|
||||
m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var),
|
||||
new_exp);
|
||||
}
|
||||
else
|
||||
new_exp = m().mk_var(t->get_idx(), s);
|
||||
|
||||
|
||||
result = new_exp;
|
||||
result_pr = 0;
|
||||
result_pr = 0;
|
||||
TRACE("fpa2bv", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -593,7 +593,7 @@ func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_paramet
|
|||
}
|
||||
|
||||
func_decl * fpa_decl_plugin::mk_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (arity != 3)
|
||||
m_manager->raise_exception("invalid number of arguments to fp");
|
||||
if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) ||
|
||||
|
@ -610,7 +610,7 @@ func_decl * fpa_decl_plugin::mk_fp(decl_kind k, unsigned num_parameters, paramet
|
|||
}
|
||||
|
||||
func_decl * fpa_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
SASSERT(m_bv_plugin);
|
||||
if (arity != 2)
|
||||
m_manager->raise_exception("invalid number of arguments to fp.to_ubv");
|
||||
|
@ -631,7 +631,7 @@ func_decl * fpa_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, par
|
|||
}
|
||||
|
||||
func_decl * fpa_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
SASSERT(m_bv_plugin);
|
||||
if (arity != 2)
|
||||
m_manager->raise_exception("invalid number of arguments to fp.to_sbv");
|
||||
|
@ -671,9 +671,9 @@ func_decl * fpa_decl_plugin::mk_to_ieee_bv(decl_kind k, unsigned num_parameters,
|
|||
|
||||
unsigned float_sz = domain[0]->get_parameter(0).get_int() + domain[0]->get_parameter(1).get_int();
|
||||
parameter ps[] = { parameter(float_sz) };
|
||||
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps);
|
||||
sort * bv_srt = m_bv_plugin->mk_sort(BV_SORT, 1, ps);
|
||||
symbol name("to_ieee_bv");
|
||||
return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k));
|
||||
}
|
||||
|
||||
func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
|
@ -693,7 +693,7 @@ func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters
|
|||
func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (arity != 1)
|
||||
m_manager->raise_exception("invalid number of arguments to internal_bv_wrap");
|
||||
m_manager->raise_exception("invalid number of arguments to bv_wrap");
|
||||
if (!is_float_sort(domain[0]) && !is_rm_sort(domain[0]))
|
||||
m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint or RoundingMode sort");
|
||||
|
||||
|
@ -714,7 +714,7 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param
|
|||
func_decl * fpa_decl_plugin::mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (arity != 1)
|
||||
m_manager->raise_exception("invalid number of arguments to internal_bv_unwrap");
|
||||
m_manager->raise_exception("invalid number of arguments to bv_unwrap");
|
||||
if (!is_sort_of(domain[0], m_bv_fid, BV_SORT))
|
||||
m_manager->raise_exception("sort mismatch, expected argument of bitvector sort");
|
||||
if (!is_float_sort(range) && !is_rm_sort(range))
|
||||
|
@ -728,12 +728,12 @@ func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified(
|
|||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (arity != 0)
|
||||
m_manager->raise_exception("invalid number of arguments to fp.to_ubv_unspecified");
|
||||
if (num_parameters != 1)
|
||||
m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 1");
|
||||
if (!parameters[0].is_int())
|
||||
m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting an integer");
|
||||
if (num_parameters != 3)
|
||||
m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 3");
|
||||
if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int())
|
||||
m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting 3 integers");
|
||||
|
||||
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, parameters);
|
||||
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ¶meters[2]);
|
||||
return m_manager->mk_func_decl(symbol("fp.to_ubv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
}
|
||||
|
||||
|
@ -741,12 +741,13 @@ func_decl * fpa_decl_plugin::mk_internal_to_sbv_unspecified(
|
|||
decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (arity != 0)
|
||||
m_manager->raise_exception("invalid number of arguments to internal_to_sbv_unspecified");
|
||||
if (num_parameters != 1)
|
||||
m_manager->raise_exception("invalid number of parameters to fp.to_sbv_unspecified; expecting 1");
|
||||
if (!parameters[0].is_int())
|
||||
m_manager->raise_exception("invalid parameters type provided to fp.to_sbv_unspecified; expecting an integer");
|
||||
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, parameters);
|
||||
m_manager->raise_exception("invalid number of arguments to fp.to_sbv_unspecified");
|
||||
if (num_parameters != 3)
|
||||
m_manager->raise_exception("invalid number of parameters to fp.to_sbv_unspecified; expecting 3");
|
||||
if (!parameters[0].is_int() || !parameters[1].is_int() || !parameters[2].is_int())
|
||||
m_manager->raise_exception("invalid parameters type provided to fp.to_sbv_unspecified; expecting 3 integers");
|
||||
|
||||
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ¶meters[2]);
|
||||
return m_manager->mk_func_decl(symbol("fp.to_sbv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
}
|
||||
|
||||
|
@ -754,13 +755,32 @@ func_decl * fpa_decl_plugin::mk_internal_to_real_unspecified(
|
|||
decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (arity != 0)
|
||||
m_manager->raise_exception("invalid number of arguments to internal_to_real_unspecified");
|
||||
m_manager->raise_exception("invalid number of arguments to fp.to_real_unspecified");
|
||||
if (num_parameters != 2)
|
||||
m_manager->raise_exception("invalid number of parameters to fp.to_real_unspecified; expecting 2");
|
||||
if (!parameters[0].is_int() || !parameters[1].is_int())
|
||||
m_manager->raise_exception("invalid parameters type provided to fp.to_real_unspecified; expecting 2 integers");
|
||||
if (!is_sort_of(range, m_arith_fid, REAL_SORT))
|
||||
m_manager->raise_exception("sort mismatch, expected range of FloatingPoint sort");
|
||||
m_manager->raise_exception("sort mismatch, expected range of Real sort");
|
||||
|
||||
return m_manager->mk_func_decl(symbol("fp.to_real_unspecified"), 0, domain, m_real_sort, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
}
|
||||
|
||||
func_decl * fpa_decl_plugin::mk_internal_to_ieee_bv_unspecified(
|
||||
decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
if (arity != 0)
|
||||
m_manager->raise_exception("invalid number of arguments to to_ieee_bv_unspecified; expecting none");
|
||||
if (num_parameters != 2)
|
||||
m_manager->raise_exception("invalid number of parameters to to_ieee_bv_unspecified; expecting 2");
|
||||
if (!parameters[0].is_int() || !parameters[1].is_int())
|
||||
m_manager->raise_exception("invalid parameters type provided to to_ieee_bv_unspecified; expecting 2 integers");
|
||||
|
||||
parameter width_p[1] = { parameter(parameters[0].get_int() + parameters[1].get_int()) };
|
||||
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, width_p);
|
||||
return m_manager->mk_func_decl(symbol("to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
}
|
||||
|
||||
|
||||
func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
|
@ -846,6 +866,8 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
return mk_internal_to_sbv_unspecified(k, num_parameters, parameters, arity, domain, range);
|
||||
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
|
||||
return mk_internal_to_real_unspecified(k, num_parameters, parameters, arity, domain, range);
|
||||
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
|
||||
return mk_internal_to_ieee_bv_unspecified(k, num_parameters, parameters, arity, domain, range);
|
||||
default:
|
||||
m_manager->raise_exception("unsupported floating point operator");
|
||||
return 0;
|
||||
|
@ -1045,25 +1067,26 @@ app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) {
|
|||
return mk_value(v);
|
||||
}
|
||||
|
||||
app * fpa_util::mk_internal_to_ubv_unspecified(unsigned width) {
|
||||
parameter ps[] = { parameter(width) };
|
||||
app * fpa_util::mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
|
||||
parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) };
|
||||
sort * range = m_bv_util.mk_sort(width);
|
||||
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 1, ps, 0, 0, range);
|
||||
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 3, ps, 0, 0, range);
|
||||
}
|
||||
|
||||
app * fpa_util::mk_internal_to_sbv_unspecified(unsigned width) {
|
||||
parameter ps[] = { parameter(width) };
|
||||
app * fpa_util::mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
|
||||
parameter ps[] = { parameter(ebits), parameter(sbits), parameter(width) };
|
||||
sort * range = m_bv_util.mk_sort(width);
|
||||
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 1, ps, 0, 0, range);
|
||||
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 3, ps, 0, 0, range);
|
||||
}
|
||||
|
||||
app * fpa_util::mk_internal_to_ieee_bv_unspecified(unsigned width) {
|
||||
parameter ps[] = { parameter(width) };
|
||||
sort * range = m_bv_util.mk_sort(width);
|
||||
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 1, ps, 0, 0, range);
|
||||
app * fpa_util::mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) {
|
||||
parameter ps[] = { parameter(ebits), parameter(sbits) };
|
||||
sort * range = m_bv_util.mk_sort(ebits+sbits);
|
||||
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED, 2, ps, 0, 0, range);
|
||||
}
|
||||
|
||||
app * fpa_util::mk_internal_to_real_unspecified() {
|
||||
app * fpa_util::mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits) {
|
||||
parameter ps[] = { parameter(ebits), parameter(sbits) };
|
||||
sort * range = m_a_util.mk_real();
|
||||
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 0, 0, 0, 0, range);
|
||||
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 2, ps, 0, 0, range);
|
||||
}
|
||||
|
|
|
@ -177,11 +177,29 @@ class fpa_decl_plugin : public decl_plugin {
|
|||
unsigned arity, sort * const * domain, sort * range);
|
||||
func_decl * mk_internal_to_real_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range);
|
||||
func_decl * mk_internal_to_ieee_bv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range);
|
||||
|
||||
virtual void set_manager(ast_manager * m, family_id id);
|
||||
unsigned mk_id(mpf const & v);
|
||||
void recycled_id(unsigned id);
|
||||
|
||||
virtual bool is_considered_uninterpreted(func_decl * f) {
|
||||
if (f->get_family_id() != get_family_id())
|
||||
return false;
|
||||
switch (f->get_decl_kind())
|
||||
{
|
||||
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
|
||||
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
fpa_decl_plugin();
|
||||
|
||||
|
@ -344,10 +362,10 @@ public:
|
|||
|
||||
app * mk_to_ieee_bv(expr * arg1) { return m().mk_app(m_fid, OP_FPA_TO_IEEE_BV, arg1); }
|
||||
|
||||
app * mk_internal_to_ubv_unspecified(unsigned width);
|
||||
app * mk_internal_to_sbv_unspecified(unsigned width);
|
||||
app * mk_internal_to_ieee_bv_unspecified(unsigned width);
|
||||
app * mk_internal_to_real_unspecified();
|
||||
app * mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
|
||||
app * mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
|
||||
app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits);
|
||||
app * mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits);
|
||||
|
||||
bool is_wrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); }
|
||||
bool is_unwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVUNWRAP); }
|
||||
|
|
|
@ -638,9 +638,13 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
set_curr_sort(m().get_sort(arg1));
|
||||
numeral v1, v2;
|
||||
bool is_int;
|
||||
if (m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) {
|
||||
if (m_util.is_numeral(arg2, v2, is_int)) {
|
||||
SASSERT(!is_int);
|
||||
if (m_util.is_numeral(arg1, v1, is_int)) {
|
||||
if (v2.is_zero()) {
|
||||
result = m_util.mk_div0(arg1);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
else if (m_util.is_numeral(arg1, v1, is_int)) {
|
||||
result = m_util.mk_numeral(v1/v2, false);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
@ -691,6 +695,10 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu
|
|||
result = m_util.mk_numeral(div(v1, v2), is_int);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.is_numeral(arg2, v2, is_int) && v2.is_zero()) {
|
||||
result = m_util.mk_idiv0(arg1);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
|
|
@ -892,7 +892,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e
|
|||
if (r2.is_zero()) {
|
||||
if (!hi_div0) {
|
||||
result = m().mk_app(get_fid(), OP_BUREM0, arg1);
|
||||
return BR_DONE;
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
else {
|
||||
// The "hardware interpretation" for (bvurem x 0) is x
|
||||
|
|
|
@ -30,6 +30,14 @@ void expr_safe_replace::insert(expr* src, expr* dst) {
|
|||
m_subst.insert(src, dst);
|
||||
}
|
||||
|
||||
void expr_safe_replace::operator()(expr_ref_vector& es) {
|
||||
expr_ref val(m);
|
||||
for (unsigned i = 0; i < es.size(); ++i) {
|
||||
(*this)(es[i].get(), val);
|
||||
es[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
void expr_safe_replace::operator()(expr* e, expr_ref& res) {
|
||||
m_todo.push_back(e);
|
||||
expr* a, *b;
|
||||
|
|
|
@ -42,6 +42,8 @@ public:
|
|||
|
||||
void operator()(expr* src, expr_ref& e);
|
||||
|
||||
void operator()(expr_ref_vector& es);
|
||||
|
||||
void apply_substitution(expr* s, expr* def, expr_ref& t);
|
||||
|
||||
void reset();
|
||||
|
|
|
@ -102,11 +102,10 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
case OP_FPA_INTERNAL_RM:
|
||||
SASSERT(num_args == 1); st = mk_rm(args[0], result); break;
|
||||
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
|
||||
SASSERT(num_args == 0); st = mk_to_ubv_unspecified(f, result); break;
|
||||
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
|
||||
SASSERT(num_args == 0); st = mk_to_sbv_unspecified(f, result); break;
|
||||
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
|
||||
SASSERT(num_args == 0); st = mk_to_real_unspecified(result); break;
|
||||
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
|
||||
st = BR_FAILED;
|
||||
|
||||
case OP_FPA_INTERNAL_BVWRAP:
|
||||
case OP_FPA_INTERNAL_BVUNWRAP:
|
||||
|
@ -119,57 +118,34 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
return st;
|
||||
}
|
||||
|
||||
br_status fpa_rewriter::mk_to_ubv_unspecified(func_decl * f, expr_ref & result) {
|
||||
SASSERT(f->get_num_parameters() == 1);
|
||||
SASSERT(f->get_parameter(0).is_int());
|
||||
unsigned bv_sz = f->get_parameter(0).get_int();
|
||||
|
||||
br_status fpa_rewriter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) {
|
||||
bv_util bu(m());
|
||||
if (m_hi_fp_unspecified)
|
||||
// The "hardware interpretation" is 0.
|
||||
result = bu.mk_numeral(0, bv_sz);
|
||||
result = bu.mk_numeral(0, width);
|
||||
else
|
||||
result = m_util.mk_internal_to_ubv_unspecified(bv_sz);
|
||||
result = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
|
||||
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
br_status fpa_rewriter::mk_to_sbv_unspecified(func_decl * f, expr_ref & result) {
|
||||
SASSERT(f->get_num_parameters() == 1);
|
||||
SASSERT(f->get_parameter(0).is_int());
|
||||
unsigned bv_sz = f->get_parameter(0).get_int();
|
||||
|
||||
br_status fpa_rewriter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) {
|
||||
bv_util bu(m());
|
||||
if (m_hi_fp_unspecified)
|
||||
// The "hardware interpretation" is 0.
|
||||
result = bu.mk_numeral(0, bv_sz);
|
||||
result = bu.mk_numeral(0, width);
|
||||
else
|
||||
result = m_util.mk_internal_to_sbv_unspecified(bv_sz);
|
||||
result = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
|
||||
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
br_status fpa_rewriter::mk_to_ieee_bv_unspecified(func_decl * f, expr_ref & result) {
|
||||
SASSERT(f->get_num_parameters() == 1);
|
||||
SASSERT(f->get_parameter(0).is_int());
|
||||
unsigned bv_sz = f->get_parameter(0).get_int();
|
||||
|
||||
bv_util bu(m());
|
||||
if (m_hi_fp_unspecified)
|
||||
// The "hardware interpretation" is 0.
|
||||
result = bu.mk_numeral(0, bv_sz);
|
||||
else
|
||||
result = m_util.mk_internal_to_ieee_bv_unspecified(bv_sz);
|
||||
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
br_status fpa_rewriter::mk_to_real_unspecified(expr_ref & result) {
|
||||
br_status fpa_rewriter::mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result) {
|
||||
if (m_hi_fp_unspecified)
|
||||
// The "hardware interpretation" is 0.
|
||||
result = m_util.au().mk_numeral(rational(0), false);
|
||||
else
|
||||
result = m_util.mk_internal_to_real_unspecified();
|
||||
result = m_util.mk_internal_to_real_unspecified(ebits, sbits);
|
||||
|
||||
return BR_DONE;
|
||||
}
|
||||
|
@ -801,9 +777,10 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
|
|||
|
||||
if (m_util.is_rm_numeral(arg1, rmv) &&
|
||||
m_util.is_numeral(arg2, v)) {
|
||||
const mpf & x = v.get();
|
||||
|
||||
if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v)) {
|
||||
mk_to_ubv_unspecified(f, result);
|
||||
mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
|
@ -818,7 +795,7 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
|
|||
if (r >= ll && r <= ul)
|
||||
result = bu.mk_numeral(r, bv_sz);
|
||||
else
|
||||
mk_to_ubv_unspecified(f, result);
|
||||
mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
|
@ -834,9 +811,10 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_
|
|||
|
||||
if (m_util.is_rm_numeral(arg1, rmv) &&
|
||||
m_util.is_numeral(arg2, v)) {
|
||||
const mpf & x = v.get();
|
||||
|
||||
if (m_fm.is_nan(v) || m_fm.is_inf(v)) {
|
||||
mk_to_sbv_unspecified(f, result);
|
||||
mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
|
@ -851,7 +829,7 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_
|
|||
if (r >= ll && r <= ul)
|
||||
result = bu.mk_numeral(r, bv_sz);
|
||||
else
|
||||
mk_to_sbv_unspecified(f, result);
|
||||
mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
|
@ -862,17 +840,35 @@ br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & resu
|
|||
scoped_mpf v(m_fm);
|
||||
|
||||
if (m_util.is_numeral(arg, v)) {
|
||||
bv_util bu(m());
|
||||
const mpf & x = v.get();
|
||||
|
||||
if (m_fm.is_nan(v) || m_fm.is_inf(v)) {
|
||||
mk_to_ieee_bv_unspecified(f, result);
|
||||
if (m_fm.is_nan(v)) {
|
||||
if (m_hi_fp_unspecified) {
|
||||
result = bu.mk_concat(bu.mk_numeral(0, 1),
|
||||
bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()),
|
||||
bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2),
|
||||
bu.mk_numeral(1, 1))));
|
||||
}
|
||||
else {
|
||||
app_ref unspec(m()), mask(m()), extra(m());
|
||||
unspec = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits());
|
||||
mask = bu.mk_concat(bu.mk_numeral(0, 1),
|
||||
bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()),
|
||||
bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2),
|
||||
bu.mk_numeral(1, 1))));
|
||||
expr * args[2] = { unspec, mask };
|
||||
result = m().mk_app(bu.get_fid(), OP_BOR, 2, args);
|
||||
}
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
else {
|
||||
scoped_mpz rz(m_fm.mpq_manager());
|
||||
m_fm.to_ieee_bv_mpz(v, rz);
|
||||
|
||||
bv_util bu(m());
|
||||
scoped_mpz rz(m_fm.mpq_manager());
|
||||
m_fm.to_ieee_bv_mpz(v, rz);
|
||||
result = bu.mk_numeral(rational(rz), v.get().get_ebits() + v.get().get_sbits());
|
||||
return BR_DONE;
|
||||
result = bu.mk_numeral(rational(rz), x.get_ebits() + x.get_sbits());
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
return BR_FAILED;
|
||||
|
@ -883,7 +879,8 @@ br_status fpa_rewriter::mk_to_real(expr * arg, expr_ref & result) {
|
|||
|
||||
if (m_util.is_numeral(arg, v)) {
|
||||
if (m_fm.is_nan(v) || m_fm.is_inf(v)) {
|
||||
result = m_util.mk_internal_to_real_unspecified();
|
||||
const mpf & x = v.get();
|
||||
result = m_util.mk_internal_to_real_unspecified(x.get_ebits(), x.get_sbits());
|
||||
}
|
||||
else {
|
||||
scoped_mpq r(m_fm.mpq_manager());
|
||||
|
|
|
@ -86,10 +86,9 @@ public:
|
|||
br_status mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result);
|
||||
br_status mk_to_real(expr * arg, expr_ref & result);
|
||||
|
||||
br_status mk_to_ubv_unspecified(func_decl * f, expr_ref & result);
|
||||
br_status mk_to_sbv_unspecified(func_decl * f, expr_ref & result);
|
||||
br_status mk_to_ieee_bv_unspecified(func_decl * f, expr_ref & result);
|
||||
br_status mk_to_real_unspecified(expr_ref & result);
|
||||
br_status mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result);
|
||||
br_status mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result);
|
||||
br_status mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
53
src/ast/rewriter/label_rewriter.cpp
Normal file
53
src/ast/rewriter/label_rewriter.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
label_rewriter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic rewriting rules for removing labels.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-19-10
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
#include"rewriter.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"label_rewriter.h"
|
||||
|
||||
|
||||
label_rewriter::label_rewriter(ast_manager & m) :
|
||||
m_label_fid(m.get_label_family_id()),
|
||||
m_rwr(m, false, *this) {}
|
||||
|
||||
label_rewriter::~label_rewriter() {}
|
||||
|
||||
br_status label_rewriter::reduce_app(
|
||||
func_decl * f, unsigned num, expr * const * args, expr_ref & result,
|
||||
proof_ref & result_pr) {
|
||||
if (is_decl_of(f, m_label_fid, OP_LABEL)) {
|
||||
SASSERT(num == 1);
|
||||
result = args[0];
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
void label_rewriter::remove_labels(expr_ref& fml, proof_ref& pr) {
|
||||
ast_manager& m = fml.get_manager();
|
||||
expr_ref tmp(m);
|
||||
m_rwr(fml, tmp);
|
||||
if (pr && fml != tmp) {
|
||||
pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp));
|
||||
}
|
||||
fml = tmp;
|
||||
}
|
||||
|
||||
|
||||
//template class rewriter_tpl<label_rewriter>;
|
41
src/ast/rewriter/label_rewriter.h
Normal file
41
src/ast/rewriter/label_rewriter.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
label_rewriter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic rewriting rules for labels.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-19-10
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef LABEL_REWRITER_H_
|
||||
#define LABEL_REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"rewriter_types.h"
|
||||
|
||||
|
||||
class label_rewriter : public default_rewriter_cfg {
|
||||
family_id m_label_fid;
|
||||
rewriter_tpl<label_rewriter> m_rwr;
|
||||
public:
|
||||
label_rewriter(ast_manager & m);
|
||||
~label_rewriter();
|
||||
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
|
||||
proof_ref & result_pr);
|
||||
|
||||
|
||||
void remove_labels(expr_ref& fml, proof_ref& pr);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -73,7 +73,7 @@ public:
|
|||
unsigned nd = q->get_num_decls();
|
||||
for (unsigned i = 0; i < nd; ++i) {
|
||||
sort* s = q->get_decl_sort(i);
|
||||
app* a = m.mk_fresh_const("x", s);
|
||||
app* a = m.mk_fresh_const(q->get_decl_name(i).str().c_str(), s);
|
||||
vars.push_back(a);
|
||||
}
|
||||
expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd);
|
||||
|
@ -154,9 +154,7 @@ private:
|
|||
}
|
||||
|
||||
quantifier_type& negate(quantifier_type& qt) {
|
||||
TRACE("qe", display(qt, tout); tout << "\n";);
|
||||
qt = static_cast<quantifier_type>(qt ^0x1);
|
||||
TRACE("qe", display(qt, tout); tout << "\n";);
|
||||
return qt;
|
||||
}
|
||||
|
||||
|
@ -205,6 +203,7 @@ private:
|
|||
case AST_APP: {
|
||||
expr_ref_vector args(m);
|
||||
expr_ref tmp(m);
|
||||
expr* t1, *t2, *t3;
|
||||
unsigned num_args = 0;
|
||||
app* a = to_app(fml);
|
||||
if (m.is_and(fml)) {
|
||||
|
@ -228,16 +227,35 @@ private:
|
|||
negate(qt);
|
||||
result = m.mk_not(tmp);
|
||||
}
|
||||
else if (m.is_implies(fml)) {
|
||||
pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp);
|
||||
else if (m.is_implies(fml, t1, t2)) {
|
||||
pull_quantifier(t1, negate(qt), vars, tmp);
|
||||
negate(qt);
|
||||
pull_quantifier(to_app(fml)->get_arg(1), qt, vars, result);
|
||||
pull_quantifier(t2, qt, vars, result);
|
||||
result = m.mk_implies(tmp, result);
|
||||
}
|
||||
else if (m.is_ite(fml)) {
|
||||
pull_quantifier(to_app(fml)->get_arg(1), qt, vars, tmp);
|
||||
pull_quantifier(to_app(fml)->get_arg(2), qt, vars, result);
|
||||
result = m.mk_ite(to_app(fml)->get_arg(0), tmp, result);
|
||||
else if (m.is_ite(fml, t1, t2, t3)) {
|
||||
expr_ref tt1(m), tt2(m), tt3(m), ntt1(m), nt1(m);
|
||||
pull_quantifier(t2, qt, vars, tt2);
|
||||
pull_quantifier(t3, qt, vars, tt3);
|
||||
if (has_quantifiers(t1)) {
|
||||
pull_quantifier(t1, qt, vars, tt1);
|
||||
nt1 = m.mk_not(t1);
|
||||
pull_quantifier(nt1, qt, vars, ntt1);
|
||||
result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(tt1, tt3));
|
||||
}
|
||||
else {
|
||||
result = m.mk_ite(t1, tt2, tt3);
|
||||
}
|
||||
}
|
||||
else if ((m.is_eq(fml, t1, t2) && m.is_bool(t1)) || m.is_iff(fml, t1, t2)) {
|
||||
expr_ref tt1(m), tt2(m), ntt1(m), ntt2(m), nt1(m), nt2(m);
|
||||
pull_quantifier(t1, qt, vars, tt1);
|
||||
pull_quantifier(t2, qt, vars, tt2);
|
||||
nt1 = m.mk_not(t1);
|
||||
nt2 = m.mk_not(t2);
|
||||
pull_quantifier(nt1, qt, vars, ntt1);
|
||||
pull_quantifier(nt2, qt, vars, ntt2);
|
||||
result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(ntt2, tt1));
|
||||
}
|
||||
else {
|
||||
// the formula contains a quantifier, but it is "inaccessible"
|
||||
|
|
|
@ -595,6 +595,9 @@ void rewriter_tpl<Config>::set_inv_bindings(unsigned num_bindings, expr * const
|
|||
template<typename Config>
|
||||
template<bool ProofGen>
|
||||
void rewriter_tpl<Config>::main_loop(expr * t, expr_ref & result, proof_ref & result_pr) {
|
||||
if (m().canceled()) {
|
||||
throw rewriter_exception(m().limit().get_cancel_msg());
|
||||
}
|
||||
SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size());
|
||||
SASSERT(not_rewriting());
|
||||
m_root = t;
|
||||
|
|
|
@ -246,6 +246,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
|
|||
expr_ref _stop(bv.mk_numeral(stop, nb), m);
|
||||
expr_ref _pred(m.mk_not(m.mk_and(bv.mk_ule(_start, v), bv.mk_ule(v, _stop))), m);
|
||||
a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s));
|
||||
display_expr1 disp(m);
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp););
|
||||
return a.detach();
|
||||
}
|
||||
else if (u.re.is_to_re(e0, e1) && u.str.is_string(e1, s1) && s1.length() == 1) {
|
||||
|
@ -255,6 +257,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
|
|||
expr_ref _ch(bv.mk_numeral(s1[0], nb), m);
|
||||
expr_ref _pred(m.mk_not(m.mk_eq(v, _ch)), m);
|
||||
a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s));
|
||||
display_expr1 disp(m);
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp););
|
||||
return a.detach();
|
||||
}
|
||||
else if (u.re.is_to_re(e0, e1) && u.str.is_unit(e1, e2)) {
|
||||
|
@ -262,6 +266,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
|
|||
expr_ref v(m.mk_var(0, s), m);
|
||||
expr_ref _pred(m.mk_not(m.mk_eq(v, e2)), m);
|
||||
a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s));
|
||||
display_expr1 disp(m);
|
||||
TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp););
|
||||
return a.detach();
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -578,6 +578,16 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
return st;
|
||||
}
|
||||
|
||||
expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args) {
|
||||
expr_ref result(m());
|
||||
proof_ref pr(m());
|
||||
if (BR_FAILED == reduce_app(f, num_args, args, result, pr)) {
|
||||
result = m().mk_app(f, num_args, args);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool reduce_quantifier(quantifier * old_q,
|
||||
expr * new_body,
|
||||
expr * const * new_patterns,
|
||||
|
@ -695,6 +705,9 @@ struct th_rewriter::imp : public rewriter_tpl<th_rewriter_cfg> {
|
|||
rewriter_tpl<th_rewriter_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m, p) {
|
||||
}
|
||||
expr_ref mk_app(func_decl* f, unsigned sz, expr* const* args) {
|
||||
return m_cfg.mk_app(f, sz, args);
|
||||
}
|
||||
};
|
||||
|
||||
th_rewriter::th_rewriter(ast_manager & m, params_ref const & p):
|
||||
|
@ -776,3 +789,7 @@ void th_rewriter::reset_used_dependencies() {
|
|||
m_imp->cfg().m_used_dependencies = 0;
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref th_rewriter::mk_app(func_decl* f, unsigned num_args, expr* const* args) {
|
||||
return m_imp->mk_app(f, num_args, args);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
|
||||
void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result);
|
||||
|
||||
expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args);
|
||||
|
||||
void cleanup();
|
||||
void reset();
|
||||
|
||||
|
|
|
@ -112,6 +112,11 @@ zstring::zstring(zstring const& other) {
|
|||
m_encoding = other.m_encoding;
|
||||
}
|
||||
|
||||
zstring::zstring(unsigned sz, unsigned const* s, encoding enc) {
|
||||
m_buffer.append(sz, s);
|
||||
m_encoding = enc;
|
||||
}
|
||||
|
||||
zstring::zstring(unsigned num_bits, bool const* ch) {
|
||||
SASSERT(num_bits == 8 || num_bits == 16);
|
||||
m_encoding = (num_bits == 8)?ascii:unicode;
|
||||
|
@ -578,6 +583,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
case OP_RE_OF_PRED:
|
||||
case OP_STRING_ITOS:
|
||||
case OP_STRING_STOI:
|
||||
case OP_RE_COMPLEMENT:
|
||||
match(*m_sigs[k], arity, domain, range, rng);
|
||||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
|
||||
|
||||
|
@ -632,7 +638,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
default:
|
||||
m.raise_exception("Incorrect number of arguments passed to loop. Expected 1 regular expression and two integer parameters");
|
||||
}
|
||||
|
||||
|
||||
|
||||
case OP_STRING_CONST:
|
||||
if (!(num_parameters == 1 && arity == 0 && parameters[0].is_symbol())) {
|
||||
|
@ -641,7 +647,6 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
return m.mk_const_decl(m_stringc_sym, m_string,
|
||||
func_decl_info(m_family_id, OP_STRING_CONST, num_parameters, parameters));
|
||||
|
||||
case OP_RE_COMPLEMENT:
|
||||
case OP_RE_UNION:
|
||||
case OP_RE_CONCAT:
|
||||
case OP_RE_INTERSECT:
|
||||
|
@ -761,10 +766,27 @@ app* seq_decl_plugin::mk_string(zstring const& s) {
|
|||
|
||||
|
||||
bool seq_decl_plugin::is_value(app* e) const {
|
||||
return
|
||||
is_app_of(e, m_family_id, OP_SEQ_EMPTY) ||
|
||||
(is_app_of(e, m_family_id, OP_SEQ_UNIT) &&
|
||||
m_manager->is_value(e->get_arg(0)));
|
||||
while (true) {
|
||||
if (is_app_of(e, m_family_id, OP_SEQ_EMPTY)) {
|
||||
return true;
|
||||
}
|
||||
if (is_app_of(e, m_family_id, OP_STRING_CONST)) {
|
||||
return true;
|
||||
}
|
||||
if (is_app_of(e, m_family_id, OP_SEQ_UNIT) &&
|
||||
m_manager->is_value(e->get_arg(0))) {
|
||||
return true;
|
||||
}
|
||||
if (is_app_of(e, m_family_id, OP_SEQ_CONCAT) &&
|
||||
e->get_num_args() == 2 &&
|
||||
is_app(e->get_arg(0)) &&
|
||||
is_app(e->get_arg(1)) &&
|
||||
is_value(to_app(e->get_arg(0)))) {
|
||||
e = to_app(e->get_arg(1));
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
expr* seq_decl_plugin::get_some_value(sort* s) {
|
||||
|
|
|
@ -95,6 +95,7 @@ private:
|
|||
public:
|
||||
zstring(encoding enc = ascii);
|
||||
zstring(char const* s, encoding enc = ascii);
|
||||
zstring(unsigned sz, unsigned const* s, encoding enc = ascii);
|
||||
zstring(zstring const& other);
|
||||
zstring(unsigned num_bits, bool const* ch);
|
||||
zstring(unsigned ch, encoding enc = ascii);
|
||||
|
|
|
@ -406,8 +406,9 @@ bool arith_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * co
|
|||
case OP_POWER: return false;
|
||||
case OP_ABS: SASSERT(num_args == 1); mk_abs(args[0], result); break;
|
||||
case OP_IRRATIONAL_ALGEBRAIC_NUM: return false;
|
||||
case OP_DIV_0: return false;
|
||||
case OP_IDIV_0: return false;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
TRACE("arith_simplifier_plugin", tout << mk_pp(result.get(), m_manager) << "\n";);
|
||||
|
|
|
@ -473,6 +473,7 @@ void simplifier::mk_app(func_decl * decl, unsigned num_args, expr * const * args
|
|||
//dump_rewrite_lemma(decl, num_args, args, result.get());
|
||||
return;
|
||||
}
|
||||
|
||||
result = m.mk_app(decl, num_args, args);
|
||||
}
|
||||
|
||||
|
|
|
@ -303,8 +303,8 @@ public:
|
|||
goal_ref g = alloc(goal, m, ctx.produce_proofs(), ctx.produce_models(), ctx.produce_unsat_cores());
|
||||
assert_exprs_from(ctx, *g);
|
||||
|
||||
unsigned timeout = p.get_uint("timeout", UINT_MAX);
|
||||
unsigned rlimit = p.get_uint("rlimit", 0);
|
||||
unsigned timeout = p.get_uint("timeout", ctx.params().m_timeout);
|
||||
unsigned rlimit = p.get_uint("rlimit", ctx.params().m_rlimit);
|
||||
|
||||
goal_ref_buffer result_goals;
|
||||
model_converter_ref mc;
|
||||
|
|
|
@ -539,7 +539,6 @@ namespace algebraic_numbers {
|
|||
}
|
||||
|
||||
bool factor(scoped_upoly const & up, factors & r) {
|
||||
// std::cout << "factor: "; upm().display(std::cout, up); std::cout << std::endl;
|
||||
if (m_factor) {
|
||||
return upm().factor(up, r, m_factor_params);
|
||||
}
|
||||
|
@ -547,7 +546,7 @@ namespace algebraic_numbers {
|
|||
scoped_upoly & up_sqf = m_isolate_tmp3;
|
||||
up_sqf.reset();
|
||||
upm().square_free(up.size(), up.c_ptr(), up_sqf);
|
||||
TRACE("anum_bug", upm().display(tout, up_sqf.size(), up_sqf.c_ptr()); tout << "\n";);
|
||||
TRACE("algebraic", upm().display(tout, up_sqf.size(), up_sqf.c_ptr()); tout << "\n";);
|
||||
r.push_back(up_sqf, 1);
|
||||
return false;
|
||||
}
|
||||
|
@ -566,6 +565,7 @@ namespace algebraic_numbers {
|
|||
}
|
||||
|
||||
void isolate_roots(scoped_upoly const & up, numeral_vector & roots) {
|
||||
TRACE("algebraic", upm().display(tout, up); tout << "\n";);
|
||||
if (up.empty())
|
||||
return; // ignore the zero polynomial
|
||||
factors & fs = m_isolate_factors;
|
||||
|
@ -586,6 +586,7 @@ namespace algebraic_numbers {
|
|||
upolynomial::numeral_vector const & f = fs[i];
|
||||
// polynomial f contains the non zero roots
|
||||
unsigned d = upm().degree(f);
|
||||
TRACE("algebraic", tout << "factor " << i << " degree: " << d << "\n";);
|
||||
if (d == 0)
|
||||
continue; // found all roots of f
|
||||
scoped_mpq r(qm());
|
||||
|
@ -601,8 +602,9 @@ namespace algebraic_numbers {
|
|||
}
|
||||
SASSERT(m_isolate_roots.empty() && m_isolate_lowers.empty() && m_isolate_uppers.empty());
|
||||
upm().sqf_isolate_roots(f.size(), f.c_ptr(), bqm(), m_isolate_roots, m_isolate_lowers, m_isolate_uppers);
|
||||
// collect rational/basic roots
|
||||
// collect rational/basic roots
|
||||
unsigned sz = m_isolate_roots.size();
|
||||
TRACE("algebraic", tout << "isolated roots: " << sz << "\n";);
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
to_mpq(qm(), m_isolate_roots[i], r);
|
||||
roots.push_back(numeral(mk_basic_cell(r)));
|
||||
|
|
|
@ -111,7 +111,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
|
|||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
result_pr = 0;
|
||||
family_id fid = f->get_family_id();
|
||||
if (fid == null_family_id && num == 0) {
|
||||
if (num == 0 && (fid == null_family_id || m().get_plugin(f->get_family_id())->is_considered_uninterpreted(f))) {
|
||||
expr * val = m_model.get_const_interp(f);
|
||||
if (val != 0) {
|
||||
result = val;
|
||||
|
@ -178,7 +178,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
|
|||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
TRACE("model_evaluator", tout << f->get_name() << "\n";);
|
||||
CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";);
|
||||
return st;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,5 @@ def_module_params('model',
|
|||
('v1', BOOL, False, 'use Z3 version 1.x pretty printer'),
|
||||
('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) pretty printer'),
|
||||
('compact', BOOL, False, 'try to compact function graph (i.e., function interpretations that are lookup tables)'),
|
||||
('new_eval', BOOL, True, 'use new evaluator (temporary parameter for testing)'),
|
||||
))
|
||||
|
||||
|
|
|
@ -55,8 +55,7 @@ namespace datalog {
|
|||
m_args(m),
|
||||
m_hnf(m),
|
||||
m_qe(m),
|
||||
m_cfg(m),
|
||||
m_rwr(m, false, m_cfg),
|
||||
m_rwr(m),
|
||||
m_ufproc(m) {}
|
||||
|
||||
void rule_manager::inc_ref(rule * r) {
|
||||
|
@ -76,28 +75,8 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
|
||||
rule_manager::remove_label_cfg::~remove_label_cfg() {}
|
||||
|
||||
br_status rule_manager::remove_label_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
|
||||
proof_ref & result_pr)
|
||||
{
|
||||
if (is_decl_of(f, m_label_fid, OP_LABEL)) {
|
||||
SASSERT(num == 1);
|
||||
result = args[0];
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
||||
void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) {
|
||||
expr_ref tmp(m);
|
||||
m_rwr(fml, tmp);
|
||||
if (pr && fml != tmp) {
|
||||
|
||||
pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp));
|
||||
}
|
||||
fml = tmp;
|
||||
m_rwr.remove_labels(fml, pr);
|
||||
}
|
||||
|
||||
var_idx_set& rule_manager::collect_vars(expr* e) {
|
||||
|
@ -1092,5 +1071,4 @@ namespace datalog {
|
|||
|
||||
};
|
||||
|
||||
template class rewriter_tpl<datalog::rule_manager::remove_label_cfg>;
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ Revision History:
|
|||
#include"qe_lite.h"
|
||||
#include"var_subst.h"
|
||||
#include"datatype_decl_plugin.h"
|
||||
#include"label_rewriter.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
|
@ -102,16 +103,6 @@ namespace datalog {
|
|||
*/
|
||||
class rule_manager
|
||||
{
|
||||
class remove_label_cfg : public default_rewriter_cfg {
|
||||
family_id m_label_fid;
|
||||
public:
|
||||
remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {}
|
||||
virtual ~remove_label_cfg();
|
||||
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
|
||||
proof_ref & result_pr);
|
||||
};
|
||||
|
||||
ast_manager& m;
|
||||
context& m_ctx;
|
||||
rule_counter m_counter;
|
||||
|
@ -124,8 +115,7 @@ namespace datalog {
|
|||
svector<bool> m_neg;
|
||||
hnf m_hnf;
|
||||
qe_lite m_qe;
|
||||
remove_label_cfg m_cfg;
|
||||
rewriter_tpl<remove_label_cfg> m_rwr;
|
||||
label_rewriter m_rwr;
|
||||
mutable uninterpreted_function_finder_proc m_ufproc;
|
||||
mutable quantifier_finder_proc m_qproc;
|
||||
mutable expr_sparse_mark m_visited;
|
||||
|
|
|
@ -29,7 +29,6 @@ Revision History:
|
|||
#include"ast_counter.h"
|
||||
#include"statistics.h"
|
||||
#include"lbool.h"
|
||||
#include"qe_util.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ Revision History:
|
|||
#include "pdr_closure.h"
|
||||
#include "pdr_context.h"
|
||||
#include "expr_safe_replace.h"
|
||||
#include "ast_util.h"
|
||||
|
||||
namespace pdr {
|
||||
|
||||
|
@ -147,7 +148,7 @@ namespace pdr {
|
|||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
fmls[i] = close_fml(fmls[i].get());
|
||||
}
|
||||
return qe::mk_and(fmls);
|
||||
return expr_ref(mk_and(fmls), m);
|
||||
}
|
||||
|
||||
expr_ref closure::relax(unsigned i, expr* fml) {
|
||||
|
@ -169,7 +170,7 @@ namespace pdr {
|
|||
for (unsigned i = 0; i < As.size(); ++i) {
|
||||
fmls.push_back(relax(i, As[i]));
|
||||
}
|
||||
B = qe::mk_and(fmls);
|
||||
B = mk_and(fmls);
|
||||
return B;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@ Notes:
|
|||
#include "smt_value_sort.h"
|
||||
#include "proof_utils.h"
|
||||
#include "dl_boogie_proof.h"
|
||||
#include "qe_util.h"
|
||||
#include "scoped_proof.h"
|
||||
#include "blast_term_ite_tactic.h"
|
||||
#include "model_implicant.h"
|
||||
|
|
|
@ -201,7 +201,7 @@ namespace pdr {
|
|||
lits.push_back(extract_consequence(lo, hi));
|
||||
lo = hi;
|
||||
}
|
||||
res = qe::mk_or(lits);
|
||||
res = mk_or(lits);
|
||||
IF_VERBOSE(2, { if (lits.size() > 1) { verbose_stream() << "combined lemma: " << mk_pp(res, m) << "\n"; } });
|
||||
#endif
|
||||
}
|
||||
|
@ -415,6 +415,7 @@ namespace pdr {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class collect_pure_proc {
|
||||
|
|
|
@ -117,7 +117,7 @@ namespace pdr {
|
|||
void core_farkas_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) {
|
||||
ast_manager& m = n.pt().get_manager();
|
||||
if (core.empty()) return;
|
||||
expr_ref A(m), B(qe::mk_and(core)), C(m);
|
||||
expr_ref A(m), B(mk_and(core)), C(m);
|
||||
expr_ref_vector Bs(m);
|
||||
flatten_or(B, Bs);
|
||||
A = n.pt().get_propagation_formula(m_ctx.get_pred_transformers(), n.level());
|
||||
|
@ -129,13 +129,13 @@ namespace pdr {
|
|||
if (m_farkas_learner.get_lemma_guesses(A, B, lemmas)) {
|
||||
TRACE("pdr",
|
||||
tout << "Old core:\n" << mk_pp(B, m) << "\n";
|
||||
tout << "New core:\n" << mk_pp(qe::mk_and(lemmas), m) << "\n";);
|
||||
Bs[i] = qe::mk_and(lemmas);
|
||||
tout << "New core:\n" << mk_and(lemmas) << "\n";);
|
||||
Bs[i] = mk_and(lemmas);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
if (change) {
|
||||
C = qe::mk_or(Bs);
|
||||
C = mk_or(Bs);
|
||||
TRACE("pdr", tout << "prop:\n" << mk_pp(A,m) << "\ngen:" << mk_pp(B, m) << "\nto: " << mk_pp(C, m) << "\n";);
|
||||
core.reset();
|
||||
flatten_and(C, core);
|
||||
|
@ -186,7 +186,7 @@ namespace pdr {
|
|||
}
|
||||
closure cl(n.pt(), m_is_closure);
|
||||
|
||||
expr_ref fml1 = qe::mk_and(core);
|
||||
expr_ref fml1 = mk_and(core);
|
||||
expr_ref fml2 = n.pt().get_formulas(n.level(), false);
|
||||
fml1_2.push_back(fml1);
|
||||
fml1_2.push_back(0);
|
||||
|
@ -205,7 +205,7 @@ namespace pdr {
|
|||
if (l_false == n.pt().is_reachable(nd, &conv2, uses_level1)) {
|
||||
new_cores.push_back(std::make_pair(conv2, uses_level1));
|
||||
change = true;
|
||||
expr_ref state1 = qe::mk_and(conv2);
|
||||
expr_ref state1 = mk_and(conv2);
|
||||
TRACE("pdr",
|
||||
tout << mk_pp(state, m) << "\n";
|
||||
tout << "Generalized to:\n" << mk_pp(state1, m) << "\n";);
|
||||
|
@ -593,7 +593,7 @@ namespace pdr {
|
|||
for (unsigned i = ut_size; i < t_size; i++) {
|
||||
conj.push_back(rule.get_tail(i));
|
||||
}
|
||||
result = qe::mk_and(conj);
|
||||
result = mk_and(conj);
|
||||
if (!sub.empty()) {
|
||||
expr_ref tmp = result;
|
||||
var_subst(m, false)(tmp, sub.size(), sub.c_ptr(), result);
|
||||
|
@ -685,7 +685,7 @@ namespace pdr {
|
|||
for (unsigned i = 0; i < rules.size(); ++i) {
|
||||
fmls.push_back(m.mk_not(mk_transition_rule(reps, level, *rules[i])));
|
||||
}
|
||||
fml = qe::mk_and(fmls);
|
||||
fml = mk_and(fmls);
|
||||
TRACE("pdr", tout << mk_pp(fml, m) << "\n";);
|
||||
return fml;
|
||||
}
|
||||
|
@ -741,7 +741,7 @@ namespace pdr {
|
|||
}
|
||||
}
|
||||
|
||||
expr_ref result = qe::mk_and(conjs);
|
||||
expr_ref result = mk_and(conjs);
|
||||
TRACE("pdr", tout << mk_pp(result, m) << "\n";);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ sym_mux::sym_mux(ast_manager & m)
|
|||
: m(m), m_ref_holder(m),
|
||||
m_next_sym_suffix_idx(0) {
|
||||
m_suffixes.push_back("_n");
|
||||
unsigned suf_sz = m_suffixes.size();
|
||||
size_t suf_sz = m_suffixes.size();
|
||||
for(unsigned i = 0; i < suf_sz; ++i) {
|
||||
symbol suff_sym = symbol(m_suffixes[i].c_str());
|
||||
m_used_suffixes.insert(suff_sym);
|
||||
|
|
|
@ -93,7 +93,6 @@ private:
|
|||
std::string get_suffix(unsigned i);
|
||||
void ensure_tuple_size(func_decl * prim, unsigned sz);
|
||||
|
||||
expr_ref isolate_o_idx(expr* e, unsigned idx) const;
|
||||
public:
|
||||
sym_mux(ast_manager & m);
|
||||
|
||||
|
@ -241,8 +240,6 @@ public:
|
|||
func_decl * const * begin_prim_preds() const { return m_prim_preds.begin(); }
|
||||
func_decl * const * end_prim_preds() const { return m_prim_preds.end(); }
|
||||
|
||||
void get_muxed_cube_from_model(const model_core & model, expr_ref_vector & res) const;
|
||||
|
||||
std::string pp_model(const model_core & mdl) const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ Copyright (c) 2015 Microsoft Corporation
|
|||
|
||||
#include "check_relation.h"
|
||||
#include "dl_relation_manager.h"
|
||||
#include "qe_util.h"
|
||||
#include "ast_util.h"
|
||||
#include "smt_kernel.h"
|
||||
#include <typeinfo>
|
||||
|
|
|
@ -23,7 +23,6 @@ Notes:
|
|||
--*/
|
||||
#include "udoc_relation.h"
|
||||
#include "dl_relation_manager.h"
|
||||
#include "qe_util.h"
|
||||
#include "ast_util.h"
|
||||
#include "smt_kernel.h"
|
||||
|
||||
|
|
|
@ -39,6 +39,17 @@ namespace nlsat {
|
|||
m_values.swap(other.m_values);
|
||||
m_assigned.swap(other.m_assigned);
|
||||
}
|
||||
void copy(assignment const& other) {
|
||||
m_assigned.reset();
|
||||
m_assigned.append(other.m_assigned);
|
||||
m_values.reserve(m_assigned.size(), anum());
|
||||
for (unsigned i = 0; i < m_assigned.size(); ++i) {
|
||||
if (is_assigned(i)) {
|
||||
am().set(m_values[i], other.value(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_core(var x, anum & v) {
|
||||
m_values.reserve(x+1, anum());
|
||||
m_assigned.reserve(x+1, false);
|
||||
|
@ -52,11 +63,26 @@ namespace nlsat {
|
|||
am().set(m_values[x], v);
|
||||
}
|
||||
void reset(var x) { if (x < m_assigned.size()) m_assigned[x] = false; }
|
||||
void reset() { m_assigned.reset(); }
|
||||
bool is_assigned(var x) const { return m_assigned.get(x, false); }
|
||||
anum const & value(var x) const { return m_values[x]; }
|
||||
virtual anum_manager & m() const { return am(); }
|
||||
virtual bool contains(var x) const { return is_assigned(x); }
|
||||
virtual anum const & operator()(var x) const { SASSERT(is_assigned(x)); return value(x); }
|
||||
void swap(var x, var y) {
|
||||
SASSERT(x < m_values.size() && y < m_values.size());
|
||||
std::swap(m_assigned[x], m_assigned[y]);
|
||||
std::swap(m_values[x], m_values[y]);
|
||||
}
|
||||
void display(std::ostream& out) const {
|
||||
for (unsigned i = 0; i < m_assigned.size(); ++i) {
|
||||
if (m_assigned[i]) {
|
||||
out << "x" << i << " := ";
|
||||
m_values.m().display(out, m_values[i]);
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,10 +18,12 @@ Revision History:
|
|||
|
||||
--*/
|
||||
#include"nlsat_evaluator.h"
|
||||
#include"nlsat_solver.h"
|
||||
|
||||
namespace nlsat {
|
||||
|
||||
struct evaluator::imp {
|
||||
solver& m_solver;
|
||||
assignment const & m_assignment;
|
||||
pmanager & m_pm;
|
||||
small_object_allocator & m_allocator;
|
||||
|
@ -357,7 +359,8 @@ namespace nlsat {
|
|||
|
||||
sign_table m_sign_table_tmp;
|
||||
|
||||
imp(assignment const & x2v, pmanager & pm, small_object_allocator & allocator):
|
||||
imp(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator):
|
||||
m_solver(s),
|
||||
m_assignment(x2v),
|
||||
m_pm(pm),
|
||||
m_allocator(allocator),
|
||||
|
@ -420,10 +423,25 @@ namespace nlsat {
|
|||
scoped_anum_vector & roots = m_tmp_values;
|
||||
roots.reset();
|
||||
m_am.isolate_roots(polynomial_ref(a->p(), m_pm), undef_var_assignment(m_assignment, a->x()), roots);
|
||||
TRACE("nlsat",
|
||||
m_solver.display(tout << (neg?"!":""), *a); tout << "\n";
|
||||
if (roots.empty()) {
|
||||
tout << "No roots\n";
|
||||
}
|
||||
else {
|
||||
tout << "Roots for ";
|
||||
for (unsigned i = 0; i < roots.size(); ++i) {
|
||||
m_am.display_interval(tout, roots[i]); tout << " ";
|
||||
}
|
||||
tout << "\n";
|
||||
}
|
||||
m_assignment.display(tout);
|
||||
);
|
||||
SASSERT(a->i() > 0);
|
||||
if (a->i() > roots.size())
|
||||
return false; // p does have sufficient roots
|
||||
int sign = m_am.compare(m_assignment.value(a->x()), roots[a->i() - 1]);
|
||||
if (a->i() > roots.size()) {
|
||||
return neg;
|
||||
}
|
||||
int sign = m_am.compare(m_assignment.value(a->x()), roots[a->i() - 1]);
|
||||
return satisfied(sign, k, neg);
|
||||
}
|
||||
|
||||
|
@ -649,8 +667,8 @@ namespace nlsat {
|
|||
}
|
||||
};
|
||||
|
||||
evaluator::evaluator(assignment const & x2v, pmanager & pm, small_object_allocator & allocator) {
|
||||
m_imp = alloc(imp, x2v, pm, allocator);
|
||||
evaluator::evaluator(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator) {
|
||||
m_imp = alloc(imp, s, x2v, pm, allocator);
|
||||
}
|
||||
|
||||
evaluator::~evaluator() {
|
||||
|
|
|
@ -26,11 +26,13 @@ Revision History:
|
|||
|
||||
namespace nlsat {
|
||||
|
||||
class solver;
|
||||
|
||||
class evaluator {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
public:
|
||||
evaluator(assignment const & x2v, pmanager & pm, small_object_allocator & allocator);
|
||||
evaluator(solver& s, assignment const & x2v, pmanager & pm, small_object_allocator & allocator);
|
||||
~evaluator();
|
||||
|
||||
interval_set_manager & ism() const;
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace nlsat {
|
|||
polynomial::cache & m_cache;
|
||||
pmanager & m_pm;
|
||||
polynomial_ref_vector m_ps;
|
||||
polynomial_ref_vector m_ps2;
|
||||
polynomial_ref_vector m_psc_tmp;
|
||||
polynomial_ref_vector m_factors;
|
||||
scoped_anum_vector m_roots_tmp;
|
||||
|
@ -43,6 +44,7 @@ namespace nlsat {
|
|||
bool m_full_dimensional;
|
||||
bool m_minimize_cores;
|
||||
bool m_factor;
|
||||
bool m_signed_project;
|
||||
|
||||
struct todo_set {
|
||||
polynomial::cache & m_cache;
|
||||
|
@ -137,6 +139,7 @@ namespace nlsat {
|
|||
m_cache(u),
|
||||
m_pm(u.pm()),
|
||||
m_ps(m_pm),
|
||||
m_ps2(m_pm),
|
||||
m_psc_tmp(m_pm),
|
||||
m_factors(m_pm),
|
||||
m_roots_tmp(m_am),
|
||||
|
@ -148,6 +151,7 @@ namespace nlsat {
|
|||
m_simplify_cores = false;
|
||||
m_full_dimensional = false;
|
||||
m_minimize_cores = false;
|
||||
m_signed_project = false;
|
||||
}
|
||||
|
||||
~imp() {
|
||||
|
@ -202,7 +206,7 @@ namespace nlsat {
|
|||
void reset_already_added() {
|
||||
SASSERT(m_result != 0);
|
||||
unsigned sz = m_result->size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
m_already_added_literal[(*m_result)[i].index()] = false;
|
||||
}
|
||||
|
||||
|
@ -212,7 +216,7 @@ namespace nlsat {
|
|||
max_var(p) must be assigned in the current interpretation.
|
||||
*/
|
||||
int sign(polynomial_ref const & p) {
|
||||
TRACE("nlsat_explain", tout << "p: " << p << "\n";);
|
||||
TRACE("nlsat_explain", tout << "p: " << p << " var: " << max_var(p) << "\n";);
|
||||
SASSERT(max_var(p) == null_var || m_assignment.is_assigned(max_var(p)));
|
||||
return m_am.eval_sign_at(p, m_assignment);
|
||||
}
|
||||
|
@ -697,39 +701,163 @@ namespace nlsat {
|
|||
}
|
||||
}
|
||||
|
||||
void test_root_literal(atom::kind k, var y, unsigned i, poly * p, scoped_literal_vector& result) {
|
||||
m_result = &result;
|
||||
add_root_literal(k, y, i, p);
|
||||
reset_already_added();
|
||||
m_result = 0;
|
||||
}
|
||||
|
||||
void add_root_literal(atom::kind k, var y, unsigned i, poly * p) {
|
||||
polynomial_ref pr(p, m_pm);
|
||||
TRACE("nlsat_explain",
|
||||
display(tout << "x" << y << " " << k << "[" << i << "](", pr); tout << ")\n";);
|
||||
|
||||
if (!mk_linear_root(k, y, i, p) &&
|
||||
//!mk_plinear_root(k, y, i, p) &&
|
||||
!mk_quadratic_root(k, y, i, p)&&
|
||||
true) {
|
||||
bool_var b = m_solver.mk_root_atom(k, y, i, p);
|
||||
literal l(b, true);
|
||||
TRACE("nlsat_explain", tout << "adding literal\n"; display(tout, l); tout << "\n";);
|
||||
add_literal(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* literal can be expressed using a linear ineq_atom
|
||||
*/
|
||||
bool mk_linear_root(atom::kind k, var y, unsigned i, poly * p) {
|
||||
scoped_mpz c(m_pm.m());
|
||||
bool_var b;
|
||||
bool lsign = false;
|
||||
if (m_pm.degree(p, y) == 1 && m_pm.const_coeff(p, y, 1, c)) {
|
||||
SASSERT(!m_pm.m().is_zero(c));
|
||||
// literal can be expressed using a linear ineq_atom
|
||||
polynomial_ref p_prime(m_pm);
|
||||
p_prime = p;
|
||||
if (m_pm.m().is_neg(c))
|
||||
p_prime = neg(p_prime);
|
||||
p = p_prime.get();
|
||||
switch (k) {
|
||||
case atom::ROOT_EQ: k = atom::EQ; lsign = false; break;
|
||||
case atom::ROOT_LT: k = atom::LT; lsign = false; break;
|
||||
case atom::ROOT_GT: k = atom::GT; lsign = false; break;
|
||||
case atom::ROOT_LE: k = atom::GT; lsign = true; break;
|
||||
case atom::ROOT_GE: k = atom::LT; lsign = true; break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
bool is_even = false;
|
||||
b = m_solver.mk_ineq_atom(k, 1, &p, &is_even);
|
||||
mk_linear_root(k, y, i, p, m_pm.m().is_neg(c));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
b = m_solver.mk_root_atom(k, y, i, p);
|
||||
lsign = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Create pseudo-linear root depending on the sign of the coefficient to y.
|
||||
*/
|
||||
bool mk_plinear_root(atom::kind k, var y, unsigned i, poly * p) {
|
||||
if (m_pm.degree(p, y) != 1) {
|
||||
return false;
|
||||
}
|
||||
lsign = !lsign; // adding as an assumption
|
||||
literal l(b, lsign);
|
||||
TRACE("nlsat_explain", tout << "adding literal\n"; display(tout, l); tout << "\n";);
|
||||
add_literal(l);
|
||||
polynomial_ref c(m_pm);
|
||||
c = m_pm.coeff(p, y, 1);
|
||||
int s = sign(c);
|
||||
if (s == 0) {
|
||||
return false;
|
||||
}
|
||||
ensure_sign(c);
|
||||
mk_linear_root(k, y, i, p, s < 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Encode root conditions for quadratic polynomials.
|
||||
|
||||
Basically implements Thom's theorem. The roots are characterized by the sign of polynomials and their derivatives.
|
||||
|
||||
b^2 - 4ac = 0:
|
||||
- there is only one root, which is -b/2a.
|
||||
- relation to root is a function of the sign of
|
||||
- 2ax + b
|
||||
b^2 - 4ac > 0:
|
||||
- assert i == 1 or i == 2
|
||||
- relation to root is a function of the signs of:
|
||||
- 2ax + b
|
||||
- ax^2 + bx + c
|
||||
*/
|
||||
|
||||
bool mk_quadratic_root(atom::kind k, var y, unsigned i, poly * p) {
|
||||
if (m_pm.degree(p, y) != 2) {
|
||||
return false;
|
||||
}
|
||||
if (i != 1 && i != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SASSERT(m_assignment.is_assigned(y));
|
||||
polynomial_ref A(m_pm), B(m_pm), C(m_pm), q(m_pm), p_diff(m_pm), yy(m_pm);
|
||||
A = m_pm.coeff(p, y, 2);
|
||||
B = m_pm.coeff(p, y, 1);
|
||||
C = m_pm.coeff(p, y, 0);
|
||||
// TBD throttle based on degree of q?
|
||||
q = (B*B) - (4*A*C);
|
||||
yy = m_pm.mk_polynomial(y);
|
||||
p_diff = 2*A*yy + B;
|
||||
p_diff = m_pm.normalize(p_diff);
|
||||
int sq = ensure_sign(q);
|
||||
if (sq < 0) {
|
||||
return false;
|
||||
}
|
||||
int sa = ensure_sign(A);
|
||||
if (sa == 0) {
|
||||
q = B*yy + C;
|
||||
return mk_plinear_root(k, y, i, q);
|
||||
}
|
||||
ensure_sign(p_diff);
|
||||
if (sq > 0) {
|
||||
polynomial_ref pr(p, m_pm);
|
||||
ensure_sign(pr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int ensure_sign(polynomial_ref & p) {
|
||||
#if 0
|
||||
polynomial_ref f(m_pm);
|
||||
factor(p, m_factors);
|
||||
m_is_even.reset();
|
||||
unsigned num_factors = m_factors.size();
|
||||
int s = 1;
|
||||
for (unsigned i = 0; i < num_factors; i++) {
|
||||
f = m_factors.get(i);
|
||||
s *= sign(f);
|
||||
m_is_even.push_back(false);
|
||||
}
|
||||
if (num_factors > 0) {
|
||||
atom::kind k = atom::EQ;
|
||||
if (s == 0) k = atom::EQ;
|
||||
if (s < 0) k = atom::LT;
|
||||
if (s > 0) k = atom::GT;
|
||||
bool_var b = m_solver.mk_ineq_atom(k, num_factors, m_factors.c_ptr(), m_is_even.c_ptr());
|
||||
add_literal(literal(b, true));
|
||||
}
|
||||
return s;
|
||||
#else
|
||||
int s = sign(p);
|
||||
if (!is_const(p)) {
|
||||
add_simple_assumption(s == 0 ? atom::EQ : (s < 0 ? atom::LT : atom::GT), p);
|
||||
}
|
||||
return s;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Auxiliary function to linear roots.
|
||||
*/
|
||||
void mk_linear_root(atom::kind k, var y, unsigned i, poly * p, bool mk_neg) {
|
||||
polynomial_ref p_prime(m_pm);
|
||||
p_prime = p;
|
||||
bool lsign = false;
|
||||
if (mk_neg)
|
||||
p_prime = neg(p_prime);
|
||||
p = p_prime.get();
|
||||
switch (k) {
|
||||
case atom::ROOT_EQ: k = atom::EQ; lsign = false; break;
|
||||
case atom::ROOT_LT: k = atom::LT; lsign = false; break;
|
||||
case atom::ROOT_GT: k = atom::GT; lsign = false; break;
|
||||
case atom::ROOT_LE: k = atom::GT; lsign = true; break;
|
||||
case atom::ROOT_GE: k = atom::LT; lsign = true; break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
add_simple_assumption(k, p, lsign);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1332,10 +1460,333 @@ namespace nlsat {
|
|||
TRACE("nlsat_explain", tout << "[explain] result\n"; display(tout, result););
|
||||
CASSERT("nlsat", check_already_added());
|
||||
}
|
||||
|
||||
|
||||
void project(var x, unsigned num, literal const * ls, scoped_literal_vector & result) {
|
||||
m_result = &result;
|
||||
svector<literal> lits;
|
||||
TRACE("nlsat", tout << "project x" << x << "\n"; m_solver.display(tout););
|
||||
|
||||
DEBUG_CODE(
|
||||
for (unsigned i = 0; i < num; ++i) {
|
||||
SASSERT(m_solver.value(ls[i]) == l_true);
|
||||
atom* a = m_atoms[ls[i].var()];
|
||||
SASSERT(!a || m_evaluator.eval(a, ls[i].sign()));
|
||||
});
|
||||
split_literals(x, num, ls, lits);
|
||||
collect_polys(lits.size(), lits.c_ptr(), m_ps);
|
||||
var mx_var = max_var(m_ps);
|
||||
if (!m_ps.empty()) {
|
||||
svector<var> renaming;
|
||||
if (x != mx_var) {
|
||||
for (var i = 0; i < m_solver.num_vars(); ++i) {
|
||||
renaming.push_back(i);
|
||||
}
|
||||
std::swap(renaming[x], renaming[mx_var]);
|
||||
m_solver.reorder(renaming.size(), renaming.c_ptr());
|
||||
TRACE("qe", tout << "x: " << x << " max: " << mx_var << " num_vars: " << m_solver.num_vars() << "\n";
|
||||
m_solver.display(tout););
|
||||
}
|
||||
elim_vanishing(m_ps);
|
||||
if (m_signed_project) {
|
||||
signed_project(m_ps, mx_var);
|
||||
}
|
||||
else {
|
||||
project(m_ps, mx_var);
|
||||
}
|
||||
reset_already_added();
|
||||
m_result = 0;
|
||||
if (x != mx_var) {
|
||||
m_solver.restore_order();
|
||||
}
|
||||
}
|
||||
else {
|
||||
reset_already_added();
|
||||
m_result = 0;
|
||||
}
|
||||
for (unsigned i = 0; i < result.size(); ++i) {
|
||||
result.set(i, ~result[i]);
|
||||
}
|
||||
DEBUG_CODE(
|
||||
for (unsigned i = 0; i < result.size(); ++i) {
|
||||
SASSERT(l_true == m_solver.value(result[i]));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void split_literals(var x, unsigned n, literal const* ls, svector<literal>& lits) {
|
||||
var_vector vs;
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
vs.reset();
|
||||
m_solver.vars(ls[i], vs);
|
||||
if (vs.contains(x)) {
|
||||
lits.push_back(ls[i]);
|
||||
}
|
||||
else {
|
||||
add_literal(~ls[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Signed projection.
|
||||
|
||||
Assumptions:
|
||||
- any variable in ps is at most x.
|
||||
- root expressions are satisfied (positive literals)
|
||||
|
||||
Effect:
|
||||
- if x not in p, then
|
||||
- if sign(p) < 0: p < 0
|
||||
- if sign(p) = 0: p = 0
|
||||
- if sign(p) > 0: p > 0
|
||||
else:
|
||||
- let roots_j be the roots of p_j or roots_j[i]
|
||||
- let L = { roots_j[i] | M(roots_j[i]) < M(x) }
|
||||
- let U = { roots_j[i] | M(roots_j[i]) > M(x) }
|
||||
- let E = { roots_j[i] | M(roots_j[i]) = M(x) }
|
||||
- let glb in L, s.t. forall l in L . M(glb) >= M(l)
|
||||
- let lub in U, s.t. forall u in U . M(lub) <= M(u)
|
||||
- if root in E, then
|
||||
- add E x . x = root & x > lb for lb in L
|
||||
- add E x . x = root & x < ub for ub in U
|
||||
- add E x . x = root & x = root2 for root2 in E \ { root }
|
||||
- else
|
||||
- assume |L| <= |U| (other case is symmetric)
|
||||
- add E x . lb <= x & x <= glb for lb in L
|
||||
- add E x . x = glb & x < ub for ub in U
|
||||
*/
|
||||
|
||||
|
||||
void signed_project(polynomial_ref_vector& ps, var x) {
|
||||
|
||||
TRACE("nlsat_explain", tout << "Signed projection\n";);
|
||||
polynomial_ref p(m_pm);
|
||||
unsigned eq_index = 0;
|
||||
bool eq_valid = false;
|
||||
unsigned eq_degree = 0;
|
||||
for (unsigned i = 0; i < ps.size(); ++i) {
|
||||
p = ps.get(i);
|
||||
int s = sign(p);
|
||||
if (max_var(p) != x) {
|
||||
atom::kind k = (s == 0)?(atom::EQ):((s < 0)?(atom::LT):(atom::GT));
|
||||
add_simple_assumption(k, p, false);
|
||||
ps[i] = ps.back();
|
||||
ps.pop_back();
|
||||
--i;
|
||||
}
|
||||
else if (s == 0) {
|
||||
if (!eq_valid || degree(p, x) < eq_degree) {
|
||||
eq_index = i;
|
||||
eq_valid = true;
|
||||
eq_degree = degree(p, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ps.size() == 1) {
|
||||
project_single(x, ps.get(0));
|
||||
return;
|
||||
}
|
||||
|
||||
// ax + b = 0, p(x) > 0 ->
|
||||
|
||||
if (eq_valid) {
|
||||
p = ps.get(eq_index);
|
||||
if (degree(p, x) == 1) {
|
||||
// ax + b = 0
|
||||
// let d be maximal degree of x in p.
|
||||
// p(x) -> a^d*p(-b/a), a
|
||||
// perform virtual substitution with equality.
|
||||
solve_eq(x, eq_index, ps);
|
||||
}
|
||||
else {
|
||||
project_pairs(x, eq_index, ps);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned num_lub = 0, num_glb = 0;
|
||||
unsigned glb_index = 0, lub_index = 0;
|
||||
scoped_anum lub(m_am), glb(m_am), x_val(m_am);
|
||||
x_val = m_assignment.value(x);
|
||||
for (unsigned i = 0; i < ps.size(); ++i) {
|
||||
p = ps.get(i);
|
||||
scoped_anum_vector & roots = m_roots_tmp;
|
||||
roots.reset();
|
||||
m_am.isolate_roots(p, undef_var_assignment(m_assignment, x), roots);
|
||||
bool glb_valid = false, lub_valid = false;
|
||||
for (unsigned j = 0; j < roots.size(); ++j) {
|
||||
int s = m_am.compare(x_val, roots[j]);
|
||||
SASSERT(s != 0);
|
||||
lub_valid |= s < 0;
|
||||
glb_valid |= s > 0;
|
||||
|
||||
if (s < 0 && m_am.lt(roots[j], lub)) {
|
||||
lub_index = i;
|
||||
m_am.set(lub, roots[j]);
|
||||
}
|
||||
|
||||
if (s > 0 && m_am.lt(glb, roots[j])) {
|
||||
glb_index = i;
|
||||
m_am.set(glb, roots[j]);
|
||||
}
|
||||
}
|
||||
if (glb_valid) {
|
||||
++num_glb;
|
||||
}
|
||||
if (lub_valid) {
|
||||
++num_lub;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_lub == 0) {
|
||||
project_plus_infinity(x, ps);
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_glb == 0) {
|
||||
project_minus_infinity(x, ps);
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_lub <= num_glb) {
|
||||
glb_index = lub_index;
|
||||
}
|
||||
|
||||
project_pairs(x, glb_index, ps);
|
||||
}
|
||||
|
||||
void project_plus_infinity(var x, polynomial_ref_vector const& ps) {
|
||||
polynomial_ref p(m_pm), lc(m_pm);
|
||||
for (unsigned i = 0; i < ps.size(); ++i) {
|
||||
p = ps.get(i);
|
||||
unsigned d = degree(p, x);
|
||||
lc = m_pm.coeff(p, x, d);
|
||||
if (!is_const(lc)) {
|
||||
unsigned s = sign(p);
|
||||
SASSERT(s != 0);
|
||||
atom::kind k = (s > 0)?(atom::GT):(atom::LT);
|
||||
add_simple_assumption(k, lc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void project_minus_infinity(var x, polynomial_ref_vector const& ps) {
|
||||
polynomial_ref p(m_pm), lc(m_pm);
|
||||
for (unsigned i = 0; i < ps.size(); ++i) {
|
||||
p = ps.get(i);
|
||||
unsigned d = degree(p, x);
|
||||
lc = m_pm.coeff(p, x, d);
|
||||
if (!is_const(lc)) {
|
||||
unsigned s = sign(p);
|
||||
SASSERT(s != 0);
|
||||
atom::kind k;
|
||||
if (s > 0) {
|
||||
k = (d % 2 == 0)?(atom::GT):(atom::LT);
|
||||
}
|
||||
else {
|
||||
k = (d % 2 == 0)?(atom::LT):(atom::GT);
|
||||
}
|
||||
add_simple_assumption(k, lc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void project_pairs(var x, unsigned idx, polynomial_ref_vector const& ps) {
|
||||
polynomial_ref p(m_pm);
|
||||
p = ps.get(idx);
|
||||
for (unsigned i = 0; i < ps.size(); ++i) {
|
||||
if (i != idx) {
|
||||
project_pair(x, ps.get(i), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void project_pair(var x, polynomial::polynomial* p1, polynomial::polynomial* p2) {
|
||||
m_ps2.reset();
|
||||
m_ps2.push_back(p1);
|
||||
m_ps2.push_back(p2);
|
||||
project(m_ps2, x);
|
||||
}
|
||||
|
||||
void project_single(var x, polynomial::polynomial* p) {
|
||||
m_ps2.reset();
|
||||
m_ps2.push_back(p);
|
||||
project(m_ps2, x);
|
||||
}
|
||||
|
||||
void solve_eq(var x, unsigned idx, polynomial_ref_vector const& ps) {
|
||||
polynomial_ref p(m_pm), A(m_pm), B(m_pm), C(m_pm), D(m_pm), E(m_pm), q(m_pm), r(m_pm);
|
||||
polynomial_ref_vector qs(m_pm);
|
||||
p = ps.get(idx);
|
||||
SASSERT(degree(p, x) == 1);
|
||||
A = m_pm.coeff(p, x, 1);
|
||||
B = m_pm.coeff(p, x, 0);
|
||||
B = neg(B);
|
||||
TRACE("nlsat_explain", tout << "p: " << p << " A: " << A << " B: " << B << "\n";);
|
||||
// x = B/A
|
||||
for (unsigned i = 0; i < ps.size(); ++i) {
|
||||
if (i != idx) {
|
||||
q = ps.get(i);
|
||||
unsigned d = degree(q, x);
|
||||
D = m_pm.mk_const(rational(1));
|
||||
E = D;
|
||||
r = m_pm.mk_zero();
|
||||
for (unsigned j = 0; j <= d; ++j) {
|
||||
qs.push_back(D);
|
||||
D = D*A;
|
||||
}
|
||||
for (unsigned j = 0; j <= d; ++j) {
|
||||
// A^d*p0 + A^{d-1}*B*p1 + ... + B^j*A^{d-j}*pj + ... + B^d*p_d
|
||||
C = m_pm.coeff(q, x, j);
|
||||
if (!is_zero(C)) {
|
||||
D = qs.get(d-j);
|
||||
r = r + D*E*C;
|
||||
}
|
||||
E = E*B;
|
||||
}
|
||||
TRACE("nlsat_explain", tout << "q: " << q << " r: " << r << "\n";);
|
||||
ensure_sign(r);
|
||||
}
|
||||
else {
|
||||
ensure_sign(A);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void maximize(var x, unsigned num, literal const * ls, scoped_anum& val, bool& unbounded) {
|
||||
svector<literal> lits;
|
||||
polynomial_ref p(m_pm);
|
||||
split_literals(x, num, ls, lits);
|
||||
collect_polys(lits.size(), lits.c_ptr(), m_ps);
|
||||
unbounded = true;
|
||||
scoped_anum x_val(m_am);
|
||||
x_val = m_assignment.value(x);
|
||||
for (unsigned i = 0; i < m_ps.size(); ++i) {
|
||||
p = m_ps.get(i);
|
||||
scoped_anum_vector & roots = m_roots_tmp;
|
||||
roots.reset();
|
||||
m_am.isolate_roots(p, undef_var_assignment(m_assignment, x), roots);
|
||||
for (unsigned j = 0; j < roots.size(); ++j) {
|
||||
int s = m_am.compare(x_val, roots[j]);
|
||||
if (s <= 0 && (unbounded || m_am.compare(roots[j], val) <= 0)) {
|
||||
unbounded = false;
|
||||
val = roots[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
explain::explain(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq,
|
||||
evaluator & ev) {
|
||||
explain::explain(solver & s, assignment const & x2v, polynomial::cache & u,
|
||||
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev) {
|
||||
m_imp = alloc(imp, s, x2v, u, atoms, x2eq, ev);
|
||||
}
|
||||
|
||||
|
@ -1364,10 +1815,26 @@ namespace nlsat {
|
|||
m_imp->m_factor = f;
|
||||
}
|
||||
|
||||
void explain::set_signed_project(bool f) {
|
||||
m_imp->m_signed_project = f;
|
||||
}
|
||||
|
||||
void explain::operator()(unsigned n, literal const * ls, scoped_literal_vector & result) {
|
||||
(*m_imp)(n, ls, result);
|
||||
}
|
||||
|
||||
void explain::project(var x, unsigned n, literal const * ls, scoped_literal_vector & result) {
|
||||
m_imp->project(x, n, ls, result);
|
||||
}
|
||||
|
||||
void explain::maximize(var x, unsigned n, literal const * ls, scoped_anum& val, bool& unbounded) {
|
||||
m_imp->maximize(x, n, ls, val, unbounded);
|
||||
}
|
||||
|
||||
void explain::test_root_literal(atom::kind k, var y, unsigned i, poly* p, scoped_literal_vector & result) {
|
||||
m_imp->test_root_literal(k, y, i, p, result);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
|
@ -1398,3 +1865,4 @@ void pp_lit(nlsat::explain::imp & ex, nlsat::literal l) {
|
|||
std::cout << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -22,9 +22,11 @@ Revision History:
|
|||
#include"nlsat_solver.h"
|
||||
#include"nlsat_scoped_literal_vector.h"
|
||||
#include"polynomial_cache.h"
|
||||
#include"algebraic_numbers.h"
|
||||
|
||||
namespace nlsat {
|
||||
class evaluator;
|
||||
|
||||
|
||||
class explain {
|
||||
public:
|
||||
|
@ -32,8 +34,8 @@ namespace nlsat {
|
|||
private:
|
||||
imp * m_imp;
|
||||
public:
|
||||
explain(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq,
|
||||
evaluator & ev);
|
||||
explain(solver & s, assignment const & x2v, polynomial::cache & u,
|
||||
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev);
|
||||
~explain();
|
||||
|
||||
void reset();
|
||||
|
@ -41,6 +43,7 @@ namespace nlsat {
|
|||
void set_full_dimensional(bool f);
|
||||
void set_minimize_cores(bool f);
|
||||
void set_factor(bool f);
|
||||
void set_signed_project(bool f);
|
||||
|
||||
/**
|
||||
\brief Given a set of literals ls[0], ... ls[n-1] s.t.
|
||||
|
@ -60,6 +63,48 @@ namespace nlsat {
|
|||
- s_1, ..., s_m are false in the current interpretation
|
||||
*/
|
||||
void operator()(unsigned n, literal const * ls, scoped_literal_vector & result);
|
||||
|
||||
|
||||
/**
|
||||
\brief projection for a given variable.
|
||||
|
||||
Given: M |= l1[x] /\ ... /\ ln[x]
|
||||
|
||||
Find: M |= s1, ..., sm
|
||||
|
||||
Such that: |= ~s1 \/ ... \/ ~sm \/ E x. l1[x] /\ ... /\ ln[x]
|
||||
|
||||
Contrast this with with the core-based projection above:
|
||||
|
||||
Given: M |= A x . l1[x] \/ ... \/ ln[x]
|
||||
|
||||
Find: M |= ~s1, ..., ~sm.
|
||||
|
||||
Such that: |= s1 \/ ... \/ sm \/ A x . l1[x] \/ ... \/ ln[x]
|
||||
|
||||
Claim: the two compute the same solutions if the projection operators are independent of the value of x.
|
||||
Claim: A complete, convergent projection operator can be obtained from M in a way that is independent of x.
|
||||
|
||||
|
||||
*/
|
||||
void project(var x, unsigned n, literal const * ls, scoped_literal_vector & result);
|
||||
|
||||
/**
|
||||
Maximize the value of x (locally) under the current assignment to other variables and
|
||||
while maintaining the assignment to the literals ls.
|
||||
Set unbounded to 'true' if the value of x is unbounded.
|
||||
|
||||
Precondition: the set of literals are true in the current model.
|
||||
|
||||
By local optimization we understand that x is increased to the largest value within
|
||||
the signs delineated by the roots of the polynomials in ls.
|
||||
*/
|
||||
void maximize(var x, unsigned n, literal const * ls, scoped_anum& val, bool& unbounded);
|
||||
|
||||
/**
|
||||
Unit test routine.
|
||||
*/
|
||||
void test_root_literal(atom::kind k, var y, unsigned i, poly* p, scoped_literal_vector & result);
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -64,6 +64,13 @@ namespace nlsat {
|
|||
for (unsigned i = 0; i < sz; i++)
|
||||
push_back(ls[i]);
|
||||
}
|
||||
void append(scoped_literal_vector const& ls) {
|
||||
append(ls.size(), ls.c_ptr());
|
||||
}
|
||||
void swap(scoped_literal_vector& other) {
|
||||
SASSERT(&m_solver == &other.m_solver);
|
||||
m_lits.swap(other.m_lits);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ namespace nlsat {
|
|||
typedef polynomial::cache cache;
|
||||
typedef ptr_vector<interval_set> interval_set_vector;
|
||||
|
||||
solver & m_solver;
|
||||
reslimit& m_rlimit;
|
||||
small_object_allocator m_allocator;
|
||||
unsynch_mpq_manager m_qm;
|
||||
|
@ -159,8 +158,7 @@ namespace nlsat {
|
|||
unsigned m_stages;
|
||||
unsigned m_irrational_assignments; // number of irrational witnesses
|
||||
|
||||
imp(solver & s, reslimit& rlim, params_ref const & p):
|
||||
m_solver(s),
|
||||
imp(solver& s, reslimit& rlim, params_ref const & p):
|
||||
m_rlimit(rlim),
|
||||
m_allocator("nlsat"),
|
||||
m_pm(rlim, m_qm, &m_allocator),
|
||||
|
@ -168,7 +166,7 @@ namespace nlsat {
|
|||
m_am(rlim, m_qm, p, &m_allocator),
|
||||
m_asm(*this, m_allocator),
|
||||
m_assignment(m_am),
|
||||
m_evaluator(m_assignment, m_pm, m_allocator),
|
||||
m_evaluator(s, m_assignment, m_pm, m_allocator),
|
||||
m_ism(m_evaluator.ism()),
|
||||
m_num_bool_vars(0),
|
||||
m_display_var(m_perm),
|
||||
|
@ -183,12 +181,7 @@ namespace nlsat {
|
|||
}
|
||||
|
||||
~imp() {
|
||||
m_explain.reset();
|
||||
m_lemma.reset();
|
||||
m_lazy_clause.reset();
|
||||
undo_until_size(0);
|
||||
del_clauses();
|
||||
del_unref_atoms();
|
||||
reset();
|
||||
}
|
||||
|
||||
void mk_true_bvar() {
|
||||
|
@ -216,6 +209,18 @@ namespace nlsat {
|
|||
m_am.updt_params(p.p);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_explain.reset();
|
||||
m_lemma.reset();
|
||||
m_lazy_clause.reset();
|
||||
undo_until_size(0);
|
||||
del_clauses();
|
||||
del_unref_atoms();
|
||||
m_cache.reset();
|
||||
m_assignment.reset();
|
||||
}
|
||||
|
||||
|
||||
void checkpoint() {
|
||||
if (!m_rlimit.inc()) throw solver_exception(m_rlimit.get_cancel_msg());
|
||||
if (memory::get_allocation_size() > m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG);
|
||||
|
@ -252,6 +257,7 @@ namespace nlsat {
|
|||
}
|
||||
|
||||
void inc_ref(bool_var b) {
|
||||
TRACE("ref", tout << "inc: " << b << "\n";);
|
||||
if (b == null_bool_var)
|
||||
return;
|
||||
if (m_atoms[b] == 0)
|
||||
|
@ -264,6 +270,7 @@ namespace nlsat {
|
|||
}
|
||||
|
||||
void dec_ref(bool_var b) {
|
||||
TRACE("ref", tout << "dec: " << b << "\n";);
|
||||
if (b == null_bool_var)
|
||||
return;
|
||||
atom * a = m_atoms[b];
|
||||
|
@ -412,6 +419,34 @@ namespace nlsat {
|
|||
return x;
|
||||
}
|
||||
|
||||
svector<bool> m_found_vars;
|
||||
void vars(literal l, var_vector& vs) {
|
||||
vs.reset();
|
||||
atom * a = m_atoms[l.var()];
|
||||
if (a == 0) {
|
||||
|
||||
}
|
||||
else if (a->is_ineq_atom()) {
|
||||
unsigned sz = to_ineq_atom(a)->size();
|
||||
var_vector new_vs;
|
||||
for (unsigned j = 0; j < sz; j++) {
|
||||
m_found_vars.reset();
|
||||
m_pm.vars(to_ineq_atom(a)->p(j), new_vs);
|
||||
for (unsigned i = 0; i < new_vs.size(); ++i) {
|
||||
if (!m_found_vars.get(new_vs[i], false)) {
|
||||
m_found_vars.setx(new_vs[i], true, false);
|
||||
vs.push_back(new_vs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_pm.vars(to_root_atom(a)->p(), vs);
|
||||
//vs.erase(max_var(to_root_atom(a)->p()));
|
||||
vs.push_back(to_root_atom(a)->x());
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate(ineq_atom * a) {
|
||||
unsigned obj_sz = ineq_atom::get_obj_size(a->size());
|
||||
a->~ineq_atom();
|
||||
|
@ -425,7 +460,7 @@ namespace nlsat {
|
|||
|
||||
void del(bool_var b) {
|
||||
SASSERT(m_bwatches[b].empty());
|
||||
SASSERT(m_bvalues[b] == l_undef);
|
||||
//SASSERT(m_bvalues[b] == l_undef);
|
||||
m_num_bool_vars--;
|
||||
m_dead[b] = true;
|
||||
m_atoms[b] = 0;
|
||||
|
@ -491,6 +526,7 @@ namespace nlsat {
|
|||
TRACE("nlsat_table_bug", ineq_atom::hash_proc h;
|
||||
tout << "mk_ineq_atom hash: " << h(new_atom) << "\n"; display(tout, *new_atom, m_display_var); tout << "\n";);
|
||||
ineq_atom * old_atom = m_ineq_atoms.insert_if_not_there(new_atom);
|
||||
CTRACE("nlsat_table_bug", old_atom->max_var() != max, display(tout, *old_atom, m_display_var); tout << "\n";);
|
||||
SASSERT(old_atom->max_var() == max);
|
||||
if (old_atom != new_atom) {
|
||||
deallocate(new_atom);
|
||||
|
@ -726,7 +762,7 @@ namespace nlsat {
|
|||
|
||||
template<typename Predicate>
|
||||
void undo_until(Predicate const & pred) {
|
||||
while (pred()) {
|
||||
while (pred() && !m_trail.empty()) {
|
||||
trail & t = m_trail.back();
|
||||
switch (t.m_kind) {
|
||||
case trail::BVAR_ASSIGNMENT:
|
||||
|
@ -803,6 +839,14 @@ namespace nlsat {
|
|||
SASSERT(m_bvalues[b] == l_undef);
|
||||
}
|
||||
|
||||
struct true_pred {
|
||||
bool operator()() const { return true; }
|
||||
};
|
||||
|
||||
void undo_until_empty() {
|
||||
undo_until(true_pred());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create a new scope level
|
||||
*/
|
||||
|
@ -868,10 +912,11 @@ namespace nlsat {
|
|||
var max = a->max_var();
|
||||
if (!m_assignment.is_assigned(max))
|
||||
return l_undef;
|
||||
TRACE("value_bug", tout << "value of: "; display(tout, l); tout << "\n"; tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n";
|
||||
display_assignment(tout);
|
||||
display_bool_assignment(tout););
|
||||
return to_lbool(m_evaluator.eval(a, l.sign()));
|
||||
val = to_lbool(m_evaluator.eval(a, l.sign()));
|
||||
TRACE("value_bug", tout << "value of: "; display(tout, l); tout << " := " << val << "\n";
|
||||
tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n";
|
||||
display_assignment(tout););
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -880,8 +925,10 @@ namespace nlsat {
|
|||
bool is_satisfied(clause const & cls) const {
|
||||
unsigned sz = cls.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (const_cast<imp*>(this)->value(cls[i]) == l_true)
|
||||
if (const_cast<imp*>(this)->value(cls[i]) == l_true) {
|
||||
TRACE("value_bug:", tout << cls[i] << " := true\n";);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -984,8 +1031,10 @@ namespace nlsat {
|
|||
If satisfy_learned is true, then learned clauses are satisfied even if m_lazy > 0
|
||||
*/
|
||||
bool process_arith_clause(clause const & cls, bool satisfy_learned) {
|
||||
if (!satisfy_learned && m_lazy >= 2 && cls.is_learned())
|
||||
if (!satisfy_learned && m_lazy >= 2 && cls.is_learned()) {
|
||||
TRACE("nlsat", tout << "skip learned\n";);
|
||||
return true; // ignore lemmas in super lazy mode
|
||||
}
|
||||
SASSERT(m_xk == max_var(cls));
|
||||
unsigned num_undef = 0; // number of undefined literals
|
||||
unsigned first_undef = UINT_MAX; // position of the first undefined literal
|
||||
|
@ -1064,7 +1113,7 @@ namespace nlsat {
|
|||
If satisfy_learned is true, then (arithmetic) learned clauses are satisfied even if m_lazy > 0
|
||||
*/
|
||||
bool process_clause(clause const & cls, bool satisfy_learned) {
|
||||
TRACE("nlsat", tout << "processing clause:\n"; display(tout, cls); tout << "\n";);
|
||||
TRACE("nlsat", tout << "processing clause: "; display(tout, cls); tout << "\n";);
|
||||
if (is_satisfied(cls))
|
||||
return true;
|
||||
if (m_xk == null_var)
|
||||
|
@ -1151,7 +1200,7 @@ namespace nlsat {
|
|||
}
|
||||
TRACE("nlsat_bug", tout << "xk: x" << m_xk << " bk: b" << m_bk << "\n";);
|
||||
if (m_bk == null_bool_var && m_xk >= num_vars()) {
|
||||
TRACE("nlsat", tout << "found model\n"; display_assignment(tout); display_bool_assignment(tout););
|
||||
TRACE("nlsat", tout << "found model\n"; display_assignment(tout););
|
||||
return l_true; // all variables were assigned, and all clauses were satisfied.
|
||||
}
|
||||
TRACE("nlsat", tout << "processing variable ";
|
||||
|
@ -1186,23 +1235,102 @@ namespace nlsat {
|
|||
lbool check() {
|
||||
TRACE("nlsat_smt2", display_smt2(tout););
|
||||
TRACE("nlsat_fd", tout << "is_full_dimensional: " << is_full_dimensional() << "\n";);
|
||||
m_xk = null_var;
|
||||
init_search();
|
||||
m_explain.set_full_dimensional(is_full_dimensional());
|
||||
if (m_random_order) {
|
||||
bool reordered = false;
|
||||
if (!can_reorder()) {
|
||||
|
||||
}
|
||||
else if (m_random_order) {
|
||||
shuffle_vars();
|
||||
reordered = true;
|
||||
}
|
||||
else if (m_reorder) {
|
||||
heuristic_reorder();
|
||||
reordered = true;
|
||||
}
|
||||
sort_watched_clauses();
|
||||
lbool r = search();
|
||||
CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout); display_bool_assignment(tout););
|
||||
if (m_reorder)
|
||||
CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout););
|
||||
if (reordered)
|
||||
restore_order();
|
||||
CTRACE("nlsat_model", r == l_true, tout << "model\n"; display_assignment(tout); display_bool_assignment(tout););
|
||||
CTRACE("nlsat_model", r == l_true, tout << "model\n"; display_assignment(tout););
|
||||
CTRACE("nlsat", r == l_false, display(tout););
|
||||
return r;
|
||||
}
|
||||
|
||||
void init_search() {
|
||||
undo_until_empty();
|
||||
while (m_scope_lvl > 0) {
|
||||
undo_new_level();
|
||||
}
|
||||
m_xk = null_var;
|
||||
for (unsigned i = 0; i < m_bvalues.size(); ++i) {
|
||||
m_bvalues[i] = l_undef;
|
||||
}
|
||||
m_assignment.reset();
|
||||
}
|
||||
|
||||
lbool check(literal_vector& assumptions) {
|
||||
literal_vector result;
|
||||
unsigned sz = assumptions.size();
|
||||
literal const* ptr = assumptions.c_ptr();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
mk_clause(1, ptr+i, (assumption)(ptr+i));
|
||||
}
|
||||
lbool r = check();
|
||||
|
||||
if (r == l_false) {
|
||||
// collect used literals from m_lemma_assumptions
|
||||
vector<assumption, false> deps;
|
||||
m_asm.linearize(m_lemma_assumptions.get(), deps);
|
||||
for (unsigned i = 0; i < deps.size(); ++i) {
|
||||
literal const* lp = (literal const*)(deps[i]);
|
||||
if (ptr <= lp && lp < ptr + sz) {
|
||||
result.push_back(*lp);
|
||||
}
|
||||
}
|
||||
}
|
||||
collect(assumptions, m_clauses);
|
||||
collect(assumptions, m_learned);
|
||||
|
||||
assumptions.reset();
|
||||
assumptions.append(result);
|
||||
return r;
|
||||
}
|
||||
|
||||
void collect(literal_vector const& assumptions, clause_vector& clauses) {
|
||||
unsigned n = clauses.size();
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
clause * c = clauses[i];
|
||||
if (collect(assumptions, *c)) {
|
||||
del_clause(c);
|
||||
}
|
||||
else {
|
||||
clauses[j] = c;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
clauses.shrink(j);
|
||||
}
|
||||
|
||||
bool collect(literal_vector const& assumptions, clause const& c) {
|
||||
unsigned sz = assumptions.size();
|
||||
literal const* ptr = assumptions.c_ptr();
|
||||
_assumption_set asms = static_cast<_assumption_set>(c.assumptions());
|
||||
if (asms == 0) {
|
||||
return false;
|
||||
}
|
||||
vector<assumption, false> deps;
|
||||
m_asm.linearize(asms, deps);
|
||||
bool found = false;
|
||||
for (unsigned i = 0; !found && i < deps.size(); ++i) {
|
||||
found = ptr <= deps[i] && deps[i] < ptr + sz;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Conflict Resolution
|
||||
|
@ -1447,7 +1575,7 @@ namespace nlsat {
|
|||
TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause); tout << "\n";
|
||||
tout << "xk: "; if (m_xk != null_var) m_display_var(tout, m_xk); else tout << "<null>"; tout << "\n";
|
||||
tout << "scope_lvl: " << scope_lvl() << "\n";
|
||||
tout << "current assignment\n"; display_assignment(tout); display_bool_assignment(tout););
|
||||
tout << "current assignment\n"; display_assignment(tout););
|
||||
|
||||
// static unsigned counter = 0;
|
||||
// counter++;
|
||||
|
@ -1588,7 +1716,7 @@ namespace nlsat {
|
|||
conflict_clause = new_cls;
|
||||
goto start;
|
||||
}
|
||||
TRACE("nlsat_resolve_done", display_assignment(tout); display_bool_assignment(tout););
|
||||
TRACE("nlsat_resolve_done", display_assignment(tout););
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1801,6 +1929,15 @@ namespace nlsat {
|
|||
reorder(p.size(), p.c_ptr());
|
||||
}
|
||||
|
||||
bool can_reorder() const {
|
||||
for (unsigned i = 0; i < m_atoms.size(); ++i) {
|
||||
if (m_atoms[i]) {
|
||||
if (m_atoms[i]->is_root_atom()) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Reorder variables using the giving permutation.
|
||||
p maps internal variables to their new positions
|
||||
|
@ -1921,6 +2058,9 @@ namespace nlsat {
|
|||
void reinit_cache() {
|
||||
reinit_cache(m_clauses);
|
||||
reinit_cache(m_learned);
|
||||
for (unsigned i = 0; i < m_atoms.size(); ++i) {
|
||||
reinit_cache(m_atoms[i]);
|
||||
}
|
||||
}
|
||||
void reinit_cache(clause_vector const & cs) {
|
||||
unsigned sz = cs.size();
|
||||
|
@ -1934,10 +2074,13 @@ namespace nlsat {
|
|||
}
|
||||
void reinit_cache(literal l) {
|
||||
bool_var b = l.var();
|
||||
atom * a = m_atoms[b];
|
||||
if (a == 0)
|
||||
return;
|
||||
if (a->is_ineq_atom()) {
|
||||
reinit_cache(m_atoms[b]);
|
||||
}
|
||||
void reinit_cache(atom* a) {
|
||||
if (a == 0) {
|
||||
|
||||
}
|
||||
else if (a->is_ineq_atom()) {
|
||||
var max = 0;
|
||||
unsigned sz = to_ineq_atom(a)->size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
|
@ -2073,7 +2216,7 @@ namespace nlsat {
|
|||
//
|
||||
// -----------------------
|
||||
|
||||
void display_assignment(std::ostream & out, display_var_proc const & proc) const {
|
||||
void display_num_assignment(std::ostream & out, display_var_proc const & proc) const {
|
||||
for (var x = 0; x < num_vars(); x++) {
|
||||
if (m_assignment.is_assigned(x)) {
|
||||
proc(out, x);
|
||||
|
@ -2084,7 +2227,7 @@ namespace nlsat {
|
|||
}
|
||||
}
|
||||
|
||||
void display_bool_assignment(std::ostream & out, display_var_proc const & proc) const {
|
||||
void display_bool_assignment(std::ostream & out) const {
|
||||
unsigned sz = m_atoms.size();
|
||||
for (bool_var b = 0; b < sz; b++) {
|
||||
if (m_atoms[b] == 0 && m_bvalues[b] != l_undef) {
|
||||
|
@ -2112,12 +2255,13 @@ namespace nlsat {
|
|||
return !first;
|
||||
}
|
||||
|
||||
void display_assignment(std::ostream & out) const {
|
||||
display_assignment(out, m_display_var);
|
||||
void display_num_assignment(std::ostream & out) const {
|
||||
display_num_assignment(out, m_display_var);
|
||||
}
|
||||
|
||||
void display_bool_assignment(std::ostream & out) const {
|
||||
display_bool_assignment(out, m_display_var);
|
||||
void display_assignment(std::ostream& out) const {
|
||||
display_bool_assignment(out);
|
||||
display_num_assignment(out);
|
||||
}
|
||||
|
||||
void display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const {
|
||||
|
@ -2511,6 +2655,7 @@ namespace nlsat {
|
|||
|
||||
void display(std::ostream & out) const {
|
||||
display(out, m_display_var);
|
||||
display_assignment(out);
|
||||
}
|
||||
|
||||
void display_vars(std::ostream & out) const {
|
||||
|
@ -2562,6 +2707,20 @@ namespace nlsat {
|
|||
return m_imp->check();
|
||||
}
|
||||
|
||||
lbool solver::check(literal_vector& assumptions) {
|
||||
return m_imp->check(assumptions);
|
||||
}
|
||||
|
||||
void solver::reset() {
|
||||
m_imp->reset();
|
||||
}
|
||||
|
||||
|
||||
void solver::updt_params(params_ref const & p) {
|
||||
m_imp->updt_params(p);
|
||||
}
|
||||
|
||||
|
||||
void solver::collect_param_descrs(param_descrs & d) {
|
||||
algebraic_numbers::manager::collect_param_descrs(d);
|
||||
nlsat_params::collect_param_descrs(d);
|
||||
|
@ -2583,6 +2742,10 @@ namespace nlsat {
|
|||
m_imp->m_display_var.m_proc = &proc;
|
||||
}
|
||||
|
||||
unsigned solver::num_vars() const {
|
||||
return m_imp->num_vars();
|
||||
}
|
||||
|
||||
bool solver::is_int(var x) const {
|
||||
return m_imp->is_int(x);
|
||||
}
|
||||
|
@ -2590,10 +2753,61 @@ namespace nlsat {
|
|||
bool_var solver::mk_bool_var() {
|
||||
return m_imp->mk_bool_var();
|
||||
}
|
||||
|
||||
literal solver::mk_true() {
|
||||
return literal(0, false);
|
||||
}
|
||||
|
||||
atom * solver::bool_var2atom(bool_var b) {
|
||||
return m_imp->m_atoms[b];
|
||||
}
|
||||
|
||||
void solver::vars(literal l, var_vector& vs) {
|
||||
m_imp->vars(l, vs);
|
||||
}
|
||||
|
||||
atom_vector const& solver::get_atoms() {
|
||||
return m_imp->m_atoms;
|
||||
}
|
||||
|
||||
atom_vector const& solver::get_var2eq() {
|
||||
return m_imp->m_var2eq;
|
||||
}
|
||||
|
||||
evaluator& solver::get_evaluator() {
|
||||
return m_imp->m_evaluator;
|
||||
}
|
||||
|
||||
explain& solver::get_explain() {
|
||||
return m_imp->m_explain;
|
||||
}
|
||||
|
||||
void solver::reorder(unsigned sz, var const* p) {
|
||||
m_imp->reorder(sz, p);
|
||||
}
|
||||
|
||||
void solver::restore_order() {
|
||||
m_imp->restore_order();
|
||||
}
|
||||
|
||||
void solver::set_rvalues(assignment const& as) {
|
||||
m_imp->m_assignment.copy(as);
|
||||
}
|
||||
|
||||
void solver::get_rvalues(assignment& as) {
|
||||
as.copy(m_imp->m_assignment);
|
||||
}
|
||||
|
||||
void solver::get_bvalues(svector<lbool>& vs) {
|
||||
vs.reset();
|
||||
vs.append(m_imp->m_bvalues);
|
||||
}
|
||||
|
||||
void solver::set_bvalues(svector<lbool> const& vs) {
|
||||
m_imp->m_bvalues.reset();
|
||||
m_imp->m_bvalues.append(vs);
|
||||
m_imp->m_bvalues.resize(m_imp->m_atoms.size(), l_undef);
|
||||
}
|
||||
|
||||
var solver::mk_var(bool is_int) {
|
||||
return m_imp->mk_var(is_int);
|
||||
|
@ -2631,10 +2845,21 @@ namespace nlsat {
|
|||
m_imp->display(out, l);
|
||||
}
|
||||
|
||||
void solver::display(std::ostream & out, unsigned n, literal const* ls) const {
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
display(out, ls[i]);
|
||||
out << "; ";
|
||||
}
|
||||
}
|
||||
|
||||
void solver::display(std::ostream & out, var x) const {
|
||||
m_imp->m_display_var(out, x);
|
||||
}
|
||||
|
||||
void solver::display(std::ostream & out, atom const& a) const {
|
||||
m_imp->display(out, a, m_imp->m_display_var);
|
||||
}
|
||||
|
||||
display_var_proc const & solver::display_proc() const {
|
||||
return m_imp->m_display_var;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,9 @@ Revision History:
|
|||
|
||||
namespace nlsat {
|
||||
|
||||
class evaluator;
|
||||
class explain;
|
||||
|
||||
class solver {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
|
@ -63,7 +66,9 @@ namespace nlsat {
|
|||
nonlinear arithmetic atom.
|
||||
*/
|
||||
bool_var mk_bool_var();
|
||||
|
||||
|
||||
literal mk_true();
|
||||
|
||||
/**
|
||||
\brief Create a real/integer variable.
|
||||
*/
|
||||
|
@ -121,6 +126,48 @@ namespace nlsat {
|
|||
*/
|
||||
atom * bool_var2atom(bool_var b);
|
||||
|
||||
/**
|
||||
\brief extract free variables from literal.
|
||||
*/
|
||||
void vars(literal l, var_vector& vs);
|
||||
|
||||
/**
|
||||
\brief provide access to atoms. Used by explain.
|
||||
*/
|
||||
atom_vector const& get_atoms();
|
||||
|
||||
/**
|
||||
\brief Access var -> asserted equality.
|
||||
*/
|
||||
|
||||
atom_vector const& get_var2eq();
|
||||
|
||||
/**
|
||||
\brief expose evaluator.
|
||||
*/
|
||||
|
||||
evaluator& get_evaluator();
|
||||
|
||||
/**
|
||||
\brief Access explanation module.
|
||||
*/
|
||||
explain& get_explain();
|
||||
|
||||
/**
|
||||
\brief Access assignments to variables.
|
||||
*/
|
||||
void get_rvalues(assignment& as);
|
||||
void set_rvalues(assignment const& as);
|
||||
|
||||
void get_bvalues(svector<lbool>& vs);
|
||||
void set_bvalues(svector<lbool> const& vs);
|
||||
|
||||
/**
|
||||
\brief reorder variables.
|
||||
*/
|
||||
void reorder(unsigned sz, var const* permutation);
|
||||
void restore_order();
|
||||
|
||||
/**
|
||||
\brief Return number of integer/real variables
|
||||
*/
|
||||
|
@ -135,6 +182,8 @@ namespace nlsat {
|
|||
// -----------------------
|
||||
lbool check();
|
||||
|
||||
lbool check(literal_vector& assumptions);
|
||||
|
||||
// -----------------------
|
||||
//
|
||||
// Model
|
||||
|
@ -154,6 +203,7 @@ namespace nlsat {
|
|||
void updt_params(params_ref const & p);
|
||||
static void collect_param_descrs(param_descrs & d);
|
||||
|
||||
void reset();
|
||||
void collect_statistics(statistics & st);
|
||||
void reset_statistics();
|
||||
void display_status(std::ostream & out) const;
|
||||
|
@ -174,6 +224,10 @@ namespace nlsat {
|
|||
*/
|
||||
void display(std::ostream & out, literal l) const;
|
||||
|
||||
void display(std::ostream & out, unsigned n, literal const* ls) const;
|
||||
|
||||
void display(std::ostream & out, atom const& a) const;
|
||||
|
||||
/**
|
||||
\brief Display variable
|
||||
*/
|
||||
|
|
|
@ -111,6 +111,21 @@ namespace nlsat {
|
|||
struct eq_proc { bool operator()(ineq_atom const * a1, ineq_atom const * a2) const; };
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, atom::kind k) {
|
||||
switch (k) {
|
||||
case atom::EQ: return out << "=";
|
||||
case atom::LT: return out << "<";
|
||||
case atom::GT: return out << ">";
|
||||
case atom::ROOT_EQ: return out << "= root";
|
||||
case atom::ROOT_LT: return out << "< root";
|
||||
case atom::ROOT_LE: return out << "<= root";
|
||||
case atom::ROOT_GT: return out << "> root";
|
||||
case atom::ROOT_GE: return out << ">= root";
|
||||
default: return out << (int)k;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
class root_atom : public atom {
|
||||
friend class solver;
|
||||
var m_x;
|
||||
|
|
|
@ -29,7 +29,9 @@ Notes:
|
|||
#include"expr2var.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"tactic.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"ast_pp.h"
|
||||
#include"polynomial.h"
|
||||
#include"algebraic_numbers.h"
|
||||
|
||||
struct goal2nlsat::imp {
|
||||
struct nlsat_expr2polynomial : public expr2polynomial {
|
||||
|
@ -124,7 +126,7 @@ struct goal2nlsat::imp {
|
|||
m_qm.neg(d2);
|
||||
polynomial_ref p(m_pm);
|
||||
p = m_pm.addmul(d1, m_pm.mk_unit(), p1, d2, m_pm.mk_unit(), p2);
|
||||
TRACE("goal2nlsat_bug", tout << "p: " << p << "\nk: " << k << "\n";);
|
||||
TRACE("goal2nlsat_bug", tout << mk_pp(f, m) << " p: " << p << "\nk: " << k << "\n";);
|
||||
if (is_const(p)) {
|
||||
int sign;
|
||||
if (is_zero(p))
|
||||
|
@ -192,7 +194,7 @@ struct goal2nlsat::imp {
|
|||
switch (to_app(f)->get_decl_kind()) {
|
||||
case OP_TRUE:
|
||||
case OP_FALSE:
|
||||
TRACE("goal2nlsat", tout << "f: " << mk_ismt2_pp(f, m) << "\n";);
|
||||
TRACE("goal2nlsat", tout << "f: " << mk_pp(f, m) << "\n";);
|
||||
throw tactic_exception("apply simplify before applying nlsat");
|
||||
case OP_AND:
|
||||
case OP_OR:
|
||||
|
@ -257,6 +259,7 @@ struct goal2nlsat::imp {
|
|||
process(g.form(i), g.dep(i));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct goal2nlsat::scoped_set_imp {
|
||||
|
@ -289,4 +292,154 @@ void goal2nlsat::operator()(goal const & g, params_ref const & p, nlsat::solver
|
|||
scoped_set_imp setter(*this, local_imp);
|
||||
local_imp(g);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct nlsat2goal::imp {
|
||||
ast_manager& m;
|
||||
arith_util a;
|
||||
u_map<expr*> const* m_x2t;
|
||||
public:
|
||||
imp(ast_manager& m):m(m),a(m) {}
|
||||
|
||||
expr_ref operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l) {
|
||||
m_x2t = &x2t;
|
||||
expr_ref result(m);
|
||||
expr* t;
|
||||
if (b2a.find(l.var(), t)) {
|
||||
result = t;
|
||||
}
|
||||
else {
|
||||
nlsat::atom const* at = s.bool_var2atom(l.var());
|
||||
SASSERT(at != 0);
|
||||
if (at->is_ineq_atom()) {
|
||||
nlsat::ineq_atom const* ia = to_ineq_atom(at);
|
||||
unsigned sz = ia->size();
|
||||
expr_ref_vector ps(m);
|
||||
bool is_int = true;
|
||||
for (unsigned i = 0; is_int && i < sz; ++i) {
|
||||
is_int = poly_is_int(ia->p(i));
|
||||
}
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
polynomial::polynomial* p = ia->p(i);
|
||||
expr_ref t = poly2expr(s, p, is_int);
|
||||
if (ia->is_even(i)) {
|
||||
t = a.mk_power(t, a.mk_numeral(rational(2), a.is_int(t)));
|
||||
}
|
||||
ps.push_back(t);
|
||||
}
|
||||
result = a.mk_mul_simplify(ps);
|
||||
expr_ref zero(m);
|
||||
zero = a.mk_numeral(rational(0), a.is_int(result));
|
||||
switch (ia->get_kind()) {
|
||||
case nlsat::atom::EQ:
|
||||
result = m.mk_eq(result, zero);
|
||||
break;
|
||||
case nlsat::atom::LT:
|
||||
if (l.sign()) {
|
||||
l.neg();
|
||||
result = a.mk_ge(result, zero);
|
||||
}
|
||||
else {
|
||||
result = a.mk_lt(result, zero);
|
||||
}
|
||||
break;
|
||||
case nlsat::atom::GT:
|
||||
if (l.sign()) {
|
||||
l.neg();
|
||||
result = a.mk_le(result, zero);
|
||||
}
|
||||
else {
|
||||
result = a.mk_gt(result, zero);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
else {
|
||||
//nlsat::root_atom const* ra = nlsat::to_root_atom(at);
|
||||
//ra->i();
|
||||
//expr_ref p = poly2expr(s, ra->p());
|
||||
//expr* x = m_x2t->find(ra->x());
|
||||
std::ostringstream strm;
|
||||
s.display(strm, l.sign()?~l:l);
|
||||
result = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort());
|
||||
}
|
||||
}
|
||||
|
||||
if (l.sign()) {
|
||||
result = m.mk_not(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref poly2expr(nlsat::solver& s, polynomial::polynomial* p, bool is_int) {
|
||||
expr_ref result(m);
|
||||
unsigned sz = polynomial::manager::size(p);
|
||||
expr_ref_vector args(m);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
args.push_back(mono2expr(s,
|
||||
polynomial::manager::coeff(p, i),
|
||||
polynomial::manager::get_monomial(p, i), is_int));
|
||||
}
|
||||
result = a.mk_add_simplify(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref mono2expr(nlsat::solver& s, polynomial::numeral const& c, polynomial::monomial* mon, bool is_int) {
|
||||
expr_ref result(m);
|
||||
expr_ref_vector args(m);
|
||||
unsigned sz = polynomial::manager::size(mon);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
unsigned d = polynomial::manager::degree(mon, i);
|
||||
expr* t = m_x2t->find(polynomial::manager::get_var(mon, i));
|
||||
SASSERT(d >= 1);
|
||||
if (d == 1) {
|
||||
args.push_back(t);
|
||||
}
|
||||
else {
|
||||
args.push_back(a.mk_power(t, a.mk_numeral(rational(d), a.is_int(t))));
|
||||
}
|
||||
}
|
||||
if (!s.pm().m().is_one(c)) {
|
||||
args.push_back(a.mk_numeral(c, is_int));
|
||||
}
|
||||
result = a.mk_mul_simplify(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool poly_is_int(polynomial::polynomial* p) {
|
||||
bool is_int = true;
|
||||
unsigned sz = polynomial::manager::size(p);
|
||||
for (unsigned i = 0; is_int && i < sz; ++i) {
|
||||
is_int = mono_is_int(polynomial::manager::get_monomial(p, i));
|
||||
}
|
||||
return is_int;
|
||||
}
|
||||
|
||||
bool mono_is_int(polynomial::monomial* mon) {
|
||||
bool is_int = true;
|
||||
unsigned sz = polynomial::manager::size(mon);
|
||||
for (unsigned i = 0; is_int && i < sz; ++i) {
|
||||
is_int = a.is_int(m_x2t->find(polynomial::manager::get_var(mon, i)));
|
||||
}
|
||||
return is_int;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
nlsat2goal::nlsat2goal(ast_manager& m) {
|
||||
m_imp = alloc(imp, m);
|
||||
}
|
||||
|
||||
|
||||
nlsat2goal::~nlsat2goal() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
expr_ref nlsat2goal::operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l) {
|
||||
return (*m_imp)(s, b2a, x2t, l);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -57,17 +57,16 @@ class nlsat2goal {
|
|||
struct imp;
|
||||
imp * m_imp;
|
||||
public:
|
||||
nlsat2goal();
|
||||
nlsat2goal(ast_manager& m);
|
||||
~nlsat2goal();
|
||||
|
||||
static void collect_param_descrs(param_descrs & r);
|
||||
|
||||
/**
|
||||
\brief Translate the state of the nlsat engine back into a goal.
|
||||
*/
|
||||
void operator()(nlsat::solver const & s, expr2var const & a2b, expr2var const & t2x,
|
||||
params_ref const & p, goal & g, model_converter_ref & mc);
|
||||
|
||||
\brief Translate a literal into a formula.
|
||||
*/
|
||||
expr_ref operator()(nlsat::solver& s, u_map<expr*> const& b2a, u_map<expr*> const& x2t, nlsat::literal l);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -116,11 +116,9 @@ public:
|
|||
{}
|
||||
|
||||
virtual void reset(cmd_context & ctx) { }
|
||||
|
||||
virtual char const * get_usage() const { return "<term>"; }
|
||||
virtual char const * get_descr(cmd_context & ctx) const { return "check sat modulo objective function";}
|
||||
virtual unsigned get_arity() const { return 1; }
|
||||
|
||||
virtual void prepare(cmd_context & ctx) {}
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_EXPR; }
|
||||
|
||||
|
@ -139,204 +137,74 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class alternate_min_max_cmd : public cmd {
|
||||
app_ref_vector* m_vars;
|
||||
svector<bool> m_is_max;
|
||||
unsigned m_position;
|
||||
public:
|
||||
alternate_min_max_cmd():
|
||||
cmd("min-max"),
|
||||
m_vars(0),
|
||||
m_position(0)
|
||||
{}
|
||||
|
||||
virtual void reset(cmd_context & ctx) {
|
||||
dealloc(m_vars);
|
||||
m_is_max.reset();
|
||||
m_position = 0;
|
||||
}
|
||||
virtual char const * get_usage() const { return "(min | max | var)+ <term>"; }
|
||||
virtual char const * get_descr(cmd_context & ctx) const { return "check sat modulo alternating min-max objectives";}
|
||||
virtual unsigned get_arity() const { return 2; }
|
||||
virtual void prepare(cmd_context & ctx) {}
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
|
||||
switch (m_position) {
|
||||
case 0: return CPK_SYMBOL_LIST;
|
||||
case 1: return CPK_EXPR;
|
||||
default: return CPK_SYMBOL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_next_arg(cmd_context & ctx, unsigned num, symbol const * slist) {
|
||||
bool is_max = false;
|
||||
for (unsigned i = 0; i < num; ++i) {
|
||||
if (slist[i] == symbol("max")) {
|
||||
is_max = true;
|
||||
}
|
||||
else if (slist[i] == symbol("min")) {
|
||||
is_max = false;
|
||||
}
|
||||
else {
|
||||
m_is_max.push_back(is_max);
|
||||
if (!m_vars) m_vars = alloc(app_ref_vector, ctx.m());
|
||||
m_vars->push_back(ctx.m().mk_const(ctx.find_func_decl(slist[i])));
|
||||
}
|
||||
}
|
||||
++m_position;
|
||||
}
|
||||
|
||||
virtual void set_next_arg(cmd_context & ctx, expr * t) {
|
||||
if (!is_app(t)) {
|
||||
throw cmd_exception("malformed objective term: it cannot be a quantifier or bound variable");
|
||||
}
|
||||
++m_position;
|
||||
if (!m_vars) m_vars = alloc(app_ref_vector, ctx.m());
|
||||
get_opt(ctx).min_max(to_app(t), *m_vars, m_is_max);
|
||||
}
|
||||
|
||||
virtual void failure_cleanup(cmd_context & ctx) {
|
||||
reset(ctx);
|
||||
}
|
||||
|
||||
virtual void execute(cmd_context & ctx) { }
|
||||
};
|
||||
|
||||
|
||||
void install_opt_cmds(cmd_context & ctx) {
|
||||
ctx.insert(alloc(assert_soft_cmd));
|
||||
ctx.insert(alloc(min_maximize_cmd, true));
|
||||
ctx.insert(alloc(min_maximize_cmd, false));
|
||||
ctx.insert(alloc(alternate_min_max_cmd));
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
ctx.insert(alloc(optimize_cmd));
|
||||
ctx.insert(alloc(assert_weighted_cmd));
|
||||
|
||||
|
||||
class optimize_cmd : public parametric_cmd {
|
||||
public:
|
||||
optimize_cmd():
|
||||
parametric_cmd("optimize")
|
||||
{}
|
||||
|
||||
virtual ~optimize_cmd() {
|
||||
}
|
||||
|
||||
virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) {
|
||||
insert_timeout(p);
|
||||
insert_max_memory(p);
|
||||
p.insert("print_statistics", CPK_BOOL, "(default: false) print statistics.");
|
||||
opt::context::collect_param_descrs(p);
|
||||
}
|
||||
|
||||
virtual char const * get_main_descr() const { return "check sat modulo objective function";}
|
||||
virtual char const * get_usage() const { return "(<keyword> <value>)*"; }
|
||||
virtual void prepare(cmd_context & ctx) {
|
||||
parametric_cmd::prepare(ctx);
|
||||
}
|
||||
virtual void failure_cleanup(cmd_context & ctx) {
|
||||
reset(ctx);
|
||||
}
|
||||
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
|
||||
return parametric_cmd::next_arg_kind(ctx);
|
||||
}
|
||||
|
||||
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
params_ref p = ctx.params().merge_default_params(ps());
|
||||
opt::context& opt = get_opt(ctx);
|
||||
opt.updt_params(p);
|
||||
unsigned timeout = p.get_uint("timeout", UINT_MAX);
|
||||
|
||||
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
|
||||
ptr_vector<expr>::const_iterator end = ctx.end_assertions();
|
||||
for (; it != end; ++it) {
|
||||
opt.add_hard_constraint(*it);
|
||||
}
|
||||
lbool r = l_undef;
|
||||
cancel_eh<reslimit> eh(m.limit());
|
||||
{
|
||||
scoped_ctrl_c ctrlc(eh);
|
||||
scoped_timer timer(timeout, &eh);
|
||||
cmd_context::scoped_watch sw(ctx);
|
||||
try {
|
||||
r = opt.optimize();
|
||||
if (r == l_true && opt.is_pareto()) {
|
||||
while (r == l_true) {
|
||||
display_result(ctx);
|
||||
ctx.regular_stream() << "\n";
|
||||
r = opt.optimize();
|
||||
}
|
||||
if (p.get_bool("print_statistics", false)) {
|
||||
display_statistics(ctx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (z3_error& ex) {
|
||||
ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl;
|
||||
}
|
||||
catch (z3_exception& ex) {
|
||||
ctx.regular_stream() << "(error: " << ex.msg() << "\")" << std::endl;
|
||||
}
|
||||
}
|
||||
switch(r) {
|
||||
case l_true: {
|
||||
ctx.regular_stream() << "sat\n";
|
||||
display_result(ctx);
|
||||
break;
|
||||
}
|
||||
case l_false:
|
||||
ctx.regular_stream() << "unsat\n";
|
||||
break;
|
||||
case l_undef:
|
||||
ctx.regular_stream() << "unknown\n";
|
||||
display_result(ctx);
|
||||
break;
|
||||
}
|
||||
if (p.get_bool("print_statistics", false)) {
|
||||
display_statistics(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void display_result(cmd_context & ctx) {
|
||||
params_ref p = ctx.params().merge_default_params(ps());
|
||||
opt::context& opt = get_opt(ctx);
|
||||
opt.display_assignment(ctx.regular_stream());
|
||||
opt_params optp(p);
|
||||
if (optp.print_model()) {
|
||||
model_ref mdl;
|
||||
opt.get_model(mdl);
|
||||
if (mdl) {
|
||||
ctx.regular_stream() << "(model " << std::endl;
|
||||
model_smt2_pp(ctx.regular_stream(), ctx, *(mdl.get()), 2);
|
||||
ctx.regular_stream() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
||||
void display_statistics(cmd_context& ctx) {
|
||||
statistics stats;
|
||||
get_opt(ctx).collect_statistics(stats);
|
||||
stats.update("time", ctx.get_seconds());
|
||||
stats.display_smt2(ctx.regular_stream());
|
||||
}
|
||||
};
|
||||
|
||||
class assert_weighted_cmd : public cmd {
|
||||
unsigned m_idx;
|
||||
expr* m_formula;
|
||||
rational m_weight;
|
||||
symbol m_id;
|
||||
|
||||
public:
|
||||
assert_weighted_cmd():
|
||||
cmd("assert-weighted"),
|
||||
m_idx(0),
|
||||
m_formula(0),
|
||||
m_weight(0)
|
||||
{}
|
||||
|
||||
virtual ~assert_weighted_cmd() {
|
||||
}
|
||||
|
||||
virtual void reset(cmd_context & ctx) {
|
||||
m_idx = 0;
|
||||
m_formula = 0;
|
||||
m_id = symbol::null;
|
||||
}
|
||||
|
||||
virtual char const * get_usage() const { return "<formula> <rational-weight>"; }
|
||||
virtual char const * get_descr(cmd_context & ctx) const { return "assert soft constraint with weight"; }
|
||||
virtual unsigned get_arity() const { return VAR_ARITY; }
|
||||
|
||||
// command invocation
|
||||
virtual void prepare(cmd_context & ctx) {}
|
||||
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
|
||||
switch(m_idx) {
|
||||
case 0: return CPK_EXPR;
|
||||
case 1: return CPK_NUMERAL;
|
||||
default: return CPK_SYMBOL;
|
||||
}
|
||||
}
|
||||
virtual void set_next_arg(cmd_context & ctx, rational const & val) {
|
||||
SASSERT(m_idx == 1);
|
||||
if (!val.is_pos()) {
|
||||
throw cmd_exception("Invalid weight. Weights must be positive.");
|
||||
}
|
||||
m_weight = val;
|
||||
++m_idx;
|
||||
}
|
||||
|
||||
virtual void set_next_arg(cmd_context & ctx, expr * t) {
|
||||
SASSERT(m_idx == 0);
|
||||
if (!ctx.m().is_bool(t)) {
|
||||
throw cmd_exception("Invalid type for expression. Expected Boolean type.");
|
||||
}
|
||||
m_formula = t;
|
||||
++m_idx;
|
||||
}
|
||||
|
||||
virtual void set_next_arg(cmd_context & ctx, symbol const& s) {
|
||||
SASSERT(m_idx > 1);
|
||||
m_id = s;
|
||||
++m_idx;
|
||||
}
|
||||
|
||||
virtual void failure_cleanup(cmd_context & ctx) {
|
||||
reset(ctx);
|
||||
}
|
||||
|
||||
virtual void execute(cmd_context & ctx) {
|
||||
get_opt(ctx).add_soft_constraint(m_formula, m_weight, m_id);
|
||||
reset(ctx);
|
||||
}
|
||||
|
||||
virtual void finalize(cmd_context & ctx) {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -193,6 +193,8 @@ namespace opt {
|
|||
return m_scoped_state.add(t, is_max);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void context::import_scoped_state() {
|
||||
m_optsmt.reset();
|
||||
reset_maxsmts();
|
||||
|
@ -209,6 +211,20 @@ namespace opt {
|
|||
m_hard_constraints.append(s.m_hard);
|
||||
}
|
||||
|
||||
lbool context::min_max(app* t, app_ref_vector const& vars, svector<bool> const& is_max) {
|
||||
clear_state();
|
||||
init_solver();
|
||||
import_scoped_state();
|
||||
normalize();
|
||||
internalize();
|
||||
update_solver();
|
||||
solver& s = get_solver();
|
||||
s.assert_expr(m_hard_constraints);
|
||||
std::cout << "min-max is TBD\n";
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
|
||||
lbool context::optimize() {
|
||||
if (m_pareto) {
|
||||
return execute_pareto();
|
||||
|
@ -223,10 +239,7 @@ namespace opt {
|
|||
internalize();
|
||||
update_solver();
|
||||
solver& s = get_solver();
|
||||
for (unsigned i = 0; i < m_hard_constraints.size(); ++i) {
|
||||
TRACE("opt", tout << "Hard constraint: " << mk_ismt2_pp(m_hard_constraints[i].get(), m) << std::endl;);
|
||||
s.assert_expr(m_hard_constraints[i].get());
|
||||
}
|
||||
s.assert_expr(m_hard_constraints);
|
||||
display_benchmark();
|
||||
IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n";);
|
||||
lbool is_sat = s.check_sat(0,0);
|
||||
|
@ -514,12 +527,10 @@ namespace opt {
|
|||
|
||||
void context::init_solver() {
|
||||
setup_arith_solver();
|
||||
#pragma omp critical (opt_context)
|
||||
{
|
||||
m_opt_solver = alloc(opt_solver, m, m_params, m_fm);
|
||||
m_opt_solver->set_logic(m_logic);
|
||||
m_solver = m_opt_solver.get();
|
||||
}
|
||||
m_opt_solver = alloc(opt_solver, m, m_params, m_fm);
|
||||
m_opt_solver->set_logic(m_logic);
|
||||
m_solver = m_opt_solver.get();
|
||||
|
||||
if (opt_params(m_params).priority() == symbol("pareto") ||
|
||||
(opt_params(m_params).priority() == symbol("lex") && m_objectives.size() > 1)) {
|
||||
m_opt_solver->ensure_pb();
|
||||
|
@ -556,10 +567,7 @@ namespace opt {
|
|||
for (unsigned i = 0; i < sz; ++i) {
|
||||
m_sat_solver->assert_expr(get_solver().get_assertion(i));
|
||||
}
|
||||
#pragma omp critical (opt_context)
|
||||
{
|
||||
m_solver = m_sat_solver.get();
|
||||
}
|
||||
m_solver = m_sat_solver.get();
|
||||
}
|
||||
|
||||
void context::enable_sls(bool force) {
|
||||
|
@ -649,10 +657,7 @@ namespace opt {
|
|||
void context::add_maxsmt(symbol const& id, unsigned index) {
|
||||
maxsmt* ms = alloc(maxsmt, *this, index);
|
||||
ms->updt_params(m_params);
|
||||
#pragma omp critical (opt_context)
|
||||
{
|
||||
m_maxsmts.insert(id, ms);
|
||||
}
|
||||
m_maxsmts.insert(id, ms);
|
||||
}
|
||||
|
||||
bool context::is_numeral(expr* e, rational & n) const {
|
||||
|
@ -896,7 +901,7 @@ namespace opt {
|
|||
}
|
||||
mk_atomic(terms);
|
||||
SASSERT(obj.m_id == id);
|
||||
obj.m_term = to_app(orig_term);
|
||||
obj.m_term = orig_term?to_app(orig_term):0;
|
||||
obj.m_terms.reset();
|
||||
obj.m_terms.append(terms);
|
||||
obj.m_weights.reset();
|
||||
|
@ -940,6 +945,9 @@ namespace opt {
|
|||
bool context::verify_model(unsigned index, model* md, rational const& _v) {
|
||||
rational r;
|
||||
app_ref term = m_objectives[index].m_term;
|
||||
if (!term) {
|
||||
return true;
|
||||
}
|
||||
rational v = m_objectives[index].m_adjust_value(_v);
|
||||
expr_ref val(m);
|
||||
model_ref mdl = md;
|
||||
|
@ -1274,10 +1282,7 @@ namespace opt {
|
|||
}
|
||||
|
||||
void context::set_simplify(tactic* tac) {
|
||||
#pragma omp critical (opt_context)
|
||||
{
|
||||
m_simplify = tac;
|
||||
}
|
||||
m_simplify = tac;
|
||||
}
|
||||
|
||||
void context::clear_state() {
|
||||
|
@ -1287,10 +1292,7 @@ namespace opt {
|
|||
}
|
||||
|
||||
void context::set_pareto(pareto_base* p) {
|
||||
#pragma omp critical (opt_context)
|
||||
{
|
||||
m_pareto = p;
|
||||
}
|
||||
m_pareto = p;
|
||||
}
|
||||
|
||||
void context::collect_statistics(statistics& stats) const {
|
||||
|
|
|
@ -172,6 +172,7 @@ namespace opt {
|
|||
virtual ~context();
|
||||
unsigned add_soft_constraint(expr* f, rational const& w, symbol const& id);
|
||||
unsigned add_objective(app* t, bool is_max);
|
||||
lbool min_max(app* t, app_ref_vector const& vars, svector<bool> const& is_max);
|
||||
void add_hard_constraint(expr* f);
|
||||
|
||||
|
||||
|
@ -226,8 +227,6 @@ namespace opt {
|
|||
virtual bool verify_model(unsigned id, model* mdl, rational const& v);
|
||||
|
||||
private:
|
||||
void validate_feasibility(maxsmt& ms);
|
||||
|
||||
lbool execute(objective const& obj, bool committed, bool scoped);
|
||||
lbool execute_min_max(unsigned index, bool committed, bool scoped, bool is_max);
|
||||
lbool execute_maxsat(symbol const& s, bool committed, bool scoped);
|
||||
|
|
1044
src/qe/nlqsat.cpp
Normal file
1044
src/qe/nlqsat.cpp
Normal file
File diff suppressed because it is too large
Load diff
38
src/qe/nlqsat.h
Normal file
38
src/qe/nlqsat.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
nlqsat.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Quantifier Satisfiability Solver for nlsat
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-10-17
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef QE_NLQSAT_H__
|
||||
#define QE_NLQSAT_H__
|
||||
|
||||
#include "tactic.h"
|
||||
|
||||
|
||||
tactic * mk_nlqsat_tactic(ast_manager & m, params_ref const& p = params_ref());
|
||||
tactic * mk_nlqe_tactic(ast_manager & m, params_ref const& p = params_ref());
|
||||
|
||||
|
||||
/*
|
||||
ADD_TACTIC("nlqsat", "apply a NL-QSAT solver.", "mk_nlqsat_tactic(m, p)")
|
||||
|
||||
*/
|
||||
|
||||
// TBD_TACTIC("nlqe", "apply a NL-QE solver.", "mk_nlqe_tactic(m, p)")
|
||||
|
||||
#endif
|
|
@ -36,7 +36,6 @@ Revision History:
|
|||
#include "expr_functors.h"
|
||||
#include "quant_hoist.h"
|
||||
#include "bool_rewriter.h"
|
||||
#include "qe_util.h"
|
||||
#include "th_rewriter.h"
|
||||
#include "smt_kernel.h"
|
||||
#include "model_evaluator.h"
|
||||
|
@ -2281,7 +2280,7 @@ namespace qe {
|
|||
}
|
||||
}
|
||||
|
||||
static void extract_vars(quantifier* q, expr_ref& new_body, app_ref_vector& vars) {
|
||||
void extract_vars(quantifier* q, expr_ref& new_body, app_ref_vector& vars) {
|
||||
ast_manager& m = new_body.get_manager();
|
||||
expr_ref tmp(m);
|
||||
unsigned nd = q->get_num_decls();
|
||||
|
|
|
@ -223,6 +223,8 @@ namespace qe {
|
|||
|
||||
qe_solver_plugin* mk_arith_plugin(i_solver_context& ctx, bool produce_models, smt_params& p);
|
||||
|
||||
void extract_vars(quantifier* q, expr_ref& new_body, app_ref_vector& vars);
|
||||
|
||||
class def_vector {
|
||||
func_decl_ref_vector m_vars;
|
||||
expr_ref_vector m_defs;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,16 +9,33 @@ Copyright (c) 2015 Microsoft Corporation
|
|||
#define QE_ARITH_H_
|
||||
|
||||
#include "model.h"
|
||||
#include "arith_decl_plugin.h"
|
||||
#include "qe_mbp.h"
|
||||
|
||||
namespace qe {
|
||||
|
||||
/**
|
||||
Loos-Weispfenning model-based projection for a basic conjunction.
|
||||
Lits is a vector of literals.
|
||||
return vector of variables that could not be projected.
|
||||
*/
|
||||
expr_ref arith_project(model& model, app_ref_vector& vars, expr_ref_vector const& lits);
|
||||
|
||||
expr_ref arith_project(model& model, app_ref_vector& vars, expr* fml);
|
||||
class arith_project_plugin : public project_plugin {
|
||||
struct imp;
|
||||
imp* m_imp;
|
||||
public:
|
||||
arith_project_plugin(ast_manager& m);
|
||||
virtual ~arith_project_plugin();
|
||||
virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits);
|
||||
virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits);
|
||||
virtual family_id get_family_id();
|
||||
};
|
||||
|
||||
bool arith_project(model& model, app* var, expr_ref_vector& lits);
|
||||
|
||||
// match e := t mod k = 0.
|
||||
bool is_divides(arith_util& a, expr* e, rational& k, expr_ref& t);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,6 +32,7 @@ Revision History:
|
|||
#include "nlarith_util.h"
|
||||
#include "model_evaluator.h"
|
||||
#include "smt_kernel.h"
|
||||
#include "qe_arith.h"
|
||||
|
||||
namespace qe {
|
||||
|
||||
|
@ -266,23 +267,8 @@ namespace qe {
|
|||
//
|
||||
// match 0 == p mod k, p mod k == 0
|
||||
//
|
||||
bool is_divides(app* e, numeral& k, expr_ref& p) {
|
||||
expr* e1, *e2;
|
||||
if (!m.is_eq(e, e1, e2)) {
|
||||
return false;
|
||||
}
|
||||
return is_divides(e1, e2, k, p) || is_divides(e2, e1, k, p);
|
||||
}
|
||||
|
||||
bool is_divides(expr* e1, expr* e2, numeral& k, expr_ref& p) {
|
||||
if (m_arith.is_mod(e2) &&
|
||||
m_arith.is_numeral(e1, k) &&
|
||||
k.is_zero() &&
|
||||
m_arith.is_numeral(to_app(e2)->get_arg(1), k)) {
|
||||
p = to_app(e2)->get_arg(0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
bool is_divides(expr* e, numeral& k, expr_ref& p) {
|
||||
return qe::is_divides(m_arith, e, k, p);
|
||||
}
|
||||
|
||||
bool is_not_divides(app* e, app_ref& n, numeral& k, expr_ref& p) {
|
||||
|
|
434
src/qe/qe_arrays.cpp
Normal file
434
src/qe/qe_arrays.cpp
Normal file
|
@ -0,0 +1,434 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qe_arrays.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Model based projection for arrays
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-06-13
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "qe_arrays.h"
|
||||
#include "rewriter_def.h"
|
||||
#include "expr_functors.h"
|
||||
#include "expr_safe_replace.h"
|
||||
#include "lbool.h"
|
||||
#include "ast_util.h"
|
||||
#include "ast_pp.h"
|
||||
|
||||
namespace qe {
|
||||
|
||||
struct array_project_plugin::imp {
|
||||
|
||||
// rewriter or direct procedure.
|
||||
struct rw_cfg : public default_rewriter_cfg {
|
||||
ast_manager& m;
|
||||
array_util& a;
|
||||
expr_ref_vector m_lits;
|
||||
model* m_model;
|
||||
imp* m_imp;
|
||||
|
||||
rw_cfg(ast_manager& m, array_util& a):
|
||||
m(m), a(a), m_lits(m), m_model(0) {}
|
||||
|
||||
br_status reduce_app(func_decl* f, unsigned n, expr* const* args, expr_ref& result, proof_ref & pr) {
|
||||
if (a.is_select(f) && a.is_store(args[0])) {
|
||||
expr_ref val1(m), val2(m);
|
||||
app* b = to_app(args[0]);
|
||||
SASSERT(b->get_num_args() == n + 1);
|
||||
for (unsigned i = 1; i < n; ++i) {
|
||||
expr* arg1 = args[i];
|
||||
expr* arg2 = b->get_arg(i);
|
||||
if (arg1 == arg2) {
|
||||
val1 = val2 = arg1;
|
||||
}
|
||||
else {
|
||||
VERIFY(m_model->eval(arg1, val1));
|
||||
VERIFY(m_model->eval(arg2, val2));
|
||||
}
|
||||
switch(compare(val1, val2)) {
|
||||
case l_true:
|
||||
if (arg1 != arg2) {
|
||||
m_lits.push_back(m.mk_eq(arg1, arg2));
|
||||
}
|
||||
break;
|
||||
case l_false: {
|
||||
ptr_vector<expr> new_args;
|
||||
if (i > 0) {
|
||||
m_lits.resize(m_lits.size() - i);
|
||||
}
|
||||
m_lits.push_back(m.mk_not(m.mk_eq(arg1, arg2)));
|
||||
new_args.push_back(b->get_arg(0));
|
||||
new_args.append(n-1, args+1);
|
||||
result = m.mk_app(f, n, new_args.c_ptr());
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
case l_undef:
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
result = b->get_arg(n);
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
lbool compare(expr* x, expr* y) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
return l_undef;
|
||||
}
|
||||
};
|
||||
|
||||
struct indices {
|
||||
expr_ref_vector m_values;
|
||||
expr* const* m_vars;
|
||||
|
||||
indices(ast_manager& m, model& model, unsigned n, expr* const* vars):
|
||||
m_values(m), m_vars(vars) {
|
||||
expr_ref val(m);
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
VERIFY(model.eval(vars[i], val));
|
||||
m_values.push_back(val);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ast_manager& m;
|
||||
array_util a;
|
||||
scoped_ptr<contains_app> m_var;
|
||||
|
||||
imp(ast_manager& m): m(m), a(m) {}
|
||||
~imp() {}
|
||||
|
||||
virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
|
||||
TRACE("qe", tout << mk_pp(var, m) << "\n" << lits;);
|
||||
m_var = alloc(contains_app, m, var);
|
||||
|
||||
// reduce select-store redeces based on model.
|
||||
// rw_cfg rw(m);
|
||||
// rw(lits);
|
||||
|
||||
// try first to solve for var.
|
||||
if (solve_eq(model, vars, lits)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
app_ref_vector selects(m);
|
||||
|
||||
// check that only non-select occurrences are in disequalities.
|
||||
if (!check_diseqs(lits, selects)) {
|
||||
TRACE("qe", tout << "Could not project " << mk_pp(var, m) << " for:\n" << lits << "\n";);
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove disequalities.
|
||||
elim_diseqs(lits);
|
||||
|
||||
// Ackerman reduction on remaining select occurrences
|
||||
// either replace occurrences by model value or other node
|
||||
// that is congruent to model value.
|
||||
|
||||
ackermanize_select(model, selects, vars, lits);
|
||||
|
||||
TRACE("qe", tout << selects << "\n" << lits << "\n";);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ackermanize_select(model& model, app_ref_vector const& selects, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
expr_ref_vector vals(m), reps(m);
|
||||
expr_ref val(m);
|
||||
expr_safe_replace sub(m);
|
||||
|
||||
if (selects.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
app_ref sel(m);
|
||||
for (unsigned i = 0; i < selects.size(); ++i) {
|
||||
sel = m.mk_fresh_const("sel", m.get_sort(selects[i]));
|
||||
VERIFY (model.eval(selects[i], val));
|
||||
model.register_decl(sel->get_decl(), val);
|
||||
vals.push_back(to_app(val));
|
||||
reps.push_back(val); // TODO: direct pass could handle nested selects.
|
||||
vars.push_back(sel);
|
||||
sub.insert(selects[i], val);
|
||||
}
|
||||
|
||||
sub(lits);
|
||||
remove_true(lits);
|
||||
project_plugin::partition_args(model, selects, lits);
|
||||
project_plugin::partition_values(model, reps, lits);
|
||||
}
|
||||
|
||||
void remove_true(expr_ref_vector& lits) {
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
if (m.is_true(lits[i].get())) {
|
||||
project_plugin::erase(lits, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool contains_x(expr* e) {
|
||||
return (*m_var)(e);
|
||||
}
|
||||
|
||||
void mk_eq(indices& x, indices y, expr_ref_vector& lits) {
|
||||
unsigned n = x.m_values.size();
|
||||
for (unsigned j = 0; j < n; ++j) {
|
||||
lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j]));
|
||||
}
|
||||
}
|
||||
|
||||
// check that x occurs only under selects or in disequalities.
|
||||
bool check_diseqs(expr_ref_vector const& lits, app_ref_vector& selects) {
|
||||
expr_mark mark;
|
||||
ptr_vector<app> todo;
|
||||
app* e;
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
e = to_app(lits[i]);
|
||||
if (is_diseq_x(e)) {
|
||||
continue;
|
||||
}
|
||||
if (contains_x(e)) {
|
||||
todo.push_back(e);
|
||||
}
|
||||
}
|
||||
while (!todo.empty()) {
|
||||
e = todo.back();
|
||||
todo.pop_back();
|
||||
if (mark.is_marked(e)) {
|
||||
continue;
|
||||
}
|
||||
mark.mark(e);
|
||||
if (m_var->x() == e) {
|
||||
return false;
|
||||
}
|
||||
unsigned start = 0;
|
||||
if (a.is_select(e)) {
|
||||
if (e->get_arg(0) == m_var->x()) {
|
||||
start = 1;
|
||||
selects.push_back(e);
|
||||
}
|
||||
}
|
||||
for (unsigned i = start; i < e->get_num_args(); ++i) {
|
||||
todo.push_back(to_app(e->get_arg(i)));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void elim_diseqs(expr_ref_vector& lits) {
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
if (is_diseq_x(lits[i].get())) {
|
||||
project_plugin::erase(lits, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_update_x(app* e) {
|
||||
do {
|
||||
if (m_var->x() == e) {
|
||||
return true;
|
||||
}
|
||||
if (a.is_store(e) && contains_x(e->get_arg(0))) {
|
||||
for (unsigned i = 1; i < e->get_num_args(); ++i) {
|
||||
if (contains_x(e->get_arg(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
e = to_app(e->get_arg(0));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_diseq_x(expr* e) {
|
||||
expr *f, * s, *t;
|
||||
if (m.is_not(e, f) && m.is_eq(f, s, t)) {
|
||||
if (contains_x(s) && !contains_x(t) && is_update_x(to_app(s))) return true;
|
||||
if (contains_x(t) && !contains_x(s) && is_update_x(to_app(t))) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
// find an equality to solve for.
|
||||
expr* s, *t;
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
if (m.is_eq(lits[i].get(), s, t)) {
|
||||
vector<indices> idxs;
|
||||
expr_ref save(m), back(m);
|
||||
save = lits[i].get();
|
||||
back = lits.back();
|
||||
lits[i] = back;
|
||||
lits.pop_back();
|
||||
unsigned sz = lits.size();
|
||||
if (contains_x(s) && !contains_x(t) && is_app(s)) {
|
||||
if (solve(model, to_app(s), t, idxs, vars, lits)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (contains_x(t) && !contains_x(s) && is_app(t)) {
|
||||
if (solve(model, to_app(t), s, idxs, vars, lits)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// put back the equality literal.
|
||||
lits.resize(sz);
|
||||
lits.push_back(back);
|
||||
lits[i] = save;
|
||||
}
|
||||
// TBD: not distinct?
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool solve(model& model, app* s, expr* t, vector<indices>& idxs, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
SASSERT(contains_x(s));
|
||||
SASSERT(!contains_x(t));
|
||||
|
||||
if (s == m_var->x()) {
|
||||
expr_ref result(t, m);
|
||||
expr_ref_vector args(m);
|
||||
sort* range = get_array_range(m.get_sort(s));
|
||||
for (unsigned i = 0; i < idxs.size(); ++i) {
|
||||
app_ref var(m), sel(m);
|
||||
expr_ref val(m);
|
||||
var = m.mk_fresh_const("value", range);
|
||||
vars.push_back(var);
|
||||
args.reset();
|
||||
|
||||
args.push_back (s);
|
||||
args.append(idxs[i].m_values.size(), idxs[i].m_vars);
|
||||
sel = a.mk_select (args.size (), args.c_ptr ());
|
||||
VERIFY (model.eval (sel, val));
|
||||
model.register_decl (var->get_decl (), val);
|
||||
|
||||
args[0] = result;
|
||||
args.push_back(var);
|
||||
result = a.mk_store(args.size(), args.c_ptr());
|
||||
}
|
||||
expr_safe_replace sub(m);
|
||||
sub.insert(s, result);
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
sub(lits[i].get(), result);
|
||||
lits[i] = result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a.is_store(s)) {
|
||||
unsigned n = s->get_num_args()-2;
|
||||
indices idx(m, model, n, s->get_args()+1);
|
||||
for (unsigned i = 1; i < n; ++i) {
|
||||
if (contains_x(s->get_arg(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
unsigned i;
|
||||
expr_ref_vector args(m);
|
||||
switch (contains(idx, idxs, i)) {
|
||||
case l_true:
|
||||
mk_eq(idx, idxs[i], lits);
|
||||
return solve(model, to_app(s->get_arg(0)), t, idxs, vars, lits);
|
||||
case l_false:
|
||||
for (unsigned i = 0; i < idxs.size(); ++i) {
|
||||
expr_ref_vector eqs(m);
|
||||
mk_eq(idx, idxs[i], eqs);
|
||||
lits.push_back(m.mk_not(mk_and(eqs))); // TBD: extract single index of difference based on model.
|
||||
}
|
||||
args.push_back(t);
|
||||
args.append(n, s->get_args()+1);
|
||||
lits.push_back(m.mk_eq(a.mk_select(args.size(), args.c_ptr()), s->get_arg(n+1)));
|
||||
idxs.push_back(idx);
|
||||
return solve(model, to_app(s->get_arg(0)), t, idxs, vars, lits);
|
||||
case l_undef:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
lbool contains(indices const& idx, vector<indices> const& idxs, unsigned& j) {
|
||||
for (unsigned i = 0; i < idxs.size(); ++i) {
|
||||
switch (compare(idx, idxs[i])) {
|
||||
case l_true:
|
||||
j = i;
|
||||
return l_true;
|
||||
case l_false:
|
||||
break;
|
||||
case l_undef:
|
||||
return l_undef;
|
||||
}
|
||||
}
|
||||
return l_false;
|
||||
}
|
||||
|
||||
lbool compare(indices const& idx1, indices const& idx2) {
|
||||
unsigned n = idx1.m_values.size();
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
switch (compare(idx1.m_values[i], idx2.m_values[i])) {
|
||||
case l_true:
|
||||
break;
|
||||
case l_false:
|
||||
return l_false;
|
||||
case l_undef:
|
||||
return l_undef;
|
||||
}
|
||||
}
|
||||
return l_true;
|
||||
}
|
||||
|
||||
lbool compare(expr* val1, expr* val2) {
|
||||
if (m.are_equal (val1, val2)) return l_true;
|
||||
if (m.are_distinct (val1, val2)) return l_false;
|
||||
|
||||
if (is_uninterp(val1) ||
|
||||
is_uninterp(val2)) {
|
||||
// TBD chase definition of nested array.
|
||||
return l_undef;
|
||||
}
|
||||
return l_undef;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
array_project_plugin::array_project_plugin(ast_manager& m) {
|
||||
m_imp = alloc(imp, m);
|
||||
}
|
||||
|
||||
array_project_plugin::~array_project_plugin() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
return (*m_imp)(model, var, vars, lits);
|
||||
}
|
||||
|
||||
bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
return m_imp->solve(model, vars, lits);
|
||||
}
|
||||
|
||||
family_id array_project_plugin::get_family_id() {
|
||||
return m_imp->a.get_family_id();
|
||||
}
|
||||
|
||||
};
|
||||
|
42
src/qe/qe_arrays.h
Normal file
42
src/qe/qe_arrays.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qe_arrays.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Model based projection for arrays
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-06-13
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#ifndef __QE_ARRAYS_H_
|
||||
#define __QE_ARRAYS_H_
|
||||
|
||||
#include "array_decl_plugin.h"
|
||||
#include "qe_mbp.h"
|
||||
|
||||
namespace qe {
|
||||
|
||||
class array_project_plugin : public project_plugin {
|
||||
struct imp;
|
||||
imp* m_imp;
|
||||
public:
|
||||
array_project_plugin(ast_manager& m);
|
||||
virtual ~array_project_plugin();
|
||||
virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits);
|
||||
virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits);
|
||||
virtual family_id get_family_id();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
312
src/qe/qe_datatypes.cpp
Normal file
312
src/qe/qe_datatypes.cpp
Normal file
|
@ -0,0 +1,312 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qe_datatypes.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Simple projection function for algebraic datatypes.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-06-13
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "qe_arith.h"
|
||||
#include "ast_pp.h"
|
||||
#include "th_rewriter.h"
|
||||
#include "expr_functors.h"
|
||||
#include "model_v2_pp.h"
|
||||
#include "expr_safe_replace.h"
|
||||
#include "obj_pair_hashtable.h"
|
||||
#include "qe_datatypes.h"
|
||||
|
||||
namespace qe {
|
||||
|
||||
struct datatype_project_plugin::imp {
|
||||
ast_manager& m;
|
||||
datatype_util dt;
|
||||
app_ref m_val;
|
||||
scoped_ptr<contains_app> m_var;
|
||||
|
||||
imp(ast_manager& m):
|
||||
m(m), dt(m), m_val(m) {}
|
||||
|
||||
virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
return lift_foreign(vars, lits);
|
||||
}
|
||||
|
||||
bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
expr_ref val(m);
|
||||
VERIFY(model.eval(var, val));
|
||||
SASSERT(is_app(val));
|
||||
TRACE("qe", tout << mk_pp(var, m) << " := " << val << "\n";);
|
||||
m_val = to_app(val);
|
||||
if (!dt.is_constructor(m_val)) {
|
||||
// assert: var does not occur in lits.
|
||||
return true;
|
||||
}
|
||||
m_var = alloc(contains_app, m, var);
|
||||
|
||||
|
||||
try {
|
||||
if (dt.is_recursive(m.get_sort(var))) {
|
||||
project_rec(model, vars, lits);
|
||||
}
|
||||
else {
|
||||
project_nonrec(model, vars, lits);
|
||||
}
|
||||
}
|
||||
catch (cant_project) {
|
||||
TRACE("qe", tout << "can't project:" << mk_pp(var, m) << "\n";);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void project_nonrec(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
expr_ref tmp(m), val(m);
|
||||
expr_ref_vector args(m);
|
||||
app_ref arg(m);
|
||||
SASSERT(dt.is_constructor(m_val));
|
||||
func_decl* f = m_val->get_decl();
|
||||
ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(f);
|
||||
for (unsigned i = 0; i < acc.size(); ++i) {
|
||||
arg = m.mk_fresh_const(acc[i]->get_name().str().c_str(), acc[i]->get_range());
|
||||
model.register_decl(arg->get_decl(), m_val->get_arg(i));
|
||||
args.push_back(arg);
|
||||
}
|
||||
val = m.mk_app(f, args.size(), args.c_ptr());
|
||||
TRACE("qe", tout << mk_pp(m_var->x(), m) << " |-> " << val << "\n";);
|
||||
reduce(val, lits);
|
||||
}
|
||||
|
||||
void project_rec(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
func_decl* f = m_val->get_decl();
|
||||
expr_ref rhs(m);
|
||||
expr_ref_vector eqs(m);
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
if (solve(model, vars, lits[i].get(), rhs, eqs)) {
|
||||
project_plugin::erase(lits, i);
|
||||
reduce(rhs, lits);
|
||||
lits.append(eqs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, unfold the constructor associated with m_var
|
||||
// once according to the model. In this way, selector-constructor
|
||||
// redexes are reduced and disequalities are eventually solved
|
||||
// by virtue of the constructors being different.
|
||||
project_nonrec(model, vars, lits);
|
||||
}
|
||||
|
||||
void reduce(expr* val, expr_ref_vector& lits) {
|
||||
expr_safe_replace sub(m);
|
||||
th_rewriter rw(m);
|
||||
expr_ref tmp(m);
|
||||
sub.insert(m_var->x(), val);
|
||||
TRACE("qe", tout << mk_pp(m_var->x(), m) << " = " << mk_pp(val, m) << "\n";
|
||||
tout << lits << "\n";);
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
sub(lits[i].get(), tmp);
|
||||
rw(tmp);
|
||||
lits[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
bool contains_x(expr* e) {
|
||||
return (*m_var)(e);
|
||||
}
|
||||
|
||||
bool solve(model& model, app_ref_vector& vars, expr* fml, expr_ref& t, expr_ref_vector& eqs) {
|
||||
expr* t1, *t2;
|
||||
if (m.is_eq(fml, t1, t2)) {
|
||||
if (contains_x(t1) && !contains_x(t2) && is_app(t1)) {
|
||||
return solve(model, vars, to_app(t1), t2, t, eqs);
|
||||
}
|
||||
if (contains_x(t2) && !contains_x(t1) && is_app(t2)) {
|
||||
return solve(model, vars, to_app(t2), t1, t, eqs);
|
||||
}
|
||||
}
|
||||
if (m.is_not(fml, t1) && m.is_distinct(t1)) {
|
||||
expr_ref eq = project_plugin::pick_equality(m, model, t1);
|
||||
return solve(model, vars, eq, t, eqs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool solve(model& model, app_ref_vector& vars, app* a, expr* b, expr_ref& t, expr_ref_vector& eqs) {
|
||||
SASSERT(contains_x(a));
|
||||
SASSERT(!contains_x(b));
|
||||
if (m_var->x() == a) {
|
||||
t = b;
|
||||
return true;
|
||||
}
|
||||
if (!dt.is_constructor(a)) {
|
||||
return false;
|
||||
}
|
||||
func_decl* c = a->get_decl();
|
||||
func_decl* rec = dt.get_constructor_recognizer(c);
|
||||
ptr_vector<func_decl> const & acc = *dt.get_constructor_accessors(c);
|
||||
SASSERT(acc.size() == a->get_num_args());
|
||||
//
|
||||
// It suffices to solve just the first available equality.
|
||||
// The others are determined by the first.
|
||||
//
|
||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||
expr* l = a->get_arg(i);
|
||||
if (is_app(l) && contains_x(l)) {
|
||||
expr_ref r(m);
|
||||
r = access(c, i, acc, b);
|
||||
if (solve(model, vars, to_app(l), r, t, eqs)) {
|
||||
for (unsigned j = 0; j < c->get_arity(); ++j) {
|
||||
if (i != j) {
|
||||
eqs.push_back(m.mk_eq(access(c, j, acc, b), a->get_arg(j)));
|
||||
}
|
||||
}
|
||||
if (!is_app_of(b, c)) {
|
||||
eqs.push_back(m.mk_app(rec, b));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
expr* access(func_decl* c, unsigned i, ptr_vector<func_decl> const& acc, expr* e) {
|
||||
if (is_app_of(e,c)) {
|
||||
return to_app(e)->get_arg(i);
|
||||
}
|
||||
else {
|
||||
return m.mk_app(acc[i], e);
|
||||
}
|
||||
}
|
||||
|
||||
bool lift_foreign(app_ref_vector const& vars, expr_ref_vector& lits) {
|
||||
|
||||
bool reduced = false;
|
||||
expr_mark visited;
|
||||
expr_mark has_var;
|
||||
bool inserted = false;
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
if (m.is_bool(vars[i])) continue;
|
||||
if (dt.is_datatype(m.get_sort(vars[i]))) continue;
|
||||
inserted = true;
|
||||
has_var.mark(vars[i]);
|
||||
visited.mark(vars[i]);
|
||||
}
|
||||
if (inserted) {
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
expr* e = lits[i].get(), *l, *r;
|
||||
if (m.is_eq(e, l, r) && reduce_eq(visited, has_var, l, r, lits)) {
|
||||
project_plugin::erase(lits, i);
|
||||
reduced = true;
|
||||
}
|
||||
}
|
||||
CTRACE("qe", reduced, tout << vars << "\n" << lits << "\n";);
|
||||
}
|
||||
return reduced;
|
||||
}
|
||||
|
||||
bool reduce_eq(expr_mark& has_var, expr_mark& visited, expr* l, expr* r, expr_ref_vector& lits) {
|
||||
if (!is_app(l) || !is_app(r)) {
|
||||
return false;
|
||||
}
|
||||
bool reduce = false;
|
||||
if (dt.is_constructor(to_app(r)) && contains_foreign(has_var, visited, r)) {
|
||||
std::swap(l, r);
|
||||
reduce = true;
|
||||
}
|
||||
reduce |= dt.is_constructor(to_app(l)) && contains_foreign(has_var, visited, l);
|
||||
if (!reduce) {
|
||||
return false;
|
||||
}
|
||||
func_decl* c = to_app(l)->get_decl();
|
||||
ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(c);
|
||||
if (!is_app_of(r, c)) {
|
||||
lits.push_back(m.mk_app(dt.get_constructor_recognizer(c), r));
|
||||
}
|
||||
for (unsigned i = 0; i < acc.size(); ++i) {
|
||||
lits.push_back(m.mk_eq(to_app(l)->get_arg(i), access(c, i, acc, r)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
ptr_vector<expr> todo;
|
||||
|
||||
bool contains_foreign(expr_mark& has_var, expr_mark& visited, expr* e) {
|
||||
todo.push_back(e);
|
||||
while (!todo.empty()) {
|
||||
expr* _f = todo.back();
|
||||
if (visited.is_marked(_f)) {
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
if (!is_app(_f)) {
|
||||
visited.mark(_f);
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
app* f = to_app(_f);
|
||||
bool has_new = false, has_v = false;
|
||||
for (unsigned i = 0; i < f->get_num_args(); ++i) {
|
||||
expr* arg = f->get_arg(i);
|
||||
if (!visited.is_marked(arg)) {
|
||||
todo.push_back(arg);
|
||||
has_new = true;
|
||||
}
|
||||
else {
|
||||
has_v |= has_var.is_marked(arg);
|
||||
}
|
||||
}
|
||||
if (has_new) {
|
||||
continue;
|
||||
}
|
||||
todo.pop_back();
|
||||
if (has_v) {
|
||||
has_var.mark(f);
|
||||
}
|
||||
TRACE("qe", tout << "contains: " << mk_pp(f, m) << " " << has_var.is_marked(f) << "\n";);
|
||||
visited.mark(f);
|
||||
}
|
||||
TRACE("qe", tout << "contains: " << mk_pp(e, m) << " " << has_var.is_marked(e) << "\n";);
|
||||
return has_var.is_marked(e);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
datatype_project_plugin::datatype_project_plugin(ast_manager& m) {
|
||||
m_imp = alloc(imp, m);
|
||||
}
|
||||
|
||||
datatype_project_plugin::~datatype_project_plugin() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
bool datatype_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
return (*m_imp)(model, var, vars, lits);
|
||||
}
|
||||
|
||||
bool datatype_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
return m_imp->solve(model, vars, lits);
|
||||
}
|
||||
|
||||
|
||||
family_id datatype_project_plugin::get_family_id() {
|
||||
return m_imp->dt.get_family_id();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
42
src/qe/qe_datatypes.h
Normal file
42
src/qe/qe_datatypes.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qe_datatypes.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Model based projection for algebraic datatypes
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-06-13
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#ifndef __QE_DATATYPES_H_
|
||||
#define __QE_DATATYPES_H_
|
||||
|
||||
#include "datatype_decl_plugin.h"
|
||||
#include "qe_mbp.h"
|
||||
|
||||
namespace qe {
|
||||
|
||||
class datatype_project_plugin : public project_plugin {
|
||||
struct imp;
|
||||
imp* m_imp;
|
||||
public:
|
||||
datatype_project_plugin(ast_manager& m);
|
||||
virtual ~datatype_project_plugin();
|
||||
virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits);
|
||||
virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits);
|
||||
virtual family_id get_family_id();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -21,7 +21,6 @@ Revision History:
|
|||
#include "expr_abstract.h"
|
||||
#include "used_vars.h"
|
||||
#include "occurs.h"
|
||||
#include "for_each_expr.h"
|
||||
#include "rewriter_def.h"
|
||||
#include "ast_pp.h"
|
||||
#include "ast_ll_pp.h"
|
||||
|
@ -31,7 +30,6 @@ Revision History:
|
|||
#include "var_subst.h"
|
||||
#include "uint_set.h"
|
||||
#include "ast_util.h"
|
||||
#include "qe_util.h"
|
||||
#include "th_rewriter.h"
|
||||
#include "for_each_expr.h"
|
||||
#include "expr_safe_replace.h"
|
||||
|
@ -493,6 +491,10 @@ namespace eq {
|
|||
m_new_args.push_back(args[i]);
|
||||
}
|
||||
}
|
||||
if (m_new_args.size() == num_args) {
|
||||
r = q;
|
||||
return;
|
||||
}
|
||||
|
||||
expr_ref t(m);
|
||||
if (q->is_forall()) {
|
||||
|
@ -773,7 +775,7 @@ namespace eq {
|
|||
proof_ref curr_pr(m);
|
||||
q = to_quantifier(r);
|
||||
reduce_quantifier1(q, r, curr_pr);
|
||||
if (m.proofs_enabled()) {
|
||||
if (m.proofs_enabled() && r != q) {
|
||||
pr = m.mk_transitivity(pr, curr_pr);
|
||||
}
|
||||
} while (q != r && is_quantifier(r));
|
||||
|
@ -2299,7 +2301,7 @@ public:
|
|||
}
|
||||
m_imp(indices, true, result);
|
||||
if (is_forall(q)) {
|
||||
result = m.mk_not(result);
|
||||
result = push_not(result);
|
||||
}
|
||||
result = m.update_quantifier(
|
||||
q,
|
||||
|
@ -2424,9 +2426,6 @@ public:
|
|||
TRACE("qe_lite", for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
tout << mk_pp(fmls[i].get(), m) << "\n";
|
||||
});
|
||||
IF_VERBOSE(3, for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
verbose_stream() << mk_pp(fmls[i].get(), m) << "\n";
|
||||
});
|
||||
is_variable_test is_var(index_set, index_of_bound);
|
||||
m_der.set_is_variable_proc(is_var);
|
||||
m_fm.set_is_variable_proc(is_var);
|
||||
|
@ -2481,6 +2480,41 @@ class qe_lite_tactic : public tactic {
|
|||
cooperate("qe-lite");
|
||||
}
|
||||
|
||||
void debug_diff(expr* a, expr* b) {
|
||||
ptr_vector<expr> as, bs;
|
||||
as.push_back(a);
|
||||
bs.push_back(b);
|
||||
expr* a1, *a2, *b1, *b2;
|
||||
while (!as.empty()) {
|
||||
a = as.back();
|
||||
b = bs.back();
|
||||
as.pop_back();
|
||||
bs.pop_back();
|
||||
if (a == b) {
|
||||
continue;
|
||||
}
|
||||
else if (is_forall(a) && is_forall(b)) {
|
||||
as.push_back(to_quantifier(a)->get_expr());
|
||||
bs.push_back(to_quantifier(b)->get_expr());
|
||||
}
|
||||
else if (m.is_and(a, a1, a2) && m.is_and(b, b1, b2)) {
|
||||
as.push_back(a1);
|
||||
as.push_back(a2);
|
||||
bs.push_back(b1);
|
||||
bs.push_back(b2);
|
||||
}
|
||||
else if (m.is_eq(a, a1, a2) && m.is_eq(b, b1, b2)) {
|
||||
as.push_back(a1);
|
||||
as.push_back(a2);
|
||||
bs.push_back(b1);
|
||||
bs.push_back(b2);
|
||||
}
|
||||
else {
|
||||
TRACE("qe", tout << mk_pp(a, m) << " != " << mk_pp(b, m) << "\n";);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
|
@ -2512,7 +2546,10 @@ class qe_lite_tactic : public tactic {
|
|||
new_pr = g->pr(i);
|
||||
}
|
||||
}
|
||||
g->update(i, new_f, new_pr, g->dep(i));
|
||||
if (f != new_f) {
|
||||
TRACE("qe", tout << mk_pp(f, m) << "\n" << new_f << "\n";);
|
||||
g->update(i, new_f, new_pr, g->dep(i));
|
||||
}
|
||||
}
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
|
|
369
src/qe/qe_mbp.cpp
Normal file
369
src/qe/qe_mbp.cpp
Normal file
|
@ -0,0 +1,369 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qe_mbp.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Model-based projection utilities
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-5-29
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "qe_mbp.h"
|
||||
#include "qe_arith.h"
|
||||
#include "qe_arrays.h"
|
||||
#include "qe_datatypes.h"
|
||||
#include "expr_safe_replace.h"
|
||||
#include "ast_pp.h"
|
||||
#include "ast_util.h"
|
||||
#include "th_rewriter.h"
|
||||
#include "model_v2_pp.h"
|
||||
#include "expr_functors.h"
|
||||
|
||||
|
||||
using namespace qe;
|
||||
|
||||
|
||||
/**
|
||||
\brief return two terms that are equal in the model.
|
||||
The distinct term t is false in model, so there
|
||||
are at least two arguments of t that are equal in the model.
|
||||
*/
|
||||
expr_ref project_plugin::pick_equality(ast_manager& m, model& model, expr* t) {
|
||||
SASSERT(m.is_distinct(t));
|
||||
expr_ref val(m);
|
||||
expr_ref_vector vals(m);
|
||||
obj_map<expr, expr*> val2expr;
|
||||
app* alit = to_app(t);
|
||||
for (unsigned i = 0; i < alit->get_num_args(); ++i) {
|
||||
expr* e1 = alit->get_arg(i), *e2;
|
||||
VERIFY(model.eval(e1, val));
|
||||
if (val2expr.find(val, e2)) {
|
||||
return expr_ref(m.mk_eq(e1, e2), m);
|
||||
}
|
||||
val2expr.insert(val, e1);
|
||||
vals.push_back(val);
|
||||
}
|
||||
UNREACHABLE();
|
||||
return expr_ref(0, m);
|
||||
}
|
||||
|
||||
void project_plugin::partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits) {
|
||||
ast_manager& m = vals.get_manager();
|
||||
expr_ref val(m);
|
||||
expr_ref_vector trail(m), reps(m);
|
||||
obj_map<expr, expr*> roots;
|
||||
for (unsigned i = 0; i < vals.size(); ++i) {
|
||||
expr* v = vals[i], *root;
|
||||
VERIFY (model.eval(v, val));
|
||||
if (roots.find(val, root)) {
|
||||
lits.push_back(m.mk_eq(v, root));
|
||||
}
|
||||
else {
|
||||
roots.insert(val, v);
|
||||
trail.push_back(val);
|
||||
reps.push_back(v);
|
||||
}
|
||||
}
|
||||
if (reps.size() > 1) {
|
||||
lits.push_back(mk_distinct(reps));
|
||||
}
|
||||
}
|
||||
|
||||
void project_plugin::partition_args(model& model, app_ref_vector const& selects, expr_ref_vector& lits) {
|
||||
ast_manager& m = selects.get_manager();
|
||||
if (selects.empty()) return;
|
||||
unsigned num_args = selects[0]->get_decl()->get_arity();
|
||||
for (unsigned j = 1; j < num_args; ++j) {
|
||||
expr_ref_vector args(m);
|
||||
for (unsigned i = 0; i < selects.size(); ++i) {
|
||||
args.push_back(selects[i]->get_arg(j));
|
||||
}
|
||||
project_plugin::partition_values(model, args, lits);
|
||||
}
|
||||
}
|
||||
|
||||
void project_plugin::erase(expr_ref_vector& lits, unsigned& i) {
|
||||
lits[i] = lits.back();
|
||||
lits.pop_back();
|
||||
--i;
|
||||
}
|
||||
|
||||
void project_plugin::push_back(expr_ref_vector& lits, expr* e) {
|
||||
if (lits.get_manager().is_true(e)) return;
|
||||
lits.push_back(e);
|
||||
}
|
||||
|
||||
|
||||
class mbp::impl {
|
||||
ast_manager& m;
|
||||
ptr_vector<project_plugin> m_plugins;
|
||||
|
||||
void add_plugin(project_plugin* p) {
|
||||
family_id fid = p->get_family_id();
|
||||
SASSERT(!m_plugins.get(fid, 0));
|
||||
m_plugins.setx(fid, p, 0);
|
||||
}
|
||||
|
||||
project_plugin* get_plugin(app* var) {
|
||||
family_id fid = m.get_sort(var)->get_family_id();
|
||||
return m_plugins.get(fid, 0);
|
||||
}
|
||||
|
||||
bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) {
|
||||
expr_mark is_var, is_rem;
|
||||
if (vars.empty()) {
|
||||
return false;
|
||||
}
|
||||
bool reduced = false;
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
is_var.mark(vars[i].get());
|
||||
}
|
||||
expr_ref tmp(m), t(m), v(m);
|
||||
th_rewriter rw(m);
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
expr* e = lits[i].get(), *l, *r;
|
||||
if (m.is_eq(e, l, r) && reduce_eq(is_var, l, r, v, t)) {
|
||||
reduced = true;
|
||||
project_plugin::erase(lits, i);
|
||||
expr_safe_replace sub(m);
|
||||
sub.insert(v, t);
|
||||
is_rem.mark(v);
|
||||
for (unsigned j = 0; j < lits.size(); ++j) {
|
||||
sub(lits[j].get(), tmp);
|
||||
rw(tmp);
|
||||
lits[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reduced) {
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
if (!is_rem.is_marked(vars[i].get())) {
|
||||
if (i != j) {
|
||||
vars[j] = vars[i].get();
|
||||
}
|
||||
++j;
|
||||
}
|
||||
}
|
||||
vars.shrink(j);
|
||||
}
|
||||
return reduced;
|
||||
}
|
||||
|
||||
bool reduce_eq(expr_mark& is_var, expr* l, expr* r, expr_ref& v, expr_ref& t) {
|
||||
if (is_var.is_marked(r)) {
|
||||
std::swap(l, r);
|
||||
}
|
||||
if (is_var.is_marked(l)) {
|
||||
contains_app cont(m, to_app(l));
|
||||
if (!cont(r)) {
|
||||
v = to_app(l);
|
||||
t = r;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void extract_literals(model& model, expr_ref_vector& fmls) {
|
||||
expr_ref val(m);
|
||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
expr* fml = fmls[i].get(), *nfml, *f1, *f2, *f3;
|
||||
if (m.is_not(fml, nfml) && m.is_distinct(nfml)) {
|
||||
fmls[i] = project_plugin::pick_equality(m, model, nfml);
|
||||
--i;
|
||||
}
|
||||
else if (m.is_or(fml)) {
|
||||
for (unsigned j = 0; j < to_app(fml)->get_num_args(); ++j) {
|
||||
VERIFY (model.eval(to_app(fml)->get_arg(j), val));
|
||||
if (m.is_true(val)) {
|
||||
fmls[i] = to_app(fml)->get_arg(j);
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m.is_and(fml)) {
|
||||
fmls.append(to_app(fml)->get_num_args(), to_app(fml)->get_args());
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else if (m.is_iff(fml, f1, f2) || (m.is_not(fml, nfml) && m.is_xor(nfml, f1, f2))) {
|
||||
VERIFY (model.eval(f1, val));
|
||||
if (m.is_false(val)) {
|
||||
f1 = mk_not(m, f1);
|
||||
f2 = mk_not(m, f2);
|
||||
}
|
||||
project_plugin::push_back(fmls, f1);
|
||||
project_plugin::push_back(fmls, f2);
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else if (m.is_implies(fml, f1, f2)) {
|
||||
VERIFY (model.eval(f2, val));
|
||||
if (m.is_true(val)) {
|
||||
project_plugin::push_back(fmls, f2);
|
||||
}
|
||||
else {
|
||||
project_plugin::push_back(fmls, mk_not(m, f1));
|
||||
}
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else if (m.is_ite(fml, f1, f2, f3)) {
|
||||
VERIFY (model.eval(f1, val));
|
||||
if (m.is_true(val)) {
|
||||
project_plugin::push_back(fmls, f2);
|
||||
}
|
||||
else {
|
||||
project_plugin::push_back(fmls, f3);
|
||||
}
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else if (m.is_not(fml, nfml) && m.is_not(nfml, nfml)) {
|
||||
project_plugin::push_back(fmls, nfml);
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else if (m.is_not(fml, nfml) && m.is_and(nfml)) {
|
||||
for (unsigned j = 0; j < to_app(nfml)->get_num_args(); ++j) {
|
||||
VERIFY (model.eval(to_app(nfml)->get_arg(j), val));
|
||||
if (m.is_false(val)) {
|
||||
fmls[i] = mk_not(m, to_app(nfml)->get_arg(j));
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m.is_not(fml, nfml) && m.is_or(nfml)) {
|
||||
for (unsigned j = 0; j < to_app(nfml)->get_num_args(); ++j) {
|
||||
project_plugin::push_back(fmls, mk_not(m, to_app(nfml)->get_arg(j)));
|
||||
}
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else if ((m.is_not(fml, nfml) && m.is_iff(nfml, f1, f2)) || m.is_xor(fml, f1, f2)) {
|
||||
VERIFY (model.eval(f1, val));
|
||||
if (m.is_true(val)) {
|
||||
f2 = mk_not(m, f2);
|
||||
}
|
||||
else {
|
||||
f1 = mk_not(m, f1);
|
||||
}
|
||||
project_plugin::push_back(fmls, f1);
|
||||
project_plugin::push_back(fmls, f2);
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else if (m.is_not(fml, nfml) && m.is_implies(nfml, f1, f2)) {
|
||||
project_plugin::push_back(fmls, f1);
|
||||
project_plugin::push_back(fmls, mk_not(m, f2));
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else if (m.is_not(fml, nfml) && m.is_ite(nfml, f1, f2, f3)) {
|
||||
VERIFY (model.eval(f1, val));
|
||||
if (m.is_true(val)) {
|
||||
project_plugin::push_back(fmls, mk_not(m, f2));
|
||||
}
|
||||
else {
|
||||
project_plugin::push_back(fmls, mk_not(m, f3));
|
||||
}
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else {
|
||||
// TBD other Boolean operations.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl(ast_manager& m):m(m) {
|
||||
add_plugin(alloc(arith_project_plugin, m));
|
||||
add_plugin(alloc(datatype_project_plugin, m));
|
||||
add_plugin(alloc(array_project_plugin, m));
|
||||
}
|
||||
|
||||
~impl() {
|
||||
std::for_each(m_plugins.begin(), m_plugins.end(), delete_proc<project_plugin>());
|
||||
}
|
||||
|
||||
void preprocess_solve(model& model, app_ref_vector& vars, expr_ref_vector& fmls) {
|
||||
extract_literals(model, fmls);
|
||||
bool change = true;
|
||||
while (change && !vars.empty()) {
|
||||
change = solve(model, vars, fmls);
|
||||
for (unsigned i = 0; i < m_plugins.size(); ++i) {
|
||||
if (m_plugins[i] && m_plugins[i]->solve(model, vars, fmls)) {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls) {
|
||||
expr_ref val(m), tmp(m);
|
||||
app_ref var(m);
|
||||
th_rewriter rw(m);
|
||||
bool progress = true;
|
||||
while (progress && !vars.empty()) {
|
||||
preprocess_solve(model, vars, fmls);
|
||||
app_ref_vector new_vars(m);
|
||||
progress = false;
|
||||
while (!vars.empty()) {
|
||||
var = vars.back();
|
||||
vars.pop_back();
|
||||
project_plugin* p = get_plugin(var);
|
||||
if (p && (*p)(model, var, vars, fmls)) {
|
||||
progress = true;
|
||||
}
|
||||
else {
|
||||
new_vars.push_back(var);
|
||||
}
|
||||
}
|
||||
if (!progress && !new_vars.empty() && force_elim) {
|
||||
var = new_vars.back();
|
||||
new_vars.pop_back();
|
||||
expr_safe_replace sub(m);
|
||||
VERIFY(model.eval(var, val));
|
||||
sub.insert(var, val);
|
||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
sub(fmls[i].get(), tmp);
|
||||
rw(tmp);
|
||||
if (m.is_true(tmp)) {
|
||||
project_plugin::erase(fmls, i);
|
||||
}
|
||||
else {
|
||||
fmls[i] = tmp;
|
||||
}
|
||||
}
|
||||
progress = true;
|
||||
}
|
||||
vars.append(new_vars);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
mbp::mbp(ast_manager& m) {
|
||||
m_impl = alloc(impl, m);
|
||||
}
|
||||
|
||||
mbp::~mbp() {
|
||||
dealloc(m_impl);
|
||||
}
|
||||
|
||||
void mbp::operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls) {
|
||||
(*m_impl)(force_elim, vars, mdl, fmls);
|
||||
}
|
||||
|
||||
void mbp::solve(model& model, app_ref_vector& vars, expr_ref_vector& fmls) {
|
||||
m_impl->preprocess_solve(model, vars, fmls);
|
||||
}
|
||||
|
||||
void mbp::extract_literals(model& model, expr_ref_vector& lits) {
|
||||
m_impl->extract_literals(model, lits);
|
||||
}
|
76
src/qe/qe_mbp.h
Normal file
76
src/qe/qe_mbp.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qe_mbp.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Model-based projection utilities
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-5-28
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __QE_MBP_H__
|
||||
#define __QE_MBP_H__
|
||||
|
||||
#include "ast.h"
|
||||
#include "params.h"
|
||||
#include "model.h"
|
||||
|
||||
|
||||
namespace qe {
|
||||
|
||||
struct cant_project {};
|
||||
|
||||
class project_plugin {
|
||||
public:
|
||||
virtual ~project_plugin() {}
|
||||
virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) = 0;
|
||||
virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) = 0;
|
||||
virtual family_id get_family_id() = 0;
|
||||
|
||||
static expr_ref pick_equality(ast_manager& m, model& model, expr* t);
|
||||
static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits);
|
||||
static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits);
|
||||
static void erase(expr_ref_vector& lits, unsigned& i);
|
||||
static void push_back(expr_ref_vector& lits, expr* lit);
|
||||
};
|
||||
|
||||
class mbp {
|
||||
class impl;
|
||||
impl * m_impl;
|
||||
public:
|
||||
mbp(ast_manager& m);
|
||||
|
||||
~mbp();
|
||||
|
||||
/**
|
||||
\brief
|
||||
Apply model-based qe on constants provided as vector of variables.
|
||||
Return the updated formula and updated set of variables that were not eliminated.
|
||||
*/
|
||||
void operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls);
|
||||
|
||||
/**
|
||||
\brief
|
||||
Solve as many variables as possible using "cheap" quantifier elimination"
|
||||
*/
|
||||
void solve(model& model, app_ref_vector& vars, expr_ref_vector& lits);
|
||||
|
||||
/**
|
||||
\brief
|
||||
Extract literals from formulas based on model.
|
||||
*/
|
||||
void extract_literals(model& model, expr_ref_vector& lits);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -22,6 +22,7 @@ Revision History:
|
|||
#include"qe.h"
|
||||
|
||||
class qe_tactic : public tactic {
|
||||
statistics m_st;
|
||||
struct imp {
|
||||
ast_manager & m;
|
||||
smt_params m_fparams;
|
||||
|
@ -78,10 +79,19 @@ class qe_tactic : public tactic {
|
|||
g->update(i, new_f, new_pr, g->dep(i));
|
||||
}
|
||||
g->inc_depth();
|
||||
g->elim_true();
|
||||
result.push_back(g.get());
|
||||
TRACE("qe", g->display(tout););
|
||||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
|
||||
void collect_statistics(statistics & st) const {
|
||||
m_qe.collect_statistics(st);
|
||||
}
|
||||
|
||||
void reset_statistics() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
imp * m_imp;
|
||||
|
@ -117,7 +127,19 @@ public:
|
|||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
(*m_imp)(in, result, mc, pc, core);
|
||||
m_st.reset();
|
||||
m_imp->collect_statistics(m_st);
|
||||
|
||||
}
|
||||
|
||||
virtual void collect_statistics(statistics & st) const {
|
||||
st.copy(m_st);
|
||||
}
|
||||
|
||||
virtual void reset_statistics() {
|
||||
m_st.reset();
|
||||
}
|
||||
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m;
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
|
||||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
--*/
|
||||
|
||||
#include "qe_util.h"
|
||||
#include "bool_rewriter.h"
|
||||
|
||||
namespace qe {
|
||||
|
||||
expr_ref mk_and(expr_ref_vector const& fmls) {
|
||||
ast_manager& m = fmls.get_manager();
|
||||
expr_ref result(m);
|
||||
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref mk_or(expr_ref_vector const& fmls) {
|
||||
ast_manager& m = fmls.get_manager();
|
||||
expr_ref result(m);
|
||||
bool_rewriter(m).mk_or(fmls.size(), fmls.c_ptr(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qe_util.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Utilities for quantifiers.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-08-28
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef QE_UTIL_H_
|
||||
#define QE_UTIL_H_
|
||||
|
||||
#include "ast.h"
|
||||
|
||||
namespace qe {
|
||||
|
||||
expr_ref mk_and(expr_ref_vector const& fmls);
|
||||
|
||||
expr_ref mk_or(expr_ref_vector const& fmls);
|
||||
|
||||
}
|
||||
#endif
|
1258
src/qe/qsat.cpp
Normal file
1258
src/qe/qsat.cpp
Normal file
File diff suppressed because it is too large
Load diff
146
src/qe/qsat.h
Normal file
146
src/qe/qsat.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qsat.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Quantifier Satisfiability Solver.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2015-5-28
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef QE_QSAT_H__
|
||||
#define QE_QSAT_H__
|
||||
|
||||
#include "tactic.h"
|
||||
#include "filter_model_converter.h"
|
||||
|
||||
namespace qe {
|
||||
|
||||
struct max_level {
|
||||
unsigned m_ex, m_fa;
|
||||
max_level(): m_ex(UINT_MAX), m_fa(UINT_MAX) {}
|
||||
void merge(max_level const& other) {
|
||||
merge(m_ex, other.m_ex);
|
||||
merge(m_fa, other.m_fa);
|
||||
}
|
||||
static unsigned max(unsigned a, unsigned b) {
|
||||
if (a == UINT_MAX) return b;
|
||||
if (b == UINT_MAX) return a;
|
||||
return std::max(a, b);
|
||||
}
|
||||
unsigned max() const {
|
||||
return max(m_ex, m_fa);
|
||||
}
|
||||
void merge(unsigned& lvl, unsigned other) {
|
||||
lvl = max(lvl, other);
|
||||
}
|
||||
std::ostream& display(std::ostream& out) const {
|
||||
if (m_ex != UINT_MAX) out << "e" << m_ex << " ";
|
||||
if (m_fa != UINT_MAX) out << "a" << m_fa << " ";
|
||||
return out;
|
||||
}
|
||||
|
||||
bool operator==(max_level const& other) const {
|
||||
return
|
||||
m_ex == other.m_ex &&
|
||||
m_fa == other.m_fa;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, max_level const& lvl) {
|
||||
return lvl.display(out);
|
||||
}
|
||||
|
||||
class pred_abs {
|
||||
ast_manager& m;
|
||||
vector<app_ref_vector> m_preds;
|
||||
expr_ref_vector m_asms;
|
||||
unsigned_vector m_asms_lim;
|
||||
obj_map<expr, expr*> m_pred2lit; // maintain definitions of predicates.
|
||||
obj_map<expr, app*> m_lit2pred; // maintain reverse mapping to predicates
|
||||
obj_map<expr, app*> m_asm2pred; // maintain map from assumptions to predicates
|
||||
obj_map<expr, expr*> m_pred2asm; // predicates |-> assumptions
|
||||
expr_ref_vector m_trail;
|
||||
filter_model_converter_ref m_fmc;
|
||||
ptr_vector<expr> todo;
|
||||
obj_map<expr, max_level> m_elevel;
|
||||
obj_map<func_decl, max_level> m_flevel;
|
||||
|
||||
template <typename T>
|
||||
void dec_keys(obj_map<expr, T*>& map) {
|
||||
typename obj_map<expr, T*>::iterator it = map.begin(), end = map.end();
|
||||
for (; it != end; ++it) {
|
||||
m.dec_ref(it->m_key);
|
||||
}
|
||||
}
|
||||
void add_lit(app* p, app* lit);
|
||||
void add_asm(app* p, expr* lit);
|
||||
bool is_predicate(app* a, unsigned l);
|
||||
void mk_concrete(expr_ref_vector& fmls, obj_map<expr, expr*> const& map);
|
||||
public:
|
||||
|
||||
pred_abs(ast_manager& m);
|
||||
filter_model_converter* fmc();
|
||||
void reset();
|
||||
max_level compute_level(app* e);
|
||||
void push();
|
||||
void pop(unsigned num_scopes);
|
||||
void insert(app* a, max_level const& lvl);
|
||||
void get_assumptions(model* mdl, expr_ref_vector& asms);
|
||||
void set_expr_level(app* v, max_level const& lvl);
|
||||
void set_decl_level(func_decl* v, max_level const& lvl);
|
||||
void abstract_atoms(expr* fml, max_level& level, expr_ref_vector& defs);
|
||||
void abstract_atoms(expr* fml, expr_ref_vector& defs);
|
||||
expr_ref mk_abstract(expr* fml);
|
||||
void pred2lit(expr_ref_vector& fmls);
|
||||
expr_ref pred2asm(expr* fml);
|
||||
void get_free_vars(expr* fml, app_ref_vector& vars);
|
||||
expr_ref mk_assumption_literal(expr* a, model* mdl, max_level const& lvl, expr_ref_vector& defs);
|
||||
void add_pred(app* p, app* lit);
|
||||
app_ref fresh_bool(char const* name);
|
||||
void display(std::ostream& out) const;
|
||||
void display(std::ostream& out, expr_ref_vector const& asms) const;
|
||||
void collect_statistics(statistics& st) const;
|
||||
};
|
||||
|
||||
class min_max_opt {
|
||||
struct imp;
|
||||
imp* m_imp;
|
||||
public:
|
||||
min_max_opt(ast_manager& m);
|
||||
~min_max_opt();
|
||||
void add(expr* e);
|
||||
void add(expr_ref_vector const& fmls);
|
||||
lbool check(svector<bool> const& is_max, app_ref_vector const& vars, app* t);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
tactic * mk_qsat_tactic(ast_manager & m, params_ref const& p = params_ref());
|
||||
|
||||
tactic * mk_qe2_tactic(ast_manager & m, params_ref const& p = params_ref());
|
||||
|
||||
tactic * mk_qe_rec_tactic(ast_manager & m, params_ref const& p = params_ref());
|
||||
|
||||
|
||||
/*
|
||||
ADD_TACTIC("qsat", "apply a QSAT solver.", "mk_qsat_tactic(m, p)")
|
||||
|
||||
ADD_TACTIC("qe2", "apply a QSAT based quantifier elimination.", "mk_qe2_tactic(m, p)")
|
||||
|
||||
ADD_TACTIC("qe_rec", "apply a QSAT based quantifier elimination recursively.", "mk_qe_rec_tactic(m, p)")
|
||||
|
||||
*/
|
||||
|
||||
#endif
|
|
@ -72,7 +72,7 @@ public:
|
|||
m_asmsf(m),
|
||||
m_fmls_head(0),
|
||||
m_core(m),
|
||||
m_map(m),
|
||||
m_map(m),
|
||||
m_num_scopes(0),
|
||||
m_dep_core(m),
|
||||
m_unknown("no reason given") {
|
||||
|
@ -163,14 +163,14 @@ public:
|
|||
m_fmls_lim.push_back(m_fmls.size());
|
||||
m_asms_lim.push_back(m_asmsf.size());
|
||||
m_fmls_head_lim.push_back(m_fmls_head);
|
||||
m_bb_rewriter->push();
|
||||
if (m_bb_rewriter) m_bb_rewriter->push();
|
||||
m_map.push();
|
||||
}
|
||||
virtual void pop(unsigned n) {
|
||||
if (n > m_num_scopes) { // allow inc_sat_solver to
|
||||
n = m_num_scopes; // take over for another solver.
|
||||
}
|
||||
m_bb_rewriter->pop(n);
|
||||
if (m_bb_rewriter) m_bb_rewriter->pop(n);
|
||||
m_map.pop(n);
|
||||
SASSERT(n <= m_num_scopes);
|
||||
m_solver.user_pop(n);
|
||||
|
@ -214,7 +214,7 @@ public:
|
|||
m_optimize_model = m_params.get_bool("optimize_model", false);
|
||||
}
|
||||
virtual void collect_statistics(statistics & st) const {
|
||||
m_preprocess->collect_statistics(st);
|
||||
if (m_preprocess) m_preprocess->collect_statistics(st);
|
||||
m_solver.collect_statistics(st);
|
||||
}
|
||||
virtual void get_unsat_core(ptr_vector<expr> & r) {
|
||||
|
@ -257,8 +257,10 @@ public:
|
|||
if (m_preprocess) {
|
||||
m_preprocess->reset();
|
||||
}
|
||||
if (!m_bb_rewriter) {
|
||||
m_bb_rewriter = alloc(bit_blaster_rewriter, m, m_params);
|
||||
}
|
||||
params_ref simp2_p = m_params;
|
||||
m_bb_rewriter = alloc(bit_blaster_rewriter, m, m_params);
|
||||
simp2_p.set_bool("som", true);
|
||||
simp2_p.set_bool("pull_cheap_ite", true);
|
||||
simp2_p.set_bool("push_ite_bv", false);
|
||||
|
@ -429,7 +431,7 @@ private:
|
|||
}
|
||||
m_model = md;
|
||||
|
||||
if (!m_bb_rewriter->const2bits().empty()) {
|
||||
if (m_bb_rewriter.get() && !m_bb_rewriter->const2bits().empty()) {
|
||||
m_mc0 = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits()));
|
||||
}
|
||||
if (m_mc0) {
|
||||
|
@ -440,7 +442,7 @@ private:
|
|||
DEBUG_CODE(
|
||||
for (unsigned i = 0; i < m_fmls.size(); ++i) {
|
||||
expr_ref tmp(m);
|
||||
if (m_model->eval(m_fmls[i].get(), tmp, true)) {
|
||||
if (m_model->eval(m_fmls[i].get(), tmp, true)) {
|
||||
CTRACE("sat", !m.is_true(tmp),
|
||||
tout << "Evaluation failed: " << mk_pp(m_fmls[i].get(), m)
|
||||
<< " to " << tmp << "\n";
|
||||
|
|
|
@ -509,7 +509,7 @@ struct sat2goal::imp {
|
|||
// This information may be stored as a vector of pairs.
|
||||
// The mapping is only created during the model conversion.
|
||||
expr_ref_vector m_var2expr;
|
||||
ref<filter_model_converter> m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion
|
||||
filter_model_converter_ref m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion
|
||||
|
||||
sat_model_converter(ast_manager & m):
|
||||
m_var2expr(m) {
|
||||
|
|
|
@ -109,7 +109,7 @@ static void on_timeout() {
|
|||
exit(0);
|
||||
}
|
||||
|
||||
static void on_ctrl_c(int) {
|
||||
static void STD_CALL on_ctrl_c(int) {
|
||||
signal (SIGINT, SIG_DFL);
|
||||
display_statistics();
|
||||
raise(SIGINT);
|
||||
|
|
|
@ -47,7 +47,7 @@ static void on_timeout() {
|
|||
exit(0);
|
||||
}
|
||||
|
||||
static void on_ctrl_c(int) {
|
||||
static void STD_CALL on_ctrl_c(int) {
|
||||
signal (SIGINT, SIG_DFL);
|
||||
display_statistics();
|
||||
raise(SIGINT);
|
||||
|
|
|
@ -66,7 +66,7 @@ void display_usage() {
|
|||
#ifdef Z3GITHASH
|
||||
std::cout << " - build hashcode " << STRINGIZE_VALUE_OF(Z3GITHASH);
|
||||
#endif
|
||||
std::cout << "]. (C) Copyright 2006-2014 Microsoft Corp.\n";
|
||||
std::cout << "]. (C) Copyright 2006-2016 Microsoft Corp.\n";
|
||||
std::cout << "Usage: z3 [options] [-file:]file\n";
|
||||
std::cout << "\nInput format:\n";
|
||||
std::cout << " -smt use parser for SMT input format.\n";
|
||||
|
@ -291,7 +291,7 @@ char const * get_extension(char const * file_name) {
|
|||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int STD_CALL main(int argc, char ** argv) {
|
||||
try{
|
||||
unsigned return_value = 0;
|
||||
memory::initialize(0);
|
||||
|
|
|
@ -305,7 +305,7 @@ static void display_statistics() {
|
|||
display_results();
|
||||
}
|
||||
|
||||
static void on_ctrl_c(int) {
|
||||
static void STD_CALL on_ctrl_c(int) {
|
||||
if (g_opt && g_first_interrupt) {
|
||||
g_opt->get_manager().limit().cancel();
|
||||
g_first_interrupt = false;
|
||||
|
|
|
@ -62,7 +62,7 @@ static void on_timeout() {
|
|||
}
|
||||
}
|
||||
|
||||
static void on_ctrl_c(int) {
|
||||
static void STD_CALL on_ctrl_c(int) {
|
||||
signal (SIGINT, SIG_DFL);
|
||||
#pragma omp critical (g_display_stats)
|
||||
{
|
||||
|
|
|
@ -607,27 +607,25 @@ void asserted_formulas::propagate_values() {
|
|||
expr_ref n(m_asserted_formulas.get(i), m_manager);
|
||||
proof_ref pr(m_asserted_formula_prs.get(i, 0), m_manager);
|
||||
TRACE("simplifier", tout << mk_pp(n, m_manager) << "\n";);
|
||||
if (m_manager.is_eq(n)) {
|
||||
expr * lhs = to_app(n)->get_arg(0);
|
||||
expr * rhs = to_app(n)->get_arg(1);
|
||||
if (m_manager.is_value(lhs) || m_manager.is_value(rhs)) {
|
||||
if (m_manager.is_value(lhs)) {
|
||||
std::swap(lhs, rhs);
|
||||
n = m_manager.mk_eq(lhs, rhs);
|
||||
pr = m_manager.mk_symmetry(pr);
|
||||
}
|
||||
if (!m_manager.is_value(lhs) && !m_simplifier.is_cached(lhs)) {
|
||||
if (i >= m_asserted_qhead) {
|
||||
new_exprs1.push_back(n);
|
||||
if (m_manager.proofs_enabled())
|
||||
new_prs1.push_back(pr);
|
||||
}
|
||||
TRACE("propagate_values", tout << "found:\n" << mk_pp(lhs, m_manager) << "\n->\n" << mk_pp(rhs, m_manager) << "\n";
|
||||
if (pr) tout << "proof: " << mk_pp(pr, m_manager) << "\n";);
|
||||
m_simplifier.cache_result(lhs, rhs, pr);
|
||||
found = true;
|
||||
continue;
|
||||
expr* lhs, *rhs;
|
||||
if (m_manager.is_eq(n, lhs, rhs) &&
|
||||
(m_manager.is_value(lhs) || m_manager.is_value(rhs))) {
|
||||
if (m_manager.is_value(lhs)) {
|
||||
std::swap(lhs, rhs);
|
||||
n = m_manager.mk_eq(lhs, rhs);
|
||||
pr = m_manager.mk_symmetry(pr);
|
||||
}
|
||||
if (!m_manager.is_value(lhs) && !m_simplifier.is_cached(lhs)) {
|
||||
if (i >= m_asserted_qhead) {
|
||||
new_exprs1.push_back(n);
|
||||
if (m_manager.proofs_enabled())
|
||||
new_prs1.push_back(pr);
|
||||
}
|
||||
TRACE("propagate_values", tout << "found:\n" << mk_pp(lhs, m_manager) << "\n->\n" << mk_pp(rhs, m_manager) << "\n";
|
||||
if (pr) tout << "proof: " << mk_pp(pr, m_manager) << "\n";);
|
||||
m_simplifier.cache_result(lhs, rhs, pr);
|
||||
found = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (i >= m_asserted_qhead) {
|
||||
|
@ -797,13 +795,7 @@ MK_SIMPLIFIER(apply_bit2int, bit2int& functor = m_bit2int, "bit2int", "propagate
|
|||
|
||||
MK_SIMPLIFIER(cheap_quant_fourier_motzkin, elim_bounds_star functor(m_manager), "elim_bounds", "cheap-fourier-motzkin", true);
|
||||
|
||||
// MK_SIMPLIFIER(quant_elim, qe::expr_quant_elim_star1 &functor = m_quant_elim,
|
||||
// "quantifiers", "quantifier elimination procedures", true);
|
||||
|
||||
bool asserted_formulas::quant_elim() {
|
||||
throw default_exception("QUANT_ELIM option is deprecated, please consider using the 'qe' tactic.");
|
||||
return false;
|
||||
}
|
||||
|
||||
MK_SIMPLIFIER(elim_bvs_from_quantifiers, bv_elim_star functor(m_manager), "bv_elim", "eliminate-bit-vectors-from-quantifiers", true);
|
||||
|
||||
|
|
|
@ -55,7 +55,6 @@ class asserted_formulas {
|
|||
maximise_bv_sharing m_bv_sharing;
|
||||
|
||||
bool m_inconsistent;
|
||||
// qe::expr_quant_elim_star1 m_quant_elim;
|
||||
|
||||
struct scope {
|
||||
unsigned m_asserted_formulas_lim;
|
||||
|
@ -84,7 +83,6 @@ class asserted_formulas {
|
|||
void eliminate_and();
|
||||
void refine_inj_axiom();
|
||||
bool cheap_quant_fourier_motzkin();
|
||||
bool quant_elim();
|
||||
void apply_distribute_forall();
|
||||
bool apply_bit2int();
|
||||
void lift_ite();
|
||||
|
@ -106,7 +104,6 @@ public:
|
|||
void assert_expr(expr * e, proof * in_pr);
|
||||
void assert_expr(expr * e);
|
||||
void reset();
|
||||
void set_cancel_flag(bool f);
|
||||
void push_scope();
|
||||
void pop_scope(unsigned num_scopes);
|
||||
bool inconsistent() const { return m_inconsistent; }
|
||||
|
|
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