mirror of
https://github.com/Z3Prover/z3
synced 2025-06-23 14:23:40 +00:00
univariate solver seems to work
This commit is contained in:
parent
1de51da67e
commit
c4370eb7e6
4 changed files with 143 additions and 34 deletions
|
@ -20,26 +20,32 @@ Author:
|
||||||
#include "sat/sat_solver/inc_sat_solver.h"
|
#include "sat/sat_solver/inc_sat_solver.h"
|
||||||
#include "solver/solver.h"
|
#include "solver/solver.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
#include "ast/ast.h"
|
||||||
|
#include "ast/reg_decl_plugins.h"
|
||||||
|
#include "ast/ast_smt2_pp.h"
|
||||||
|
|
||||||
|
|
||||||
namespace polysat {
|
namespace polysat {
|
||||||
|
|
||||||
class univariate_bitblast_solver : public univariate_solver {
|
class univariate_bitblast_solver : public univariate_solver {
|
||||||
|
// TODO: does it make sense to share m and bv between different solver instances?
|
||||||
ast_manager m;
|
ast_manager m;
|
||||||
bv_util bv;
|
scoped_ptr<bv_util> bv;
|
||||||
scoped_ptr<solver> s;
|
scoped_ptr<solver> s;
|
||||||
unsigned bit_width;
|
unsigned bit_width;
|
||||||
func_decl* x_decl;
|
func_decl* x_decl;
|
||||||
|
expr* x;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
univariate_bitblast_solver(solver_factory& mk_solver, unsigned bit_width) :
|
univariate_bitblast_solver(solver_factory& mk_solver, unsigned bit_width) :
|
||||||
bv(m),
|
|
||||||
bit_width(bit_width)
|
bit_width(bit_width)
|
||||||
{
|
{
|
||||||
|
// m.register_plugin(symbol("bv"), alloc(bv_decl_plugin)); // this alone doesn't work
|
||||||
|
reg_decl_plugins(m);
|
||||||
|
bv = alloc(bv_util, m);
|
||||||
s = mk_solver(m, params_ref::get_empty(), false, true, true, symbol::null);
|
s = mk_solver(m, params_ref::get_empty(), false, true, true, symbol::null);
|
||||||
// auto s = bv.mk_sort(bit_width);
|
x_decl = m.mk_const_decl("x", bv->mk_sort(bit_width));
|
||||||
// auto n = bv.mk_numeral(rational(123), bit_width);
|
x = m.mk_const(x_decl);
|
||||||
x_decl = m.mk_const_decl("x", bv.mk_sort(bit_width));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~univariate_bitblast_solver() override = default;
|
~univariate_bitblast_solver() override = default;
|
||||||
|
@ -52,57 +58,80 @@ namespace polysat {
|
||||||
s->pop(n);
|
s->pop(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
expr* mk_poly(univariate p) {
|
expr* mk_numeral(rational const& r) const {
|
||||||
NOT_IMPLEMENTED_YET();
|
return bv->mk_numeral(r, bit_width);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_ule(univariate lhs, univariate rhs, bool sign, dep_t dep) override {
|
// [d,c,b,a] ==> ((a*x + b)*x + c)*x + d
|
||||||
expr* e = bv.mk_ule(mk_poly(lhs), mk_poly(rhs));
|
expr* mk_poly(univariate const& p) const {
|
||||||
|
if (p.empty()) {
|
||||||
|
return mk_numeral(rational::zero());
|
||||||
|
} else {
|
||||||
|
expr* e = mk_numeral(p.back());
|
||||||
|
for (unsigned i = p.size() - 1; i-- > 0; ) {
|
||||||
|
e = bv->mk_bv_mul(e, x);
|
||||||
|
if (!p[i].is_zero())
|
||||||
|
e = bv->mk_bv_add(e, mk_numeral(p[i]));
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(expr* e, bool sign, dep_t dep) {
|
||||||
if (sign)
|
if (sign)
|
||||||
e = m.mk_not(e);
|
e = m.mk_not(e);
|
||||||
// TODO: record dep, and pass second argument to assert_expr (for tracking in the unsat core)
|
expr* a = m.mk_const(m.mk_const_decl(symbol(dep), m.mk_bool_sort()));
|
||||||
s->assert_expr(e);
|
s->assert_expr(e, a);
|
||||||
|
// std::cout << "add: " << expr_ref(e, m) << " <== " << expr_ref(a, m) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_umul_ovfl(univariate lhs, univariate rhs, bool sign, dep_t dep) override {
|
void add_ule(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override {
|
||||||
NOT_IMPLEMENTED_YET();
|
add(bv->mk_ule(mk_poly(lhs), mk_poly(rhs)), sign, dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_smul_ovfl(univariate lhs, univariate rhs, bool sign, dep_t dep) override {
|
void add_umul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override {
|
||||||
NOT_IMPLEMENTED_YET();
|
add(bv->mk_bvumul_no_ovfl(mk_poly(lhs), mk_poly(rhs)), !sign, dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_smul_udfl(univariate lhs, univariate rhs, bool sign, dep_t dep) override {
|
void add_smul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override {
|
||||||
NOT_IMPLEMENTED_YET();
|
add(bv->mk_bvsmul_no_ovfl(mk_poly(lhs), mk_poly(rhs)), !sign, dep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_smul_udfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override {
|
||||||
|
add(bv->mk_bvsmul_no_udfl(mk_poly(lhs), mk_poly(rhs)), !sign, dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool check() override {
|
lbool check() override {
|
||||||
// TODO: need to pass assumptions to get an unsat core?
|
|
||||||
return s->check_sat();
|
return s->check_sat();
|
||||||
}
|
}
|
||||||
|
|
||||||
dep_vector unsat_core() override {
|
dep_vector unsat_core() override {
|
||||||
SASSERT(s->status() == l_false);
|
dep_vector deps;
|
||||||
expr_ref_vector core(m);
|
expr_ref_vector core(m);
|
||||||
s->get_unsat_core(core);
|
s->get_unsat_core(core);
|
||||||
NOT_IMPLEMENTED_YET();
|
for (expr* a : core) {
|
||||||
return {};
|
unsigned dep = to_app(a)->get_decl()->get_name().get_num();
|
||||||
|
deps.push_back(dep);
|
||||||
|
}
|
||||||
|
SASSERT(deps.size() > 0);
|
||||||
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
rational model() override {
|
rational model() override {
|
||||||
SASSERT(s->status() == l_true);
|
|
||||||
model_ref model;
|
model_ref model;
|
||||||
s->get_model(model);
|
s->get_model(model);
|
||||||
expr* val_expr = model->get_const_interp(x_decl);
|
SASSERT(model);
|
||||||
SASSERT(val_expr->get_kind() == AST_APP);
|
app* val = to_app(model->get_const_interp(x_decl));
|
||||||
app* val = static_cast<app*>(val_expr);
|
SASSERT(val->get_decl_kind() == OP_BV_NUM);
|
||||||
SASSERT(val->get_kind() == OP_BV_NUM);
|
|
||||||
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();
|
return p.get_rational();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& display(std::ostream& out) const override {
|
||||||
|
return out << *s;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class univariate_bitblast_factory : public univariate_solver_factory {
|
class univariate_bitblast_factory : public univariate_solver_factory {
|
||||||
|
|
|
@ -17,6 +17,7 @@ Author:
|
||||||
--*/
|
--*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
#include "util/lbool.h"
|
#include "util/lbool.h"
|
||||||
#include "util/rational.h"
|
#include "util/rational.h"
|
||||||
#include "util/vector.h"
|
#include "util/vector.h"
|
||||||
|
@ -29,6 +30,9 @@ namespace polysat {
|
||||||
public:
|
public:
|
||||||
using dep_t = unsigned;
|
using dep_t = unsigned;
|
||||||
using dep_vector = svector<dep_t>;
|
using dep_vector = svector<dep_t>;
|
||||||
|
|
||||||
|
/// Coefficients of univariate polynomial, index == degree,
|
||||||
|
/// e.g., the vector [ c, b, a ] represents a*x^2 + b*x + c.
|
||||||
using univariate = vector<rational>;
|
using univariate = vector<rational>;
|
||||||
|
|
||||||
virtual ~univariate_solver() = default;
|
virtual ~univariate_solver() = default;
|
||||||
|
@ -40,13 +44,19 @@ namespace polysat {
|
||||||
virtual dep_vector unsat_core() = 0;
|
virtual dep_vector unsat_core() = 0;
|
||||||
virtual rational model() = 0;
|
virtual rational model() = 0;
|
||||||
|
|
||||||
virtual void add_ule(univariate lhs, univariate 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 lhs, univariate 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 lhs, univariate 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_udfl(univariate lhs, univariate rhs, bool sign, dep_t dep) = 0;
|
virtual void add_smul_udfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0;
|
||||||
// op constraints?
|
// op constraints?
|
||||||
|
|
||||||
|
virtual std::ostream& display(std::ostream& out) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, univariate_solver& s) {
|
||||||
|
return s.display(out);
|
||||||
|
}
|
||||||
|
|
||||||
class univariate_solver_factory {
|
class univariate_solver_factory {
|
||||||
public:
|
public:
|
||||||
virtual ~univariate_solver_factory() = default;
|
virtual ~univariate_solver_factory() = default;
|
||||||
|
|
|
@ -3,7 +3,7 @@ add_subdirectory(lp)
|
||||||
################################################################################
|
################################################################################
|
||||||
# z3-test executable
|
# z3-test executable
|
||||||
################################################################################
|
################################################################################
|
||||||
set(z3_test_deps api fuzzing simplex polysat)
|
set(z3_test_deps api fuzzing simplex polysat polysat_univariate_solver)
|
||||||
z3_expand_dependencies(z3_test_expanded_deps ${z3_test_deps})
|
z3_expand_dependencies(z3_test_expanded_deps ${z3_test_deps})
|
||||||
set (z3_test_extra_object_files "")
|
set (z3_test_extra_object_files "")
|
||||||
foreach (component ${z3_test_expanded_deps})
|
foreach (component ${z3_test_expanded_deps})
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "math/polysat/log.h"
|
#include "math/polysat/log.h"
|
||||||
#include "math/polysat/solver.h"
|
#include "math/polysat/solver.h"
|
||||||
#include "math/polysat/viable.h"
|
#include "math/polysat/viable.h"
|
||||||
|
#include "math/polysat/univariate/univariate_solver.h"
|
||||||
|
|
||||||
namespace polysat {
|
namespace polysat {
|
||||||
|
|
||||||
|
@ -113,11 +114,80 @@ namespace polysat {
|
||||||
vector<std::pair<unsigned, unsigned>> intervals;
|
vector<std::pair<unsigned, unsigned>> intervals;
|
||||||
test_intervals(3, intervals);
|
test_intervals(3, intervals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_univariate() {
|
||||||
|
std::cout << "\ntest_univariate\n";
|
||||||
|
unsigned bw = 32;
|
||||||
|
rational modulus = rational::power_of_two(bw);
|
||||||
|
auto factory = mk_univariate_bitblast_factory();
|
||||||
|
auto solver = (*factory)(bw);
|
||||||
|
|
||||||
|
vector<rational> lhs;
|
||||||
|
vector<rational> rhs;
|
||||||
|
|
||||||
|
// c0: 2x+10 <= 123
|
||||||
|
lhs.clear();
|
||||||
|
lhs.push_back(rational(10));
|
||||||
|
lhs.push_back(rational(2));
|
||||||
|
rhs.clear();
|
||||||
|
rhs.push_back(rational(123));
|
||||||
|
solver->add_ule(lhs, rhs, false, 0);
|
||||||
|
std::cout << "status: " << solver->check() << "\n";
|
||||||
|
std::cout << "model: " << solver->model() << "\n";
|
||||||
|
|
||||||
|
solver->push();
|
||||||
|
|
||||||
|
// c1: x*x == 16
|
||||||
|
lhs.clear();
|
||||||
|
lhs.push_back(modulus - 16);
|
||||||
|
lhs.push_back(rational(0));
|
||||||
|
lhs.push_back(rational(1));
|
||||||
|
rhs.clear();
|
||||||
|
solver->add_ule(lhs, rhs, false, 1);
|
||||||
|
std::cout << "status: " << solver->check() << "\n";
|
||||||
|
std::cout << "model: " << solver->model() << "\n";
|
||||||
|
|
||||||
|
solver->push();
|
||||||
|
|
||||||
|
// c2: x <= 1000
|
||||||
|
lhs.clear();
|
||||||
|
lhs.push_back(rational(0));
|
||||||
|
lhs.push_back(rational(1));
|
||||||
|
rhs.clear();
|
||||||
|
rhs.push_back(rational(1000));
|
||||||
|
solver->add_ule(lhs, rhs, false, 2);
|
||||||
|
// std::cout << *solver << '\n';
|
||||||
|
std::cout << "status: " << solver->check() << "\n";
|
||||||
|
std::cout << "model: " << solver->model() << "\n";
|
||||||
|
|
||||||
|
solver->pop(2);
|
||||||
|
|
||||||
|
// c3: umul_ovfl(2, x)
|
||||||
|
lhs.clear();
|
||||||
|
lhs.push_back(rational(2));
|
||||||
|
rhs.clear();
|
||||||
|
rhs.push_back(rational(0));
|
||||||
|
rhs.push_back(rational(1));
|
||||||
|
solver->add_umul_ovfl(lhs, rhs, false, 3);
|
||||||
|
std::cout << "status: " << solver->check() << "\n";
|
||||||
|
std::cout << "model: " << solver->model() << "\n";
|
||||||
|
|
||||||
|
// c4: 1000 > x
|
||||||
|
lhs.clear();
|
||||||
|
lhs.push_back(rational(1000));
|
||||||
|
rhs.clear();
|
||||||
|
rhs.push_back(rational(0));
|
||||||
|
rhs.push_back(rational(1));
|
||||||
|
solver->add_ule(lhs, rhs, true, 4);
|
||||||
|
std::cout << "status: " << solver->check() << "\n";
|
||||||
|
std::cout << "core: " << solver->unsat_core() << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void tst_viable() {
|
void tst_viable() {
|
||||||
polysat::test1();
|
polysat::test1();
|
||||||
polysat::test2();
|
// polysat::test2();
|
||||||
}
|
polysat::test_univariate();
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue