3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-12 12:08:18 +00:00

add unit extraction

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2018-03-06 01:08:17 -08:00
parent 75ba65a18a
commit 718e5a9b6c
27 changed files with 207 additions and 76 deletions

View file

@ -39,6 +39,8 @@ public:
virtual ~ackr_model_converter() { } virtual ~ackr_model_converter() { }
virtual void get_units(obj_map<expr, bool>& units) { units.reset(); }
virtual void operator()(model_ref & md, unsigned goal_idx) { virtual void operator()(model_ref & md, unsigned goal_idx) {
SASSERT(goal_idx == 0); SASSERT(goal_idx == 0);
SASSERT(!fixed_model || md.get() == 0 || (!md->get_num_constants() && !md->get_num_functions())); SASSERT(!fixed_model || md.get() == 0 || (!md->get_num_constants() && !md->get_num_functions()));

View file

@ -43,6 +43,8 @@ public:
operator()(md, 0); operator()(md, 0);
} }
virtual void get_units(obj_map<expr, bool>& units) { units.reset(); }
//void display(std::ostream & out); //void display(std::ostream & out);
virtual model_converter * translate(ast_translation & translator) { virtual model_converter * translate(ast_translation & translator) {

View file

@ -347,6 +347,22 @@ extern "C" {
Z3_CATCH_RETURN(0); Z3_CATCH_RETURN(0);
} }
Z3_ast_vector Z3_API Z3_solver_get_units(Z3_context c, Z3_solver s) {
Z3_TRY;
LOG_Z3_solver_get_units(c, s);
RESET_ERROR_CODE();
init_solver(c, s);
Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
mk_c(c)->save_object(v);
expr_ref_vector fmls = to_solver_ref(s)->get_units(mk_c(c)->m());
for (expr* f : fmls) {
v->m_ast_vector.push_back(f);
}
RETURN_Z3(of_ast_vector(v));
Z3_CATCH_RETURN(0);
}
static Z3_lbool _solver_check(Z3_context c, Z3_solver s, unsigned num_assumptions, Z3_ast const assumptions[]) { static Z3_lbool _solver_check(Z3_context c, Z3_solver s, unsigned num_assumptions, Z3_ast const assumptions[]) {
for (unsigned i = 0; i < num_assumptions; i++) { for (unsigned i = 0; i < num_assumptions; i++) {
if (!is_expr(to_ast(assumptions[i]))) { if (!is_expr(to_ast(assumptions[i]))) {

View file

@ -265,6 +265,20 @@ namespace Microsoft.Z3
} }
} }
/// <summary>
/// Currently inferred units.
/// </summary>
public BoolExpr[] Units
{
get
{
Contract.Ensures(Contract.Result<BoolExpr[]>() != null);
ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_units(Context.nCtx, NativeObject));
return assertions.ToBoolExprArray();
}
}
/// <summary> /// <summary>
/// Checks whether the assertions in the solver are consistent or not. /// Checks whether the assertions in the solver are consistent or not.
/// </summary> /// </summary>

View file

@ -6369,6 +6369,11 @@ class Solver(Z3PPObject):
""" """
return AstVector(Z3_solver_get_assertions(self.ctx.ref(), self.solver), self.ctx) return AstVector(Z3_solver_get_assertions(self.ctx.ref(), self.solver), self.ctx)
def units(self):
"""Return an AST vector containing all currently inferred units.
"""
return AstVector(Z3_solver_get_units(self.ctx.ref(), self.solver), self.ctx)
def statistics(self): def statistics(self):
"""Return statistics for the last `check()`. """Return statistics for the last `check()`.

View file

@ -6163,6 +6163,13 @@ extern "C" {
*/ */
Z3_ast_vector Z3_API Z3_solver_get_assertions(Z3_context c, Z3_solver s); Z3_ast_vector Z3_API Z3_solver_get_assertions(Z3_context c, Z3_solver s);
/**
\brief Return the set of units modulo model conversion.
def_API('Z3_solver_get_units', AST_VECTOR, (_in(CONTEXT), _in(SOLVER)))
*/
Z3_ast_vector Z3_API Z3_solver_get_units(Z3_context c, Z3_solver s);
/** /**
\brief Check whether the assertions in a given solver are consistent or not. \brief Check whether the assertions in a given solver are consistent or not.

View file

@ -387,6 +387,9 @@ namespace datalog {
void operator()(model_ref&) override {} void operator()(model_ref&) override {}
void display(std::ostream & out) override { } void display(std::ostream & out) override { }
void get_units(obj_map<expr, bool>& units) override {}
}; };
model_converter* mk_skip_model_converter() { return alloc(skip_model_converter); } model_converter* mk_skip_model_converter() { return alloc(skip_model_converter); }

View file

@ -63,6 +63,8 @@ namespace datalog {
return alloc(bit_blast_model_converter, m); return alloc(bit_blast_model_converter, m);
} }
virtual void get_units(obj_map<expr, bool>& units) {}
virtual void display(std::ostream& out) { out << "(bit-blast-model-converter)\n"; } virtual void display(std::ostream& out) { out << "(bit-blast-model-converter)\n"; }
virtual void operator()(model_ref & model) { virtual void operator()(model_ref & model) {

View file

@ -120,6 +120,8 @@ namespace datalog {
} }
} }
virtual void get_units(obj_map<expr, bool>& units) {}
virtual void operator()(model_ref & mr) { virtual void operator()(model_ref & mr) {
for (unsigned i = 0; i < m_funcs.size(); ++i) { for (unsigned i = 0; i < m_funcs.size(); ++i) {
func_decl* p = m_funcs[i].get(); func_decl* p = m_funcs[i].get();

View file

@ -55,6 +55,8 @@ namespace datalog {
virtual void display(std::ostream& out) { display_add(out, m); } virtual void display(std::ostream& out) { display_add(out, m); }
virtual void get_units(obj_map<expr, bool>& units) { units.reset(); }
void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, sort_ref_vector& sorts, svector<bool> const& bound) { void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, sort_ref_vector& sorts, svector<bool> const& bound) {
m_old_funcs.push_back(old_p); m_old_funcs.push_back(old_p);
m_new_funcs.push_back(new_p); m_new_funcs.push_back(new_p);

View file

@ -38,13 +38,13 @@ namespace datalog {
m_new2old.insert(new_f, old_f); m_new2old.insert(new_f, old_f);
} }
virtual void get_units(obj_map<expr, bool>& units) { units.reset(); }
virtual void operator()(model_ref& md) { virtual void operator()(model_ref& md) {
model_ref old_model = alloc(model, m); model_ref old_model = alloc(model, m);
obj_map<func_decl, func_decl*>::iterator it = m_new2old.begin(); for (auto const& kv : m_new2old) {
obj_map<func_decl, func_decl*>::iterator end = m_new2old.end(); func_decl* old_p = kv.m_value;
for (; it != end; ++it) { func_decl* new_p = kv.m_key;
func_decl* old_p = it->m_value;
func_decl* new_p = it->m_key;
func_interp* old_fi = alloc(func_interp, m, old_p->get_arity()); func_interp* old_fi = alloc(func_interp, m, old_p->get_arity());
if (new_p->get_arity() == 0) { if (new_p->get_arity() == 0) {

View file

@ -308,6 +308,8 @@ namespace datalog {
m_sliceable.insert(f, bv); m_sliceable.insert(f, bv);
} }
void get_units(obj_map<expr, bool>& units) override {}
void operator()(model_ref & md) override { void operator()(model_ref & md) override {
if (m_slice2old.empty()) { if (m_slice2old.empty()) {
return; return;

View file

@ -981,6 +981,12 @@ void sat2goal::mc::display(std::ostream& out) {
if (m_gmc) m_gmc->display(out); if (m_gmc) m_gmc->display(out);
} }
void sat2goal::mc::get_units(obj_map<expr, bool>& units) {
flush_gmc();
if (m_gmc) m_gmc->get_units(units);
}
void sat2goal::mc::operator()(model_ref & md) { void sat2goal::mc::operator()(model_ref & md) {
model_evaluator ev(*md); model_evaluator ev(*md);
ev.set_model_completion(false); ev.set_model_completion(false);

View file

@ -94,7 +94,7 @@ public:
model_converter* translate(ast_translation& translator) override; model_converter* translate(ast_translation& translator) override;
void collect(ast_pp_util& visitor) override; void collect(ast_pp_util& visitor) override;
void display(std::ostream& out) override; void display(std::ostream& out) override;
void get_units(obj_map<expr, bool>& units) override;
app* var2expr(sat::bool_var v) const { return m_var2expr.get(v, nullptr); } app* var2expr(sat::bool_var v) const { return m_var2expr.get(v, nullptr); }
expr_ref lit2expr(sat::literal l); expr_ref lit2expr(sat::literal l);
void insert(sat::bool_var v, app * atom, bool aux); void insert(sat::bool_var v, app * atom, bool aux);

View file

@ -211,7 +211,35 @@ void solver::updt_params(params_ref const & p) {
m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false);
} }
void solver::hoist_converter(model_converter_ref& mc) {
}
expr_ref_vector solver::get_units(ast_manager& m) {
expr_ref_vector fmls(m), result(m), tmp(m);
get_assertions(fmls);
obj_map<expr, bool> units;
for (expr* f : fmls) {
if (m.is_not(f, f) && is_literal(m, f)) {
m.inc_ref(f);
units.insert(f, false);
}
else if (is_literal(m, f)) {
m.inc_ref(f);
units.insert(f, true);
}
}
model_converter_ref mc = get_model_converter();
if (mc) {
mc->get_units(units);
}
for (auto const& kv : units) {
tmp.push_back(kv.m_key);
if (kv.m_value)
result.push_back(kv.m_key);
else
result.push_back(m.mk_not(kv.m_key));
}
for (expr* e : tmp) {
m.dec_ref(e);
}
return result;
}

View file

@ -203,6 +203,11 @@ public:
virtual model_converter_ref get_model_converter() const { return m_mc0; } virtual model_converter_ref get_model_converter() const { return m_mc0; }
/**
\brief extract units from solver.
*/
expr_ref_vector get_units(ast_manager& m);
class scoped_push { class scoped_push {
solver& s; solver& s;
bool m_nopop; bool m_nopop;
@ -220,7 +225,6 @@ protected:
bool is_literal(ast_manager& m, expr* e); bool is_literal(ast_manager& m, expr* e);
void hoist_converter(model_converter_ref& mc);
}; };
typedef ref<solver> solver_ref; typedef ref<solver> solver_ref;

View file

@ -119,6 +119,8 @@ class eq2bv_tactic : public tactic {
} }
} }
virtual void get_units(obj_map<expr, bool>& units) { units.reset(); }
}; };
public: public:

