mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 10:25:18 +00:00
working on incremtal PB theory
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
1f7c994e43
commit
236b2d2ff3
|
@ -23,7 +23,8 @@ pb_decl_plugin::pb_decl_plugin():
|
|||
m_at_most_sym("at-most"),
|
||||
m_at_least_sym("at-least"),
|
||||
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,
|
||||
|
@ -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_PB_LE: sym = m_pble_sym; break;
|
||||
case OP_PB_GE: sym = m_pbge_sym; break;
|
||||
case OP_PB_EQ: sym = m_pbeq_sym; break;
|
||||
default: break;
|
||||
}
|
||||
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);
|
||||
}
|
||||
case OP_PB_GE:
|
||||
case OP_PB_LE: {
|
||||
case OP_PB_LE:
|
||||
case OP_PB_EQ: {
|
||||
if (num_parameters != 1 + arity) {
|
||||
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 {
|
||||
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());
|
||||
|
@ -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) {
|
||||
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_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_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());
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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)) {
|
||||
k = get_k(a);
|
||||
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) {
|
||||
parameter param(k);
|
||||
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);
|
||||
}
|
||||
|
||||
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)) {
|
||||
k = get_k(a);
|
||||
return true;
|
||||
|
@ -159,7 +172,7 @@ rational pb_util::get_k(func_decl *a) const {
|
|||
return to_rational(p);
|
||||
}
|
||||
else {
|
||||
SASSERT(is_le(a) || is_ge(a));
|
||||
SASSERT(is_le(a) || is_ge(a) || is_eq(a));
|
||||
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);
|
||||
}
|
||||
|
||||
bool pb_util::is_le(app* a, rational& k) const {
|
||||
bool pb_util::is_le(expr* a, rational& k) const {
|
||||
if (is_le(a)) {
|
||||
k = get_k(a);
|
||||
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);
|
||||
}
|
||||
|
||||
bool pb_util::is_ge(app* a, rational& k) const {
|
||||
bool pb_util::is_ge(expr* a, rational& k) const {
|
||||
if (is_ge(a)) {
|
||||
k = get_k(a);
|
||||
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 {
|
||||
if (is_at_most_k(a) || is_at_least_k(a)) {
|
||||
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());
|
||||
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_PB_LE, // pseudo-Boolean <= (generalizes at_most_k)
|
||||
OP_PB_GE, // pseudo-Boolean >=
|
||||
OP_PB_EQ, // equality
|
||||
LAST_PB_OP
|
||||
};
|
||||
|
||||
|
@ -43,10 +44,12 @@ class pb_decl_plugin : public decl_plugin {
|
|||
symbol m_at_least_sym;
|
||||
symbol m_pble_sym;
|
||||
symbol m_pbge_sym;
|
||||
symbol m_pbeq_sym;
|
||||
func_decl * mk_at_most(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_ge(unsigned arity, rational const* coeffs, int k);
|
||||
func_decl * mk_eq(unsigned arity, rational const* coeffs, int k);
|
||||
public:
|
||||
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_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_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(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(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(expr *a) const { return get_k(to_app(a)->get_decl()); }
|
||||
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(app* a, rational& k) const;
|
||||
bool is_le(expr* a, rational& k) 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(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(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:
|
||||
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;
|
||||
case OP_AT_LEAST_K:
|
||||
case OP_PB_GE:
|
||||
case OP_PB_EQ:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
bool is_eq = f->get_decl_kind() == OP_PB_EQ;
|
||||
|
||||
pb_ast_rewriter_util pbu(m);
|
||||
pb_rewriter_util<pb_ast_rewriter_util> util(pbu);
|
||||
|
||||
util.unique(vec, k);
|
||||
lbool is_sat = util.normalize(vec, k);
|
||||
util.prune(vec, k);
|
||||
util.unique(vec, k, is_eq);
|
||||
lbool is_sat = util.normalize(vec, k, is_eq);
|
||||
util.prune(vec, k, is_eq);
|
||||
switch (is_sat) {
|
||||
case l_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_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;
|
||||
}
|
||||
TRACE("pb",
|
||||
|
|
|
@ -28,12 +28,12 @@ Notes:
|
|||
template<typename PBU>
|
||||
class pb_rewriter_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:
|
||||
pb_rewriter_util(PBU& u) : m_util(u) {}
|
||||
void unique(typename PBU::args_t& args, typename PBU::numeral& k);
|
||||
lbool normalize(typename PBU::args_t& args, typename PBU::numeral& k);
|
||||
void prune(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, bool is_eq);
|
||||
void prune(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,20 +23,20 @@ Notes:
|
|||
|
||||
|
||||
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) {
|
||||
out << args[i].second << " * ";
|
||||
m_util.display(out, args[i].first);
|
||||
out << " ";
|
||||
if (i+1 < args.size()) out << "+ ";
|
||||
}
|
||||
out << " >= " << k << "\n";
|
||||
out << (is_eq?" = ":" >= ") << k << "\n";
|
||||
}
|
||||
|
||||
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) {
|
||||
if (m_util.is_negated(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);
|
||||
TRACE("pb_verbose", display(tout << "post-unique:", args, k););
|
||||
TRACE("pb_verbose", display(tout << "post-unique:", args, k, is_eq););
|
||||
}
|
||||
|
||||
template<typename PBU>
|
||||
lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU::numeral& k) {
|
||||
TRACE("pb_verbose", display(tout << "pre-normalize:", args, 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, is_eq););
|
||||
|
||||
DEBUG_CODE(
|
||||
bool found = false;
|
||||
for (unsigned i = 0; !found && i < args.size(); ++i) {
|
||||
found = args[i].second.is_zero();
|
||||
}
|
||||
if (found) display(verbose_stream(), args, k);
|
||||
if (found) display(verbose_stream(), args, k, is_eq);
|
||||
SASSERT(!found););
|
||||
|
||||
//
|
||||
|
@ -121,17 +121,29 @@ lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU:
|
|||
sum += args[i].second;
|
||||
}
|
||||
// detect tautologies:
|
||||
if (k <= PBU::numeral::zero()) {
|
||||
if (!is_eq && k <= PBU::numeral::zero()) {
|
||||
args.reset();
|
||||
k = PBU::numeral::zero();
|
||||
return l_true;
|
||||
}
|
||||
if (is_eq && k.is_zero() && args.empty()) {
|
||||
return l_true;
|
||||
}
|
||||
|
||||
// detect infeasible constraints:
|
||||
if (sum < k) {
|
||||
args.reset();
|
||||
k = PBU::numeral::one();
|
||||
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;
|
||||
for (unsigned i = 0; all_int && i < args.size(); ++i) {
|
||||
|
@ -150,6 +162,11 @@ lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU:
|
|||
args[i].second *= d;
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
sum = PBU::numeral::zero();
|
||||
|
@ -193,7 +210,7 @@ lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU:
|
|||
}
|
||||
else if (g > PBU::numeral::one()) {
|
||||
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 n2 = ceil(k/min) - PBU::numeral::one();
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
TRACE("pb_verbose", display(tout << "post-normalize:", args, k, is_eq););
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
unsigned occ = 0;
|
||||
for (unsigned i = 0; nlt < k && i < args.size(); ++i) {
|
||||
|
@ -264,8 +283,7 @@ void pb_rewriter_util<PBU>::prune(typename PBU::args_t& args, typename PBU::nume
|
|||
++occ;
|
||||
}
|
||||
}
|
||||
if (0 < occ && nlt < k) {
|
||||
|
||||
if (0 < occ && nlt < k) {
|
||||
for (unsigned i = 0; i < args.size(); ++i) {
|
||||
if (args[i].second < k) {
|
||||
args[i] = args.back();
|
||||
|
@ -273,8 +291,8 @@ void pb_rewriter_util<PBU>::prune(typename PBU::args_t& args, typename PBU::nume
|
|||
--i;
|
||||
}
|
||||
}
|
||||
unique(args, k);
|
||||
normalize(args, k);
|
||||
unique(args, k, is_eq);
|
||||
normalize(args, k, is_eq);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ Notes:
|
|||
#include "tactic.h"
|
||||
#include "lia2card_tactic.h"
|
||||
#include "elim01_tactic.h"
|
||||
#include "solve_eqs_tactic.h"
|
||||
#include "simplify_tactic.h"
|
||||
#include "tactical.h"
|
||||
#include "model_smt2_pp.h"
|
||||
|
@ -299,15 +300,15 @@ namespace opt {
|
|||
g->assert_expr(fmls[i].get());
|
||||
}
|
||||
tactic_ref tac0 = mk_simplify_tactic(m);
|
||||
tactic_ref tac1 = mk_elim01_tactic(m);
|
||||
tactic_ref tac2 = mk_lia2card_tactic(m);
|
||||
tactic_ref tac2 = mk_elim01_tactic(m);
|
||||
tactic_ref tac3 = mk_lia2card_tactic(m);
|
||||
tactic_ref tac;
|
||||
opt_params optp(m_params);
|
||||
if (optp.elim_01()) {
|
||||
tac = and_then(tac0.get(), tac1.get(), tac2.get());
|
||||
tac = and_then(tac0.get(), tac2.get(), tac3.get());
|
||||
}
|
||||
else {
|
||||
tac = tac0;
|
||||
tac = tac0.get();
|
||||
}
|
||||
proof_converter_ref pc;
|
||||
expr_dependency_ref core(m);
|
||||
|
|
|
@ -38,20 +38,26 @@ namespace smt {
|
|||
stats() { reset(); }
|
||||
};
|
||||
|
||||
opt::opt_solver& s;
|
||||
app_ref_vector m_vars; // Auxiliary variables per soft clause
|
||||
expr_ref_vector m_fmls; // Formulas per soft clause
|
||||
opt::opt_solver& s;
|
||||
mutable unsynch_mpz_manager m_mpz;
|
||||
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_vector m_min_cost_atoms;
|
||||
bool_var m_min_cost_bv; // max cost Boolean variable
|
||||
vector<rational> m_weights; // weights of theory variables.
|
||||
svector<theory_var> m_costs; // set of asserted theory variables
|
||||
svector<theory_var> m_cost_save; // set of asserted theory variables
|
||||
rational m_cost; // current sum of asserted costs
|
||||
rational m_min_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_var m_min_cost_bv; // max cost Boolean variable
|
||||
vector<rational> m_rweights; // weights of theory variables.
|
||||
scoped_mpz_vector m_zweights;
|
||||
svector<theory_var> m_costs; // set of asserted theory variables
|
||||
svector<theory_var> m_cost_save; // set of asserted theory variables
|
||||
rational m_rcost; // current sum of asserted costs
|
||||
rational m_rmin_cost; // current maximal cost assignment.
|
||||
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_normalize;
|
||||
rational m_den; // lcm of denominators for rational weights.
|
||||
svector<bool> m_assigned;
|
||||
stats m_stats;
|
||||
|
||||
|
@ -63,9 +69,15 @@ namespace smt {
|
|||
m_fmls(m),
|
||||
m_min_cost_atom(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.
|
||||
*/
|
||||
|
@ -100,14 +112,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
virtual void init_search_eh() {
|
||||
context & ctx = get_context();
|
||||
ast_manager& m = get_manager();
|
||||
bool initialized = !m_var2bool.empty();
|
||||
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) {
|
||||
|
@ -118,12 +123,12 @@ namespace smt {
|
|||
s.mc().insert(var->get_decl());
|
||||
wfml = m.mk_or(var, fml);
|
||||
ctx.assert_expr(wfml);
|
||||
m_weights.push_back(w);
|
||||
m_rweights.push_back(w);
|
||||
m_vars.push_back(var);
|
||||
m_fmls.push_back(fml);
|
||||
m_assigned.push_back(false);
|
||||
m_min_cost += w;
|
||||
|
||||
m_rmin_cost += w;
|
||||
m_normalize = true;
|
||||
register_var(var, true);
|
||||
}
|
||||
|
||||
|
@ -152,15 +157,20 @@ namespace smt {
|
|||
return bv;
|
||||
}
|
||||
|
||||
rational const& get_min_cost() const {
|
||||
return m_min_cost;
|
||||
rational const& get_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) {
|
||||
m_normalize = true;
|
||||
ast_manager& m = get_manager();
|
||||
std::ostringstream strm;
|
||||
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_atoms.push_back(m_min_cost_atom);
|
||||
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) {
|
||||
TRACE("opt", tout << "Assign " << mk_pp(m_vars[m_bool2var[v]].get(), get_manager()) << " " << is_true << "\n";);
|
||||
if (is_true) {
|
||||
if (m_normalize) normalize();
|
||||
context& ctx = get_context();
|
||||
theory_var tv = m_bool2var[v];
|
||||
if (m_assigned[tv]) return;
|
||||
rational const& w = m_weights[tv];
|
||||
ctx.push_trail(value_trail<context, rational>(m_cost));
|
||||
mpz const& w = m_zweights[tv];
|
||||
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(value_trail<context, bool>(m_assigned[tv]));
|
||||
m_cost += w;
|
||||
m_zcost += w;
|
||||
m_costs.push_back(tv);
|
||||
m_assigned[tv] = true;
|
||||
if (m_cost > m_min_cost) {
|
||||
if (m_zcost > m_zmin_cost) {
|
||||
block();
|
||||
}
|
||||
}
|
||||
|
@ -213,10 +224,13 @@ namespace smt {
|
|||
theory::reset_eh();
|
||||
m_vars.reset();
|
||||
m_fmls.reset();
|
||||
m_weights.reset();
|
||||
m_rweights.reset();
|
||||
m_costs.reset();
|
||||
m_min_cost.reset();
|
||||
m_cost.reset();
|
||||
m_rmin_cost.reset();
|
||||
m_rcost.reset();
|
||||
m_zweights.reset();
|
||||
m_zcost.reset();
|
||||
m_zmin_cost.reset();
|
||||
m_cost_save.reset();
|
||||
m_bool2var.reset();
|
||||
m_var2bool.reset();
|
||||
|
@ -254,7 +268,7 @@ namespace smt {
|
|||
}
|
||||
|
||||
bool is_optimal() const {
|
||||
return m_cost < m_min_cost;
|
||||
return m_mpz.lt(m_zcost, m_zmin_cost);
|
||||
}
|
||||
|
||||
expr_ref mk_block() {
|
||||
|
@ -263,17 +277,22 @@ namespace smt {
|
|||
compare_cost compare_cost(*this);
|
||||
svector<theory_var> costs(m_costs);
|
||||
std::sort(costs.begin(), costs.end(), compare_cost);
|
||||
rational weight(0);
|
||||
for (unsigned i = 0; i < costs.size() && weight < m_min_cost; ++i) {
|
||||
weight += m_weights[costs[i]];
|
||||
scoped_mpz weight(m_mpz);
|
||||
m_mpz.reset(weight);
|
||||
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()));
|
||||
}
|
||||
if (m_min_cost_atom) {
|
||||
disj.push_back(m.mk_not(m_min_cost_atom));
|
||||
}
|
||||
if (is_optimal()) {
|
||||
IF_VERBOSE(1, verbose_stream() << "(wmaxsat with upper bound: " << weight << ")\n";);
|
||||
m_min_cost = weight;
|
||||
unsynch_mpq_manager mgr;
|
||||
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.append(m_costs);
|
||||
}
|
||||
|
@ -307,9 +326,11 @@ namespace smt {
|
|||
compare_cost compare_cost(*this);
|
||||
svector<theory_var> costs(m_costs);
|
||||
std::sort(costs.begin(), costs.end(), compare_cost);
|
||||
rational weight(0);
|
||||
for (unsigned i = 0; i < costs.size() && weight < m_min_cost; ++i) {
|
||||
weight += m_weights[costs[i]];
|
||||
|
||||
scoped_mpz weight(m_mpz);
|
||||
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]]));
|
||||
}
|
||||
if (m_min_cost_atom) {
|
||||
|
@ -328,13 +349,33 @@ namespace smt {
|
|||
ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
theory_weighted_maxsat& m_th;
|
||||
public:
|
||||
compare_cost(theory_weighted_maxsat& t):m_th(t) {}
|
||||
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 {
|
||||
|
||||
struct sort_expr;
|
||||
struct psort_expr;
|
||||
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 vector<std::pair<literal, numeral> > arg_t;
|
||||
|
||||
|
@ -48,20 +52,24 @@ namespace smt {
|
|||
|
||||
struct ineq {
|
||||
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;
|
||||
numeral m_k; // invariants: m_k > 0, coeffs[i] > 0
|
||||
|
||||
// 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.
|
||||
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_compilation_threshold;
|
||||
lbool m_compiled;
|
||||
|
||||
ineq(literal l) : m_lit(l) {
|
||||
ineq(literal l, bool is_eq) : m_lit(l), m_is_eq(is_eq) {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -75,10 +83,16 @@ namespace smt {
|
|||
|
||||
numeral const& watch_sum() const { return m_watch_sum; }
|
||||
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; }
|
||||
|
||||
// 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) {
|
||||
while (lit(begin).var() != v) {
|
||||
++begin;
|
||||
|
@ -100,17 +114,19 @@ namespace smt {
|
|||
bool well_formed() const;
|
||||
|
||||
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;
|
||||
|
||||
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.
|
||||
unsigned_vector m_ineqs_trail;
|
||||
unsigned_vector m_ineqs_lim;
|
||||
ptr_vector<ineq> m_assign_ineqs_trail;
|
||||
unsigned_vector m_assign_ineqs_lim;
|
||||
literal_vector m_literals; // temporary vector
|
||||
pb_util m_util;
|
||||
stats m_stats;
|
||||
|
@ -118,13 +134,24 @@ namespace smt {
|
|||
unsigned m_conflict_frequency;
|
||||
bool m_learn_complements;
|
||||
bool m_enable_compilation;
|
||||
rational m_max_compiled_coeff;
|
||||
|
||||
// internalize_atom:
|
||||
literal compile_arg(expr* arg);
|
||||
void add_watch(ineq& c, unsigned 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_eq(ineq& c, bool is_true);
|
||||
|
||||
std::ostream& display(std::ostream& out, ineq const& c, bool values = false) 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);
|
||||
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_unhelpful_literals(ineq& c, bool negate);
|
||||
|
||||
|
|
|
@ -26,10 +26,12 @@ Notes:
|
|||
#include"model_smt2_pp.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;
|
||||
ast_manager& m;
|
||||
arith_util a;
|
||||
func_decl_ref_vector m_refs;
|
||||
obj_hashtable<func_decl> m_bools;
|
||||
vector<ptr_vector<func_decl> > m_nums_as_bool;
|
||||
ptr_vector<func_decl> m_nums_as_int;
|
||||
public:
|
||||
|
||||
bool2int_model_converter(ast_manager& m):
|
||||
|
@ -42,26 +44,34 @@ public:
|
|||
SASSERT(goal_idx == 0);
|
||||
model * new_model = alloc(model, m);
|
||||
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) {
|
||||
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 {
|
||||
if (!m_bools.contains(f)) {
|
||||
new_model->register_decl(f, fi);
|
||||
}
|
||||
}
|
||||
|
@ -78,15 +88,27 @@ public:
|
|||
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);
|
||||
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) {
|
||||
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));
|
||||
for (unsigned i = 0; i < m_nums_as_int.size(); ++i) {
|
||||
mc->insert(m_nums_as_int[i], m_nums_as_bool[i].size(), m_nums_as_bool[i].c_ptr());
|
||||
}
|
||||
return mc;
|
||||
}
|
||||
|
@ -99,10 +121,14 @@ public:
|
|||
ast_manager & m;
|
||||
arith_util a;
|
||||
params_ref m_params;
|
||||
unsigned m_max_hi_default;
|
||||
rational m_max_hi;
|
||||
|
||||
elim01_tactic(ast_manager & _m, params_ref const & p):
|
||||
m(_m),
|
||||
a(m) {
|
||||
a(m),
|
||||
m_max_hi_default(8),
|
||||
m_max_hi(rational(m_max_hi_default)) {
|
||||
}
|
||||
|
||||
virtual ~elim01_tactic() {
|
||||
|
@ -111,9 +137,15 @@ public:
|
|||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
goal_ref_buffer & result,
|
||||
|
@ -129,6 +161,7 @@ public:
|
|||
bool2int_model_converter* b2i = alloc(bool2int_model_converter, m);
|
||||
mc = b2i;
|
||||
bound_manager bounds(m);
|
||||
expr_ref_vector axioms(m);
|
||||
bounds(*g);
|
||||
|
||||
bound_manager::iterator bit = bounds.begin(), bend = bounds.end();
|
||||
|
@ -139,11 +172,8 @@ public:
|
|||
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());
|
||||
bounds.has_upper(x, hi, s2) && !s2 && hi <= m_max_hi) {
|
||||
add_variable(b2i, sub, x, hi.get_unsigned(), axioms);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,6 +185,9 @@ public:
|
|||
sub(curr, new_curr);
|
||||
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();
|
||||
result.push_back(g.get());
|
||||
TRACE("pb", g->display(tout););
|
||||
|
@ -166,10 +199,41 @@ public:
|
|||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(elim01_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {}
|
||||
|
||||
|
||||
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) {
|
||||
|
|
|
@ -155,8 +155,7 @@ public:
|
|||
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(mk_le(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff),
|
||||
mk_ge(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff));
|
||||
result = mk_eq(coeffs.size(), coeffs.c_ptr(), args.c_ptr(), -coeff);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -174,6 +173,14 @@ public:
|
|||
}
|
||||
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) {
|
||||
if (sz == 0) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue