3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-03 11:25:40 +00:00

Merge branch 'unstable' of https://git01.codeplex.com/z3 into unstable

This commit is contained in:
Nikolaj Bjorner 2014-07-28 09:59:40 -07:00
commit 4ab9c8fd00
22 changed files with 223 additions and 109 deletions

View file

@ -764,7 +764,7 @@ class Component:
out.write('\n') out.write('\n')
mk_dir(os.path.join(BUILD_DIR, self.build_dir)) mk_dir(os.path.join(BUILD_DIR, self.build_dir))
if VS_PAR and IS_WINDOWS: if VS_PAR and IS_WINDOWS:
cppfiles = get_cpp_files(self.src_dir) cppfiles = list(get_cpp_files(self.src_dir))
dependencies = set() dependencies = set()
for cppfile in cppfiles: for cppfile in cppfiles:
dependencies.add(os.path.join(self.to_src_dir, cppfile)) dependencies.add(os.path.join(self.to_src_dir, cppfile))
@ -2591,16 +2591,17 @@ def mk_vs_proj(name, components):
def mk_win_dist(build_path, dist_path): def mk_win_dist(build_path, dist_path):
for c in get_components(): for c in get_components():
c.mk_win_dist(build_path, dist_path) c.mk_win_dist(build_path, dist_path)
# Add Z3Py to lib directory # Add Z3Py to bin directory
for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(build_path)): print("Adding to %s\n" % dist_path)
for pyc in filter(lambda f: f.endswith('.pyc') or f.endswith('.py'), os.listdir(build_path)):
shutil.copy(os.path.join(build_path, pyc), shutil.copy(os.path.join(build_path, pyc),
os.path.join(dist_path, 'bin', pyc)) os.path.join(dist_path, 'bin', pyc))
def mk_unix_dist(build_path, dist_path): def mk_unix_dist(build_path, dist_path):
for c in get_components(): for c in get_components():
c.mk_unix_dist(build_path, dist_path) c.mk_unix_dist(build_path, dist_path)
# Add Z3Py to lib directory # Add Z3Py to bin directory
for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(build_path)): for pyc in filter(lambda f: f.endswith('.pyc') or f.endswith('.py'), os.listdir(build_path)):
shutil.copy(os.path.join(build_path, pyc), shutil.copy(os.path.join(build_path, pyc),
os.path.join(dist_path, 'bin', pyc)) os.path.join(dist_path, 'bin', pyc))

View file

@ -269,6 +269,14 @@ namespace Microsoft.Z3
AST.ArrayLength(queries), AST.ArrayToNative(queries)); AST.ArrayLength(queries), AST.ArrayToNative(queries));
} }
BoolExpr[] ToBoolExprs(ASTVector v) {
uint n = v.Size;
BoolExpr[] res = new BoolExpr[n];
for (uint i = 0; i < n; i++)
res[i] = new BoolExpr(Context, v[i].NativeObject);
return res;
}
/// <summary> /// <summary>
/// Retrieve set of rules added to fixedpoint context. /// Retrieve set of rules added to fixedpoint context.
/// </summary> /// </summary>
@ -278,12 +286,7 @@ namespace Microsoft.Z3
{ {
Contract.Ensures(Contract.Result<BoolExpr[]>() != null); Contract.Ensures(Contract.Result<BoolExpr[]>() != null);
ASTVector v = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject)); return ToBoolExprs(new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject)));
uint n = v.Size;
BoolExpr[] res = new BoolExpr[n];
for (uint i = 0; i < n; i++)
res[i] = new BoolExpr(Context, v[i].NativeObject);
return res;
} }
} }
@ -296,15 +299,27 @@ namespace Microsoft.Z3
{ {
Contract.Ensures(Contract.Result<BoolExpr[]>() != null); Contract.Ensures(Contract.Result<BoolExpr[]>() != null);
ASTVector v = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject)); return ToBoolExprs(new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject)));
uint n = v.Size;
BoolExpr[] res = new BoolExpr[n];
for (uint i = 0; i < n; i++)
res[i] = new BoolExpr(Context, v[i].NativeObject);
return res;
} }
} }
/// <summary>
/// Parse an SMT-LIB2 file with fixedpoint rules.
/// Add the rules to the current fixedpoint context.
/// Return the set of queries in the file.
/// </summary>
public BoolExpr[] ParseFile(string file) {
return ToBoolExprs(new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file)));
}
/// <summary>
/// Similar to ParseFile. Instead it takes as argument a string.
/// </summary>
public BoolExpr[] ParseString(string s) {
return ToBoolExprs(new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s)));
}
#region Internal #region Internal
internal Fixedpoint(Context ctx, IntPtr obj) internal Fixedpoint(Context ctx, IntPtr obj)

View file

@ -5668,7 +5668,8 @@ END_MLAPI_EXCLUDE
Each conjunct encodes values of the bound variables of the query that are satisfied. Each conjunct encodes values of the bound variables of the query that are satisfied.
In PDR mode, the returned answer is a single conjunction. In PDR mode, the returned answer is a single conjunction.
The previous call to Z3_fixedpoint_query must have returned Z3_L_TRUE. When used in Datalog mode the previous call to Z3_fixedpoint_query must have returned Z3_L_TRUE.
When used with the PDR engine, the previous call must have been either Z3_L_TRUE or Z3_L_FALSE.
def_API('Z3_fixedpoint_get_answer', AST, (_in(CONTEXT), _in(FIXEDPOINT))) def_API('Z3_fixedpoint_get_answer', AST, (_in(CONTEXT), _in(FIXEDPOINT)))
*/ */

View file

@ -569,7 +569,7 @@ class smt_printer {
m_out << ")"; m_out << ")";
} }
if (m_is_smt2 && q->get_num_patterns() > 0) { if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
m_out << "(! "; m_out << "(! ";
} }
{ {
@ -609,7 +609,11 @@ class smt_printer {
m_out << "}"; m_out << "}";
} }
} }
if (m_is_smt2 && q->get_num_patterns() > 0) {
if (q->get_qid() != symbol::null)
m_out << " :qid " << q->get_qid();
if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
m_out << ")"; m_out << ")";
} }
m_out << ")"; m_out << ")";

