3
0
Fork 0
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:
Christoph M. Wintersteiger 2016-03-31 18:11:30 +01:00
commit b178420797
174 changed files with 9762 additions and 2502 deletions

View file

@ -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());
}

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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'; );

View file

@ -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();

View file

@ -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); }

View file

@ -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`.

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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());

View file

@ -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;

View file

@ -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

View file

@ -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";
}

View file

@ -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;

View file

@ -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.
*/

View file

@ -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);

View file

@ -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_ */

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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

View file

@ -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) {

View file

@ -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);

View file

@ -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;
}

View file

@ -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, &parameters[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, &parameters[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);
}

View file

@ -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); }

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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();

View file

@ -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());

View file

@ -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

View 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>;

View 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

View file

@ -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"

View file

@ -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;

View file

@ -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 {

View file

@ -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);
}

View file

@ -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();

View file

@ -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) {

View file

@ -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);

View file

@ -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";);

View file

@ -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);
}

View file

@ -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;

View file

@ -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)));

View file

@ -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;
}

View file

@ -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)'),
))

View file

@ -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>;

View file

@ -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;

View file

@ -29,7 +29,6 @@ Revision History:
#include"ast_counter.h"
#include"statistics.h"
#include"lbool.h"
#include"qe_util.h"
namespace datalog {

View file

@ -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;
}

View file

@ -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"

View file

@ -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 {

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
};
}

View file

@ -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>

View file

@ -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"

View file

@ -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";
}
}
}
};
/**

View file

@ -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() {

View file

@ -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;

View file

@ -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

View file

@ -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);
};
};

View file

@ -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);
}
};

View file

@ -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;
}

View file

@ -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
*/

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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

File diff suppressed because it is too large Load diff

38
src/qe/nlqsat.h Normal file
View 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

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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
View 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
View 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
View 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
View 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

View file

@ -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
View 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
View 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

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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

File diff suppressed because it is too large Load diff

146
src/qe/qsat.h Normal file
View 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

View file

@ -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";

View file

@ -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) {

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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)
{

View file

@ -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);

View file

@ -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