mirror of
https://github.com/Z3Prover/z3
synced 2025-06-06 06:03:23 +00:00
working on incremtal PB theory
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
1f7c994e43
commit
236b2d2ff3
12 changed files with 1419 additions and 912 deletions
|
@ -23,7 +23,8 @@ pb_decl_plugin::pb_decl_plugin():
|
||||||
m_at_most_sym("at-most"),
|
m_at_most_sym("at-most"),
|
||||||
m_at_least_sym("at-least"),
|
m_at_least_sym("at-least"),
|
||||||
m_pble_sym("pble"),
|
m_pble_sym("pble"),
|
||||||
m_pbge_sym("pbge")
|
m_pbge_sym("pbge"),
|
||||||
|
m_pbeq_sym("pbeq")
|
||||||
{}
|
{}
|
||||||
|
|
||||||
func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||||
|
@ -41,6 +42,7 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
|
||||||
case OP_AT_MOST_K: sym = m_at_most_sym; break;
|
case OP_AT_MOST_K: sym = m_at_most_sym; break;
|
||||||
case OP_PB_LE: sym = m_pble_sym; break;
|
case OP_PB_LE: sym = m_pble_sym; break;
|
||||||
case OP_PB_GE: sym = m_pbge_sym; break;
|
case OP_PB_GE: sym = m_pbge_sym; break;
|
||||||
|
case OP_PB_EQ: sym = m_pbeq_sym; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
switch(k) {
|
switch(k) {
|
||||||
|
@ -53,7 +55,8 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
|
||||||
return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info);
|
return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info);
|
||||||
}
|
}
|
||||||
case OP_PB_GE:
|
case OP_PB_GE:
|
||||||
case OP_PB_LE: {
|
case OP_PB_LE:
|
||||||
|
case OP_PB_EQ: {
|
||||||
if (num_parameters != 1 + arity) {
|
if (num_parameters != 1 + arity) {
|
||||||
m.raise_exception("function expects arity+1 rational parameters");
|
m.raise_exception("function expects arity+1 rational parameters");
|
||||||
}
|
}
|
||||||
|
@ -74,7 +77,7 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m.raise_exception("function 'pble' expects arity+1 integer parameters");
|
m.raise_exception("functions 'pble/pbge/pbeq' expect arity+1 integer parameters");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func_decl_info info(m_family_id, k, num_parameters, params.c_ptr());
|
func_decl_info info(m_family_id, k, num_parameters, params.c_ptr());
|
||||||
|
@ -89,8 +92,10 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
|
||||||
void pb_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
|
void pb_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
|
||||||
if (logic == symbol::null) {
|
if (logic == symbol::null) {
|
||||||
op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K));
|
op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K));
|
||||||
|
op_names.push_back(builtin_name(m_at_least_sym.bare_str(), OP_AT_LEAST_K));
|
||||||
op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE));
|
op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE));
|
||||||
op_names.push_back(builtin_name(m_pbge_sym.bare_str(), OP_PB_GE));
|
op_names.push_back(builtin_name(m_pbge_sym.bare_str(), OP_PB_GE));
|
||||||
|
op_names.push_back(builtin_name(m_pbeq_sym.bare_str(), OP_PB_EQ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +117,15 @@ app * pb_util::mk_ge(unsigned num_args, rational const * coeffs, expr * const *
|
||||||
return m.mk_app(m_fid, OP_PB_GE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
|
return m.mk_app(m_fid, OP_PB_GE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
|
||||||
|
vector<parameter> params;
|
||||||
|
params.push_back(parameter(k));
|
||||||
|
for (unsigned i = 0; i < num_args; ++i) {
|
||||||
|
params.push_back(parameter(coeffs[i]));
|
||||||
|
}
|
||||||
|
return m.mk_app(m_fid, OP_PB_EQ, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app * pb_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) {
|
app * pb_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) {
|
||||||
|
@ -123,7 +137,7 @@ bool pb_util::is_at_most_k(func_decl *a) const {
|
||||||
return is_decl_of(a, m_fid, OP_AT_MOST_K);
|
return is_decl_of(a, m_fid, OP_AT_MOST_K);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pb_util::is_at_most_k(app *a, rational& k) const {
|
bool pb_util::is_at_most_k(expr *a, rational& k) const {
|
||||||
if (is_at_most_k(a)) {
|
if (is_at_most_k(a)) {
|
||||||
k = get_k(a);
|
k = get_k(a);
|
||||||
return true;
|
return true;
|
||||||
|
@ -133,7 +147,6 @@ bool pb_util::is_at_most_k(app *a, rational& k) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
app * pb_util::mk_at_least_k(unsigned num_args, expr * const * args, unsigned k) {
|
app * pb_util::mk_at_least_k(unsigned num_args, expr * const * args, unsigned k) {
|
||||||
parameter param(k);
|
parameter param(k);
|
||||||
return m.mk_app(m_fid, OP_AT_LEAST_K, 1, ¶m, num_args, args, m.mk_bool_sort());
|
return m.mk_app(m_fid, OP_AT_LEAST_K, 1, ¶m, num_args, args, m.mk_bool_sort());
|
||||||
|
@ -143,7 +156,7 @@ bool pb_util::is_at_least_k(func_decl *a) const {
|
||||||
return is_decl_of(a, m_fid, OP_AT_LEAST_K);
|
return is_decl_of(a, m_fid, OP_AT_LEAST_K);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pb_util::is_at_least_k(app *a, rational& k) const {
|
bool pb_util::is_at_least_k(expr *a, rational& k) const {
|
||||||
if (is_at_least_k(a)) {
|
if (is_at_least_k(a)) {
|
||||||
k = get_k(a);
|
k = get_k(a);
|
||||||
return true;
|
return true;
|
||||||
|
@ -159,7 +172,7 @@ rational pb_util::get_k(func_decl *a) const {
|
||||||
return to_rational(p);
|
return to_rational(p);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SASSERT(is_le(a) || is_ge(a));
|
SASSERT(is_le(a) || is_ge(a) || is_eq(a));
|
||||||
return to_rational(p);
|
return to_rational(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,7 +182,7 @@ bool pb_util::is_le(func_decl *a) const {
|
||||||
return is_decl_of(a, m_fid, OP_PB_LE);
|
return is_decl_of(a, m_fid, OP_PB_LE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pb_util::is_le(app* a, rational& k) const {
|
bool pb_util::is_le(expr* a, rational& k) const {
|
||||||
if (is_le(a)) {
|
if (is_le(a)) {
|
||||||
k = get_k(a);
|
k = get_k(a);
|
||||||
return true;
|
return true;
|
||||||
|
@ -183,7 +196,7 @@ bool pb_util::is_ge(func_decl *a) const {
|
||||||
return is_decl_of(a, m_fid, OP_PB_GE);
|
return is_decl_of(a, m_fid, OP_PB_GE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pb_util::is_ge(app* a, rational& k) const {
|
bool pb_util::is_ge(expr* a, rational& k) const {
|
||||||
if (is_ge(a)) {
|
if (is_ge(a)) {
|
||||||
k = get_k(a);
|
k = get_k(a);
|
||||||
return true;
|
return true;
|
||||||
|
@ -193,11 +206,26 @@ bool pb_util::is_ge(app* a, rational& k) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool pb_util::is_eq(func_decl *a) const {
|
||||||
|
return is_decl_of(a, m_fid, OP_PB_EQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pb_util::is_eq(expr* a, rational& k) const {
|
||||||
|
if (is_eq(a)) {
|
||||||
|
k = get_k(a);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rational pb_util::get_coeff(func_decl* a, unsigned index) const {
|
rational pb_util::get_coeff(func_decl* a, unsigned index) const {
|
||||||
if (is_at_most_k(a) || is_at_least_k(a)) {
|
if (is_at_most_k(a) || is_at_least_k(a)) {
|
||||||
return rational::one();
|
return rational::one();
|
||||||
}
|
}
|
||||||
SASSERT(is_le(a) || is_ge(a));
|
SASSERT(is_le(a) || is_ge(a) || is_eq(a));
|
||||||
SASSERT(1 + index < a->get_num_parameters());
|
SASSERT(1 + index < a->get_num_parameters());
|
||||||
return to_rational(a->get_parameter(index + 1));
|
return to_rational(a->get_parameter(index + 1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ enum pb_op_kind {
|
||||||
OP_AT_LEAST_K, // at least K Booleans are true.
|
OP_AT_LEAST_K, // at least K Booleans are true.
|
||||||
OP_PB_LE, // pseudo-Boolean <= (generalizes at_most_k)
|
OP_PB_LE, // pseudo-Boolean <= (generalizes at_most_k)
|
||||||
OP_PB_GE, // pseudo-Boolean >=
|
OP_PB_GE, // pseudo-Boolean >=
|
||||||
|
OP_PB_EQ, // equality
|
||||||
LAST_PB_OP
|
LAST_PB_OP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,10 +44,12 @@ class pb_decl_plugin : public decl_plugin {
|
||||||
symbol m_at_least_sym;
|
symbol m_at_least_sym;
|
||||||
symbol m_pble_sym;
|
symbol m_pble_sym;
|
||||||
symbol m_pbge_sym;
|
symbol m_pbge_sym;
|
||||||
|
symbol m_pbeq_sym;
|
||||||
func_decl * mk_at_most(unsigned arity, unsigned k);
|
func_decl * mk_at_most(unsigned arity, unsigned k);
|
||||||
func_decl * mk_at_least(unsigned arity, unsigned k);
|
func_decl * mk_at_least(unsigned arity, unsigned k);
|
||||||
func_decl * mk_le(unsigned arity, rational const* coeffs, int k);
|
func_decl * mk_le(unsigned arity, rational const* coeffs, int k);
|
||||||
func_decl * mk_ge(unsigned arity, rational const* coeffs, int k);
|
func_decl * mk_ge(unsigned arity, rational const* coeffs, int k);
|
||||||
|
func_decl * mk_eq(unsigned arity, rational const* coeffs, int k);
|
||||||
public:
|
public:
|
||||||
pb_decl_plugin();
|
pb_decl_plugin();
|
||||||
virtual ~pb_decl_plugin() {}
|
virtual ~pb_decl_plugin() {}
|
||||||
|
@ -82,22 +85,27 @@ public:
|
||||||
app * mk_at_least_k(unsigned num_args, expr * const * args, unsigned k);
|
app * mk_at_least_k(unsigned num_args, expr * const * args, unsigned k);
|
||||||
app * mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k);
|
app * mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k);
|
||||||
app * mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k);
|
app * mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k);
|
||||||
|
app * mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k);
|
||||||
bool is_at_most_k(func_decl *a) const;
|
bool is_at_most_k(func_decl *a) const;
|
||||||
bool is_at_most_k(expr *a) const { return is_app(a) && is_at_most_k(to_app(a)->get_decl()); }
|
bool is_at_most_k(expr *a) const { return is_app(a) && is_at_most_k(to_app(a)->get_decl()); }
|
||||||
bool is_at_most_k(app *a, rational& k) const;
|
bool is_at_most_k(expr *a, rational& k) const;
|
||||||
bool is_at_least_k(func_decl *a) const;
|
bool is_at_least_k(func_decl *a) const;
|
||||||
bool is_at_least_k(expr *a) const { return is_app(a) && is_at_least_k(to_app(a)->get_decl()); }
|
bool is_at_least_k(expr *a) const { return is_app(a) && is_at_least_k(to_app(a)->get_decl()); }
|
||||||
bool is_at_least_k(app *a, rational& k) const;
|
bool is_at_least_k(expr *a, rational& k) const;
|
||||||
rational get_k(func_decl *a) const;
|
rational get_k(func_decl *a) const;
|
||||||
rational get_k(expr *a) const { return get_k(to_app(a)->get_decl()); }
|
rational get_k(expr *a) const { return get_k(to_app(a)->get_decl()); }
|
||||||
bool is_le(func_decl *a) const;
|
bool is_le(func_decl *a) const;
|
||||||
bool is_le(expr *a) const { return is_app(a) && is_le(to_app(a)->get_decl()); }
|
bool is_le(expr *a) const { return is_app(a) && is_le(to_app(a)->get_decl()); }
|
||||||
bool is_le(app* a, rational& k) const;
|
bool is_le(expr* a, rational& k) const;
|
||||||
bool is_ge(func_decl* a) const;
|
bool is_ge(func_decl* a) const;
|
||||||
bool is_ge(expr* a) const { return is_app(a) && is_ge(to_app(a)->get_decl()); }
|
bool is_ge(expr* a) const { return is_app(a) && is_ge(to_app(a)->get_decl()); }
|
||||||
bool is_ge(app* a, rational& k) const;
|
bool is_ge(expr* a, rational& k) const;
|
||||||
rational get_coeff(expr* a, unsigned index) const { return get_coeff(to_app(a)->get_decl(), index); }
|
rational get_coeff(expr* a, unsigned index) const { return get_coeff(to_app(a)->get_decl(), index); }
|
||||||
rational get_coeff(func_decl* a, unsigned index) const;
|
rational get_coeff(func_decl* a, unsigned index) const;
|
||||||
|
|
||||||
|
bool is_eq(func_decl* f) const;
|
||||||
|
bool is_eq(expr* e) const { return is_app(e) && is_eq(to_app(e)->get_decl()); }
|
||||||
|
bool is_eq(expr* e, rational& k) const;
|
||||||
private:
|
private:
|
||||||
rational to_rational(parameter const& p) const;
|
rational to_rational(parameter const& p) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -102,19 +102,21 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
||||||
break;
|
break;
|
||||||
case OP_AT_LEAST_K:
|
case OP_AT_LEAST_K:
|
||||||
case OP_PB_GE:
|
case OP_PB_GE:
|
||||||
|
case OP_PB_EQ:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return BR_FAILED;
|
return BR_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_eq = f->get_decl_kind() == OP_PB_EQ;
|
||||||
|
|
||||||
pb_ast_rewriter_util pbu(m);
|
pb_ast_rewriter_util pbu(m);
|
||||||
pb_rewriter_util<pb_ast_rewriter_util> util(pbu);
|
pb_rewriter_util<pb_ast_rewriter_util> util(pbu);
|
||||||
|
|
||||||
util.unique(vec, k);
|
util.unique(vec, k, is_eq);
|
||||||
lbool is_sat = util.normalize(vec, k);
|
lbool is_sat = util.normalize(vec, k, is_eq);
|
||||||
util.prune(vec, k);
|
util.prune(vec, k, is_eq);
|
||||||
switch (is_sat) {
|
switch (is_sat) {
|
||||||
case l_true:
|
case l_true:
|
||||||
result = m.mk_true();
|
result = m.mk_true();
|
||||||
|
@ -129,7 +131,12 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
||||||
m_args.push_back(vec[i].first);
|
m_args.push_back(vec[i].first);
|
||||||
m_coeffs.push_back(vec[i].second);
|
m_coeffs.push_back(vec[i].second);
|
||||||
}
|
}
|
||||||
result = m_util.mk_ge(vec.size(), m_coeffs.c_ptr(), m_args.c_ptr(), k);
|
if (is_eq) {
|
||||||
|
result = m_util.mk_eq(vec.size(), m_coeffs.c_ptr(), m_args.c_ptr(), k);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = m_util.mk_ge(vec.size(), m_coeffs.c_ptr(), m_args.c_ptr(), k);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TRACE("pb",
|
TRACE("pb",
|
||||||
|
|
|
@ -28,12 +28,12 @@ Notes:
|
||||||
template<typename PBU>
|
template<typename PBU>
|
||||||
class pb_rewriter_util {
|
class pb_rewriter_util {
|
||||||
PBU& m_util;
|
PBU& m_util;
|
||||||
void display(std::ostream& out, typename PBU::args_t& args, typename PBU::numeral& k);
|
void display(std::ostream& out, typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq);
|
||||||
public:
|
public:
|
||||||
pb_rewriter_util(PBU& u) : m_util(u) {}
|
pb_rewriter_util(PBU& u) : m_util(u) {}
|
||||||
void unique(typename PBU::args_t& args, typename PBU::numeral& k);
|
void unique(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq);
|
||||||
lbool normalize(typename PBU::args_t& args, typename PBU::numeral& k);
|
lbool normalize(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq);
|
||||||
void prune(typename PBU::args_t& args, typename PBU::numeral& k);
|
void prune(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,20 +23,20 @@ Notes:
|
||||||
|
|
||||||
|
|
||||||
template<typename PBU>
|
template<typename PBU>
|
||||||
void pb_rewriter_util<PBU>::display(std::ostream& out, typename PBU::args_t& args, typename PBU::numeral& k) {
|
void pb_rewriter_util<PBU>::display(std::ostream& out, typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq) {
|
||||||
for (unsigned i = 0; i < args.size(); ++i) {
|
for (unsigned i = 0; i < args.size(); ++i) {
|
||||||
out << args[i].second << " * ";
|
out << args[i].second << " * ";
|
||||||
m_util.display(out, args[i].first);
|
m_util.display(out, args[i].first);
|
||||||
out << " ";
|
out << " ";
|
||||||
if (i+1 < args.size()) out << "+ ";
|
if (i+1 < args.size()) out << "+ ";
|
||||||
}
|
}
|
||||||
out << " >= " << k << "\n";
|
out << (is_eq?" = ":" >= ") << k << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PBU>
|
template<typename PBU>
|
||||||
void pb_rewriter_util<PBU>::unique(typename PBU::args_t& args, typename PBU::numeral& k) {
|
void pb_rewriter_util<PBU>::unique(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq) {
|
||||||
|
|
||||||
TRACE("pb_verbose", display(tout << "pre-unique:", args, k););
|
TRACE("pb_verbose", display(tout << "pre-unique:", args, k, is_eq););
|
||||||
for (unsigned i = 0; i < args.size(); ++i) {
|
for (unsigned i = 0; i < args.size(); ++i) {
|
||||||
if (m_util.is_negated(args[i].first)) {
|
if (m_util.is_negated(args[i].first)) {
|
||||||
args[i].first = m_util.negate(args[i].first);
|
args[i].first = m_util.negate(args[i].first);
|
||||||
|
@ -85,19 +85,19 @@ void pb_rewriter_util<PBU>::unique(typename PBU::args_t& args, typename PBU::num
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args.resize(i);
|
args.resize(i);
|
||||||
TRACE("pb_verbose", display(tout << "post-unique:", args, k););
|
TRACE("pb_verbose", display(tout << "post-unique:", args, k, is_eq););
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PBU>
|
template<typename PBU>
|
||||||
lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU::numeral& k) {
|
lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq) {
|
||||||
TRACE("pb_verbose", display(tout << "pre-normalize:", args, k););
|
TRACE("pb_verbose", display(tout << "pre-normalize:", args, k, is_eq););
|
||||||
|
|
||||||
DEBUG_CODE(
|
DEBUG_CODE(
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (unsigned i = 0; !found && i < args.size(); ++i) {
|
for (unsigned i = 0; !found && i < args.size(); ++i) {
|
||||||
found = args[i].second.is_zero();
|
found = args[i].second.is_zero();
|
||||||
}
|
}
|
||||||
if (found) display(verbose_stream(), args, k);
|
if (found) display(verbose_stream(), args, k, is_eq);
|
||||||
SASSERT(!found););
|
SASSERT(!found););
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -121,11 +121,15 @@ lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU:
|
||||||
sum += args[i].second;
|
sum += args[i].second;
|
||||||
}
|
}
|
||||||
// detect tautologies:
|
// detect tautologies:
|
||||||
if (k <= PBU::numeral::zero()) {
|
if (!is_eq && k <= PBU::numeral::zero()) {
|
||||||
args.reset();
|
args.reset();
|
||||||
k = PBU::numeral::zero();
|
k = PBU::numeral::zero();
|
||||||
return l_true;
|
return l_true;
|
||||||
}
|
}
|
||||||
|
if (is_eq && k.is_zero() && args.empty()) {
|
||||||
|
return l_true;
|
||||||
|
}
|
||||||
|
|
||||||
// detect infeasible constraints:
|
// detect infeasible constraints:
|
||||||
if (sum < k) {
|
if (sum < k) {
|
||||||
args.reset();
|
args.reset();
|
||||||
|
@ -133,6 +137,14 @@ lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU:
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_eq && k == sum) {
|
||||||
|
for (unsigned i = 0; i < args.size(); ++i) {
|
||||||
|
args[i].second = PBU::numeral::one();
|
||||||
|
}
|
||||||
|
k = PBU::numeral::one();
|
||||||
|
return l_undef;
|
||||||
|
}
|
||||||
|
|
||||||
bool all_int = true;
|
bool all_int = true;
|
||||||
for (unsigned i = 0; all_int && i < args.size(); ++i) {
|
for (unsigned i = 0; all_int && i < args.size(); ++i) {
|
||||||
all_int = args[i].second.is_int();
|
all_int = args[i].second.is_int();
|
||||||
|
@ -151,6 +163,11 @@ lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_eq) {
|
||||||
|
TRACE("pb_verbose", display(tout << "post-normalize:", args, k, is_eq););
|
||||||
|
return l_undef;
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the largest coefficient is not larger than k:
|
// Ensure the largest coefficient is not larger than k:
|
||||||
sum = PBU::numeral::zero();
|
sum = PBU::numeral::zero();
|
||||||
for (unsigned i = 0; i < args.size(); ++i) {
|
for (unsigned i = 0; i < args.size(); ++i) {
|
||||||
|
@ -193,7 +210,7 @@ lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU:
|
||||||
}
|
}
|
||||||
else if (g > PBU::numeral::one()) {
|
else if (g > PBU::numeral::one()) {
|
||||||
IF_VERBOSE(3, verbose_stream() << "cut " << g << "\n";
|
IF_VERBOSE(3, verbose_stream() << "cut " << g << "\n";
|
||||||
display(verbose_stream(), args, k);
|
display(verbose_stream(), args, k, is_eq);
|
||||||
);
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -241,7 +258,7 @@ lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU:
|
||||||
PBU::numeral n1 = floor(n0);
|
PBU::numeral n1 = floor(n0);
|
||||||
PBU::numeral n2 = ceil(k/min) - PBU::numeral::one();
|
PBU::numeral n2 = ceil(k/min) - PBU::numeral::one();
|
||||||
if (n1 == n2 && !n0.is_int()) {
|
if (n1 == n2 && !n0.is_int()) {
|
||||||
IF_VERBOSE(3, display(verbose_stream() << "set cardinality\n", args, k););
|
IF_VERBOSE(3, display(verbose_stream() << "set cardinality\n", args, k, is_eq););
|
||||||
|
|
||||||
for (unsigned i = 0; i < args.size(); ++i) {
|
for (unsigned i = 0; i < args.size(); ++i) {
|
||||||
args[i].second = PBU::numeral::one();
|
args[i].second = PBU::numeral::one();
|
||||||
|
@ -249,13 +266,15 @@ lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU:
|
||||||
k = n1 + PBU::numeral::one();
|
k = n1 + PBU::numeral::one();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TRACE("pb_verbose", display(tout << "post-normalize:", args, k, is_eq););
|
||||||
return l_undef;
|
return l_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename PBU>
|
template<typename PBU>
|
||||||
void pb_rewriter_util<PBU>::prune(typename PBU::args_t& args, typename PBU::numeral& k) {
|
void pb_rewriter_util<PBU>::prune(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq) {
|
||||||
|
if (is_eq) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
PBU::numeral nlt(0);
|
PBU::numeral nlt(0);
|
||||||
unsigned occ = 0;
|
unsigned occ = 0;
|
||||||
for (unsigned i = 0; nlt < k && i < args.size(); ++i) {
|
for (unsigned i = 0; nlt < k && i < args.size(); ++i) {
|
||||||
|
@ -265,7 +284,6 @@ void pb_rewriter_util<PBU>::prune(typename PBU::args_t& args, typename PBU::nume
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (0 < occ && nlt < k) {
|
if (0 < occ && nlt < k) {
|
||||||
|
|
||||||
for (unsigned i = 0; i < args.size(); ++i) {
|
for (unsigned i = 0; i < args.size(); ++i) {
|
||||||
if (args[i].second < k) {
|
if (args[i].second < k) {
|
||||||
args[i] = args.back();
|
args[i] = args.back();
|
||||||
|
@ -273,8 +291,8 @@ void pb_rewriter_util<PBU>::prune(typename PBU::args_t& args, typename PBU::nume
|
||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unique(args, k);
|
unique(args, k, is_eq);
|
||||||
normalize(args, k);
|
normalize(args, k, is_eq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ Notes:
|
||||||
#include "tactic.h"
|
#include "tactic.h"
|
||||||
#include "lia2card_tactic.h"
|
#include "lia2card_tactic.h"
|
||||||
#include "elim01_tactic.h"
|
#include "elim01_tactic.h"
|
||||||
|
#include "solve_eqs_tactic.h"
|
||||||
#include "simplify_tactic.h"
|
#include "simplify_tactic.h"
|
||||||
#include "tactical.h"
|
#include "tactical.h"
|
||||||
#include "model_smt2_pp.h"
|
#include "model_smt2_pp.h"
|
||||||
|
@ -299,15 +300,15 @@ namespace opt {
|
||||||
g->assert_expr(fmls[i].get());
|
g->assert_expr(fmls[i].get());
|
||||||
}
|
}
|
||||||
tactic_ref tac0 = mk_simplify_tactic(m);
|
tactic_ref tac0 = mk_simplify_tactic(m);
|
||||||
tactic_ref tac1 = mk_elim01_tactic(m);
|
tactic_ref tac2 = mk_elim01_tactic(m);
|
||||||
tactic_ref tac2 = mk_lia2card_tactic(m);
|
tactic_ref tac3 = mk_lia2card_tactic(m);
|
||||||
tactic_ref tac;
|
tactic_ref tac;
|
||||||
opt_params optp(m_params);
|
opt_params optp(m_params);
|
||||||
if (optp.elim_01()) {
|
if (optp.elim_01()) {
|
||||||
tac = and_then(tac0.get(), tac1.get(), tac2.get());
|
tac = and_then(tac0.get(), tac2.get(), tac3.get());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tac = tac0;
|
tac = tac0.get();
|
||||||
}
|
}
|
||||||
proof_converter_ref pc;
|
proof_converter_ref pc;
|
||||||
expr_dependency_ref core(m);
|
expr_dependency_ref core(m);
|
||||||
|
|
|
@ -38,20 +38,26 @@ namespace smt {
|
||||||
stats() { reset(); }
|
stats() { reset(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
opt::opt_solver& s;
|
opt::opt_solver& s;
|
||||||
app_ref_vector m_vars; // Auxiliary variables per soft clause
|
mutable unsynch_mpz_manager m_mpz;
|
||||||
expr_ref_vector m_fmls; // Formulas per soft clause
|
app_ref_vector m_vars; // Auxiliary variables per soft clause
|
||||||
|
expr_ref_vector m_fmls; // Formulas per soft clause
|
||||||
app_ref m_min_cost_atom; // atom tracking modified lower bound
|
app_ref m_min_cost_atom; // atom tracking modified lower bound
|
||||||
app_ref_vector m_min_cost_atoms;
|
app_ref_vector m_min_cost_atoms;
|
||||||
bool_var m_min_cost_bv; // max cost Boolean variable
|
bool_var m_min_cost_bv; // max cost Boolean variable
|
||||||
vector<rational> m_weights; // weights of theory variables.
|
vector<rational> m_rweights; // weights of theory variables.
|
||||||
svector<theory_var> m_costs; // set of asserted theory variables
|
scoped_mpz_vector m_zweights;
|
||||||
svector<theory_var> m_cost_save; // set of asserted theory variables
|
svector<theory_var> m_costs; // set of asserted theory variables
|
||||||
rational m_cost; // current sum of asserted costs
|
svector<theory_var> m_cost_save; // set of asserted theory variables
|
||||||
rational m_min_cost; // current maximal cost assignment.
|
rational m_rcost; // current sum of asserted costs
|
||||||
u_map<theory_var> m_bool2var; // bool_var -> theory_var
|
rational m_rmin_cost; // current maximal cost assignment.
|
||||||
svector<bool_var> m_var2bool; // theory_var -> bool_var
|
scoped_mpz m_zcost; // current sum of asserted costs
|
||||||
|
scoped_mpz m_zmin_cost; // current maximal cost assignment.
|
||||||
|
u_map<theory_var> m_bool2var; // bool_var -> theory_var
|
||||||
|
svector<bool_var> m_var2bool; // theory_var -> bool_var
|
||||||
bool m_propagate;
|
bool m_propagate;
|
||||||
|
bool m_normalize;
|
||||||
|
rational m_den; // lcm of denominators for rational weights.
|
||||||
svector<bool> m_assigned;
|
svector<bool> m_assigned;
|
||||||
stats m_stats;
|
stats m_stats;
|
||||||
|
|
||||||
|
@ -63,9 +69,15 @@ namespace smt {
|
||||||
m_fmls(m),
|
m_fmls(m),
|
||||||
m_min_cost_atom(m),
|
m_min_cost_atom(m),
|
||||||
m_min_cost_atoms(m),
|
m_min_cost_atoms(m),
|
||||||
m_propagate(false)
|
m_zweights(m_mpz),
|
||||||
|
m_zcost(m_mpz),
|
||||||
|
m_zmin_cost(m_mpz),
|
||||||
|
m_propagate(false),
|
||||||
|
m_normalize(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
virtual ~theory_weighted_maxsat() { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief return the complement of variables that are currently assigned.
|
\brief return the complement of variables that are currently assigned.
|
||||||
*/
|
*/
|
||||||
|
@ -100,14 +112,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void init_search_eh() {
|
virtual void init_search_eh() {
|
||||||
context & ctx = get_context();
|
|
||||||
ast_manager& m = get_manager();
|
|
||||||
bool initialized = !m_var2bool.empty();
|
|
||||||
m_propagate = true;
|
m_propagate = true;
|
||||||
|
|
||||||
for (unsigned i = 0; i < m_min_cost_atoms.size(); ++i) {
|
|
||||||
app* var = m_min_cost_atoms[i].get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void assert_weighted(expr* fml, rational const& w) {
|
void assert_weighted(expr* fml, rational const& w) {
|
||||||
|
@ -118,12 +123,12 @@ namespace smt {
|
||||||
s.mc().insert(var->get_decl());
|
s.mc().insert(var->get_decl());
|
||||||
wfml = m.mk_or(var, fml);
|
wfml = m.mk_or(var, fml);
|
||||||
ctx.assert_expr(wfml);
|
ctx.assert_expr(wfml);
|
||||||
m_weights.push_back(w);
|
m_rweights.push_back(w);
|
||||||
m_vars.push_back(var);
|
m_vars.push_back(var);
|
||||||
m_fmls.push_back(fml);
|
m_fmls.push_back(fml);
|
||||||
m_assigned.push_back(false);
|
m_assigned.push_back(false);
|
||||||
m_min_cost += w;
|
m_rmin_cost += w;
|
||||||
|
m_normalize = true;
|
||||||
register_var(var, true);
|
register_var(var, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,15 +157,20 @@ namespace smt {
|
||||||
return bv;
|
return bv;
|
||||||
}
|
}
|
||||||
|
|
||||||
rational const& get_min_cost() const {
|
rational const& get_min_cost() {
|
||||||
return m_min_cost;
|
unsynch_mpq_manager mgr;
|
||||||
|
scoped_mpq q(mgr);
|
||||||
|
mgr.set(q, m_zmin_cost, m_den.to_mpq().numerator());
|
||||||
|
m_rmin_cost = rational(q);
|
||||||
|
return m_rmin_cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr* set_min_cost(rational const& c) {
|
expr* set_min_cost(rational const& c) {
|
||||||
|
m_normalize = true;
|
||||||
ast_manager& m = get_manager();
|
ast_manager& m = get_manager();
|
||||||
std::ostringstream strm;
|
std::ostringstream strm;
|
||||||
strm << "cost <= " << c;
|
strm << "cost <= " << c;
|
||||||
m_min_cost = c;
|
m_rmin_cost = c;
|
||||||
m_min_cost_atom = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort());
|
m_min_cost_atom = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort());
|
||||||
m_min_cost_atoms.push_back(m_min_cost_atom);
|
m_min_cost_atoms.push_back(m_min_cost_atom);
|
||||||
s.mc().insert(m_min_cost_atom->get_decl());
|
s.mc().insert(m_min_cost_atom->get_decl());
|
||||||
|
@ -177,17 +187,18 @@ namespace smt {
|
||||||
virtual void assign_eh(bool_var v, bool is_true) {
|
virtual void assign_eh(bool_var v, bool is_true) {
|
||||||
TRACE("opt", tout << "Assign " << mk_pp(m_vars[m_bool2var[v]].get(), get_manager()) << " " << is_true << "\n";);
|
TRACE("opt", tout << "Assign " << mk_pp(m_vars[m_bool2var[v]].get(), get_manager()) << " " << is_true << "\n";);
|
||||||
if (is_true) {
|
if (is_true) {
|
||||||
|
if (m_normalize) normalize();
|
||||||
context& ctx = get_context();
|
context& ctx = get_context();
|
||||||
theory_var tv = m_bool2var[v];
|
theory_var tv = m_bool2var[v];
|
||||||
if (m_assigned[tv]) return;
|
if (m_assigned[tv]) return;
|
||||||
rational const& w = m_weights[tv];
|
mpz const& w = m_zweights[tv];
|
||||||
ctx.push_trail(value_trail<context, rational>(m_cost));
|
ctx.push_trail(value_trail<context, scoped_mpz>(m_zcost));
|
||||||
ctx.push_trail(push_back_vector<context, svector<theory_var> >(m_costs));
|
ctx.push_trail(push_back_vector<context, svector<theory_var> >(m_costs));
|
||||||
ctx.push_trail(value_trail<context, bool>(m_assigned[tv]));
|
ctx.push_trail(value_trail<context, bool>(m_assigned[tv]));
|
||||||
m_cost += w;
|
m_zcost += w;
|
||||||
m_costs.push_back(tv);
|
m_costs.push_back(tv);
|
||||||
m_assigned[tv] = true;
|
m_assigned[tv] = true;
|
||||||
if (m_cost > m_min_cost) {
|
if (m_zcost > m_zmin_cost) {
|
||||||
block();
|
block();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,10 +224,13 @@ namespace smt {
|
||||||
theory::reset_eh();
|
theory::reset_eh();
|
||||||
m_vars.reset();
|
m_vars.reset();
|
||||||
m_fmls.reset();
|
m_fmls.reset();
|
||||||
m_weights.reset();
|
m_rweights.reset();
|
||||||
m_costs.reset();
|
m_costs.reset();
|
||||||
m_min_cost.reset();
|
m_rmin_cost.reset();
|
||||||
m_cost.reset();
|
m_rcost.reset();
|
||||||
|
m_zweights.reset();
|
||||||
|
m_zcost.reset();
|
||||||
|
m_zmin_cost.reset();
|
||||||
m_cost_save.reset();
|
m_cost_save.reset();
|
||||||
m_bool2var.reset();
|
m_bool2var.reset();
|
||||||
m_var2bool.reset();
|
m_var2bool.reset();
|
||||||
|
@ -254,7 +268,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_optimal() const {
|
bool is_optimal() const {
|
||||||
return m_cost < m_min_cost;
|
return m_mpz.lt(m_zcost, m_zmin_cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_ref mk_block() {
|
expr_ref mk_block() {
|
||||||
|
@ -263,17 +277,22 @@ namespace smt {
|
||||||
compare_cost compare_cost(*this);
|
compare_cost compare_cost(*this);
|
||||||
svector<theory_var> costs(m_costs);
|
svector<theory_var> costs(m_costs);
|
||||||
std::sort(costs.begin(), costs.end(), compare_cost);
|
std::sort(costs.begin(), costs.end(), compare_cost);
|
||||||
rational weight(0);
|
scoped_mpz weight(m_mpz);
|
||||||
for (unsigned i = 0; i < costs.size() && weight < m_min_cost; ++i) {
|
m_mpz.reset(weight);
|
||||||
weight += m_weights[costs[i]];
|
for (unsigned i = 0; i < costs.size() && m_mpz.lt(weight, m_zmin_cost); ++i) {
|
||||||
|
weight += m_zweights[costs[i]];
|
||||||
disj.push_back(m.mk_not(m_vars[costs[i]].get()));
|
disj.push_back(m.mk_not(m_vars[costs[i]].get()));
|
||||||
}
|
}
|
||||||
if (m_min_cost_atom) {
|
if (m_min_cost_atom) {
|
||||||
disj.push_back(m.mk_not(m_min_cost_atom));
|
disj.push_back(m.mk_not(m_min_cost_atom));
|
||||||
}
|
}
|
||||||
if (is_optimal()) {
|
if (is_optimal()) {
|
||||||
IF_VERBOSE(1, verbose_stream() << "(wmaxsat with upper bound: " << weight << ")\n";);
|
unsynch_mpq_manager mgr;
|
||||||
m_min_cost = weight;
|
scoped_mpq q(mgr);
|
||||||
|
mgr.set(q, m_zmin_cost, m_den.to_mpq().numerator());
|
||||||
|
rational rw = rational(q);
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "(wmaxsat with upper bound: " << rw << ")\n";);
|
||||||
|
m_zmin_cost = weight;
|
||||||
m_cost_save.reset();
|
m_cost_save.reset();
|
||||||
m_cost_save.append(m_costs);
|
m_cost_save.append(m_costs);
|
||||||
}
|
}
|
||||||
|
@ -307,9 +326,11 @@ namespace smt {
|
||||||
compare_cost compare_cost(*this);
|
compare_cost compare_cost(*this);
|
||||||
svector<theory_var> costs(m_costs);
|
svector<theory_var> costs(m_costs);
|
||||||
std::sort(costs.begin(), costs.end(), compare_cost);
|
std::sort(costs.begin(), costs.end(), compare_cost);
|
||||||
rational weight(0);
|
|
||||||
for (unsigned i = 0; i < costs.size() && weight < m_min_cost; ++i) {
|
scoped_mpz weight(m_mpz);
|
||||||
weight += m_weights[costs[i]];
|
m_mpz.reset(weight);
|
||||||
|
for (unsigned i = 0; i < costs.size() && weight < m_zmin_cost; ++i) {
|
||||||
|
weight += m_zweights[costs[i]];
|
||||||
lits.push_back(~literal(m_var2bool[costs[i]]));
|
lits.push_back(~literal(m_var2bool[costs[i]]));
|
||||||
}
|
}
|
||||||
if (m_min_cost_atom) {
|
if (m_min_cost_atom) {
|
||||||
|
@ -329,12 +350,32 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void normalize() {
|
||||||
|
m_den = rational::one();
|
||||||
|
for (unsigned i = 0; i < m_rweights.size(); ++i) {
|
||||||
|
m_den = lcm(m_den, denominator(m_rweights[i]));
|
||||||
|
}
|
||||||
|
m_den = lcm(m_den, denominator(m_rmin_cost));
|
||||||
|
m_zweights.reset();
|
||||||
|
for (unsigned i = 0; i < m_rweights.size(); ++i) {
|
||||||
|
rational r = m_rweights[i]*m_den;
|
||||||
|
SASSERT(r.is_int());
|
||||||
|
mpq const& q = r.to_mpq();
|
||||||
|
m_zweights.push_back(q.numerator());
|
||||||
|
}
|
||||||
|
rational r = m_rcost* m_den;
|
||||||
|
m_zcost = r.to_mpq().numerator();
|
||||||
|
r = m_rmin_cost * m_den;
|
||||||
|
m_zmin_cost = r.to_mpq().numerator();
|
||||||
|
m_normalize = false;
|
||||||
|
}
|
||||||
|
|
||||||
class compare_cost {
|
class compare_cost {
|
||||||
theory_weighted_maxsat& m_th;
|
theory_weighted_maxsat& m_th;
|
||||||
public:
|
public:
|
||||||
compare_cost(theory_weighted_maxsat& t):m_th(t) {}
|
compare_cost(theory_weighted_maxsat& t):m_th(t) {}
|
||||||
bool operator() (theory_var v, theory_var w) const {
|
bool operator() (theory_var v, theory_var w) const {
|
||||||
return m_th.m_weights[v] > m_th.m_weights[w];
|
return m_th.m_mpz.gt(m_th.m_zweights[v], m_th.m_zweights[w]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,8 +29,12 @@ namespace smt {
|
||||||
class theory_pb : public theory {
|
class theory_pb : public theory {
|
||||||
|
|
||||||
struct sort_expr;
|
struct sort_expr;
|
||||||
|
struct psort_expr;
|
||||||
class pb_justification;
|
class pb_justification;
|
||||||
class pb_model_value_proc;
|
class pb_model_value_proc;
|
||||||
|
class unwatch_ge;
|
||||||
|
class rewatch_vars;
|
||||||
|
class negate_ineq;
|
||||||
typedef rational numeral;
|
typedef rational numeral;
|
||||||
typedef vector<std::pair<literal, numeral> > arg_t;
|
typedef vector<std::pair<literal, numeral> > arg_t;
|
||||||
|
|
||||||
|
@ -48,20 +52,24 @@ namespace smt {
|
||||||
|
|
||||||
struct ineq {
|
struct ineq {
|
||||||
literal m_lit; // literal repesenting predicate
|
literal m_lit; // literal repesenting predicate
|
||||||
|
bool m_is_eq; // is this an = or >=.
|
||||||
arg_t m_args; // encode args[0]*coeffs[0]+...+args[n-1]*coeffs[n-1] >= m_k;
|
arg_t m_args; // encode args[0]*coeffs[0]+...+args[n-1]*coeffs[n-1] >= m_k;
|
||||||
numeral m_k; // invariants: m_k > 0, coeffs[i] > 0
|
numeral m_k; // invariants: m_k > 0, coeffs[i] > 0
|
||||||
|
|
||||||
// Watch the first few positions until the sum satisfies:
|
// Watch the first few positions until the sum satisfies:
|
||||||
// sum coeffs[i] >= m_lower + max_watch
|
// sum coeffs[i] >= m_lower + max_watch
|
||||||
|
|
||||||
numeral m_max_watch; // maximal coefficient.
|
numeral m_max_watch; // maximal coefficient.
|
||||||
unsigned m_watch_sz; // number of literals being watched.
|
unsigned m_watch_sz; // number of literals being watched.
|
||||||
numeral m_watch_sum; // maximal sum of watch literals.
|
numeral m_watch_sum; // maximal sum of watch literals.
|
||||||
|
// Watch infrastructure for = and unassigned >=:
|
||||||
|
unsigned m_nfixed; // number of variables that are fixed.
|
||||||
|
numeral m_max_sum; // maximal possible sum.
|
||||||
|
numeral m_min_sum; // minimal possible sum.
|
||||||
unsigned m_num_propagations;
|
unsigned m_num_propagations;
|
||||||
unsigned m_compilation_threshold;
|
unsigned m_compilation_threshold;
|
||||||
lbool m_compiled;
|
lbool m_compiled;
|
||||||
|
|
||||||
ineq(literal l) : m_lit(l) {
|
ineq(literal l, bool is_eq) : m_lit(l), m_is_eq(is_eq) {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,9 +84,15 @@ namespace smt {
|
||||||
numeral const& watch_sum() const { return m_watch_sum; }
|
numeral const& watch_sum() const { return m_watch_sum; }
|
||||||
numeral const& max_watch() const { return m_max_watch; }
|
numeral const& max_watch() const { return m_max_watch; }
|
||||||
void set_max_watch(numeral const& n) { m_max_watch = n; }
|
void set_max_watch(numeral const& n) { m_max_watch = n; }
|
||||||
|
|
||||||
unsigned watch_size() const { return m_watch_sz; }
|
unsigned watch_size() const { return m_watch_sz; }
|
||||||
|
|
||||||
|
// variable watch infrastructure
|
||||||
|
numeral min_sum() const { return m_min_sum; }
|
||||||
|
numeral max_sum() const { return m_max_sum; }
|
||||||
|
unsigned nfixed() const { return m_nfixed; }
|
||||||
|
bool vwatch_initialized() const { return !max_sum().is_zero(); }
|
||||||
|
void vwatch_reset() { m_min_sum.reset(); m_max_sum.reset(); m_nfixed = 0; }
|
||||||
|
|
||||||
unsigned find_lit(bool_var v, unsigned begin, unsigned end) {
|
unsigned find_lit(bool_var v, unsigned begin, unsigned end) {
|
||||||
while (lit(begin).var() != v) {
|
while (lit(begin).var() != v) {
|
||||||
++begin;
|
++begin;
|
||||||
|
@ -100,17 +114,19 @@ namespace smt {
|
||||||
bool well_formed() const;
|
bool well_formed() const;
|
||||||
|
|
||||||
app_ref to_expr(context& ctx, ast_manager& m);
|
app_ref to_expr(context& ctx, ast_manager& m);
|
||||||
|
|
||||||
|
bool is_eq() const { return m_is_eq; }
|
||||||
|
bool is_ge() const { return !m_is_eq; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ptr_vector<ineq> watch_list;
|
typedef ptr_vector<ineq> watch_list;
|
||||||
|
|
||||||
theory_pb_params m_params;
|
theory_pb_params m_params;
|
||||||
u_map<watch_list*> m_watch; // per literal.
|
u_map<watch_list*> m_lwatch; // per literal.
|
||||||
|
u_map<watch_list*> m_vwatch; // per variable.
|
||||||
u_map<ineq*> m_ineqs; // per inequality.
|
u_map<ineq*> m_ineqs; // per inequality.
|
||||||
unsigned_vector m_ineqs_trail;
|
unsigned_vector m_ineqs_trail;
|
||||||
unsigned_vector m_ineqs_lim;
|
unsigned_vector m_ineqs_lim;
|
||||||
ptr_vector<ineq> m_assign_ineqs_trail;
|
|
||||||
unsigned_vector m_assign_ineqs_lim;
|
|
||||||
literal_vector m_literals; // temporary vector
|
literal_vector m_literals; // temporary vector
|
||||||
pb_util m_util;
|
pb_util m_util;
|
||||||
stats m_stats;
|
stats m_stats;
|
||||||
|
@ -118,13 +134,24 @@ namespace smt {
|
||||||
unsigned m_conflict_frequency;
|
unsigned m_conflict_frequency;
|
||||||
bool m_learn_complements;
|
bool m_learn_complements;
|
||||||
bool m_enable_compilation;
|
bool m_enable_compilation;
|
||||||
|
rational m_max_compiled_coeff;
|
||||||
|
|
||||||
// internalize_atom:
|
// internalize_atom:
|
||||||
literal compile_arg(expr* arg);
|
literal compile_arg(expr* arg);
|
||||||
void add_watch(ineq& c, unsigned index);
|
void add_watch(ineq& c, unsigned index);
|
||||||
void del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index);
|
void del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index);
|
||||||
bool assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index);
|
void init_watch_literal(ineq& c);
|
||||||
|
void init_watch_var(ineq& c);
|
||||||
|
void clear_watch(ineq& c);
|
||||||
|
void watch_literal(literal lit, ineq* c);
|
||||||
|
void watch_var(bool_var v, ineq* c);
|
||||||
|
void unwatch_literal(literal w, ineq* c);
|
||||||
|
void unwatch_var(bool_var v, ineq* c);
|
||||||
|
void remove(ptr_vector<ineq>& ineqs, ineq* c);
|
||||||
|
bool assign_watch_ge(bool_var v, bool is_true, watch_list& watch, unsigned index);
|
||||||
|
void assign_watch(bool_var v, bool is_true, ineq& c);
|
||||||
void assign_ineq(ineq& c, bool is_true);
|
void assign_ineq(ineq& c, bool is_true);
|
||||||
|
void assign_eq(ineq& c, bool is_true);
|
||||||
|
|
||||||
std::ostream& display(std::ostream& out, ineq const& c, bool values = false) const;
|
std::ostream& display(std::ostream& out, ineq const& c, bool values = false) const;
|
||||||
virtual void display(std::ostream& out) const;
|
virtual void display(std::ostream& out) const;
|
||||||
|
@ -134,6 +161,7 @@ namespace smt {
|
||||||
void add_assign(ineq& c, literal_vector const& lits, literal l);
|
void add_assign(ineq& c, literal_vector const& lits, literal l);
|
||||||
literal_vector& get_lits();
|
literal_vector& get_lits();
|
||||||
|
|
||||||
|
literal_vector& get_all_literals(ineq& c, bool negate);
|
||||||
literal_vector& get_helpful_literals(ineq& c, bool negate);
|
literal_vector& get_helpful_literals(ineq& c, bool negate);
|
||||||
literal_vector& get_unhelpful_literals(ineq& c, bool negate);
|
literal_vector& get_unhelpful_literals(ineq& c, bool negate);
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,12 @@ Notes:
|
||||||
#include"model_smt2_pp.h"
|
#include"model_smt2_pp.h"
|
||||||
|
|
||||||
class bool2int_model_converter : public model_converter {
|
class bool2int_model_converter : public model_converter {
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
arith_util a;
|
arith_util a;
|
||||||
func_decl_ref_vector m_refs;
|
func_decl_ref_vector m_refs;
|
||||||
obj_map<func_decl, func_decl*> m_bool2int;
|
obj_hashtable<func_decl> m_bools;
|
||||||
|
vector<ptr_vector<func_decl> > m_nums_as_bool;
|
||||||
|
ptr_vector<func_decl> m_nums_as_int;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool2int_model_converter(ast_manager& m):
|
bool2int_model_converter(ast_manager& m):
|
||||||
|
@ -42,26 +44,34 @@ public:
|
||||||
SASSERT(goal_idx == 0);
|
SASSERT(goal_idx == 0);
|
||||||
model * new_model = alloc(model, m);
|
model * new_model = alloc(model, m);
|
||||||
unsigned num = old_model->get_num_constants();
|
unsigned num = old_model->get_num_constants();
|
||||||
|
for (unsigned i = 0; i < m_nums_as_int.size(); ++i) {
|
||||||
|
func_decl* f_old = m_nums_as_int[i];
|
||||||
|
rational val(0);
|
||||||
|
rational po(1);
|
||||||
|
bool is_value = true;
|
||||||
|
for (unsigned j = 0; is_value && j < m_nums_as_bool[i].size(); ++j) {
|
||||||
|
func_decl* f = m_nums_as_bool[i][j];
|
||||||
|
expr* fi = old_model->get_const_interp(f);
|
||||||
|
if (!fi) {
|
||||||
|
is_value = false;
|
||||||
|
}
|
||||||
|
else if (m.is_true(fi)) {
|
||||||
|
val += po;
|
||||||
|
}
|
||||||
|
else if (!m.is_false(fi)) {
|
||||||
|
is_value = false;
|
||||||
|
}
|
||||||
|
po *= rational(2);
|
||||||
|
}
|
||||||
|
if (is_value) {
|
||||||
|
expr* fi = a.mk_numeral(val, true);
|
||||||
|
new_model->register_decl(f_old, fi);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (unsigned i = 0; i < num; ++i) {
|
for (unsigned i = 0; i < num; ++i) {
|
||||||
func_decl* f = old_model->get_constant(i);
|
func_decl* f = old_model->get_constant(i);
|
||||||
expr* fi = old_model->get_const_interp(f);
|
expr* fi = old_model->get_const_interp(f);
|
||||||
func_decl* f_old;
|
if (!m_bools.contains(f)) {
|
||||||
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);
|
new_model->register_decl(f, fi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,15 +88,27 @@ public:
|
||||||
void insert(func_decl* x_new, func_decl* x_old) {
|
void insert(func_decl* x_new, func_decl* x_old) {
|
||||||
m_refs.push_back(x_new);
|
m_refs.push_back(x_new);
|
||||||
m_refs.push_back(x_old);
|
m_refs.push_back(x_old);
|
||||||
m_bool2int.insert(x_new, x_old);
|
m_bools.insert(x_new);
|
||||||
|
m_nums_as_int.push_back(x_old);
|
||||||
|
m_nums_as_bool.push_back(ptr_vector<func_decl>());
|
||||||
|
m_nums_as_bool.back().push_back(x_new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void insert(func_decl* x_old, unsigned sz, func_decl * const* x_new) {
|
||||||
|
m_nums_as_int.push_back(x_old);
|
||||||
|
m_nums_as_bool.push_back(ptr_vector<func_decl>());
|
||||||
|
m_refs.push_back(x_old);
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
m_refs.push_back(x_new[i]);
|
||||||
|
m_nums_as_bool.back().push_back(x_new[i]);
|
||||||
|
m_bools.insert(x_new[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual model_converter * translate(ast_translation & translator) {
|
virtual model_converter * translate(ast_translation & translator) {
|
||||||
bool2int_model_converter* mc = alloc(bool2int_model_converter, translator.to());
|
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 (unsigned i = 0; i < m_nums_as_int.size(); ++i) {
|
||||||
for (; it != end; ++it) {
|
mc->insert(m_nums_as_int[i], m_nums_as_bool[i].size(), m_nums_as_bool[i].c_ptr());
|
||||||
mc->insert(translator(it->m_key), translator(it->m_value));
|
|
||||||
}
|
}
|
||||||
return mc;
|
return mc;
|
||||||
}
|
}
|
||||||
|
@ -99,10 +121,14 @@ public:
|
||||||
ast_manager & m;
|
ast_manager & m;
|
||||||
arith_util a;
|
arith_util a;
|
||||||
params_ref m_params;
|
params_ref m_params;
|
||||||
|
unsigned m_max_hi_default;
|
||||||
|
rational m_max_hi;
|
||||||
|
|
||||||
elim01_tactic(ast_manager & _m, params_ref const & p):
|
elim01_tactic(ast_manager & _m, params_ref const & p):
|
||||||
m(_m),
|
m(_m),
|
||||||
a(m) {
|
a(m),
|
||||||
|
m_max_hi_default(8),
|
||||||
|
m_max_hi(rational(m_max_hi_default)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~elim01_tactic() {
|
virtual ~elim01_tactic() {
|
||||||
|
@ -111,10 +137,16 @@ public:
|
||||||
void set_cancel(bool f) {
|
void set_cancel(bool f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void updt_params(params_ref const & p) {
|
virtual void updt_params(params_ref const & p) {
|
||||||
|
m_max_hi = rational(p.get_uint("max_coefficient", m_max_hi_default));
|
||||||
m_params = p;
|
m_params = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void collect_param_descrs(param_descrs & r) {
|
||||||
|
r.insert("max_coefficient", CPK_UINT, "(default: 1) maximal upper bound for finite range -> Bool conversion");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void operator()(goal_ref const & g,
|
virtual void operator()(goal_ref const & g,
|
||||||
goal_ref_buffer & result,
|
goal_ref_buffer & result,
|
||||||
model_converter_ref & mc,
|
model_converter_ref & mc,
|
||||||
|
@ -129,6 +161,7 @@ public:
|
||||||
bool2int_model_converter* b2i = alloc(bool2int_model_converter, m);
|
bool2int_model_converter* b2i = alloc(bool2int_model_converter, m);
|
||||||
mc = b2i;
|
mc = b2i;
|
||||||
bound_manager bounds(m);
|
bound_manager bounds(m);
|
||||||
|
expr_ref_vector axioms(m);
|
||||||
bounds(*g);
|
bounds(*g);
|
||||||
|
|
||||||
bound_manager::iterator bit = bounds.begin(), bend = bounds.end();
|
bound_manager::iterator bit = bounds.begin(), bend = bounds.end();
|
||||||
|
@ -139,11 +172,8 @@ public:
|
||||||
rational lo, hi;
|
rational lo, hi;
|
||||||
if (a.is_int(x) &&
|
if (a.is_int(x) &&
|
||||||
bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() &&
|
bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() &&
|
||||||
bounds.has_upper(x, hi, s2) && !s2 && hi.is_one()) {
|
bounds.has_upper(x, hi, s2) && !s2 && hi <= m_max_hi) {
|
||||||
app* x_new = m.mk_fresh_const(x->get_decl()->get_name().str().c_str(), m.mk_bool_sort());
|
add_variable(b2i, sub, x, hi.get_unsigned(), axioms);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +185,9 @@ public:
|
||||||
sub(curr, new_curr);
|
sub(curr, new_curr);
|
||||||
g->update(i, new_curr, new_pr, g->dep(i));
|
g->update(i, new_curr, new_pr, g->dep(i));
|
||||||
}
|
}
|
||||||
|
for (unsigned i = 0; i < axioms.size(); ++i) {
|
||||||
|
g->assert_expr(axioms[i].get());
|
||||||
|
}
|
||||||
g->inc_depth();
|
g->inc_depth();
|
||||||
result.push_back(g.get());
|
result.push_back(g.get());
|
||||||
TRACE("pb", g->display(tout););
|
TRACE("pb", g->display(tout););
|
||||||
|
@ -167,9 +200,40 @@ public:
|
||||||
return alloc(elim01_tactic, m, m_params);
|
return alloc(elim01_tactic, m, m_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void collect_param_descrs(param_descrs & r) {}
|
|
||||||
|
|
||||||
virtual void cleanup() {}
|
virtual void cleanup() {}
|
||||||
|
|
||||||
|
void add_variable(bool2int_model_converter* b2i,
|
||||||
|
expr_safe_replace& sub,
|
||||||
|
app* x,
|
||||||
|
unsigned max_value,
|
||||||
|
expr_ref_vector& axioms) {
|
||||||
|
std::string name = x->get_decl()->get_name().str();
|
||||||
|
unsigned sh = 0;
|
||||||
|
app_ref_vector xs(m), ites(m);
|
||||||
|
func_decl_ref_vector xfs(m);
|
||||||
|
app_ref zero(m), sum(m);
|
||||||
|
zero = a.mk_numeral(rational(0), true);
|
||||||
|
while (max_value >= (1ul << sh)) {
|
||||||
|
xs.push_back(m.mk_fresh_const(name.c_str(), m.mk_bool_sort()));
|
||||||
|
xfs.push_back(xs.back()->get_decl());
|
||||||
|
ites.push_back(m.mk_ite(xs.back(), a.mk_numeral(rational(1 << sh), true), zero));
|
||||||
|
++sh;
|
||||||
|
}
|
||||||
|
if (ites.size() == 1) {
|
||||||
|
sum = ites[0].get();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sum = a.mk_add(ites.size(), (expr*const*)ites.c_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
sub.insert(x, sum);
|
||||||
|
b2i->insert(x->get_decl(), xfs.size(), xfs.c_ptr());
|
||||||
|
// if max_value+1 is not a power of two:
|
||||||
|
if ((max_value & (max_value + 1)) != 0) {
|
||||||
|
axioms.push_back(a.mk_le(sum, a.mk_numeral(rational(max_value), true)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p) {
|
tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p) {
|
||||||
|
|
|
@ -155,8 +155,7 @@ public:
|
||||||
else if (m.is_eq(fml, x, y) &&
|
else if (m.is_eq(fml, x, y) &&
|
||||||
get_pb_sum(x, rational::one(), args, coeffs, coeff) &&
|
get_pb_sum(x, rational::one(), args, coeffs, coeff) &&
|
||||||
get_pb_sum(y, -rational::one(), args, coeffs, coeff)) {
|
get_pb_sum(y, -rational::one(), args, coeffs, coeff)) {
|
||||||
result = m.mk_and(mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff),
|
result = mk_eq(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff);
|
||||||
mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -175,6 +174,14 @@ public:
|
||||||
return m_pb.mk_le(sz, weights, args, w);
|
return m_pb.mk_le(sz, weights, args, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr* mk_eq(unsigned sz, rational const* weights, expr* const* args, rational const& w) {
|
||||||
|
#if 1
|
||||||
|
return m.mk_and(mk_ge(sz, weights, args, w), mk_le(sz, weights, args, w));
|
||||||
|
#else
|
||||||
|
return m_pb.mk_eq(sz, weights, args, w);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
expr* mk_ge(unsigned sz, rational const* weights, expr* const* args, rational const& w) {
|
expr* mk_ge(unsigned sz, rational const* weights, expr* const* args, rational const& w) {
|
||||||
if (sz == 0) {
|
if (sz == 0) {
|
||||||
return w.is_pos()?m.mk_false():m.mk_true();
|
return w.is_pos()?m.mk_false():m.mk_true();
|
||||||
|
|
|
@ -116,4 +116,649 @@ Notes:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// parametric sorting network
|
||||||
|
// Described in Abio et.al. CP 2013.
|
||||||
|
template<class psort_expr>
|
||||||
|
class psort_nw {
|
||||||
|
typedef typename psort_expr::literal literal;
|
||||||
|
typedef typename psort_expr::literal_vector literal_vector;
|
||||||
|
|
||||||
|
class vc {
|
||||||
|
unsigned v; // number of vertices
|
||||||
|
unsigned c; // number of clauses
|
||||||
|
static const unsigned lambda = 5;
|
||||||
|
public:
|
||||||
|
vc(unsigned v, unsigned c):v(v), c(c) {}
|
||||||
|
|
||||||
|
bool operator<(vc const& other) const {
|
||||||
|
return to_int() < other.to_int();
|
||||||
|
}
|
||||||
|
vc operator+(vc const& other) const {
|
||||||
|
return vc(v + other.v, c + other.c);
|
||||||
|
}
|
||||||
|
unsigned to_int() const {
|
||||||
|
return lambda*v + c;
|
||||||
|
}
|
||||||
|
vc operator*(unsigned n) const {
|
||||||
|
return vc(n*v, n*c);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static vc min(vc const& v1, vc const& v2) {
|
||||||
|
return (v1.to_int() < v2.to_int())?v1:v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum cmp_t { LE, GE, EQ, GE_FULL, LE_FULL };
|
||||||
|
psort_expr& ctx;
|
||||||
|
cmp_t m_t;
|
||||||
|
|
||||||
|
// for testing
|
||||||
|
static const bool m_disable_dcard = false;
|
||||||
|
static const bool m_disable_dsorting = false;
|
||||||
|
static const bool m_disable_dsmerge = false;
|
||||||
|
static const bool m_force_dcard = false;
|
||||||
|
static const bool m_force_dsorting = false;
|
||||||
|
static const bool m_force_dsmerge = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct stats {
|
||||||
|
unsigned m_num_compiled_vars;
|
||||||
|
unsigned m_num_compiled_clauses;
|
||||||
|
void reset() { memset(this, 0, sizeof(*this)); }
|
||||||
|
stats() { reset(); }
|
||||||
|
};
|
||||||
|
stats m_stats;
|
||||||
|
|
||||||
|
psort_nw(psort_expr& c): ctx(c) {}
|
||||||
|
|
||||||
|
literal ge(bool full, unsigned k, unsigned n, literal const* xs) {
|
||||||
|
if (k > n) {
|
||||||
|
return ctx.mk_false();
|
||||||
|
}
|
||||||
|
if (k == 0) {
|
||||||
|
return ctx.mk_true();
|
||||||
|
}
|
||||||
|
SASSERT(0 < k && k <= n);
|
||||||
|
literal_vector in, out;
|
||||||
|
if (dualize(k, n, xs, in)) {
|
||||||
|
return le(full, k, in.size(), in.c_ptr());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(2*k <= n);
|
||||||
|
m_t = full?GE_FULL:GE;
|
||||||
|
card(k, n, xs, out);
|
||||||
|
return out[k-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
literal le(bool full, unsigned k, unsigned n, literal const* xs) {
|
||||||
|
if (k >= n) {
|
||||||
|
return ctx.mk_true();
|
||||||
|
}
|
||||||
|
SASSERT(k < n);
|
||||||
|
literal_vector in, out;
|
||||||
|
if (dualize(k, n, xs, in)) {
|
||||||
|
return ge(full, k, n, in.c_ptr());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(2*k <= n);
|
||||||
|
m_t = full?LE_FULL:LE;
|
||||||
|
card(k + 1, n, xs, out);
|
||||||
|
return ~out[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
literal eq(unsigned k, unsigned n, literal const* xs) {
|
||||||
|
if (k > n) {
|
||||||
|
return ctx.mk_false();
|
||||||
|
}
|
||||||
|
SASSERT(k <= n);
|
||||||
|
literal_vector in, out;
|
||||||
|
if (dualize(k, n, xs, in)) {
|
||||||
|
return eq(k, n, in.c_ptr());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(2*k < n);
|
||||||
|
m_t = EQ;
|
||||||
|
card(k+1, n, xs, out);
|
||||||
|
SASSERT(out.size() >= k+1);
|
||||||
|
return out[k-1]; // & ~out[m] TBD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::ostream& pp(std::ostream& out, unsigned n, literal const* lits) {
|
||||||
|
for (unsigned i = 0; i < n; ++i) ctx.pp(out, lits[i]) << " ";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& pp(std::ostream& out, literal_vector const& lits) {
|
||||||
|
for (unsigned i = 0; i < lits.size(); ++i) ctx.pp(out, lits[i]) << " ";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 <= k <= N
|
||||||
|
// SUM x_i >= k
|
||||||
|
// <=>
|
||||||
|
// SUM ~x_i <= N - k
|
||||||
|
// suppose k > N/2, then it is better to solve dual.
|
||||||
|
|
||||||
|
bool dualize(unsigned& k, unsigned N, literal const* xs, literal_vector& in) {
|
||||||
|
SASSERT(0 <= k && k <= N);
|
||||||
|
if (2*k <= N) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
k = N - k;
|
||||||
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
|
in.push_back(~xs[i]);
|
||||||
|
}
|
||||||
|
TRACE("pb",
|
||||||
|
pp(tout << N << ": ", in);
|
||||||
|
tout << " ~ " << k << "\n";);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool even(unsigned n) const { return (0 == (n & 0x1)); }
|
||||||
|
bool odd(unsigned n) const { return !even(n); }
|
||||||
|
unsigned ceil2(unsigned n) const { return n/2 + odd(n); }
|
||||||
|
unsigned floor2(unsigned n) const { return n/2; }
|
||||||
|
unsigned power2(unsigned n) const { SASSERT(n < 10); return 1 << n; }
|
||||||
|
|
||||||
|
|
||||||
|
literal max(literal a, literal b) {
|
||||||
|
if (a == b) return a;
|
||||||
|
m_stats.m_num_compiled_vars++;
|
||||||
|
return ctx.max(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
literal min(literal a, literal b) {
|
||||||
|
if (a == b) return a;
|
||||||
|
m_stats.m_num_compiled_vars++;
|
||||||
|
return ctx.min(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
literal fresh() {
|
||||||
|
m_stats.m_num_compiled_vars++;
|
||||||
|
return ctx.fresh();
|
||||||
|
}
|
||||||
|
void add_clause(literal l1, literal l2, literal l3) {
|
||||||
|
literal lits[3] = { l1, l2, l3 };
|
||||||
|
add_clause(3, lits);
|
||||||
|
}
|
||||||
|
void add_clause(literal l1, literal l2) {
|
||||||
|
literal lits[2] = { l1, l2 };
|
||||||
|
add_clause(2, lits);
|
||||||
|
}
|
||||||
|
void add_clause(unsigned n, literal const* ls) {
|
||||||
|
m_stats.m_num_compiled_clauses++;
|
||||||
|
literal_vector tmp(n, ls);
|
||||||
|
ctx.mk_clause(n, tmp.c_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// y1 <= max(x1,x2)
|
||||||
|
// y2 <= min(x1,x2)
|
||||||
|
void cmp_ge(literal x1, literal x2, literal y1, literal y2) {
|
||||||
|
add_clause(~y2, x1);
|
||||||
|
add_clause(~y2, x2);
|
||||||
|
add_clause(~y1, x1, x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// max(x1,x2) <= y1
|
||||||
|
// min(x1,x2) <= y2
|
||||||
|
void cmp_le(literal x1, literal x2, literal y1, literal y2) {
|
||||||
|
add_clause(~x1, y1);
|
||||||
|
add_clause(~x2, y1);
|
||||||
|
add_clause(~x1, ~x2, y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmp_eq(literal x1, literal x2, literal y1, literal y2) {
|
||||||
|
cmp_ge(x1, x2, y1, y2);
|
||||||
|
cmp_le(x1, x2, y1, y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmp(literal x1, literal x2, literal y1, literal y2) {
|
||||||
|
switch(m_t) {
|
||||||
|
case LE: cmp_le(x1, x2, y1, y2); break;
|
||||||
|
case GE: cmp_ge(x1, x2, y1, y2); break;
|
||||||
|
case EQ: cmp_eq(x1, x2, y1, y2); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vc vc_cmp() {
|
||||||
|
return vc(2, (m_t==EQ)?6:3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void card(unsigned k, unsigned n, literal const* xs, literal_vector& out) {
|
||||||
|
TRACE("pb", tout << "card k:" << k << " n: " << n << "\n";);
|
||||||
|
if (n <= k) {
|
||||||
|
sorting(n, xs, out);
|
||||||
|
}
|
||||||
|
else if (use_dcard(k, n)) {
|
||||||
|
dsorting(k, n, xs, out);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
literal_vector out1, out2;
|
||||||
|
unsigned l = n/2; // TBD
|
||||||
|
card(k, l, xs, out1);
|
||||||
|
card(k, n-l, xs + l, out2);
|
||||||
|
smerge(k, out1.size(), out1.c_ptr(), out2.size(), out2.c_ptr(), out);
|
||||||
|
}
|
||||||
|
TRACE("pb", tout << "card k:" << k << " n: " << n << "\n";
|
||||||
|
pp(tout << "in:", n, xs) << "\n";
|
||||||
|
pp(tout << "out:", out) << "\n";);
|
||||||
|
|
||||||
|
}
|
||||||
|
vc vc_card(unsigned k, unsigned n) {
|
||||||
|
if (n <= k) {
|
||||||
|
return vc_sorting(n);
|
||||||
|
}
|
||||||
|
else if (use_dcard(k, n)) {
|
||||||
|
return vc_dsorting(k, n);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return vc_card_rec(k, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vc vc_card_rec(unsigned k, unsigned n) {
|
||||||
|
unsigned l = n/2;
|
||||||
|
return vc_card(k, l) + vc_card(k, n-l) + vc_smerge(k, l, n-l);
|
||||||
|
}
|
||||||
|
bool use_dcard(unsigned k, unsigned n) {
|
||||||
|
return m_force_dcard || (!m_disable_dcard && n < 10 && vc_dsorting(k, n) < vc_card_rec(k, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void merge(unsigned a, literal const* as,
|
||||||
|
unsigned b, literal const* bs,
|
||||||
|
literal_vector& out) {
|
||||||
|
TRACE("pb", tout << "merge a: " << a << " b: " << b << "\n";);
|
||||||
|
if (a == 1 && b == 1) {
|
||||||
|
literal y1 = max(as[0], bs[0]);
|
||||||
|
literal y2 = min(as[0], bs[0]);
|
||||||
|
out.push_back(y1);
|
||||||
|
out.push_back(y2);
|
||||||
|
cmp(as[0], bs[0], y1, y2);
|
||||||
|
}
|
||||||
|
else if (a == 0) {
|
||||||
|
out.append(b, bs);
|
||||||
|
}
|
||||||
|
else if (b == 0) {
|
||||||
|
out.append(a, as);
|
||||||
|
}
|
||||||
|
else if (use_dsmerge(a, b, a + b)) {
|
||||||
|
dsmerge(a + b, a, as, b, bs, out);
|
||||||
|
}
|
||||||
|
else if (even(a) && odd(b)) {
|
||||||
|
merge(b, bs, a, as, out);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
literal_vector even_a, odd_a;
|
||||||
|
literal_vector even_b, odd_b;
|
||||||
|
literal_vector out1, out2;
|
||||||
|
SASSERT(a > 1 || b > 1);
|
||||||
|
split(a, as, even_a, odd_a);
|
||||||
|
split(b, bs, even_b, odd_b);
|
||||||
|
SASSERT(!even_a.empty());
|
||||||
|
SASSERT(!even_b.empty());
|
||||||
|
merge(even_a.size(), even_a.c_ptr(),
|
||||||
|
even_b.size(), even_b.c_ptr(), out1);
|
||||||
|
merge(odd_a.size(), odd_a.c_ptr(),
|
||||||
|
odd_b.size(), odd_b.c_ptr(), out2);
|
||||||
|
interleave(out1, out2, out);
|
||||||
|
}
|
||||||
|
TRACE("pb", tout << "merge a: " << a << " b: " << b << "\n";
|
||||||
|
pp(tout << "a:", a, as) << "\n";
|
||||||
|
pp(tout << "b:", b, bs) << "\n";
|
||||||
|
pp(tout << "out:", out) << "\n";);
|
||||||
|
}
|
||||||
|
vc vc_merge(unsigned a, unsigned b) {
|
||||||
|
if (a == 1 && b == 1) {
|
||||||
|
return vc_cmp();
|
||||||
|
}
|
||||||
|
else if (a == 0 || b == 0) {
|
||||||
|
return vc(0, 0);
|
||||||
|
}
|
||||||
|
else if (use_dsmerge(a, b, a + b)) {
|
||||||
|
return vc_dsmerge(a, b, a + b);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return vc_merge_rec(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vc vc_merge_rec(unsigned a, unsigned b) {
|
||||||
|
return
|
||||||
|
vc_merge(ceil2(a), ceil2(b)) +
|
||||||
|
vc_merge(floor2(a), floor2(b)) +
|
||||||
|
vc_interleave(ceil2(a) + ceil2(b), floor2(a) + floor2(b));
|
||||||
|
}
|
||||||
|
void split(unsigned n, literal const* ls, literal_vector& even, literal_vector& odd) {
|
||||||
|
for (unsigned i = 0; i < n; i += 2) {
|
||||||
|
even.push_back(ls[i]);
|
||||||
|
}
|
||||||
|
for (unsigned i = 1; i < n; i += 2) {
|
||||||
|
odd.push_back(ls[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void interleave(literal_vector const& as,
|
||||||
|
literal_vector const& bs,
|
||||||
|
literal_vector& out) {
|
||||||
|
TRACE("pb", tout << "interleave: " << as.size() << " " << bs.size() << "\n";);
|
||||||
|
SASSERT(as.size() >= bs.size());
|
||||||
|
SASSERT(as.size() <= bs.size() + 2);
|
||||||
|
SASSERT(!as.empty());
|
||||||
|
out.push_back(as[0]);
|
||||||
|
unsigned sz = std::min(as.size()-1, bs.size());
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
literal y1 = max(as[i+1],bs[i]);
|
||||||
|
literal y2 = min(as[i+1],bs[i]);
|
||||||
|
cmp(as[i+1], bs[i], y1, y2);
|
||||||
|
out.push_back(y1);
|
||||||
|
out.push_back(y2);
|
||||||
|
}
|
||||||
|
if (as.size() == bs.size()) {
|
||||||
|
out.push_back(bs[sz]);
|
||||||
|
}
|
||||||
|
else if (as.size() == bs.size() + 2) {
|
||||||
|
out.push_back(as[sz+1]);
|
||||||
|
}
|
||||||
|
SASSERT(out.size() == as.size() + bs.size());
|
||||||
|
TRACE("pb", tout << "interleave: " << as.size() << " " << bs.size() << "\n";
|
||||||
|
pp(tout << "a: ", as) << "\n";
|
||||||
|
pp(tout << "b: ", bs) << "\n";
|
||||||
|
pp(tout << "out: ", out) << "\n";);
|
||||||
|
|
||||||
|
}
|
||||||
|
vc vc_interleave(unsigned a, unsigned b) {
|
||||||
|
return vc_cmp()*std::min(a-1,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sorting(unsigned n, literal const* xs, literal_vector& out) {
|
||||||
|
TRACE("pb", tout << "sorting: " << n << "\n";);
|
||||||
|
switch(n) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
out.push_back(xs[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
merge(1, xs, 1, xs+1, out);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (use_dsorting(n)) {
|
||||||
|
dsorting(n, n, xs, out);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
literal_vector out1, out2;
|
||||||
|
unsigned l = n/2; // TBD
|
||||||
|
sorting(l, xs, out1);
|
||||||
|
sorting(n-l, xs+l, out2);
|
||||||
|
merge(out1.size(), out1.c_ptr(),
|
||||||
|
out2.size(), out2.c_ptr(),
|
||||||
|
out);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TRACE("pb", tout << "sorting: " << n << "\n";
|
||||||
|
pp(tout << "in:", n, xs) << "\n";
|
||||||
|
pp(tout << "out:", out) << "\n";);
|
||||||
|
|
||||||
|
}
|
||||||
|
vc vc_sorting(unsigned n) {
|
||||||
|
switch(n) {
|
||||||
|
case 0: return vc(0,0);
|
||||||
|
case 1: return vc(0,0);
|
||||||
|
case 2: return vc_merge(1,1);
|
||||||
|
default:
|
||||||
|
if (use_dsorting(n)) {
|
||||||
|
return vc_dsorting(n, n);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return vc_sorting_rec(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vc vc_sorting_rec(unsigned n) {
|
||||||
|
SASSERT(n > 2);
|
||||||
|
unsigned l = n/2;
|
||||||
|
return vc_sorting(l) + vc_sorting(n-l) + vc_merge(l, n-l);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool use_dsorting(unsigned n) {
|
||||||
|
SASSERT(n > 2);
|
||||||
|
return m_force_dsorting ||
|
||||||
|
(!m_disable_dsorting && n < 10 && vc_dsorting(n, n) < vc_sorting_rec(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
void smerge(unsigned c,
|
||||||
|
unsigned a, literal const* as,
|
||||||
|
unsigned b, literal const* bs,
|
||||||
|
literal_vector& out) {
|
||||||
|
TRACE("pb", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n";);
|
||||||
|
if (a == 1 && b == 1 && c == 1) {
|
||||||
|
literal y = max(as[0], bs[0]);
|
||||||
|
if (m_t != GE) {
|
||||||
|
// x1 <= max(x1,x2)
|
||||||
|
// x2 <= max(x1,x2)
|
||||||
|
add_clause(~as[0], y);
|
||||||
|
add_clause(~bs[0], y);
|
||||||
|
}
|
||||||
|
if (m_t != LE) {
|
||||||
|
// max(x1,x2) <= x1, x2
|
||||||
|
add_clause(~y, as[0], bs[0]);
|
||||||
|
}
|
||||||
|
out.push_back(y);
|
||||||
|
}
|
||||||
|
else if (a == 0) {
|
||||||
|
out.append(std::min(c, b), bs);
|
||||||
|
}
|
||||||
|
else if (b == 0) {
|
||||||
|
out.append(std::min(c, a), as);
|
||||||
|
}
|
||||||
|
else if (a > c) {
|
||||||
|
smerge(c, c, as, b, bs, out);
|
||||||
|
}
|
||||||
|
else if (b > c) {
|
||||||
|
smerge(c, a, as, c, bs, out);
|
||||||
|
}
|
||||||
|
else if (a + b <= c) {
|
||||||
|
merge(a, as, b, bs, out);
|
||||||
|
}
|
||||||
|
else if (use_dsmerge(a, b, c)) {
|
||||||
|
dsmerge(c, a, as, b, bs, out);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
literal_vector even_a, odd_a;
|
||||||
|
literal_vector even_b, odd_b;
|
||||||
|
literal_vector out1, out2;
|
||||||
|
split(a, as, even_a, odd_a);
|
||||||
|
split(b, bs, even_b, odd_b);
|
||||||
|
SASSERT(!even_a.empty());
|
||||||
|
SASSERT(!even_b.empty());
|
||||||
|
unsigned c1, c2;
|
||||||
|
if (even(c)) {
|
||||||
|
c1 = 1 + c/2; c2 = c/2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c1 = (c + 1)/2; c2 = (c - 1)/2;
|
||||||
|
}
|
||||||
|
smerge(c1, even_a.size(), even_a.c_ptr(),
|
||||||
|
even_b.size(), even_b.c_ptr(), out1);
|
||||||
|
smerge(c2, odd_a.size(), odd_a.c_ptr(),
|
||||||
|
odd_b.size(), odd_b.c_ptr(), out2);
|
||||||
|
SASSERT(out1.size() == std::min(even_a.size()+even_b.size(), c1));
|
||||||
|
SASSERT(out2.size() == std::min(odd_a.size()+odd_b.size(), c2));
|
||||||
|
literal y;
|
||||||
|
if (even(c)) {
|
||||||
|
literal z1 = out1.back();
|
||||||
|
literal z2 = out2.back();
|
||||||
|
out1.pop_back();
|
||||||
|
out2.pop_back();
|
||||||
|
y = max(z1, z2);
|
||||||
|
if (m_t != GE) {
|
||||||
|
add_clause(~z1, y);
|
||||||
|
add_clause(~z2, y);
|
||||||
|
}
|
||||||
|
if (m_t != LE) {
|
||||||
|
add_clause(~y, z1, z2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interleave(out1, out2, out);
|
||||||
|
if (even(c)) {
|
||||||
|
out.push_back(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRACE("pb", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n";
|
||||||
|
pp(tout << "a:", a, as) << "\n";
|
||||||
|
pp(tout << "b:", b, bs) << "\n";
|
||||||
|
pp(tout << "out:", out) << "\n";
|
||||||
|
);
|
||||||
|
SASSERT(out.size() == std::min(a + b, c));
|
||||||
|
}
|
||||||
|
|
||||||
|
vc vc_smerge(unsigned a, unsigned b, unsigned c) {
|
||||||
|
if (a == 1 && b == 1 && c == 1) {
|
||||||
|
vc v(1,0);
|
||||||
|
if (m_t != GE) v = v + vc(0, 2);
|
||||||
|
if (m_t != LE) v = v + vc(0, 1);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
if (a == 0 || b == 0) return vc(0, 0);
|
||||||
|
if (a > c) return vc_smerge(c, b, c);
|
||||||
|
if (b > c) return vc_smerge(a, c, c);
|
||||||
|
if (a + b <= c) return vc_merge(a, b);
|
||||||
|
if (use_dsmerge(a, b, c)) return vc_dsmerge(a, b, c);
|
||||||
|
return vc_smerge_rec(a, b, c);
|
||||||
|
}
|
||||||
|
vc vc_smerge_rec(unsigned a, unsigned b, unsigned c) {
|
||||||
|
return
|
||||||
|
vc_smerge(ceil2(a), ceil2(b), even(c)?(1+c/2):((c+1)/2)) +
|
||||||
|
vc_smerge(floor2(a), floor2(b), even(c)?(c/2):((c-1)/2)) +
|
||||||
|
vc_interleave(ceil2(a)+ceil2(b),floor2(a)+floor2(b)) +
|
||||||
|
vc(1, 0) +
|
||||||
|
((m_t != GE)?vc(0, 2):vc(0, 0)) +
|
||||||
|
((m_t != LE)?vc(0, 1):vc(0, 0));
|
||||||
|
}
|
||||||
|
bool use_dsmerge(unsigned a, unsigned b, unsigned c) {
|
||||||
|
return
|
||||||
|
m_force_dsmerge ||
|
||||||
|
(!m_disable_dsmerge &&
|
||||||
|
a < (1 << 15) && b < (1 << 15) &&
|
||||||
|
vc_dsmerge(a, b, a + b) < vc_smerge_rec(a, b, c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsmerge(
|
||||||
|
unsigned c,
|
||||||
|
unsigned a, literal const* as,
|
||||||
|
unsigned b, literal const* bs,
|
||||||
|
literal_vector& out) {
|
||||||
|
TRACE("pb", tout << "dsmerge: c:" << c << " a:" << a << " b:" << b << "\n";);
|
||||||
|
SASSERT(a <= c);
|
||||||
|
SASSERT(b <= c);
|
||||||
|
SASSERT(a + b >= c);
|
||||||
|
for (unsigned i = 0; i < c; ++i) {
|
||||||
|
out.push_back(fresh());
|
||||||
|
}
|
||||||
|
if (m_t != GE) {
|
||||||
|
for (unsigned i = 0; i < a; ++i) {
|
||||||
|
add_clause(~as[i], out[i]);
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < b; ++i) {
|
||||||
|
add_clause(~bs[i], out[i]);
|
||||||
|
}
|
||||||
|
for (unsigned i = 1; i <= a; ++i) {
|
||||||
|
for (unsigned j = 1; j <= b && i + j <= c; ++j) {
|
||||||
|
add_clause(~as[i-1],~bs[j-1],out[i+j-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_t != LE) {
|
||||||
|
for (unsigned k = 1; k <= c; ++k) {
|
||||||
|
literal_vector ls;
|
||||||
|
ls.push_back(~out[k-1]);
|
||||||
|
if (k <= a) {
|
||||||
|
ls.push_back(as[k-1]);
|
||||||
|
}
|
||||||
|
if (k <= b) {
|
||||||
|
ls.push_back(bs[k-1]);
|
||||||
|
}
|
||||||
|
for (unsigned i = 1; i <= std::min(a,k-1); ++i) {
|
||||||
|
if (k + 1 - i <= b) {
|
||||||
|
ls.push_back(as[i-1]);
|
||||||
|
ls.push_back(bs[k-i]);
|
||||||
|
add_clause(ls.size(), ls.c_ptr());
|
||||||
|
ls.pop_back();
|
||||||
|
ls.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vc vc_dsmerge(unsigned a, unsigned b, unsigned c) {
|
||||||
|
vc v(c, 0);
|
||||||
|
if (m_t != GE) {
|
||||||
|
v = v + vc(0, a + b + std::min(a, c)*std::min(b, c)/2);
|
||||||
|
}
|
||||||
|
if (m_t != LE) {
|
||||||
|
v = v + vc(0, std::min(a, c)*std::min(b, c)/2);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dsorting(unsigned m, unsigned n, literal const* xs,
|
||||||
|
literal_vector& out) {
|
||||||
|
TRACE("pb", tout << "dsorting m: " << m << " n: " << n << "\n";);
|
||||||
|
SASSERT(m <= n);
|
||||||
|
literal_vector lits;
|
||||||
|
for (unsigned i = 0; i < m; ++i) {
|
||||||
|
out.push_back(fresh());
|
||||||
|
}
|
||||||
|
if (m_t != GE) {
|
||||||
|
for (unsigned k = 1; k <= m; ++k) {
|
||||||
|
lits.push_back(out[k-1]);
|
||||||
|
add_subset(true, k, 0, lits, n, xs);
|
||||||
|
lits.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_t != LE) {
|
||||||
|
for (unsigned k = 1; k <= m; ++k) {
|
||||||
|
lits.push_back(~out[k-1]);
|
||||||
|
add_subset(false, n-k+1, 0, lits, n, xs);
|
||||||
|
lits.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vc vc_dsorting(unsigned m, unsigned n) {
|
||||||
|
SASSERT(m <= n && n < 10);
|
||||||
|
vc v(m, 0);
|
||||||
|
if (m_t != GE) {
|
||||||
|
v = v + vc(0, power2(n-1));
|
||||||
|
}
|
||||||
|
if (m_t != LE) {
|
||||||
|
v = v + vc(0, power2(n-1));
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_subset(bool polarity, unsigned k, unsigned offset, literal_vector& lits,
|
||||||
|
unsigned n, literal const* xs) {
|
||||||
|
TRACE("pb", tout << "k:" << k << " offset: " << offset << " n: " << n << " ";
|
||||||
|
pp(tout, lits) << "\n";);
|
||||||
|
SASSERT(k + offset <= n);
|
||||||
|
if (k == 0) {
|
||||||
|
add_clause(lits.size(), lits.c_ptr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (unsigned i = offset; i < n - k + 1; ++i) {
|
||||||
|
lits.push_back(polarity?~xs[i]:xs[i]);
|
||||||
|
add_subset(polarity, k-1, i+1, lits, n, xs);
|
||||||
|
lits.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue