mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
checkpoint
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
f6c89ba1d3
commit
6fd63cd05a
69 changed files with 9 additions and 1 deletions
|
@ -1,366 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bv_size_reduction_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Reduce the number of bits used to encode constants, by using signed bounds.
|
||||
Example: suppose x is a bit-vector of size 8, and we have
|
||||
signed bounds for x such that:
|
||||
-2 <= x <= 2
|
||||
Then, x can be replaced by ((sign-extend 5) k)
|
||||
where k is a fresh bit-vector constant of size 3.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-19
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"expr_replacer.h"
|
||||
#include"extension_model_converter.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
|
||||
class bv_size_reduction_tactic : public tactic {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
public:
|
||||
bv_size_reduction_tactic(ast_manager & m);
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(bv_size_reduction_tactic, m);
|
||||
}
|
||||
|
||||
virtual ~bv_size_reduction_tactic();
|
||||
|
||||
virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core);
|
||||
|
||||
virtual void cleanup();
|
||||
virtual void set_cancel(bool f);
|
||||
};
|
||||
|
||||
tactic * mk_bv_size_reduction_tactic(ast_manager & m, params_ref const & p) {
|
||||
return clean(alloc(bv_size_reduction_tactic, m));
|
||||
}
|
||||
|
||||
struct bv_size_reduction_tactic::imp {
|
||||
typedef rational numeral;
|
||||
typedef extension_model_converter bv_size_reduction_mc;
|
||||
|
||||
ast_manager & m;
|
||||
bv_util m_util;
|
||||
obj_map<app, numeral> m_signed_lowers;
|
||||
obj_map<app, numeral> m_signed_uppers;
|
||||
obj_map<app, numeral> m_unsigned_lowers;
|
||||
obj_map<app, numeral> m_unsigned_uppers;
|
||||
ref<bv_size_reduction_mc> m_mc;
|
||||
scoped_ptr<expr_replacer> m_replacer;
|
||||
bool m_produce_models;
|
||||
volatile bool m_cancel;
|
||||
|
||||
imp(ast_manager & _m):
|
||||
m(_m),
|
||||
m_util(m),
|
||||
m_replacer(mk_default_expr_replacer(m)),
|
||||
m_cancel(false) {
|
||||
}
|
||||
|
||||
void update_signed_lower(app * v, numeral const & k) {
|
||||
// k <= v
|
||||
obj_map<app, numeral>::obj_map_entry * entry = m_signed_lowers.insert_if_not_there2(v, k);
|
||||
if (entry->get_data().m_value < k) {
|
||||
// improve bound
|
||||
entry->get_data().m_value = k;
|
||||
}
|
||||
}
|
||||
|
||||
void update_signed_upper(app * v, numeral const & k) {
|
||||
// v <= k
|
||||
obj_map<app, numeral>::obj_map_entry * entry = m_signed_uppers.insert_if_not_there2(v, k);
|
||||
if (k < entry->get_data().m_value) {
|
||||
// improve bound
|
||||
entry->get_data().m_value = k;
|
||||
}
|
||||
}
|
||||
|
||||
void update_unsigned_lower(app * v, numeral const & k) {
|
||||
SASSERT(k > numeral(0));
|
||||
// k <= v
|
||||
obj_map<app, numeral>::obj_map_entry * entry = m_unsigned_lowers.insert_if_not_there2(v, k);
|
||||
if (entry->get_data().m_value < k) {
|
||||
// improve bound
|
||||
entry->get_data().m_value = k;
|
||||
}
|
||||
}
|
||||
|
||||
void update_unsigned_upper(app * v, numeral const & k) {
|
||||
SASSERT(k > numeral(0));
|
||||
// v <= k
|
||||
obj_map<app, numeral>::obj_map_entry * entry = m_unsigned_uppers.insert_if_not_there2(v, k);
|
||||
if (k < entry->get_data().m_value) {
|
||||
// improve bound
|
||||
entry->get_data().m_value = k;
|
||||
}
|
||||
}
|
||||
|
||||
void collect_bounds(goal const & g) {
|
||||
unsigned sz = g.size();
|
||||
numeral val;
|
||||
unsigned bv_sz;
|
||||
expr * f, * lhs, * rhs;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
bool negated = false;
|
||||
f = g.form(i);
|
||||
if (m.is_not(f)) {
|
||||
negated = true;
|
||||
f = to_app(f)->get_arg(0);
|
||||
}
|
||||
|
||||
if (m_util.is_bv_sle(f, lhs, rhs)) {
|
||||
if (is_uninterp_const(lhs) && m_util.is_numeral(rhs, val, bv_sz)) {
|
||||
TRACE("bv_size_reduction", tout << (negated?"not ":"") << mk_ismt2_pp(f, m) << std::endl; );
|
||||
// v <= k
|
||||
if (negated) update_signed_lower(to_app(lhs), val+numeral(1));
|
||||
else update_signed_upper(to_app(lhs), val);
|
||||
}
|
||||
else if (is_uninterp_const(rhs) && m_util.is_numeral(lhs, val, bv_sz)) {
|
||||
TRACE("bv_size_reduction", tout << (negated?"not ":"") << mk_ismt2_pp(f, m) << std::endl; );
|
||||
// k <= v
|
||||
if (negated) update_signed_upper(to_app(rhs), val-numeral(1));
|
||||
else update_signed_lower(to_app(rhs), val);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
else if (m_util.is_bv_ule(f, lhs, rhs)) {
|
||||
if (is_uninterp_const(lhs) && m_util.is_numeral(rhs, val, bv_sz)) {
|
||||
TRACE("bv_size_reduction", tout << (negated?"not ":"") << mk_ismt2_pp(f, m) << std::endl; );
|
||||
// v <= k
|
||||
if (negated) update_unsigned_lower(to_app(lhs), val+numeral(1));
|
||||
else update_unsigned_upper(to_app(lhs), val);
|
||||
}
|
||||
else if (is_uninterp_const(rhs) && m_util.is_numeral(lhs, val, bv_sz)) {
|
||||
TRACE("bv_size_reduction", tout << (negated?"not ":"") << mk_ismt2_pp(f, m) << std::endl; );
|
||||
// k <= v
|
||||
if (negated) update_unsigned_upper(to_app(rhs), val-numeral(1));
|
||||
else update_unsigned_lower(to_app(rhs), val);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void checkpoint() {
|
||||
if (m_cancel)
|
||||
throw tactic_exception(TACTIC_CANCELED_MSG);
|
||||
}
|
||||
|
||||
void operator()(goal & g, model_converter_ref & mc) {
|
||||
if (g.inconsistent())
|
||||
return;
|
||||
TRACE("before_bv_size_reduction", g.display(tout););
|
||||
m_produce_models = g.models_enabled();
|
||||
mc = 0;
|
||||
m_mc = 0;
|
||||
unsigned num_reduced = 0;
|
||||
{
|
||||
tactic_report report("bv-size-reduction", g);
|
||||
collect_bounds(g);
|
||||
|
||||
// create substitution
|
||||
expr_substitution subst(m);
|
||||
|
||||
if (!(m_signed_lowers.empty() || m_signed_uppers.empty())) {
|
||||
TRACE("bv_size_reduction",
|
||||
tout << "m_signed_lowers: " << std::endl;
|
||||
for (obj_map<app, numeral>::iterator it = m_signed_lowers.begin(); it != m_signed_lowers.end(); it++)
|
||||
tout << mk_ismt2_pp(it->m_key, m) << " >= " << it->m_value.to_string() << std::endl;
|
||||
tout << "m_signed_uppers: " << std::endl;
|
||||
for (obj_map<app, numeral>::iterator it = m_signed_uppers.begin(); it != m_signed_uppers.end(); it++)
|
||||
tout << mk_ismt2_pp(it->m_key, m) << " <= " << it->m_value.to_string() << std::endl;
|
||||
);
|
||||
|
||||
obj_map<app, numeral>::iterator it = m_signed_lowers.begin();
|
||||
obj_map<app, numeral>::iterator end = m_signed_lowers.end();
|
||||
for (; it != end; ++it) {
|
||||
app * v = it->m_key;
|
||||
unsigned bv_sz = m_util.get_bv_size(v);
|
||||
numeral l = m_util.norm(it->m_value, bv_sz, true);
|
||||
obj_map<app, numeral>::obj_map_entry * entry = m_signed_uppers.find_core(v);
|
||||
if (entry != 0) {
|
||||
numeral u = m_util.norm(entry->get_data().m_value, bv_sz, true);
|
||||
TRACE("bv_size_reduction", tout << l << " <= " << v->get_decl()->get_name() << " <= " << u << "\n";);
|
||||
expr * new_def = 0;
|
||||
if (l > u) {
|
||||
g.assert_expr(m.mk_false());
|
||||
return;
|
||||
}
|
||||
else if (l == u) {
|
||||
new_def = m_util.mk_numeral(l, m.get_sort(v));
|
||||
}
|
||||
else {
|
||||
// l < u
|
||||
if (l.is_neg()) {
|
||||
unsigned i_nb = (u - l).get_num_bits();
|
||||
unsigned v_nb = m_util.get_bv_size(v);
|
||||
if (i_nb < v_nb)
|
||||
new_def = m_util.mk_sign_extend(v_nb - i_nb, m.mk_fresh_const(0, m_util.mk_sort(i_nb)));
|
||||
}
|
||||
else {
|
||||
// 0 <= l <= v <= u
|
||||
unsigned u_nb = u.get_num_bits();
|
||||
unsigned v_nb = m_util.get_bv_size(v);
|
||||
if (u_nb < v_nb)
|
||||
new_def = m_util.mk_concat(m_util.mk_numeral(numeral(0), v_nb - u_nb), m.mk_fresh_const(0, m_util.mk_sort(u_nb)));
|
||||
}
|
||||
}
|
||||
|
||||
if (new_def) {
|
||||
subst.insert(v, new_def);
|
||||
if (m_produce_models) {
|
||||
if (!m_mc)
|
||||
m_mc = alloc(bv_size_reduction_mc, m);
|
||||
m_mc->insert(v->get_decl(), new_def);
|
||||
}
|
||||
num_reduced++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!(m_unsigned_lowers.empty() && m_unsigned_uppers.empty())) {
|
||||
TRACE("bv_size_reduction",
|
||||
tout << "m_unsigned_lowers: " << std::endl;
|
||||
for (obj_map<app, numeral>::iterator it = m_unsigned_lowers.begin(); it != m_unsigned_lowers.end(); it++)
|
||||
tout << mk_ismt2_pp(it->m_key, m) << " >= " << it->m_value.to_string() << std::endl;
|
||||
tout << "m_unsigned_uppers: " << std::endl;
|
||||
for (obj_map<app, numeral>::iterator it = m_unsigned_uppers.begin(); it != m_unsigned_uppers.end(); it++)
|
||||
tout << mk_ismt2_pp(it->m_key, m) << " <= " << it->m_value.to_string() << std::endl;
|
||||
);
|
||||
|
||||
obj_map<app, numeral>::iterator it = m_unsigned_uppers.begin();
|
||||
obj_map<app, numeral>::iterator end = m_unsigned_uppers.end();
|
||||
for (; it != end; ++it) {
|
||||
app * v = it->m_key;
|
||||
unsigned bv_sz = m_util.get_bv_size(v);
|
||||
numeral u = m_util.norm(it->m_value, bv_sz, false);
|
||||
obj_map<app, numeral>::obj_map_entry * entry = m_signed_lowers.find_core(v);
|
||||
numeral l = (entry != 0) ? m_util.norm(entry->get_data().m_value, bv_sz, false) : numeral(0);
|
||||
|
||||
obj_map<app, numeral>::obj_map_entry * lse = m_signed_lowers.find_core(v);
|
||||
obj_map<app, numeral>::obj_map_entry * use = m_signed_uppers.find_core(v);
|
||||
if ((lse != 0 && lse->get_data().m_value > l) &&
|
||||
(use != 0 && use->get_data().m_value < u))
|
||||
continue; // Skip, we had better signed bounds.
|
||||
|
||||
if (lse != 0 && lse->get_data().m_value > l) l = lse->get_data().m_value;
|
||||
if (use != 0 && use->get_data().m_value < u) u = use->get_data().m_value;
|
||||
|
||||
TRACE("bv_size_reduction", tout << l << " <= " << v->get_decl()->get_name() << " <= " << u << "\n";);
|
||||
expr * new_def = 0;
|
||||
if (l > u) {
|
||||
g.assert_expr(m.mk_false());
|
||||
return;
|
||||
}
|
||||
else if (l == u) {
|
||||
new_def = m_util.mk_numeral(l, m.get_sort(v));
|
||||
}
|
||||
else {
|
||||
// 0 <= l <= v <= u
|
||||
unsigned u_nb = u.get_num_bits();
|
||||
unsigned v_nb = m_util.get_bv_size(v);
|
||||
if (u_nb < v_nb)
|
||||
new_def = m_util.mk_concat(m_util.mk_numeral(numeral(0), v_nb - u_nb), m.mk_fresh_const(0, m_util.mk_sort(u_nb)));
|
||||
}
|
||||
|
||||
if (new_def) {
|
||||
subst.insert(v, new_def);
|
||||
if (m_produce_models) {
|
||||
if (!m_mc)
|
||||
m_mc = alloc(bv_size_reduction_mc, m);
|
||||
m_mc->insert(v->get_decl(), new_def);
|
||||
}
|
||||
num_reduced++;
|
||||
TRACE("bv_size_reduction", tout << "New definition = " << mk_ismt2_pp(new_def, m) << "\n";);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (subst.empty())
|
||||
return;
|
||||
|
||||
m_replacer->set_substitution(&subst);
|
||||
|
||||
unsigned sz = g.size();
|
||||
expr * f;
|
||||
expr_ref new_f(m);
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (g.inconsistent())
|
||||
return;
|
||||
f = g.form(i);
|
||||
(*m_replacer)(f, new_f);
|
||||
g.update(i, new_f);
|
||||
}
|
||||
mc = m_mc.get();
|
||||
m_mc = 0;
|
||||
}
|
||||
report_tactic_progress(":bv-reduced", num_reduced);
|
||||
TRACE("after_bv_size_reduction", g.display(tout); if (m_mc) m_mc->display(tout););
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_replacer->set_cancel(f);
|
||||
m_cancel = f;
|
||||
}
|
||||
};
|
||||
|
||||
bv_size_reduction_tactic::bv_size_reduction_tactic(ast_manager & m) {
|
||||
m_imp = alloc(imp, m);
|
||||
}
|
||||
|
||||
bv_size_reduction_tactic::~bv_size_reduction_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
void bv_size_reduction_tactic::operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
fail_if_proof_generation("bv-size-reduction", g);
|
||||
fail_if_unsat_core_generation("bv-size-reduction", g);
|
||||
mc = 0; pc = 0; core = 0; result.reset();
|
||||
m_imp->operator()(*(g.get()), mc);
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
|
||||
void bv_size_reduction_tactic::set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
|
||||
void bv_size_reduction_tactic::cleanup() {
|
||||
ast_manager & m = m_imp->m;
|
||||
imp * d = m_imp;
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = 0;
|
||||
}
|
||||
dealloc(d);
|
||||
d = alloc(imp, m);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = d;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bv_size_reduction.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Reduce the number of bits used to encode constants, by using signed bounds.
|
||||
Example: suppose x is a bit-vector of size 8, and we have
|
||||
signed bounds for x such that:
|
||||
-2 <= x <= 2
|
||||
Then, x can be replaced by ((sign-extend 5) k)
|
||||
where k is a fresh bit-vector constant of size 3.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-19
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _BV_SIZE_REDUCTION_TACTIC_H_
|
||||
#define _BV_SIZE_REDUCTION_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_bv_size_reduction_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,27 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
contains_var.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2007-06-12.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _CONTAINS_VAR_H_
|
||||
#define _CONTAINS_VAR_H_
|
||||
|
||||
class ast;
|
||||
|
||||
bool contains_var(ast * n);
|
||||
|
||||
#endif /* _CONTAINS_VAR_H_ */
|
||||
|
132
lib/dimacs.cpp
132
lib/dimacs.cpp
|
@ -1,132 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dimacs.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Dimacs CNF parser
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-07-26.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"dimacs.h"
|
||||
#undef max
|
||||
#undef min
|
||||
#include"sat_solver.h"
|
||||
|
||||
class stream_buffer {
|
||||
std::istream & m_stream;
|
||||
int m_val;
|
||||
public:
|
||||
|
||||
stream_buffer(std::istream & s):
|
||||
m_stream(s) {
|
||||
m_val = m_stream.get();
|
||||
}
|
||||
|
||||
int operator *() const {
|
||||
return m_val;
|
||||
}
|
||||
|
||||
void operator ++() {
|
||||
m_val = m_stream.get();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Buffer>
|
||||
void skip_whitespace(Buffer & in) {
|
||||
while ((*in >= 9 && *in <= 13) || *in == 32) {
|
||||
++in;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Buffer>
|
||||
void skip_line(Buffer & in) {
|
||||
while(true) {
|
||||
if (*in == EOF) {
|
||||
return;
|
||||
}
|
||||
if (*in == '\n') {
|
||||
++in;
|
||||
return;
|
||||
}
|
||||
++in;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Buffer>
|
||||
int parse_int(Buffer & in) {
|
||||
int val = 0;
|
||||
bool neg = false;
|
||||
skip_whitespace(in);
|
||||
|
||||
if (*in == '-') {
|
||||
neg = true;
|
||||
++in;
|
||||
}
|
||||
else if (*in == '+') {
|
||||
++in;
|
||||
}
|
||||
|
||||
if (*in < '0' || *in > '9') {
|
||||
std::cerr << "(error, \"unexpected char: " << *in << "\")\n";
|
||||
exit(3);
|
||||
exit(ERR_PARSER);
|
||||
}
|
||||
|
||||
while (*in >= '0' && *in <= '9') {
|
||||
val = val*10 + (*in - '0');
|
||||
++in;
|
||||
}
|
||||
|
||||
return neg ? -val : val;
|
||||
}
|
||||
|
||||
template<typename Buffer>
|
||||
void read_clause(Buffer & in, sat::solver & solver, sat::literal_vector & lits) {
|
||||
int parsed_lit;
|
||||
int var;
|
||||
|
||||
lits.reset();
|
||||
|
||||
while (true) {
|
||||
parsed_lit = parse_int(in);
|
||||
if (parsed_lit == 0)
|
||||
break;
|
||||
var = abs(parsed_lit);
|
||||
SASSERT(var > 0);
|
||||
while (static_cast<unsigned>(var) >= solver.num_vars())
|
||||
solver.mk_var();
|
||||
lits.push_back(sat::literal(var, parsed_lit < 0));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Buffer>
|
||||
void parse_dimacs_core(Buffer & in, sat::solver & solver) {
|
||||
sat::literal_vector lits;
|
||||
while (true) {
|
||||
skip_whitespace(in);
|
||||
if (*in == EOF) {
|
||||
break;
|
||||
}
|
||||
else if (*in == 'c' || *in == 'p') {
|
||||
skip_line(in);
|
||||
}
|
||||
else {
|
||||
read_clause(in, solver, lits);
|
||||
solver.mk_clause(lits.size(), lits.c_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parse_dimacs(std::istream & in, sat::solver & solver) {
|
||||
stream_buffer _in(in);
|
||||
parse_dimacs_core(_in, solver);
|
||||
}
|
27
lib/dimacs.h
27
lib/dimacs.h
|
@ -1,27 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dimacs.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Dimacs CNF parser
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-07-26.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _DIMACS_H_
|
||||
#define _DIMACS_H_
|
||||
|
||||
#include"sat_types.h"
|
||||
|
||||
void parse_dimacs(std::istream & s, sat::solver & solver);
|
||||
|
||||
#endif /* _DIMACS_PARSER_H_ */
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr2dot.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-03-07.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"expr2dot.h"
|
||||
#include"for_each_expr.h"
|
||||
|
||||
class dot_printer {
|
||||
std::ostream & m_out;
|
||||
ast_manager & m_manager;
|
||||
bool m_proofs_only;
|
||||
public:
|
||||
dot_printer(std::ostream & out, ast_manager & m, bool proofs):
|
||||
m_out(out),
|
||||
m_manager(m),
|
||||
m_proofs_only(proofs) {
|
||||
}
|
||||
|
||||
char const * get_color(app * n) {
|
||||
if (m_manager.is_unit_resolution(n))
|
||||
return "blue";
|
||||
else if (m_manager.is_lemma(n))
|
||||
return "gold";
|
||||
else if (m_manager.is_transitivity(n))
|
||||
return "red";
|
||||
else if (m_manager.is_monotonicity(n))
|
||||
return "green";
|
||||
else
|
||||
return "black";
|
||||
}
|
||||
|
||||
void operator()(var * n) {
|
||||
if (!m_proofs_only) {
|
||||
m_out << n->get_id() << "[label=\"\",shape=circle];\n";
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(quantifier * n) {
|
||||
if (!m_proofs_only) {
|
||||
m_out << n->get_id() << "[label=\"\",shape=circle,color=gray];\n";
|
||||
m_out << n->get_expr()->get_id() << " -> " << n->get_id() << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(app * n) {
|
||||
if (!m_proofs_only || m_manager.is_proof(n)) {
|
||||
char const * c = get_color(n);
|
||||
m_out << n->get_id() << "[label=\"\",shape=circle,color=" << c << "];\n";
|
||||
if (m_proofs_only) {
|
||||
unsigned num = m_manager.get_num_parents(n);
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
m_out << m_manager.get_parent(n, i)->get_id() << " -> " << n->get_id() << " [color=" << c << "];\n";
|
||||
}
|
||||
else {
|
||||
unsigned num = n->get_num_args();
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
m_out << n->get_arg(i)->get_id() << " -> " << n->get_id() << " [color=" << c << "];\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void expr2dot(std::ostream & out, expr * n, ast_manager & m, bool proofs) {
|
||||
out << "digraph \"ast\" {\n";
|
||||
dot_printer p(out, m, proofs);
|
||||
for_each_expr(p, n);
|
||||
out << "}\n";
|
||||
}
|
||||
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr2dot.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Convert expressions into a .DOT file
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-03-07.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _EXPR2DOT_H_
|
||||
#define _EXPR2DOT_H_
|
||||
|
||||
#include"ast.h"
|
||||
|
||||
void expr2dot(std::ostream & out, expr * a, ast_manager & m, bool proofs = false);
|
||||
|
||||
#endif /* _AST2DOT_H_ */
|
||||
|
|
@ -1,481 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr2polynomial.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Translator from Z3 expressions into multivariate polynomials (and back).
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-12-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"expr2polynomial.h"
|
||||
#include"expr2var.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"z3_exception.h"
|
||||
#include"cooperate.h"
|
||||
|
||||
struct expr2polynomial::imp {
|
||||
struct frame {
|
||||
app * m_curr;
|
||||
unsigned m_idx;
|
||||
frame():m_curr(0), m_idx(0) {}
|
||||
frame(app * t):m_curr(t), m_idx(0) {}
|
||||
};
|
||||
|
||||
expr2polynomial & m_wrapper;
|
||||
ast_manager & m_am;
|
||||
arith_util m_autil;
|
||||
polynomial::manager & m_pm;
|
||||
expr2var * m_expr2var;
|
||||
bool m_expr2var_owner;
|
||||
expr_ref_vector m_var2expr;
|
||||
|
||||
obj_map<expr, unsigned> m_cache;
|
||||
expr_ref_vector m_cached_domain;
|
||||
polynomial::polynomial_ref_vector m_cached_polynomials;
|
||||
polynomial::scoped_numeral_vector m_cached_denominators;
|
||||
|
||||
svector<frame> m_frame_stack;
|
||||
polynomial::polynomial_ref_vector m_presult_stack;
|
||||
polynomial::scoped_numeral_vector m_dresult_stack;
|
||||
|
||||
volatile bool m_cancel;
|
||||
|
||||
imp(expr2polynomial & w, ast_manager & am, polynomial::manager & pm, expr2var * e2v):
|
||||
m_wrapper(w),
|
||||
m_am(am),
|
||||
m_autil(am),
|
||||
m_pm(pm),
|
||||
m_expr2var(e2v == 0 ? alloc(expr2var, am) : e2v),
|
||||
m_expr2var_owner(e2v == 0),
|
||||
m_var2expr(am),
|
||||
m_cached_domain(am),
|
||||
m_cached_polynomials(pm),
|
||||
m_cached_denominators(pm.m()),
|
||||
m_presult_stack(pm),
|
||||
m_dresult_stack(pm.m()),
|
||||
m_cancel(false) {
|
||||
}
|
||||
|
||||
~imp() {
|
||||
if (m_expr2var_owner)
|
||||
dealloc(m_expr2var);
|
||||
}
|
||||
|
||||
ast_manager & m() { return m_am; }
|
||||
polynomial::manager & pm() { return m_pm; }
|
||||
polynomial::numeral_manager & nm() { return pm().m(); }
|
||||
|
||||
void reset() {
|
||||
m_frame_stack.reset();
|
||||
m_presult_stack.reset();
|
||||
m_dresult_stack.reset();
|
||||
}
|
||||
|
||||
void reset_cache() {
|
||||
m_cache.reset();
|
||||
m_cached_domain.reset();
|
||||
m_cached_polynomials.reset();
|
||||
m_cached_denominators.reset();
|
||||
}
|
||||
|
||||
void checkpoint() {
|
||||
if (m_cancel)
|
||||
throw default_exception("canceled");
|
||||
cooperate("expr2polynomial");
|
||||
}
|
||||
|
||||
void push_frame(app * t) {
|
||||
m_frame_stack.push_back(frame(t));
|
||||
}
|
||||
|
||||
void cache_result(expr * t) {
|
||||
SASSERT(!m_cache.contains(t));
|
||||
SASSERT(m_cached_denominators.size() == m_cached_polynomials.size());
|
||||
SASSERT(m_cached_denominators.size() == m_cached_domain.size());
|
||||
if (t->get_ref_count() <= 1)
|
||||
return;
|
||||
unsigned idx = m_cached_polynomials.size();
|
||||
m_cache.insert(t, idx);
|
||||
m_cached_domain.push_back(t);
|
||||
m_cached_polynomials.push_back(m_presult_stack.back());
|
||||
m_cached_denominators.push_back(m_dresult_stack.back());
|
||||
}
|
||||
|
||||
bool is_cached(expr * t) {
|
||||
return t->get_ref_count() > 1 && m_cache.contains(t);
|
||||
}
|
||||
|
||||
bool is_int_real(expr * t) {
|
||||
return m_autil.is_int_real(t);
|
||||
}
|
||||
|
||||
void store_result(expr * t, polynomial::polynomial * p, polynomial::numeral & d) {
|
||||
m_presult_stack.push_back(p);
|
||||
m_dresult_stack.push_back(d);
|
||||
cache_result(t);
|
||||
}
|
||||
|
||||
void store_var_poly(expr * t) {
|
||||
polynomial::var x = m_expr2var->to_var(t);
|
||||
if (x == UINT_MAX) {
|
||||
bool is_int = m_autil.is_int(t);
|
||||
x = m_wrapper.mk_var(is_int);
|
||||
m_expr2var->insert(t, x);
|
||||
if (x >= m_var2expr.size())
|
||||
m_var2expr.resize(x+1, 0);
|
||||
m_var2expr.set(x, t);
|
||||
}
|
||||
polynomial::numeral one(1);
|
||||
store_result(t, pm().mk_polynomial(x), one);
|
||||
}
|
||||
|
||||
void store_const_poly(app * n) {
|
||||
rational val;
|
||||
VERIFY(m_autil.is_numeral(n, val));
|
||||
polynomial::scoped_numeral d(nm());
|
||||
d = val.to_mpq().denominator();
|
||||
store_result(n, pm().mk_const(numerator(val)), d);
|
||||
}
|
||||
|
||||
bool visit_arith_app(app * t) {
|
||||
switch (t->get_decl_kind()) {
|
||||
case OP_NUM:
|
||||
store_const_poly(t);
|
||||
return true;
|
||||
case OP_ADD: case OP_SUB: case OP_MUL: case OP_UMINUS: case OP_TO_REAL:
|
||||
push_frame(t);
|
||||
return false;
|
||||
case OP_POWER: {
|
||||
rational k;
|
||||
SASSERT(t->get_num_args() == 2);
|
||||
if (!m_autil.is_numeral(t->get_arg(1), k) || !k.is_int() || !k.is_unsigned()) {
|
||||
store_var_poly(t);
|
||||
return true;
|
||||
}
|
||||
push_frame(t);
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
// can't handle operator
|
||||
store_var_poly(t);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool visit(expr * t) {
|
||||
SASSERT(is_int_real(t));
|
||||
if (is_cached(t)) {
|
||||
unsigned idx = m_cache.find(t);
|
||||
m_presult_stack.push_back(m_cached_polynomials.get(idx));
|
||||
m_dresult_stack.push_back(m_cached_denominators.get(idx));
|
||||
return true;
|
||||
}
|
||||
|
||||
SASSERT(!is_quantifier(t));
|
||||
if (::is_var(t)) {
|
||||
store_var_poly(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
SASSERT(is_app(t));
|
||||
if (!m_autil.is_arith_expr(t)) {
|
||||
store_var_poly(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
return visit_arith_app(to_app(t));
|
||||
}
|
||||
|
||||
void pop(unsigned num_args) {
|
||||
SASSERT(m_presult_stack.size() == m_dresult_stack.size());
|
||||
SASSERT(m_presult_stack.size() >= num_args);
|
||||
m_presult_stack.shrink(m_presult_stack.size() - num_args);
|
||||
m_dresult_stack.shrink(m_dresult_stack.size() - num_args);
|
||||
}
|
||||
|
||||
polynomial::polynomial * const * polynomial_args(unsigned num_args) {
|
||||
SASSERT(m_presult_stack.size() >= num_args);
|
||||
return m_presult_stack.c_ptr() + m_presult_stack.size() - num_args;
|
||||
}
|
||||
|
||||
polynomial::numeral const * denominator_args(unsigned num_args) {
|
||||
SASSERT(m_dresult_stack.size() >= num_args);
|
||||
return m_dresult_stack.c_ptr() + m_dresult_stack.size() - num_args;
|
||||
}
|
||||
|
||||
template<bool is_add>
|
||||
void process_add_sub(app * t) {
|
||||
SASSERT(t->get_num_args() <= m_presult_stack.size());
|
||||
unsigned num_args = t->get_num_args();
|
||||
polynomial::polynomial * const * p_args = polynomial_args(num_args);
|
||||
polynomial::numeral const * d_args = denominator_args(num_args);
|
||||
polynomial::polynomial_ref p(pm());
|
||||
polynomial::polynomial_ref p_aux(pm());
|
||||
polynomial::scoped_numeral d(nm());
|
||||
polynomial::scoped_numeral d_aux(nm());
|
||||
d = 1;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
nm().lcm(d, d_args[i], d);
|
||||
}
|
||||
p = pm().mk_zero();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
checkpoint();
|
||||
nm().div(d, d_args[i], d_aux);
|
||||
p_aux = pm().mul(d_aux, p_args[i]);
|
||||
if (i == 0)
|
||||
p = p_aux;
|
||||
else if (is_add)
|
||||
p = pm().add(p, p_aux);
|
||||
else
|
||||
p = pm().sub(p, p_aux);
|
||||
}
|
||||
pop(num_args);
|
||||
store_result(t, p.get(), d.get());
|
||||
}
|
||||
|
||||
void process_add(app * t) {
|
||||
process_add_sub<true>(t);
|
||||
}
|
||||
|
||||
void process_sub(app * t) {
|
||||
process_add_sub<false>(t);
|
||||
}
|
||||
|
||||
void process_mul(app * t) {
|
||||
SASSERT(t->get_num_args() <= m_presult_stack.size());
|
||||
unsigned num_args = t->get_num_args();
|
||||
polynomial::polynomial * const * p_args = polynomial_args(num_args);
|
||||
polynomial::numeral const * d_args = denominator_args(num_args);
|
||||
polynomial::polynomial_ref p(pm());
|
||||
polynomial::scoped_numeral d(nm());
|
||||
p = pm().mk_const(rational(1));
|
||||
d = 1;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
checkpoint();
|
||||
p = pm().mul(p, p_args[i]);
|
||||
d = d * d_args[i];
|
||||
}
|
||||
pop(num_args);
|
||||
store_result(t, p.get(), d.get());
|
||||
}
|
||||
|
||||
void process_uminus(app * t) {
|
||||
SASSERT(t->get_num_args() <= m_presult_stack.size());
|
||||
polynomial::polynomial_ref neg_p(pm());
|
||||
neg_p = pm().neg(m_presult_stack.back());
|
||||
m_presult_stack.pop_back();
|
||||
m_presult_stack.push_back(neg_p);
|
||||
cache_result(t);
|
||||
}
|
||||
|
||||
void process_power(app * t) {
|
||||
SASSERT(t->get_num_args() <= m_presult_stack.size());
|
||||
rational _k;
|
||||
VERIFY(m_autil.is_numeral(t->get_arg(1), _k));
|
||||
SASSERT(_k.is_int() && _k.is_unsigned());
|
||||
unsigned k = _k.get_unsigned();
|
||||
polynomial::polynomial_ref p(pm());
|
||||
polynomial::scoped_numeral d(nm());
|
||||
unsigned num_args = t->get_num_args();
|
||||
polynomial::polynomial * const * p_args = polynomial_args(num_args);
|
||||
polynomial::numeral const * d_args = denominator_args(num_args);
|
||||
pm().pw(p_args[0], k, p);
|
||||
nm().power(d_args[0], k, d);
|
||||
pop(num_args);
|
||||
store_result(t, p.get(), d.get());
|
||||
}
|
||||
|
||||
void process_to_real(app * t) {
|
||||
// do nothing
|
||||
cache_result(t);
|
||||
}
|
||||
|
||||
void process_app(app * t) {
|
||||
SASSERT(m_presult_stack.size() == m_dresult_stack.size());
|
||||
|
||||
switch (t->get_decl_kind()) {
|
||||
case OP_ADD:
|
||||
process_add(t);
|
||||
return;
|
||||
case OP_SUB:
|
||||
process_sub(t);
|
||||
return;
|
||||
case OP_MUL:
|
||||
process_mul(t);
|
||||
return;
|
||||
case OP_POWER:
|
||||
process_power(t);
|
||||
return;
|
||||
case OP_UMINUS:
|
||||
process_uminus(t);
|
||||
return;
|
||||
case OP_TO_REAL:
|
||||
process_to_real(t);
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
bool to_polynomial(expr * t, polynomial::polynomial_ref & p, polynomial::scoped_numeral & d) {
|
||||
if (!is_int_real(t))
|
||||
return false;
|
||||
reset();
|
||||
if (!visit(t)) {
|
||||
while (!m_frame_stack.empty()) {
|
||||
begin_loop:
|
||||
checkpoint();
|
||||
frame & fr = m_frame_stack.back();
|
||||
app * t = fr.m_curr;
|
||||
TRACE("expr2polynomial", tout << "processing: " << fr.m_idx << "\n" << mk_ismt2_pp(t, m()) << "\n";);
|
||||
unsigned num_args = t->get_num_args();
|
||||
while (fr.m_idx < num_args) {
|
||||
expr * arg = t->get_arg(fr.m_idx);
|
||||
fr.m_idx++;
|
||||
if (!visit(arg))
|
||||
goto begin_loop;
|
||||
}
|
||||
process_app(t);
|
||||
m_frame_stack.pop_back();
|
||||
}
|
||||
}
|
||||
p = m_presult_stack.back();
|
||||
d = m_dresult_stack.back();
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_int_poly(polynomial::polynomial_ref const & p) {
|
||||
unsigned sz = size(p);
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
polynomial::monomial * m = pm().get_monomial(p, i);
|
||||
unsigned msz = pm().size(m);
|
||||
for (unsigned j = 0; j < msz; j++) {
|
||||
polynomial::var x = pm().get_var(m, j);
|
||||
if (!m_wrapper.is_int(x))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void to_expr(polynomial::polynomial_ref const & p, bool use_power, expr_ref & r) {
|
||||
expr_ref_buffer args(m());
|
||||
expr_ref_buffer margs(m());
|
||||
unsigned sz = size(p);
|
||||
bool is_int = is_int_poly(p);
|
||||
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
margs.reset();
|
||||
polynomial::monomial * m = pm().get_monomial(p, i);
|
||||
polynomial::numeral const & a = pm().coeff(p, i);
|
||||
if (!nm().is_one(a)) {
|
||||
margs.push_back(m_autil.mk_numeral(rational(a), is_int));
|
||||
}
|
||||
unsigned msz = pm().size(m);
|
||||
for (unsigned j = 0; j < msz; j++) {
|
||||
polynomial::var x = pm().get_var(m, j);
|
||||
expr * t = m_var2expr.get(x);
|
||||
if (m_wrapper.is_int(x) && !is_int) {
|
||||
t = m_autil.mk_to_real(t);
|
||||
}
|
||||
unsigned d = pm().degree(m, j);
|
||||
if (use_power && d > 1) {
|
||||
margs.push_back(m_autil.mk_power(t, m_autil.mk_numeral(rational(d), is_int)));
|
||||
}
|
||||
else {
|
||||
for (unsigned k = 0; k < d; k++)
|
||||
margs.push_back(t);
|
||||
}
|
||||
}
|
||||
if (margs.size() == 0) {
|
||||
args.push_back(m_autil.mk_numeral(rational(1), is_int));
|
||||
}
|
||||
else if (margs.size() == 1) {
|
||||
args.push_back(margs[0]);
|
||||
}
|
||||
else {
|
||||
args.push_back(m_autil.mk_mul(margs.size(), margs.c_ptr()));
|
||||
}
|
||||
}
|
||||
|
||||
if (args.size() == 0) {
|
||||
r = m_autil.mk_numeral(rational(0), is_int);
|
||||
}
|
||||
else if (args.size() == 1) {
|
||||
r = args[0];
|
||||
}
|
||||
else {
|
||||
r = m_autil.mk_add(args.size(), args.c_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_cancel = f;
|
||||
}
|
||||
};
|
||||
|
||||
expr2polynomial::expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v) {
|
||||
m_imp = alloc(imp, *this, am, pm, e2v);
|
||||
}
|
||||
|
||||
expr2polynomial::~expr2polynomial() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
ast_manager & expr2polynomial::m() const {
|
||||
return m_imp->m_am;
|
||||
}
|
||||
|
||||
polynomial::manager & expr2polynomial::pm() const {
|
||||
return m_imp->m_pm;
|
||||
}
|
||||
|
||||
bool expr2polynomial::to_polynomial(expr * t, polynomial::polynomial_ref & p, polynomial::scoped_numeral & d) {
|
||||
return m_imp->to_polynomial(t, p, d);
|
||||
}
|
||||
|
||||
void expr2polynomial::to_expr(polynomial::polynomial_ref const & p, bool use_power, expr_ref & r) {
|
||||
m_imp->to_expr(p, use_power, r);
|
||||
}
|
||||
|
||||
bool expr2polynomial::is_var(expr * t) const {
|
||||
return m_imp->m_expr2var->is_var(t);
|
||||
}
|
||||
|
||||
expr2var const & expr2polynomial::get_mapping() const {
|
||||
return *(m_imp->m_expr2var);
|
||||
}
|
||||
|
||||
void expr2polynomial::set_cancel(bool f) {
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
|
||||
default_expr2polynomial::default_expr2polynomial(ast_manager & am, polynomial::manager & pm):
|
||||
expr2polynomial(am, pm, 0) {
|
||||
}
|
||||
|
||||
default_expr2polynomial::~default_expr2polynomial() {
|
||||
}
|
||||
|
||||
bool default_expr2polynomial::is_int(polynomial::var x) const {
|
||||
return m_is_int[x];
|
||||
}
|
||||
|
||||
polynomial::var default_expr2polynomial::mk_var(bool is_int) {
|
||||
polynomial::var x = pm().mk_var();
|
||||
m_is_int.reserve(x+1, false);
|
||||
m_is_int[x] = is_int;
|
||||
return x;
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr2polynomial.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Translator from Z3 expressions into multivariate polynomials (and back).
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-12-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _EXPR2POLYNOMIAL_H_
|
||||
#define _EXPR2POLYNOMIAL_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"polynomial.h"
|
||||
|
||||
class expr2var;
|
||||
|
||||
class expr2polynomial {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
public:
|
||||
expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v);
|
||||
virtual ~expr2polynomial();
|
||||
|
||||
ast_manager & m() const;
|
||||
polynomial::manager & pm() const;
|
||||
|
||||
/**
|
||||
\brief Convert a Z3 expression into a polynomial in Z[x0, ..., x_n].
|
||||
Since Z3 expressions may be representing polynomials in Q[x0, ..., x_n],
|
||||
the method also returns a "denominator" d.
|
||||
Thus, we have that n is equal to p/d
|
||||
|
||||
\remark Return false if t is not an integer or real expression.
|
||||
|
||||
\pre The only supported operators are MUL, ADD, SUB, UMINUS, TO_REAL, TO_INT, POWER (with constants)
|
||||
*/
|
||||
bool to_polynomial(expr * t, polynomial::polynomial_ref & p, polynomial::scoped_numeral & d);
|
||||
|
||||
/**
|
||||
\brief Convert a polynomial into a Z3 expression.
|
||||
|
||||
\remark If the polynomial has one real variable, then the resultant
|
||||
expression is an real expression. Otherwise, it is an integer
|
||||
*/
|
||||
void to_expr(polynomial::polynomial_ref const & p, bool use_power, expr_ref & r);
|
||||
|
||||
/**
|
||||
\brief Return true if t was encoded as a variable by the translator.
|
||||
*/
|
||||
bool is_var(expr * t) const;
|
||||
|
||||
|
||||
/**
|
||||
\brief Return the mapping from expressions to variables
|
||||
*/
|
||||
expr2var const & get_mapping() const;
|
||||
|
||||
/**
|
||||
\brief Cancel/Interrupt execution.
|
||||
*/
|
||||
void set_cancel(bool f);
|
||||
|
||||
/**
|
||||
\brief Return true if the variable is associated with an expression of integer sort.
|
||||
*/
|
||||
virtual bool is_int(polynomial::var x) const = 0;
|
||||
|
||||
protected:
|
||||
virtual polynomial::var mk_var(bool is_int) = 0;
|
||||
};
|
||||
|
||||
class default_expr2polynomial : public expr2polynomial {
|
||||
svector<bool> m_is_int;
|
||||
public:
|
||||
default_expr2polynomial(ast_manager & am, polynomial::manager & pm);
|
||||
virtual ~default_expr2polynomial();
|
||||
virtual bool is_int(polynomial::var x) const;
|
||||
protected:
|
||||
virtual polynomial::var mk_var(bool is_int);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,395 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr2subpaving.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Translator from Z3 expressions into generic subpaving data-structure.
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-08-08
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"expr2subpaving.h"
|
||||
#include"expr2var.h"
|
||||
#include"ref_util.h"
|
||||
#include"z3_exception.h"
|
||||
#include"cooperate.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"scoped_numeral_buffer.h"
|
||||
|
||||
struct expr2subpaving::imp {
|
||||
struct frame {
|
||||
app * m_curr;
|
||||
unsigned m_idx;
|
||||
frame():m_curr(0), m_idx(0) {}
|
||||
frame(app * t):m_curr(t), m_idx(0) {}
|
||||
};
|
||||
|
||||
ast_manager & m_manager;
|
||||
subpaving::context & m_subpaving;
|
||||
unsynch_mpq_manager & m_qm;
|
||||
arith_util m_autil;
|
||||
expr2var * m_expr2var;
|
||||
bool m_expr2var_owner;
|
||||
|
||||
expr_ref_vector m_var2expr;
|
||||
|
||||
typedef svector<subpaving::var> var_vector;
|
||||
|
||||
obj_map<expr, unsigned> m_cache;
|
||||
var_vector m_cached_vars;
|
||||
scoped_mpz_vector m_cached_numerators;
|
||||
scoped_mpz_vector m_cached_denominators;
|
||||
|
||||
obj_map<expr, subpaving::ineq*> m_lit_cache;
|
||||
|
||||
volatile bool m_cancel;
|
||||
|
||||
imp(ast_manager & m, subpaving::context & s, expr2var * e2v):
|
||||
m_manager(m),
|
||||
m_subpaving(s),
|
||||
m_qm(s.qm()),
|
||||
m_autil(m),
|
||||
m_var2expr(m),
|
||||
m_cached_numerators(m_qm),
|
||||
m_cached_denominators(m_qm) {
|
||||
|
||||
if (e2v == 0) {
|
||||
m_expr2var = alloc(expr2var, m);
|
||||
m_expr2var_owner = true;
|
||||
}
|
||||
else {
|
||||
m_expr2var = e2v;
|
||||
m_expr2var_owner = false;
|
||||
}
|
||||
|
||||
m_cancel = false;
|
||||
}
|
||||
|
||||
~imp() {
|
||||
reset_cache();
|
||||
if (m_expr2var_owner)
|
||||
dealloc(m_expr2var);
|
||||
}
|
||||
|
||||
ast_manager & m() { return m_manager; }
|
||||
|
||||
subpaving::context & s() { return m_subpaving; }
|
||||
|
||||
unsynch_mpq_manager & qm() const { return m_qm; }
|
||||
|
||||
void reset_cache() {
|
||||
dec_ref_map_keys(m(), m_cache);
|
||||
m_cached_vars.reset();
|
||||
m_cached_numerators.reset();
|
||||
m_cached_denominators.reset();
|
||||
dec_ref_map_key_values(m(), s(), m_lit_cache);
|
||||
}
|
||||
|
||||
void checkpoint() {
|
||||
if (m_cancel)
|
||||
throw default_exception("canceled");
|
||||
cooperate("expr2subpaving");
|
||||
}
|
||||
|
||||
subpaving::var mk_var_for(expr * t) {
|
||||
SASSERT(!m_autil.is_numeral(t));
|
||||
subpaving::var x = m_expr2var->to_var(t);
|
||||
if (x == subpaving::null_var) {
|
||||
bool is_int = m_autil.is_int(t);
|
||||
x = s().mk_var(is_int);
|
||||
m_expr2var->insert(t, x);
|
||||
if (x >= m_var2expr.size())
|
||||
m_var2expr.resize(x+1, 0);
|
||||
m_var2expr.set(x, t);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void found_non_simplified() {
|
||||
throw default_exception("you must apply simplifier before internalizing expressions into the subpaving module.");
|
||||
}
|
||||
|
||||
bool is_cached(expr * t) {
|
||||
return t->get_ref_count() > 1 && m_cache.contains(t);
|
||||
}
|
||||
|
||||
bool is_int_real(expr * t) {
|
||||
return m_autil.is_int_real(t);
|
||||
}
|
||||
|
||||
void cache_result(expr * t, subpaving::var x, mpz const & n, mpz const & d) {
|
||||
SASSERT(!m_cache.contains(t));
|
||||
SASSERT(m_cached_numerators.size() == m_cached_vars.size());
|
||||
SASSERT(m_cached_denominators.size() == m_cached_vars.size());
|
||||
if (t->get_ref_count() <= 1)
|
||||
return;
|
||||
unsigned idx = m_cached_vars.size();
|
||||
m_cache.insert(t, idx);
|
||||
m().inc_ref(t);
|
||||
m_cached_vars.push_back(x);
|
||||
m_cached_numerators.push_back(n);
|
||||
m_cached_denominators.push_back(d);
|
||||
}
|
||||
|
||||
subpaving::var process_num(app * t, unsigned depth, mpz & n, mpz & d) {
|
||||
rational k;
|
||||
VERIFY(m_autil.is_numeral(t, k));
|
||||
qm().set(n, k.to_mpq().numerator());
|
||||
qm().set(d, k.to_mpq().denominator());
|
||||
return subpaving::null_var;
|
||||
}
|
||||
|
||||
// Put t as a^k.
|
||||
void as_power(expr * t, expr * & a, unsigned & k) {
|
||||
if (!m_autil.is_power(t)) {
|
||||
a = t;
|
||||
k = 1;
|
||||
return;
|
||||
}
|
||||
rational _k;
|
||||
if (!m_autil.is_numeral(to_app(t)->get_arg(1), _k) || !_k.is_int() || !_k.is_unsigned()) {
|
||||
a = t;
|
||||
k = 1;
|
||||
return;
|
||||
}
|
||||
a = to_app(t)->get_arg(0);
|
||||
k = _k.get_unsigned();
|
||||
}
|
||||
|
||||
subpaving::var process_mul(app * t, unsigned depth, mpz & n, mpz & d) {
|
||||
unsigned num_args = t->get_num_args();
|
||||
if (num_args <= 1)
|
||||
found_non_simplified();
|
||||
rational k;
|
||||
expr * m;
|
||||
if (m_autil.is_numeral(t->get_arg(0), k)) {
|
||||
if (num_args != 2)
|
||||
found_non_simplified();
|
||||
qm().set(n, k.to_mpq().numerator());
|
||||
qm().set(d, k.to_mpq().denominator());
|
||||
m = t->get_arg(1);
|
||||
}
|
||||
else {
|
||||
qm().set(n, 1);
|
||||
qm().set(d, 1);
|
||||
m = t;
|
||||
}
|
||||
expr * const * margs;
|
||||
unsigned sz;
|
||||
if (m_autil.is_mul(m)) {
|
||||
margs = to_app(m)->get_args();
|
||||
sz = to_app(m)->get_num_args();
|
||||
}
|
||||
else {
|
||||
margs = &m;
|
||||
sz = 1;
|
||||
}
|
||||
scoped_mpz n_arg(qm());
|
||||
scoped_mpz d_arg(qm());
|
||||
sbuffer<subpaving::power> pws;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * arg = margs[i];
|
||||
unsigned k;
|
||||
as_power(arg, arg, k);
|
||||
subpaving::var x_arg = process(arg, depth+1, n_arg, d_arg);
|
||||
qm().power(n_arg, k, n_arg);
|
||||
qm().power(d_arg, k, d_arg);
|
||||
qm().mul(n, n_arg, n);
|
||||
qm().mul(d, d_arg, d);
|
||||
if (x_arg != subpaving::null_var)
|
||||
pws.push_back(subpaving::power(x_arg, k));
|
||||
}
|
||||
subpaving::var x;
|
||||
if (pws.empty())
|
||||
x = subpaving::null_var;
|
||||
else if (pws.size() == 1 && pws[0].degree() == 1)
|
||||
x = pws[0].get_var();
|
||||
else
|
||||
x = s().mk_monomial(pws.size(), pws.c_ptr());
|
||||
cache_result(t, x, n, d);
|
||||
return x;
|
||||
}
|
||||
|
||||
typedef _scoped_numeral_buffer<unsynch_mpz_manager> mpz_buffer;
|
||||
typedef sbuffer<subpaving::var> var_buffer;
|
||||
|
||||
subpaving::var process_add(app * t, unsigned depth, mpz & n, mpz & d) {
|
||||
unsigned num_args = t->get_num_args();
|
||||
mpz_buffer ns(qm()), ds(qm());
|
||||
var_buffer xs;
|
||||
scoped_mpq c(qm()), c_arg(qm());
|
||||
scoped_mpz n_arg(qm()), d_arg(qm());
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * arg = t->get_arg(i);
|
||||
subpaving::var x_arg = process(arg, depth+1, n_arg, d_arg);
|
||||
if (x_arg == subpaving::null_var) {
|
||||
qm().set(c_arg, n_arg, d_arg);
|
||||
qm().add(c, c_arg, c);
|
||||
}
|
||||
else {
|
||||
xs.push_back(x_arg);
|
||||
ns.push_back(n_arg);
|
||||
ds.push_back(d_arg);
|
||||
}
|
||||
}
|
||||
qm().set(d, c.get().denominator());
|
||||
unsigned sz = xs.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
qm().lcm(d, ds[i], d);
|
||||
}
|
||||
scoped_mpz & k = d_arg;
|
||||
qm().div(d, c.get().denominator(), k);
|
||||
scoped_mpz sum_c(qm());
|
||||
qm().mul(c.get().numerator(), k, sum_c);
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
qm().div(d, ds[i], k);
|
||||
qm().mul(ns[i], k, ns[i]);
|
||||
}
|
||||
subpaving::var x;
|
||||
if (sz == 0) {
|
||||
qm().set(n, sum_c);
|
||||
x = subpaving::null_var;
|
||||
}
|
||||
else {
|
||||
x = s().mk_sum(sum_c, sz, ns.c_ptr(), xs.c_ptr());
|
||||
qm().set(n, 1);
|
||||
}
|
||||
cache_result(t, x, n, d);
|
||||
return x;
|
||||
}
|
||||
|
||||
subpaving::var process_power(app * t, unsigned depth, mpz & n, mpz & d) {
|
||||
rational k;
|
||||
SASSERT(t->get_num_args() == 2);
|
||||
if (!m_autil.is_numeral(t->get_arg(1), k) || !k.is_int() || !k.is_unsigned()) {
|
||||
qm().set(n, 1);
|
||||
qm().set(d, 1);
|
||||
return mk_var_for(t);
|
||||
}
|
||||
unsigned _k = k.get_unsigned();
|
||||
subpaving::var x = process(t->get_arg(0), depth+1, n, d);
|
||||
if (x != subpaving::null_var) {
|
||||
subpaving::power p(x, _k);
|
||||
x = s().mk_monomial(1, &p);
|
||||
}
|
||||
qm().power(n, _k, n);
|
||||
qm().power(d, _k, d);
|
||||
cache_result(t, x, n, d);
|
||||
return x;
|
||||
}
|
||||
|
||||
subpaving::var process_arith_app(app * t, unsigned depth, mpz & n, mpz & d) {
|
||||
SASSERT(m_autil.is_arith_expr(t));
|
||||
|
||||
switch (t->get_decl_kind()) {
|
||||
case OP_NUM:
|
||||
return process_num(t, depth, n, d);
|
||||
case OP_ADD:
|
||||
return process_add(t, depth, n, d);
|
||||
case OP_MUL:
|
||||
return process_mul(t, depth, n, d);
|
||||
case OP_POWER:
|
||||
return process_power(t, depth, n, d);
|
||||
case OP_TO_REAL:
|
||||
return process(t->get_arg(0), depth+1, n, d);
|
||||
case OP_SUB:
|
||||
case OP_UMINUS:
|
||||
found_non_simplified();
|
||||
break;
|
||||
case OP_TO_INT:
|
||||
case OP_DIV:
|
||||
case OP_IDIV:
|
||||
case OP_MOD:
|
||||
case OP_REM:
|
||||
case OP_IRRATIONAL_ALGEBRAIC_NUM:
|
||||
throw default_exception("you must apply arithmetic purifier before internalizing expressions into the subpaving module.");
|
||||
case OP_SIN:
|
||||
case OP_COS:
|
||||
case OP_TAN:
|
||||
case OP_ASIN:
|
||||
case OP_ACOS:
|
||||
case OP_ATAN:
|
||||
case OP_SINH:
|
||||
case OP_COSH:
|
||||
case OP_TANH:
|
||||
case OP_ASINH:
|
||||
case OP_ACOSH:
|
||||
case OP_ATANH:
|
||||
// TODO
|
||||
throw default_exception("transcendental and hyperbolic functions are not supported yet.");
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return subpaving::null_var;
|
||||
}
|
||||
|
||||
subpaving::var process(expr * t, unsigned depth, mpz & n, mpz & d) {
|
||||
SASSERT(is_int_real(t));
|
||||
checkpoint();
|
||||
|
||||
if (is_cached(t)) {
|
||||
unsigned idx = m_cache.find(t);
|
||||
qm().set(n, m_cached_numerators[idx]);
|
||||
qm().set(d, m_cached_denominators[idx]);
|
||||
return m_cached_vars[idx];
|
||||
}
|
||||
|
||||
SASSERT(!is_quantifier(t));
|
||||
if (::is_var(t) || !m_autil.is_arith_expr(t)) {
|
||||
qm().set(n, 1);
|
||||
qm().set(d, 1);
|
||||
return mk_var_for(t);
|
||||
}
|
||||
|
||||
return process_arith_app(to_app(t), depth, n, d);
|
||||
}
|
||||
|
||||
bool is_var(expr * t) const {
|
||||
return m_expr2var->is_var(t);
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_cancel = f;
|
||||
}
|
||||
|
||||
subpaving::var internalize_term(expr * t, mpz & n, mpz & d) {
|
||||
return process(t, 0, n, d);
|
||||
}
|
||||
};
|
||||
|
||||
expr2subpaving::expr2subpaving(ast_manager & m, subpaving::context & s, expr2var * e2v) {
|
||||
m_imp = alloc(imp, m, s, e2v);
|
||||
}
|
||||
|
||||
expr2subpaving::~expr2subpaving() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
ast_manager & expr2subpaving::m() const {
|
||||
return m_imp->m();
|
||||
}
|
||||
|
||||
subpaving::context & expr2subpaving::s() const {
|
||||
return m_imp->s();
|
||||
}
|
||||
|
||||
bool expr2subpaving::is_var(expr * t) const {
|
||||
return m_imp->is_var(t);
|
||||
}
|
||||
|
||||
void expr2subpaving::set_cancel(bool f) {
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
|
||||
subpaving::var expr2subpaving::internalize_term(expr * t, mpz & n, mpz & d) {
|
||||
return m_imp->internalize_term(t, n, d);
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr2subpaving.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Translator from Z3 expressions into generic subpaving data-structure.
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-08-08
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _EXPR2SUBPAVING_H_
|
||||
#define _EXPR2SUBPAVING_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"subpaving.h"
|
||||
|
||||
class expr2var;
|
||||
|
||||
class expr2subpaving {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
public:
|
||||
expr2subpaving(ast_manager & m, subpaving::context & s, expr2var * e2v = 0);
|
||||
~expr2subpaving();
|
||||
|
||||
ast_manager & m() const;
|
||||
|
||||
subpaving::context & s() const;
|
||||
|
||||
/**
|
||||
\brief Return true if t was encoded as a variable by the translator.
|
||||
*/
|
||||
bool is_var(expr * t) const;
|
||||
|
||||
/**
|
||||
\brief Cancel/Interrupt execution.
|
||||
*/
|
||||
void set_cancel(bool f);
|
||||
|
||||
/**
|
||||
\brief Internalize a Z3 arithmetical expression into the subpaving data-structure.
|
||||
|
||||
\remark throws subpaving::exception there is a translation error (when using imprecise representations, i.e. floats, in the subpaving module)
|
||||
*/
|
||||
subpaving::var internalize_term(expr * t, /* out */ mpz & n, /* out */ mpz & d);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,77 +0,0 @@
|
|||
#include "expr_delta.h"
|
||||
#include "ast_pp.h"
|
||||
|
||||
expr_delta::expr_delta(ast_manager& m) : m_manager(m), m_exprs(m) {}
|
||||
|
||||
void expr_delta::assert_cnstr(expr* n) {
|
||||
m_exprs.push_back(n);
|
||||
}
|
||||
|
||||
bool expr_delta::delta_dfs(unsigned n, expr_ref_vector& result) {
|
||||
return delta_dfs(n, m_exprs.size(), m_exprs.c_ptr(), result);
|
||||
}
|
||||
|
||||
bool expr_delta::delta_dfs(unsigned& n, unsigned sz, expr* const* exprs, expr_ref_vector& result) {
|
||||
expr_ref r(m_manager);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
expr* e = exprs[i];
|
||||
if (delta_dfs(n, e, r)) {
|
||||
result.push_back(r.get());
|
||||
for (unsigned j = i+1; j < sz; ++j) {
|
||||
result.push_back(exprs[j]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
result.push_back(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool expr_delta::delta_dfs(unsigned& n, app* a, expr_ref& result) {
|
||||
expr_ref_vector args(m_manager);
|
||||
if (delta_dfs(n, a->get_num_args(), a->get_args(), args)) {
|
||||
result = m_manager.mk_app(a->get_decl(), args.size(), args.c_ptr());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool expr_delta::delta_dfs(unsigned& n, expr* e, expr_ref& result) {
|
||||
ast_manager& m = m_manager;
|
||||
if (m.is_true(e) || m.is_false(e)) {
|
||||
return false;
|
||||
}
|
||||
if (n == 0 && m.is_bool(e)) {
|
||||
result = m.mk_true();
|
||||
return true;
|
||||
}
|
||||
else if (n == 1 && m.is_bool(e)) {
|
||||
result = m.mk_false();
|
||||
return true;
|
||||
}
|
||||
else if (is_app(e)) {
|
||||
if (m.is_bool(e)) {
|
||||
SASSERT(n >= 2);
|
||||
n -= 2;
|
||||
}
|
||||
return delta_dfs(n, to_app(e), result);
|
||||
}
|
||||
else if (is_quantifier(e)) {
|
||||
SASSERT(n >= 2);
|
||||
n -= 2;
|
||||
quantifier* q = to_quantifier(e);
|
||||
if (delta_dfs(n, q->get_expr(), result)) {
|
||||
result = m.update_quantifier(q, result.get());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2008 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr_delta.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Delta debugging support for specifications.
|
||||
A specification is a list of assumptions.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2008-21-06
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _EXPR_DELTA_H_
|
||||
#define _EXPR_DELTA_H_
|
||||
|
||||
#include "ast.h"
|
||||
|
||||
class expr_delta {
|
||||
ast_manager& m_manager;
|
||||
expr_ref_vector m_exprs;
|
||||
public:
|
||||
expr_delta(ast_manager& m);
|
||||
|
||||
// Assert a constraint.
|
||||
void assert_cnstr(expr* e);
|
||||
|
||||
//
|
||||
// Create the n'th delta in dfs mode.
|
||||
// resturn 'true' if a delta was obtained.
|
||||
//
|
||||
bool delta_dfs(unsigned n, expr_ref_vector& result);
|
||||
|
||||
private:
|
||||
|
||||
// perform delta
|
||||
bool delta_dfs(unsigned& n, expr* e, expr_ref& result);
|
||||
|
||||
bool delta_dfs(unsigned& n, app* a, expr_ref& result);
|
||||
|
||||
bool delta_dfs(unsigned& n, unsigned sz, expr* const* exprs, expr_ref_vector& result);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,268 +0,0 @@
|
|||
#include "expr_rand.h"
|
||||
#include "bv_decl_plugin.h"
|
||||
#include "array_decl_plugin.h"
|
||||
#include "arith_decl_plugin.h"
|
||||
#include "ast_pp.h"
|
||||
|
||||
|
||||
expr_rand::expr_rand(ast_manager& m):
|
||||
m_manager(m),
|
||||
m_num_vars(0),
|
||||
m_num_apps(0),
|
||||
m_num_nodes(0),
|
||||
m_max_steps(10),
|
||||
m_funcs(m)
|
||||
{}
|
||||
|
||||
expr_rand::~expr_rand() {
|
||||
map_t::iterator it = m_nodes.begin();
|
||||
map_t::iterator end = m_nodes.end();
|
||||
for (; it != end; ++it) {
|
||||
dealloc(it->m_value);
|
||||
}
|
||||
}
|
||||
|
||||
void expr_rand::add_var(sort* s) {
|
||||
add_expr(m_manager.mk_fresh_const("x", s));
|
||||
}
|
||||
|
||||
void expr_rand::add_func_decl(func_decl* f) {
|
||||
m_funcs.push_back(f);
|
||||
}
|
||||
|
||||
void expr_rand::add_expr(expr* t) {
|
||||
sort* s = m_manager.get_sort(t);
|
||||
expr_ref_vector* vals = 0;
|
||||
if (!m_nodes.find(s, vals)) {
|
||||
vals = alloc(expr_ref_vector, m_manager);
|
||||
m_nodes.insert(s, vals);
|
||||
}
|
||||
vals->push_back(t);
|
||||
}
|
||||
|
||||
void expr_rand::get_next(sort* s, expr_ref& e) {
|
||||
walk(m_max_steps);
|
||||
e = choose_expr(s);
|
||||
}
|
||||
|
||||
void expr_rand::walk() {
|
||||
func_decl* f = choose_func_decl();
|
||||
unsigned arity = f->get_arity();
|
||||
expr_ref_vector args(m_manager);
|
||||
for (unsigned i = 0; i < arity; ++i) {
|
||||
args.push_back(choose_expr(f->get_domain(i)));
|
||||
}
|
||||
expr* r = m_manager.mk_app(f, args.size(), args.c_ptr());
|
||||
add_expr(r);
|
||||
}
|
||||
|
||||
void expr_rand::walk(unsigned n) {
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
walk();
|
||||
}
|
||||
}
|
||||
|
||||
func_decl* expr_rand::choose_func_decl() {
|
||||
unsigned idx = m_random(m_funcs.size());
|
||||
return m_funcs[idx].get();
|
||||
}
|
||||
|
||||
expr* expr_rand::choose_expr(sort* s) {
|
||||
expr_ref_vector* vals = 0;
|
||||
if (!m_nodes.find(s, vals)) {
|
||||
add_var(s);
|
||||
if (!m_nodes.find(s, vals)) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
SASSERT(vals);
|
||||
}
|
||||
unsigned idx = m_random(vals->size());
|
||||
return (*vals)[idx].get();
|
||||
}
|
||||
|
||||
void expr_rand::initialize_arith(unsigned num_vars) {
|
||||
arith_util u(m_manager);
|
||||
family_id afid = m_manager.get_family_id("arith");
|
||||
sort* i_ty = m_manager.mk_sort(afid, INT_SORT, 0, 0);
|
||||
for(unsigned i = 0; i < num_vars; ++i) {
|
||||
add_var(i_ty);
|
||||
}
|
||||
sort* is[2] = { i_ty, i_ty };
|
||||
decl_kind kinds[7] = {OP_ADD, OP_MUL, OP_SUB, OP_LE, OP_LT, OP_GE, OP_GT };
|
||||
for (unsigned i = 0; i < 7; ++i) {
|
||||
add_func_decl(m_manager.mk_func_decl(afid, kinds[i], 0, 0, 2, is));
|
||||
}
|
||||
|
||||
add_expr(u.mk_numeral(rational(0), true));
|
||||
add_expr(u.mk_numeral(rational(1), true));
|
||||
add_expr(u.mk_numeral(rational(2), true));
|
||||
add_expr(u.mk_numeral(rational(3), true));
|
||||
add_expr(u.mk_numeral(rational(6), true));
|
||||
add_expr(u.mk_numeral(rational(7), true));
|
||||
add_expr(u.mk_numeral(rational(-1), true));
|
||||
add_expr(u.mk_numeral(rational(-2), true));
|
||||
}
|
||||
|
||||
void expr_rand::initialize_bv(unsigned num_vars) {
|
||||
bv_util u(m_manager);
|
||||
family_id bfid = m_manager.get_basic_family_id();
|
||||
family_id bvfid = m_manager.get_family_id("bv");
|
||||
|
||||
|
||||
const unsigned num_sizes = 6;
|
||||
unsigned sizes[num_sizes] = { 1, 2, 8, 16, 24, 32 };
|
||||
parameter p1(1), p2(2), p3(3), p4(4), p8(8), p16(16), p24(24), p32(32);
|
||||
|
||||
for (unsigned i = 0; i < num_sizes; ++i) {
|
||||
add_expr(u.mk_numeral(rational(0), sizes[i]));
|
||||
add_expr(u.mk_numeral(rational(1), sizes[i]));
|
||||
}
|
||||
add_expr(u.mk_numeral(rational(2), 2));
|
||||
add_expr(u.mk_numeral(rational(3), 2));
|
||||
add_expr(u.mk_numeral(rational(6), 8));
|
||||
add_expr(u.mk_numeral(rational(7), 8));
|
||||
add_expr(u.mk_numeral(rational(static_cast<unsigned>(-2)), 32));
|
||||
add_expr(u.mk_numeral(rational(static_cast<unsigned>(-1)), 32));
|
||||
|
||||
for (unsigned i = 0; num_vars > 0; ++i, --num_vars) {
|
||||
i = i % num_sizes;
|
||||
parameter param(sizes[i]);
|
||||
add_var(m_manager.mk_sort(bvfid, BV_SORT, 1, ¶m));
|
||||
}
|
||||
for (unsigned i = 0; i < num_sizes; ++i) {
|
||||
parameter param(sizes[i]);
|
||||
sort* s = m_manager.mk_sort(bvfid, BV_SORT, 1, ¶m);
|
||||
|
||||
sort* ss[3] = { s, s, s };
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BNEG, 0, 0, 1, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BADD, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSUB, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BMUL, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSDIV, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BUDIV, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSREM, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BUREM, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSMOD, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ULEQ, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SLEQ, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_UGEQ, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SGEQ, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ULT, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SLT, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_UGT, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SGT, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BAND, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BOR, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BNOT, 0, 0, 1, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BXOR, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BXNOR, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BNAND, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BCOMP, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BREDAND, 0, 0, 1, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BREDOR, 0, 0, 1, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSHL, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BLSHR, 0, 0, 2, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_BASHR, 0, 0, 2, ss));
|
||||
|
||||
add_func_decl(m_manager.mk_func_decl(bfid, OP_EQ, 0, 0, 2, ss));
|
||||
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ROTATE_LEFT, 1, &p1, 1, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ROTATE_RIGHT, 1, &p1, 1, ss));
|
||||
|
||||
}
|
||||
|
||||
sort* b8 = m_manager.mk_sort(bvfid, BV_SORT, 1, &p8);
|
||||
sort* b16 = m_manager.mk_sort(bvfid, BV_SORT, 1, &p16);
|
||||
sort* b24 = m_manager.mk_sort(bvfid, BV_SORT, 1, &p24);
|
||||
sort* b32 = m_manager.mk_sort(bvfid, BV_SORT, 1, &p32);
|
||||
|
||||
// OP_CONCAT:
|
||||
{
|
||||
sort* ss[2] = { b8, b8 };
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss));
|
||||
ss[0] = b16;
|
||||
ss[1] = b8;
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss));
|
||||
ss[0] = b8;
|
||||
ss[1] = b16;
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss));
|
||||
ss[0] = b16;
|
||||
ss[1] = b16;
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss));
|
||||
ss[0] = b24;
|
||||
ss[1] = b8;
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss));
|
||||
ss[0] = b8;
|
||||
ss[1] = b24;
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss));
|
||||
}
|
||||
|
||||
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SIGN_EXT, 1, &p8, 1, &b8));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SIGN_EXT, 1, &p8, 1, &b16));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SIGN_EXT, 1, &p16, 1, &b8));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SIGN_EXT, 1, &p16, 1, &b16));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SIGN_EXT, 1, &p8, 1, &b16));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SIGN_EXT, 1, &p16, 1, &b8));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_SIGN_EXT, 1, &p8, 1, &b24));
|
||||
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ZERO_EXT, 1, &p8, 1, &b8));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ZERO_EXT, 1, &p8, 1, &b16));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ZERO_EXT, 1, &p16, 1, &b8));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ZERO_EXT, 1, &p16, 1, &b16));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ZERO_EXT, 1, &p8, 1, &b16));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ZERO_EXT, 1, &p16, 1, &b8));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_ZERO_EXT, 1, &p8, 1, &b24));
|
||||
|
||||
parameter bounds[2] = { parameter(7), parameter(0) };
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_EXTRACT, 2, bounds, 1, &b32));
|
||||
bounds[0] = parameter(15);
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_EXTRACT, 2, bounds, 1, &b32));
|
||||
bounds[0] = parameter(23);
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_EXTRACT, 2, bounds, 1, &b32));
|
||||
bounds[1] = parameter(8);
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_EXTRACT, 2, bounds, 1, &b32));
|
||||
bounds[1] = parameter(16);
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_EXTRACT, 2, bounds, 1, &b32));
|
||||
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_REPEAT, 1, &p4, 1, &b8));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_REPEAT, 1, &p3, 1, &b8));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_REPEAT, 1, &p2, 1, &b8));
|
||||
add_func_decl(m_manager.mk_func_decl(bvfid, OP_REPEAT, 1, &p1, 1, &b8));
|
||||
|
||||
/*
|
||||
OP_ROTATE_LEFT,
|
||||
OP_ROTATE_RIGHT,
|
||||
*/
|
||||
}
|
||||
|
||||
void expr_rand::initialize_array(unsigned num_vars, sort* dom, sort* rng) {
|
||||
family_id afid = m_manager.get_family_id("array");
|
||||
parameter p1(dom), p2(rng);
|
||||
parameter ps[2] = { p1, p2 };
|
||||
sort* a = m_manager.mk_sort(afid, ARRAY_SORT, 2, ps);
|
||||
sort* ss[3] = { a, dom, rng };
|
||||
|
||||
add_func_decl(m_manager.mk_func_decl(afid, OP_STORE, 0, 0, 3, ss));
|
||||
add_func_decl(m_manager.mk_func_decl(afid, OP_SELECT, 0, 0, 2, ss));
|
||||
|
||||
for (unsigned i = 0; i < num_vars; ++i) {
|
||||
add_var(a);
|
||||
}
|
||||
}
|
||||
|
||||
void expr_rand::initialize_basic(unsigned amplification) {
|
||||
family_id bfid = m_manager.get_basic_family_id();
|
||||
sort* bools[2] = { m_manager.mk_bool_sort(), m_manager.mk_bool_sort() };
|
||||
for (unsigned i = 0; i < amplification; ++i) {
|
||||
add_func_decl(m_manager.mk_func_decl(bfid, OP_OR, 0, 0, 2, bools));
|
||||
add_func_decl(m_manager.mk_func_decl(bfid, OP_NOT, 0, 0, 1, bools));
|
||||
}
|
||||
map_t::iterator it = m_nodes.begin();
|
||||
map_t::iterator end = m_nodes.end();
|
||||
for (; it != end; ++it) {
|
||||
sort* s = it->m_key;
|
||||
sort* ites[3] = { bools[0], s, s };
|
||||
add_func_decl(m_manager.mk_func_decl(bfid, OP_ITE, 0, 0, 3, ites));
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2008 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr_rand.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Generator of random ASTs.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2008-04-10.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _EXPR_RAND_H_
|
||||
#define _EXPR_RAND_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
class expr_rand {
|
||||
ast_manager& m_manager;
|
||||
unsigned m_num_vars;
|
||||
unsigned m_num_apps;
|
||||
unsigned m_num_nodes;
|
||||
unsigned m_max_steps;
|
||||
random_gen m_random;
|
||||
|
||||
typedef obj_map<sort, expr_ref_vector*> map_t;
|
||||
|
||||
func_decl_ref_vector m_funcs;
|
||||
map_t m_nodes;
|
||||
|
||||
public:
|
||||
expr_rand(ast_manager& m);
|
||||
~expr_rand();
|
||||
void add_var(sort*);
|
||||
void add_func_decl(func_decl*);
|
||||
void add_expr(expr* t);
|
||||
void get_next(sort* s, expr_ref& e);
|
||||
void initialize_bv(unsigned num_vars);
|
||||
void initialize_arith(unsigned num_vars);
|
||||
void initialize_array(unsigned num_vars, sort* dom, sort* rng);
|
||||
void initialize_basic(unsigned amplification);
|
||||
void seed(unsigned n) { m_random = random_gen(n); }
|
||||
|
||||
private:
|
||||
void walk();
|
||||
void walk(unsigned n);
|
||||
|
||||
func_decl* choose_func_decl();
|
||||
expr* choose_expr(sort*);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,361 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
factor_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Polynomial factorization tactic.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-02-03
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"expr2polynomial.h"
|
||||
#include"rewriter_def.h"
|
||||
|
||||
class factor_tactic : public tactic {
|
||||
|
||||
struct rw_cfg : public default_rewriter_cfg {
|
||||
ast_manager & m;
|
||||
arith_util m_util;
|
||||
unsynch_mpq_manager m_qm;
|
||||
polynomial::manager m_pm;
|
||||
default_expr2polynomial m_expr2poly;
|
||||
polynomial::factor_params m_fparams;
|
||||
bool m_split_factors;
|
||||
|
||||
rw_cfg(ast_manager & _m, params_ref const & p):
|
||||
m(_m),
|
||||
m_util(_m),
|
||||
m_pm(m_qm),
|
||||
m_expr2poly(m, m_pm) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_split_factors = p.get_bool(":split-factors", true);
|
||||
m_fparams.updt_params(p);
|
||||
}
|
||||
|
||||
expr * mk_mul(unsigned sz, expr * const * args) {
|
||||
SASSERT(sz > 0);
|
||||
if (sz == 1)
|
||||
return args[0];
|
||||
return m_util.mk_mul(sz, args);
|
||||
}
|
||||
|
||||
expr * mk_zero_for(expr * arg) {
|
||||
return m_util.mk_numeral(rational(0), m_util.is_int(arg));
|
||||
}
|
||||
|
||||
// p1^k1 * p2^k2 = 0 --> p1*p2 = 0
|
||||
void mk_eq(polynomial::factors const & fs, expr_ref & result) {
|
||||
expr_ref_buffer args(m);
|
||||
expr_ref arg(m);
|
||||
for (unsigned i = 0; i < fs.distinct_factors(); i++) {
|
||||
m_expr2poly.to_expr(fs[i], true, arg);
|
||||
args.push_back(arg);
|
||||
}
|
||||
result = m.mk_eq(mk_mul(args.size(), args.c_ptr()), mk_zero_for(arg));
|
||||
}
|
||||
|
||||
// p1^k1 * p2^k2 = 0 --> p1 = 0 or p2 = 0
|
||||
void mk_split_eq(polynomial::factors const & fs, expr_ref & result) {
|
||||
expr_ref_buffer args(m);
|
||||
expr_ref arg(m);
|
||||
for (unsigned i = 0; i < fs.distinct_factors(); i++) {
|
||||
m_expr2poly.to_expr(fs[i], true, arg);
|
||||
args.push_back(m.mk_eq(arg, mk_zero_for(arg)));
|
||||
}
|
||||
if (args.size() == 1)
|
||||
result = args[0];
|
||||
else
|
||||
result = m.mk_or(args.size(), args.c_ptr());
|
||||
}
|
||||
|
||||
decl_kind flip(decl_kind k) {
|
||||
SASSERT(k == OP_LT || k == OP_GT || k == OP_LE || k == OP_GE);
|
||||
switch (k) {
|
||||
case OP_LT: return OP_GT;
|
||||
case OP_LE: return OP_GE;
|
||||
case OP_GT: return OP_LT;
|
||||
case OP_GE: return OP_LE;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return k;
|
||||
}
|
||||
}
|
||||
|
||||
// p1^{2*k1} * p2^{2*k2 + 1} >=< 0
|
||||
// -->
|
||||
// (p1^2)*p2 >=<0
|
||||
void mk_comp(decl_kind k, polynomial::factors const & fs, expr_ref & result) {
|
||||
SASSERT(k == OP_LT || k == OP_GT || k == OP_LE || k == OP_GE);
|
||||
expr_ref_buffer args(m);
|
||||
expr_ref arg(m);
|
||||
for (unsigned i = 0; i < fs.distinct_factors(); i++) {
|
||||
m_expr2poly.to_expr(fs[i], true, arg);
|
||||
if (fs.get_degree(i) % 2 == 0)
|
||||
arg = m_util.mk_power(arg, m_util.mk_numeral(rational(2), m_util.is_int(arg)));
|
||||
args.push_back(arg);
|
||||
}
|
||||
expr * lhs = mk_mul(args.size(), args.c_ptr());
|
||||
result = m.mk_app(m_util.get_family_id(), k, lhs, mk_zero_for(lhs));
|
||||
}
|
||||
|
||||
// See mk_split_strict_comp and mk_split_nonstrict_comp
|
||||
void split_even_odd(bool strict, polynomial::factors const & fs, expr_ref_buffer & even_eqs, expr_ref_buffer & odd_factors) {
|
||||
expr_ref arg(m);
|
||||
for (unsigned i = 0; i < fs.distinct_factors(); i++) {
|
||||
m_expr2poly.to_expr(fs[i], true, arg);
|
||||
if (fs.get_degree(i) % 2 == 0) {
|
||||
expr * eq = m.mk_eq(arg, mk_zero_for(arg));
|
||||
if (strict)
|
||||
even_eqs.push_back(m.mk_not(eq));
|
||||
else
|
||||
even_eqs.push_back(eq);
|
||||
}
|
||||
else {
|
||||
odd_factors.push_back(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strict case
|
||||
// p1^{2*k1} * p2^{2*k2 + 1} >< 0
|
||||
// -->
|
||||
// p1 != 0 and p2 >< 0
|
||||
//
|
||||
// Nonstrict
|
||||
// p1^{2*k1} * p2^{2*k2 + 1} >=< 0
|
||||
// -->
|
||||
// p1 = 0 or p2 >=< 0
|
||||
//
|
||||
void mk_split_comp(decl_kind k, polynomial::factors const & fs, expr_ref & result) {
|
||||
SASSERT(k == OP_LT || k == OP_GT || k == OP_LE || k == OP_GE);
|
||||
bool strict = (k == OP_LT) || (k == OP_GT);
|
||||
expr_ref_buffer args(m);
|
||||
expr_ref_buffer odd_factors(m);
|
||||
split_even_odd(strict, fs, args, odd_factors);
|
||||
if (odd_factors.empty()) {
|
||||
if (k == OP_LT) {
|
||||
result = m.mk_false();
|
||||
return;
|
||||
}
|
||||
if (k == OP_GE) {
|
||||
result = m.mk_true();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
args.push_back(m.mk_app(m_util.get_family_id(), k, mk_mul(odd_factors.size(), odd_factors.c_ptr()), mk_zero_for(odd_factors[0])));
|
||||
}
|
||||
SASSERT(!args.empty());
|
||||
if (args.size() == 1)
|
||||
result = args[0];
|
||||
else if (strict)
|
||||
result = m.mk_and(args.size(), args.c_ptr());
|
||||
else
|
||||
result = m.mk_or(args.size(), args.c_ptr());
|
||||
}
|
||||
|
||||
br_status factor(func_decl * f, expr * lhs, expr * rhs, expr_ref & result) {
|
||||
polynomial_ref p1(m_pm);
|
||||
polynomial_ref p2(m_pm);
|
||||
scoped_mpz d1(m_qm);
|
||||
scoped_mpz d2(m_qm);
|
||||
m_expr2poly.to_polynomial(lhs, p1, d1);
|
||||
m_expr2poly.to_polynomial(rhs, p2, d2);
|
||||
TRACE("factor_tactic_bug",
|
||||
tout << "lhs: " << mk_ismt2_pp(lhs, m) << "\n";
|
||||
tout << "p1: " << p1 << "\n";
|
||||
tout << "d1: " << d1 << "\n";
|
||||
tout << "rhs: " << mk_ismt2_pp(rhs, m) << "\n";
|
||||
tout << "p2: " << p2 << "\n";
|
||||
tout << "d2: " << d2 << "\n";);
|
||||
scoped_mpz lcm(m_qm);
|
||||
m_qm.lcm(d1, d2, lcm);
|
||||
m_qm.div(lcm, d1, d1);
|
||||
m_qm.div(lcm, d2, d2);
|
||||
m_qm.neg(d2);
|
||||
polynomial_ref p(m_pm);
|
||||
p = m_pm.addmul(d1, m_pm.mk_unit(), p1, d2, m_pm.mk_unit(), p2);
|
||||
if (is_const(p))
|
||||
return BR_FAILED;
|
||||
polynomial::factors fs(m_pm);
|
||||
TRACE("factor_tactic_bug", tout << "p: " << p << "\n";);
|
||||
m_pm.factor(p, fs, m_fparams);
|
||||
SASSERT(fs.distinct_factors() > 0);
|
||||
TRACE("factor_tactic_bug", tout << "factors:\n"; fs.display(tout); tout << "\n";);
|
||||
if (fs.distinct_factors() == 1 && fs.get_degree(0) == 1)
|
||||
return BR_FAILED;
|
||||
if (m.is_eq(f)) {
|
||||
if (m_split_factors)
|
||||
mk_split_eq(fs, result);
|
||||
else
|
||||
mk_eq(fs, result);
|
||||
}
|
||||
else {
|
||||
decl_kind k = f->get_decl_kind();
|
||||
if (m_qm.is_neg(fs.get_constant()))
|
||||
k = flip(k);
|
||||
|
||||
if (m_split_factors)
|
||||
mk_split_comp(k, fs, result);
|
||||
else
|
||||
mk_comp(k, fs, result);
|
||||
}
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
if (num != 2)
|
||||
return BR_FAILED;
|
||||
if (m.is_eq(f) && (m_util.is_arith_expr(args[0]) || m_util.is_arith_expr(args[1])))
|
||||
return factor(f, args[0], args[1], result);
|
||||
if (f->get_family_id() != m_util.get_family_id())
|
||||
return BR_FAILED;
|
||||
switch (f->get_decl_kind()) {
|
||||
case OP_LT:
|
||||
case OP_GT:
|
||||
case OP_LE:
|
||||
case OP_GE:
|
||||
return factor(f, args[0], args[1], result);
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
};
|
||||
|
||||
struct rw : public rewriter_tpl<rw_cfg> {
|
||||
rw_cfg m_cfg;
|
||||
|
||||
rw(ast_manager & m, params_ref const & p):
|
||||
rewriter_tpl<rw_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m, p) {
|
||||
}
|
||||
};
|
||||
|
||||
struct imp {
|
||||
ast_manager & m;
|
||||
rw m_rw;
|
||||
|
||||
imp(ast_manager & _m, params_ref const & p):
|
||||
m(_m),
|
||||
m_rw(m, p) {
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_rw.set_cancel(f);
|
||||
m_rw.cfg().m_pm.set_cancel(f);
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_rw.cfg().updt_params(p);
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
mc = 0; pc = 0; core = 0;
|
||||
tactic_report report("factor", *g);
|
||||
bool produce_proofs = g->proofs_enabled();
|
||||
|
||||
expr_ref new_curr(m);
|
||||
proof_ref new_pr(m);
|
||||
unsigned size = g->size();
|
||||
for (unsigned idx = 0; idx < size; idx++) {
|
||||
expr * curr = g->form(idx);
|
||||
m_rw(curr, new_curr, new_pr);
|
||||
if (produce_proofs) {
|
||||
proof * pr = g->pr(idx);
|
||||
new_pr = m.mk_modus_ponens(pr, new_pr);
|
||||
}
|
||||
g->update(idx, new_curr, new_pr, g->dep(idx));
|
||||
}
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
TRACE("factor", g->display(tout););
|
||||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
};
|
||||
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
public:
|
||||
factor_tactic(ast_manager & m, params_ref const & p):
|
||||
m_params(p) {
|
||||
m_imp = alloc(imp, m, p);
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(factor_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual ~factor_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_imp->m_rw.cfg().updt_params(p);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
r.insert(":split-factors", CPK_BOOL,
|
||||
"(default: true) apply simplifications such as (= (* p1 p2) 0) --> (or (= p1 0) (= p2 0)).");
|
||||
polynomial::factor_params::get_param_descrs(r);
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
try {
|
||||
(*m_imp)(in, result, mc, pc, core);
|
||||
}
|
||||
catch (z3_error & ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (z3_exception & ex) {
|
||||
throw tactic_exception(ex.msg());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m;
|
||||
imp * d = m_imp;
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = 0;
|
||||
}
|
||||
dealloc(d);
|
||||
d = alloc(imp, m, m_params);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = d;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_factor_tactic(ast_manager & m, params_ref const & p) {
|
||||
return clean(alloc(factor_tactic, m, p));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
factor_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Polynomial factorization tactic.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-02-03
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _FACTOR_TACTIC_H_
|
||||
#define _FACTOR_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_factor_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,200 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fpa2bv_converter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Conversion routines for Floating Point -> Bit-Vector
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2012-02-09
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _FPA2BV_CONVERTER_
|
||||
#define _FPA2BV_CONVERTER_
|
||||
|
||||
#include"ast.h"
|
||||
#include"obj_hashtable.h"
|
||||
#include"ref_util.h"
|
||||
#include"float_decl_plugin.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"model_converter.h"
|
||||
#include"basic_simplifier_plugin.h"
|
||||
|
||||
typedef enum { BV_RM_TIES_TO_AWAY=0, BV_RM_TIES_TO_EVEN=1, BV_RM_TO_NEGATIVE=2, BV_RM_TO_POSITIVE=3, BV_RM_TO_ZERO=4 } BV_RM_VAL;
|
||||
|
||||
class fpa2bv_model_converter;
|
||||
|
||||
class fpa2bv_converter {
|
||||
ast_manager & m;
|
||||
basic_simplifier_plugin m_simp;
|
||||
float_util m_util;
|
||||
mpf_manager & m_mpf_manager;
|
||||
unsynch_mpz_manager & m_mpz_manager;
|
||||
bv_util m_bv_util;
|
||||
float_decl_plugin * m_plugin;
|
||||
|
||||
obj_map<func_decl, expr*> m_const2bv;
|
||||
obj_map<func_decl, expr*> m_rm_const2bv;
|
||||
|
||||
public:
|
||||
fpa2bv_converter(ast_manager & m);
|
||||
~fpa2bv_converter();
|
||||
|
||||
float_util & fu() { return m_util; }
|
||||
|
||||
bool is_float(sort * s) { return m_util.is_float(s); }
|
||||
bool is_float(expr * e) { return is_app(e) && m_util.is_float(to_app(e)->get_decl()->get_range()); }
|
||||
bool is_float_family(func_decl * f) { return f->get_family_id() == m_util.get_family_id(); }
|
||||
bool is_rm_sort(sort * s) { return m_util.is_rm(s); }
|
||||
|
||||
void mk_triple(expr * sign, expr * significand, expr * exponent, expr_ref & result) {
|
||||
SASSERT(m_bv_util.is_bv(sign) && m_bv_util.get_bv_size(sign) == 1);
|
||||
SASSERT(m_bv_util.is_bv(significand));
|
||||
SASSERT(m_bv_util.is_bv(exponent));
|
||||
result = m.mk_app(m_util.get_family_id(), OP_TO_FLOAT, sign, significand, exponent);
|
||||
}
|
||||
|
||||
void mk_eq(expr * a, expr * b, expr_ref & result);
|
||||
void mk_ite(expr * c, expr * t, expr * f, expr_ref & result);
|
||||
|
||||
void mk_rounding_mode(func_decl * f, expr_ref & result);
|
||||
void mk_value(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_const(func_decl * f, expr_ref & result);
|
||||
void mk_rm_const(func_decl * f, expr_ref & result);
|
||||
|
||||
void mk_plus_inf(func_decl * f, expr_ref & result);
|
||||
void mk_minus_inf(func_decl * f, expr_ref & result);
|
||||
void mk_nan(func_decl * f, expr_ref & result);
|
||||
void mk_nzero(func_decl *f, expr_ref & result);
|
||||
void mk_pzero(func_decl *f, expr_ref & result);
|
||||
|
||||
void mk_add(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_sub(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_uminus(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_div(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_remainder(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_abs(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_fusedma(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_sqrt(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_round_to_integral(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
void mk_float_eq(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_float_lt(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_float_gt(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_float_le(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_float_ge(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
void mk_is_zero(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_is_nzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_is_pzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
void mk_is_sign_minus(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
void mk_to_float(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
fpa2bv_model_converter * mk_model_converter();
|
||||
|
||||
void dbg_decouple(const char * prefix, expr_ref & e);
|
||||
expr_ref_vector extra_assertions;
|
||||
|
||||
protected:
|
||||
void split(expr * e, expr * & sgn, expr * & sig, expr * & exp) const;
|
||||
|
||||
void mk_is_nan(expr * e, expr_ref & result);
|
||||
void mk_is_inf(expr * e, expr_ref & result);
|
||||
void mk_is_pinf(expr * e, expr_ref & result);
|
||||
void mk_is_ninf(expr * e, expr_ref & result);
|
||||
void mk_is_pos(expr * e, expr_ref & result);
|
||||
void mk_is_neg(expr * e, expr_ref & result);
|
||||
void mk_is_zero(expr * e, expr_ref & result);
|
||||
void mk_is_nzero(expr * e, expr_ref & result);
|
||||
void mk_is_pzero(expr * e, expr_ref & result);
|
||||
void mk_is_denormal(expr * e, expr_ref & result);
|
||||
void mk_is_normal(expr * e, expr_ref & result);
|
||||
|
||||
void mk_is_rm(expr * e, BV_RM_VAL rm, expr_ref & result);
|
||||
|
||||
void mk_top_exp(unsigned sz, expr_ref & result);
|
||||
void mk_bot_exp(unsigned sz, expr_ref & result);
|
||||
void mk_min_exp(unsigned ebits, expr_ref & result);
|
||||
void mk_max_exp(unsigned ebits, expr_ref & result);
|
||||
|
||||
void mk_leading_zeros(expr * e, unsigned max_bits, expr_ref & result);
|
||||
|
||||
void mk_bias(expr * e, expr_ref & result);
|
||||
void mk_unbias(expr * e, expr_ref & result);
|
||||
|
||||
void unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, bool normalize);
|
||||
void round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & result);
|
||||
|
||||
void add_core(unsigned sbits, unsigned ebits, expr_ref & rm,
|
||||
expr_ref & c_sgn, expr_ref & c_sig, expr_ref & c_exp, expr_ref & d_sgn, expr_ref & d_sig, expr_ref & d_exp,
|
||||
expr_ref & res_sgn, expr_ref & res_sig, expr_ref & res_exp);
|
||||
};
|
||||
|
||||
|
||||
class fpa2bv_model_converter : public model_converter {
|
||||
ast_manager & m;
|
||||
obj_map<func_decl, expr*> m_const2bv;
|
||||
obj_map<func_decl, expr*> m_rm_const2bv;
|
||||
|
||||
public:
|
||||
fpa2bv_model_converter(ast_manager & m, obj_map<func_decl, expr*> & const2bv,
|
||||
obj_map<func_decl, expr*> & rm_const2bv) :
|
||||
m(m) {
|
||||
// Just create a copy?
|
||||
for (obj_map<func_decl, expr*>::iterator it = const2bv.begin();
|
||||
it != const2bv.end();
|
||||
it++)
|
||||
{
|
||||
m_const2bv.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value);
|
||||
}
|
||||
for (obj_map<func_decl, expr*>::iterator it = rm_const2bv.begin();
|
||||
it != rm_const2bv.end();
|
||||
it++)
|
||||
{
|
||||
m_rm_const2bv.insert(it->m_key, it->m_value);
|
||||
m.inc_ref(it->m_key);
|
||||
m.inc_ref(it->m_value);
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~fpa2bv_model_converter() {
|
||||
dec_ref_map_key_values(m, m_const2bv);
|
||||
dec_ref_map_key_values(m, m_rm_const2bv);
|
||||
}
|
||||
|
||||
virtual void operator()(model_ref & md, unsigned goal_idx) {
|
||||
SASSERT(goal_idx == 0);
|
||||
model * new_model = alloc(model, m);
|
||||
obj_hashtable<func_decl> bits;
|
||||
convert(md.get(), new_model);
|
||||
md = new_model;
|
||||
}
|
||||
|
||||
virtual void operator()(model_ref & md) {
|
||||
operator()(md, 0);
|
||||
}
|
||||
|
||||
void display(std::ostream & out);
|
||||
|
||||
virtual model_converter * translate(ast_translation & translator);
|
||||
|
||||
protected:
|
||||
fpa2bv_model_converter(ast_manager & m) : m(m) { }
|
||||
|
||||
void convert(model * bv_mdl, model * float_mdl);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,310 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fpa2bv_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic that converts floating points to bit-vectors
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2012-02-09
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"cooperate.h"
|
||||
#include"ref_util.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"float_decl_plugin.h"
|
||||
#include"fpa2bv_converter.h"
|
||||
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
|
||||
#include"fpa2bv_tactic.h"
|
||||
|
||||
struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
|
||||
ast_manager & m_manager;
|
||||
expr_ref_vector m_out;
|
||||
fpa2bv_converter & m_conv;
|
||||
|
||||
unsigned long long m_max_memory;
|
||||
unsigned m_max_steps;
|
||||
|
||||
ast_manager & m() const { return m_manager; }
|
||||
|
||||
fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, params_ref const & p):
|
||||
m_manager(m),
|
||||
m_out(m),
|
||||
m_conv(c) {
|
||||
updt_params(p);
|
||||
// We need to make sure that the mananger has the BV plugin loaded.
|
||||
symbol s_bv("bv");
|
||||
if (!m_manager.has_plugin(s_bv))
|
||||
m_manager.register_plugin(s_bv, alloc(bv_decl_plugin));
|
||||
}
|
||||
|
||||
~fpa2bv_rewriter_cfg() {
|
||||
}
|
||||
|
||||
void cleanup_buffers() {
|
||||
m_out.finalize();
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_max_memory = megabytes_to_bytes(p.get_uint(":max-memory", UINT_MAX));
|
||||
m_max_steps = p.get_uint(":max-steps", UINT_MAX);
|
||||
}
|
||||
|
||||
bool max_steps_exceeded(unsigned num_steps) const {
|
||||
cooperate("fpa2bv");
|
||||
if (memory::get_allocation_size() > m_max_memory)
|
||||
throw tactic_exception(TACTIC_MAX_MEMORY_MSG);
|
||||
return num_steps > m_max_steps;
|
||||
}
|
||||
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
TRACE("fpa2bv_rw", tout << "APP: " << f->get_name() << std::endl; );
|
||||
|
||||
if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_float(f->get_range())) {
|
||||
m_conv.mk_const(f, result);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_rm_sort(f->get_range())) {
|
||||
m_conv.mk_rm_const(f, result);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
if (m().is_eq(f)) {
|
||||
SASSERT(num == 2);
|
||||
if (m_conv.is_float(args[0])) {
|
||||
m_conv.mk_eq(args[0], args[1], result);
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
if (m().is_ite(f)) {
|
||||
SASSERT(num == 3);
|
||||
if (m_conv.is_float(args[1])) {
|
||||
m_conv.mk_ite(args[0], args[1], args[2], result);
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
if (m_conv.is_float_family(f)) {
|
||||
switch (f->get_decl_kind()) {
|
||||
case OP_RM_NEAREST_TIES_TO_AWAY:
|
||||
case OP_RM_NEAREST_TIES_TO_EVEN:
|
||||
case OP_RM_TOWARD_NEGATIVE:
|
||||
case OP_RM_TOWARD_POSITIVE:
|
||||
case OP_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE;
|
||||
case OP_FLOAT_VALUE: m_conv.mk_value(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_PLUS_INF: m_conv.mk_plus_inf(f, result); return BR_DONE;
|
||||
case OP_FLOAT_MINUS_INF: m_conv.mk_minus_inf(f, result); return BR_DONE;
|
||||
case OP_FLOAT_NAN: m_conv.mk_nan(f, result); return BR_DONE;
|
||||
case OP_FLOAT_ADD: m_conv.mk_add(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_SUB: m_conv.mk_sub(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_UMINUS: m_conv.mk_uminus(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_MUL: m_conv.mk_mul(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_REM: m_conv.mk_remainder(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_MIN: m_conv.mk_min(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_MAX: m_conv.mk_max(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_FUSED_MA: m_conv.mk_fusedma(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_EQ: m_conv.mk_float_eq(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_LT: m_conv.mk_float_lt(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_GT: m_conv.mk_float_gt(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_LE: m_conv.mk_float_le(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_GE: m_conv.mk_float_ge(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_IS_NZERO: m_conv.mk_is_nzero(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_IS_PZERO: m_conv.mk_is_pzero(f, num, args, result); return BR_DONE;
|
||||
case OP_FLOAT_IS_SIGN_MINUS: m_conv.mk_is_sign_minus(f, num, args, result); return BR_DONE;
|
||||
case OP_TO_FLOAT: m_conv.mk_to_float(f, num, args, result); return BR_DONE;
|
||||
default:
|
||||
TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n";
|
||||
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
|
||||
throw tactic_exception("NYI");
|
||||
}
|
||||
}
|
||||
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
bool reduce_quantifier(quantifier * old_q,
|
||||
expr * new_body,
|
||||
expr * const * new_patterns,
|
||||
expr * const * new_no_patterns,
|
||||
expr_ref & result,
|
||||
proof_ref & result_pr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template class rewriter_tpl<fpa2bv_rewriter_cfg>;
|
||||
|
||||
struct fpa2bv_rewriter : public rewriter_tpl<fpa2bv_rewriter_cfg> {
|
||||
fpa2bv_rewriter_cfg m_cfg;
|
||||
fpa2bv_rewriter(ast_manager & m, fpa2bv_converter & c, params_ref const & p):
|
||||
rewriter_tpl<fpa2bv_rewriter_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m, c, p) {
|
||||
}
|
||||
};
|
||||
|
||||
class fpa2bv_tactic : public tactic {
|
||||
struct imp {
|
||||
ast_manager & m;
|
||||
fpa2bv_converter m_conv;
|
||||
fpa2bv_rewriter m_rw;
|
||||
unsigned m_num_steps;
|
||||
|
||||
bool m_proofs_enabled;
|
||||
bool m_produce_models;
|
||||
bool m_produce_unsat_cores;
|
||||
|
||||
imp(ast_manager & _m, params_ref const & p):
|
||||
m(_m),
|
||||
m_conv(m),
|
||||
m_rw(m, m_conv, p),
|
||||
m_proofs_enabled(false),
|
||||
m_produce_models(false),
|
||||
m_produce_unsat_cores(false) {
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_rw.cfg().updt_params(p);
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_rw.set_cancel(f);
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
fail_if_proof_generation("fpa2bv", g);
|
||||
fail_if_unsat_core_generation("fpa2bv", g);
|
||||
m_proofs_enabled = g->proofs_enabled();
|
||||
m_produce_models = g->models_enabled();
|
||||
m_produce_unsat_cores = g->unsat_core_enabled();
|
||||
|
||||
mc = 0; pc = 0; core = 0; result.reset();
|
||||
tactic_report report("fpa2bv", *g);
|
||||
m_rw.reset();
|
||||
|
||||
TRACE("fpa2bv", tout << "BEFORE: " << std::endl; g->display(tout););
|
||||
|
||||
if (g->inconsistent()) {
|
||||
result.push_back(g.get());
|
||||
return;
|
||||
}
|
||||
|
||||
m_num_steps = 0;
|
||||
expr_ref new_curr(m);
|
||||
proof_ref new_pr(m);
|
||||
unsigned size = g->size();
|
||||
for (unsigned idx = 0; idx < size; idx++) {
|
||||
if (g->inconsistent())
|
||||
break;
|
||||
expr * curr = g->form(idx);
|
||||
m_rw(curr, new_curr, new_pr);
|
||||
m_num_steps += m_rw.get_num_steps();
|
||||
if (m_proofs_enabled) {
|
||||
proof * pr = g->pr(idx);
|
||||
new_pr = m.mk_modus_ponens(pr, new_pr);
|
||||
}
|
||||
g->update(idx, new_curr, new_pr, g->dep(idx));
|
||||
}
|
||||
|
||||
if (g->models_enabled())
|
||||
mc = m_conv.mk_model_converter();
|
||||
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
|
||||
for (unsigned i = 0; i < m_conv.extra_assertions.size(); i++)
|
||||
result.back()->assert_expr(m_conv.extra_assertions[i].get());
|
||||
|
||||
SASSERT(g->is_well_sorted());
|
||||
TRACE("fpa2bv", tout << "AFTER: " << std::endl; g->display(tout);
|
||||
if (mc) mc->display(tout); tout << std::endl; );
|
||||
}
|
||||
};
|
||||
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
|
||||
public:
|
||||
fpa2bv_tactic(ast_manager & m, params_ref const & p):
|
||||
m_params(p) {
|
||||
m_imp = alloc(imp, m, p);
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(fpa2bv_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual ~fpa2bv_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_imp->updt_params(p);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
(*m_imp)(in, result, mc, pc, core);
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m;
|
||||
imp * d = m_imp;
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
d = m_imp;
|
||||
}
|
||||
dealloc(d);
|
||||
d = alloc(imp, m, m_params);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = d;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_fpa2bv_tactic(ast_manager & m, params_ref const & p) {
|
||||
return clean(alloc(fpa2bv_tactic, m, p));
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fpa2bv_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic that converts floating points to bit-vectors
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2012-02-09
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _FPA2BV_TACTIC_
|
||||
#define _FPA2BV_TACTIC_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_fpa2bv_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,309 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
goal2nlsat.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
"Compile" a goal into the nonlinear arithmetic engine.
|
||||
Non-arithmetic atoms are "abstracted" into boolean variables.
|
||||
Non-supported terms are "abstracted" into variables.
|
||||
|
||||
The mappings can be used to convert back the state of the
|
||||
engine into a goal.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-01-02
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"goal2nlsat.h"
|
||||
#include"goal.h"
|
||||
#include"goal_util.h"
|
||||
#include"nlsat_solver.h"
|
||||
#include"expr2polynomial.h"
|
||||
#include"expr2var.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"tactic.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
|
||||
struct goal2nlsat::imp {
|
||||
struct nlsat_expr2polynomial : public expr2polynomial {
|
||||
nlsat::solver & m_solver;
|
||||
nlsat_expr2polynomial(nlsat::solver & s, ast_manager & m, polynomial::manager & pm, expr2var * e2v):
|
||||
expr2polynomial(m, pm, e2v),
|
||||
m_solver(s) {
|
||||
}
|
||||
|
||||
virtual bool is_int(polynomial::var x) const {
|
||||
return m_solver.is_int(x);
|
||||
}
|
||||
|
||||
virtual polynomial::var mk_var(bool is_int) {
|
||||
return m_solver.mk_var(is_int);
|
||||
}
|
||||
};
|
||||
|
||||
ast_manager & m;
|
||||
nlsat::solver & m_solver;
|
||||
polynomial::manager & m_pm;
|
||||
unsynch_mpq_manager & m_qm;
|
||||
arith_util m_util;
|
||||
expr2var & m_a2b;
|
||||
expr2var & m_t2x;
|
||||
nlsat_expr2polynomial m_expr2poly;
|
||||
polynomial::factor_params m_fparams;
|
||||
|
||||
unsigned long long m_max_memory;
|
||||
bool m_factor;
|
||||
|
||||
volatile bool m_cancel;
|
||||
|
||||
imp(ast_manager & _m, params_ref const & p, nlsat::solver & s, expr2var & a2b, expr2var & t2x):
|
||||
m(_m),
|
||||
m_solver(s),
|
||||
m_pm(s.pm()),
|
||||
m_qm(s.qm()),
|
||||
m_util(m),
|
||||
m_a2b(a2b),
|
||||
m_t2x(t2x),
|
||||
m_expr2poly(m_solver, m, m_solver.pm(), &m_t2x) {
|
||||
updt_params(p);
|
||||
m_cancel = false;
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_max_memory = megabytes_to_bytes(p.get_uint(":max-memory", UINT_MAX));
|
||||
m_factor = p.get_bool(":factor", true);
|
||||
m_fparams.updt_params(p);
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_cancel = f;
|
||||
m_pm.set_cancel(f);
|
||||
}
|
||||
|
||||
nlsat::atom::kind flip(nlsat::atom::kind k) {
|
||||
switch (k) {
|
||||
case nlsat::atom::EQ: return k;
|
||||
case nlsat::atom::LT: return nlsat::atom::GT;
|
||||
case nlsat::atom::GT: return nlsat::atom::LT;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return k;
|
||||
}
|
||||
}
|
||||
|
||||
nlsat::bool_var factor_atom(polynomial::polynomial * p, nlsat::atom::kind k) {
|
||||
sbuffer<bool> is_even;
|
||||
ptr_buffer<polynomial::polynomial> ps;
|
||||
polynomial::factors fs(m_pm);
|
||||
m_pm.factor(p, fs, m_fparams);
|
||||
TRACE("goal2nlsat_bug", tout << "factors:\n" << fs << "\n";);
|
||||
SASSERT(fs.distinct_factors() > 0);
|
||||
for (unsigned i = 0; i < fs.distinct_factors(); i++) {
|
||||
ps.push_back(fs[i]);
|
||||
is_even.push_back(fs.get_degree(i) % 2 == 0);
|
||||
}
|
||||
if (m_qm.is_neg(fs.get_constant()))
|
||||
k = flip(k);
|
||||
return m_solver.mk_ineq_atom(k, ps.size(), ps.c_ptr(), is_even.c_ptr());
|
||||
}
|
||||
|
||||
nlsat::literal process_atom(app * f, nlsat::atom::kind k) {
|
||||
SASSERT(f->get_num_args() == 2);
|
||||
expr * lhs = f->get_arg(0);
|
||||
expr * rhs = f->get_arg(1);
|
||||
polynomial_ref p1(m_pm);
|
||||
polynomial_ref p2(m_pm);
|
||||
scoped_mpz d1(m_qm);
|
||||
scoped_mpz d2(m_qm);
|
||||
m_expr2poly.to_polynomial(lhs, p1, d1);
|
||||
m_expr2poly.to_polynomial(rhs, p2, d2);
|
||||
scoped_mpz lcm(m_qm);
|
||||
m_qm.lcm(d1, d2, lcm);
|
||||
m_qm.div(lcm, d1, d1);
|
||||
m_qm.div(lcm, d2, d2);
|
||||
m_qm.neg(d2);
|
||||
polynomial_ref p(m_pm);
|
||||
p = m_pm.addmul(d1, m_pm.mk_unit(), p1, d2, m_pm.mk_unit(), p2);
|
||||
TRACE("goal2nlsat_bug", tout << "p: " << p << "\nk: " << k << "\n";);
|
||||
if (is_const(p)) {
|
||||
int sign;
|
||||
if (is_zero(p))
|
||||
sign = 0;
|
||||
else
|
||||
sign = m_qm.is_pos(m_pm.coeff(p, 0)) ? 1 : -1;
|
||||
switch (k) {
|
||||
case nlsat::atom::EQ: return sign == 0 ? nlsat::true_literal : nlsat::false_literal;
|
||||
case nlsat::atom::LT: return sign < 0 ? nlsat::true_literal : nlsat::false_literal;
|
||||
case nlsat::atom::GT: return sign > 0 ? nlsat::true_literal : nlsat::false_literal;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return nlsat::true_literal;
|
||||
}
|
||||
}
|
||||
if (m_factor) {
|
||||
return nlsat::literal(factor_atom(p, k), false);
|
||||
}
|
||||
else {
|
||||
bool is_even = false;
|
||||
polynomial::polynomial * _p = p.get();
|
||||
return nlsat::literal(m_solver.mk_ineq_atom(k, 1, &_p, &is_even), false);
|
||||
}
|
||||
}
|
||||
|
||||
nlsat::literal process_eq(app * f) {
|
||||
return process_atom(f, nlsat::atom::EQ);
|
||||
}
|
||||
|
||||
nlsat::literal process_le(app * f) {
|
||||
return ~process_atom(f, nlsat::atom::GT);
|
||||
}
|
||||
|
||||
nlsat::literal process_ge(app * f) {
|
||||
return ~process_atom(f, nlsat::atom::LT);
|
||||
}
|
||||
|
||||
// everything else is compiled as a boolean variable
|
||||
nlsat::bool_var process_bvar(expr * f) {
|
||||
if (m_a2b.is_var(f)) {
|
||||
return static_cast<nlsat::bool_var>(m_a2b.to_var(f));
|
||||
}
|
||||
else {
|
||||
nlsat::bool_var b = m_solver.mk_bool_var();
|
||||
m_a2b.insert(f, b);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
nlsat::literal process_atom(expr * f) {
|
||||
if (m.is_eq(f)) {
|
||||
if (m_util.is_int_real(to_app(f)->get_arg(0)))
|
||||
return process_eq(to_app(f));
|
||||
else
|
||||
return nlsat::literal(process_bvar(f), false);
|
||||
}
|
||||
else if (m_util.is_le(f)) {
|
||||
return process_le(to_app(f));
|
||||
}
|
||||
else if (m_util.is_ge(f)) {
|
||||
return process_ge(to_app(f));
|
||||
}
|
||||
else if (is_app(f)) {
|
||||
if (to_app(f)->get_family_id() == m.get_basic_family_id()) {
|
||||
switch (to_app(f)->get_decl_kind()) {
|
||||
case OP_TRUE:
|
||||
case OP_FALSE:
|
||||
TRACE("goal2nlsat", tout << "f: " << mk_ismt2_pp(f, m) << "\n";);
|
||||
throw tactic_exception("apply simplify before applying nlsat");
|
||||
case OP_AND:
|
||||
case OP_OR:
|
||||
case OP_IFF:
|
||||
case OP_XOR:
|
||||
case OP_NOT:
|
||||
case OP_IMPLIES:
|
||||
throw tactic_exception("convert goal into cnf before applying nlsat");
|
||||
case OP_DISTINCT:
|
||||
throw tactic_exception("eliminate distinct operator (use tactic '(using-params simplify :blast-distinct true)') before applying nlsat");
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return nlsat::literal(nlsat::null_bool_var, false);
|
||||
}
|
||||
}
|
||||
else if (to_app(f)->get_family_id() == m_util.get_family_id()) {
|
||||
throw tactic_exception("apply purify-arith before applying nlsat");
|
||||
}
|
||||
else {
|
||||
return nlsat::literal(process_bvar(f), false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(is_quantifier(f));
|
||||
return nlsat::literal(process_bvar(f), false);
|
||||
}
|
||||
}
|
||||
|
||||
nlsat::literal process_literal(expr * f) {
|
||||
bool neg = false;
|
||||
while (m.is_not(f, f))
|
||||
neg = !neg;
|
||||
nlsat::literal l = process_atom(f);
|
||||
if (neg)
|
||||
l.neg();
|
||||
return l;
|
||||
}
|
||||
|
||||
void process(expr * f, expr_dependency * dep) {
|
||||
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;
|
||||
}
|
||||
sbuffer<nlsat::literal> ls;
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
ls.push_back(process_literal(lits[i]));
|
||||
}
|
||||
m_solver.mk_clause(ls.size(), ls.c_ptr(), dep);
|
||||
}
|
||||
|
||||
void operator()(goal const & g) {
|
||||
if (has_term_ite(g))
|
||||
throw tactic_exception("eliminate term-ite before applying nlsat");
|
||||
unsigned sz = g.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
process(g.form(i), g.dep(i));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct goal2nlsat::scoped_set_imp {
|
||||
goal2nlsat & m_owner;
|
||||
scoped_set_imp(goal2nlsat & o, imp & i):m_owner(o) {
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_owner.m_imp = &i;
|
||||
}
|
||||
}
|
||||
|
||||
~scoped_set_imp() {
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_owner.m_imp = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
goal2nlsat::goal2nlsat() {
|
||||
m_imp = 0;
|
||||
}
|
||||
|
||||
goal2nlsat::~goal2nlsat() {
|
||||
SASSERT(m_imp == 0);
|
||||
}
|
||||
|
||||
void goal2nlsat::collect_param_descrs(param_descrs & r) {
|
||||
insert_max_memory(r);
|
||||
r.insert(":factor", CPK_BOOL, "(default: true) factor polynomials.");
|
||||
polynomial::factor_params::get_param_descrs(r);
|
||||
}
|
||||
|
||||
void goal2nlsat::operator()(goal const & g, params_ref const & p, nlsat::solver & s, expr2var & a2b, expr2var & t2x) {
|
||||
imp local_imp(g.m(), p, s, a2b, t2x);
|
||||
scoped_set_imp setter(*this, local_imp);
|
||||
local_imp(g);
|
||||
}
|
||||
|
||||
void goal2nlsat::set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
goal2nlsat.h
|
||||
|
||||
Abstract:
|
||||
|
||||
"Compile" a goal into the nonlinear arithmetic engine.
|
||||
Non-arithmetic atoms are "abstracted" into boolean variables.
|
||||
Non-supported terms are "abstracted" into variables.
|
||||
|
||||
The mappings can be used to convert back the state of the
|
||||
engine into a goal.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-01-02
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _GOAL2NLSAT_H_
|
||||
#define _GOAL2NLSAT_H_
|
||||
|
||||
#include"nlsat_types.h"
|
||||
#include"model_converter.h"
|
||||
|
||||
class goal;
|
||||
class expr2var;
|
||||
|
||||
class goal2nlsat {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
struct scoped_set_imp;
|
||||
public:
|
||||
goal2nlsat();
|
||||
~goal2nlsat();
|
||||
|
||||
static void collect_param_descrs(param_descrs & r);
|
||||
|
||||
/**
|
||||
\brief "Compile" the goal into the given nlsat engine.
|
||||
Store a mapping from atoms to boolean variables into a2b.
|
||||
Store a mapping from terms into arithmetic variables into t2x.
|
||||
|
||||
\remark a2b and t2x m don't need to be empty. The definitions there are reused.
|
||||
|
||||
The input is expected to be in CNF
|
||||
*/
|
||||
void operator()(goal const & g, params_ref const & p, nlsat::solver & s, expr2var & a2b, expr2var & t2x);
|
||||
|
||||
void set_cancel(bool f);
|
||||
};
|
||||
|
||||
class nlsat2goal {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
public:
|
||||
nlsat2goal();
|
||||
~nlsat2goal();
|
||||
|
||||
static void collect_param_descrs(param_descrs & r);
|
||||
|
||||
/**
|
||||
\brief Translate the state of the nlsat engine back into a goal.
|
||||
*/
|
||||
void operator()(nlsat::solver const & s, expr2var const & a2b, expr2var const & t2x,
|
||||
params_ref const & p, goal & g, model_converter_ref & mc);
|
||||
|
||||
void set_cancel(bool f);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,424 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
lru_cache.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
expr -> expr LRU cache
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-04-12
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"lru_cache.h"
|
||||
#include"ast_ll_pp.h"
|
||||
|
||||
#define MIN_MAX_SIZE 1024
|
||||
#define INITIAL_CAPACITY 128
|
||||
|
||||
lru_cache::cell * lru_cache::allocate(unsigned capacity) {
|
||||
cell * mem = static_cast<cell*>(memory::allocate(sizeof(cell) * capacity));
|
||||
memset(mem, 0, sizeof(cell)*capacity);
|
||||
return mem;
|
||||
}
|
||||
|
||||
void lru_cache::deallocate(cell * table) {
|
||||
memory::deallocate(table);
|
||||
}
|
||||
|
||||
lru_cache::cell * lru_cache::copy_table(cell * old_head, cell * new_table, unsigned new_capacity) {
|
||||
SASSERT(old_head);
|
||||
cell * it = old_head;
|
||||
cell * new_head = 0;
|
||||
cell * prev = 0;
|
||||
do {
|
||||
expr * k = it->m_key;
|
||||
unsigned h = k->hash();
|
||||
unsigned mask = new_capacity - 1;
|
||||
unsigned idx = h & mask;
|
||||
|
||||
cell * begin = new_table + idx;
|
||||
cell * end = new_table + new_capacity;
|
||||
cell * curr = begin;
|
||||
|
||||
for (; curr != end; ++curr) {
|
||||
if (curr->m_key == 0) {
|
||||
curr->m_key = k;
|
||||
curr->m_value = it->m_value;
|
||||
LCS_CODE(curr->m_hits = it->m_hits;);
|
||||
LCS_CODE(curr->m_birthday = it->m_birthday;);
|
||||
if (prev == 0) {
|
||||
new_head = curr;
|
||||
}
|
||||
else {
|
||||
prev->m_next = curr;
|
||||
curr->m_prev = prev;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
for (curr = new_table; curr != begin; ++curr) {
|
||||
if (curr->m_key == 0) {
|
||||
curr->m_key = k;
|
||||
curr->m_value = it->m_value;
|
||||
SASSERT(prev != 0);
|
||||
prev->m_next = curr;
|
||||
curr->m_prev = prev;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
UNREACHABLE();
|
||||
end:
|
||||
prev = curr;
|
||||
it = it->m_next;
|
||||
}
|
||||
while (it != old_head);
|
||||
prev->m_next = new_head;
|
||||
new_head->m_prev = prev;
|
||||
return new_head;
|
||||
}
|
||||
|
||||
void lru_cache::expand_table() {
|
||||
SASSERT(m_head);
|
||||
unsigned new_capacity = m_capacity * 2;
|
||||
TRACE("lru_cache", tout << "expanding table new_capacity: " << new_capacity << "\n";);
|
||||
cell * new_table = allocate(new_capacity);
|
||||
m_head = copy_table(m_head, new_table, new_capacity);
|
||||
deallocate(m_table);
|
||||
m_table = new_table;
|
||||
m_capacity = new_capacity;
|
||||
m_num_deleted = 0;
|
||||
SASSERT(check_invariant());
|
||||
}
|
||||
|
||||
void lru_cache::remove_deleted() {
|
||||
SASSERT(m_head);
|
||||
TRACE("lru_cache", tout << "removing deleted entries\n";);
|
||||
cell * new_table = allocate(m_capacity);
|
||||
m_head = copy_table(m_head, new_table, m_capacity);
|
||||
deallocate(m_table);
|
||||
m_table = new_table;
|
||||
m_num_deleted = 0;
|
||||
SASSERT(check_invariant());
|
||||
}
|
||||
|
||||
void lru_cache::init() {
|
||||
if (m_max_size < MIN_MAX_SIZE)
|
||||
m_max_size = MIN_MAX_SIZE;
|
||||
m_size = 0;
|
||||
m_capacity = INITIAL_CAPACITY;
|
||||
m_table = allocate(m_capacity);
|
||||
m_head = 0;
|
||||
m_num_deleted = 0;
|
||||
}
|
||||
|
||||
lru_cache::lru_cache(ast_manager & m):
|
||||
m_manager(m),
|
||||
m_max_size(m.get_num_asts() * 100) {
|
||||
init();
|
||||
TRACE("lru_cache", tout << "new lru cache, max-size: " << m_max_size << "\n";);
|
||||
}
|
||||
|
||||
lru_cache::lru_cache(ast_manager & m, unsigned max_size):
|
||||
m_manager(m),
|
||||
m_max_size(max_size) {
|
||||
init();
|
||||
}
|
||||
|
||||
void lru_cache::dec_refs() {
|
||||
if (m_head) {
|
||||
cell * curr = m_head;
|
||||
#ifdef Z3DEBUG
|
||||
unsigned sz = 0;
|
||||
#endif
|
||||
do {
|
||||
m_manager.dec_ref(curr->m_key);
|
||||
m_manager.dec_ref(curr->m_value);
|
||||
curr = curr->m_next;
|
||||
DEBUG_CODE(sz++;);
|
||||
}
|
||||
while (curr != m_head);
|
||||
SASSERT(sz == m_size);
|
||||
}
|
||||
}
|
||||
|
||||
lru_cache::~lru_cache() {
|
||||
TRACE("lru_cache", tout << "destructor invoked size: " << m_size << ", m_head: " << m_head << "\n";);
|
||||
LCS_CODE({
|
||||
if (m_head) {
|
||||
unsigned used = 0;
|
||||
cell * curr = m_head;
|
||||
do {
|
||||
if (curr->m_hits > 0)
|
||||
used++;
|
||||
curr = curr->m_next;
|
||||
}
|
||||
while (curr != m_head);
|
||||
verbose_stream() << "[lru_cache] num-used: " << used << " size: " << m_size << "\n";
|
||||
}
|
||||
});
|
||||
SASSERT(check_invariant());
|
||||
dec_refs();
|
||||
deallocate(m_table);
|
||||
}
|
||||
|
||||
void lru_cache::del_least_used() {
|
||||
SASSERT(m_head);
|
||||
SASSERT(m_size >= 2);
|
||||
cell * c = m_head->m_prev;
|
||||
TRACE("lru_cache", tout << "del least used: " << mk_bounded_pp(c->m_key, m_manager, 3) << "\n";);
|
||||
LCS_CODE({
|
||||
static unsigned non_zero = 0;
|
||||
static unsigned long long total_hits;
|
||||
static unsigned counter = 0;
|
||||
if (c->m_hits > 0) {
|
||||
counter++;
|
||||
total_hits += c->m_hits;
|
||||
non_zero++;
|
||||
if (non_zero % 1000 == 0)
|
||||
verbose_stream() << "[lru_cache] cell with non-zero hits was deleted: " << non_zero << " avg: " << ((double)total_hits/(double) counter) << std::endl;
|
||||
}
|
||||
});
|
||||
SASSERT(c->m_prev != c);
|
||||
SASSERT(c->m_next != c);
|
||||
m_manager.dec_ref(c->m_key);
|
||||
m_manager.dec_ref(c->m_value);
|
||||
c->m_prev->m_next = c->m_next;
|
||||
c->m_next->m_prev = c->m_prev;
|
||||
SASSERT(m_head->m_prev == c->m_prev);
|
||||
c->m_key = reinterpret_cast<expr*>(1);
|
||||
c->m_prev = 0;
|
||||
c->m_next = 0;
|
||||
m_size--;
|
||||
m_num_deleted++;
|
||||
CASSERT("lru_cache", check_invariant());
|
||||
if (m_num_deleted * 3 > m_capacity)
|
||||
remove_deleted();
|
||||
}
|
||||
|
||||
void lru_cache::add_front(cell * c) {
|
||||
SASSERT(c->m_next == 0);
|
||||
SASSERT(c->m_prev == 0);
|
||||
if (m_head == 0) {
|
||||
c->m_next = c;
|
||||
c->m_prev = c;
|
||||
m_head = c;
|
||||
}
|
||||
else {
|
||||
c->m_prev = m_head->m_prev;
|
||||
c->m_next = m_head;
|
||||
m_head->m_prev->m_next = c;
|
||||
m_head->m_prev = c;
|
||||
m_head = c;
|
||||
}
|
||||
CASSERT("lru_cache", check_invariant());
|
||||
SASSERT(m_head == c);
|
||||
}
|
||||
|
||||
void lru_cache::move_front(cell * c) {
|
||||
SASSERT(m_head);
|
||||
SASSERT(c->m_next);
|
||||
SASSERT(c->m_prev);
|
||||
if (m_head != c) {
|
||||
c->m_prev->m_next = c->m_next;
|
||||
c->m_next->m_prev = c->m_prev;
|
||||
|
||||
c->m_prev = m_head->m_prev;
|
||||
c->m_next = m_head;
|
||||
|
||||
m_head->m_prev->m_next = c;
|
||||
m_head->m_prev = c;
|
||||
|
||||
m_head = c;
|
||||
}
|
||||
CASSERT("lru_cache", check_invariant());
|
||||
SASSERT(m_head == c);
|
||||
}
|
||||
|
||||
void lru_cache::insert(expr * k, expr * v) {
|
||||
LCS_CODE(m_time++;);
|
||||
if (m_size == m_max_size)
|
||||
del_least_used();
|
||||
else if (m_size * 2 > m_capacity)
|
||||
expand_table();
|
||||
SASSERT(m_size < m_max_size);
|
||||
unsigned h = k->hash();
|
||||
unsigned mask = m_capacity - 1;
|
||||
unsigned idx = h & mask;
|
||||
|
||||
cell * begin = m_table + idx;
|
||||
cell * end = m_table + m_capacity;
|
||||
cell * curr = begin;
|
||||
cell * del_cell = 0;
|
||||
|
||||
#define INSERT_LOOP() \
|
||||
if (curr->m_key == 0) { \
|
||||
cell * new_cell; \
|
||||
if (del_cell) { \
|
||||
new_cell = del_cell; \
|
||||
m_num_deleted--; \
|
||||
} \
|
||||
else { \
|
||||
new_cell = curr; \
|
||||
} \
|
||||
m_manager.inc_ref(k); \
|
||||
m_manager.inc_ref(v); \
|
||||
new_cell->m_key = k; \
|
||||
new_cell->m_value = v; \
|
||||
LCS_CODE(new_cell->m_hits = 0;); \
|
||||
LCS_CODE(new_cell->m_birthday = m_time;); \
|
||||
m_size++; \
|
||||
add_front(new_cell); \
|
||||
return; \
|
||||
} \
|
||||
if (curr->m_key == reinterpret_cast<expr*>(1)) { \
|
||||
del_cell = curr; \
|
||||
continue; \
|
||||
} \
|
||||
if (curr->m_key == k) { \
|
||||
m_manager.inc_ref(v); \
|
||||
m_manager.dec_ref(curr->m_value); \
|
||||
curr->m_value = v; \
|
||||
LCS_CODE(curr->m_hits = 0;); \
|
||||
LCS_CODE(curr->m_birthday = m_time;); \
|
||||
move_front(curr); \
|
||||
return; \
|
||||
}
|
||||
|
||||
for (; curr != end; ++curr) {
|
||||
INSERT_LOOP();
|
||||
}
|
||||
for (curr = m_table; curr != begin; ++curr) {
|
||||
INSERT_LOOP();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
expr * lru_cache::find(expr * k) {
|
||||
unsigned h = k->hash();
|
||||
unsigned mask = m_capacity - 1;
|
||||
unsigned idx = h & mask;
|
||||
|
||||
#ifdef LRU_CACHE_STATISTICS
|
||||
static unsigned long long total_age = 0;
|
||||
static unsigned long long max_time = 0;
|
||||
static unsigned counter = 0;
|
||||
#define COLLECT() \
|
||||
if (curr->m_hits == 0) { \
|
||||
counter ++; \
|
||||
unsigned age = m_time - curr->m_birthday; \
|
||||
if (age > max_time) \
|
||||
max_time = age; \
|
||||
total_age += age; \
|
||||
if (counter % 1000 == 0) \
|
||||
verbose_stream() << "[lru_cache] avg time for first hit: " << ((double) total_age / (double) counter) << " max time: " << max_time << "\n"; \
|
||||
}
|
||||
#endif
|
||||
|
||||
cell * begin = m_table + idx;
|
||||
cell * end = m_table + m_capacity;
|
||||
cell * curr = begin;
|
||||
for (; curr != end; ++curr) {
|
||||
if (curr->m_key == k) {
|
||||
// LCS_CODE(COLLECT());
|
||||
LCS_CODE(if (curr->m_hits == 0 && m_time - curr->m_birthday >= 5000) return 0;)
|
||||
LCS_CODE(curr->m_hits++;);
|
||||
move_front(curr);
|
||||
return curr->m_value;
|
||||
}
|
||||
if (curr->m_key == 0)
|
||||
return 0;
|
||||
}
|
||||
for (curr = m_table; curr != begin; ++curr) {
|
||||
if (curr->m_key == k) {
|
||||
// LCS_CODE(COLLECT());
|
||||
LCS_CODE(curr->m_hits++;);
|
||||
LCS_CODE(if (curr->m_hits == 0 && m_time - curr->m_birthday >= 5000) return 0;);
|
||||
move_front(curr);
|
||||
return curr->m_value;
|
||||
}
|
||||
if (curr->m_key == 0)
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lru_cache::reset() {
|
||||
TRACE("lru_cache", tout << "reset... m_size: " << m_size << "\n";);
|
||||
LCS_CODE(m_time = 0;);
|
||||
if (m_head) {
|
||||
cell * curr = m_head;
|
||||
#ifdef Z3DEBUG
|
||||
unsigned sz = 0;
|
||||
#endif
|
||||
do {
|
||||
m_manager.dec_ref(curr->m_key);
|
||||
m_manager.dec_ref(curr->m_value);
|
||||
cell * next = curr->m_next;
|
||||
curr->m_key = 0;
|
||||
curr->m_value = 0;
|
||||
curr->m_next = 0;
|
||||
curr->m_prev = 0;
|
||||
LCS_CODE(curr->m_hits = 0;);
|
||||
LCS_CODE(curr->m_birthday = 0;);
|
||||
curr = next;
|
||||
DEBUG_CODE(sz++;);
|
||||
}
|
||||
while (curr != m_head);
|
||||
SASSERT(sz == m_size);
|
||||
m_head = 0;
|
||||
m_size = 0;
|
||||
SASSERT(check_invariant());
|
||||
}
|
||||
}
|
||||
|
||||
void lru_cache::cleanup() {
|
||||
dec_refs();
|
||||
deallocate(m_table);
|
||||
m_capacity = INITIAL_CAPACITY;
|
||||
m_table = allocate(m_capacity);
|
||||
m_head = 0;
|
||||
m_size = 0;
|
||||
m_num_deleted = 0;
|
||||
}
|
||||
|
||||
bool lru_cache::check_invariant() const {
|
||||
SASSERT(m_size <= m_max_size);
|
||||
cell * begin = m_table;
|
||||
cell * end = m_table + m_capacity;
|
||||
unsigned sz = 0;
|
||||
if (m_head) {
|
||||
cell * curr = m_head;
|
||||
do {
|
||||
sz++;
|
||||
SASSERT(curr->m_key != 0 && curr->m_key != reinterpret_cast<expr*>(1));
|
||||
SASSERT(curr->m_next->m_prev == curr);
|
||||
SASSERT(curr->m_prev->m_next == curr);
|
||||
SASSERT(curr < end);
|
||||
SASSERT(curr >= begin);
|
||||
curr = curr->m_next;
|
||||
}
|
||||
while (curr != m_head);
|
||||
}
|
||||
SASSERT(m_size == sz);
|
||||
sz = 0;
|
||||
unsigned num_deleted = 0;
|
||||
for (cell * it = begin; it != end; it++) {
|
||||
if (it->m_key == reinterpret_cast<expr*>(1)) {
|
||||
num_deleted++;
|
||||
continue;
|
||||
}
|
||||
if (it->m_key != 0) {
|
||||
sz++;
|
||||
}
|
||||
}
|
||||
SASSERT(m_size == sz);
|
||||
SASSERT(m_num_deleted == num_deleted);
|
||||
return true;
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
lru_cache.h
|
||||
|
||||
Abstract:
|
||||
|
||||
expr -> expr LRU cache
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-04-12
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _LRU_CACHE_H_
|
||||
#define _LRU_CACHE_H_
|
||||
|
||||
#include"ast.h"
|
||||
|
||||
// #define LRU_CACHE_STATISTICS
|
||||
|
||||
#ifdef LRU_CACHE_STATISTICS
|
||||
#define LCS_CODE(CODE) { CODE }
|
||||
#else
|
||||
#define LCS_CODE(CODE)
|
||||
#endif
|
||||
|
||||
class lru_cache {
|
||||
struct cell {
|
||||
expr * m_key;
|
||||
expr * m_value;
|
||||
cell * m_prev;
|
||||
cell * m_next;
|
||||
#ifdef LRU_CACHE_STATISTICS
|
||||
unsigned m_hits;
|
||||
unsigned m_birthday;
|
||||
#endif
|
||||
};
|
||||
|
||||
ast_manager & m_manager;
|
||||
cell * m_table;
|
||||
cell * m_head;
|
||||
unsigned m_size;
|
||||
unsigned m_max_size;
|
||||
unsigned m_capacity;
|
||||
unsigned m_num_deleted;
|
||||
#ifdef LRU_CACHE_STATISTICS
|
||||
unsigned m_time;
|
||||
#endif
|
||||
|
||||
static cell * allocate(unsigned capacity);
|
||||
static void deallocate(cell * table);
|
||||
static cell * copy_table(cell * old_head, cell * new_table, unsigned new_capacity);
|
||||
|
||||
void del_least_used();
|
||||
void add_front(cell * c);
|
||||
void move_front(cell * c);
|
||||
void expand_table();
|
||||
void remove_deleted();
|
||||
void init();
|
||||
void dec_refs();
|
||||
public:
|
||||
lru_cache(ast_manager & m);
|
||||
lru_cache(ast_manager & m, unsigned max_size);
|
||||
~lru_cache();
|
||||
void insert(expr * k, expr * v);
|
||||
expr * find(expr * k);
|
||||
void reset();
|
||||
void cleanup();
|
||||
unsigned size() const { return m_size; }
|
||||
unsigned capacity() const { return m_capacity; }
|
||||
bool empty() const { return m_size == 0; }
|
||||
bool check_invariant() const;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,337 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
max_bv_sharing_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Rewriter for "maximing" the number of shared terms.
|
||||
The idea is to rewrite AC terms to maximize sharing.
|
||||
This rewriter is particularly useful for reducing
|
||||
the number of Adders and Multipliers before "bit-blasting".
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-12-29.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"obj_pair_hashtable.h"
|
||||
#include"ast_lt.h"
|
||||
#include"cooperate.h"
|
||||
|
||||
class max_bv_sharing_tactic : public tactic {
|
||||
|
||||
struct rw_cfg : public default_rewriter_cfg {
|
||||
typedef std::pair<expr *, expr *> expr_pair;
|
||||
typedef obj_pair_hashtable<expr, expr> set;
|
||||
bv_util m_util;
|
||||
set m_add_apps;
|
||||
set m_mul_apps;
|
||||
set m_xor_apps;
|
||||
set m_or_apps;
|
||||
unsigned long long m_max_memory;
|
||||
unsigned m_max_steps;
|
||||
unsigned m_max_args;
|
||||
|
||||
ast_manager & m() const { return m_util.get_manager(); }
|
||||
|
||||
rw_cfg(ast_manager & m, params_ref const & p):
|
||||
m_util(m) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
m_add_apps.finalize();
|
||||
m_mul_apps.finalize();
|
||||
m_or_apps.finalize();
|
||||
m_xor_apps.finalize();
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_max_memory = megabytes_to_bytes(p.get_uint(":max-memory", UINT_MAX));
|
||||
m_max_steps = p.get_uint(":max-steps", UINT_MAX);
|
||||
m_max_args = p.get_uint(":max-args", 128);
|
||||
}
|
||||
|
||||
bool max_steps_exceeded(unsigned num_steps) const {
|
||||
cooperate("max bv sharing");
|
||||
if (memory::get_allocation_size() > m_max_memory)
|
||||
throw tactic_exception(TACTIC_MAX_MEMORY_MSG);
|
||||
return num_steps > m_max_steps;
|
||||
}
|
||||
|
||||
set & f2set(func_decl * f) {
|
||||
switch (f->get_decl_kind()) {
|
||||
case OP_BADD: return m_add_apps;
|
||||
case OP_BMUL: return m_mul_apps;
|
||||
case OP_BXOR: return m_xor_apps;
|
||||
case OP_BOR: return m_or_apps;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return m_or_apps; // avoid compilation error
|
||||
}
|
||||
}
|
||||
|
||||
expr * reuse(set & s, func_decl * f, expr * arg1, expr * arg2) {
|
||||
if (s.contains(expr_pair(arg1, arg2)))
|
||||
return m().mk_app(f, arg1, arg2);
|
||||
if (s.contains(expr_pair(arg2, arg1)))
|
||||
return m().mk_app(f, arg2, arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ref_count_lt {
|
||||
bool operator()(expr * t1, expr * t2) const {
|
||||
if (t1->get_ref_count() < t2->get_ref_count())
|
||||
return true;
|
||||
return (t1->get_ref_count() == t2->get_ref_count()) && lt(t1, t2);
|
||||
}
|
||||
};
|
||||
|
||||
br_status reduce_ac_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
set & s = f2set(f);
|
||||
|
||||
if (num_args == 2) {
|
||||
if (!m_util.is_numeral(args[0]) && !m_util.is_numeral(args[1]))
|
||||
s.insert(expr_pair(args[0], args[1]));
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
ptr_buffer<expr, 128> _args;
|
||||
bool first = false;
|
||||
expr * num = 0;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * arg = args[i];
|
||||
if (num == 0 && m_util.is_numeral(arg)) {
|
||||
if (i == 0) first = true;
|
||||
num = arg;
|
||||
}
|
||||
else {
|
||||
_args.push_back(arg);
|
||||
}
|
||||
}
|
||||
num_args = _args.size();
|
||||
|
||||
|
||||
// std::sort(_args.begin(), _args.end(), ref_count_lt());
|
||||
// std::sort(_args.begin(), _args.end(), ast_to_lt());
|
||||
|
||||
try_to_reuse:
|
||||
if (num_args > 1 && num_args < m_max_args) {
|
||||
for (unsigned i = 0; i < num_args - 1; i++) {
|
||||
for (unsigned j = i + 1; j < num_args; j++) {
|
||||
expr * r = reuse(s, f, _args[i], _args[j]);
|
||||
if (r != 0) {
|
||||
TRACE("bv_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";);
|
||||
_args[i] = r;
|
||||
SASSERT(num_args > 1);
|
||||
for (unsigned w = j; w < num_args - 1; w++) {
|
||||
_args[w] = _args[w+1];
|
||||
}
|
||||
num_args--;
|
||||
goto try_to_reuse;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// some benchmarks are more efficiently solved using a tree-like structure (better sharing)
|
||||
// other benchmarks are more efficiently solved using a chain-like structure (better propagation for arguments "closer to the output").
|
||||
//
|
||||
// One possible solution is to do a global analysis that finds a good order that increases sharing without affecting
|
||||
// propagation.
|
||||
//
|
||||
// Another cheap trick is to create an option, and try both for a small amount of time.
|
||||
#if 0
|
||||
SASSERT(num_args > 0);
|
||||
if (num_args == 1) {
|
||||
result = _args[0];
|
||||
}
|
||||
else {
|
||||
// ref_count_lt is not a total order on expr's
|
||||
std::stable_sort(_args.c_ptr(), _args.c_ptr() + num_args, ref_count_lt());
|
||||
result = m().mk_app(f, _args[0], _args[1]);
|
||||
for (unsigned i = 2; i < num_args; i++) {
|
||||
result = m().mk_app(f, result.get(), _args[i]);
|
||||
}
|
||||
}
|
||||
if (num != 0) {
|
||||
if (first)
|
||||
result = m().mk_app(f, num, result);
|
||||
else
|
||||
result = m().mk_app(f, result, num);
|
||||
}
|
||||
return BR_DONE;
|
||||
#else
|
||||
// Create "tree-like circuit"
|
||||
while (true) {
|
||||
TRACE("bv_sharing_detail", tout << "tree-loop: num_args: " << num_args << "\n";);
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < num_args; i += 2, j++) {
|
||||
if (i == num_args - 1) {
|
||||
_args[j] = _args[i];
|
||||
}
|
||||
else {
|
||||
s.insert(expr_pair(_args[i], _args[i+1]));
|
||||
_args[j] = m().mk_app(f, _args[i], _args[i+1]);
|
||||
}
|
||||
}
|
||||
num_args = j;
|
||||
if (num_args == 1) {
|
||||
if (num == 0) {
|
||||
result = _args[0];
|
||||
}
|
||||
else {
|
||||
if (first)
|
||||
result = m().mk_app(f, num, _args[0]);
|
||||
else
|
||||
result = m().mk_app(f, _args[0], num);
|
||||
}
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
if (f->get_family_id() != m_util.get_family_id())
|
||||
return BR_FAILED;
|
||||
switch (f->get_decl_kind()) {
|
||||
case OP_BADD:
|
||||
case OP_BMUL:
|
||||
case OP_BOR:
|
||||
case OP_BXOR:
|
||||
result_pr = 0;
|
||||
return reduce_ac_app(f, num, args, result);
|
||||
default:
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct rw : public rewriter_tpl<rw_cfg> {
|
||||
rw_cfg m_cfg;
|
||||
|
||||
rw(ast_manager & m, params_ref const & p):
|
||||
rewriter_tpl<rw_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m, p) {
|
||||
}
|
||||
};
|
||||
|
||||
struct imp {
|
||||
rw m_rw;
|
||||
unsigned m_num_steps;
|
||||
|
||||
imp(ast_manager & m, params_ref const & p):
|
||||
m_rw(m, p) {
|
||||
}
|
||||
|
||||
ast_manager & m() const { return m_rw.m(); }
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_rw.set_cancel(f);
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
mc = 0; pc = 0; core = 0;
|
||||
tactic_report report("max-bv-sharing", *g);
|
||||
bool produce_proofs = g->proofs_enabled();
|
||||
|
||||
expr_ref new_curr(m());
|
||||
proof_ref new_pr(m());
|
||||
unsigned size = g->size();
|
||||
for (unsigned idx = 0; idx < size; idx++) {
|
||||
if (g->inconsistent())
|
||||
break;
|
||||
expr * curr = g->form(idx);
|
||||
m_rw(curr, new_curr, new_pr);
|
||||
m_num_steps += m_rw.get_num_steps();
|
||||
|
||||
if (produce_proofs) {
|
||||
proof * pr = g->pr(idx);
|
||||
new_pr = m().mk_modus_ponens(pr, new_pr);
|
||||
}
|
||||
g->update(idx, new_curr, new_pr, g->dep(idx));
|
||||
}
|
||||
m_rw.cfg().cleanup();
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
TRACE("qe", g->display(tout););
|
||||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
};
|
||||
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
public:
|
||||
max_bv_sharing_tactic(ast_manager & m, params_ref const & p):
|
||||
m_params(p) {
|
||||
m_imp = alloc(imp, m, p);
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(max_bv_sharing_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual ~max_bv_sharing_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_imp->m_rw.cfg().updt_params(p);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
insert_max_memory(r);
|
||||
insert_max_steps(r);
|
||||
r.insert(":max-args", CPK_UINT,
|
||||
"(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic.");
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
(*m_imp)(in, result, mc, pc, core);
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m();
|
||||
imp * d = m_imp;
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = 0;
|
||||
}
|
||||
dealloc(d);
|
||||
d = alloc(imp, m, m_params);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = d;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_max_bv_sharing_tactic(ast_manager & m, params_ref const & p) {
|
||||
return clean(alloc(max_bv_sharing_tactic, m, p));
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
max_bv_sharing_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Rewriter for "maximing" the number of shared terms.
|
||||
The idea is to rewrite AC terms to maximize sharing.
|
||||
This rewriter is particularly useful for reducing
|
||||
the number of Adders and Multipliers before "bit-blasting".
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-12-29.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MAX_BV_SHARING_TACTIC_H_
|
||||
#define _MAX_BV_SHARING_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_max_bv_sharing_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
nlsat_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for using nonlinear procedure.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-01-02
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"goal2nlsat.h"
|
||||
#include"nlsat_solver.h"
|
||||
#include"model.h"
|
||||
#include"expr2var.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"z3_exception.h"
|
||||
#include"algebraic_numbers.h"
|
||||
|
||||
class nlsat_tactic : public tactic {
|
||||
struct expr_display_var_proc : public nlsat::display_var_proc {
|
||||
ast_manager & m;
|
||||
expr_ref_vector m_var2expr;
|
||||
expr_display_var_proc(ast_manager & _m):m(_m), m_var2expr(_m) {}
|
||||
virtual void operator()(std::ostream & out, nlsat::var x) const {
|
||||
if (x < m_var2expr.size())
|
||||
out << mk_ismt2_pp(m_var2expr.get(x), m);
|
||||
else
|
||||
out << "x!" << x;
|
||||
}
|
||||
};
|
||||
|
||||
struct imp {
|
||||
ast_manager & m;
|
||||
params_ref m_params;
|
||||
expr_display_var_proc m_display_var;
|
||||
nlsat::solver m_solver;
|
||||
goal2nlsat m_g2nl;
|
||||
|
||||
imp(ast_manager & _m, params_ref const & p):
|
||||
m(_m),
|
||||
m_params(p),
|
||||
m_display_var(_m),
|
||||
m_solver(p) {
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_solver.updt_params(p);
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_solver.set_cancel(f);
|
||||
m_g2nl.set_cancel(f);
|
||||
}
|
||||
|
||||
bool contains_unsupported(expr_ref_vector & b2a, expr_ref_vector & x2t) {
|
||||
for (unsigned x = 0; x < x2t.size(); x++) {
|
||||
if (!is_uninterp_const(x2t.get(x))) {
|
||||
TRACE("unsupported", tout << "unsupported atom:\n" << mk_ismt2_pp(x2t.get(x), m) << "\n";);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (unsigned b = 0; b < b2a.size(); b++) {
|
||||
expr * a = b2a.get(b);
|
||||
if (a == 0)
|
||||
continue;
|
||||
if (is_uninterp_const(a))
|
||||
continue;
|
||||
if (m_solver.is_interpreted(b))
|
||||
continue; // arithmetic atom
|
||||
TRACE("unsupported", tout << "unsupported atom:\n" << mk_ismt2_pp(a, m) << "\n";);
|
||||
return true; // unsupported
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return false if nlsat assigned noninteger value to an integer variable.
|
||||
bool mk_model(expr_ref_vector & b2a, expr_ref_vector & x2t, model_converter_ref & mc) {
|
||||
bool ok = true;
|
||||
model_ref md = alloc(model, m);
|
||||
arith_util util(m);
|
||||
for (unsigned x = 0; x < x2t.size(); x++) {
|
||||
expr * t = x2t.get(x);
|
||||
if (!is_uninterp_const(t))
|
||||
continue;
|
||||
expr * v;
|
||||
try {
|
||||
v = util.mk_numeral(m_solver.value(x), util.is_int(t));
|
||||
}
|
||||
catch (z3_error & ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (z3_exception &) {
|
||||
v = util.mk_to_int(util.mk_numeral(m_solver.value(x), false));
|
||||
ok = false;
|
||||
}
|
||||
md->register_decl(to_app(t)->get_decl(), v);
|
||||
}
|
||||
for (unsigned b = 0; b < b2a.size(); b++) {
|
||||
expr * a = b2a.get(b);
|
||||
if (a == 0 || !is_uninterp_const(a))
|
||||
continue;
|
||||
lbool val = m_solver.bvalue(b);
|
||||
if (val == l_undef)
|
||||
continue; // don't care
|
||||
md->register_decl(to_app(a)->get_decl(), val == l_true ? m.mk_true() : m.mk_false());
|
||||
}
|
||||
mc = model2model_converter(md.get());
|
||||
return ok;
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
mc = 0; pc = 0; core = 0;
|
||||
tactic_report report("nlsat", *g);
|
||||
|
||||
if (g->is_decided()) {
|
||||
result.push_back(g.get());
|
||||
return;
|
||||
}
|
||||
|
||||
fail_if_proof_generation("nlsat", g);
|
||||
|
||||
expr2var a2b(m);
|
||||
expr2var t2x(m);
|
||||
m_g2nl(*g, m_params, m_solver, a2b, t2x);
|
||||
|
||||
m_display_var.m_var2expr.reset();
|
||||
t2x.mk_inv(m_display_var.m_var2expr);
|
||||
m_solver.set_display_var(m_display_var);
|
||||
|
||||
lbool st = m_solver.check();
|
||||
|
||||
if (st == l_undef) {
|
||||
}
|
||||
else if (st == l_true) {
|
||||
expr_ref_vector x2t(m);
|
||||
expr_ref_vector b2a(m);
|
||||
a2b.mk_inv(b2a);
|
||||
t2x.mk_inv(x2t);
|
||||
if (!contains_unsupported(b2a, x2t)) {
|
||||
// If mk_model is false it means that the model produced by nlsat
|
||||
// assigns noninteger values to integer variables
|
||||
if (mk_model(b2a, x2t, mc)) {
|
||||
// result goal is trivially SAT
|
||||
g->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: extract unsat core
|
||||
g->assert_expr(m.mk_false(), 0, 0);
|
||||
}
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
TRACE("nlsat", g->display(tout););
|
||||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
};
|
||||
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
statistics m_stats;
|
||||
|
||||
struct scoped_set_imp {
|
||||
nlsat_tactic & m_owner;
|
||||
scoped_set_imp(nlsat_tactic & o, imp & i):m_owner(o) {
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_owner.m_imp = &i;
|
||||
}
|
||||
}
|
||||
|
||||
~scoped_set_imp() {
|
||||
m_owner.m_imp->m_solver.collect_statistics(m_owner.m_stats);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_owner.m_imp = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
nlsat_tactic(params_ref const & p):
|
||||
m_params(p) {
|
||||
m_imp = 0;
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(nlsat_tactic, m_params);
|
||||
}
|
||||
|
||||
virtual ~nlsat_tactic() {
|
||||
SASSERT(m_imp == 0);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
goal2nlsat::collect_param_descrs(r);
|
||||
nlsat::solver::collect_param_descrs(r);
|
||||
algebraic_numbers::manager::collect_param_descrs(r);
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
try {
|
||||
imp local_imp(in->m(), m_params);
|
||||
scoped_set_imp setter(*this, local_imp);
|
||||
local_imp(in, result, mc, pc, core);
|
||||
}
|
||||
catch (z3_error & ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (z3_exception & ex) {
|
||||
throw tactic_exception(ex.msg());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void cleanup() {}
|
||||
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
|
||||
virtual void collect_statistics(statistics & st) const {
|
||||
st.copy(m_stats);
|
||||
}
|
||||
|
||||
virtual void reset_statistics() {
|
||||
m_stats.reset();
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_nlsat_tactic(ast_manager & m, params_ref const & p) {
|
||||
return clean(alloc(nlsat_tactic, p));
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
nlsat_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for using nonlinear procedure.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-01-02
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _NLSAT_TACTIC_H_
|
||||
#define _NLSAT_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_nlsat_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,47 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
nra_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for NRA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-03-13
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
#include"nnf_tactic.h"
|
||||
#include"qe_tactic.h"
|
||||
#include"qfnra_nlsat_tactic.h"
|
||||
#include"probe_arith.h"
|
||||
|
||||
tactic * mk_nra_tactic(ast_manager & m, params_ref const& p) {
|
||||
params_ref p1 = p;
|
||||
p1.set_uint(":seed", 11);
|
||||
p1.set_bool(":factor", false);
|
||||
params_ref p2 = p;
|
||||
p2.set_uint(":seed", 13);
|
||||
p2.set_bool(":factor", false);
|
||||
|
||||
return and_then(mk_simplify_tactic(m, p),
|
||||
mk_nnf_tactic(m, p),
|
||||
mk_propagate_values_tactic(m, p),
|
||||
mk_qe_tactic(m, p),
|
||||
cond(mk_is_qfnra_probe(),
|
||||
or_else(try_for(mk_qfnra_nlsat_tactic(m, p), 5000),
|
||||
try_for(mk_qfnra_nlsat_tactic(m, p1), 10000),
|
||||
mk_qfnra_nlsat_tactic(m, p2)),
|
||||
mk_smt_tactic(p)));
|
||||
}
|
||||
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
nra_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for NRA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-03-13
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _NRA_TACTIC_H_
|
||||
#define _NRA_TACTIC_H_
|
||||
|
||||
tactic * mk_nra_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,65 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfaufbv_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_AUFBV benchmarks.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"bit_blaster_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"max_bv_sharing_tactic.h"
|
||||
#include"bv_size_reduction_tactic.h"
|
||||
#include"ctx_simplify_tactic.h"
|
||||
#include"sat_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
|
||||
tactic * mk_qfaufbv_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref main_p;
|
||||
main_p.set_bool(":elim-and", true);
|
||||
main_p.set_bool(":sort-store", true);
|
||||
|
||||
params_ref simp2_p = p;
|
||||
simp2_p.set_bool(":som", true);
|
||||
simp2_p.set_bool(":pull-cheap-ite", true);
|
||||
simp2_p.set_bool(":push-ite-bv", false);
|
||||
simp2_p.set_bool(":local-ctx", true);
|
||||
simp2_p.set_uint(":local-ctx-limit", 10000000);
|
||||
|
||||
params_ref ctx_simp_p;
|
||||
ctx_simp_p.set_uint(":max-depth", 32);
|
||||
ctx_simp_p.set_uint(":max-steps", 5000000);
|
||||
|
||||
params_ref solver_p;
|
||||
solver_p.set_bool(":array-old-simplifier", false);
|
||||
|
||||
tactic * preamble_st = and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
// using_params(mk_ctx_simplify_tactic(m), ctx_simp_p),
|
||||
mk_solve_eqs_tactic(m),
|
||||
mk_elim_uncnstr_tactic(m),
|
||||
if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))),
|
||||
using_params(mk_simplify_tactic(m), simp2_p),
|
||||
mk_max_bv_sharing_tactic(m)
|
||||
);
|
||||
|
||||
tactic * st = using_params(and_then(preamble_st,
|
||||
using_params(mk_smt_tactic(), solver_p)),
|
||||
main_p);
|
||||
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfaufbv_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_AUFBV
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFAUFBV_TACTIC_H_
|
||||
#define _QFAUFBV_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qfaufbv_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfauflia_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_AUFLIA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-21
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"propagate_ineqs_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
|
||||
tactic * mk_qfauflia_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref main_p;
|
||||
main_p.set_bool(":elim-and", true);
|
||||
main_p.set_bool(":som", true);
|
||||
main_p.set_bool(":sort-store", true);
|
||||
|
||||
params_ref ctx_simp_p;
|
||||
ctx_simp_p.set_uint(":max-depth", 30);
|
||||
ctx_simp_p.set_uint(":max-steps", 5000000);
|
||||
|
||||
params_ref solver_p;
|
||||
solver_p.set_bool(":array-old-simplifier", false);
|
||||
|
||||
tactic * preamble_st = and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
mk_solve_eqs_tactic(m),
|
||||
mk_elim_uncnstr_tactic(m),
|
||||
mk_simplify_tactic(m)
|
||||
);
|
||||
|
||||
tactic * st = and_then(using_params(preamble_st, main_p),
|
||||
using_params(mk_smt_tactic(), solver_p));
|
||||
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfauflia_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_AUFLIA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-21
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFAUFLIA_TACTIC_H_
|
||||
#define _QFAUFLIA_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qfauflia_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,118 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfbv_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_BV based on bit-blasting
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-22
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
#include"bit_blaster_tactic.h"
|
||||
#include"bv1_blaster_tactic.h"
|
||||
#include"max_bv_sharing_tactic.h"
|
||||
#include"bv_size_reduction_tactic.h"
|
||||
#include"aig_tactic.h"
|
||||
#include"sat_tactic.h"
|
||||
|
||||
#define MEMLIMIT 300
|
||||
|
||||
tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref main_p;
|
||||
main_p.set_bool(":elim-and", true);
|
||||
main_p.set_bool(":push-ite-bv", true);
|
||||
main_p.set_bool(":blast-distinct", true);
|
||||
|
||||
params_ref simp2_p = p;
|
||||
simp2_p.set_bool(":som", true);
|
||||
simp2_p.set_bool(":pull-cheap-ite", true);
|
||||
simp2_p.set_bool(":push-ite-bv", false);
|
||||
simp2_p.set_bool(":local-ctx", true);
|
||||
simp2_p.set_uint(":local-ctx-limit", 10000000);
|
||||
|
||||
params_ref local_ctx_p = p;
|
||||
local_ctx_p.set_bool(":local-ctx", true);
|
||||
|
||||
params_ref solver_p;
|
||||
solver_p.set_bool(":preprocess", false); // preprocessor of smt::context is not needed.
|
||||
|
||||
params_ref no_flat_p;
|
||||
no_flat_p.set_bool(":flat", false);
|
||||
|
||||
params_ref ctx_simp_p;
|
||||
ctx_simp_p.set_uint(":max-depth", 32);
|
||||
ctx_simp_p.set_uint(":max-steps", 50000000);
|
||||
|
||||
params_ref hoist_p;
|
||||
hoist_p.set_bool(":hoist-mul", true);
|
||||
hoist_p.set_bool(":som", false);
|
||||
|
||||
params_ref solve_eq_p;
|
||||
// conservative guassian elimination.
|
||||
solve_eq_p.set_uint(":solve-eqs-max-occs", 2);
|
||||
|
||||
params_ref big_aig_p;
|
||||
big_aig_p.set_bool(":aig-per-assertion", false);
|
||||
|
||||
tactic * preamble_st = and_then(and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
using_params(mk_solve_eqs_tactic(m), solve_eq_p),
|
||||
mk_elim_uncnstr_tactic(m),
|
||||
if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))),
|
||||
using_params(mk_simplify_tactic(m), simp2_p)),
|
||||
// Z3 can solve a couple of extra benchmarks by using :hoist-mul
|
||||
// but the timeout in SMT-COMP is too small.
|
||||
// Moreover, it impacted negatively some easy benchmarks.
|
||||
// We should decide later, if we keep it or not.
|
||||
using_params(mk_simplify_tactic(m), hoist_p),
|
||||
mk_max_bv_sharing_tactic(m));
|
||||
|
||||
#ifdef USE_OLD_SAT_SOLVER
|
||||
tactic * new_sat = and_then(mk_simplify_tactic(m),
|
||||
mk_smt_tactic());
|
||||
#else
|
||||
tactic * new_sat = cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()),
|
||||
and_then(mk_simplify_tactic(m),
|
||||
mk_smt_tactic()),
|
||||
mk_sat_tactic(m));
|
||||
#endif
|
||||
|
||||
tactic * st = using_params(and_then(preamble_st,
|
||||
// If the user sets HI_DIV0=false, then the formula may contain uninterpreted function
|
||||
// symbols. In this case, we should not use
|
||||
cond(mk_is_qfbv_probe(),
|
||||
cond(mk_is_qfbv_eq_probe(),
|
||||
and_then(mk_bv1_blaster_tactic(m),
|
||||
using_params(mk_smt_tactic(), solver_p)),
|
||||
and_then(mk_bit_blaster_tactic(m),
|
||||
when(mk_lt(mk_memory_probe(), mk_const_probe(MEMLIMIT)),
|
||||
and_then(using_params(and_then(mk_simplify_tactic(m),
|
||||
mk_solve_eqs_tactic(m)),
|
||||
local_ctx_p),
|
||||
if_no_proofs(cond(mk_produce_unsat_cores_probe(),
|
||||
mk_aig_tactic(),
|
||||
using_params(mk_aig_tactic(),
|
||||
big_aig_p))))),
|
||||
new_sat)),
|
||||
mk_smt_tactic())),
|
||||
main_p);
|
||||
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
||||
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfbv_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_BV based on bit-blasting
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-22
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFBV_TACTIC_
|
||||
#define _QFBV_TACTIC_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,38 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qffpa_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_FPA benchmarks.
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2012-01-16
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"bit_blaster_tactic.h"
|
||||
#include"sat_tactic.h"
|
||||
#include"fpa2bv_tactic.h"
|
||||
|
||||
#include"qffpa_tactic.h"
|
||||
|
||||
tactic * mk_qffpa_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref sat_simp_p = p;
|
||||
sat_simp_p .set_bool(":elim-and", true);
|
||||
|
||||
return and_then(mk_simplify_tactic(m, p),
|
||||
mk_fpa2bv_tactic(m, p),
|
||||
using_params(mk_simplify_tactic(m, p), sat_simp_p),
|
||||
mk_bit_blaster_tactic(m, p),
|
||||
using_params(mk_simplify_tactic(m, p), sat_simp_p),
|
||||
mk_sat_tactic(m, p),
|
||||
mk_fail_if_undecided_tactic());
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qffpa_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic QF_FPA benchmarks.
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2012-01-16
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
--*/
|
||||
#ifndef _QFFPA_TACTIC_H_
|
||||
#define _QFFPA_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qffpa_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,111 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfidl_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_IDL
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-21
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"propagate_ineqs_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"normalize_bounds_tactic.h"
|
||||
#include"fix_dl_var_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
#include"lia2pb_tactic.h"
|
||||
#include"pb2bv_tactic.h"
|
||||
#include"diff_neq_tactic.h"
|
||||
#include"bit_blaster_tactic.h"
|
||||
#include"max_bv_sharing_tactic.h"
|
||||
#include"aig_tactic.h"
|
||||
#include"sat_tactic.h"
|
||||
|
||||
#define BIG_PROBLEM 5000
|
||||
|
||||
tactic * mk_qfidl_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref main_p;
|
||||
main_p.set_bool(":elim-and", true);
|
||||
main_p.set_bool(":blast-distinct", true);
|
||||
main_p.set_bool(":som", true);
|
||||
|
||||
params_ref lhs_p;
|
||||
lhs_p.set_bool(":arith-lhs", true);
|
||||
|
||||
params_ref lia2pb_p;
|
||||
lia2pb_p.set_uint(":lia2pb-max-bits", 4);
|
||||
|
||||
params_ref pb2bv_p;
|
||||
pb2bv_p.set_uint(":pb2bv-all-clauses-limit", 8);
|
||||
|
||||
params_ref pull_ite_p;
|
||||
pull_ite_p.set_bool(":pull-cheap-ite", true);
|
||||
pull_ite_p.set_bool(":local-ctx", true);
|
||||
pull_ite_p.set_uint(":local-ctx-limit", 10000000);
|
||||
|
||||
tactic * preamble_st = and_then(and_then(mk_simplify_tactic(m),
|
||||
mk_fix_dl_var_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
mk_elim_uncnstr_tactic(m)
|
||||
),
|
||||
and_then(mk_solve_eqs_tactic(m),
|
||||
using_params(mk_simplify_tactic(m), lhs_p),
|
||||
mk_propagate_values_tactic(m),
|
||||
mk_normalize_bounds_tactic(m),
|
||||
mk_solve_eqs_tactic(m)));
|
||||
|
||||
|
||||
|
||||
params_ref bv_solver_p;
|
||||
// The cardinality constraint encoding generates a lot of shared if-then-else's that can be flattened.
|
||||
// Several of them are simplified to and/or. If we flat them, we increase a lot the memory consumption.
|
||||
bv_solver_p.set_bool(":flat", false);
|
||||
bv_solver_p.set_bool(":som", false);
|
||||
// dynamic psm seems to work well.
|
||||
bv_solver_p.set_sym(":gc-strategy", symbol("dyn-psm"));
|
||||
|
||||
tactic * bv_solver = using_params(and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
mk_solve_eqs_tactic(m),
|
||||
mk_max_bv_sharing_tactic(m),
|
||||
mk_bit_blaster_tactic(m),
|
||||
mk_aig_tactic(),
|
||||
mk_sat_tactic(m)),
|
||||
bv_solver_p);
|
||||
|
||||
tactic * try2bv =
|
||||
and_then(using_params(mk_lia2pb_tactic(m), lia2pb_p),
|
||||
mk_propagate_ineqs_tactic(m),
|
||||
using_params(mk_pb2bv_tactic(m), pb2bv_p),
|
||||
fail_if(mk_not(mk_is_qfbv_probe())),
|
||||
bv_solver);
|
||||
|
||||
params_ref diff_neq_p;
|
||||
diff_neq_p.set_uint(":diff-neq-max-k", 25);
|
||||
|
||||
tactic * st = cond(mk_and(mk_lt(mk_num_consts_probe(), mk_const_probe(static_cast<double>(BIG_PROBLEM))),
|
||||
mk_and(mk_not(mk_produce_proofs_probe()),
|
||||
mk_not(mk_produce_unsat_cores_probe()))),
|
||||
using_params(and_then(preamble_st,
|
||||
or_else(using_params(mk_diff_neq_tactic(m), diff_neq_p),
|
||||
try2bv,
|
||||
mk_smt_tactic())),
|
||||
main_p),
|
||||
mk_smt_tactic());
|
||||
|
||||
st->updt_params(p);
|
||||
|
||||
return st;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfidl_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_IDL
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-21
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFIDL_TACTIC_H_
|
||||
#define _QFIDL_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qfidl_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,218 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qflia_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_LIA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-26
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"propagate_ineqs_tactic.h"
|
||||
#include"normalize_bounds_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
#include"mip_tactic.h"
|
||||
#include"add_bounds_tactic.h"
|
||||
#include"pb2bv_tactic.h"
|
||||
#include"lia2pb_tactic.h"
|
||||
#include"ctx_simplify_tactic.h"
|
||||
#include"bit_blaster_tactic.h"
|
||||
#include"max_bv_sharing_tactic.h"
|
||||
#include"aig_tactic.h"
|
||||
#include"sat_tactic.h"
|
||||
#include"bound_manager.h"
|
||||
#include"probe_arith.h"
|
||||
|
||||
struct quasi_pb_probe : public probe {
|
||||
virtual result operator()(goal const & g) {
|
||||
bool found_non_01 = false;
|
||||
bound_manager bm(g.m());
|
||||
bm(g);
|
||||
rational l, u; bool st;
|
||||
bound_manager::iterator it = bm.begin();
|
||||
bound_manager::iterator end = bm.end();
|
||||
for (; it != end; ++it) {
|
||||
expr * t = *it;
|
||||
if (bm.has_lower(t, l, st) && bm.has_upper(t, u, st) && (l.is_zero() || l.is_one()) && (u.is_zero() || u.is_one()))
|
||||
continue;
|
||||
if (found_non_01)
|
||||
return false;
|
||||
found_non_01 = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
probe * mk_quasi_pb_probe() {
|
||||
return mk_and(mk_not(mk_is_unbounded_probe()),
|
||||
alloc(quasi_pb_probe));
|
||||
}
|
||||
|
||||
// Create SMT solver that does not use cuts
|
||||
static tactic * mk_no_cut_smt_tactic(unsigned rs) {
|
||||
params_ref solver_p;
|
||||
solver_p.set_uint(":arith-branch-cut-ratio", 10000000);
|
||||
solver_p.set_uint(":random-seed", rs);
|
||||
return using_params(mk_smt_tactic_using(false), solver_p);
|
||||
}
|
||||
|
||||
// Create SMT solver that does not use cuts
|
||||
static tactic * mk_no_cut_no_relevancy_smt_tactic(unsigned rs) {
|
||||
params_ref solver_p;
|
||||
solver_p.set_uint(":arith-branch-cut-ratio", 10000000);
|
||||
solver_p.set_uint(":random-seed", rs);
|
||||
solver_p.set_uint(":relevancy", 0);
|
||||
return using_params(mk_smt_tactic_using(false), solver_p);
|
||||
}
|
||||
|
||||
static tactic * mk_bv2sat_tactic(ast_manager & m) {
|
||||
params_ref solver_p;
|
||||
// The cardinality constraint encoding generates a lot of shared if-then-else's that can be flattened.
|
||||
// Several of them are simplified to and/or. If we flat them, we increase a lot the memory consumption.
|
||||
solver_p.set_bool(":flat", false);
|
||||
solver_p.set_bool(":som", false);
|
||||
// dynamic psm seems to work well.
|
||||
solver_p.set_sym(":gc-strategy", symbol("dyn-psm"));
|
||||
|
||||
return using_params(and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
mk_solve_eqs_tactic(m),
|
||||
mk_max_bv_sharing_tactic(m),
|
||||
mk_bit_blaster_tactic(m),
|
||||
mk_aig_tactic(),
|
||||
mk_sat_tactic(m)),
|
||||
solver_p);
|
||||
}
|
||||
|
||||
#define SMALL_SIZE 80000
|
||||
|
||||
static tactic * mk_pb_tactic(ast_manager & m) {
|
||||
params_ref pb2bv_p;
|
||||
pb2bv_p.set_bool(":ite-extra", true);
|
||||
pb2bv_p.set_uint(":pb2bv-all-clauses-limit", 8);
|
||||
|
||||
return and_then(fail_if_not(mk_is_pb_probe()),
|
||||
fail_if(mk_produce_proofs_probe()),
|
||||
fail_if(mk_produce_unsat_cores_probe()),
|
||||
or_else(and_then(fail_if(mk_ge(mk_num_exprs_probe(), mk_const_probe(SMALL_SIZE))),
|
||||
fail_if_not(mk_is_ilp_probe()),
|
||||
try_for(mk_mip_tactic(m), 8000),
|
||||
mk_fail_if_undecided_tactic()),
|
||||
and_then(using_params(mk_pb2bv_tactic(m), pb2bv_p),
|
||||
fail_if_not(mk_is_qfbv_probe()),
|
||||
mk_bv2sat_tactic(m))));
|
||||
}
|
||||
|
||||
|
||||
static tactic * mk_lia2sat_tactic(ast_manager & m) {
|
||||
params_ref pb2bv_p;
|
||||
pb2bv_p.set_bool(":ite-extra", true);
|
||||
pb2bv_p.set_uint(":pb2bv-all-clauses-limit", 8);
|
||||
|
||||
return and_then(fail_if(mk_is_unbounded_probe()),
|
||||
fail_if(mk_produce_proofs_probe()),
|
||||
fail_if(mk_produce_unsat_cores_probe()),
|
||||
mk_propagate_ineqs_tactic(m),
|
||||
mk_normalize_bounds_tactic(m),
|
||||
mk_lia2pb_tactic(m),
|
||||
using_params(mk_pb2bv_tactic(m), pb2bv_p),
|
||||
fail_if_not(mk_is_qfbv_probe()),
|
||||
mk_bv2sat_tactic(m));
|
||||
}
|
||||
|
||||
// Try to find a model for an unbounded ILP problem.
|
||||
// Fails if the problem is no ILP.
|
||||
static tactic * mk_ilp_model_finder_tactic(ast_manager & m) {
|
||||
params_ref add_bounds_p1;
|
||||
add_bounds_p1.set_rat(":add-bound-lower", rational(-16));
|
||||
add_bounds_p1.set_rat(":add-bound-upper", rational(15));
|
||||
params_ref add_bounds_p2;
|
||||
add_bounds_p2.set_rat(":add-bound-lower", rational(-32));
|
||||
add_bounds_p2.set_rat(":add-bound-upper", rational(31));
|
||||
|
||||
return and_then(fail_if_not(mk_and(mk_is_ilp_probe(), mk_is_unbounded_probe())),
|
||||
fail_if(mk_produce_proofs_probe()),
|
||||
fail_if(mk_produce_unsat_cores_probe()),
|
||||
mk_propagate_ineqs_tactic(m),
|
||||
or_else(try_for(mk_mip_tactic(m), 5000),
|
||||
try_for(mk_no_cut_smt_tactic(100), 2000),
|
||||
and_then(using_params(mk_add_bounds_tactic(m), add_bounds_p1),
|
||||
try_for(mk_lia2sat_tactic(m), 5000)),
|
||||
try_for(mk_no_cut_smt_tactic(200), 5000),
|
||||
and_then(using_params(mk_add_bounds_tactic(m), add_bounds_p2),
|
||||
try_for(mk_lia2sat_tactic(m), 10000)),
|
||||
mk_mip_tactic(m)),
|
||||
mk_fail_if_undecided_tactic());
|
||||
}
|
||||
|
||||
static tactic * mk_bounded_tactic(ast_manager & m) {
|
||||
return and_then(fail_if(mk_is_unbounded_probe()),
|
||||
or_else(try_for(mk_no_cut_smt_tactic(100), 5000),
|
||||
try_for(mk_no_cut_no_relevancy_smt_tactic(200), 5000),
|
||||
try_for(mk_no_cut_smt_tactic(300), 15000)
|
||||
),
|
||||
mk_fail_if_undecided_tactic());
|
||||
}
|
||||
|
||||
tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref main_p;
|
||||
main_p.set_bool(":elim-and", true);
|
||||
main_p.set_bool(":som", true);
|
||||
// main_p.set_bool(":push-ite-arith", true);
|
||||
|
||||
params_ref pull_ite_p;
|
||||
pull_ite_p.set_bool(":pull-cheap-ite", true);
|
||||
pull_ite_p.set_bool(":push-ite-arith", false);
|
||||
pull_ite_p.set_bool(":local-ctx", true);
|
||||
pull_ite_p.set_uint(":local-ctx-limit", 10000000);
|
||||
|
||||
params_ref ctx_simp_p;
|
||||
ctx_simp_p.set_uint(":max-depth", 30);
|
||||
ctx_simp_p.set_uint(":max-steps", 5000000);
|
||||
|
||||
params_ref lhs_p;
|
||||
lhs_p.set_bool(":arith-lhs", true);
|
||||
|
||||
tactic * preamble_st = and_then(and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
using_params(mk_ctx_simplify_tactic(m), ctx_simp_p),
|
||||
using_params(mk_simplify_tactic(m), pull_ite_p)),
|
||||
mk_solve_eqs_tactic(m),
|
||||
mk_elim_uncnstr_tactic(m),
|
||||
using_params(mk_simplify_tactic(m), lhs_p)
|
||||
);
|
||||
|
||||
params_ref quasi_pb_p;
|
||||
quasi_pb_p.set_uint(":lia2pb-max-bits", 64);
|
||||
|
||||
params_ref no_cut_p;
|
||||
no_cut_p.set_uint(":arith-branch-cut-ratio", 10000000);
|
||||
|
||||
|
||||
tactic * st = using_params(and_then(preamble_st,
|
||||
or_else(mk_ilp_model_finder_tactic(m),
|
||||
mk_pb_tactic(m),
|
||||
and_then(fail_if_not(mk_quasi_pb_probe()),
|
||||
using_params(mk_lia2sat_tactic(m), quasi_pb_p),
|
||||
mk_fail_if_undecided_tactic()),
|
||||
mk_bounded_tactic(m),
|
||||
mk_smt_tactic())),
|
||||
main_p);
|
||||
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qflia_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_LRA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-26
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFLIA_TACTIC_
|
||||
#define _QFLIA_TACTIC_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,71 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qflra_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_LRA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-26
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
#include"mip_tactic.h"
|
||||
#include"recover_01_tactic.h"
|
||||
#include"ctx_simplify_tactic.h"
|
||||
#include"probe_arith.h"
|
||||
|
||||
tactic * mk_qflra_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref pivot_p;
|
||||
pivot_p.set_bool(":arith-greatest-error-pivot", true);
|
||||
|
||||
params_ref main_p = p;
|
||||
main_p.set_bool(":elim-and", true);
|
||||
main_p.set_bool(":som", true);
|
||||
main_p.set_bool(":blast-distinct", true);
|
||||
|
||||
params_ref ctx_simp_p;
|
||||
ctx_simp_p.set_uint(":max-depth", 30);
|
||||
ctx_simp_p.set_uint(":max-steps", 5000000);
|
||||
|
||||
params_ref lhs_p;
|
||||
lhs_p.set_bool(":arith-lhs", true);
|
||||
lhs_p.set_bool(":eq2ineq", true);
|
||||
|
||||
params_ref elim_to_real_p;
|
||||
elim_to_real_p.set_bool(":elim-to-real", true);
|
||||
|
||||
tactic * mip =
|
||||
and_then(fail_if(mk_produce_proofs_probe()),
|
||||
fail_if(mk_produce_unsat_cores_probe()),
|
||||
using_params(and_then(and_then(mk_simplify_tactic(m),
|
||||
mk_recover_01_tactic(m),
|
||||
using_params(mk_simplify_tactic(m), elim_to_real_p),
|
||||
mk_propagate_values_tactic(m)),
|
||||
using_params(mk_ctx_simplify_tactic(m), ctx_simp_p),
|
||||
mk_elim_uncnstr_tactic(m),
|
||||
mk_solve_eqs_tactic(m),
|
||||
using_params(mk_simplify_tactic(m), lhs_p),
|
||||
using_params(mk_simplify_tactic(m), elim_to_real_p)
|
||||
),
|
||||
main_p),
|
||||
fail_if(mk_not(mk_is_mip_probe())),
|
||||
try_for(mk_mip_tactic(m), 30000),
|
||||
mk_fail_if_undecided_tactic());
|
||||
|
||||
return using_params(or_else(mip,
|
||||
using_params(mk_smt_tactic(), pivot_p)),
|
||||
p);
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qflra_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_LRA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-26
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFLRA_TACTIC_
|
||||
#define _QFLRA_TACTIC_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qflra_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,93 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qflia_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_NIA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-28
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
#include"bit_blaster_tactic.h"
|
||||
#include"max_bv_sharing_tactic.h"
|
||||
#include"sat_tactic.h"
|
||||
#include"nla2bv_tactic.h"
|
||||
#include"ctx_simplify_tactic.h"
|
||||
#include"cofactor_term_ite_tactic.h"
|
||||
|
||||
tactic * mk_qfnia_bv_solver(ast_manager & m, params_ref const & p_ref) {
|
||||
params_ref p = p_ref;
|
||||
p.set_bool(":flat", false);
|
||||
p.set_bool(":hi-div0", true);
|
||||
p.set_bool(":elim-and", true);
|
||||
p.set_bool(":blast-distinct", true);
|
||||
|
||||
params_ref simp2_p = p;
|
||||
simp2_p.set_bool(":local-ctx", true);
|
||||
simp2_p.set_uint(":local-ctx-limit", 10000000);
|
||||
|
||||
|
||||
tactic * r = using_params(and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
using_params(mk_simplify_tactic(m), simp2_p),
|
||||
mk_max_bv_sharing_tactic(m),
|
||||
mk_bit_blaster_tactic(m),
|
||||
mk_sat_tactic(m)),
|
||||
p);
|
||||
return r;
|
||||
}
|
||||
|
||||
tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) {
|
||||
params_ref pull_ite_p = p_ref;
|
||||
pull_ite_p.set_bool(":pull-cheap-ite", true);
|
||||
pull_ite_p.set_bool(":local-ctx", true);
|
||||
pull_ite_p.set_uint(":local-ctx-limit", 10000000);
|
||||
|
||||
params_ref ctx_simp_p = p_ref;
|
||||
ctx_simp_p.set_uint(":max-depth", 30);
|
||||
ctx_simp_p.set_uint(":max-steps", 5000000);
|
||||
|
||||
params_ref simp_p = p_ref;
|
||||
simp_p.set_bool(":hoist-mul", true);
|
||||
|
||||
params_ref elim_p = p_ref;
|
||||
elim_p.set_uint(":max-memory",20);
|
||||
|
||||
return
|
||||
and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
using_params(mk_ctx_simplify_tactic(m), ctx_simp_p),
|
||||
using_params(mk_simplify_tactic(m), pull_ite_p),
|
||||
mk_elim_uncnstr_tactic(m),
|
||||
skip_if_failed(using_params(mk_cofactor_term_ite_tactic(m), elim_p)),
|
||||
using_params(mk_simplify_tactic(m), simp_p));
|
||||
}
|
||||
|
||||
tactic * mk_qfnia_sat_solver(ast_manager & m, params_ref const & p) {
|
||||
params_ref nia2sat_p = p;
|
||||
nia2sat_p.set_uint(":nla2bv-max-bv-size", 64);
|
||||
|
||||
return and_then(mk_nla2bv_tactic(m, nia2sat_p),
|
||||
mk_qfnia_bv_solver(m, p),
|
||||
mk_fail_if_undecided_tactic());
|
||||
}
|
||||
|
||||
tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) {
|
||||
return and_then(mk_qfnia_premable(m, p),
|
||||
or_else(mk_qfnia_sat_solver(m, p),
|
||||
mk_smt_tactic()));
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfnia_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_NIA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-28
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFNIA_TACTIC_
|
||||
#define _QFNIA_TACTIC_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,63 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfnra_nlsat_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic based on nlsat for solving QF_NRA problems
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-01-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
|
||||
#include"tseitin_cnf_tactic.h"
|
||||
#include"degree_shift_tactic.h"
|
||||
#include"purify_arith_tactic.h"
|
||||
#include"nlsat_tactic.h"
|
||||
#include"factor_tactic.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"elim_term_ite_tactic.h"
|
||||
|
||||
tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref main_p = p;
|
||||
main_p.set_bool(":elim-and", true);
|
||||
main_p.set_bool(":blast-distinct", true);
|
||||
params_ref purify_p = p;
|
||||
purify_p.set_bool(":complete", false); // temporary hack, solver does not support uninterpreted functions for encoding (div0 x) applications. So, we replace it application of this kind with an uninterpreted function symbol.
|
||||
|
||||
tactic * factor;
|
||||
if (p.get_bool(":factor", true))
|
||||
factor = mk_factor_tactic(m, p);
|
||||
else
|
||||
factor = mk_skip_tactic();
|
||||
|
||||
return and_then(and_then(using_params(mk_simplify_tactic(m, p),
|
||||
main_p),
|
||||
using_params(mk_purify_arith_tactic(m, p),
|
||||
purify_p),
|
||||
mk_propagate_values_tactic(m, p),
|
||||
mk_solve_eqs_tactic(m, p),
|
||||
mk_elim_uncnstr_tactic(m, p),
|
||||
mk_elim_term_ite_tactic(m, p)),
|
||||
and_then(/* mk_degree_shift_tactic(m, p), */ // may affect full dimensionality detection
|
||||
factor,
|
||||
mk_solve_eqs_tactic(m, p),
|
||||
using_params(mk_simplify_tactic(m, p),
|
||||
main_p),
|
||||
mk_tseitin_cnf_core_tactic(m, p),
|
||||
using_params(mk_simplify_tactic(m, p),
|
||||
main_p),
|
||||
mk_nlsat_tactic(m, p)));
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfnra_nlsat_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic based on nlsat for solving QF_NRA problems
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-01-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFNRA_NLSAT_TACTIC_H_
|
||||
#define _QFNRA_NLSAT_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
MK_SIMPLE_TACTIC_FACTORY(qfnra_nlsat_fct, mk_qfnra_nlsat_tactic(m, p));
|
||||
|
||||
#endif
|
|
@ -1,53 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfnra_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_NRA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-28
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"nla2bv_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
#include"qfnra_nlsat_tactic.h"
|
||||
|
||||
static tactic * mk_qfnra_sat_solver(ast_manager& m, params_ref const& p, unsigned bv_size) {
|
||||
params_ref nra2sat_p = p;
|
||||
nra2sat_p.set_uint(":nla2bv-max-bv-size", p.get_uint(":nla2bv-max-bv-size", bv_size));
|
||||
|
||||
return and_then(mk_nla2bv_tactic(m, nra2sat_p),
|
||||
mk_smt_tactic(),
|
||||
mk_fail_if_undecided_tactic());
|
||||
}
|
||||
|
||||
tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) {
|
||||
params_ref p1 = p;
|
||||
p1.set_uint(":seed", 11);
|
||||
p1.set_bool(":factor", false);
|
||||
params_ref p2 = p;
|
||||
p2.set_uint(":seed", 13);
|
||||
p2.set_bool(":factor", false);
|
||||
|
||||
return and_then(mk_simplify_tactic(m, p),
|
||||
mk_propagate_values_tactic(m, p),
|
||||
or_else(try_for(mk_qfnra_nlsat_tactic(m, p), 5000),
|
||||
try_for(mk_qfnra_nlsat_tactic(m, p1), 10000),
|
||||
mk_qfnra_sat_solver(m, p, 4),
|
||||
and_then(try_for(mk_smt_tactic(), 5000), mk_fail_if_undecided_tactic()),
|
||||
mk_qfnra_sat_solver(m, p, 6),
|
||||
mk_qfnra_nlsat_tactic(m, p2)));
|
||||
}
|
||||
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfnra_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_NRA
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-28
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFNRA_TACTIC_
|
||||
#define _QFNRA_TACTIC_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qfnra_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,40 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfuf_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_QFUF benchmarks.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-02-21
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"symmetry_reduce_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
|
||||
tactic * mk_qfuf_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref s2_p;
|
||||
s2_p.set_bool(":pull-cheap-ite", true);
|
||||
s2_p.set_bool(":local-ctx", true);
|
||||
s2_p.set_uint(":local-ctx-limit", 10000000);
|
||||
return and_then(mk_simplify_tactic(m, p),
|
||||
mk_propagate_values_tactic(m, p),
|
||||
mk_solve_eqs_tactic(m, p),
|
||||
using_params(mk_simplify_tactic(m, p), s2_p),
|
||||
mk_symmetry_reduce_tactic(m, p),
|
||||
mk_smt_tactic(p));
|
||||
}
|
||||
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfuf_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_QFUF benchmarks.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-02-21
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFUF_TACTIC_
|
||||
#define _QFUF_TACTIC_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qfuf_tactic(ast_manager & m, params_ref const & p);
|
||||
|
||||
#endif
|
|
@ -1,53 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfufbv_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_UFBV
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-27
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
#include"max_bv_sharing_tactic.h"
|
||||
#include"bv_size_reduction_tactic.h"
|
||||
#include"reduce_args_tactic.h"
|
||||
|
||||
tactic * mk_qfufbv_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref main_p;
|
||||
main_p.set_bool(":elim-and", true);
|
||||
main_p.set_bool(":blast-distinct", true);
|
||||
|
||||
tactic * preamble_st = and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
mk_solve_eqs_tactic(m),
|
||||
mk_elim_uncnstr_tactic(m),
|
||||
if_no_proofs(if_no_unsat_cores(mk_reduce_args_tactic(m))),
|
||||
if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))),
|
||||
mk_max_bv_sharing_tactic(m)
|
||||
);
|
||||
|
||||
tactic * st = using_params(and_then(preamble_st,
|
||||
mk_smt_tactic()),
|
||||
main_p);
|
||||
|
||||
//cond(is_qfbv(),
|
||||
// and_then(mk_bit_blaster(m),
|
||||
// mk_sat_solver(m)),
|
||||
// mk_smt_solver())
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
qfufbv_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactic for QF_UFBV
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-02-27
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _QFUFBV_TACTIC_
|
||||
#define _QFUFBV_TACTIC_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_qfufbv_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,106 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
quant_tactics.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactics for benchmarks containing quantifiers.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-02-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"elim_uncnstr_tactic.h"
|
||||
#include"qe_tactic.h"
|
||||
#include"ctx_simplify_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
|
||||
static tactic * mk_quant_preprocessor(ast_manager & m, bool disable_gaussian = false) {
|
||||
params_ref pull_ite_p;
|
||||
pull_ite_p.set_bool(":pull-cheap-ite", true);
|
||||
pull_ite_p.set_bool(":local-ctx", true);
|
||||
pull_ite_p.set_uint(":local-ctx-limit", 10000000);
|
||||
|
||||
params_ref ctx_simp_p;
|
||||
ctx_simp_p.set_uint(":max-depth", 30);
|
||||
ctx_simp_p.set_uint(":max-steps", 5000000);
|
||||
|
||||
tactic * solve_eqs;
|
||||
if (disable_gaussian)
|
||||
solve_eqs = mk_skip_tactic();
|
||||
else
|
||||
solve_eqs = when(mk_not(mk_has_pattern_probe()), mk_solve_eqs_tactic(m));
|
||||
|
||||
// remark: investigate if gaussian elimination is useful when patterns are not provided.
|
||||
return and_then(mk_simplify_tactic(m),
|
||||
mk_propagate_values_tactic(m),
|
||||
using_params(mk_ctx_simplify_tactic(m), ctx_simp_p),
|
||||
using_params(mk_simplify_tactic(m), pull_ite_p),
|
||||
solve_eqs,
|
||||
mk_elim_uncnstr_tactic(m),
|
||||
mk_simplify_tactic(m));
|
||||
}
|
||||
|
||||
static tactic * mk_no_solve_eq_preprocessor(ast_manager & m) {
|
||||
return mk_quant_preprocessor(m, true);
|
||||
}
|
||||
|
||||
tactic * mk_ufnia_tactic(ast_manager & m, params_ref const & p) {
|
||||
tactic * st = and_then(mk_no_solve_eq_preprocessor(m),
|
||||
mk_smt_tactic());
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
||||
|
||||
tactic * mk_uflra_tactic(ast_manager & m, params_ref const & p) {
|
||||
tactic * st = and_then(mk_quant_preprocessor(m),
|
||||
mk_smt_tactic());
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
||||
|
||||
tactic * mk_auflia_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref qi_p;
|
||||
qi_p.set_str(":qi-cost", "0");
|
||||
TRACE("qi_cost", qi_p.display(tout); tout << "\n" << qi_p.get_str(":qi-cost", "<null>") << "\n";);
|
||||
tactic * st = and_then(mk_no_solve_eq_preprocessor(m),
|
||||
or_else(and_then(fail_if(mk_gt(mk_num_exprs_probe(), mk_const_probe(static_cast<double>(128)))),
|
||||
using_params(mk_smt_tactic(), qi_p),
|
||||
mk_fail_if_undecided_tactic()),
|
||||
mk_smt_tactic()));
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
||||
|
||||
tactic * mk_auflira_tactic(ast_manager & m, params_ref const & p) {
|
||||
tactic * st = and_then(mk_quant_preprocessor(m),
|
||||
mk_smt_tactic());
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
||||
|
||||
tactic * mk_aufnira_tactic(ast_manager & m, params_ref const & p) {
|
||||
tactic * st = and_then(mk_quant_preprocessor(m),
|
||||
mk_smt_tactic());
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
||||
|
||||
tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) {
|
||||
tactic * st = and_then(mk_quant_preprocessor(m),
|
||||
mk_qe_tactic(m),
|
||||
mk_smt_tactic());
|
||||
st->updt_params(p);
|
||||
return st;
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
quant_tactics.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Tactics for benchmarks containing quantifiers.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-02-21.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _QUANT_TACTICS_H_
|
||||
#define _QUANT_TACTICS_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_ufnia_tactic(ast_manager & m, params_ref const & p);
|
||||
tactic * mk_uflra_tactic(ast_manager & m, params_ref const & p);
|
||||
tactic * mk_auflia_tactic(ast_manager & m, params_ref const & p);
|
||||
tactic * mk_auflira_tactic(ast_manager & m, params_ref const & p);
|
||||
tactic * mk_aufnira_tactic(ast_manager & m, params_ref const & p);
|
||||
tactic * mk_lra_tactic(ast_manager & m, params_ref const & p);
|
||||
|
||||
#endif
|
|
@ -1,61 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sls_strategy.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A Stochastic Local Search (SLS) strategy
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2011-09-23
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _SLS_STRATEGY_H_
|
||||
#define _SLS_STRATEGY_H_
|
||||
|
||||
#include"assertion_set_strategy.h"
|
||||
|
||||
MK_ST_EXCEPTION(sls_exception);
|
||||
|
||||
class sls_st : public assertion_set_strategy {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
public:
|
||||
sls_st(ast_manager & m, params_ref const & p = params_ref());
|
||||
virtual ~sls_st();
|
||||
|
||||
ast_manager & m () const;
|
||||
|
||||
virtual void updt_params(params_ref const & p);
|
||||
static void get_param_descrs(param_descrs & r);
|
||||
virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); }
|
||||
|
||||
bool is_target(assertion_set const & s) const;
|
||||
|
||||
virtual void operator()(assertion_set & s, model_converter_ref & mc);
|
||||
|
||||
virtual void cleanup();
|
||||
|
||||
virtual void collect_statistics(statistics & st) const;
|
||||
virtual void reset_statistics();
|
||||
protected:
|
||||
virtual void set_cancel(bool f);
|
||||
};
|
||||
|
||||
inline as_st * mk_sls(ast_manager & m, params_ref const & p = params_ref()) {
|
||||
return clean(alloc(sls_st, m, p));
|
||||
}
|
||||
|
||||
|
||||
as_st * mk_qfbv_sls_strategy(ast_manager & m, params_ref const & p);
|
||||
|
||||
MK_SIMPLE_ST_FACTORY(qfbv_sls_stf, mk_qfbv_sls_strategy(m, p));
|
||||
|
||||
#endif
|
1913
lib/sls_tactic.cpp
1913
lib/sls_tactic.cpp
File diff suppressed because it is too large
Load diff
|
@ -1,30 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sls_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A Stochastic Local Search (SLS) tactic
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2012-02-29
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _SLS_TACTIC_H_
|
||||
#define _SLS_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_sls_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
tactic * mk_qfbv_sls_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
3605
lib/smt_arith.cpp
3605
lib/smt_arith.cpp
File diff suppressed because it is too large
Load diff
|
@ -1,56 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt_arith.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Arithmetic solver for smt::solver
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-06-25.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SMT_ARITH_H_
|
||||
#define _SMT_ARITH_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"smt_solver_types.h"
|
||||
#include"params.h"
|
||||
#include"statistics.h"
|
||||
class model;
|
||||
|
||||
namespace smt {
|
||||
|
||||
class arith {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
public:
|
||||
arith(ast_manager & m, params_ref const & p);
|
||||
~arith();
|
||||
void updt_params(params_ref const & p);
|
||||
void assert_axiom(expr * t, bool neg);
|
||||
void mk_atom(expr * t, atom_id id);
|
||||
void asserted(atom_id id, bool is_true);
|
||||
bool inconsistent() const;
|
||||
void push();
|
||||
void pop(unsigned num_scopes);
|
||||
void set_cancel(bool f);
|
||||
void simplify();
|
||||
void display(std::ostream & out) const;
|
||||
void reset();
|
||||
void preprocess();
|
||||
void collect_statistics(statistics & st) const;
|
||||
void reset_statistics();
|
||||
lbool check();
|
||||
void mk_model(model * md);
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,619 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt_implied_equalities.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Procedure for obtaining implied equalities relative to the
|
||||
state of a solver.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-02-29
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "smt_implied_equalities.h"
|
||||
#include "union_find.h"
|
||||
#include "cmd_context.h"
|
||||
#include "parametric_cmd.h"
|
||||
#include "ast_pp.h"
|
||||
#include "arith_decl_plugin.h"
|
||||
#include "datatype_decl_plugin.h"
|
||||
#include "array_decl_plugin.h"
|
||||
#include "uint_set.h"
|
||||
#include "model_v2_pp.h"
|
||||
|
||||
|
||||
namespace smt {
|
||||
|
||||
class get_implied_equalities_impl {
|
||||
|
||||
ast_manager& m;
|
||||
smt::solver& m_solver;
|
||||
union_find_default_ctx m_df;
|
||||
union_find<union_find_default_ctx> m_uf;
|
||||
array_util m_array_util;
|
||||
stopwatch m_stats_timer;
|
||||
unsigned m_stats_calls;
|
||||
stopwatch m_stats_val_eq_timer;
|
||||
static stopwatch s_timer;
|
||||
static stopwatch s_stats_val_eq_timer;
|
||||
|
||||
struct term_id {
|
||||
expr_ref term;
|
||||
unsigned id;
|
||||
term_id(expr_ref t, unsigned id): term(t), id(id) {}
|
||||
};
|
||||
|
||||
typedef vector<term_id> term_ids;
|
||||
|
||||
typedef obj_map<sort, term_ids> sort2term_ids; // partition of terms by sort.
|
||||
|
||||
void partition_terms(unsigned num_terms, expr* const* terms, sort2term_ids& termids) {
|
||||
for (unsigned i = 0; i < num_terms; ++i) {
|
||||
sort* s = m.get_sort(terms[i]);
|
||||
term_ids& vec = termids.insert_if_not_there2(s, term_ids())->get_data().m_value;
|
||||
vec.push_back(term_id(expr_ref(terms[i],m), i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Basic implied equalities method.
|
||||
It performs a simple N^2 loop over all pairs of terms.
|
||||
|
||||
n1, .., n_k,
|
||||
t1, .., t_l
|
||||
*/
|
||||
|
||||
void get_implied_equalities_filter_basic(uint_set const& non_values, term_ids& terms) {
|
||||
m_stats_timer.start();
|
||||
uint_set root_indices;
|
||||
for (unsigned j = 0; j < terms.size(); ++j) {
|
||||
if (terms[j].id == m_uf.find(terms[j].id)) {
|
||||
root_indices.insert(j);
|
||||
}
|
||||
}
|
||||
uint_set::iterator it = non_values.begin(), end = non_values.end();
|
||||
|
||||
for (; it != end; ++it) {
|
||||
unsigned i = *it;
|
||||
expr* t = terms[i].term;
|
||||
uint_set::iterator it2 = root_indices.begin(), end2 = root_indices.end();
|
||||
bool found_root_value = false;
|
||||
for (; it2 != end2; ++it2) {
|
||||
unsigned j = *it2;
|
||||
if (j == i) continue;
|
||||
if (j < i && non_values.contains(j)) continue;
|
||||
if (found_root_value && !non_values.contains(j)) continue;
|
||||
expr* s = terms[j].term;
|
||||
SASSERT(m.get_sort(t) == m.get_sort(s));
|
||||
++m_stats_calls;
|
||||
m_solver.push();
|
||||
m_solver.assert_expr(m.mk_not(m.mk_eq(s, t)));
|
||||
bool is_eq = l_false == m_solver.check();
|
||||
m_solver.pop(1);
|
||||
TRACE("get_implied_equalities", tout << mk_pp(t, m) << " = " << mk_pp(s, m) << " " << (is_eq?"eq":"unrelated") << "\n";);
|
||||
if (is_eq) {
|
||||
m_uf.merge(terms[i].id, terms[j].id);
|
||||
if (!non_values.contains(j)) {
|
||||
found_root_value = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_stats_timer.stop();
|
||||
}
|
||||
|
||||
void get_implied_equalities_basic(term_ids& terms) {
|
||||
for (unsigned i = 0; i < terms.size(); ++i) {
|
||||
if (terms[i].id != m_uf.find(terms[i].id)) {
|
||||
continue;
|
||||
}
|
||||
expr* t = terms[i].term;
|
||||
for (unsigned j = 0; j < i; ++j) {
|
||||
expr* s = terms[j].term;
|
||||
SASSERT(m.get_sort(t) == m.get_sort(s));
|
||||
++m_stats_calls;
|
||||
m_stats_timer.start();
|
||||
m_solver.push();
|
||||
m_solver.assert_expr(m.mk_not(m.mk_eq(s, t)));
|
||||
bool is_eq = l_false == m_solver.check();
|
||||
m_solver.pop(1);
|
||||
m_stats_timer.stop();
|
||||
TRACE("get_implied_equalities", tout << mk_pp(t, m) << " = " << mk_pp(s, m) << " " << (is_eq?"eq":"unrelated") << "\n";);
|
||||
if (is_eq) {
|
||||
m_uf.merge(terms[i].id, terms[j].id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_simple_type(sort* s) {
|
||||
arith_util arith(m);
|
||||
datatype_util data(m);
|
||||
|
||||
ptr_vector<sort> sorts;
|
||||
ast_mark mark;
|
||||
sorts.push_back(s);
|
||||
|
||||
while (!sorts.empty()) {
|
||||
s = sorts.back();
|
||||
sorts.pop_back();
|
||||
if (mark.is_marked(s)) {
|
||||
continue;
|
||||
}
|
||||
mark.mark(s, true);
|
||||
if (arith.is_int_real(s)) {
|
||||
// simple
|
||||
}
|
||||
else if (m.is_bool(s)) {
|
||||
// simple
|
||||
}
|
||||
else if (data.is_datatype(s)) {
|
||||
ptr_vector<func_decl> const& cs = *data.get_datatype_constructors(s);
|
||||
for (unsigned i = 0; i < cs.size(); ++i) {
|
||||
func_decl* f = cs[i];
|
||||
for (unsigned j = 0; j < f->get_arity(); ++j) {
|
||||
sorts.push_back(f->get_domain(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Extract implied equalities for a collection of terms in the current context.
|
||||
|
||||
The routine relies on model values being unique for equal terms.
|
||||
So in particular, arrays that are equal should be canonized to the same value.
|
||||
This is not the case for Z3's models of arrays.
|
||||
Arrays are treated by extensionality: introduce a fresh index and compare
|
||||
the select of the arrays.
|
||||
*/
|
||||
void get_implied_equalities_model_based(model_ref& model, term_ids& terms) {
|
||||
|
||||
SASSERT(!terms.empty());
|
||||
|
||||
sort* srt = m.get_sort(terms[0].term);
|
||||
|
||||
if (m_array_util.is_array(srt)) {
|
||||
|
||||
m_solver.push();
|
||||
unsigned arity = get_array_arity(srt);
|
||||
expr_ref_vector args(m);
|
||||
args.push_back(0);
|
||||
for (unsigned i = 0; i < arity; ++i) {
|
||||
sort* srt_i = get_array_domain(srt, i);
|
||||
expr* idx = m.mk_fresh_const("index", srt_i);
|
||||
args.push_back(idx);
|
||||
}
|
||||
for (unsigned i = 0; i < terms.size(); ++i) {
|
||||
args[0] = terms[i].term;
|
||||
terms[i].term = m.mk_app(m_array_util.get_family_id(), OP_SELECT, 0, 0, args.size(), args.c_ptr());
|
||||
}
|
||||
assert_relevant(terms);
|
||||
lbool is_sat = m_solver.check();
|
||||
model_ref model1;
|
||||
m_solver.get_model(model1);
|
||||
SASSERT(model1.get());
|
||||
SASSERT(is_sat != l_false);
|
||||
get_implied_equalities_model_based(model1, terms);
|
||||
m_solver.pop(1);
|
||||
return;
|
||||
}
|
||||
|
||||
uint_set non_values;
|
||||
|
||||
if (!is_simple_type(srt)) {
|
||||
for (unsigned i = 0; i < terms.size(); ++i) {
|
||||
non_values.insert(i);
|
||||
}
|
||||
get_implied_equalities_filter_basic(non_values, terms);
|
||||
//get_implied_equalities_basic(terms);
|
||||
return;
|
||||
}
|
||||
|
||||
expr_ref_vector vals(m);
|
||||
expr_ref vl(m), eq(m);
|
||||
obj_map<expr, unsigned_vector> vals_map;
|
||||
|
||||
m_stats_val_eq_timer.start();
|
||||
s_stats_val_eq_timer.start();
|
||||
|
||||
params_ref p;
|
||||
p.set_bool(":produce-models", false);
|
||||
m_solver.updt_params(p);
|
||||
|
||||
for (unsigned i = 0; i < terms.size(); ++i) {
|
||||
expr* t = terms[i].term;
|
||||
model->eval(t, vl);
|
||||
TRACE("get_implied_equalities", tout << mk_pp(t, m) << " |-> " << mk_pp(vl, m) << "\n";);
|
||||
reduce_value(model, vl);
|
||||
if (!m.is_value(vl)) {
|
||||
TRACE("get_implied_equalities", tout << "Not a value: " << mk_pp(vl, m) << "\n";);
|
||||
non_values.insert(i);
|
||||
continue;
|
||||
}
|
||||
vals.push_back(vl);
|
||||
unsigned_vector& vec = vals_map.insert_if_not_there2(vl, unsigned_vector())->get_data().m_value;
|
||||
bool found = false;
|
||||
|
||||
for (unsigned j = 0; !found && j < vec.size(); ++j) {
|
||||
expr* s = terms[vec[j]].term;
|
||||
m_solver.push();
|
||||
m_solver.assert_expr(m.mk_not(m.mk_eq(t, s)));
|
||||
lbool is_sat = m_solver.check();
|
||||
m_solver.pop(1);
|
||||
TRACE("get_implied_equalities", tout << mk_pp(t, m) << " = " << mk_pp(s, m) << " " << is_sat << "\n";);
|
||||
if (is_sat == l_false) {
|
||||
found = true;
|
||||
m_uf.merge(terms[i].id, terms[vec[j]].id);
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
vec.push_back(i);
|
||||
}
|
||||
}
|
||||
m_stats_val_eq_timer.stop();
|
||||
s_stats_val_eq_timer.stop();
|
||||
p.set_bool(":produce-models", true);
|
||||
m_solver.updt_params(p);
|
||||
|
||||
|
||||
if (!non_values.empty()) {
|
||||
TRACE("get_implied_equalities", model_v2_pp(tout, *model, true););
|
||||
get_implied_equalities_filter_basic(non_values, terms);
|
||||
//get_implied_equalities_basic(terms);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void get_implied_equalities_core(model_ref& model, term_ids& terms) {
|
||||
get_implied_equalities_model_based(model, terms);
|
||||
//get_implied_equalities_basic(terms);
|
||||
}
|
||||
|
||||
|
||||
void assert_relevant(unsigned num_terms, expr* const* terms) {
|
||||
for (unsigned i = 0; i < num_terms; ++i) {
|
||||
sort* srt = m.get_sort(terms[i]);
|
||||
if (!m_array_util.is_array(srt)) {
|
||||
m_solver.assert_expr(m.mk_app(m.mk_func_decl(symbol("Relevant!"), 1, &srt, m.mk_bool_sort()), terms[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assert_relevant(term_ids& terms) {
|
||||
for (unsigned i = 0; i < terms.size(); ++i) {
|
||||
expr* t = terms[i].term;
|
||||
sort* srt = m.get_sort(t);
|
||||
if (!m_array_util.is_array(srt)) {
|
||||
m_solver.assert_expr(m.mk_app(m.mk_func_decl(symbol("Relevant!"), 1, &srt, m.mk_bool_sort()), t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reduce_value(model_ref& model, expr_ref& vl) {
|
||||
expr* c, *e1, *e2;
|
||||
while (m.is_ite(vl, c, e1, e2)) {
|
||||
lbool r = reduce_cond(model, c);
|
||||
switch(r) {
|
||||
case l_true:
|
||||
vl = e1;
|
||||
break;
|
||||
case l_false:
|
||||
vl = e2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lbool reduce_cond(model_ref& model, expr* e) {
|
||||
expr* e1, *e2;
|
||||
if (m.is_eq(e, e1, e2) && m_array_util.is_as_array(e1) && m_array_util.is_as_array(e2)) {
|
||||
if (e1 == e2) {
|
||||
return l_true;
|
||||
}
|
||||
func_decl* f1 = m_array_util.get_as_array_func_decl(to_app(e1));
|
||||
func_decl* f2 = m_array_util.get_as_array_func_decl(to_app(e2));
|
||||
func_interp* fi1 = model->get_func_interp(f1);
|
||||
func_interp* fi2 = model->get_func_interp(f2);
|
||||
if (fi1 == fi2) {
|
||||
return l_true;
|
||||
}
|
||||
unsigned n1 = fi1->num_entries();
|
||||
for (unsigned i = 0; i < n1; ++i) {
|
||||
func_entry const* h1 = fi1->get_entry(i);
|
||||
for (unsigned j = 0; j < fi1->get_arity(); ++j) {
|
||||
if (!m.is_value(h1->get_arg(j))) {
|
||||
return l_undef;
|
||||
}
|
||||
}
|
||||
func_entry* h2 = fi2->get_entry(h1->get_args());
|
||||
if (h2 &&
|
||||
h1->get_result() != h2->get_result() &&
|
||||
m.is_value(h1->get_result()) &&
|
||||
m.is_value(h2->get_result())) {
|
||||
return l_false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
get_implied_equalities_impl(smt::solver& s) : m(s.m()), m_solver(s), m_uf(m_df), m_array_util(m), m_stats_calls(0) {}
|
||||
|
||||
lbool operator()(unsigned num_terms, expr* const* terms, unsigned* class_ids) {
|
||||
params_ref p;
|
||||
p.set_bool(":produce-models", true);
|
||||
m_solver.updt_params(p);
|
||||
sort2term_ids termids;
|
||||
stopwatch timer;
|
||||
timer.start();
|
||||
s_timer.start();
|
||||
|
||||
for (unsigned i = 0; i < num_terms; ++i) {
|
||||
m_uf.mk_var();
|
||||
}
|
||||
|
||||
m_solver.push();
|
||||
assert_relevant(num_terms, terms);
|
||||
lbool is_sat = m_solver.check();
|
||||
|
||||
if (is_sat != l_false) {
|
||||
model_ref model;
|
||||
m_solver.get_model(model);
|
||||
SASSERT(model.get());
|
||||
|
||||
partition_terms(num_terms, terms, termids);
|
||||
sort2term_ids::iterator it = termids.begin(), end = termids.end();
|
||||
for (; it != end; ++it) {
|
||||
term_ids& term_ids = it->m_value;
|
||||
get_implied_equalities_core(model, term_ids);
|
||||
for (unsigned i = 0; i < term_ids.size(); ++i) {
|
||||
class_ids[term_ids[i].id] = m_uf.find(term_ids[i].id);
|
||||
}
|
||||
}
|
||||
TRACE("get_implied_equalities",
|
||||
for (unsigned i = 0; i < num_terms; ++i) {
|
||||
tout << mk_pp(terms[i], m) << " |-> " << class_ids[i] << "\n";
|
||||
});
|
||||
}
|
||||
m_solver.pop(1);
|
||||
timer.stop();
|
||||
s_timer.stop();
|
||||
IF_VERBOSE(1, verbose_stream() << s_timer.get_seconds() << "\t" << num_terms << "\t"
|
||||
<< timer.get_seconds() << "\t" << m_stats_calls << "\t"
|
||||
<< m_stats_timer.get_seconds() << "\t"
|
||||
<< m_stats_val_eq_timer.get_seconds() << "\t"
|
||||
<< s_stats_val_eq_timer.get_seconds() << "\n";);
|
||||
return is_sat;
|
||||
}
|
||||
};
|
||||
|
||||
stopwatch get_implied_equalities_impl::s_timer;
|
||||
stopwatch get_implied_equalities_impl::s_stats_val_eq_timer;
|
||||
|
||||
lbool implied_equalities(smt::solver& solver, unsigned num_terms, expr* const* terms, unsigned* class_ids) {
|
||||
get_implied_equalities_impl gi(solver);
|
||||
return gi(num_terms, terms, class_ids);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
// maxsat class for internal purposes.
|
||||
class maxsat {
|
||||
ast_manager& m;
|
||||
solver& m_solver;
|
||||
public:
|
||||
maxsat(solver& s) : m(s.m()), m_solver(s) {}
|
||||
|
||||
lbool operator()(ptr_vector<expr>& soft_cnstrs) {
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class term_equivs {
|
||||
union_find_default_ctx m_df;
|
||||
union_find<union_find_default_ctx> m_uf;
|
||||
obj_map<expr,unsigned> m_term2idx;
|
||||
ptr_vector<expr> m_idx2term;
|
||||
|
||||
public:
|
||||
term_equivs(): m_uf(m_df) {}
|
||||
|
||||
void merge(expr* t, expr* s) {
|
||||
m_uf.merge(var(t), var(s));
|
||||
}
|
||||
private:
|
||||
unsigned var(expr* t) {
|
||||
map::obj_map_entry* e = m_term2idx.insert_if_not_there(t, m_idx2term.size());
|
||||
unsigned idx = e->get_data().m_value;
|
||||
if (idx == m_idx2term.size()) {
|
||||
m_idx2term.push_back(t);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief class to find implied equalities.
|
||||
|
||||
It implements the following half-naive algorithm.
|
||||
The algorithm is half-naive because the terms being checked for equivalence class membership
|
||||
are foreign and it is up to the theory integration whether pairs of interface equalities
|
||||
are checked. The idea is that the model-based combination would avoid useless equality literals
|
||||
in the core.
|
||||
An alternative algorithm could use 'distinct' and an efficient solver for 'distinct'.
|
||||
|
||||
Given terms t1, ..., tn, of the same type.
|
||||
- assert f(t1) = 1, .., f(tn) = n.
|
||||
- find MAX-SAT set A1, let the other literals be in B.
|
||||
- find MAX-SAT set of B, put it in A2, etc.
|
||||
- we now have MAX-SAT sets A1, A2, ... A_m.
|
||||
- terms in each set A_i can be different, but cannot be different at the same time as elements in A_{i+1}.
|
||||
- for i = m to 2 do:
|
||||
- Let A = A_i B = A_{i-1}
|
||||
- assert g(A) = 0, g(B) = 1
|
||||
- find MAX-SAT set C over this constraint.
|
||||
- For each element t from A\C
|
||||
- check if g(t) = 0 and g(B) = 1 is unsat
|
||||
- minimize core, if there is pair such that
|
||||
- g(t) = 0, g(b) = 1 is unsat, then equality is forced.
|
||||
*/
|
||||
|
||||
class implied_equalities_finder {
|
||||
ast_manager& m;
|
||||
solver& m_solver;
|
||||
term_equivs m_find;
|
||||
expr_ref_vector m_refs;
|
||||
obj_map<expr,expr*> m_fs; // t_i -> f(t_i) = i
|
||||
obj_map<expr,epxr*> m_gs; // t_i -> g(t_i)
|
||||
|
||||
public:
|
||||
implied_equalities_finder(solver& solver): m(solver.m()), m_solver(solver), m_refs(m) {}
|
||||
|
||||
lbool operator()(unsigned num_terms, expr* const* terms, unsigned* class_ids) {
|
||||
m_find.reset();
|
||||
//
|
||||
return l_undef;
|
||||
}
|
||||
private:
|
||||
|
||||
void initialize(unsigned num_terms, expr* const* terms) {
|
||||
sort_ref bv(m);
|
||||
expr_ref eq(m), g(m), eq_proxy(m);
|
||||
symbol f("f"), g("g");
|
||||
unsigned log_terms = 1, nt = num_terms;
|
||||
while (nt > 0) { log_terms++; nt /= 2; }
|
||||
|
||||
bv = m_bv.mk_bv_sort(log_terms);
|
||||
for (unsigned i = 0; i < num_terms; ++i) {
|
||||
expr* t = terms[i];
|
||||
sort* s = m.get_sort(t);
|
||||
eq = m.mk_eq(m.mk_app(m.mk_func_decl(f, 1, &s, bv), t), m_bv.mk_numeral(rational(i), bv));
|
||||
eq_proxy = m.mk_fresh_const("f", m.mk_bool_sort());
|
||||
m_solver.assert_expr(m.mk_iff(eq, eq_proxy));
|
||||
g = m.mk_app(m.mk_func_decl(g, 1, &s, bv), t)
|
||||
m_fs.insert(t, eq_proxy);
|
||||
m_gs.insert(t, g);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// For each t in src, check if t can be different from all s in dst.
|
||||
// - if it can, then add t to dst.
|
||||
// - if it cannot, then record equivalence class.
|
||||
//
|
||||
void merge_classes(expr_ref_vector& src, expr_ref_vector& dst, equivs& eqs) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
lbool implied_equalities_core_based(
|
||||
solver& solver,
|
||||
unsigned num_terms, expr* const* terms,
|
||||
unsigned* class_ids,
|
||||
unsigned num_assumptions, expr * const * assumptions) {
|
||||
implied_equalities_finder ief(solver);
|
||||
|
||||
solver.push();
|
||||
for (unsigned i = 0; i < num_assumptions; ++i) {
|
||||
solver.assert_expr(assumptions[i]);
|
||||
}
|
||||
lbool is_sat = ief(num_terms, terms, class_ids);
|
||||
solver.pop(1);
|
||||
|
||||
return is_sat;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Extract implied equalities for a collection of terms in the current context.
|
||||
|
||||
The routine uses a partition refinement approach.
|
||||
It assumes that all terms have the same sort.
|
||||
|
||||
Initially, create the equalities E_1: t0 = t1, E_2: t1 = t2, ..., E_n: t_{n-1} = t_n
|
||||
|
||||
Check if ! (E_1 & E_2 & ... & E_n) is satisfiable.
|
||||
|
||||
if it is unsat, then all terms are equal.
|
||||
Otherwise, partition the terms by the equalities that are true in the current model,
|
||||
iterate.
|
||||
|
||||
|
||||
This version does not attempt to be economical on how many equalities are introduced and the
|
||||
size of the resulting clauses. The more advanced version of this approach re-uses
|
||||
equalities from a previous iteration and also represents a binary tree of propositional variables
|
||||
that cover multiple equalities. Eg.,
|
||||
|
||||
E_12 => E_1 & E_2, E_34 => E_3 & E_4, ...
|
||||
|
||||
|
||||
*/
|
||||
|
||||
void get_implied_equalities_eq_based(term_ids& terms) {
|
||||
expr_ref_vector eqs(m);
|
||||
if (terms.size() == 1) {
|
||||
return;
|
||||
}
|
||||
m_solver.push();
|
||||
for (unsigned i = 0; i + 1 < terms.size(); ++i) {
|
||||
expr* eq = m.mk_eq(terms[i].term, terms[i+1].term);
|
||||
expr* eq_lit = m.mk_fresh_const("E", m.mk_bool_sort());
|
||||
eqs.push_back(eq_lit);
|
||||
m_solver.assert_expr(m.mk_implies(eq_lit, eq));
|
||||
}
|
||||
m_solver.assert_expr(m.mk_not(m.mk_and(eqs.size(), eqs.c_ptr())));
|
||||
lbool is_sat = m_solver.check();
|
||||
switch(is_sat) {
|
||||
case l_false:
|
||||
for (unsigned i = 0; i + 1 < terms.size(); ++i) {
|
||||
m_uf.merge(terms[i].id, terms[i+1].id);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
term_ids tems2;
|
||||
for (unsigned i = 0; i + 1 < terms.size(); ++i) {
|
||||
expr_ref vl(m);
|
||||
model->eval(terms[i].term, vl);
|
||||
if (m.is_false(vl)) {
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_solver.pop(1);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt_implied_equalities.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Procedure for obtaining implied equalities relative to the
|
||||
state of a solver.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-02-29
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#ifndef __SMT_IMPLIED_EQUALITIES_H__
|
||||
#define __SMT_IMPLIED_EQUALITIES_H__
|
||||
|
||||
#include"smt_solver.h"
|
||||
|
||||
|
||||
namespace smt {
|
||||
|
||||
lbool implied_equalities(
|
||||
solver& solver,
|
||||
unsigned num_terms, expr* const* terms,
|
||||
unsigned* class_ids);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,317 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
smt::context as a tactic.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-10-18
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactic.h"
|
||||
#include"tactical.h"
|
||||
#include"smt_solver.h"
|
||||
#include"front_end_params.h"
|
||||
#include"params2front_end_params.h"
|
||||
|
||||
class smt_tactic : public tactic {
|
||||
scoped_ptr<front_end_params> m_params;
|
||||
params_ref m_params_ref;
|
||||
statistics m_stats;
|
||||
std::string m_failure;
|
||||
smt::solver * m_ctx;
|
||||
symbol m_logic;
|
||||
progress_callback * m_callback;
|
||||
bool m_candidate_models;
|
||||
bool m_fail_if_inconclusive;
|
||||
|
||||
public:
|
||||
smt_tactic(params_ref const & p):
|
||||
m_params_ref(p),
|
||||
m_ctx(0),
|
||||
m_callback(0) {
|
||||
updt_params_core(p);
|
||||
TRACE("smt_tactic", tout << this << "\np: " << p << "\n";);
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(smt_tactic, m_params_ref);
|
||||
}
|
||||
|
||||
virtual ~smt_tactic() {
|
||||
SASSERT(m_ctx == 0);
|
||||
}
|
||||
|
||||
front_end_params & fparams() {
|
||||
if (!m_params) {
|
||||
m_params = alloc(front_end_params);
|
||||
params2front_end_params(m_params_ref, fparams());
|
||||
}
|
||||
return *m_params;
|
||||
}
|
||||
|
||||
void updt_params_core(params_ref const & p) {
|
||||
m_candidate_models = p.get_bool(":candidate-models", false);
|
||||
m_fail_if_inconclusive = p.get_bool(":fail-if-inconclusive", true);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
TRACE("smt_tactic", tout << this << "\nupdt_params: " << p << "\n";);
|
||||
updt_params_core(p);
|
||||
m_params_ref = p;
|
||||
params2front_end_params(m_params_ref, fparams());
|
||||
SASSERT(p.get_bool(":auto_config", fparams().m_auto_config) == fparams().m_auto_config);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
r.insert(":candidate-models", CPK_BOOL, "(default: false) create candidate models even when quantifier or theory reasoning is incomplete.");
|
||||
r.insert(":fail-if-inconclusive", CPK_BOOL, "(default: true) fail if found unsat (sat) for under (over) approximated goal.");
|
||||
solver_front_end_params_descrs(r);
|
||||
}
|
||||
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_ctx)
|
||||
m_ctx->set_cancel(f);
|
||||
}
|
||||
|
||||
virtual void collect_statistics(statistics & st) const {
|
||||
if (m_ctx)
|
||||
m_ctx->collect_statistics(st); // ctx is still running...
|
||||
else
|
||||
st.copy(m_stats);
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
}
|
||||
|
||||
virtual void reset_statistics() {
|
||||
m_stats.reset();
|
||||
}
|
||||
|
||||
// for backward compatibility
|
||||
virtual void set_front_end_params(front_end_params & p) {
|
||||
m_params = alloc(front_end_params, p);
|
||||
SASSERT(m_params.get() == &fparams());
|
||||
// must propagate the params_ref to fparams
|
||||
params2front_end_params(m_params_ref, fparams());
|
||||
}
|
||||
|
||||
virtual void set_logic(symbol const & l) {
|
||||
m_logic = l;
|
||||
}
|
||||
|
||||
virtual void set_progress_callback(progress_callback * callback) {
|
||||
m_callback = callback;
|
||||
}
|
||||
|
||||
struct scoped_init_ctx {
|
||||
smt_tactic & m_owner;
|
||||
|
||||
scoped_init_ctx(smt_tactic & o, ast_manager & m):m_owner(o) {
|
||||
smt::solver * new_ctx = alloc(smt::solver, m, o.fparams());
|
||||
TRACE("smt_tactic", tout << "logic: " << o.m_logic << "\n";);
|
||||
new_ctx->set_logic(o.m_logic);
|
||||
if (o.m_callback) {
|
||||
new_ctx->set_progress_callback(o.m_callback);
|
||||
}
|
||||
#pragma omp critical (as_st_solver)
|
||||
{
|
||||
o.m_ctx = new_ctx;
|
||||
}
|
||||
}
|
||||
|
||||
~scoped_init_ctx() {
|
||||
smt::solver * d = m_owner.m_ctx;
|
||||
#pragma omp critical (as_st_cancel)
|
||||
{
|
||||
m_owner.m_ctx = 0;
|
||||
}
|
||||
if (d)
|
||||
dealloc(d);
|
||||
}
|
||||
};
|
||||
|
||||
typedef obj_map<expr, expr *> expr2expr_map;
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(in->is_well_sorted());
|
||||
ast_manager & m = in->m();
|
||||
TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " "
|
||||
<< " PREPROCESS: " << fparams().m_preprocess << ", SOLVER:" << fparams().m_solver << "\n";
|
||||
tout << "fail-if-inconclusive: " << m_fail_if_inconclusive << "\n";
|
||||
tout << "params_ref: " << m_params_ref << "\n";);
|
||||
TRACE("smt_tactic_detail", in->display(tout););
|
||||
TRACE("smt_tactic_memory", tout << "wasted_size: " << m.get_allocator().get_wasted_size() << "\n";);
|
||||
scoped_init_ctx init(*this, m);
|
||||
SASSERT(m_ctx != 0);
|
||||
|
||||
scoped_ptr<expr2expr_map> dep2bool;
|
||||
scoped_ptr<expr2expr_map> bool2dep;
|
||||
ptr_vector<expr> assumptions;
|
||||
if (in->unsat_core_enabled()) {
|
||||
if (in->proofs_enabled())
|
||||
throw tactic_exception("smt tactic does not support simultaneous generation of proofs and unsat cores");
|
||||
dep2bool = alloc(expr2expr_map);
|
||||
bool2dep = alloc(expr2expr_map);
|
||||
ptr_vector<expr> deps;
|
||||
ptr_vector<expr> clause;
|
||||
unsigned sz = in->size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * f = in->form(i);
|
||||
expr_dependency * d = in->dep(i);
|
||||
if (d == 0) {
|
||||
m_ctx->assert_expr(f);
|
||||
}
|
||||
else {
|
||||
// create clause (not d1 \/ ... \/ not dn \/ f) when the d's are the assumptions/dependencies of f.
|
||||
clause.reset();
|
||||
clause.push_back(f);
|
||||
deps.reset();
|
||||
m.linearize(d, deps);
|
||||
SASSERT(!deps.empty()); // d != 0, then deps must not be empty
|
||||
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) && m.is_bool(d)) {
|
||||
// no need to create a fresh boolean variable for d
|
||||
if (!bool2dep->contains(d)) {
|
||||
assumptions.push_back(d);
|
||||
bool2dep->insert(d, d);
|
||||
}
|
||||
clause.push_back(m.mk_not(d));
|
||||
}
|
||||
else {
|
||||
// must normalize assumption
|
||||
expr * b = 0;
|
||||
if (!dep2bool->find(d, b)) {
|
||||
b = m.mk_fresh_const(0, m.mk_bool_sort());
|
||||
dep2bool->insert(d, b);
|
||||
bool2dep->insert(b, d);
|
||||
assumptions.push_back(b);
|
||||
}
|
||||
clause.push_back(m.mk_not(b));
|
||||
}
|
||||
}
|
||||
SASSERT(clause.size() > 1);
|
||||
expr_ref cls(m);
|
||||
cls = m.mk_or(clause.size(), clause.c_ptr());
|
||||
m_ctx->assert_expr(cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (in->proofs_enabled()) {
|
||||
unsigned sz = in->size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
m_ctx->assert_expr(in->form(i), in->pr(i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned sz = in->size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
m_ctx->assert_expr(in->form(i));
|
||||
}
|
||||
}
|
||||
|
||||
lbool r;
|
||||
if (assumptions.empty())
|
||||
r = m_ctx->setup_and_check();
|
||||
else
|
||||
r = m_ctx->check(assumptions.size(), assumptions.c_ptr());
|
||||
m_ctx->collect_statistics(m_stats);
|
||||
|
||||
switch (r) {
|
||||
case l_true: {
|
||||
if (m_fail_if_inconclusive && !in->sat_preserved())
|
||||
throw tactic_exception("over-approximated goal found to be sat");
|
||||
// the empty assertion set is trivially satifiable.
|
||||
in->reset();
|
||||
result.push_back(in.get());
|
||||
// store the model in a do nothin model converter.
|
||||
if (in->models_enabled()) {
|
||||
model_ref md;
|
||||
m_ctx->get_model(md);
|
||||
mc = model2model_converter(md.get());
|
||||
}
|
||||
pc = 0;
|
||||
core = 0;
|
||||
return;
|
||||
}
|
||||
case l_false: {
|
||||
if (m_fail_if_inconclusive && !in->unsat_preserved()) {
|
||||
TRACE("smt_tactic", tout << "failed to show to be unsat...\n";);
|
||||
throw tactic_exception("under-approximated goal found to be unsat");
|
||||
}
|
||||
// formula is unsat, reset the goal, and store false there.
|
||||
in->reset();
|
||||
proof * pr = 0;
|
||||
expr_dependency * lcore = 0;
|
||||
if (in->proofs_enabled())
|
||||
pr = m_ctx->get_proof();
|
||||
if (in->unsat_core_enabled()) {
|
||||
unsigned sz = m_ctx->get_unsat_core_size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * b = m_ctx->get_unsat_core_expr(i);
|
||||
SASSERT(is_uninterp_const(b) && m.is_bool(b));
|
||||
expr * d = bool2dep->find(b);
|
||||
lcore = m.mk_join(lcore, m.mk_leaf(d));
|
||||
}
|
||||
}
|
||||
in->assert_expr(m.mk_false(), pr, lcore);
|
||||
result.push_back(in.get());
|
||||
mc = 0;
|
||||
pc = 0;
|
||||
core = 0;
|
||||
return;
|
||||
}
|
||||
case l_undef:
|
||||
if (m_fail_if_inconclusive)
|
||||
throw tactic_exception("smt tactic failed to show goal to be sat/unsat");
|
||||
result.push_back(in.get());
|
||||
if (m_candidate_models) {
|
||||
switch (m_ctx->last_failure()) {
|
||||
case smt::NUM_CONFLICTS:
|
||||
case smt::THEORY:
|
||||
case smt::QUANTIFIERS:
|
||||
if (in->models_enabled()) {
|
||||
model_ref md;
|
||||
m_ctx->get_model(md);
|
||||
mc = model2model_converter(md.get());
|
||||
}
|
||||
pc = 0;
|
||||
core = 0;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_failure = m_ctx->last_failure_as_string();
|
||||
throw tactic_exception(m_failure.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_smt_tactic(params_ref const & p) {
|
||||
return alloc(smt_tactic, p);
|
||||
}
|
||||
|
||||
tactic * mk_smt_tactic_using(bool auto_config, params_ref const & _p) {
|
||||
params_ref p = _p;
|
||||
p.set_bool(":auto-config", auto_config);
|
||||
tactic * r = mk_smt_tactic(p);
|
||||
TRACE("smt_tactic", tout << "auto_config: " << auto_config << "\nr: " << r << "\np: " << p << "\n";);
|
||||
return using_params(r, p);
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
smt_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
smt::context as a tactic.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-10-18
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _SMT_TACTIC_H_
|
||||
#define _SMT_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
|
||||
class tactic;
|
||||
|
||||
tactic * mk_smt_tactic(params_ref const & p = params_ref());
|
||||
// syntax sugar for using_params(mk_smt_tactic(), p) where p = (:auto_config, auto_config)
|
||||
tactic * mk_smt_tactic_using(bool auto_config = true, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
|
@ -1,308 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
subpaving_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
"Fake" tactic used to test subpaving module.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-08-07.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"expr2subpaving.h"
|
||||
#include"expr2var.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"hwf.h"
|
||||
#include"mpff.h"
|
||||
#include"mpfx.h"
|
||||
#include"f2n.h"
|
||||
|
||||
class subpaving_tactic : public tactic {
|
||||
|
||||
struct display_var_proc : public subpaving::display_var_proc {
|
||||
expr_ref_vector m_inv;
|
||||
|
||||
display_var_proc(expr2var & e2v):m_inv(e2v.m()) {
|
||||
e2v.mk_inv(m_inv);
|
||||
}
|
||||
|
||||
ast_manager & m() const { return m_inv.get_manager(); }
|
||||
|
||||
virtual void operator()(std::ostream & out, subpaving::var x) const {
|
||||
expr * t = m_inv.get(x, 0);
|
||||
if (t != 0)
|
||||
out << mk_ismt2_pp(t, m());
|
||||
else
|
||||
out << "k!" << x;
|
||||
}
|
||||
};
|
||||
|
||||
struct imp {
|
||||
enum engine_kind { MPQ, MPF, HWF, MPFF, MPFX, NONE };
|
||||
|
||||
ast_manager & m_manager;
|
||||
unsynch_mpq_manager m_qm;
|
||||
mpf_manager m_fm_core;
|
||||
f2n<mpf_manager> m_fm;
|
||||
hwf_manager m_hm_core;
|
||||
f2n<hwf_manager> m_hm;
|
||||
mpff_manager m_ffm;
|
||||
mpfx_manager m_fxm;
|
||||
arith_util m_autil;
|
||||
engine_kind m_kind;
|
||||
scoped_ptr<subpaving::context> m_ctx;
|
||||
scoped_ptr<display_var_proc> m_proc;
|
||||
expr2var m_e2v;
|
||||
scoped_ptr<expr2subpaving> m_e2s;
|
||||
bool m_display;
|
||||
|
||||
imp(ast_manager & m, params_ref const & p):
|
||||
m_manager(m),
|
||||
m_fm(m_fm_core),
|
||||
m_hm(m_hm_core),
|
||||
m_autil(m),
|
||||
m_kind(NONE),
|
||||
m_e2v(m) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
ast_manager & m() const { return m_manager; }
|
||||
|
||||
void collect_param_descrs(param_descrs & r) {
|
||||
m_ctx->collect_param_descrs(r);
|
||||
// #ifndef _EXTERNAL_RELEASE
|
||||
r.insert(":numeral", CPK_SYMBOL, "(default: mpq) options: mpq, mpf, hwf, mpff, mpfx.");
|
||||
r.insert(":print-nodes", CPK_BOOL, "(default: false) display subpaving tree leaves.");
|
||||
// #endif
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_display = p.get_bool(":print-nodes", false);
|
||||
symbol engine = p.get_sym(":numeral", symbol("mpq"));
|
||||
engine_kind new_kind;
|
||||
if (engine == "mpq")
|
||||
new_kind = MPQ;
|
||||
else if (engine == "mpf")
|
||||
new_kind = MPF;
|
||||
else if (engine == "mpff")
|
||||
new_kind = MPFF;
|
||||
else if (engine == "mpfx")
|
||||
new_kind = MPFX;
|
||||
else
|
||||
new_kind = HWF;
|
||||
if (m_kind != new_kind) {
|
||||
m_kind = new_kind;
|
||||
switch (m_kind) {
|
||||
case MPQ: m_ctx = subpaving::mk_mpq_context(m_qm); break;
|
||||
case MPF: m_ctx = subpaving::mk_mpf_context(m_fm); break;
|
||||
case HWF: m_ctx = subpaving::mk_hwf_context(m_hm, m_qm); break;
|
||||
case MPFF: m_ctx = subpaving::mk_mpff_context(m_ffm, m_qm); break;
|
||||
case MPFX: m_ctx = subpaving::mk_mpfx_context(m_fxm, m_qm); break;
|
||||
default: UNREACHABLE(); break;
|
||||
}
|
||||
m_e2s = alloc(expr2subpaving, m_manager, *m_ctx, &m_e2v);
|
||||
}
|
||||
m_ctx->updt_params(p);
|
||||
}
|
||||
|
||||
void collect_statistics(statistics & st) const {
|
||||
m_ctx->collect_statistics(st);
|
||||
}
|
||||
|
||||
void reset_statistics() {
|
||||
m_ctx->reset_statistics();
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_e2s->set_cancel(f);
|
||||
m_ctx->set_cancel(f);
|
||||
}
|
||||
|
||||
subpaving::ineq * mk_ineq(expr * a) {
|
||||
bool neg = false;
|
||||
while (m().is_not(a, a))
|
||||
neg = !neg;
|
||||
bool lower;
|
||||
bool open = false;
|
||||
if (m_autil.is_le(a)) {
|
||||
lower = false;
|
||||
}
|
||||
else if (m_autil.is_ge(a)) {
|
||||
lower = true;
|
||||
}
|
||||
else {
|
||||
throw tactic_exception("unsupported atom");
|
||||
}
|
||||
if (neg) {
|
||||
lower = !lower;
|
||||
open = !open;
|
||||
}
|
||||
rational _k;
|
||||
if (!m_autil.is_numeral(to_app(a)->get_arg(1), _k))
|
||||
throw tactic_exception("use simplify tactic with option :arith-lhs true");
|
||||
scoped_mpq k(m_qm);
|
||||
k = _k.to_mpq();
|
||||
scoped_mpz n(m_qm), d(m_qm);
|
||||
subpaving::var x = m_e2s->internalize_term(to_app(a)->get_arg(0), n, d);
|
||||
m_qm.mul(d, k, k);
|
||||
m_qm.div(k, n, k);
|
||||
if (is_neg(n))
|
||||
lower = !lower;
|
||||
TRACE("subpaving_tactic", tout << x << " " << k << " " << lower << " " << open << "\n";);
|
||||
return m_ctx->mk_ineq(x, k, lower, open);
|
||||
}
|
||||
|
||||
void process_clause(expr * c) {
|
||||
expr * const * args = 0;
|
||||
unsigned sz;
|
||||
if (m().is_or(c)) {
|
||||
args = to_app(c)->get_args();
|
||||
sz = to_app(c)->get_num_args();
|
||||
}
|
||||
else {
|
||||
args = &c;
|
||||
sz = 1;
|
||||
}
|
||||
ref_buffer<subpaving::ineq, subpaving::context> ineq_buffer(*m_ctx);
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
ineq_buffer.push_back(mk_ineq(args[i]));
|
||||
}
|
||||
m_ctx->add_clause(sz, ineq_buffer.c_ptr());
|
||||
}
|
||||
|
||||
void internalize(goal const & g) {
|
||||
try {
|
||||
for (unsigned i = 0; i < g.size(); i++) {
|
||||
process_clause(g.form(i));
|
||||
}
|
||||
}
|
||||
catch (subpaving::exception) {
|
||||
throw tactic_exception("failed to internalize goal into subpaving module");
|
||||
}
|
||||
}
|
||||
|
||||
void process(goal const & g) {
|
||||
internalize(g);
|
||||
m_proc = alloc(display_var_proc, m_e2v);
|
||||
m_ctx->set_display_proc(m_proc.get());
|
||||
try {
|
||||
(*m_ctx)();
|
||||
}
|
||||
catch (subpaving::exception) {
|
||||
throw tactic_exception("failed building subpaving tree...");
|
||||
}
|
||||
if (m_display) {
|
||||
m_ctx->display_constraints(std::cout);
|
||||
std::cout << "bounds at leaves: \n";
|
||||
m_ctx->display_bounds(std::cout);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
statistics m_stats;
|
||||
public:
|
||||
|
||||
subpaving_tactic(ast_manager & m, params_ref const & p):
|
||||
m_imp(alloc(imp, m, p)),
|
||||
m_params(p) {
|
||||
}
|
||||
|
||||
virtual ~subpaving_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(subpaving_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_imp->updt_params(p);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
m_imp->collect_param_descrs(r);
|
||||
}
|
||||
|
||||
virtual void collect_statistics(statistics & st) const {
|
||||
st.copy(m_stats);
|
||||
}
|
||||
|
||||
virtual void reset_statistics() {
|
||||
m_stats.reset();
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
m_imp->process(*in);
|
||||
m_imp->collect_statistics(m_stats);
|
||||
result.reset();
|
||||
result.push_back(in.get());
|
||||
mc = 0;
|
||||
pc = 0;
|
||||
core = 0;
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m();
|
||||
imp * d = m_imp;
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
d = m_imp;
|
||||
}
|
||||
dealloc(d);
|
||||
d = alloc(imp, m, m_params);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = d;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
tactic * mk_subpaving_tactic_core(ast_manager & m, params_ref const & p) {
|
||||
return alloc(subpaving_tactic, m, p);
|
||||
}
|
||||
|
||||
tactic * mk_subpaving_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref simp_p = p;
|
||||
simp_p.set_bool(":arith-lhs", true);
|
||||
simp_p.set_bool(":expand-power", true);
|
||||
simp_p.set_uint(":max-power", UINT_MAX);
|
||||
simp_p.set_bool(":som", true);
|
||||
simp_p.set_bool(":eq2ineq", true);
|
||||
simp_p.set_bool(":elim-and", true);
|
||||
simp_p.set_bool(":blast-distinct", true);
|
||||
|
||||
params_ref simp2_p = p;
|
||||
simp2_p.set_bool(":mul-to-power", true);
|
||||
|
||||
return and_then(using_params(mk_simplify_tactic(m, p),
|
||||
simp_p),
|
||||
using_params(mk_simplify_tactic(m, p),
|
||||
simp2_p),
|
||||
mk_subpaving_tactic_core(m, p));
|
||||
}
|
||||
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
subpaving_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
"Fake" tactic used to test subpaving module.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2012-08-07.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef __SUBPAVING_TACTIC_H_
|
||||
#define __SUBPAVING_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_subpaving_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue