mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 13:28:47 +00:00
fast path for antecedent extraction in smt_context
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
ceb3f0c869
commit
8221a09659
|
@ -18,6 +18,7 @@ z3_add_component(smt
|
||||||
smt_checker.cpp
|
smt_checker.cpp
|
||||||
smt_clause.cpp
|
smt_clause.cpp
|
||||||
smt_conflict_resolution.cpp
|
smt_conflict_resolution.cpp
|
||||||
|
smt_consequences.cpp
|
||||||
smt_context.cpp
|
smt_context.cpp
|
||||||
smt_context_inv.cpp
|
smt_context_inv.cpp
|
||||||
smt_context_pp.cpp
|
smt_context_pp.cpp
|
||||||
|
|
189
src/smt/smt_consequences.cpp
Normal file
189
src/smt/smt_consequences.cpp
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2006 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
smt_consequences.cpp
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Tuned consequence finding for smt_context.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
nbjorner 2016-07-28.
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#include "smt_context.h"
|
||||||
|
#include "ast_util.h"
|
||||||
|
|
||||||
|
namespace smt {
|
||||||
|
|
||||||
|
expr_ref context::antecedent2fml(uint_set const& vars) {
|
||||||
|
expr_ref_vector premises(m_manager);
|
||||||
|
uint_set::iterator it = vars.begin(), end = vars.end();
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
premises.push_back(bool_var2expr(*it));
|
||||||
|
}
|
||||||
|
return mk_and(premises);
|
||||||
|
}
|
||||||
|
|
||||||
|
void context::extract_fixed_consequences(unsigned start, obj_map<expr, expr*>& vars, obj_hashtable<expr> const& assumptions, expr_ref_vector& conseq) {
|
||||||
|
ast_manager& m = m_manager;
|
||||||
|
pop_to_search_lvl();
|
||||||
|
literal_vector const& lits = assigned_literals();
|
||||||
|
unsigned sz = lits.size();
|
||||||
|
expr* e1, *e2;
|
||||||
|
expr_ref fml(m);
|
||||||
|
for (unsigned i = start; i < sz; ++i) {
|
||||||
|
literal lit = lits[i];
|
||||||
|
if (lit == true_literal) continue;
|
||||||
|
expr* e = bool_var2expr(lit.var());
|
||||||
|
uint_set s;
|
||||||
|
if (assumptions.contains(e)) {
|
||||||
|
s.insert(get_literal(e).var());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
b_justification js = get_justification(lit.var());
|
||||||
|
switch (js.get_kind()) {
|
||||||
|
case b_justification::CLAUSE: {
|
||||||
|
clause * cls = js.get_clause();
|
||||||
|
unsigned num_lits = cls->get_num_literals();
|
||||||
|
for (unsigned j = 0; j < num_lits; ++j) {
|
||||||
|
literal lit2 = cls->get_literal(j);
|
||||||
|
if (lit2.var() != lit.var()) {
|
||||||
|
s |= m_antecedents.find(lit2.var());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case b_justification::BIN_CLAUSE: {
|
||||||
|
s |= m_antecedents.find(js.get_literal().var());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case b_justification::AXIOM: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case b_justification::JUSTIFICATION:
|
||||||
|
justification* j = js.get_justification();
|
||||||
|
// warning_msg("TODO: extract antecedents from theory justification");
|
||||||
|
// std::cout << "TODO: justification\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_antecedents.insert(lit.var(), s);
|
||||||
|
bool found = false;
|
||||||
|
if (vars.contains(e)) {
|
||||||
|
found = true;
|
||||||
|
fml = lit.sign()?m.mk_not(e):e;
|
||||||
|
vars.erase(e);
|
||||||
|
}
|
||||||
|
else if (!lit.sign() && m.is_eq(e, e1, e2)) {
|
||||||
|
if (vars.contains(e2)) {
|
||||||
|
std::swap(e1, e2);
|
||||||
|
}
|
||||||
|
if (vars.contains(e1) && m.is_value(e2)) {
|
||||||
|
found = true;
|
||||||
|
fml = e;
|
||||||
|
vars.erase(e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
fml = m.mk_implies(antecedent2fml(s), fml);
|
||||||
|
conseq.push_back(fml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lbool context::get_consequences(expr_ref_vector const& assumptions,
|
||||||
|
expr_ref_vector const& vars, expr_ref_vector& conseq) {
|
||||||
|
|
||||||
|
lbool is_sat = check(assumptions.size(), assumptions.c_ptr());
|
||||||
|
if (is_sat != l_true) {
|
||||||
|
return is_sat;
|
||||||
|
}
|
||||||
|
obj_map<expr, expr*> var2val;
|
||||||
|
obj_hashtable<expr> _assumptions;
|
||||||
|
for (unsigned i = 0; i < assumptions.size(); ++i) {
|
||||||
|
_assumptions.insert(assumptions[i]);
|
||||||
|
}
|
||||||
|
model_ref mdl;
|
||||||
|
get_model(mdl);
|
||||||
|
expr_ref_vector trail(m_manager);
|
||||||
|
model_evaluator eval(*mdl.get());
|
||||||
|
expr_ref val(m_manager);
|
||||||
|
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||||
|
eval(vars[i], val);
|
||||||
|
if (m_manager.is_value(val)) {
|
||||||
|
trail.push_back(val);
|
||||||
|
var2val.insert(vars[i], val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extract_fixed_consequences(0, var2val, _assumptions, conseq);
|
||||||
|
unsigned num_units = assigned_literals().size();
|
||||||
|
app_ref eq(m_manager);
|
||||||
|
TRACE("context",
|
||||||
|
tout << "pop: " << num_levels << "\n";
|
||||||
|
tout << "vars: " << vars.size() << "\n";
|
||||||
|
tout << "lits: " << num_units << "\n";);
|
||||||
|
m_case_split_queue->init_search_eh();
|
||||||
|
while (!var2val.empty()) {
|
||||||
|
obj_map<expr,expr*>::iterator it = var2val.begin();
|
||||||
|
expr* e = it->m_key;
|
||||||
|
expr* val = it->m_value;
|
||||||
|
push_scope();
|
||||||
|
unsigned current_level = m_scope_lvl;
|
||||||
|
|
||||||
|
literal lit;
|
||||||
|
if (m_manager.is_bool(e)) {
|
||||||
|
lit = literal(get_bool_var(e), m_manager.is_true(val));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eq = mk_eq_atom(e, val);
|
||||||
|
internalize_formula(eq, false);
|
||||||
|
lit = literal(get_bool_var(eq), true);
|
||||||
|
}
|
||||||
|
assign(lit, b_justification::mk_axiom(), true);
|
||||||
|
flet<bool> l(m_searching, true);
|
||||||
|
while (true) {
|
||||||
|
is_sat = bounded_search();
|
||||||
|
TRACE("context", tout << "search result: " << is_sat << "\n";);
|
||||||
|
if (is_sat != l_true && m_last_search_failure != OK) {
|
||||||
|
return is_sat;
|
||||||
|
}
|
||||||
|
if (is_sat == l_undef) {
|
||||||
|
TRACE("context", tout << "restart\n";);
|
||||||
|
inc_limits();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (get_assignment(lit) == l_true) {
|
||||||
|
var2val.erase(e);
|
||||||
|
}
|
||||||
|
else if (get_assign_level(lit) > get_search_level()) {
|
||||||
|
TRACE("context", tout << "Retry fixing: " << mk_pp(e, m_manager) << "\n";);
|
||||||
|
pop_to_search_lvl();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TRACE("context", tout << "Fixed: " << mk_pp(e, m_manager) << "\n";);
|
||||||
|
}
|
||||||
|
extract_fixed_consequences(num_units, var2val, _assumptions, conseq);
|
||||||
|
num_units = assigned_literals().size();
|
||||||
|
if (var2val.contains(e)) {
|
||||||
|
TRACE("context", tout << "TBD: Fixed value to " << mk_pp(e, m_manager) << " was not retrieved\n";);
|
||||||
|
var2val.erase(e);
|
||||||
|
SASSERT(get_assignment(lit) == l_false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// repeat until we either have a model with negated literal or
|
||||||
|
// the literal is implied at base.
|
||||||
|
TRACE("context", tout << "Unfixed variables: " << var2val.size() << "\n";);
|
||||||
|
}
|
||||||
|
return l_true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2460,6 +2460,13 @@ namespace smt {
|
||||||
SASSERT(m_scope_lvl == m_base_lvl);
|
SASSERT(m_scope_lvl == m_base_lvl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void context::pop_to_search_lvl() {
|
||||||
|
unsigned num_levels = m_scope_lvl - get_search_level();
|
||||||
|
if (num_levels > 0) {
|
||||||
|
pop_scope(num_levels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Simplify the given clause using the assignment. Return
|
\brief Simplify the given clause using the assignment. Return
|
||||||
true if the clause was already satisfied, and false otherwise.
|
true if the clause was already satisfied, and false otherwise.
|
||||||
|
|
|
@ -1322,6 +1322,7 @@ namespace smt {
|
||||||
virtual void setup_context(bool use_static_features);
|
virtual void setup_context(bool use_static_features);
|
||||||
void setup_components(void);
|
void setup_components(void);
|
||||||
void pop_to_base_lvl();
|
void pop_to_base_lvl();
|
||||||
|
void pop_to_search_lvl();
|
||||||
#ifdef Z3DEBUG
|
#ifdef Z3DEBUG
|
||||||
bool already_internalized_theory(theory * th) const;
|
bool already_internalized_theory(theory * th) const;
|
||||||
bool already_internalized_theory_core(theory * th, expr_ref_vector const & s) const;
|
bool already_internalized_theory_core(theory * th, expr_ref_vector const & s) const;
|
||||||
|
@ -1343,6 +1344,11 @@ namespace smt {
|
||||||
literal lit, context& src_ctx, context& dst_ctx,
|
literal lit, context& src_ctx, context& dst_ctx,
|
||||||
vector<bool_var> b2v, ast_translation& tr);
|
vector<bool_var> b2v, ast_translation& tr);
|
||||||
|
|
||||||
|
u_map<uint_set> m_antecedents;
|
||||||
|
void extract_fixed_consequences(unsigned idx, obj_map<expr, expr*>& vars, obj_hashtable<expr> const& assumptions, expr_ref_vector& conseq);
|
||||||
|
|
||||||
|
expr_ref antecedent2fml(uint_set const& ante);
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref());
|
context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref());
|
||||||
|
@ -1383,6 +1389,8 @@ namespace smt {
|
||||||
|
|
||||||
lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true);
|
lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true);
|
||||||
|
|
||||||
|
lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq);
|
||||||
|
|
||||||
lbool setup_and_check(bool reset_cancel = true);
|
lbool setup_and_check(bool reset_cancel = true);
|
||||||
|
|
||||||
// return 'true' if assertions are inconsistent.
|
// return 'true' if assertions are inconsistent.
|
||||||
|
|
|
@ -99,6 +99,10 @@ namespace smt {
|
||||||
return m_kernel.check(num_assumptions, assumptions);
|
return m_kernel.check(num_assumptions, assumptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) {
|
||||||
|
return m_kernel.get_consequences(assumptions, vars, conseq);
|
||||||
|
}
|
||||||
|
|
||||||
void get_model(model_ref & m) const {
|
void get_model(model_ref & m) const {
|
||||||
m_kernel.get_model(m);
|
m_kernel.get_model(m);
|
||||||
}
|
}
|
||||||
|
@ -264,6 +268,10 @@ namespace smt {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbool kernel::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) {
|
||||||
|
return m_imp->get_consequences(assumptions, vars, conseq);
|
||||||
|
}
|
||||||
|
|
||||||
void kernel::get_model(model_ref & m) const {
|
void kernel::get_model(model_ref & m) const {
|
||||||
m_imp->get_model(m);
|
m_imp->get_model(m);
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,11 @@ namespace smt {
|
||||||
|
|
||||||
lbool check(app_ref_vector const& asms) { return check(asms.size(), (expr* const*)asms.c_ptr()); }
|
lbool check(app_ref_vector const& asms) { return check(asms.size(), (expr* const*)asms.c_ptr()); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief extract consequences among variables.
|
||||||
|
*/
|
||||||
|
lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Return the model associated with the last check command.
|
\brief Return the model associated with the last check command.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -67,6 +67,10 @@ namespace smt {
|
||||||
m_context.collect_statistics(st);
|
m_context.collect_statistics(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) {
|
||||||
|
return m_context.get_consequences(assumptions, vars, conseq);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void assert_expr(expr * t) {
|
virtual void assert_expr(expr * t) {
|
||||||
m_context.assert_expr(t);
|
m_context.assert_expr(t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,10 @@ struct scoped_assumption_push {
|
||||||
};
|
};
|
||||||
|
|
||||||
lbool solver::get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) {
|
lbool solver::get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) {
|
||||||
|
return get_consequences_core(asms, vars, consequences);
|
||||||
|
}
|
||||||
|
|
||||||
|
lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) {
|
||||||
ast_manager& m = asms.get_manager();
|
ast_manager& m = asms.get_manager();
|
||||||
lbool is_sat = check_sat(asms);
|
lbool is_sat = check_sat(asms);
|
||||||
if (is_sat != l_true) {
|
if (is_sat != l_true) {
|
||||||
|
|
|
@ -171,6 +171,11 @@ public:
|
||||||
~scoped_push() { if (!m_nopop) s.pop(1); }
|
~scoped_push() { if (!m_nopop) s.pop(1); }
|
||||||
void disable_pop() { m_nopop = true; }
|
void disable_pop() { m_nopop = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -65,6 +65,11 @@ lbool solver_na2as::check_sat(unsigned num_assumptions, expr * const * assumptio
|
||||||
return check_sat_core(m_assumptions.size(), m_assumptions.c_ptr());
|
return check_sat_core(m_assumptions.size(), m_assumptions.c_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbool solver_na2as::get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) {
|
||||||
|
append_assumptions app(m_assumptions, asms.size(), asms.c_ptr());
|
||||||
|
return get_consequences_core(m_assumptions, vars, consequences);
|
||||||
|
}
|
||||||
|
|
||||||
void solver_na2as::push() {
|
void solver_na2as::push() {
|
||||||
m_scopes.push_back(m_assumptions.size());
|
m_scopes.push_back(m_assumptions.size());
|
||||||
push_core();
|
push_core();
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
|
|
||||||
virtual unsigned get_num_assumptions() const { return m_assumptions.size(); }
|
virtual unsigned get_num_assumptions() const { return m_assumptions.size(); }
|
||||||
virtual expr * get_assumption(unsigned idx) const { return m_assumptions[idx]; }
|
virtual expr * get_assumption(unsigned idx) const { return m_assumptions[idx]; }
|
||||||
|
virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences);
|
||||||
protected:
|
protected:
|
||||||
virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0;
|
virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0;
|
||||||
virtual void push_core() = 0;
|
virtual void push_core() = 0;
|
||||||
|
|
Loading…
Reference in a new issue