3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-23 22:33:40 +00:00

enable reduce_by, more tests

This commit is contained in:
Nikolaj Bjorner 2021-09-19 13:41:39 -04:00
parent 58c66ffee8
commit c69c316b27
7 changed files with 142 additions and 36 deletions

View file

@ -962,7 +962,6 @@ namespace dd {
quot_rem(a1, b1, q, r); quot_rem(a1, b1, q, r);
if (r.is_zero()) { if (r.is_zero()) {
std::cout << a1 << " " << b1 << " " << q << "\n";
SASSERT(q * b1 == a1); SASSERT(q * b1 == a1);
a1 = -q * pow(mk_var(v), l - m) * b2; a1 = -q * pow(mk_var(v), l - m) * b2;
if (l > m) if (l > m)

View file

@ -104,7 +104,7 @@ namespace polysat {
// if clause is unsat then assign arbitrary // if clause is unsat then assign arbitrary
// solver handles unsat clauses by creating a conflict. // solver handles unsat clauses by creating a conflict.
// solver also can propagate, but need to check that it does indeed. // solver also can propagate, but need to check that it does indeed.
void constraint_manager::watch(clause& cl, solver& s) { void constraint_manager::watch(clause& cl, solver& s) {
if (cl.size() <= 1) if (cl.size() <= 1)
return; return;
bool first = true; bool first = true;

View file

@ -93,7 +93,7 @@ namespace polysat {
} }
void ex_polynomial_superposition::reduce_by(pvar v, conflict_core& core) { void ex_polynomial_superposition::reduce_by(pvar v, conflict_core& core) {
return; //return;
bool progress = true; bool progress = true;
while (progress) { while (progress) {
progress = false; progress = false;
@ -111,6 +111,10 @@ namespace polysat {
for (auto c : core) { for (auto c : core) {
if (c == eq) if (c == eq)
continue; continue;
if (is_positive_equality_over(v, c))
continue;
if (!c.is_currently_false(s()))
continue;
if (c->is_ule()) { if (c->is_ule()) {
auto lhs = c->to_ule().lhs(); auto lhs = c->to_ule().lhs();
auto rhs = c->to_ule().rhs(); auto rhs = c->to_ule().rhs();
@ -121,10 +125,11 @@ namespace polysat {
auto c2 = s().ule(a, b); auto c2 = s().ule(a, b);
if (!c.is_positive()) if (!c.is_positive())
c2 = ~c2; c2 = ~c2;
vector<signed_constraint> premises; SASSERT(c2.is_currently_false(s()));
premises.push_back(eq); if (!c2->has_bvar() || l_undef == c2.bvalue(s()))
premises.push_back(c); core.keep(c2); // adds propagation of c to the search stack
core.replace(c, c2, premises); core.reset();
core.set(c2);
return true; return true;
} }
} }

View file

@ -16,19 +16,29 @@ Author:
namespace polysat { namespace polysat {
std::ostream& search_item::display(std::ostream& out) const { std::ostream& search_state::display(search_item const& item, std::ostream& out) const {
switch (kind()) { switch (item.kind()) {
case search_item_k::assignment: case search_item_k::assignment:
return out << "v" << var() << "=?"; return out << "v" << item.var() << " := " << value(item.var());
case search_item_k::boolean: case search_item_k::boolean:
return out << lit(); return out << item.lit();
} }
UNREACHABLE(); UNREACHABLE();
return out; return out;
} }
std::ostream& search_state::display(std::ostream& out) const { std::ostream& search_state::display(std::ostream& out) const {
return out << m_items; for (auto const& item : m_items)
display(item, out) << " ";
return out;
}
rational search_state::value(pvar v) const {
for (auto const& [p, r] : m_assignment)
if (v == p)
return r;
UNREACHABLE();
return rational::zero();
} }
void search_state::push_assignment(pvar p, rational const& r) { void search_state::push_assignment(pvar p, rational const& r) {
@ -42,9 +52,8 @@ namespace polysat {
void search_state::pop() { void search_state::pop() {
auto const& item = m_items.back(); auto const& item = m_items.back();
if (item.is_assignment()) { if (item.is_assignment())
m_assignment.pop_back(); m_assignment.pop_back();
}
m_items.pop_back(); m_items.pop_back();
} }

View file

@ -42,17 +42,15 @@ namespace polysat {
bool is_boolean() const { return m_kind == search_item_k::boolean; } bool is_boolean() const { return m_kind == search_item_k::boolean; }
search_item_k kind() const { return m_kind; } search_item_k kind() const { return m_kind; }
pvar var() const { SASSERT(is_assignment()); return m_var; } pvar var() const { SASSERT(is_assignment()); return m_var; }
sat::literal lit() const { SASSERT(is_boolean()); return m_lit; } sat::literal lit() const { SASSERT(is_boolean()); return m_lit; }
std::ostream& display(std::ostream& out) const;
}; };
inline std::ostream& operator<<(std::ostream& out, search_item const& s) { return s.display(out); }
class search_state { class search_state {
vector<search_item> m_items; vector<search_item> m_items;
assignment_t m_assignment; // First-order part of the search state assignment_t m_assignment; // First-order part of the search state
rational value(pvar v) const;
public: public:
unsigned size() const { return m_items.size(); } unsigned size() const { return m_items.size(); }
@ -70,10 +68,19 @@ namespace polysat {
const_iterator end() const { return m_items.end(); } const_iterator end() const { return m_items.end(); }
std::ostream& display(std::ostream& out) const; std::ostream& display(std::ostream& out) const;
std::ostream& display(search_item const& item, std::ostream& out) const;
};
struct search_item_pp {
search_state const& s;
search_item const& i;
search_item_pp(search_state const& s, search_item const& i) : s(s), i(i) {}
}; };
inline std::ostream& operator<<(std::ostream& out, search_state const& s) { return s.display(out); } inline std::ostream& operator<<(std::ostream& out, search_state const& s) { return s.display(out); }
inline std::ostream& operator<<(std::ostream& out, search_item_pp const& p) { return p.s.display(p.i, out); }
// Go backwards over the search_state. // Go backwards over the search_state.
// If new entries are added during processing an item, they will be queued for processing next after the current item. // If new entries are added during processing an item, they will be queued for processing next after the current item.

View file

@ -339,7 +339,6 @@ namespace polysat {
} }
} }
void solver::add_watch(signed_constraint c) { void solver::add_watch(signed_constraint c) {
SASSERT(c); SASSERT(c);
auto const& vars = c->vars(); auto const& vars = c->vars();
@ -468,7 +467,7 @@ namespace polysat {
LOG("search state: " << m_search); LOG("search state: " << m_search);
LOG("Conflict: " << m_conflict); LOG("Conflict: " << m_conflict);
auto const& item = *search_it; auto const& item = *search_it;
LOG_H2("Working on " << item); LOG_H2("Working on " << search_item_pp(m_search, item));
if (item.is_assignment()) { if (item.is_assignment()) {
// Resolve over variable assignment // Resolve over variable assignment
pvar v = item.var(); pvar v = item.var();
@ -543,7 +542,7 @@ namespace polysat {
void solver::learn_lemma(pvar v, clause& lemma) { void solver::learn_lemma(pvar v, clause& lemma) {
LOG("Learning: "<< lemma); LOG("Learning: "<< lemma);
SASSERT(lemma.size() > 0); SASSERT(!lemma.empty());
lemma.set_justified_var(v); lemma.set_justified_var(v);
add_lemma(lemma); add_lemma(lemma);
decide_bool(lemma); decide_bool(lemma);
@ -624,7 +623,7 @@ namespace polysat {
void solver::revert_bool_decision(sat::literal lit) { void solver::revert_bool_decision(sat::literal lit) {
sat::bool_var const var = lit.var(); sat::bool_var const var = lit.var();
LOG_H3("Reverting boolean decision: " << lit); LOG_H3("Reverting boolean decision: " << lit << " " << m_conflict);
SASSERT(m_bvars.is_decision(var)); SASSERT(m_bvars.is_decision(var));
// Current situation: we have a decision for boolean literal L on top of the stack, and a conflict core. // Current situation: we have a decision for boolean literal L on top of the stack, and a conflict core.
@ -663,6 +662,8 @@ namespace polysat {
} }
clause_ref reason = reason_builder.build(); clause_ref reason = reason_builder.build();
std::cout << "reason " << *reason << "\n";
// The lemma where 'lit' comes from. // The lemma where 'lit' comes from.
// Currently, boolean decisions always come from guessing a literal of a learned non-unit lemma. // Currently, boolean decisions always come from guessing a literal of a learned non-unit lemma.
clause* lemma = m_bvars.lemma(var); // need to grab this while 'lit' is still assigned clause* lemma = m_bvars.lemma(var); // need to grab this while 'lit' is still assigned
@ -748,7 +749,6 @@ namespace polysat {
LOG("Lemma: " << lemma); LOG("Lemma: " << lemma);
for (sat::literal lit : lemma) { for (sat::literal lit : lemma) {
LOG(" Literal " << lit << " is: " << lit2cnstr(lit)); LOG(" Literal " << lit << " is: " << lit2cnstr(lit));
SASSERT(!lit2cnstr(lit).is_currently_true(*this));
SASSERT(m_bvars.value(lit) != l_true); SASSERT(m_bvars.value(lit) != l_true);
} }
SASSERT(!lemma.empty()); SASSERT(!lemma.empty());

View file

@ -534,16 +534,20 @@ namespace polysat {
// we prove quot3 <= a and quot3 + em >= a // we prove quot3 <= a and quot3 + em >= a
s.push(); s.push();
s.add_ult(a, quot3); s.add_ult(quot3 + em, a);
s.check(); s.check();
s.expect_unsat(); // s.expect_unsat();
s.pop(); s.pop();
s.push(); s.push();
s.add_ult(quot3 + em, a); s.add_ult(a, quot3);
s.check(); s.check();
s.expect_unsat(); // s.expect_unsat();
s.pop(); s.pop();
//exit(0);
} }
/** Monotonicity under bounds, /** Monotonicity under bounds,
@ -718,6 +722,90 @@ namespace polysat {
s.expect_unsat(); s.expect_unsat();
} }
// xy < xz and !Omega(x*y) => y < z
static void test_ineq_axiom1(unsigned bw = 32) {
auto const bound = rational::power_of_two(bw-1);
{
scoped_solver s(__func__);
auto x = s.var(s.add_var(bw));
auto y = s.var(s.add_var(bw));
auto z = s.var(s.add_var(bw));
s.add_ult(x * y, x * z);
s.add_ule(z, y);
s.add_ult(x, bound);
s.add_ult(y, bound);
s.check();
s.expect_unsat();
}
{
scoped_solver s(__func__);
auto y = s.var(s.add_var(bw));
auto x = s.var(s.add_var(bw));
auto z = s.var(s.add_var(bw));
s.add_ult(x * y, x * z);
s.add_ule(z, y);
s.add_ult(x, bound);
s.add_ult(y, bound);
s.check();
s.expect_unsat();
}
for (unsigned i = 0; i < 3; ++i) {
for (unsigned j = 0; j < 2; ++j) {
scoped_solver s(__func__);
auto a = s.var(s.add_var(bw));
auto b = s.var(s.add_var(bw));
auto c = s.var(s.add_var(bw));
auto x = a, y = b, z = c;
if (i == 1)
std::swap(x, y);
else if (i == 2)
std::swap(x, z);
if (j == 1)
std::swap(y, z);
s.add_ult(x * y, x * z);
s.add_ule(z, y);
s.add_ult(x, bound);
s.add_ult(y, bound);
s.check();
s.expect_unsat();
}
}
}
// xy <= xz & !Omega(x*y) => y <= z or x = 0
static void test_ineq_axiom2(unsigned bw = 32) {
auto const bound = rational::power_of_two(bw - 1);
for (unsigned i = 0; i < 3; ++i) {
for (unsigned j = 0; j < 2; ++j) {
scoped_solver s(__func__);
auto a = s.var(s.add_var(bw));
auto b = s.var(s.add_var(bw));
auto c = s.var(s.add_var(bw));
auto x = a, y = b, z = c;
if (i == 1)
std::swap(x, y);
else if (i == 2)
std::swap(x, z);
if (j == 1)
std::swap(y, z);
s.add_ult(x * y, x * z);
s.add_ult(z, y);
s.add_ult(x, bound);
s.add_ult(y, bound);
s.add_diseq(x);
s.check();
s.expect_unsat();
}
}
}
// xy < b & a <= x & !Omega(x*y) => a*y < b
// xy <= b & a <= x & !Omega(x*y) => a*y <= b
// a < xy & x <= b & !Omega(x*y) => a < b*y
// a <= xy & x <= b & !omega(x*y) => a <= b*y
// Goal: we probably mix up polysat variables and PDD variables at several points; try to uncover such cases // Goal: we probably mix up polysat variables and PDD variables at several points; try to uncover such cases
// NOTE: actually, add_var seems to keep them in sync, so this is not an issue at the moment (but we should still test it later) // NOTE: actually, add_var seems to keep them in sync, so this is not an issue at the moment (but we should still test it later)
@ -843,12 +931,9 @@ namespace polysat {
void tst_polysat() { void tst_polysat() {
polysat::test_p3(); polysat::test_ineq_axiom1();
return;
polysat::test_l2();
// polysat::test_subst();
// return;
// not working // not working
// polysat::test_fixed_point_arith_div_mul_inverse(); // polysat::test_fixed_point_arith_div_mul_inverse();
@ -864,12 +949,13 @@ void tst_polysat() {
polysat::test_add_conflicts(); polysat::test_add_conflicts();
polysat::test_wlist(); polysat::test_wlist();
polysat::test_l1(); polysat::test_l1();
polysat::test_l2();
polysat::test_l3(); polysat::test_l3();
polysat::test_l4(); polysat::test_l4();
polysat::test_l5(); polysat::test_l5();
polysat::test_p1(); polysat::test_p1();
polysat::test_p2(); polysat::test_p2();
polysat::test_p3();
polysat::test_ineq_basic1(); polysat::test_ineq_basic1();
polysat::test_ineq_basic2(); polysat::test_ineq_basic2();
@ -879,7 +965,7 @@ void tst_polysat() {
polysat::test_ineq_basic6(); polysat::test_ineq_basic6();
polysat::test_monot_bounds(2); polysat::test_monot_bounds(2);
polysat::test_cjust(); polysat::test_cjust();
polysat::test_subst();
// inefficient conflicts: // inefficient conflicts:
// Takes time: polysat::test_monot_bounds_full(); // Takes time: polysat::test_monot_bounds_full();