View file

@ -41,7 +41,7 @@ void quasi_macros::find_occurrences(expr * e) {
// we remember whether we have seen an expr once, or more than once; // we remember whether we have seen an expr once, or more than once;
// when we see it the second time, we don't have to visit it another time, // when we see it the second time, we don't have to visit it another time,
// as we are only intersted in finding unique function applications. // as we are only interested in finding unique function applications.
m_visited_once.reset(); m_visited_once.reset();
m_visited_more.reset(); m_visited_more.reset();
@ -61,7 +61,7 @@ void quasi_macros::find_occurrences(expr * e) {
case AST_VAR: break; case AST_VAR: break;
case AST_QUANTIFIER: m_todo.push_back(to_quantifier(cur)->get_expr()); break; case AST_QUANTIFIER: m_todo.push_back(to_quantifier(cur)->get_expr()); break;
case AST_APP: case AST_APP:
if (is_uninterp(cur) && !is_ground(cur)) { if (is_non_ground_uninterp(cur)) {
func_decl * f = to_app(cur)->get_decl(); func_decl * f = to_app(cur)->get_decl();
m_occurrences.insert_if_not_there(f, 0); m_occurrences.insert_if_not_there(f, 0);
occurrences_map::iterator it = m_occurrences.find_iterator(f); occurrences_map::iterator it = m_occurrences.find_iterator(f);
@ -76,6 +76,10 @@ void quasi_macros::find_occurrences(expr * e) {
} }
}; };
bool quasi_macros::is_non_ground_uninterp(expr const * e) const {
return is_non_ground(e) && is_uninterp(e);
}
bool quasi_macros::is_unique(func_decl * f) const { bool quasi_macros::is_unique(func_decl * f) const {
return m_occurrences.find(f) == 1; return m_occurrences.find(f) == 1;
} }
@ -149,6 +153,7 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
// Our definition of a quasi-macro: // Our definition of a quasi-macro:
// Forall X. f[X] = T[X], where f[X] is a term starting with symbol f, f is uninterpreted, // Forall X. f[X] = T[X], where f[X] is a term starting with symbol f, f is uninterpreted,
// f[X] contains all universally quantified variables, and f does not occur in T[X]. // f[X] contains all universally quantified variables, and f does not occur in T[X].
TRACE("quasi_macros", tout << "Checking for quasi macro: " << mk_pp(e, m_manager) << std::endl;);
if (is_quantifier(e) && to_quantifier(e)->is_forall()) { if (is_quantifier(e) && to_quantifier(e)->is_forall()) {
quantifier * q = to_quantifier(e); quantifier * q = to_quantifier(e);
@ -157,23 +162,23 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
expr * lhs = to_app(qe)->get_arg(0); expr * lhs = to_app(qe)->get_arg(0);
expr * rhs = to_app(qe)->get_arg(1); expr * rhs = to_app(qe)->get_arg(1);
if (is_uninterp(lhs) && is_unique(to_app(lhs)->get_decl()) && if (is_non_ground_uninterp(lhs) && is_unique(to_app(lhs)->get_decl()) &&
!depends_on(rhs, to_app(lhs)->get_decl()) && fully_depends_on(to_app(lhs), q)) { !depends_on(rhs, to_app(lhs)->get_decl()) && fully_depends_on(to_app(lhs), q)) {
a = to_app(lhs); a = to_app(lhs);
t = rhs; t = rhs;
return true; return true;
} else if (is_uninterp(rhs) && is_unique(to_app(rhs)->get_decl()) && } else if (is_non_ground_uninterp(rhs) && is_unique(to_app(rhs)->get_decl()) &&
!depends_on(lhs, to_app(rhs)->get_decl()) && fully_depends_on(to_app(rhs), q)) { !depends_on(lhs, to_app(rhs)->get_decl()) && fully_depends_on(to_app(rhs), q)) {
a = to_app(rhs); a = to_app(rhs);
t = lhs; t = lhs;
return true; return true;
} }
} else if (m_manager.is_not(qe) && is_uninterp(to_app(qe)->get_arg(0)) && } else if (m_manager.is_not(qe) && is_non_ground_uninterp(to_app(qe)->get_arg(0)) &&
is_unique(to_app(to_app(qe)->get_arg(0))->get_decl())) { // this is like f(...) = false is_unique(to_app(to_app(qe)->get_arg(0))->get_decl())) { // this is like f(...) = false
a = to_app(to_app(qe)->get_arg(0)); a = to_app(to_app(qe)->get_arg(0));
t = m_manager.mk_false(); t = m_manager.mk_false();
return true; return true;
} else if (is_uninterp(qe) && is_unique(to_app(qe)->get_decl())) { // this is like f(...) = true } else if (is_non_ground_uninterp(qe) && is_unique(to_app(qe)->get_decl())) { // this is like f(...) = true
a = to_app(qe); a = to_app(qe);
t = m_manager.mk_true(); t = m_manager.mk_true();
return true; return true;

View file

@ -45,6 +45,7 @@ class quasi_macros {
expr_mark m_visited_more; expr_mark m_visited_more;
bool is_unique(func_decl * f) const; bool is_unique(func_decl * f) const;
bool is_non_ground_uninterp(expr const * e) const;
bool fully_depends_on(app * a, quantifier * q) const; bool fully_depends_on(app * a, quantifier * q) const;
bool depends_on(expr * e, func_decl * f) const; bool depends_on(expr * e, func_decl * f) const;

View file

@ -978,13 +978,14 @@ namespace datalog {
} }
} }
void rule::get_vars(ptr_vector<sort>& sorts) const { void rule::get_vars(ast_manager& m, ptr_vector<sort>& sorts) const {
sorts.reset(); sorts.reset();
used_vars used; used_vars used;
get_used_vars(used); get_used_vars(used);
unsigned sz = used.get_max_found_var_idx_plus_1(); unsigned sz = used.get_max_found_var_idx_plus_1();
for (unsigned i = 0; i < sz; ++i) { for (unsigned i = 0; i < sz; ++i) {
sorts.push_back(used.get(i)); sort* s = used.get(i);
sorts.push_back(s?s:m.mk_bool_sort());
} }
} }

View file

@ -304,7 +304,7 @@ namespace datalog {
void norm_vars(rule_manager & rm); void norm_vars(rule_manager & rm);
void get_vars(ptr_vector<sort>& sorts) const; void get_vars(ast_manager& m, ptr_vector<sort>& sorts) const;
void to_formula(expr_ref& result) const; void to_formula(expr_ref& result) const;

View file

@ -290,7 +290,7 @@ namespace datalog {
} }
} }
TRACE("dl_dr", TRACE("dl_dr",
tout << r.get_decl()->get_name() << "\n"; tout << mk_pp(r.get_head(), m) << " :- \n";
for (unsigned i = 0; i < body.size(); ++i) { for (unsigned i = 0; i < body.size(); ++i) {
tout << mk_pp(body[i].get(), m) << "\n"; tout << mk_pp(body[i].get(), m) << "\n";
}); });

View file

@ -148,7 +148,7 @@ namespace datalog {
void mk_qrule_vars(datalog::rule const& r, unsigned rule_id, expr_ref_vector& sub) { void mk_qrule_vars(datalog::rule const& r, unsigned rule_id, expr_ref_vector& sub) {
ptr_vector<sort> sorts; ptr_vector<sort> sorts;
r.get_vars(sorts); r.get_vars(m, sorts);
// populate substitution of bound variables. // populate substitution of bound variables.
sub.reset(); sub.reset();
sub.resize(sorts.size()); sub.resize(sorts.size());
@ -421,7 +421,7 @@ namespace datalog {
ptr_vector<sort> rule_vars; ptr_vector<sort> rule_vars;
expr_ref_vector args(m), conjs(m); expr_ref_vector args(m), conjs(m);
r.get_vars(rule_vars); r.get_vars(m, rule_vars);
obj_hashtable<expr> used_vars; obj_hashtable<expr> used_vars;
unsigned num_vars = 0; unsigned num_vars = 0;
for (unsigned i = 0; i < r.get_decl()->get_arity(); ++i) { for (unsigned i = 0; i < r.get_decl()->get_arity(); ++i) {
@ -514,7 +514,7 @@ namespace datalog {
unsigned sz = r->get_uninterpreted_tail_size(); unsigned sz = r->get_uninterpreted_tail_size();
ptr_vector<sort> rule_vars; ptr_vector<sort> rule_vars;
r->get_vars(rule_vars); r->get_vars(m, rule_vars);
args.append(prop->get_num_args(), prop->get_args()); args.append(prop->get_num_args(), prop->get_args());
expr_ref_vector sub = mk_skolem_binding(*r, rule_vars, args); expr_ref_vector sub = mk_skolem_binding(*r, rule_vars, args);
if (sub.empty() && sz == 0) { if (sub.empty() && sz == 0) {
@ -803,7 +803,7 @@ namespace datalog {
func_decl* p = r.get_decl(); func_decl* p = r.get_decl();
ptr_vector<func_decl> const& succs = *dtu.get_datatype_constructors(m.get_sort(path)); ptr_vector<func_decl> const& succs = *dtu.get_datatype_constructors(m.get_sort(path));
// populate substitution of bound variables. // populate substitution of bound variables.
r.get_vars(sorts); r.get_vars(m, sorts);
sub.reset(); sub.reset();
sub.resize(sorts.size()); sub.resize(sorts.size());
for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) { for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) {
@ -1327,7 +1327,7 @@ namespace datalog {
void mk_rule_vars(rule& r, unsigned level, unsigned rule_id, expr_ref_vector& sub) { void mk_rule_vars(rule& r, unsigned level, unsigned rule_id, expr_ref_vector& sub) {
ptr_vector<sort> sorts; ptr_vector<sort> sorts;
r.get_vars(sorts); r.get_vars(m, sorts);
// populate substitution of bound variables. // populate substitution of bound variables.
sub.reset(); sub.reset();
sub.resize(sorts.size()); sub.resize(sorts.size());

View file

@ -87,7 +87,7 @@ namespace datalog {
else { else {
if (m_next_var == 0) { if (m_next_var == 0) {
ptr_vector<sort> vars; ptr_vector<sort> vars;
r.get_vars(vars); r.get_vars(m, vars);
m_next_var = vars.size() + 1; m_next_var = vars.size() + 1;
} }
v = m.mk_var(m_next_var, m.get_sort(e)); v = m.mk_var(m_next_var, m.get_sort(e));

View file

@ -26,6 +26,7 @@ Revision History:
#include "dl_mk_interp_tail_simplifier.h" #include "dl_mk_interp_tail_simplifier.h"
#include "fixedpoint_params.hpp" #include "fixedpoint_params.hpp"
#include "scoped_proof.h" #include "scoped_proof.h"
#include "model_v2_pp.h"
namespace datalog { namespace datalog {
@ -67,11 +68,17 @@ namespace datalog {
func_decl* p = m_new_funcs[i].get(); func_decl* p = m_new_funcs[i].get();
func_decl* q = m_old_funcs[i].get(); func_decl* q = m_old_funcs[i].get();
func_interp* f = model->get_func_interp(p); func_interp* f = model->get_func_interp(p);
if (!f) continue;
expr_ref body(m); expr_ref body(m);
unsigned arity_p = p->get_arity(); unsigned arity_p = p->get_arity();
unsigned arity_q = q->get_arity(); unsigned arity_q = q->get_arity();
TRACE("dl",
model_v2_pp(tout, *model);
tout << mk_pp(p, m) << "\n";
tout << mk_pp(q, m) << "\n";);
SASSERT(0 < arity_p); SASSERT(0 < arity_p);
model->register_decl(p, f); SASSERT(f);
model->register_decl(p, f->copy());
func_interp* g = alloc(func_interp, m, arity_q); func_interp* g = alloc(func_interp, m, arity_q);
if (f) { if (f) {
@ -88,11 +95,12 @@ namespace datalog {
for (unsigned j = 0; j < arity_q; ++j) { for (unsigned j = 0; j < arity_q; ++j) {
sort* s = q->get_domain(j); sort* s = q->get_domain(j);
arg = m.mk_var(j, s); arg = m.mk_var(j, s);
expr* t = arg;
if (m_bv.is_bv_sort(s)) { if (m_bv.is_bv_sort(s)) {
expr* args[1] = { arg };
unsigned sz = m_bv.get_bv_size(s); unsigned sz = m_bv.get_bv_size(s);
for (unsigned k = 0; k < sz; ++k) { for (unsigned k = 0; k < sz; ++k) {
proj = m.mk_app(m_bv.get_family_id(), OP_BIT2BOOL, 1, args); parameter p(k);
proj = m.mk_app(m_bv.get_family_id(), OP_BIT2BOOL, 1, &p, 1, &t);
sub.insert(m.mk_var(idx++, m.mk_bool_sort()), proj); sub.insert(m.mk_var(idx++, m.mk_bool_sort()), proj);
} }
} }

View file

@ -62,7 +62,7 @@ namespace datalog {
rule_ref r(const_cast<rule*>(&rl), rm); rule_ref r(const_cast<rule*>(&rl), rm);
ptr_vector<sort> sorts; ptr_vector<sort> sorts;
expr_ref_vector revsub(m), conjs(m); expr_ref_vector revsub(m), conjs(m);
rl.get_vars(sorts); rl.get_vars(m, sorts);
revsub.resize(sorts.size()); revsub.resize(sorts.size());
svector<bool> valid(sorts.size(), true); svector<bool> valid(sorts.size(), true);
for (unsigned i = 0; i < sub.size(); ++i) { for (unsigned i = 0; i < sub.size(); ++i) {
@ -117,8 +117,8 @@ namespace datalog {
rule_ref res(rm); rule_ref res(rm);
bool_rewriter bwr(m); bool_rewriter bwr(m);
svector<bool> is_neg; svector<bool> is_neg;
tgt->get_vars(sorts1); tgt->get_vars(m, sorts1);
src.get_vars(sorts2); src.get_vars(m, sorts2);
mk_pred(head, src.get_head(), tgt->get_head()); mk_pred(head, src.get_head(), tgt->get_head());
for (unsigned i = 0; i < src.get_uninterpreted_tail_size(); ++i) { for (unsigned i = 0; i < src.get_uninterpreted_tail_size(); ++i) {

View file

@ -199,7 +199,7 @@ namespace datalog {
expr_ref fml(m), cnst(m); expr_ref fml(m), cnst(m);
var_ref var(m); var_ref var(m);
ptr_vector<sort> sorts; ptr_vector<sort> sorts;
r.get_vars(sorts); r.get_vars(m, sorts);
m_uf.reset(); m_uf.reset();
m_terms.reset(); m_terms.reset();
m_var2cnst.reset(); m_var2cnst.reset();
@ -207,9 +207,6 @@ namespace datalog {
fml = m.mk_and(conjs.size(), conjs.c_ptr()); fml = m.mk_and(conjs.size(), conjs.c_ptr());
for (unsigned i = 0; i < sorts.size(); ++i) { for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
var = m.mk_var(i, sorts[i]); var = m.mk_var(i, sorts[i]);
cnst = m.mk_fresh_const("C", sorts[i]); cnst = m.mk_fresh_const("C", sorts[i]);
m_var2cnst.insert(var, cnst); m_var2cnst.insert(var, cnst);

View file

@ -143,11 +143,8 @@ namespace datalog {
expr_ref_vector result(m); expr_ref_vector result(m);
ptr_vector<sort> sorts; ptr_vector<sort> sorts;
expr_ref v(m), w(m); expr_ref v(m), w(m);
r.get_vars(sorts); r.get_vars(m, sorts);
for (unsigned i = 0; i < sorts.size(); ++i) { for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
v = m.mk_var(i, sorts[i]); v = m.mk_var(i, sorts[i]);
m_subst.apply(2, m_deltas, expr_offset(v, is_tgt?0:1), w); m_subst.apply(2, m_deltas, expr_offset(v, is_tgt?0:1), w);
result.push_back(w); result.push_back(w);
@ -423,6 +420,11 @@ namespace datalog {
} }
TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; ); TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; );
for (unsigned i = 0; i < m_inlined_rules.get_num_rules(); ++i) {
rule* r = m_inlined_rules.get_rule(i);
datalog::del_rule(m_mc, *r);
}
} }
bool mk_rule_inliner::transform_rule(rule_set const& orig, rule * r0, rule_set& tgt) { bool mk_rule_inliner::transform_rule(rule_set const& orig, rule * r0, rule_set& tgt) {

View file

@ -141,7 +141,7 @@ namespace datalog {
m_cache.reset(); m_cache.reset();
m_trail.reset(); m_trail.reset();
m_eqs.reset(); m_eqs.reset();
r.get_vars(vars); r.get_vars(m, vars);
unsigned num_vars = vars.size(); unsigned num_vars = vars.size();
for (unsigned j = 0; j < utsz; ++j) { for (unsigned j = 0; j < utsz; ++j) {
tail.push_back(mk_pred(num_vars, r.get_tail(j))); tail.push_back(mk_pred(num_vars, r.get_tail(j)));

View file

@ -1120,6 +1120,7 @@ namespace qe {
st->init(fml); st->init(fml);
st->m_vars.append(m_vars.size(), m_vars.c_ptr()); st->m_vars.append(m_vars.size(), m_vars.c_ptr());
SASSERT(invariant()); SASSERT(invariant());
TRACE("qe", tout << mk_pp(m_fml, m) << " child: " << mk_pp(fml, m) << "\n";);
return st; return st;
} }
@ -1133,6 +1134,7 @@ namespace qe {
m_branch_index.insert(branch_id, index); m_branch_index.insert(branch_id, index);
st->m_vars.append(m_vars.size(), m_vars.c_ptr()); st->m_vars.append(m_vars.size(), m_vars.c_ptr());
SASSERT(invariant()); SASSERT(invariant());
//TRACE("qe", tout << mk_pp(m_fml, m) << " child: " << mk_pp(st->fml(), m) << "\n";);
return st; return st;
} }
@ -1164,6 +1166,16 @@ namespace qe {
} }
} }
expr_ref abstract_variable(app* x, expr* fml) const {
expr_ref result(m);
expr* y = x;
expr_abstract(m, 0, 1, &y, fml, result);
symbol X(x->get_decl()->get_name());
sort* s = m.get_sort(x);
result = m.mk_exists(1, &s, &X, result);
return result;
}
void display_validate(std::ostream& out) const { void display_validate(std::ostream& out) const {
if (m_children.empty()) { if (m_children.empty()) {
return; return;
@ -1171,25 +1183,53 @@ namespace qe {
expr_ref q(m); expr_ref q(m);
expr* x = m_var; expr* x = m_var;
if (x) { if (x) {
expr_abstract(m, 0, 1, &x, m_fml, q); q = abstract_variable(m_var, m_fml);
ptr_vector<expr> fmls;
expr_ref_vector fmls(m);
expr_ref fml(m);
for (unsigned i = 0; i < m_children.size(); ++i) { for (unsigned i = 0; i < m_children.size(); ++i) {
expr* fml = m_children[i]->fml(); search_tree const& child = *m_children[i];
fml = child.fml();
if (fml) { if (fml) {
// abstract free variables in children.
ptr_vector<app> child_vars, new_vars;
child_vars.append(child.m_vars.size(), child.m_vars.c_ptr());
if (child.m_var) {
child_vars.push_back(child.m_var);
}
for (unsigned j = 0; j < child_vars.size(); ++j) {
if (!m_vars.contains(child_vars[j]) &&
!new_vars.contains(child_vars[j])) {
fml = abstract_variable(child_vars[j], fml);
new_vars.push_back(child_vars[j]);
}
}
fmls.push_back(fml); fmls.push_back(fml);
} }
} }
symbol X(m_var->get_decl()->get_name()); bool_rewriter(m).mk_or(fmls.size(), fmls.c_ptr(), fml);
sort* s = m.get_sort(x);
q = m.mk_exists(1, &s, &X, q); fml = m.mk_not(m.mk_iff(q, fml));
expr_ref tmp(m);
bool_rewriter(m).mk_or(fmls.size(), fmls.c_ptr(), tmp);
expr_ref f(m.mk_not(m.mk_iff(q, tmp)), m);
ast_smt_pp pp(m); ast_smt_pp pp(m);
out << "(echo " << m_var->get_decl()->get_name() << ")\n"; out << "; eliminate " << mk_pp(m_var, m) << "\n";
out << "(push)\n"; out << "(push)\n";
pp.display_smt2(out, f); pp.display_smt2(out, fml);
out << "(pop)\n\n"; out << "(pop)\n\n";
DEBUG_CODE(
smt_params params;
params.m_simplify_bit2int = true;
params.m_arith_enum_const_mod = true;
params.m_bv_enable_int2bv2int = true;
params.m_relevancy_lvl = 0;
smt::kernel ctx(m, params);
ctx.assert_expr(fml);
lbool is_sat = ctx.check();
if (is_sat == l_true) {
std::cout << "; Validation failed:\n";
std::cout << mk_pp(fml, m) << "\n";
}
);
} }
for (unsigned i = 0; i < m_children.size(); ++i) { for (unsigned i = 0; i < m_children.size(); ++i) {
if (m_children[i]->fml()) { if (m_children[i]->fml()) {
@ -1410,13 +1450,9 @@ namespace qe {
m_solver.assert_expr(m_fml); m_solver.assert_expr(m_fml);
if (assumption) m_solver.assert_expr(assumption); if (assumption) m_solver.assert_expr(assumption);
bool is_sat = false; bool is_sat = false;
while (l_false != m_solver.check()) { while (l_true == m_solver.check()) {
is_sat = true; is_sat = true;
model_ref model; final_check();
m_solver.get_model(model);
TRACE("qe", model_v2_pp(tout, *model););
model_evaluator model_eval(*model);
final_check(model_eval);
} }
if (!is_sat) { if (!is_sat) {
@ -1466,14 +1502,30 @@ namespace qe {
private: private:
void final_check(model_evaluator& model_eval) { void final_check() {
TRACE("qe", tout << "\n";); model_ref model;
while (can_propagate_assignment(model_eval)) { m_solver.get_model(model);
propagate_assignment(model_eval); scoped_ptr<model_evaluator> model_eval = alloc(model_evaluator, *model);
while (true) {
TRACE("qe", model_v2_pp(tout, *model););
while (can_propagate_assignment(*model_eval)) {
propagate_assignment(*model_eval);
} }
VERIFY(CHOOSE_VAR == update_current(model_eval, true)); VERIFY(CHOOSE_VAR == update_current(*model_eval, true));
SASSERT(m_current->fml()); SASSERT(m_current->fml());
pop(model_eval); if (l_true != m_solver.check()) {
return;
}
m_solver.get_model(model);
model_eval = alloc(model_evaluator, *model);
search_tree* st = m_current;
update_current(*model_eval, false);
if (st == m_current) {
break;
}
}
pop(*model_eval);
} }
ast_manager& get_manager() { return m; } ast_manager& get_manager() { return m; }
@ -1633,6 +1685,7 @@ namespace qe {
nb = m_current->get_num_branches(); nb = m_current->get_num_branches();
expr_ref fml(m_current->fml(), m); expr_ref fml(m_current->fml(), m);
if (!eval(model_eval, b, branch) || branch >= nb) { if (!eval(model_eval, b, branch) || branch >= nb) {
TRACE("qe", tout << "evaluation failed: setting branch to 0\n";);
branch = rational::zero(); branch = rational::zero();
} }
SASSERT(!branch.is_neg()); SASSERT(!branch.is_neg());
@ -1694,11 +1747,12 @@ namespace qe {
} }
// //
// The current state is satisfiable // The closed portion of the formula
// and the closed portion of the formula // can be used as the quantifier-free portion,
// can be used as the quantifier-free portion. // unless the current state is unsatisfiable.
// //
if (m.is_true(fml_mixed)) { if (m.is_true(fml_mixed)) {
SASSERT(l_true == m_solver.check());
m_current = m_current->add_child(fml_closed); m_current = m_current->add_child(fml_closed);
for (unsigned i = 0; m_defs && i < m_current->num_free_vars(); ++i) { for (unsigned i = 0; m_defs && i < m_current->num_free_vars(); ++i) {
expr_ref val(m); expr_ref val(m);
@ -1708,6 +1762,7 @@ namespace qe {
if (val == x) { if (val == x) {
model_ref model; model_ref model;
lbool is_sat = m_solver.check(); lbool is_sat = m_solver.check();
if (is_sat == l_undef) return;
m_solver.get_model(model); m_solver.get_model(model);
SASSERT(is_sat == l_true); SASSERT(is_sat == l_true);
model_evaluator model_eval2(*model); model_evaluator model_eval2(*model);
@ -1890,7 +1945,7 @@ namespace qe {
vars.reset(); vars.reset();
closed = closed && (r != l_undef); closed = closed && (r != l_undef);
} }
TRACE("qe", tout << mk_ismt2_pp(fml, m) << "\n";); TRACE("qe", tout << mk_pp(fml, m) << "\n";);
m_current->add_child(fml)->reset_free_vars(); m_current->add_child(fml)->reset_free_vars();
block_assignment(); block_assignment();
} }

View file

@ -31,6 +31,7 @@ Revision History:
#include "obj_pair_hashtable.h" #include "obj_pair_hashtable.h"
#include "nlarith_util.h" #include "nlarith_util.h"
#include "model_evaluator.h" #include "model_evaluator.h"
#include "smt_kernel.h"
namespace qe { namespace qe {
@ -81,8 +82,8 @@ namespace qe {
i_solver_context& m_ctx; i_solver_context& m_ctx;
public: public:
arith_util m_arith; // initialize before m_zero_i, etc. arith_util m_arith; // initialize before m_zero_i, etc.
th_rewriter simplify;
private: private:
th_rewriter m_rewriter;
arith_eq_solver m_arith_solver; arith_eq_solver m_arith_solver;
bv_util m_bv; bv_util m_bv;
@ -102,7 +103,7 @@ namespace qe {
m(m), m(m),
m_ctx(ctx), m_ctx(ctx),
m_arith(m), m_arith(m),
m_rewriter(m), simplify(m),
m_arith_solver(m), m_arith_solver(m),
m_bv(m), m_bv(m),
m_zero_i(m_arith.mk_numeral(numeral(0), true), m), m_zero_i(m_arith.mk_numeral(numeral(0), true), m),
@ -434,7 +435,6 @@ namespace qe {
expr_ref tmp(e, m); expr_ref tmp(e, m);
simplify(tmp); simplify(tmp);
m_arith_rewriter.mk_le(tmp, mk_zero(e), result); m_arith_rewriter.mk_le(tmp, mk_zero(e), result);
TRACE("qe_verbose", tout << "mk_le " << mk_pp(result, m) << "\n";);
} }
void mk_lt(expr* e, expr_ref& result) { void mk_lt(expr* e, expr_ref& result) {
@ -521,7 +521,8 @@ namespace qe {
expr_ref result1(m), result2(m); expr_ref result1(m), result2(m);
// a*s + b*t <= 0 // a*s + b*t <= 0
expr_ref as_bt_le_0(result, m), tmp2(m), tmp3(m), tmp4(m); expr_ref as_bt_le_0(result, m), tmp2(m), asz_bt_le_0(m), tmp3(m), tmp4(m);
expr_ref b_divides_sz(m);
// a*s + b*t + (a-1)(b-1) <= 0 // a*s + b*t + (a-1)(b-1) <= 0
tmp2 = m_arith.mk_add(as_bt, slack); tmp2 = m_arith.mk_add(as_bt, slack);
@ -560,30 +561,36 @@ namespace qe {
sz = m_arith.mk_uminus(sz); sz = m_arith.mk_uminus(sz);
} }
tmp4 = mk_add(mk_mul(a1, sz), bt); tmp4 = mk_add(mk_mul(a1, sz), bt);
mk_le(tmp4, tmp3); mk_le(tmp4, asz_bt_le_0);
if (to_app(tmp3)->get_arg(0) == x && if (to_app(asz_bt_le_0)->get_arg(0) == x &&
m_arith.is_zero(to_app(tmp3)->get_arg(1))) { m_arith.is_zero(to_app(asz_bt_le_0)->get_arg(1))) {
// exists z in [0 .. |b|-2] . |b| | (z + s) && z <= 0 // exists z in [0 .. |b|-2] . |b| | (z + s) && z <= 0
// <=> // <=>
// |b| | s // |b| | s
mk_divides(abs_b, s, tmp2); mk_divides(abs_b, s, tmp2);
} }
else { else {
mk_divides(abs_b, sz, tmp2); mk_divides(abs_b, sz, b_divides_sz);
mk_and(tmp2, tmp3, tmp4); mk_and(b_divides_sz, asz_bt_le_0, tmp4);
mk_big_or(abs_b - numeral(2), x, tmp4, tmp2); mk_big_or(abs_b - numeral(2), x, tmp4, tmp2);
TRACE("qe",
tout << "b | s + z: " << mk_pp(b_divides_sz, m) << "\n";
tout << "a(s+z) + bt <= 0: " << mk_pp(asz_bt_le_0, m) << "\n";
);
} }
mk_flat_and(as_bt_le_0, tmp2, result2); mk_flat_and(as_bt_le_0, tmp2, result2);
mk_or(result1, result2, result); mk_or(result1, result2, result);
simplify(result); simplify(result);
// a*s + b*t + (a-1)(b-1) <= 0
// or exists z in [0 .. |b|-2] . |b| | (z + s) && a*n_sign(b)(s + z) + |b|t <= 0
} }
TRACE("qe", TRACE("qe",
{ {
expr_ref_vector trail(m); tout << (is_strict?"strict":"non-strict") << "\n";
tout << "is_strict: " << (is_strict?"true":"false") << "\n";
bound(m, a, t, false).pp(tout, x); bound(m, a, t, false).pp(tout, x);
tout << "\n"; tout << "\n";
bound(m, b, s, false).pp(tout, x); bound(m, b, s, false).pp(tout, x);
@ -592,10 +599,6 @@ namespace qe {
}); });
} }
void simplify(expr_ref& p) {
m_rewriter(p);
}
struct mul_lt { struct mul_lt {
arith_util& u; arith_util& u;
mul_lt(arith_qe_util& u): u(u.m_arith) {} mul_lt(arith_qe_util& u): u(u.m_arith) {}
@ -1052,7 +1055,6 @@ namespace qe {
} }
bool reduce_equation(expr* p, expr* fml) { bool reduce_equation(expr* p, expr* fml) {
TRACE("qe", tout << mk_pp(p, m) << "\n";);
numeral k; numeral k;
if (m_arith.is_numeral(p, k) && k.is_zero()) { if (m_arith.is_numeral(p, k) && k.is_zero()) {
@ -1555,9 +1557,10 @@ public:
mk_non_resolve(bounds, true, is_lower, result); mk_non_resolve(bounds, true, is_lower, result);
mk_non_resolve(bounds, false, is_lower, result); mk_non_resolve(bounds, false, is_lower, result);
m_util.simplify(result);
add_cache(x, fml, v, result, x_t.get_coeff(), x_t.get_term()); add_cache(x, fml, v, result, x_t.get_coeff(), x_t.get_term());
TRACE("qe", TRACE("qe",
tout << vl << " " << mk_pp(x, m) << "\n"; tout << vl << " " << mk_pp(x, m) << " infinite case\n";
tout << mk_pp(fml, m) << "\n"; tout << mk_pp(fml, m) << "\n";
tout << mk_pp(result, m) << "\n";); tout << mk_pp(result, m) << "\n";);
return; return;
@ -1592,18 +1595,21 @@ public:
expr_ref t(bounds.exprs(is_strict, is_lower)[index], m); expr_ref t(bounds.exprs(is_strict, is_lower)[index], m);
rational a = bounds.coeffs(is_strict, is_lower)[index]; rational a = bounds.coeffs(is_strict, is_lower)[index];
t = x_t.mk_term(a, t);
a = x_t.mk_coeff(a);
mk_bounds(bounds, x, true, is_eq, is_strict, is_lower, index, a, t, result); mk_bounds(bounds, x, true, is_eq, is_strict, is_lower, index, a, t, result);
mk_bounds(bounds, x, false, is_eq, is_strict, is_lower, index, a, t, result); mk_bounds(bounds, x, false, is_eq, is_strict, is_lower, index, a, t, result);
t = x_t.mk_term(a, t);
a = x_t.mk_coeff(a);
mk_resolve(bounds, x, x_t, true, is_eq, is_strict, is_lower, index, a, t, result); mk_resolve(bounds, x, x_t, true, is_eq, is_strict, is_lower, index, a, t, result);
mk_resolve(bounds, x, x_t, false, is_eq, is_strict, is_lower, index, a, t, result); mk_resolve(bounds, x, x_t, false, is_eq, is_strict, is_lower, index, a, t, result);
m_util.simplify(result);
add_cache(x, fml, v, result, x_t.get_coeff(), x_t.get_term()); add_cache(x, fml, v, result, x_t.get_coeff(), x_t.get_term());
TRACE("qe", TRACE("qe",
{ {
tout << vl << " " << mk_pp(x, m) << "\n"; tout << vl << " " << mk_pp(bounds.atoms(is_strict, is_lower)[index],m) << "\n";
tout << mk_pp(fml, m) << "\n"; tout << mk_pp(fml, m) << "\n";
tout << mk_pp(result, m) << "\n"; tout << mk_pp(result, m) << "\n";
} }
@ -2225,6 +2231,12 @@ public:
} }
} }
m_util.simplify(result); m_util.simplify(result);
TRACE("qe",
tout << (is_strict?"strict":"non-strict") << "\n";
tout << (is_lower?"is-lower":"is-upper") << "\n";
tout << "a: " << a << " " << mk_pp(t, m) << "\n";
tout << "b: " << b << " " << mk_pp(s, m) << "\n";
tout << mk_pp(result, m) << "\n";);
} }
// //
@ -2245,10 +2257,12 @@ public:
void mk_bounds(bounds_proc& bounds, void mk_bounds(bounds_proc& bounds,
app* x, bool is_strict, bool is_eq_ctx, bool is_strict_ctx, bool is_lower, unsigned index, app* x, bool is_strict, bool is_eq_ctx,
bool is_strict_ctx, bool is_lower, unsigned index,
rational const& a, expr* t, rational const& a, expr* t,
expr_ref& result) expr_ref& result)
{ {
TRACE("qe", tout << mk_pp(t, m) << "\n";);
SASSERT(!is_eq_ctx || !is_strict_ctx); SASSERT(!is_eq_ctx || !is_strict_ctx);
unsigned sz = bounds.size(is_strict, is_lower); unsigned sz = bounds.size(is_strict, is_lower);
expr_ref tmp(m), eq(m); expr_ref tmp(m), eq(m);
@ -2258,13 +2272,14 @@ public:
for (unsigned i = 0; i < sz; ++i) { for (unsigned i = 0; i < sz; ++i) {
app* e = bounds.atoms(is_strict, is_lower)[i]; app* e = bounds.atoms(is_strict, is_lower)[i];
expr* s = bounds.exprs(is_strict, is_lower)[i]; expr_ref s(bounds.exprs(is_strict, is_lower)[i], m);
rational b = bounds.coeffs(is_strict, is_lower)[i]; rational b = bounds.coeffs(is_strict, is_lower)[i];
if (same_strict && i == index) { if (same_strict && i == index) {
if (non_strict_real) { if (non_strict_real) {
m_util.mk_eq(a, x, t, eq); m_util.mk_eq(a, x, t, eq);
TRACE("qe", tout << "a:" << a << " x: " << mk_pp(x, m) << " t: " << mk_pp(t, m) << " eq: " << mk_pp(eq, m) << "\n";); TRACE("qe", tout << "a:" << a << " x: " << mk_pp(x, m) << "t: " <<
mk_pp(t, m) << " eq: " << mk_pp(eq, m) << "\n";);
if (is_eq_ctx) { if (is_eq_ctx) {
m_ctx.add_constraint(true, eq); m_ctx.add_constraint(true, eq);
} }
@ -2292,6 +2307,7 @@ public:
(non_strict_real && is_eq_ctx && is_strict) || (non_strict_real && is_eq_ctx && is_strict) ||
(same_strict && i < index); (same_strict && i < index);
mk_bound(result_is_strict, is_lower, a, t, b, s, tmp); mk_bound(result_is_strict, is_lower, a, t, b, s, tmp);
m_util.m_replace.apply_substitution(e, tmp.get(), result); m_util.m_replace.apply_substitution(e, tmp.get(), result);
@ -2330,14 +2346,17 @@ public:
s = x_t.mk_term(b, s); s = x_t.mk_term(b, s);
b = x_t.mk_coeff(b); b = x_t.mk_coeff(b);
m_util.mk_resolve(x, strict_resolve, a, t, b, s, tmp); m_util.mk_resolve(x, strict_resolve, a, t, b, s, tmp);
expr_ref save_result(result);
m_util.m_replace.apply_substitution(e, tmp.get(), result); m_util.m_replace.apply_substitution(e, tmp.get(), result);
m_ctx.add_constraint(true, mk_not(e), tmp); m_ctx.add_constraint(true, mk_not(e), tmp);
TRACE("qe_verbose", TRACE("qe_verbose",
tout << mk_pp(atm, m) << " "; tout << mk_pp(atm, m) << " ";
tout << mk_pp(e, m) << " ==> "; tout << mk_pp(e, m) << " ==>\n";
tout << mk_pp(tmp, m) << "\n"; tout << mk_pp(tmp, m) << "\n";
tout << "old fml: " << mk_pp(save_result, m) << "\n";
tout << "new fml: " << mk_pp(result, m) << "\n";
); );
} }
} }

View file

@ -22,6 +22,7 @@ Revision History:
void theory_arith_params::updt_params(params_ref const & _p) { void theory_arith_params::updt_params(params_ref const & _p) {
smt_params_helper p(_p); smt_params_helper p(_p);
m_arith_random_initial_value = p.arith_random_initial_value(); m_arith_random_initial_value = p.arith_random_initial_value();
m_arith_random_seed = p.random_seed();
m_arith_mode = static_cast<arith_solver_id>(p.arith_solver()); m_arith_mode = static_cast<arith_solver_id>(p.arith_solver());
m_nl_arith = p.arith_nl(); m_nl_arith = p.arith_nl();
m_nl_arith_gb = p.arith_nl_gb(); m_nl_arith_gb = p.arith_nl_gb();

View file

@ -1198,6 +1198,7 @@ namespace smt {
void theory_bv::relevant_eh(app * n) { void theory_bv::relevant_eh(app * n) {
ast_manager & m = get_manager(); ast_manager & m = get_manager();
context & ctx = get_context(); context & ctx = get_context();
TRACE("bv", tout << "relevant: " << mk_pp(n, m) << "\n";);
if (m.is_bool(n)) { if (m.is_bool(n)) {
bool_var v = ctx.get_bool_var(n); bool_var v = ctx.get_bool_var(n);
atom * a = get_bv2a(v); atom * a = get_bv2a(v);

View file

@ -218,6 +218,7 @@ br_status bv2int_rewriter::mk_mod(expr * s, expr * t, expr_ref & result) {
if (is_bv2int(s, s1) && is_bv2int(t, t1)) { if (is_bv2int(s, s1) && is_bv2int(t, t1)) {
align_sizes(s1, t1, false); align_sizes(s1, t1, false);
result = m_bv.mk_bv2int(m_bv.mk_bv_urem(s1, t1)); result = m_bv.mk_bv2int(m_bv.mk_bv_urem(s1, t1));
TRACE("bv2int_rewriter", tout << mk_pp(result,m()) << "\n";);
return BR_DONE; return BR_DONE;
} }
@ -232,6 +233,7 @@ br_status bv2int_rewriter::mk_mod(expr * s, expr * t, expr_ref & result) {
u1 = mk_bv_add(s1, u1, false); u1 = mk_bv_add(s1, u1, false);
align_sizes(u1, t1, false); align_sizes(u1, t1, false);
result = m_bv.mk_bv2int(m_bv.mk_bv_urem(u1, t1)); result = m_bv.mk_bv2int(m_bv.mk_bv_urem(u1, t1));
TRACE("bv2int_rewriter", tout << mk_pp(result,m()) << "\n";);
return BR_DONE; return BR_DONE;
} }

View file

@ -43,6 +43,7 @@ void filter_model_converter::operator()(model_ref & old_model, unsigned goal_idx
if (fs.is_marked(f)) if (fs.is_marked(f))
continue; continue;
func_interp * fi = old_model->get_func_interp(f); func_interp * fi = old_model->get_func_interp(f);
SASSERT(fi);
new_model->register_decl(f, fi->copy()); new_model->register_decl(f, fi->copy());
} }
new_model->copy_usort_interps(*old_model); new_model->copy_usort_interps(*old_model);