View file

@ -180,6 +180,8 @@ class fm_tactic : public tactic {
m_clauses.back().swap(c); m_clauses.back().swap(c);
} }
virtual void get_units(obj_map<expr, bool>& units) { units.reset(); }
virtual void operator()(model_ref & md) { virtual void operator()(model_ref & md) {
TRACE("fm_mc", model_v2_pp(tout, *md); display(tout);); TRACE("fm_mc", model_v2_pp(tout, *md); display(tout););
model_evaluator ev(*(md.get())); model_evaluator ev(*(md.get()));

View file

@ -50,6 +50,10 @@ pb2bv_model_converter::~pb2bv_model_converter() {
} }
} }
void pb2bv_model_converter::get_units(obj_map<expr, bool>& units) {
if (!m_c2bit.empty()) units.reset();
}
void pb2bv_model_converter::operator()(model_ref & md) { void pb2bv_model_converter::operator()(model_ref & md) {
TRACE("pb2bv", tout << "converting model:\n"; model_v2_pp(tout, *md); display(tout);); TRACE("pb2bv", tout << "converting model:\n"; model_v2_pp(tout, *md); display(tout););

View file

@ -33,6 +33,7 @@ public:
virtual ~pb2bv_model_converter(); virtual ~pb2bv_model_converter();
void operator()(model_ref & md) override; void operator()(model_ref & md) override;
void display(std::ostream & out) override; void display(std::ostream & out) override;
void get_units(obj_map<expr, bool>& units) override;
model_converter * translate(ast_translation & translator) override; model_converter * translate(ast_translation & translator) override;
}; };

