3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-17 08:42:15 +00:00

univariate::find_max

This commit is contained in:
Jakob Rath 2022-12-15 15:59:15 +01:00
parent 31e0add966
commit 8a5f1af3d1
3 changed files with 117 additions and 19 deletions

View file

@ -35,6 +35,7 @@ namespace polysat {
unsigned bit_width; unsigned bit_width;
func_decl_ref x_decl; func_decl_ref x_decl;
expr_ref x; expr_ref x;
vector<rational> model_cache;
public: public:
univariate_bitblast_solver(solver_factory& mk_solver, unsigned bit_width) : univariate_bitblast_solver(solver_factory& mk_solver, unsigned bit_width) :
@ -48,15 +49,30 @@ namespace polysat {
s = mk_solver(m, p, false, true, true, symbol::null); s = mk_solver(m, p, false, true, true, symbol::null);
x_decl = m.mk_const_decl("x", bv->mk_sort(bit_width)); x_decl = m.mk_const_decl("x", bv->mk_sort(bit_width));
x = m.mk_const(x_decl); x = m.mk_const(x_decl);
model_cache.push_back(rational(-1));
} }
~univariate_bitblast_solver() override = default; ~univariate_bitblast_solver() override = default;
void reset_cache() {
model_cache.back() = -1;
}
void push_cache() {
model_cache.push_back(model_cache.back());
}
void pop_cache() {
model_cache.pop_back();
}
void push() override { void push() override {
push_cache();
s->push(); s->push();
} }
void pop(unsigned n) override { void pop(unsigned n) override {
pop_cache();
s->pop(n); s->pop(n);
} }
@ -114,6 +130,7 @@ namespace polysat {
#endif #endif
void add(expr* e, bool sign, dep_t dep) { void add(expr* e, bool sign, dep_t dep) {
reset_cache();
if (sign) if (sign)
e = m.mk_not(e); e = m.mk_not(e);
expr* a = m.mk_const(m.mk_const_decl(symbol(dep), m.mk_bool_sort())); expr* a = m.mk_const(m.mk_const_decl(symbol(dep), m.mk_bool_sort()));
@ -194,6 +211,8 @@ namespace polysat {
} }
rational model() override { rational model() override {
rational& cached_model = model_cache.back();
if (cached_model.is_neg()) {
model_ref model; model_ref model;
s->get_model(model); s->get_model(model);
SASSERT(model); SASSERT(model);
@ -202,7 +221,9 @@ namespace polysat {
SASSERT(val->get_num_parameters() == 2); SASSERT(val->get_num_parameters() == 2);
auto const& p = val->get_parameter(0); auto const& p = val->get_parameter(0);
SASSERT(p.is_rational()); SASSERT(p.is_rational());
return p.get_rational(); cached_model = p.get_rational();
}
return cached_model;
} }
bool find_min(rational& val) override { bool find_min(rational& val) override {
@ -214,6 +235,7 @@ namespace polysat {
add_bit0(k, 0); add_bit0(k, 0);
continue; continue;
} }
// try decreasing k-th bit
push(); push();
add_bit0(k, 0); add_bit0(k, 0);
lbool result = check(); lbool result = check();
@ -233,6 +255,35 @@ namespace polysat {
return true; return true;
} }
bool find_max(rational& val) override {
val = model();
push();
// try increasing val by setting bits to 1, starting at the msb.
for (unsigned k = bit_width; k-- > 0; ) {
if (val.get_bit(k)) {
add_bit1(k, 0);
continue;
}
// try increasing k-th bit
push();
add_bit1(k, 0);
lbool result = check();
if (result == l_true) {
SASSERT(model() > val);
val = model();
}
pop(1);
if (result == l_true)
add_bit1(k, 0);
else if (result == l_false)
add_bit0(k, 0);
else
return false;
}
pop(1);
return true;
}
std::ostream& display(std::ostream& out) const override { std::ostream& display(std::ostream& out) const override {
return out << *s; return out << *s;
} }

View file

@ -42,16 +42,32 @@ namespace polysat {
virtual lbool check() = 0; virtual lbool check() = 0;
// Precondition: check() returned l_false /**
* Precondition: check() returned l_false
*/
virtual dep_vector unsat_core() = 0; virtual dep_vector unsat_core() = 0;
// Precondition: check() returned l_true /**
* Precondition: check() returned l_true
*/
virtual rational model() = 0; virtual rational model() = 0;
// Precondition: check() returned l_true /**
// Returns false on resource out. * Find minimal model.
*
* Precondition: check() returned l_true
* Returns: true on success, false on resource out.
*/
virtual bool find_min(rational& out_min) = 0; virtual bool find_min(rational& out_min) = 0;
/**
* Find maximal model.
*
* Precondition: check() returned l_true
* Returns: true on success, false on resource out.
*/
virtual bool find_max(rational& out_max) = 0;
virtual void add_ule(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0; virtual void add_ule(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0;
virtual void add_umul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0; virtual void add_umul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0;
virtual void add_smul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0; virtual void add_smul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0;

View file

@ -183,7 +183,7 @@ namespace polysat {
std::cout << "core: " << solver->unsat_core() << "\n"; std::cout << "core: " << solver->unsat_core() << "\n";
} }
static void test_univariate_min() { static void test_univariate_minmax() {
std::cout << "\ntest_univariate_min\n"; std::cout << "\ntest_univariate_min\n";
unsigned const bw = 32; unsigned const bw = 32;
auto factory = mk_univariate_bitblast_factory(); auto factory = mk_univariate_bitblast_factory();
@ -192,6 +192,7 @@ namespace polysat {
vector<rational> lhs; vector<rational> lhs;
vector<rational> rhs; vector<rational> rhs;
rational min; rational min;
rational max;
solver->push(); solver->push();
@ -204,10 +205,18 @@ namespace polysat {
solver->add_ule(lhs, rhs, false, 0); solver->add_ule(lhs, rhs, false, 0);
std::cout << "status: " << solver->check() << "\n"; std::cout << "status: " << solver->check() << "\n";
std::cout << "model: " << solver->model() << "\n"; std::cout << "model: " << solver->model() << "\n";
VERIFY(solver->find_min(min)); VERIFY(solver->find_min(min));
std::cout << "find_min: " << min << "\n"; std::cout << "find_min: " << min << "\n";
VERIFY(min == 57); // 57*2 + 10 = 124; 56*2 + 10 = 122 VERIFY(min == 57); // 57*2 + 10 = 124; 56*2 + 10 = 122
VERIFY(solver->find_max(max));
std::cout << "find_max: " << max << "\n";
solver->push();
solver->add_ugt_const(max, false, 5);
VERIFY(solver->check() == l_false);
solver->pop(1);
solver->push(); solver->push();
// c1: 127 <= x // c1: 127 <= x
@ -219,10 +228,16 @@ namespace polysat {
solver->add_ule(lhs, rhs, false, 1); solver->add_ule(lhs, rhs, false, 1);
std::cout << "status: " << solver->check() << "\n"; std::cout << "status: " << solver->check() << "\n";
std::cout << "model: " << solver->model() << "\n"; std::cout << "model: " << solver->model() << "\n";
VERIFY(solver->find_min(min)); VERIFY(solver->find_min(min));
std::cout << "find_min: " << min << "\n"; std::cout << "find_min: " << min << "\n";
VERIFY(min == 127); VERIFY(min == 127);
VERIFY(solver->find_max(max));
std::cout << "find_max: " << max << "\n";
solver->add_ugt_const(max, false, 5);
VERIFY(solver->check() == l_false);
solver->pop(1); solver->pop(1);
// c2: umul_ovfl(2, x) // c2: umul_ovfl(2, x)
@ -234,25 +249,41 @@ namespace polysat {
solver->add_umul_ovfl(lhs, rhs, false, 2); solver->add_umul_ovfl(lhs, rhs, false, 2);
std::cout << "status: " << solver->check() << "\n"; std::cout << "status: " << solver->check() << "\n";
std::cout << "model: " << solver->model() << "\n"; std::cout << "model: " << solver->model() << "\n";
VERIFY(solver->find_min(min)); VERIFY(solver->find_min(min));
std::cout << "find_min: " << min << "\n"; std::cout << "find_min: " << min << "\n";
solver->add_ule_const(min - 1, false, 3); solver->push();
solver->add_ult_const(min, false, 5);
VERIFY(solver->check() == l_false);
solver->pop(1);
VERIFY(solver->find_max(max));
std::cout << "find_max: " << max << "\n";
solver->add_ugt_const(max, false, 5);
VERIFY(solver->check() == l_false); VERIFY(solver->check() == l_false);
solver->pop(1); solver->pop(1);
// c4: umul_ovfl(2, x) // c3: umul_ovfl(2, x)
lhs.clear(); lhs.clear();
lhs.push_back(rational(2)); lhs.push_back(rational(2));
rhs.clear(); rhs.clear();
rhs.push_back(rational(0)); rhs.push_back(rational(0));
rhs.push_back(rational(1)); rhs.push_back(rational(1));
solver->add_umul_ovfl(lhs, rhs, false, 4); solver->add_umul_ovfl(lhs, rhs, false, 3);
std::cout << "status: " << solver->check() << "\n"; std::cout << "status: " << solver->check() << "\n";
std::cout << "model: " << solver->model() << "\n"; std::cout << "model: " << solver->model() << "\n";
VERIFY(solver->find_min(min)); VERIFY(solver->find_min(min));
std::cout << "find_min: " << min << "\n"; std::cout << "find_min: " << min << "\n";
solver->add_ule_const(min - 1, false, 5); solver->push();
solver->add_ult_const(min, false, 5);
VERIFY(solver->check() == l_false);
solver->pop(1);
VERIFY(solver->find_max(max));
std::cout << "find_max: " << max << "\n";
solver->add_ugt_const(max, false, 5);
VERIFY(solver->check() == l_false); VERIFY(solver->check() == l_false);
} }
@ -263,6 +294,6 @@ namespace polysat {
void tst_viable() { void tst_viable() {
polysat::test1(); polysat::test1();
polysat::test_univariate(); polysat::test_univariate();
polysat::test_univariate_min(); polysat::test_univariate_minmax();
polysat::test2(); // takes long polysat::test2(); // takes long
} }