3
0
Fork 0
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:
Leonardo de Moura 2012-10-21 20:04:34 -07:00
parent f6c89ba1d3
commit 6fd63cd05a
69 changed files with 9 additions and 1 deletions

View file

@ -0,0 +1,361 @@
/*++
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));
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,56 @@
/*++
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

84
src/ast/expr2dot.cpp Normal file
View file

@ -0,0 +1,84 @@
/*++
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";
}

27
src/ast/expr2dot.h Normal file
View file

@ -0,0 +1,27 @@
/*++
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_ */

481
src/ast/expr2polynomial.cpp Normal file
View file

@ -0,0 +1,481 @@
/*++
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;
}

93
src/ast/expr2polynomial.h Normal file
View file

@ -0,0 +1,93 @@
/*++
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

View file

@ -0,0 +1,366 @@
/*++
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;
}
}

View file

@ -0,0 +1,33 @@
/*++
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

View file

@ -0,0 +1,337 @@
/*++
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));
}

View file

@ -0,0 +1,32 @@
/*++
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

27
src/dead/contains_var.h Normal file
View file

@ -0,0 +1,27 @@
/*++
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_ */

424
src/dead/lru_cache.cpp Normal file
View file

@ -0,0 +1,424 @@
/*++
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;
}

80
src/dead/lru_cache.h Normal file
View file

@ -0,0 +1,80 @@
/*++
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

2112
src/fpa/fpa2bv_converter.cpp Normal file

File diff suppressed because it is too large Load diff

200
src/fpa/fpa2bv_converter.h Normal file
View file

@ -0,0 +1,200 @@
/*++
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

310
src/fpa/fpa2bv_tactic.cpp Normal file
View file

@ -0,0 +1,310 @@
/*++
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));
}

28
src/fpa/fpa2bv_tactic.h Normal file
View file

@ -0,0 +1,28 @@
/*++
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

38
src/fpa/qffpa_tactic.cpp Normal file
View file

@ -0,0 +1,38 @@
/*++
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());
}

29
src/fpa/qffpa_tactic.h Normal file
View file

@ -0,0 +1,29 @@
/*++
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

View file

@ -0,0 +1,77 @@
#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;
}

52
src/fuzzing/expr_delta.h Normal file
View file

@ -0,0 +1,52 @@
/*++
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

268
src/fuzzing/expr_rand.cpp Normal file
View file

@ -0,0 +1,268 @@
#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, &param));
}
for (unsigned i = 0; i < num_sizes; ++i) {
parameter param(sizes[i]);
sort* s = m_manager.mk_sort(bvfid, BV_SORT, 1, &param);
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));
}
}

61
src/fuzzing/expr_rand.h Normal file
View file

@ -0,0 +1,61 @@
/*++
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

View file

@ -0,0 +1,309 @@
/*++
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);
}

View file

@ -0,0 +1,75 @@
/*++
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

View file

@ -0,0 +1,258 @@
/*++
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));
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,63 @@
/*++
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)));
}

View file

@ -0,0 +1,30 @@
/*++
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

132
src/sat/dimacs.cpp Normal file
View file

@ -0,0 +1,132 @@
/*++
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
src/sat/dimacs.h Normal file
View file

@ -0,0 +1,27 @@
/*++
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_ */

View file

@ -0,0 +1,61 @@
/*++
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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
/*++
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

View file

@ -0,0 +1,619 @@
/*++
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

View file

@ -0,0 +1,40 @@
/*++
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

View file

@ -0,0 +1,317 @@
/*++
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);
}

View file

@ -0,0 +1,30 @@
/*++
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

View file

@ -0,0 +1,47 @@
/*++
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)));
}

View file

@ -0,0 +1,24 @@
/*++
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

View file

@ -0,0 +1,65 @@
/*++
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;
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,52 @@
/*++
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;
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,118 @@
/*++
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;
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,111 @@
/*++
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;
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,218 @@
/*++
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;
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,71 @@
/*++
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);
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,93 @@
/*++
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()));
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,53 @@
/*++
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)));
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,40 @@
/*++
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));
}

View file

@ -0,0 +1,29 @@
/*++
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

View file

@ -0,0 +1,53 @@
/*++
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;
}

View file

@ -0,0 +1,28 @@
/*++
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

View file

@ -0,0 +1,106 @@
/*++
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;
}

View file

@ -0,0 +1,33 @@
/*++
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

View file

@ -0,0 +1,395 @@
/*++
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);
}

View file

@ -0,0 +1,58 @@
/*++
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

View file

@ -0,0 +1,308 @@
/*++
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));
}

View file

@ -0,0 +1,28 @@
/*++
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