3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 10:25:18 +00:00

working on pb solver

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2013-11-16 17:01:43 -08:00
parent 06073db413
commit 77cdb2bcde
3 changed files with 343 additions and 221 deletions

View file

@ -32,6 +32,7 @@ Revision History:
#include"theory_dl.h"
#include"theory_seq_empty.h"
#include"theory_card.h"
#include"theory_pb.h"
namespace smt {
@ -792,7 +793,8 @@ namespace smt {
}
void setup::setup_card() {
m_context.register_plugin(alloc(theory_card, m_manager));
// m_context.register_plugin(alloc(theory_card, m_manager));
m_context.register_plugin(alloc(theory_pb, m_manager));
}
void setup::setup_unknown() {

View file

@ -55,14 +55,14 @@ namespace smt {
ineq* c = alloc(ineq, atom, literal(abv));
c->m_k = m_util.get_k(atom);
int& k = c->m_k;
numeral& k = c->m_k;
arg_t& args = c->m_args;
// extract literals and coefficients.
for (unsigned i = 0; i < num_args; ++i) {
expr* arg = atom->get_arg(i);
literal l = compile_arg(arg);
int c = m_util.get_le_coeff(atom, i);
numeral c = m_util.get_le_coeff(atom, i);
args.push_back(std::make_pair(l, c));
}
// turn W <= k into -W >= -k
@ -89,23 +89,22 @@ namespace smt {
// TBD: special cases: args.size() == 1
// maximal coefficient:
int& max_coeff = c->m_max_coeff;
numeral& max_coeff = c->m_max_coeff;
max_coeff = 0;
for (unsigned i = 0; i < args.size(); ++i) {
max_coeff = std::max(max_coeff, args[i].second);
}
// compute watch literals:
int sum = 0;
unsigned& wsz = c->m_watch_sz;
wsz = 0;
numeral sum = 0;
unsigned wsz = 0;
while (sum < k + max_coeff && wsz < args.size()) {
sum += args[wsz].second;
wsz++;
}
for (unsigned i = 0; i < wsz; ++i) {
add_watch(args[i].first, c);
add_watch(*c, i);
}
// pre-compile threshold for cardinality
@ -168,17 +167,40 @@ namespace smt {
return negate?~literal(bv):literal(bv);
}
void theory_pb::add_watch(literal l, ineq* c) {
unsigned idx = l.index();
ptr_vector<ineq>* ineqs;
if (!m_watch.find(idx, ineqs)) {
ineqs = alloc(ptr_vector<ineq>);
m_watch.insert(idx, ineqs);
void theory_pb::del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index) {
if (index < watch.size()) {
std::swap(watch[index], watch[watch.size()-1]);
}
ineqs->push_back(c);
watch.pop_back();
SASSERT(ineq_index < c.watch_size());
numeral coeff = c.coeff(ineq_index);
if (ineq_index + 1 < c.watch_size()) {
std::swap(c.m_args[ineq_index], c.m_args[c.watch_size()-1]);
}
--c.m_watch_sz;
c.m_max_sum -= coeff;
// current index of unwatched literal is c.watch_size().
}
static unsigned gcd(unsigned a, unsigned b) {
void theory_pb::add_watch(ineq& c, unsigned i) {
bool_var v = c.lit(i).var();
c.m_max_sum += c.coeff(i);
SASSERT(i >= c.watch_size());
if (i > c.watch_size()) {
std::swap(c.m_args[i], c.m_args[c.watch_size()]);
}
++c.m_watch_sz;
ptr_vector<ineq>* ineqs;
if (!m_watch.find(v, ineqs)) {
ineqs = alloc(ptr_vector<ineq>);
m_watch.insert(v, ineqs);
}
ineqs->push_back(&c);
}
theory_pb::numeral theory_pb::gcd(numeral a, numeral b) {
while (a != b) {
if (a == 0) return b;
if (b == 0) return a;
@ -193,7 +215,8 @@ namespace smt {
return a;
}
lbool theory_pb::normalize_ineq(arg_t& args, int& k) {
lbool theory_pb::normalize_ineq(arg_t& args, numeral& k) {
// normalize first all literals to be positive:
// then we can compare them more easily.
@ -204,6 +227,18 @@ namespace smt {
args[i].second = -args[i].second;
}
}
// remove constants
for (unsigned i = 0; i < args.size(); ++i) {
if (args[i].first == true_literal) {
k += args[i].second;
std::swap(args[i], args[args.size()-1]);
args.pop_back();
}
else if (args[i].first == false_literal) {
std::swap(args[i], args[args.size()-1]);
args.pop_back();
}
}
// sort and coalesce arguments:
std::sort(args.begin(), args.end());
for (unsigned i = 0; i + 1 < args.size(); ++i) {
@ -220,7 +255,7 @@ namespace smt {
}
args.resize(args.size()-1);
}
}
}
//
// Ensure all coefficients are positive:
// c*l + y >= k
@ -231,9 +266,9 @@ namespace smt {
// <=>
// -c*~l + y >= k - c
//
unsigned sum = 0;
numeral sum = 0;
for (unsigned i = 0; i < args.size(); ++i) {
int c = args[i].second;
numeral c = args[i].second;
if (c < 0) {
args[i].second = -c;
args[i].first = ~args[i].first;
@ -247,13 +282,13 @@ namespace smt {
return l_true;
}
// detect infeasible constraints:
if (static_cast<int>(sum) < k) {
if (sum < k) {
args.reset();
return l_false;
}
// Ensure the largest coefficient is not larger than k:
for (unsigned i = 0; i < args.size(); ++i) {
int c = args[i].second;
numeral c = args[i].second;
if (c > k) {
args[i].second = k;
}
@ -261,9 +296,9 @@ namespace smt {
SASSERT(!args.empty());
// apply cutting plane reduction:
unsigned g = 0;
numeral g = 0;
for (unsigned i = 0; g != 1 && i < args.size(); ++i) {
int c = args[i].second;
numeral c = args[i].second;
if (c != k) {
g = gcd(g, c);
}
@ -281,12 +316,12 @@ namespace smt {
// Example 5x + 5y + 2z + 2u >= 5
// becomes 3x + 3y + z + u >= 3
//
int k_new = k / g; // k_new is the ceiling of k / g.
if (gcd(k, g) != g) {
numeral k_new = k / g;
if ((k % g) != 0) { // k_new is the ceiling of k / g.
k_new++;
}
for (unsigned i = 0; i < args.size(); ++i) {
int c = args[i].second;
numeral c = args[i].second;
if (c == k) {
c = k_new;
}
@ -324,124 +359,9 @@ namespace smt {
m_ineqs_trail.reset();
m_ineqs_lim.reset();
m_stats.reset();
m_to_compile.reset();
}
#if 0
void theory_pb::propagate_assignment(ineq& c) {
if (c.m_compiled) {
return;
}
if (should_compile(c)) {
compile_ineq(c);
return;
}
context& ctx = get_context();
ast_manager& m = get_manager();
arg_t const& args = c.m_args;
bool_var abv = c.m_bv;
int min = c.m_current_min;
int max = c.m_current_max;
int k = c.m_k;
TRACE("card",
tout << mk_pp(c.m_app, m) << " min: "
<< min << " max: " << max << "\n";);
//
// if min > k && abv != l_false -> force abv false
// if max <= k && abv != l_true -> force abv true
// if min == k && abv == l_true -> force positive
// unassigned literals false
// if max == k + 1 && abv == l_false -> force negative
// unassigned literals false
//
lbool aval = ctx.get_assignment(abv);
if (min > k && aval != l_false) {
literal_vector& lits = get_lits();
int curr_min = accumulate_min(lits, c);
SASSERT(curr_min > k);
add_assign(c, lits, ~literal(abv));
}
else if (max <= k && aval != l_true) {
literal_vector& lits = get_lits();
int curr_max = accumulate_max(lits, c);
SASSERT(curr_max <= k);
add_assign(c, lits, literal(abv));
}
else if (min <= k && k < min + get_max_delta(c) && aval == l_true) {
literal_vector& lits = get_lits();
lits.push_back(~literal(abv));
int curr_min = accumulate_min(lits, c);
if (curr_min > k) {
add_clause(c, lits);
}
else {
for (unsigned i = 0; i < args.size(); ++i) {
bool_var bv = args[i].first;
int inc = args[i].second;
if (curr_min + inc > k && inc_min(inc, ctx.get_assignment(bv)) == l_undef) {
add_assign(c, lits, literal(bv, inc > 0));
}
}
}
}
else if (max - get_max_delta(c) <= k && k < max && aval == l_false) {
literal_vector& lits = get_lits();
lits.push_back(literal(abv));
int curr_max = accumulate_max(lits, c);
if (curr_max <= k) {
add_clause(c, lits);
}
else {
for (unsigned i = 0; i < args.size(); ++i) {
bool_var bv = args[i].first;
int inc = args[i].second;
if (curr_max - abs(inc) <= k && dec_max(inc, ctx.get_assignment(bv)) == l_undef) {
add_assign(c, lits, literal(bv, inc < 0));
}
}
}
}
else if (aval == l_true) {
SASSERT(min < k);
literal_vector& lits = get_lits();
int curr_min = accumulate_min(lits, c);
bool all_inc = curr_min == k;
unsigned num_incs = 0;
for (unsigned i = 0; all_inc && i < args.size(); ++i) {
bool_var bv = args[i].first;
int inc = args[i].second;
if (inc_min(inc, ctx.get_assignment(bv)) == l_undef) {
all_inc = inc + min > k;
num_incs++;
}
}
if (num_incs > 0) {
std::cout << "missed T propgations " << num_incs << "\n";
}
}
else if (aval == l_false) {
literal_vector& lits = get_lits();
lits.push_back(literal(abv));
int curr_max = accumulate_max(lits, c);
bool all_dec = curr_max > k;
unsigned num_decs = 0;
for (unsigned i = 0; all_dec && i < args.size(); ++i) {
bool_var bv = args[i].first;
int inc = args[i].second;
if (dec_max(inc, ctx.get_assignment(bv)) == l_undef) {
all_dec = inc + max <= k;
num_decs++;
}
}
if (num_decs > 0) {
std::cout << "missed F propgations " << num_decs << "\n";
}
}
}
#endif
void theory_pb::assign_eh(bool_var v, bool is_true) {
context& ctx = get_context();
ast_manager& m = get_manager();
@ -455,38 +375,194 @@ namespace smt {
}
}
if (m_ineqs.find(v, c)) {
// TBD: propagate_assignment(*c);
assign_ineq(*c);
}
}
void theory_pb::assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index) {
#if 0
TBD
ineq& c = *watch[i];
c.m_sum;
unsigned w;
for (w = 0; w < c.m_watch_sz; ++i) {
if (c.m_args[w].first.var() == v) {
literal_vector& theory_pb::get_helpful_literals(ineq& c, bool negate) {
numeral sum = 0;
context& ctx = get_context();
literal_vector& lits = get_lits();
for (unsigned i = 0; sum < c.k() && i < c.size(); ++i) {
literal l = c.lit(i);
if (ctx.get_assignment(l) == l_true) {
sum += c.coeff(i);
if (negate) l = ~l;
lits.push_back(l);
}
}
SASSERT(sum >= c.k());
return lits;
}
literal_vector& theory_pb::get_unhelpful_literals(ineq& c, bool negate) {
context& ctx = get_context();
literal_vector& lits = get_lits();
for (unsigned i = 0; i < c.size(); ++i) {
literal l = c.lit(i);
if (ctx.get_assignment(l) == l_false) {
if (negate) l = ~l;
lits.push_back(l);
}
}
return lits;
}
/**
\brief propagate assignment to inequality.
This is a basic, non-optimized implementation based
on the assumption that inequalities are mostly units
and/or relatively few compared to number of argumets.
*/
void theory_pb::assign_ineq(ineq& c) {
context& ctx = get_context();
numeral sum = 0, maxsum = 0;
for (unsigned i = 0; i < c.size(); ++i) {
switch (ctx.get_assignment(c.lit(i))) {
case l_true:
sum += c.coeff(i);
// falll through
case l_undef:
maxsum += c.coeff(i);
break;
default:
break;
}
}
SASSERT(w < c.m_watch_sz);
literal l = c.m_args[w].first;
int coeff = c.m_args[w].second;
if (is_true == !l.sign()) {
ctx.push_trail(value_trail<context, int>(c.m_sum));
c.m_sum += coeff;
// optional propagate
lbool lit_assignment = ctx.get_assignment(c.lit());
SASSERT(lit_assignment != l_undef);
if (sum >= c.k() && lit_assignment == l_false) {
literal_vector& lits = get_helpful_literals(c, true);
lits.push_back(c.lit());
add_clause(c, lits);
}
else if (maxsum < c.k() && lit_assignment == l_true) {
literal_vector& lits = get_unhelpful_literals(c, true);
lits.push_back(~c.lit());
add_clause(c, lits);
}
}
/**
\brief v is assigned in inequality c. Update current bounds and watch list.
Optimize for case where the c.lit() is True. This covers the case where
inequalities are unit literals and formulas in negation normal form
(inequalities are closed under negation).
*/
void theory_pb::assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned watch_index) {
context& ctx = get_context();
ineq& c = *watch[watch_index];
numeral k = c.m_k;
unsigned w = c.find_lit(v, 0, c.watch_size());
numeral coeff = c.coeff(w);
if (is_true == c.lit(w).sign()) {
//
// sum is not increased.
// Adjust set of watched literals.
//
del_watch(watch, watch_index, c, w);
numeral tmp_sum = c.sum();
for (unsigned i = c.watch_size(); c.max_sum() - coeff < k + c.max_coeff() && i < c.size(); ++i) {
lbool lit_assignment = ctx.get_assignment(c.lit(i));
switch(lit_assignment) {
case l_true:
tmp_sum += c.coeff(i);
// fall-through
case l_undef:
add_watch(c, i);
break;
case l_false:
break;
}
}
SASSERT(tmp_sum <= c.max_sum());
if (c.max_sum() < k) {
//
// c.lit() <- false
// we have to add the previously watched literal back.
// such that the sum of watched literals has maximal sum >= k
//
SASSERT(coeff == c.coeff(w));
SASSERT(c.max_sum() + coeff >= k);
add_watch(c, c.find_lit(v, c.watch_size(), c.size()));
SASSERT(c.max_sum() >= k);
switch(ctx.get_assignment(c.lit())) {
case l_false:
break;
case l_true: {
literal_vector& lits = get_unhelpful_literals(c, true);
lits.push_back(~c.lit());
add_clause(c, lits);
break;
}
case l_undef: {
add_assign(c, get_unhelpful_literals(c, false), ~c.lit());
break;
}
}
}
else if (tmp_sum >= k) {
// ineq should be true.
// this is handled below
}
else if (c.max_sum() - c.max_coeff() < k) {
// tmp_sum < k <= c.max_sum()
// opportunities for unit propagation for unassigned
// literals whose coefficients satisfy
// c.max_sum() - coeff < k
if (l_true == ctx.get_assignment(c.lit())) {
literal_vector& lits = get_unhelpful_literals(c, false);
for (unsigned i = 0; i < c.size(); ++i) {
if (c.max_sum() - c.coeff(i) < k && ctx.get_assignment(c.lit(i)) == l_undef) {
add_assign(c, lits, c.lit(i));
}
}
}
}
else {
// tmp_sum < k <= c.max_sum() - c.max_coeff()
// we might miss opportunities for unit propagation if
// max_coeff is not the maximal coefficient
// of the current unassigned literal, but we can
// rely on eventually learning this from propagations.
}
}
else {
unsigned deficit = c.m_max_sum - coeff;
for (unsigned i = c.m_watch_sz; i < c.m_args.size(); ++i) {
if
}
// find a different literal to watch.
ctx.push_trail(value_trail<context, unsigned>(c.m_watch_sz));
// sum is increased the current set of watch
// literals represent a potentially feasible assignment.
//
ctx.push_trail(value_trail<context, numeral>(c.m_sum));
c.m_sum += coeff;
}
#endif
if (c.sum() >= k) {
lbool ineq_assignment = ctx.get_assignment(c.lit());
switch(ineq_assignment) {
case l_true:
break;
case l_undef: {
add_assign(c, get_helpful_literals(c, false), c.lit());
break;
}
case l_false: {
literal_vector& lits = get_helpful_literals(c, true);
lits.push_back(c.lit());
add_clause(c, lits);
break;
}
}
}
// else if c.sum() < k and lit(w) was assigned to true:
// Progress was made.
// The watch list contains at least enough
// literals to force the assignment.
}
struct theory_pb::sort_expr {
@ -526,8 +602,12 @@ namespace smt {
literal internalize(ineq& ca, expr* e) {
obj_map<expr, literal> cache;
for (unsigned i = 0; i < ca.m_args.size(); ++i) {
cache.insert(ca.m_app->get_arg(i), literal(ca.m_args[i].first));
expr_ref_vector trail(m);
for (unsigned i = 0; i < ca.size(); ++i) {
expr_ref tmp(m);
ctx.literal2expr(ca.lit(i), tmp);
cache.insert(tmp, ca.lit(i));
trail.push_back(tmp);
}
cache.insert(m.mk_false(), false_literal);
cache.insert(m.mk_true(), true_literal);
@ -618,49 +698,53 @@ namespace smt {
};
bool theory_pb::should_compile(ineq& c) {
#if 1
return false;
#else
return c.m_num_propagations > c.m_compilation_threshold;
#endif
void theory_pb::inc_propagations(ineq& c) {
++c.m_num_propagations;
if (c.m_compiled == l_false && c.m_num_propagations > c.m_compilation_threshold) {
c.m_compiled = l_undef;
m_to_compile.push_back(&c);
}
}
void theory_pb::restart_eh() {
for (unsigned i = 0; i < m_to_compile.size(); ++i) {
compile_ineq(*m_to_compile[i]);
}
m_to_compile.reset();
}
void theory_pb::compile_ineq(ineq& c) {
++m_stats.m_num_compiles;
ast_manager& m = get_manager();
context& ctx = get_context();
app* a = c.m_app;
SASSERT(m_util.is_at_most_k(a));
literal atmostk;
int k = m_util.get_k(a);
unsigned num_args = a->get_num_args();
// only cardinality constraints are compiled.
SASSERT(c.m_compilation_threshold < UINT_MAX);
DEBUG_CODE(for (unsigned i = 0; i < c.size(); ++i) SASSERT(c.coeff(i) == 1); );
unsigned k = static_cast<unsigned>(c.k());
unsigned num_args = c.size();
SASSERT(0 <= k && k <= num_args);
sort_expr se(*this);
if (k >= static_cast<int>(num_args)) {
atmostk = true_literal;
sorting_network<sort_expr> sn(se);
expr_ref_vector in(m), out(m);
expr_ref tmp(m);
for (unsigned i = 0; i < num_args; ++i) {
ctx.literal2expr(c.lit(i), tmp);
in.push_back(tmp);
}
else if (k < 0) {
atmostk = false_literal;
}
else {
sorting_network<sort_expr> sn(se);
expr_ref_vector in(m), out(m);
for (unsigned i = 0; i < num_args; ++i) {
in.push_back(c.m_app->get_arg(i));
}
sn(in, out);
atmostk = ~se.internalize(c, out[k].get()); // k'th output is 0.
TRACE("card", tout << "~atmost: " << mk_pp(out[k].get(), m) << "\n";);
}
literal thl = c.m_lit;
se.add_clause(~thl, atmostk);
se.add_clause(thl, ~atmostk);
TRACE("card", tout << mk_pp(a, m) << "\n";);
sn(in, out);
literal at_least_k = se.internalize(c, out[k-1].get()); // first k outputs are 1.
TRACE("card", tout << "at_least: " << mk_pp(out[k-1].get(), m) << "\n";);
literal thl = c.lit();
se.add_clause(~thl, at_least_k);
se.add_clause(thl, ~at_least_k);
TRACE("card", tout << mk_pp(c.m_app, m) << "\n";);
// auxiliary clauses get removed when popping scopes.
// we have to recompile the circuit after back-tracking.
ctx.push_trail(value_trail<context, bool>(c.m_compiled));
c.m_compiled = true;
c.m_compiled = l_false;
ctx.push_trail(value_trail<context, lbool>(c.m_compiled));
c.m_compiled = l_true;
}
@ -685,16 +769,16 @@ namespace smt {
std::ostream& theory_pb::display(std::ostream& out, ineq& c) const {
ast_manager& m = get_manager();
out << mk_pp(c.m_app, m) << "\n";
for (unsigned i = 0; i < c.m_args.size(); ++i) {
out << c.m_args[i].second << "*" << c.m_args[i].first;
if (i + 1 < c.m_args.size()) {
for (unsigned i = 0; i < c.size(); ++i) {
out << c.coeff(i) << "*" << c.lit(i);
if (i + 1 < c.size()) {
out << " + ";
}
}
out << " >= " << c.m_k << "\n"
<< "propagations: " << c.m_num_propagations
<< " max_coeff: " << c.m_max_coeff
<< " watch size: " << c.m_watch_sz
<< " max_coeff: " << c.max_coeff()
<< " watch size: " << c.watch_size()
<< "\n";
return out;
}
@ -706,20 +790,18 @@ namespace smt {
}
void theory_pb::add_assign(ineq& c, literal_vector const& lits, literal l) {
literal_vector ls;
++c.m_num_propagations;
inc_propagations(c);
m_stats.m_num_propagations++;
context& ctx = get_context();
for (unsigned i = 0; i < lits.size(); ++i) {
ls.push_back(~lits[i]);
}
ctx.assign(l, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), ls.size(), ls.c_ptr(), l)));
ctx.assign(l, ctx.mk_justification(
theory_propagation_justification(
get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l)));
}
void theory_pb::add_clause(ineq& c, literal_vector const& lits) {
++c.m_num_propagations;
inc_propagations(c);
m_stats.m_num_axioms++;
context& ctx = get_context();
TRACE("card", tout << "#prop:" << c.m_num_propagations << " - "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";);

View file

@ -28,7 +28,8 @@ namespace smt {
class theory_pb : public theory {
struct sort_expr;
typedef svector<std::pair<literal, int> > arg_t;
typedef int64 numeral;
typedef svector<std::pair<literal, numeral> > arg_t;
struct stats {
unsigned m_num_axioms;
@ -44,24 +45,52 @@ namespace smt {
app* m_app;
literal m_lit; // literal repesenting predicate
arg_t m_args; // encode args[0]*coeffs[0]+...+args[n-1]*coeffs[n-1] >= m_k;
int 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:
// sum coeffs[i] >= m_lower + max_coeff
int m_max_coeff; // maximal coefficient.
numeral m_max_coeff; // maximal coefficient.
unsigned m_watch_sz; // number of literals being watched.
numeral m_sum; // sum of coefficients so far.
numeral m_max_sum; // maximal sum of watch literals.
unsigned m_num_propagations;
unsigned m_compilation_threshold;
bool m_compiled;
lbool m_compiled;
ineq(app* a, literal l):
m_app(a),
m_lit(l),
m_lit(l),
m_max_coeff(0),
m_watch_sz(0),
m_sum(0),
m_max_sum(0),
m_num_propagations(0),
m_compilation_threshold(UINT_MAX),
m_compiled(false)
m_compiled(l_false)
{}
literal lit() const { return m_lit; }
numeral const & k() const { return m_k; }
literal lit(unsigned i) const { return m_args[i].first; }
numeral const & coeff(unsigned i) const { return m_args[i].second; }
unsigned size() const { return m_args.size(); }
numeral const& sum() const { return m_sum; }
numeral const& max_sum() const { return m_max_sum; }
numeral const& max_coeff() const { return m_max_coeff; }
unsigned watch_size() const { return m_watch_sz; }
unsigned find_lit(bool_var v, unsigned begin, unsigned end) {
while (lit(begin).var() != v) {
++begin;
SASSERT(begin < end);
}
return begin;
}
};
typedef ptr_vector<ineq> watch_list;
@ -73,12 +102,16 @@ namespace smt {
literal_vector m_literals; // temporary vector
card_util m_util;
stats m_stats;
ptr_vector<ineq> m_to_compile; // inequalities to compile.
// internalize_atom:
lbool normalize_ineq(arg_t& args, int& k);
lbool normalize_ineq(arg_t& args, numeral& k);
static numeral gcd(numeral a, numeral b);
literal compile_arg(expr* arg);
void add_watch(literal l, ineq* c);
void add_watch(ineq& c, unsigned index);
void del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index);
void assign_watch(bool_var v, bool is_true, watch_list& watch, unsigned index);
void assign_ineq(ineq& c);
std::ostream& display(std::ostream& out, ineq& c) const;
@ -86,12 +119,15 @@ namespace smt {
void add_assign(ineq& c, literal_vector const& lits, literal l);
literal_vector& get_lits();
literal_vector& get_helpful_literals(ineq& c, bool negate);
literal_vector& get_unhelpful_literals(ineq& c, bool negate);
//
// Utilities to compile cardinality
// constraints into a sorting network.
//
void compile_ineq(ineq& c);
bool should_compile(ineq& c);
void inc_propagations(ineq& c);
unsigned get_compilation_threshold(ineq& c);
public:
theory_pb(ast_manager& m);
@ -112,7 +148,9 @@ namespace smt {
virtual void init_search_eh();
virtual void push_scope_eh();
virtual void pop_scope_eh(unsigned num_scopes);
virtual void restart_eh();
virtual void collect_statistics(::statistics & st) const;
};
};