3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 17:15:31 +00:00

Merge branch 'str-at-semantics' into develop

This commit is contained in:
Murphy Berzish 2017-03-13 14:40:40 -04:00
commit 94d5f242b8
35 changed files with 799 additions and 66 deletions

View file

@ -3942,7 +3942,7 @@ namespace smt {
#endif
virtual void on_match(quantifier * qa, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, ptr_vector<enode> & used_enodes) {
TRACE("trigger_bug", tout << "found match\n";);
TRACE("trigger_bug", tout << "found match " << mk_pp(qa, m_ast_manager) << "\n";);
#ifdef Z3DEBUG
if (m_check_missing_instances) {
if (!m_context.slow_contains_instance(qa, num_bindings, bindings)) {

View file

@ -93,6 +93,7 @@ bool proto_model::is_select_of_model_value(expr* e) const {
bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
m_eval.set_model_completion(model_completion);
m_eval.set_expand_array_equalities(false);
try {
m_eval(e, result);
#if 0

View file

@ -306,7 +306,6 @@ namespace smt {
TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " ";
display_literal_verbose(tout, l); tout << " level: " << m_scope_lvl << "\n";
display(tout, j););
SASSERT(l.var() < static_cast<int>(m_b_internalized_stack.size()));
m_assigned_literals.push_back(l);
m_assignment[l.index()] = l_true;
m_assignment[(~l).index()] = l_false;
@ -321,14 +320,23 @@ namespace smt {
d.m_phase_available = true;
d.m_phase = !l.sign();
TRACE("phase_selection", tout << "saving phase, is_pos: " << d.m_phase << " l: " << l << "\n";);
TRACE("relevancy",
tout << "is_atom: " << d.is_atom() << " is relevant: " << is_relevant_core(bool_var2expr(l.var())) << "\n";);
if (d.is_atom() && (m_fparams.m_relevancy_lvl == 0 || (m_fparams.m_relevancy_lvl == 1 && !d.is_quantifier()) || is_relevant_core(bool_var2expr(l.var()))))
tout << "is_atom: " << d.is_atom() << " is relevant: " << is_relevant_core(l) << "\n";);
if (d.is_atom() && (m_fparams.m_relevancy_lvl == 0 || (m_fparams.m_relevancy_lvl == 1 && !d.is_quantifier()) || is_relevant_core(l)))
m_atom_propagation_queue.push_back(l);
if (m_manager.has_trace_stream())
trace_assign(l, j, decision);
m_case_split_queue->assign_lit_eh(l);
// a unit is asserted at search level. Mark it as relevant.
// this addresses bug... where a literal becomes fixed to true (false)
// as a conflict gets assigned misses relevancy (and quantifier instantiation).
//
if (false && !decision && relevancy() && at_search_level() && !is_relevant_core(l)) {
mark_as_relevant(l);
}
}
bool context::bcp() {
@ -1637,7 +1645,7 @@ namespace smt {
m_atom_propagation_queue.push_back(literal(v, val == l_false));
}
}
TRACE("propagate_relevancy", tout << "marking as relevant:\n" << mk_bounded_pp(n, m_manager) << "\n";);
TRACE("propagate_relevancy", tout << "marking as relevant:\n" << mk_bounded_pp(n, m_manager) << " " << m_scope_lvl << "\n";);
#ifndef SMTCOMP
m_case_split_queue->relevant_eh(n);
#endif
@ -3895,6 +3903,7 @@ namespace smt {
// I invoke pop_scope_core instead of pop_scope because I don't want
// to reset cached generations... I need them to rebuild the literals
// of the new conflict clause.
if (relevancy()) record_relevancy(num_lits, lits);
unsigned num_bool_vars = pop_scope_core(m_scope_lvl - new_lvl);
SASSERT(m_scope_lvl == new_lvl);
// the logical context may still be in conflict after
@ -3926,6 +3935,7 @@ namespace smt {
}
}
}
if (relevancy()) restore_relevancy(num_lits, lits);
// Resetting the cache manually because I did not invoke pop_scope, but pop_scope_core
reset_cache_generation();
TRACE("resolve_conflict_bug",
@ -4008,6 +4018,28 @@ namespace smt {
}
return false;
}
/*
\brief we record and restore relevancy information for literals in conflict clauses.
A literal may have been marked relevant within the scope that gets popped during
conflict resolution. In this case, the literal is no longer marked as relevant after
the pop. This can cause quantifier instantiation to miss relevant triggers and thereby
cause incmpleteness.
*/
void context::record_relevancy(unsigned n, literal const* lits) {
m_relevant_conflict_literals.reset();
for (unsigned i = 0; i < n; ++i) {
m_relevant_conflict_literals.push_back(is_relevant(lits[i]));
}
}
void context::restore_relevancy(unsigned n, literal const* lits) {
for (unsigned i = 0; i < n; ++i) {
if (m_relevant_conflict_literals[i] && !is_relevant(lits[i])) {
mark_as_relevant(lits[i]);
}
}
}
void context::get_relevant_labels(expr* cnstr, buffer<symbol> & result) {
if (m_fparams.m_check_at_labels) {
@ -4281,6 +4313,7 @@ namespace smt {
if (fcs == FC_DONE) {
mk_proto_model(l_true);
m_model = m_proto_model->mk_model();
add_rec_funs_to_model();
}
return fcs == FC_DONE;
@ -4333,8 +4366,51 @@ namespace smt {
return m_last_search_failure;
}
void context::add_rec_funs_to_model() {
ast_manager& m = m_manager;
SASSERT(m_model);
for (unsigned i = 0; i < m_asserted_formulas.get_num_formulas(); ++i) {
expr* e = m_asserted_formulas.get_formula(i);
if (is_quantifier(e)) {
quantifier* q = to_quantifier(e);
if (!m.is_rec_fun_def(q)) continue;
SASSERT(q->get_num_patterns() == 1);
expr* fn = to_app(q->get_pattern(0))->get_arg(0);
SASSERT(is_app(fn));
func_decl* f = to_app(fn)->get_decl();
expr* eq = q->get_expr();
expr_ref body(m);
if (is_fun_def(fn, q->get_expr(), body)) {
func_interp* fi = alloc(func_interp, m, f->get_arity());
fi->set_else(body);
m_model->register_decl(f, fi);
}
}
}
}
bool context::is_fun_def(expr* f, expr* body, expr_ref& result) {
expr* t1, *t2, *t3;
if (m_manager.is_eq(body, t1, t2) || m_manager.is_iff(body, t1, t2)) {
if (t1 == f) return result = t2, true;
if (t2 == f) return result = t1, true;
return false;
}
if (m_manager.is_ite(body, t1, t2, t3)) {
expr_ref body1(m_manager), body2(m_manager);
if (is_fun_def(f, t2, body1) && is_fun_def(f, t3, body2)) {
// f is not free in t1
result = m_manager.mk_ite(t1, body1, body2);
return true;
}
}
return false;
}
};
#ifdef Z3DEBUG
void pp(smt::context & c) {
c.display(std::cout);

View file

@ -209,6 +209,7 @@ namespace smt {
~scoped_mk_model() {
if (m_ctx.m_proto_model.get() != 0) {
m_ctx.m_model = m_ctx.m_proto_model->mk_model();
m_ctx.add_rec_funs_to_model();
m_ctx.m_proto_model = 0; // proto_model is not needed anymore.
}
}
@ -1132,6 +1133,10 @@ namespace smt {
bool is_relevant_core(expr * n) const { return m_relevancy_propagator->is_relevant(n); }
svector<bool> m_relevant_conflict_literals;
void record_relevancy(unsigned n, literal const* lits);
void restore_relevancy(unsigned n, literal const* lits);
public:
// event handler for relevancy_propagator class
void relevant_eh(expr * n);
@ -1153,6 +1158,10 @@ namespace smt {
return is_relevant(l.var());
}
bool is_relevant_core(literal l) const {
return is_relevant_core(bool_var2expr(l.var()));
}
void mark_as_relevant(expr * n) { m_relevancy_propagator->mark_as_relevant(n); m_relevancy_propagator->propagate(); }
void mark_as_relevant(enode * n) { mark_as_relevant(n->get_owner()); }
@ -1186,6 +1195,10 @@ namespace smt {
bool propagate();
void add_rec_funs_to_model();
bool is_fun_def(expr* f, expr* q, expr_ref& body);
public:
bool can_propagate() const;

View file

@ -290,7 +290,7 @@ namespace smt {
while (true) {
lbool r = m_aux_context->check();
TRACE("model_checker", tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";);
TRACE("model_checker", tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";);
if (r != l_true)
break;
model_ref cex;
@ -300,7 +300,7 @@ namespace smt {
}
num_new_instances++;
if (num_new_instances >= m_max_cexs || !add_blocking_clause(cex.get(), sks)) {
TRACE("model_checker", tout << "Add blocking clause failed\n";);
TRACE("model_checker", tout << "Add blocking clause failed new-instances: " << num_new_instances << " max-cex: " << m_max_cexs << "\n";);
// add_blocking_clause failed... stop the search for new counter-examples...
break;
}
@ -407,6 +407,7 @@ namespace smt {
found_relevant = true;
if (m.is_rec_fun_def(q)) {
if (!check_rec_fun(q)) {
TRACE("model_checker", tout << "checking recursive function failed\n";);
num_failures++;
}
}
@ -414,6 +415,7 @@ namespace smt {
if (m_params.m_mbqi_trace || get_verbosity_level() >= 5) {
verbose_stream() << "(smt.mbqi :failed " << q->get_qid() << ")\n";
}
TRACE("model_checker", tout << "checking quantifier " << mk_pp(q, m) << " failed\n";);
num_failures++;
}
}
@ -452,6 +454,7 @@ namespace smt {
}
bool model_checker::has_new_instances() {
TRACE("model_checker", tout << "instances: " << m_new_instances.size() << "\n";);
return !m_new_instances.empty();
}

View file

@ -52,8 +52,9 @@ namespace smt {
m_qi_queue.setup();
}
bool has_trace_stream() const { return m_context.get_manager().has_trace_stream(); }
std::ostream & trace_stream() { return m_context.get_manager().trace_stream(); }
ast_manager& m() const { return m_context.get_manager(); }
bool has_trace_stream() const { return m().has_trace_stream(); }
std::ostream & trace_stream() { return m().trace_stream(); }
quantifier_stat * get_stat(quantifier * q) const {
return m_quantifier_stat.find(q);
@ -110,8 +111,9 @@ namespace smt {
unsigned max_top_generation,
ptr_vector<enode> & used_enodes) {
max_generation = std::max(max_generation, get_generation(q));
if (m_num_instances > m_params.m_qi_max_instances)
if (m_num_instances > m_params.m_qi_max_instances) {
return false;
}
get_stat(q)->update_max_generation(max_generation);
fingerprint * f = m_context.add_fingerprint(q, q->get_id(), num_bindings, bindings);
if (f) {
@ -132,9 +134,17 @@ namespace smt {
}
m_qi_queue.insert(f, pat, max_generation, min_top_generation, max_top_generation); // TODO
m_num_instances++;
return true;
}
return false;
TRACE("quantifier",
tout << mk_pp(q, m()) << " ";
for (unsigned i = 0; i < num_bindings; ++i) {
tout << mk_pp(bindings[i]->get_owner(), m()) << " ";
}
tout << "\n";
tout << "inserted: " << (f != 0) << "\n";
);
return f != 0;
}
void init_search_eh() {
@ -186,7 +196,7 @@ namespace smt {
}
bool check_quantifier(quantifier* q) {
return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // && !m_context.get_manager().is_rec_fun_def(q);
return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // && !m().is_rec_fun_def(q);
}
bool quick_check_quantifiers() {
@ -501,13 +511,13 @@ namespace smt {
SASSERT(m_context->get_manager().is_pattern(mp));
bool unary = (mp->get_num_args() == 1);
if (!unary && j >= num_eager_multi_patterns) {
TRACE("assign_quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n"
TRACE("quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n"
<< "j: " << j << " unary: " << unary << " m_params.m_qi_max_eager_multipatterns: " << m_fparams->m_qi_max_eager_multipatterns
<< " num_eager_multi_patterns: " << num_eager_multi_patterns << "\n";);
m_lazy_mam->add_pattern(q, mp);
}
else {
TRACE("assign_quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";);
TRACE("quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";);
m_mam->add_pattern(q, mp);
}
if (!unary)

View file

@ -165,6 +165,8 @@ namespace smt {
virtual void push() = 0;
virtual void pop(unsigned num_scopes) = 0;
};
};