mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 09:35:32 +00:00
first pass on normalization
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
6300d82224
commit
da348fe1c0
10 changed files with 539 additions and 72 deletions
177
src/tactic/arith/elim01_tactic.cpp
Normal file
177
src/tactic/arith/elim01_tactic.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
elim01_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Replace 0-1 integer variables by Booleans.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-12-7
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"cooperate.h"
|
||||
#include"bound_manager.h"
|
||||
#include"ast_pp.h"
|
||||
#include"expr_safe_replace.h" // NB: should use proof-producing expr_substitute in polished version.
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"elim01_tactic.h"
|
||||
|
||||
class bool2int_model_converter : public model_converter {
|
||||
ast_manager& m;
|
||||
arith_util a;
|
||||
func_decl_ref_vector m_refs;
|
||||
obj_map<func_decl, func_decl*> m_bool2int;
|
||||
public:
|
||||
|
||||
bool2int_model_converter(ast_manager& m):
|
||||
m(m),
|
||||
a(m),
|
||||
m_refs(m)
|
||||
{}
|
||||
|
||||
virtual void operator()(model_ref & old_model, unsigned goal_idx) {
|
||||
SASSERT(goal_idx == 0);
|
||||
model * new_model = alloc(model, m);
|
||||
unsigned num = old_model->get_num_constants();
|
||||
for (unsigned i = 0; i < num; ++i) {
|
||||
func_decl* f = old_model->get_constant(i);
|
||||
expr* fi = old_model->get_const_interp(f);
|
||||
func_decl* f_old;
|
||||
if (m_bool2int.find(f, f_old)) {
|
||||
if (!fi) {
|
||||
// no-op
|
||||
}
|
||||
else if (m.is_false(fi)) {
|
||||
fi = a.mk_numeral(rational(0), true);
|
||||
}
|
||||
else if (m.is_true(fi)) {
|
||||
fi = a.mk_numeral(rational(1), true);
|
||||
}
|
||||
else {
|
||||
fi = 0;
|
||||
}
|
||||
new_model->register_decl(f_old, fi);
|
||||
}
|
||||
else {
|
||||
new_model->register_decl(f, fi);
|
||||
}
|
||||
num = old_model->get_num_functions();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
func_decl * f = old_model->get_function(i);
|
||||
func_interp * fi = old_model->get_func_interp(f);
|
||||
new_model->register_decl(f, fi->copy());
|
||||
}
|
||||
new_model->copy_usort_interps(*old_model);
|
||||
old_model = new_model;
|
||||
}
|
||||
}
|
||||
|
||||
void insert(func_decl* x_new, func_decl* x_old) {
|
||||
m_refs.push_back(x_new);
|
||||
m_refs.push_back(x_old);
|
||||
m_bool2int.insert(x_new, x_old);
|
||||
}
|
||||
|
||||
|
||||
virtual model_converter * translate(ast_translation & translator) {
|
||||
bool2int_model_converter* mc = alloc(bool2int_model_converter, translator.to());
|
||||
obj_map<func_decl, func_decl*>::iterator it = m_bool2int.begin(), end = m_bool2int.end();
|
||||
for (; it != end; ++it) {
|
||||
mc->insert(translator(it->m_key), translator(it->m_value));
|
||||
}
|
||||
return mc;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class elim01_tactic : public tactic {
|
||||
public:
|
||||
typedef obj_hashtable<expr> expr_set;
|
||||
ast_manager & m;
|
||||
arith_util a;
|
||||
params_ref m_params;
|
||||
|
||||
elim01_tactic(ast_manager & _m, params_ref const & p):
|
||||
m(_m),
|
||||
a(m) {
|
||||
}
|
||||
|
||||
virtual ~elim01_tactic() {
|
||||
}
|
||||
|
||||
void set_cancel(bool f) {
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
}
|
||||
|
||||
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());
|
||||
mc = 0; pc = 0; core = 0;
|
||||
|
||||
tactic_report report("elim01", *g);
|
||||
|
||||
expr_safe_replace sub(m);
|
||||
bool2int_model_converter* b2i = alloc(bool2int_model_converter, m);
|
||||
mc = b2i;
|
||||
bound_manager bounds(m);
|
||||
bounds(*g);
|
||||
|
||||
bound_manager::iterator bit = bounds.begin(), bend = bounds.end();
|
||||
for (; bit != bend; ++bit) {
|
||||
if (!is_app(*bit)) continue;
|
||||
app* x = to_app(*bit);
|
||||
bool s1, s2;
|
||||
rational lo, hi;
|
||||
if (a.is_int(x) &&
|
||||
bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() &&
|
||||
bounds.has_upper(x, hi, s2) && !s2 && hi.is_one()) {
|
||||
app* x_new = m.mk_fresh_const(x->get_decl()->get_name().str().c_str(), m.mk_bool_sort());
|
||||
sub.insert(x, m.mk_ite(x_new, a.mk_numeral(rational(1), true),
|
||||
a.mk_numeral(rational(0), true)));
|
||||
b2i->insert(x_new->get_decl(), x->get_decl());
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref new_curr(m);
|
||||
proof_ref new_pr(m);
|
||||
|
||||
for (unsigned i = 0; i < g->size(); i++) {
|
||||
expr * curr = g->form(i);
|
||||
sub(curr, new_curr);
|
||||
g->update(i, new_curr, new_pr, g->dep(i));
|
||||
}
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
TRACE("pb", g->display(tout););
|
||||
SASSERT(g->is_well_sorted());
|
||||
|
||||
// TBD: support proof conversion (or not..)
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(elim01_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {}
|
||||
|
||||
virtual void cleanup() {}
|
||||
};
|
||||
|
||||
tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p) {
|
||||
return clean(alloc(elim01_tactic, m, p));
|
||||
}
|
||||
|
33
src/tactic/arith/elim01_tactic.h
Normal file
33
src/tactic/arith/elim01_tactic.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
elim01_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Replace 0-1 integer variables by Booleans.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2013-12-7
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _ELIM01_TACTIC_H_
|
||||
#define _ELIM01_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p = params_ref());
|
||||
|
||||
/*
|
||||
ADD_TACTIC("elim01", "eliminate 0-1 integer variables, replace them by Booleans.", "mk_elim01_tactic(m, p)")
|
||||
*/
|
||||
|
||||
|
||||
#endif
|
|
@ -143,24 +143,44 @@ public:
|
|||
if ((a.is_le(fml, x, y) || a.is_ge(fml, y, x)) &&
|
||||
get_pb_sum(x, rational::one(), args, coeffs, coeff) &&
|
||||
get_pb_sum(y, -rational::one(), args, coeffs, coeff)) {
|
||||
result = m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff);
|
||||
result = mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff);
|
||||
return true;
|
||||
}
|
||||
else if ((a.is_lt(fml, y, x) || a.is_gt(fml, x, y)) &&
|
||||
get_pb_sum(x, rational::one(), args, coeffs, coeff) &&
|
||||
get_pb_sum(y, -rational::one(), args, coeffs, coeff)) {
|
||||
result = m.mk_not(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff));
|
||||
result = m.mk_not(mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff));
|
||||
return true;
|
||||
}
|
||||
else if (m.is_eq(fml, x, y) &&
|
||||
get_pb_sum(x, rational::one(), args, coeffs, coeff) &&
|
||||
get_pb_sum(y, -rational::one(), args, coeffs, coeff)) {
|
||||
result = m.mk_and(m_pb.mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff),
|
||||
m_pb.mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff));
|
||||
result = m.mk_and(mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff),
|
||||
mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
expr* mk_le(unsigned sz, rational const* weights, expr* const* args, rational const& w) {
|
||||
if (sz == 1 && weights[0].is_one() && w >= rational::one()) {
|
||||
return m.mk_true();
|
||||
}
|
||||
if (sz == 1 && weights[0].is_one() && w.is_zero()) {
|
||||
return m.mk_not(args[0]);
|
||||
}
|
||||
return m_pb.mk_le(sz, weights, args, w);
|
||||
}
|
||||
|
||||
expr* mk_ge(unsigned sz, rational const* weights, expr* const* args, rational const& w) {
|
||||
if (sz == 1 && weights[0].is_one() && w.is_one()) {
|
||||
return args[0];
|
||||
}
|
||||
if (sz == 1 && weights[0].is_one() && w.is_zero()) {
|
||||
return m.mk_not(args[0]);
|
||||
}
|
||||
return m_pb.mk_ge(sz, weights, args, w);
|
||||
}
|
||||
|
||||
bool get_pb_sum(expr* x, rational const& mul, expr_ref_vector& args, vector<rational>& coeffs, rational& coeff) {
|
||||
expr *y, *z, *u;
|
||||
|
@ -179,31 +199,53 @@ public:
|
|||
else if (a.is_uminus(x, y)) {
|
||||
ok = get_pb_sum(y, -mul, args, coeffs, coeff);
|
||||
}
|
||||
else if (a.is_mul(x, y, z) && a.is_numeral(y, r)) {
|
||||
else if (a.is_mul(x, y, z) && is_numeral(y, r)) {
|
||||
ok = get_pb_sum(z, r*mul, args, coeffs, coeff);
|
||||
}
|
||||
else if (a.is_mul(x, z, y) && a.is_numeral(y, r)) {
|
||||
else if (a.is_mul(x, z, y) && is_numeral(y, r)) {
|
||||
ok = get_pb_sum(z, r*mul, args, coeffs, coeff);
|
||||
}
|
||||
else if (m.is_ite(x, y, z, u) && a.is_numeral(z, r) && a.is_numeral(u, q)) {
|
||||
args.push_back(y);
|
||||
coeffs.push_back(r*mul);
|
||||
args.push_back(m.mk_not(y));
|
||||
coeffs.push_back(q*mul);
|
||||
else if (m.is_ite(x, y, z, u) && is_numeral(z, r) && is_numeral(u, q)) {
|
||||
insert_arg(r*mul, y, args, coeffs, coeff);
|
||||
// q*(1-y) = -q*y + q
|
||||
coeff += q*mul;
|
||||
insert_arg(-q*mul, y, args, coeffs, coeff);
|
||||
}
|
||||
else if (is_01var(x)) {
|
||||
args.push_back(mk_01(x));
|
||||
coeffs.push_back(mul);
|
||||
insert_arg(mul, mk_01(x), args, coeffs, coeff);
|
||||
}
|
||||
else if (a.is_numeral(x, r)) {
|
||||
else if (is_numeral(x, r)) {
|
||||
coeff += mul*r;
|
||||
}
|
||||
else {
|
||||
TRACE("pb", tout << "Can't handle " << mk_pp(x, m) << "\n";);
|
||||
ok = false;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool is_numeral(expr* e, rational& r) {
|
||||
if (a.is_uminus(e, e) && is_numeral(e, r)) {
|
||||
r.neg();
|
||||
return true;
|
||||
}
|
||||
return a.is_numeral(e, r);
|
||||
}
|
||||
|
||||
void insert_arg(rational const& p, expr* x,
|
||||
expr_ref_vector& args, vector<rational>& coeffs, rational& coeff) {
|
||||
if (p.is_neg()) {
|
||||
// p*x = -p*(1-x) + p
|
||||
args.push_back(m.mk_not(x));
|
||||
coeffs.push_back(-p);
|
||||
coeff += p;
|
||||
}
|
||||
else if (p.is_pos()) {
|
||||
args.push_back(x);
|
||||
coeffs.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(lia2card_tactic, m, m_params);
|
||||
}
|
||||
|
@ -224,6 +266,9 @@ tactic * mk_lia2card_tactic(ast_manager & m, params_ref const & p) {
|
|||
return clean(alloc(lia2card_tactic, m, p));
|
||||
}
|
||||
|
||||
void convert_objectives() {
|
||||
|
||||
bool get_pb_sum(expr* term, expr_ref_vector& args, vector<rational>& coeffs, rational& coeff) {
|
||||
params_ref p;
|
||||
ast_manager& m = args.get_manager();
|
||||
lia2card_tactic tac(m, p);
|
||||
return tac.get_pb_sum(term, rational::one(), args, coeffs, coeff);
|
||||
}
|
||||
|
|
|
@ -30,4 +30,6 @@ tactic * mk_lia2card_tactic(ast_manager & m, params_ref const & p = params_ref()
|
|||
ADD_TACTIC("lia2card", "introduce cardinality constraints from 0-1 integer.", "mk_lia2card_tactic(m, p)")
|
||||
*/
|
||||
|
||||
bool get_pb_sum(expr* term, expr_ref_vector& args, vector<rational>& coeffs, rational& coeff);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue