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

checkpoint

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2012-11-30 18:16:02 -08:00
parent 3e6bddbad1
commit 6195ed7c66
17 changed files with 120 additions and 326 deletions

View file

@ -17,6 +17,7 @@ Revision History:
--*/
#include"cnf.h"
#include"cnf_params.hpp"
#include"var_subst.h"
#include"ast_util.h"
#include"ast_pp.h"
@ -159,7 +160,7 @@ inline bool cnf::is_too_expensive(approx_nat approx_result_size, ptr_buffer<expr
// (OR A (AND B C)) is always considered cheap.
if (args.size() == 2 && (!m_manager.is_and(args[0]) || !m_manager.is_and(args[1])))
return false;
return !(approx_result_size < m_params.m_cnf_factor);
return !(approx_result_size < m_cnf_factor);
}
/**
@ -265,13 +266,13 @@ void cnf::reduce1_or(app * n, bool in_q) {
get_args(n, in_q, new_args, new_arg_prs);
expr * r;
proof * pr = 0;
if (in_q || m_params.m_cnf_mode == CNF_OPPORTUNISTIC || m_params.m_cnf_mode == CNF_FULL) {
if (in_q || m_cnf_mode == CNF_OPPORTUNISTIC || m_cnf_mode == CNF_FULL) {
ptr_buffer<expr> f_args;
flat_args(n->get_decl(), new_args, f_args);
TRACE("cnf_or", for (unsigned i = 0; i < f_args.size(); i++) tout << mk_pp(f_args[i], m_manager) << "\n";);
approx_nat result_size = approx_result_size_for_disj(f_args);
TRACE("cnf_or", tout << mk_pp(n, m_manager) << "\napprox. result: " << result_size << "\n";);
if (m_params.m_cnf_mode != CNF_OPPORTUNISTIC || result_size < m_params.m_cnf_factor) {
if (m_cnf_mode != CNF_OPPORTUNISTIC || result_size < m_cnf_factor) {
expr_ref_buffer cheap_args(m_manager);
proof_ref_buffer cheap_args_pr(m_manager);
if (is_too_expensive(result_size, f_args)) {
@ -354,7 +355,7 @@ void cnf::reduce1_and(app * n, bool in_q) {
get_args(n, in_q, new_args, new_arg_prs);
app * r;
proof * pr = 0;
if (in_q || m_params.m_cnf_mode == CNF_OPPORTUNISTIC || m_params.m_cnf_mode == CNF_FULL) {
if (in_q || m_cnf_mode == CNF_OPPORTUNISTIC || m_cnf_mode == CNF_FULL) {
ptr_buffer<expr> f_args;
flat_args(n->get_decl(), new_args, f_args);
r = m_manager.mk_and(f_args.size(), f_args.c_ptr());
@ -379,7 +380,7 @@ void cnf::reduce1_label(app * n, bool in_q) {
expr * new_arg;
proof * new_arg_pr;
get_cached(n->get_arg(0), true, new_arg, new_arg_pr);
if (in_q || m_params.m_cnf_mode == CNF_FULL) {
if (in_q || m_cnf_mode == CNF_FULL) {
// TODO: in the current implementation, labels are removed during CNF translation.
// This is satisfactory for Boogie, since it does not use labels inside quantifiers,
// and we only need CNF_QUANT for Superposition Calculus.
@ -439,8 +440,7 @@ void cnf::reduce1_quantifier(quantifier * q, bool in_q) {
TRACE("cnf_quant", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";);
}
cnf::cnf(ast_manager & m, defined_names & n, cnf_params & params):
m_params(params),
cnf::cnf(ast_manager & m, defined_names & n, params_ref const & params):
m_manager(m),
m_defined_names(n),
m_pull(m),
@ -448,6 +448,9 @@ cnf::cnf(ast_manager & m, defined_names & n, cnf_params & params):
m_todo_defs(m),
m_todo_proofs(m),
m_coarse_proofs(m) {
cnf_params p(params);
m_cnf_mode = static_cast<cnf_mode>(p.mode());
m_cnf_factor = p.factor();
}
cnf::~cnf() {
@ -488,7 +491,7 @@ void cnf::reduce(expr * n, expr_ref & r, proof_ref & pr) {
}
void cnf::operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & pr) {
if (m_params.m_cnf_mode == CNF_DISABLED) {
if (m_cnf_mode == CNF_DISABLED) {
r = n;
pr = m_manager.mk_reflexivity(n);
return;

View file

@ -19,11 +19,29 @@ Revision History:
#ifndef _CNF_H_
#define _CNF_H_
#include"cnf_params.h"
#include"pull_quant.h"
#include"nnf.h"
#include"approx_nat.h"
/**
\brief CNF translation mode. The cheapest mode is CNF_QUANT, and
the most expensive is CNF_FULL.
*/
enum cnf_mode {
CNF_DISABLED, /* CNF translator is disabled.
This mode is sufficient when using E-matching.
*/
CNF_QUANT, /* A subformula is put into CNF if it is inside of a
quantifier.
This mode is sufficient when using Superposition
Calculus.
*/
CNF_OPPORTUNISTIC, /* a subformula is also put in CNF if it is cheap. */
CNF_FULL /* Everything is put into CNF, new names are introduced
if it is too expensive. */
};
/**
\brief Entry into the todo list of the CNF translator. It is also used as the key in the CNF cache.
*/
@ -71,7 +89,6 @@ public:
*/
class cnf {
typedef std::pair<expr *, bool> expr_bool_pair;
cnf_params & m_params;
ast_manager & m_manager;
defined_names & m_defined_names;
pull_quant m_pull;
@ -83,6 +100,9 @@ class cnf {
ptr_vector<proof> m_result_def_proofs;
proof_ref_vector m_coarse_proofs;
cnf_mode m_cnf_mode;
unsigned m_cnf_factor;
void cache_result(expr * e, bool in_q, expr * r, proof * pr);
void get_cached(expr * n, bool in_q, expr * & r, proof * & pr) const { m_cache.get(cnf_entry(n, true, in_q), r, pr); }
bool is_cached(expr * n, bool in_q) const { return m_cache.contains(cnf_entry(n, true, in_q)); }
@ -105,7 +125,7 @@ class cnf {
void reduce(expr * n, expr_ref & r, proof_ref & pr);
public:
cnf(ast_manager & m, defined_names & n, cnf_params & params);
cnf(ast_manager & m, defined_names & n, params_ref const & p = params_ref());
~cnf();
void operator()(expr * n, // [IN] expression that should be put into CNF
expr_ref_vector & new_defs, // [OUT] new definitions

View file

@ -0,0 +1,4 @@
def_module_params('cnf',
export=True,
params=(('mode', UINT, 0, 'CNF translation mode: 0 - disabled, 1 - quantifiers in CNF, 2 - opportunistic, 3 - full'),
('factor', UINT, 4, 'the maximum number of clauses that can be created when converting a subformula')))

View file

@ -18,6 +18,7 @@ Notes:
--*/
#include"nnf.h"
#include"nnf_params.hpp"
#include"warning.h"
#include"used_vars.h"
#include"well_sorted.h"
@ -29,6 +30,40 @@ Notes:
#include"ast_smt2_pp.h"
/**
\brief NNF translation mode. The cheapest mode is NNF_SKOLEM, and
the most expensive is NNF_FULL.
*/
enum nnf_mode {
NNF_SKOLEM, /* A subformula is put into NNF only if it contains
quantifiers or labels. The result of the
transformation will be in skolem normal form.
If a formula is too expensive to be put into NNF,
then nested quantifiers and labels are renamed.
This mode is sufficient when using E-matching.
*/
NNF_QUANT, /* A subformula is put into NNF if it contains
quantifiers, labels, or is in the scope of a
quantifier. The result of the transformation will be
in skolem normal form, and the body of quantifiers
will be in NNF. If a ground formula is too expensive to
be put into NNF, then nested quantifiers and labels
are renamed.
This mode is sufficient when using Superposition
Calculus.
Remark: If the problem does not contain quantifiers,
then NNF_QUANT is identical to NNF_SKOLEM.
*/
NNF_OPPORTUNISTIC, /* Similar to NNF_QUANT, but a subformula is
also put into NNF, if it is
cheap. Otherwise, the nested quantifiers and
labels are renamed. */
NNF_FULL /* Everything is put into NNF. */
};
class skolemizer {
typedef act_cache cache;
@ -113,20 +148,16 @@ class skolemizer {
}
public:
skolemizer(ast_manager & m, params_ref const & p):
skolemizer(ast_manager & m):
m_manager(m),
m_sk_hack("sk_hack"),
m_sk_hack_enabled(false),
m_cache(m),
m_cache_pr(m) {
updt_params(p);
}
void updt_params(params_ref const & p) {
m_sk_hack_enabled = p.get_bool("sk_hack", false);
}
static void get_param_descrs(param_descrs & r) {
r.insert("sk_hack", CPK_BOOL, "(default: false) hack for VCC");
void set_sk_hack(bool f) {
m_sk_hack_enabled = f;
}
ast_manager & m() const { return m_manager; }
@ -220,8 +251,6 @@ struct nnf::imp {
name_exprs * m_name_nested_formulas;
name_exprs * m_name_quant;
symbol m_skolem;
volatile bool m_cancel;
unsigned long long m_max_memory; // in bytes
@ -231,10 +260,9 @@ struct nnf::imp {
m_todo_defs(m),
m_todo_proofs(m),
m_result_pr_stack(m),
m_skolemizer(m, p),
m_skolem("skolem"),
m_skolemizer(m),
m_cancel(false) {
updt_local_params(p);
updt_params(p);
for (unsigned i = 0; i < 4; i++) {
m_cache[i] = alloc(act_cache, m);
if (m.proofs_enabled())
@ -258,14 +286,10 @@ struct nnf::imp {
del_name_exprs(m_name_quant);
}
void updt_params(params_ref const & p) {
updt_local_params(p);
m_skolemizer.updt_params(p);
}
void updt_local_params(params_ref const & p) {
symbol mode_sym = p.get_sym("mode", m_skolem);
if (mode_sym == m_skolem)
void updt_params(params_ref const & _p) {
nnf_params p(_p);
symbol mode_sym = p.mode();
if (mode_sym == "skolem")
m_mode = NNF_SKOLEM;
else if (mode_sym == "full")
m_mode = NNF_FULL;
@ -273,23 +297,17 @@ struct nnf::imp {
m_mode = NNF_QUANT;
else
throw nnf_params_exception("invalid NNF mode");
TRACE("nnf", tout << "nnf-mode: " << m_mode << " " << mode_sym << "\n" << _p << "\n";);
TRACE("nnf", tout << "nnf-mode: " << m_mode << " " << mode_sym << "\n" << p << "\n";);
m_ignore_labels = p.get_bool("ignore_labels", false);
m_skolemize = p.get_bool("skolemize", true);
m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
m_ignore_labels = p.ignore_labels();
m_skolemize = p.skolemize();
m_max_memory = megabytes_to_bytes(p.max_memory());
m_skolemizer.set_sk_hack(p.sk_hack());
}
static void get_param_descrs(param_descrs & r) {
insert_max_memory(r);
r.insert("mode", CPK_SYMBOL,
"(default: skolem) NNF translation mode: skolem (skolem normal form), quantifiers (skolem normal form + quantifiers in NNF), full");
r.insert("ignore_labels", CPK_BOOL,
"(default: false) remove/ignore labels in the input formula, this option is ignored if proofs are enabled");
r.insert("skolemize", CPK_BOOL,
"(default: true) skolemize (existential force) quantifiers");
skolemizer::get_param_descrs(r);
nnf_params::collect_param_descrs(r);
}
void reset() {
@ -881,21 +899,6 @@ nnf::nnf(ast_manager & m, defined_names & n, params_ref const & p) {
m_imp = alloc(imp, m, n, p);
}
nnf::nnf(ast_manager & m, defined_names & n, nnf_params & np) {
params_ref p;
if (np.m_nnf_mode == NNF_FULL)
p.set_sym("mode", symbol("full"));
else if (np.m_nnf_mode == NNF_QUANT)
p.set_sym("mode", symbol("quantifiers"));
if (np.m_nnf_ignore_labels)
p.set_bool("ignore_labels", true);
if (np.m_nnf_sk_hack)
p.set_bool("sk_hack", true);
m_imp = alloc(imp, m, n, p);
}
nnf::~nnf() {
dealloc(m_imp);
}

View file

@ -21,7 +21,6 @@ Notes:
#define _NNF_H_
#include"ast.h"
#include"nnf_params.h"
#include"params.h"
#include"defined_names.h"
@ -30,7 +29,6 @@ class nnf {
imp * m_imp;
public:
nnf(ast_manager & m, defined_names & n, params_ref const & p = params_ref());
nnf(ast_manager & m, defined_names & n, nnf_params & params); // for backward compatibility
~nnf();
void operator()(expr * n, // [IN] expression that should be put into NNF

View file

@ -0,0 +1,8 @@
def_module_params('nnf',
export=True,
params=(max_memory_param(),
('sk_hack', BOOL, False, 'hack for VCC'),
('mode', SYMBOL, 'skolem',
'NNF translation mode: skolem (skolem normal form), quantifiers (skolem normal form + quantifiers in NNF), full'),
('ignore_labels', BOOL, False, 'remove/ignore labels in the input formula, this option is ignored if proofs are enabled'),
('skolemize', BOOL, True, 'skolemize (existential force) quantifiers')))