3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-25 01:55:32 +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);
if (r.is_zero()) {
std::cout << a1 << " " << b1 << " " << q << "\n";
SASSERT(q * b1 == a1);
a1 = -q * pow(mk_var(v), l - m) * b2;
if (l > m)

View file

@ -104,7 +104,7 @@ namespace polysat {
// if clause is unsat then assign arbitrary
// solver handles unsat clauses by creating a conflict.
// 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)
return;
bool first = true;

View file

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

View file

@ -16,19 +16,29 @@ Author:
namespace polysat {
std::ostream& search_item::display(std::ostream& out) const {
switch (kind()) {
std::ostream& search_state::display(search_item const& item, std::ostream& out) const {
switch (item.kind()) {
case search_item_k::assignment:
return out << "v" << var() << "=?";
return out << "v" << item.var() << " := " << value(item.var());
case search_item_k::boolean:
return out << lit();
return out << item.lit();
}
UNREACHABLE();
return out;
}
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) {
@ -42,9 +52,8 @@ namespace polysat {
void search_state::pop() {
auto const& item = m_items.back();
if (item.is_assignment()) {
m_assignment.pop_back();
}
if (item.is_assignment())
m_assignment.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; }
search_item_k kind() const { return m_kind; }
pvar var() const { SASSERT(is_assignment()); return m_var; }
sat::literal lit() const { SASSERT(is_boolean()); return m_lit; }
std::ostream& display(std::ostream& out) const;
sat::literal lit() const { SASSERT(is_boolean()); return m_lit; }
};
inline std::ostream& operator<<(std::ostream& out, search_item const& s) { return s.display(out); }
class search_state {
vector<search_item> m_items;
assignment_t m_assignment; // First-order part of the search state
rational value(pvar v) const;
public:
unsigned size() const { return m_items.size(); }
@ -70,10 +68,19 @@ namespace polysat {
const_iterator end() const { return m_items.end(); }
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_item_pp const& p) { return p.s.display(p.i, out); }
// 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.

View file

@ -339,7 +339,6 @@ namespace polysat {
}
}
void solver::add_watch(signed_constraint c) {
SASSERT(c);
auto const& vars = c->vars();
@ -468,7 +467,7 @@ namespace polysat {
LOG("search state: " << m_search);
LOG("Conflict: " << m_conflict);
auto const& item = *search_it;
LOG_H2("Working on " << item);
LOG_H2("Working on " << search_item_pp(m_search, item));
if (item.is_assignment()) {
// Resolve over variable assignment
pvar v = item.var();
@ -543,7 +542,7 @@ namespace polysat {
void solver::learn_lemma(pvar v, clause& lemma) {
LOG("Learning: "<< lemma);
SASSERT(lemma.size() > 0);
SASSERT(!lemma.empty());
lemma.set_justified_var(v);
add_lemma(lemma);
decide_bool(lemma);
@ -624,7 +623,7 @@ namespace polysat {
void solver::revert_bool_decision(sat::literal lit) {
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));
// 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();
std::cout << "reason " << *reason << "\n";
// The lemma where 'lit' comes from.
// 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
@ -748,7 +749,6 @@ namespace polysat {
LOG("Lemma: " << lemma);
for (sat::literal lit : lemma) {
LOG(" Literal " << lit << " is: " << lit2cnstr(lit));
SASSERT(!lit2cnstr(lit).is_currently_true(*this));
SASSERT(m_bvars.value(lit) != l_true);
}
SASSERT(!lemma.empty());

View file

@ -534,16 +534,20 @@ namespace polysat {
// we prove quot3 <= a and quot3 + em >= a
s.push();
s.add_ult(a, quot3);
s.add_ult(quot3 + em, a);
s.check();
s.expect_unsat();
// s.expect_unsat();
s.pop();
s.push();
s.add_ult(quot3 + em, a);
s.add_ult(a, quot3);
s.check();
s.expect_unsat();
// s.expect_unsat();
s.pop();
//exit(0);
}
/** Monotonicity under bounds,
@ -718,6 +722,90 @@ namespace polysat {
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
// 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() {
polysat::test_p3();
polysat::test_ineq_axiom1();
return;
polysat::test_l2();
// polysat::test_subst();
// return;
// not working
// polysat::test_fixed_point_arith_div_mul_inverse();
@ -864,12 +949,13 @@ void tst_polysat() {
polysat::test_add_conflicts();
polysat::test_wlist();
polysat::test_l1();
polysat::test_l2();
polysat::test_l3();
polysat::test_l4();
polysat::test_l5();
polysat::test_p1();
polysat::test_p2();
polysat::test_p3();
polysat::test_ineq_basic1();
polysat::test_ineq_basic2();
@ -879,7 +965,7 @@ void tst_polysat() {
polysat::test_ineq_basic6();
polysat::test_monot_bounds(2);
polysat::test_cjust();
polysat::test_subst();
// inefficient conflicts:
// Takes time: polysat::test_monot_bounds_full();