View file

@ -206,6 +206,10 @@ struct bit_blaster_model_converter : public model_converter {
} }
} }
void get_units(obj_map<expr, bool>& units) override {
// no-op
}
protected: protected:
bit_blaster_model_converter(ast_manager & m):m_vars(m), m_bits(m) { } bit_blaster_model_converter(ast_manager & m):m_vars(m), m_bits(m) { }
public: public:

View file

@ -33,60 +33,13 @@ Notes:
--*/ --*/
#include "tactic/core/pb_preprocess_tactic.h" #include "tactic/core/pb_preprocess_tactic.h"
#include "tactic/tactical.h" #include "tactic/tactical.h"
#include "tactic/generic_model_converter.h"
#include "ast/for_each_expr.h" #include "ast/for_each_expr.h"
#include "ast/pb_decl_plugin.h" #include "ast/pb_decl_plugin.h"
#include "ast/rewriter/th_rewriter.h" #include "ast/rewriter/th_rewriter.h"
#include "ast/expr_substitution.h" #include "ast/expr_substitution.h"
#include "ast/ast_pp.h" #include "ast/ast_pp.h"
class pb_preproc_model_converter : public model_converter {
ast_manager& m;
pb_util pb;
expr_ref_vector m_refs;
svector<std::pair<app*, expr*> > m_const;
public:
pb_preproc_model_converter(ast_manager& m):m(m), pb(m), m_refs(m) {}
virtual void operator()(model_ref & mdl) {
for (auto const& kv : m_const) {
mdl->register_decl(kv.first->get_decl(), kv.second);
}
}
void set_value(expr* e, bool p) {
while (m.is_not(e, e)) {
p = !p;
}
SASSERT(is_app(e));
set_value_p(to_app(e), p?m.mk_true():m.mk_false());
}
virtual model_converter * translate(ast_translation & translator) {
pb_preproc_model_converter* mc = alloc(pb_preproc_model_converter, translator.to());
for (auto const& kv : m_const) {
mc->set_value_p(translator(kv.first), translator(kv.second));
}
return mc;
}
virtual void display(std::ostream & out) {
for (auto const& kv : m_const) {
out << "(model-set " << mk_pp(kv.first, m) << " " << mk_pp(kv.second, m) << ")\n";
}
}
private:
void set_value_p(app* e, expr* v) {
SASSERT(e->get_num_args() == 0);
SASSERT(is_uninterp_const(e));
m_const.push_back(std::make_pair(e, v));
m_refs.push_back(e);
m_refs.push_back(v);
}
};
class pb_preprocess_tactic : public tactic { class pb_preprocess_tactic : public tactic {
struct rec { unsigned_vector pos, neg; rec() { } }; struct rec { unsigned_vector pos, neg; rec() { } };
typedef obj_map<app, rec> var_map; typedef obj_map<app, rec> var_map;
@ -119,24 +72,31 @@ class pb_preprocess_tactic : public tactic {
for (unsigned i = 0; i < m_other.size(); ++i) { for (unsigned i = 0; i < m_other.size(); ++i) {
out << "ot " << m_other[i] << ": " << mk_pp(g->form(m_other[i]), m) << "\n"; out << "ot " << m_other[i] << ": " << mk_pp(g->form(m_other[i]), m) << "\n";
} }
var_map::iterator it = m_vars.begin(); for (auto const& kv : m_vars) {
var_map::iterator end = m_vars.end(); app* e = kv.m_key;
for (; it != end; ++it) { unsigned_vector const& pos = kv.m_value.pos;
app* e = it->m_key; unsigned_vector const& neg = kv.m_value.neg;
unsigned_vector const& pos = it->m_value.pos;
unsigned_vector const& neg = it->m_value.neg;
out << mk_pp(e, m) << ": "; out << mk_pp(e, m) << ": ";
for (unsigned i = 0; i < pos.size(); ++i) { for (unsigned p : pos) {
out << "p: " << pos[i] << " "; out << "p: " << p << " ";
} }
for (unsigned i = 0; i < neg.size(); ++i) { for (unsigned n : neg) {
out << "n: " << neg[i] << " "; out << "n: " << n << " ";
} }
out << "\n"; out << "\n";
} }
} }
void set_value(generic_model_converter& mc, expr* e, bool p) {
while (m.is_not(e, e)) {
p = !p;
}
SASSERT(is_app(e));
mc.add(to_app(e), p?m.mk_true():m.mk_false());
}
public: public:
pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()):
m(m), pb(m), m_r(m) {} m(m), pb(m), m_r(m) {}
@ -156,7 +116,7 @@ public:
throw tactic_exception("pb-preprocess does not support proofs"); throw tactic_exception("pb-preprocess does not support proofs");
} }
pb_preproc_model_converter* pp = alloc(pb_preproc_model_converter, m); generic_model_converter* pp = alloc(generic_model_converter, m, "pb-preprocess");
g->add(pp); g->add(pp);
g->inc_depth(); g->inc_depth();
@ -165,7 +125,7 @@ public:
// decompose(g); // decompose(g);
} }
bool simplify(goal_ref const& g, pb_preproc_model_converter& mc) { bool simplify(goal_ref const& g, generic_model_converter& mc) {
reset(); reset();
normalize(g); normalize(g);
if (g->inconsistent()) { if (g->inconsistent()) {
@ -203,11 +163,11 @@ public:
TRACE("pb", tout << mk_pp(e, m) << " " << r.pos.size() << " " << r.neg.size() << "\n";); TRACE("pb", tout << mk_pp(e, m) << " " << r.pos.size() << " " << r.neg.size() << "\n";);
if (r.pos.empty()) { if (r.pos.empty()) {
replace(r.neg, e, m.mk_false(), g); replace(r.neg, e, m.mk_false(), g);
mc.set_value(e, false); set_value(mc, e, false);
} }
else if (r.neg.empty()) { else if (r.neg.empty()) {
replace(r.pos, e, m.mk_true(), g); replace(r.pos, e, m.mk_true(), g);
mc.set_value(e, true); set_value(mc, e, true);
} }
if (g->inconsistent()) return false; if (g->inconsistent()) return false;
++it; ++it;
@ -509,7 +469,7 @@ private:
// Implement very special case of resolution. // Implement very special case of resolution.
void resolve(pb_preproc_model_converter& mc, unsigned idx1, void resolve(generic_model_converter& mc, unsigned idx1,
unsigned_vector const& positions, app* e, bool pos, goal_ref const& g) { unsigned_vector const& positions, app* e, bool pos, goal_ref const& g) {
if (positions.size() != 1) return; if (positions.size() != 1) return;
unsigned idx2 = positions[0]; unsigned idx2 = positions[0];
@ -558,7 +518,7 @@ private:
else { else {
args2[j] = m.mk_true(); args2[j] = m.mk_true();
} }
mc.set_value(arg, j != min_index); set_value(mc, arg, j != min_index);
} }
tmp1 = pb.mk_ge(args2.size(), coeffs2.c_ptr(), args2.c_ptr(), k2); tmp1 = pb.mk_ge(args2.size(), coeffs2.c_ptr(), args2.c_ptr(), k2);

View file

@ -181,6 +181,53 @@ void generic_model_converter::operator()(expr_ref& fml) {
fml = mk_and(fmls); fml = mk_and(fmls);
} }
void generic_model_converter::get_units(obj_map<expr, bool>& units) {
th_rewriter rw(m);
expr_safe_replace rep(m);
expr_ref tmp(m);
bool val = false;
expr* f = nullptr;
for (auto const& kv : units) {
rep.insert(kv.m_key, kv.m_value ? m.mk_true() : m.mk_false());
}
for (unsigned i = m_entries.size(); i-- > 0;) {
entry const& e = m_entries[i];
switch (e.m_instruction) {
case HIDE:
tmp = m.mk_const(e.m_f);
if (units.contains(tmp)) {
m.dec_ref(tmp);
units.remove(tmp);
}
break;
case ADD:
if (e.m_f->get_arity() == 0 && m.is_bool(e.m_f->get_range())) {
tmp = m.mk_const(e.m_f);
if (units.contains(tmp)) {
break;
}
tmp = e.m_def;
rep(tmp);
rw(tmp);
if (m.is_true(tmp)) {
tmp = m.mk_const(e.m_f);
m.inc_ref(tmp);
units.insert(tmp, true);
rep.insert(tmp, m.mk_true());
}
else if (m.is_false(tmp)) {
tmp = m.mk_const(e.m_f);
m.inc_ref(tmp);
units.insert(tmp, false);
rep.insert(tmp, m.mk_false());
}
}
break;
}
}
}
/* /*
\brief simplify definition expansion from model converter in the case they come from blocked clauses. \brief simplify definition expansion from model converter in the case they come from blocked clauses.
In this case the definitions are of the form: In this case the definitions are of the form:

View file

@ -71,6 +71,8 @@ public:
void collect(ast_pp_util& visitor) override; void collect(ast_pp_util& visitor) override;
void operator()(expr_ref& fml) override; void operator()(expr_ref& fml) override;
void get_units(obj_map<expr, bool>& units) override;
}; };
typedef ref<generic_model_converter> generic_model_converter_ref; typedef ref<generic_model_converter> generic_model_converter_ref;

View file

@ -80,6 +80,9 @@ public:
ast_manager& get_manager() { return m; } ast_manager& get_manager() { return m; }
void display(std::ostream & out) override {} void display(std::ostream & out) override {}
void get_units(obj_map<expr, bool>& units) override { units.reset(); }
}; };
#endif #endif

View file

@ -71,14 +71,19 @@ public:
} }
void operator()(expr_ref & fml) override { void operator()(expr_ref & fml) override {
this->m_c1->operator()(fml);
this->m_c2->operator()(fml); this->m_c2->operator()(fml);
this->m_c1->operator()(fml);
} }
void operator()(labels_vec & r) override { void operator()(labels_vec & r) override {
this->m_c2->operator()(r); this->m_c2->operator()(r);
this->m_c1->operator()(r); this->m_c1->operator()(r);
} }
void get_units(obj_map<expr, bool>& fmls) override {
m_c2->get_units(fmls);
m_c1->get_units(fmls);
}
char const * get_name() const override { return "concat-model-converter"; } char const * get_name() const override { return "concat-model-converter"; }
@ -125,6 +130,10 @@ public:
fml = r; fml = r;
} }
void get_units(obj_map<expr, bool>& fmls) override {
// no-op
}
void cancel() override { void cancel() override {
} }

View file

@ -88,6 +88,8 @@ public:
formula and removing these definitions from the model converter. formula and removing these definitions from the model converter.
*/ */
virtual void operator()(expr_ref& formula) { UNREACHABLE(); } virtual void operator()(expr_ref& formula) { UNREACHABLE(); }
virtual void get_units(obj_map<expr, bool>& fmls) { UNREACHABLE(); }
}; };
typedef ref<model_converter> model_converter_ref; typedef ref<model_converter> model_converter_ref;