mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 17:45:32 +00:00
Reorganizing code base
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
9a84cba6c9
commit
ded42feeb6
62 changed files with 4 additions and 115 deletions
630
src/tactic/goal.cpp
Normal file
630
src/tactic/goal.cpp
Normal file
|
@ -0,0 +1,630 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
goal.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Proof / Model finding Goals
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-10-12
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"goal.h"
|
||||
#include"cmd_context.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"well_sorted.h"
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, goal::precision p) {
|
||||
switch (p) {
|
||||
case goal::PRECISE: out << "precise"; break;
|
||||
case goal::UNDER: out << "under"; break;
|
||||
case goal::OVER: out << "over"; break;
|
||||
case goal::UNDER_OVER: out << "under-over"; break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void goal::copy_to(goal & target) const {
|
||||
SASSERT(&m_manager == &(target.m_manager));
|
||||
if (this == &target)
|
||||
return;
|
||||
|
||||
m().copy(m_forms, target.m_forms);
|
||||
m().copy(m_proofs, target.m_proofs);
|
||||
m().copy(m_dependencies, target.m_dependencies);
|
||||
|
||||
target.m_depth = std::max(m_depth, target.m_depth);
|
||||
SASSERT(target.m_proofs_enabled == m_proofs_enabled);
|
||||
SASSERT(target.m_core_enabled == m_core_enabled);
|
||||
target.m_inconsistent = m_inconsistent;
|
||||
target.m_precision = mk_union(prec(), target.prec());
|
||||
}
|
||||
|
||||
void goal::push_back(expr * f, proof * pr, expr_dependency * d) {
|
||||
if (m().is_true(f))
|
||||
return;
|
||||
if (m().is_false(f)) {
|
||||
m().del(m_forms);
|
||||
m().del(m_proofs);
|
||||
m().del(m_dependencies);
|
||||
m_inconsistent = true;
|
||||
}
|
||||
else {
|
||||
SASSERT(!m_inconsistent);
|
||||
}
|
||||
m().push_back(m_forms, f);
|
||||
if (proofs_enabled())
|
||||
m().push_back(m_proofs, pr);
|
||||
if (unsat_core_enabled())
|
||||
m().push_back(m_dependencies, d);
|
||||
}
|
||||
|
||||
void goal::quick_process(bool save_first, expr * & f, expr_dependency * d) {
|
||||
if (!m().is_and(f) && !(m().is_not(f) && m().is_or(to_app(f)->get_arg(0)))) {
|
||||
if (!save_first) {
|
||||
push_back(f, 0, d);
|
||||
}
|
||||
return;
|
||||
}
|
||||
typedef std::pair<expr *, bool> expr_pol;
|
||||
sbuffer<expr_pol, 64> todo;
|
||||
todo.push_back(expr_pol(f, true));
|
||||
while (!todo.empty()) {
|
||||
if (m_inconsistent)
|
||||
return;
|
||||
expr_pol p = todo.back();
|
||||
expr * curr = p.first;
|
||||
bool pol = p.second;
|
||||
todo.pop_back();
|
||||
if (pol && m().is_and(curr)) {
|
||||
app * t = to_app(curr);
|
||||
unsigned i = t->get_num_args();
|
||||
while (i > 0) {
|
||||
--i;
|
||||
todo.push_back(expr_pol(t->get_arg(i), true));
|
||||
}
|
||||
}
|
||||
else if (!pol && m().is_or(curr)) {
|
||||
app * t = to_app(curr);
|
||||
unsigned i = t->get_num_args();
|
||||
while (i > 0) {
|
||||
--i;
|
||||
todo.push_back(expr_pol(t->get_arg(i), false));
|
||||
}
|
||||
}
|
||||
else if (m().is_not(curr)) {
|
||||
todo.push_back(expr_pol(to_app(curr)->get_arg(0), !pol));
|
||||
}
|
||||
else {
|
||||
if (!pol)
|
||||
curr = m().mk_not(curr);
|
||||
if (save_first) {
|
||||
f = curr;
|
||||
save_first = false;
|
||||
}
|
||||
else {
|
||||
push_back(curr, 0, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void goal::process_and(bool save_first, app * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr) {
|
||||
unsigned num = f->get_num_args();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
if (m_inconsistent)
|
||||
return;
|
||||
slow_process(save_first && i == 0, f->get_arg(i), m().mk_and_elim(pr, i), d, out_f, out_pr);
|
||||
}
|
||||
}
|
||||
|
||||
void goal::process_not_or(bool save_first, app * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr) {
|
||||
unsigned num = f->get_num_args();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
if (m_inconsistent)
|
||||
return;
|
||||
expr * child = f->get_arg(i);
|
||||
if (m().is_not(child)) {
|
||||
expr * not_child = to_app(child)->get_arg(0);
|
||||
slow_process(save_first && i == 0, not_child, m().mk_not_or_elim(pr, i), d, out_f, out_pr);
|
||||
}
|
||||
else {
|
||||
expr_ref not_child(m());
|
||||
not_child = m().mk_not(child);
|
||||
slow_process(save_first && i == 0, not_child, m().mk_not_or_elim(pr, i), d, out_f, out_pr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void goal::slow_process(bool save_first, expr * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr) {
|
||||
if (m().is_and(f))
|
||||
process_and(save_first, to_app(f), pr, d, out_f, out_pr);
|
||||
else if (m().is_not(f) && m().is_or(to_app(f)->get_arg(0)))
|
||||
process_not_or(save_first, to_app(to_app(f)->get_arg(0)), pr, d, out_f, out_pr);
|
||||
else if (save_first) {
|
||||
out_f = f;
|
||||
out_pr = pr;
|
||||
}
|
||||
else {
|
||||
push_back(f, pr, d);
|
||||
}
|
||||
}
|
||||
|
||||
void goal::slow_process(expr * f, proof * pr, expr_dependency * d) {
|
||||
expr_ref out_f(m());
|
||||
proof_ref out_pr(m());
|
||||
slow_process(false, f, pr, d, out_f, out_pr);
|
||||
}
|
||||
|
||||
void goal::assert_expr(expr * f, proof * pr, expr_dependency * d) {
|
||||
SASSERT(proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr)));
|
||||
if (m_inconsistent)
|
||||
return;
|
||||
if (proofs_enabled())
|
||||
slow_process(f, pr, d);
|
||||
else
|
||||
quick_process(false, f, d);
|
||||
}
|
||||
|
||||
void goal::get_formulas(ptr_vector<expr> & result) {
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
result.push_back(form(i));
|
||||
}
|
||||
}
|
||||
|
||||
void goal::update(unsigned i, expr * f, proof * pr, expr_dependency * d) {
|
||||
SASSERT(proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr)));
|
||||
if (m_inconsistent)
|
||||
return;
|
||||
if (proofs_enabled()) {
|
||||
expr_ref out_f(m());
|
||||
proof_ref out_pr(m());
|
||||
slow_process(true, f, pr, d, out_f, out_pr);
|
||||
if (!m_inconsistent) {
|
||||
if (m().is_false(out_f)) {
|
||||
push_back(out_f, out_pr, d);
|
||||
}
|
||||
else {
|
||||
m().set(m_forms, i, out_f);
|
||||
m().set(m_proofs, i, out_pr);
|
||||
if (unsat_core_enabled())
|
||||
m().set(m_dependencies, i, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
quick_process(true, f, d);
|
||||
if (!m_inconsistent) {
|
||||
if (m().is_false(f)) {
|
||||
push_back(f, 0, d);
|
||||
}
|
||||
else {
|
||||
m().set(m_forms, i, f);
|
||||
if (unsat_core_enabled())
|
||||
m().set(m_dependencies, i, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void goal::reset_core() {
|
||||
m().del(m_forms);
|
||||
m().del(m_proofs);
|
||||
m().del(m_dependencies);
|
||||
}
|
||||
|
||||
void goal::reset_all() {
|
||||
reset_core();
|
||||
m_depth = 0;
|
||||
m_inconsistent = false;
|
||||
m_precision = PRECISE;
|
||||
}
|
||||
|
||||
void goal::reset() {
|
||||
reset_core();
|
||||
m_inconsistent = false;
|
||||
}
|
||||
|
||||
void goal::display(cmd_context & ctx, std::ostream & out) const {
|
||||
out << "(goal";
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
out << "\n ";
|
||||
ctx.display(out, form(i), 2);
|
||||
}
|
||||
out << "\n :precision " << prec() << " :depth " << depth() << ")" << std::endl;
|
||||
}
|
||||
|
||||
void goal::display_with_dependencies(cmd_context & ctx, std::ostream & out) const {
|
||||
ptr_vector<expr> deps;
|
||||
obj_hashtable<expr> to_pp;
|
||||
out << "(goal";
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
out << "\n |-";
|
||||
deps.reset();
|
||||
m().linearize(dep(i), deps);
|
||||
ptr_vector<expr>::iterator it = deps.begin();
|
||||
ptr_vector<expr>::iterator end = deps.end();
|
||||
for (; it != end; ++it) {
|
||||
expr * d = *it;
|
||||
if (is_uninterp_const(d)) {
|
||||
out << " " << mk_ismt2_pp(d, m());
|
||||
}
|
||||
else {
|
||||
out << " #" << d->get_id();
|
||||
to_pp.insert(d);
|
||||
}
|
||||
}
|
||||
out << "\n ";
|
||||
ctx.display(out, form(i), 2);
|
||||
}
|
||||
if (!to_pp.empty()) {
|
||||
out << "\n :dependencies-definitions (";
|
||||
obj_hashtable<expr>::iterator it = to_pp.begin();
|
||||
obj_hashtable<expr>::iterator end = to_pp.end();
|
||||
for (; it != end; ++it) {
|
||||
expr * d = *it;
|
||||
out << "\n (#" << d->get_id() << "\n ";
|
||||
ctx.display(out, d, 2);
|
||||
out << ")";
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
out << "\n :precision " << prec() << " :depth " << depth() << ")" << std::endl;
|
||||
}
|
||||
|
||||
void goal::display_with_dependencies(std::ostream & out) const {
|
||||
ptr_vector<expr> deps;
|
||||
out << "(goal";
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
out << "\n |-";
|
||||
deps.reset();
|
||||
m().linearize(dep(i), deps);
|
||||
ptr_vector<expr>::iterator it = deps.begin();
|
||||
ptr_vector<expr>::iterator end = deps.end();
|
||||
for (; it != end; ++it) {
|
||||
expr * d = *it;
|
||||
if (is_uninterp_const(d)) {
|
||||
out << " " << mk_ismt2_pp(d, m());
|
||||
}
|
||||
else {
|
||||
out << " #" << d->get_id();
|
||||
}
|
||||
}
|
||||
out << "\n " << mk_ismt2_pp(form(i), m(), 2);
|
||||
}
|
||||
out << "\n :precision " << prec() << " :depth " << depth() << ")" << std::endl;
|
||||
}
|
||||
|
||||
void goal::display(cmd_context & ctx) const {
|
||||
display(ctx, ctx.regular_stream());
|
||||
}
|
||||
|
||||
void goal::display_with_dependencies(cmd_context & ctx) const {
|
||||
display_with_dependencies(ctx, ctx.regular_stream());
|
||||
}
|
||||
|
||||
void goal::display(std::ostream & out) const {
|
||||
out << "(goal";
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
out << "\n ";
|
||||
out << mk_ismt2_pp(form(i), m(), 2);
|
||||
}
|
||||
out << ")" << std::endl;
|
||||
}
|
||||
|
||||
void goal::display_as_and(std::ostream & out) const {
|
||||
ptr_buffer<expr> args;
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
args.push_back(form(i));
|
||||
expr_ref tmp(m());
|
||||
tmp = m().mk_and(args.size(), args.c_ptr());
|
||||
out << mk_ismt2_pp(tmp, m()) << "\n";
|
||||
}
|
||||
|
||||
void goal::display_ll(std::ostream & out) const {
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
out << mk_ll_pp(form(i), m()) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Assumes that the formula is already in CNF.
|
||||
*/
|
||||
void goal::display_dimacs(std::ostream & out) const {
|
||||
obj_map<expr, unsigned> expr2var;
|
||||
unsigned num_vars = 0;
|
||||
unsigned num_cls = size();
|
||||
for (unsigned i = 0; i < num_cls; i++) {
|
||||
expr * f = form(i);
|
||||
unsigned num_lits;
|
||||
expr * const * lits;
|
||||
if (m().is_or(f)) {
|
||||
num_lits = to_app(f)->get_num_args();
|
||||
lits = to_app(f)->get_args();
|
||||
}
|
||||
else {
|
||||
num_lits = 1;
|
||||
lits = &f;
|
||||
}
|
||||
for (unsigned j = 0; j < num_lits; j++) {
|
||||
expr * l = lits[j];
|
||||
if (m().is_not(l))
|
||||
l = to_app(l)->get_arg(0);
|
||||
if (expr2var.contains(l))
|
||||
continue;
|
||||
num_vars++;
|
||||
expr2var.insert(l, num_vars);
|
||||
}
|
||||
}
|
||||
out << "p cnf " << num_vars << " " << num_cls << "\n";
|
||||
for (unsigned i = 0; i < num_cls; i++) {
|
||||
expr * f = form(i);
|
||||
unsigned num_lits;
|
||||
expr * const * lits;
|
||||
if (m().is_or(f)) {
|
||||
num_lits = to_app(f)->get_num_args();
|
||||
lits = to_app(f)->get_args();
|
||||
}
|
||||
else {
|
||||
num_lits = 1;
|
||||
lits = &f;
|
||||
}
|
||||
for (unsigned j = 0; j < num_lits; j++) {
|
||||
expr * l = lits[j];
|
||||
if (m().is_not(l)) {
|
||||
out << "-";
|
||||
l = to_app(l)->get_arg(0);
|
||||
}
|
||||
unsigned id = UINT_MAX;
|
||||
expr2var.find(l, id);
|
||||
SASSERT(id != UINT_MAX);
|
||||
out << id << " ";
|
||||
}
|
||||
out << "0\n";
|
||||
}
|
||||
}
|
||||
|
||||
unsigned goal::num_exprs() const {
|
||||
expr_fast_mark1 visited;
|
||||
unsigned sz = size();
|
||||
unsigned r = 0;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
r += get_num_exprs(form(i), visited);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void goal::shrink(unsigned j) {
|
||||
SASSERT(j <= size());
|
||||
unsigned sz = size();
|
||||
for (unsigned i = j; i < sz; i++)
|
||||
m().pop_back(m_forms);
|
||||
if (proofs_enabled()) {
|
||||
for (unsigned i = j; i < sz; i++)
|
||||
m().pop_back(m_proofs);
|
||||
}
|
||||
if (unsat_core_enabled()) {
|
||||
for (unsigned i = j; i < sz; i++)
|
||||
m().pop_back(m_dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Eliminate true formulas.
|
||||
*/
|
||||
void goal::elim_true() {
|
||||
unsigned sz = size();
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * f = form(i);
|
||||
if (m().is_true(f))
|
||||
continue;
|
||||
if (i == j) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
m().set(m_forms, j, f);
|
||||
if (proofs_enabled())
|
||||
m().set(m_proofs, j, m().get(m_proofs, i));
|
||||
if (unsat_core_enabled())
|
||||
m().set(m_dependencies, j, m().get(m_dependencies, i));
|
||||
j++;
|
||||
}
|
||||
shrink(j);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the position of formula f in the goal.
|
||||
Return UINT_MAX if f is not in the goal
|
||||
*/
|
||||
unsigned goal::get_idx(expr * f) const {
|
||||
unsigned sz = size();
|
||||
for (unsigned j = 0; j < sz; j++) {
|
||||
if (form(j) == f)
|
||||
return j;
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the position of formula (not f) in the goal.
|
||||
Return UINT_MAX if (not f) is not in the goal
|
||||
*/
|
||||
unsigned goal::get_not_idx(expr * f) const {
|
||||
expr * atom;
|
||||
unsigned sz = size();
|
||||
for (unsigned j = 0; j < sz; j++) {
|
||||
if (m().is_not(form(j), atom) && atom == f)
|
||||
return j;
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
void goal::elim_redundancies() {
|
||||
if (inconsistent())
|
||||
return;
|
||||
expr_ref_fast_mark1 neg_lits(m());
|
||||
expr_ref_fast_mark2 pos_lits(m());
|
||||
unsigned sz = size();
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * f = form(i);
|
||||
if (m().is_true(f))
|
||||
continue;
|
||||
if (m().is_not(f)) {
|
||||
expr * atom = to_app(f)->get_arg(0);
|
||||
if (neg_lits.is_marked(atom))
|
||||
continue;
|
||||
if (pos_lits.is_marked(atom)) {
|
||||
proof * p = 0;
|
||||
if (proofs_enabled()) {
|
||||
proof * prs[2] = { pr(get_idx(atom)), pr(i) };
|
||||
p = m().mk_unit_resolution(2, prs);
|
||||
}
|
||||
expr_dependency_ref d(m());
|
||||
if (unsat_core_enabled())
|
||||
d = m().mk_join(dep(get_idx(atom)), dep(i));
|
||||
push_back(m().mk_false(), p, d);
|
||||
return;
|
||||
}
|
||||
neg_lits.mark(atom);
|
||||
}
|
||||
else {
|
||||
if (pos_lits.is_marked(f))
|
||||
continue;
|
||||
if (neg_lits.is_marked(f)) {
|
||||
proof * p = 0;
|
||||
if (proofs_enabled()) {
|
||||
proof * prs[2] = { pr(get_not_idx(f)), pr(i) };
|
||||
p = m().mk_unit_resolution(2, prs);
|
||||
}
|
||||
expr_dependency_ref d(m());
|
||||
if (unsat_core_enabled())
|
||||
d = m().mk_join(dep(get_not_idx(f)), dep(i));
|
||||
push_back(m().mk_false(), p, d);
|
||||
return;
|
||||
}
|
||||
pos_lits.mark(f);
|
||||
}
|
||||
if (i == j) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
m().set(m_forms, j, f);
|
||||
if (proofs_enabled())
|
||||
m().set(m_proofs, j, pr(i));
|
||||
if (unsat_core_enabled())
|
||||
m().set(m_dependencies, j, dep(i));
|
||||
j++;
|
||||
}
|
||||
shrink(j);
|
||||
}
|
||||
|
||||
bool goal::is_well_sorted() const {
|
||||
unsigned sz = size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * t = form(i);
|
||||
if (!::is_well_sorted(m(), t))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Assert expressions from ctx into t.
|
||||
*/
|
||||
void assert_exprs_from(cmd_context const & ctx, goal & t) {
|
||||
if (ctx.produce_proofs() && ctx.produce_unsat_cores())
|
||||
throw cmd_exception("Frontend does not support simultaneous generation of proofs and unsat cores");
|
||||
ast_manager & m = t.m();
|
||||
bool proofs_enabled = t.proofs_enabled();
|
||||
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
|
||||
ptr_vector<expr>::const_iterator end = ctx.end_assertions();
|
||||
for (; it != end; ++it) {
|
||||
t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : 0, 0);
|
||||
}
|
||||
if (ctx.produce_unsat_cores()) {
|
||||
SASSERT(!ctx.produce_proofs());
|
||||
it = ctx.begin_assumptions();
|
||||
end = ctx.end_assumptions();
|
||||
for (; it != end; ++it) {
|
||||
t.assert_expr(*it, 0, m.mk_leaf(*it));
|
||||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(ctx.begin_assumptions() == ctx.end_assumptions());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Translate the assertion set to a new one that uses a different ast_manager.
|
||||
*/
|
||||
goal * goal::translate(ast_translation & translator) const {
|
||||
expr_dependency_translation dep_translator(translator);
|
||||
|
||||
ast_manager & m_to = translator.to();
|
||||
goal * res = alloc(goal, m_to, m_to.proofs_enabled() && proofs_enabled(), models_enabled(), unsat_core_enabled());
|
||||
|
||||
unsigned sz = m().size(m_forms);
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
res->m().push_back(res->m_forms, translator(m().get(m_forms, i)));
|
||||
if (res->proofs_enabled())
|
||||
res->m().push_back(res->m_proofs, translator(m().get(m_proofs, i)));
|
||||
if (res->unsat_core_enabled())
|
||||
res->m().push_back(res->m_dependencies, dep_translator(m().get(m_dependencies, i)));
|
||||
}
|
||||
|
||||
res->m_inconsistent = m_inconsistent;
|
||||
res->m_depth = m_depth;
|
||||
res->m_precision = m_precision;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool is_equal(goal const & s1, goal const & s2) {
|
||||
if (s1.size() != s2.size())
|
||||
return false;
|
||||
unsigned num1 = 0; // num unique ASTs in s1
|
||||
unsigned num2 = 0; // num unique ASTs in s2
|
||||
expr_fast_mark1 visited1;
|
||||
expr_fast_mark2 visited2;
|
||||
unsigned sz = s1.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * f1 = s1.form(i);
|
||||
if (visited1.is_marked(f1))
|
||||
continue;
|
||||
num1++;
|
||||
visited1.mark(f1);
|
||||
}
|
||||
SASSERT(num1 <= sz);
|
||||
SASSERT(0 <= num1);
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * f2 = s2.form(i);
|
||||
if (visited2.is_marked(f2))
|
||||
continue;
|
||||
num2++;
|
||||
visited2.mark(f2);
|
||||
if (!visited1.is_marked(f2))
|
||||
return false;
|
||||
}
|
||||
SASSERT(num2 <= sz);
|
||||
SASSERT(0 <= num2);
|
||||
SASSERT(num1 >= num2);
|
||||
return num1 == num2;
|
||||
}
|
255
src/tactic/goal.h
Normal file
255
src/tactic/goal.h
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
goal.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A goal is essentially a set of formulas. Tactics are used to build
|
||||
proof and model finding procedures for these sets.
|
||||
|
||||
Remark: In a previous version of Z3, goals were called assertion_sets.
|
||||
Here is a summary of the main changes:
|
||||
- Goals track whether they are the result of applying over/under approximation steps.
|
||||
This prevent users from creating unsound strategies (e.g., user uses nia2sat, but does not check the sat_preserving flag).
|
||||
- Goals track dependencies (aka light proofs) for unsat core extraction, and building multi-tier solvers.
|
||||
This kind of dependency tracking is more powerful than the one used in the current Z3, since
|
||||
it does not prevent the use of preprocessing steps such as "Gaussian Elimination".
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-10-12
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _GOAL_H_
|
||||
#define _GOAL_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"ast_translation.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"ref.h"
|
||||
#include"ref_vector.h"
|
||||
#include"ref_buffer.h"
|
||||
|
||||
class cmd_context;
|
||||
|
||||
class goal {
|
||||
public:
|
||||
enum precision {
|
||||
PRECISE,
|
||||
UNDER, // goal is the product of an under-approximation
|
||||
OVER, // goal is the product of an over-approximation
|
||||
UNDER_OVER // goal is garbage: the produce of combined under and over approximation steps.
|
||||
};
|
||||
|
||||
static precision mk_union(precision p1, precision p2) {
|
||||
if (p1 == PRECISE) return p2;
|
||||
if (p2 == PRECISE) return p1;
|
||||
if (p1 != p2) return UNDER_OVER;
|
||||
return p1;
|
||||
}
|
||||
|
||||
protected:
|
||||
ast_manager & m_manager;
|
||||
unsigned m_ref_count;
|
||||
expr_array m_forms;
|
||||
expr_array m_proofs;
|
||||
expr_dependency_array m_dependencies;
|
||||
// attributes
|
||||
unsigned m_depth:26; // depth of the goal in the goal tree.
|
||||
unsigned m_models_enabled:1; // model generation is enabled.
|
||||
unsigned m_proofs_enabled:1; // proof production is enabled. m_manager.proofs_enabled() must be true if m_proofs_enabled == true
|
||||
unsigned m_core_enabled:1; // unsat core extraction is enabled.
|
||||
unsigned m_inconsistent:1; // true if the goal is known to be inconsistent.
|
||||
unsigned m_precision:2; // PRECISE, UNDER, OVER.
|
||||
|
||||
void push_back(expr * f, proof * pr, expr_dependency * d);
|
||||
void quick_process(bool save_first, expr * & f, expr_dependency * d);
|
||||
void process_and(bool save_first, app * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr);
|
||||
void process_not_or(bool save_first, app * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr);
|
||||
void slow_process(bool save_first, expr * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr);
|
||||
void slow_process(expr * f, proof * pr, expr_dependency * d);
|
||||
unsigned get_idx(expr * f) const;
|
||||
unsigned get_not_idx(expr * f) const;
|
||||
void shrink(unsigned j);
|
||||
void reset_core();
|
||||
|
||||
public:
|
||||
goal(ast_manager & m, bool models_enabled = true, bool core_enabled = false):
|
||||
m_manager(m),
|
||||
m_ref_count(0),
|
||||
m_depth(0),
|
||||
m_models_enabled(models_enabled),
|
||||
m_proofs_enabled(m.proofs_enabled()),
|
||||
m_core_enabled(core_enabled),
|
||||
m_inconsistent(false),
|
||||
m_precision(PRECISE) {
|
||||
}
|
||||
|
||||
goal(ast_manager & m, bool proofs_enabled, bool models_enabled, bool core_enabled):
|
||||
m_manager(m),
|
||||
m_ref_count(0),
|
||||
m_depth(0),
|
||||
m_models_enabled(models_enabled),
|
||||
m_proofs_enabled(proofs_enabled),
|
||||
m_core_enabled(core_enabled),
|
||||
m_inconsistent(false),
|
||||
m_precision(PRECISE) {
|
||||
SASSERT(!proofs_enabled || m.proofs_enabled());
|
||||
}
|
||||
|
||||
goal(goal const & src):
|
||||
m_manager(src.m()),
|
||||
m_ref_count(0),
|
||||
m_depth(0),
|
||||
m_models_enabled(src.models_enabled()),
|
||||
m_proofs_enabled(src.proofs_enabled()),
|
||||
m_core_enabled(src.unsat_core_enabled()),
|
||||
m_inconsistent(false),
|
||||
m_precision(PRECISE) {
|
||||
copy_from(src);
|
||||
}
|
||||
|
||||
// Copy configuration: depth, models/proofs/cores flags, and precision from src.
|
||||
// The assertions are not copied
|
||||
goal(goal const & src, bool):
|
||||
m_manager(src.m()),
|
||||
m_ref_count(0),
|
||||
m_depth(src.m_depth),
|
||||
m_models_enabled(src.models_enabled()),
|
||||
m_proofs_enabled(src.proofs_enabled()),
|
||||
m_core_enabled(src.unsat_core_enabled()),
|
||||
m_inconsistent(false),
|
||||
m_precision(src.m_precision) {
|
||||
}
|
||||
|
||||
~goal() { reset_core(); }
|
||||
|
||||
void inc_ref() { ++m_ref_count; }
|
||||
void dec_ref() { --m_ref_count; if (m_ref_count == 0) dealloc(this); }
|
||||
|
||||
ast_manager & m() const { return m_manager; }
|
||||
|
||||
unsigned depth() const { return m_depth; }
|
||||
bool models_enabled() const { return m_models_enabled; }
|
||||
bool proofs_enabled() const { return m_proofs_enabled; }
|
||||
bool unsat_core_enabled() const { return m_core_enabled; }
|
||||
bool inconsistent() const { return m_inconsistent; }
|
||||
precision prec() const { return static_cast<precision>(m_precision); }
|
||||
|
||||
void set_depth(unsigned d) { m_depth = d; }
|
||||
void inc_depth() { m_depth++; }
|
||||
void set_prec(precision d) { m_precision = d; }
|
||||
void updt_prec(precision d) { m_precision = mk_union(prec(), d); }
|
||||
|
||||
void reset_all(); // reset goal and precision and depth attributes.
|
||||
void reset(); // reset goal but preserve precision and depth attributes.
|
||||
|
||||
void copy_to(goal & target) const;
|
||||
void copy_from(goal const & src) { src.copy_to(*this); }
|
||||
|
||||
void assert_expr(expr * f, proof * pr, expr_dependency * d);
|
||||
void assert_expr(expr * f) {
|
||||
assert_expr(f, proofs_enabled() ? m().mk_asserted(f) : 0, 0);
|
||||
}
|
||||
|
||||
unsigned size() const { return m().size(m_forms); }
|
||||
|
||||
unsigned num_exprs() const;
|
||||
|
||||
expr * form(unsigned i) const { return m().get(m_forms, i); }
|
||||
proof * pr(unsigned i) const { return proofs_enabled() ? static_cast<proof*>(m().get(m_proofs, i)) : 0; }
|
||||
expr_dependency * dep(unsigned i) const { return unsat_core_enabled() ? m().get(m_dependencies, i) : 0; }
|
||||
|
||||
void update(unsigned i, expr * f, proof * pr = 0, expr_dependency * dep = 0);
|
||||
|
||||
void get_formulas(ptr_vector<expr> & result);
|
||||
|
||||
void elim_true();
|
||||
void elim_redundancies();
|
||||
|
||||
void display(cmd_context & ctx, std::ostream & out) const;
|
||||
void display(cmd_context & ctx) const;
|
||||
void display(std::ostream & out) const;
|
||||
void display_ll(std::ostream & out) const;
|
||||
void display_as_and(std::ostream & out) const;
|
||||
void display_dimacs(std::ostream & out) const;
|
||||
void display_with_dependencies(cmd_context & ctx, std::ostream & out) const;
|
||||
void display_with_dependencies(cmd_context & ctx) const;
|
||||
void display_with_dependencies(std::ostream & out) const;
|
||||
|
||||
bool sat_preserved() const {
|
||||
return prec() == PRECISE || prec() == UNDER;
|
||||
}
|
||||
|
||||
bool unsat_preserved() const {
|
||||
return prec() == PRECISE || prec() == OVER;
|
||||
}
|
||||
|
||||
bool is_decided_sat() const {
|
||||
return size() == 0 && sat_preserved();
|
||||
}
|
||||
|
||||
bool is_decided_unsat() const {
|
||||
return inconsistent() && unsat_preserved();
|
||||
}
|
||||
|
||||
bool is_decided() const {
|
||||
return is_decided_sat() || is_decided_unsat();
|
||||
}
|
||||
|
||||
bool is_well_sorted() const;
|
||||
|
||||
goal * translate(ast_translation & translator) const;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, goal::precision p);
|
||||
|
||||
typedef ref<goal> goal_ref;
|
||||
typedef sref_vector<goal> goal_ref_vector;
|
||||
typedef sref_buffer<goal> goal_ref_buffer;
|
||||
|
||||
template<typename GoalCollection>
|
||||
inline bool is_decided(GoalCollection const & c) { return c.size() == 1 && c[0]->is_decided(); }
|
||||
template<typename GoalCollection>
|
||||
inline bool is_decided_sat(GoalCollection const & c) { return c.size() == 1 && c[0]->is_decided_sat(); }
|
||||
template<typename GoalCollection>
|
||||
inline bool is_decided_unsat(GoalCollection const & c) { return c.size() == 1 && c[0]->is_decided_unsat(); }
|
||||
|
||||
void assert_exprs_from(cmd_context const & ctx, goal & t);
|
||||
|
||||
template<typename ForEachProc>
|
||||
void for_each_expr_at(ForEachProc& proc, goal const & s) {
|
||||
expr_mark visited;
|
||||
for (unsigned i = 0; i < s.size(); ++i) {
|
||||
for_each_expr(proc, visited, s.form(i));
|
||||
}
|
||||
}
|
||||
|
||||
bool is_equal(goal const & g1, goal const & g2);
|
||||
|
||||
template<typename Predicate>
|
||||
bool test(goal const & g, Predicate & proc) {
|
||||
expr_fast_mark1 visited;
|
||||
try {
|
||||
unsigned sz = g.size();
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
quick_for_each_expr(proc, visited, g.form(i));
|
||||
}
|
||||
catch (typename Predicate::found) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Predicate>
|
||||
bool test(goal const & g) {
|
||||
Predicate proc(g.m());
|
||||
return test(g, proc);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue