mirror of
https://github.com/Z3Prover/z3
synced 2025-11-25 15:09:32 +00:00
revamp stellensatz to use polynomals
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
21b36868b5
commit
c7084e9998
4 changed files with 397 additions and 542 deletions
|
|
@ -1908,6 +1908,36 @@ namespace dd {
|
||||||
return m->mk_var(var())*h + l;
|
return m->mk_var(var())*h + l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pdd::merge(unsigned_vector& lo, unsigned_vector& hi, unsigned_vector& common) {
|
||||||
|
std::sort(lo.begin(), lo.end());
|
||||||
|
std::sort(hi.begin(), hi.end());
|
||||||
|
unsigned ir = 0, jr = 0;
|
||||||
|
for (unsigned i = 0, j = 0; i < lo.size() || j < hi.size(); ) {
|
||||||
|
if (i == lo.size())
|
||||||
|
hi[jr++] = hi[j++];
|
||||||
|
else if (j == hi.size())
|
||||||
|
lo[ir++] = lo[i++];
|
||||||
|
else if (lo[i] == hi[j]) {
|
||||||
|
common.push_back(lo[i]);
|
||||||
|
++i;
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
else if (lo[i] > hi[j])
|
||||||
|
hi[jr++] = hi[j++];
|
||||||
|
else
|
||||||
|
lo[ir++] = lo[i++];
|
||||||
|
}
|
||||||
|
lo.shrink(ir);
|
||||||
|
hi.shrink(jr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdd pdd::mul(unsigned_vector const& vars) const {
|
||||||
|
pdd r = *this;
|
||||||
|
for (auto v : vars)
|
||||||
|
r = m->mk_var(v) * r;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<unsigned_vector, pdd> pdd::var_factors() const {
|
std::pair<unsigned_vector, pdd> pdd::var_factors() const {
|
||||||
if (is_val())
|
if (is_val())
|
||||||
return { unsigned_vector(), *this };
|
return { unsigned_vector(), *this };
|
||||||
|
|
@ -1924,49 +1954,23 @@ namespace dd {
|
||||||
return { unsigned_vector(), *this };
|
return { unsigned_vector(), *this };
|
||||||
|
|
||||||
unsigned_vector lo_and_hi;
|
unsigned_vector lo_and_hi;
|
||||||
auto merge = [&](unsigned_vector& lo_vars, unsigned_vector& hi_vars) {
|
|
||||||
unsigned ir = 0, jr = 0;
|
|
||||||
for (unsigned i = 0, j = 0; i < lo_vars.size() || j < hi_vars.size(); ) {
|
|
||||||
if (i == lo_vars.size())
|
|
||||||
hi_vars[jr++] = hi_vars[j++];
|
|
||||||
else if (j == hi_vars.size())
|
|
||||||
lo_vars[ir++] = lo_vars[i++];
|
|
||||||
else if (lo_vars[i] == hi_vars[j]) {
|
|
||||||
lo_and_hi.push_back(lo_vars[i]);
|
|
||||||
++i;
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
else if (m->m_var2level[lo_vars[i]] > m->m_var2level[hi_vars[j]])
|
|
||||||
hi_vars[jr++] = hi_vars[j++];
|
|
||||||
else
|
|
||||||
lo_vars[ir++] = lo_vars[i++];
|
|
||||||
}
|
|
||||||
lo_vars.shrink(ir);
|
|
||||||
hi_vars.shrink(jr);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto mul = [&](unsigned_vector const& vars, pdd p) {
|
|
||||||
for (auto v : vars)
|
|
||||||
p *= m->mk_var(v);
|
|
||||||
return p;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto [hi_vars, p] = hi().var_factors();
|
auto [hi_vars, p] = hi().var_factors();
|
||||||
if (lo_vars.back() == v) {
|
if (lo_vars.back() == v) {
|
||||||
lo_vars.pop_back();
|
lo_vars.pop_back();
|
||||||
merge(lo_vars, hi_vars);
|
merge(lo_vars, hi_vars, lo_and_hi);
|
||||||
lo_and_hi.push_back(v);
|
lo_and_hi.push_back(v);
|
||||||
return { lo_and_hi, mul(lo_vars, q) + mul(hi_vars, p) };
|
return { lo_and_hi, q.mul(lo_vars) + p.mul(hi_vars) };
|
||||||
}
|
}
|
||||||
if (hi_vars.empty())
|
if (hi_vars.empty())
|
||||||
return { unsigned_vector(), *this };
|
return { unsigned_vector(), *this };
|
||||||
|
|
||||||
merge(lo_vars, hi_vars);
|
merge(lo_vars, hi_vars, lo_and_hi);
|
||||||
hi_vars.push_back(v);
|
hi_vars.push_back(v);
|
||||||
if (lo_and_hi.empty())
|
if (lo_and_hi.empty())
|
||||||
return { unsigned_vector(), *this };
|
return { unsigned_vector(), *this };
|
||||||
else
|
else
|
||||||
return { lo_and_hi, mul(lo_vars, q) + mul(hi_vars, p) };
|
return { lo_and_hi, q.mul(lo_vars) + p.mul(hi_vars) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -483,6 +483,8 @@ namespace dd {
|
||||||
* \brief factor out variables
|
* \brief factor out variables
|
||||||
*/
|
*/
|
||||||
std::pair<unsigned_vector, pdd> var_factors() const;
|
std::pair<unsigned_vector, pdd> var_factors() const;
|
||||||
|
static void merge(unsigned_vector &lo, unsigned_vector &hi, unsigned_vector& common);
|
||||||
|
pdd mul(unsigned_vector const &vars) const;
|
||||||
|
|
||||||
pdd subst_val0(vector<std::pair<unsigned, rational>> const& s) const { return m->subst_val0(*this, s); }
|
pdd subst_val0(vector<std::pair<unsigned, rational>> const& s) const { return m->subst_val0(*this, s); }
|
||||||
pdd subst_val(pdd const& s) const { VERIFY_EQ(m, s.m); return m->subst_val(*this, s); }
|
pdd subst_val(pdd const& s) const { VERIFY_EQ(m, s.m); return m->subst_val(*this, s); }
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -5,9 +5,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "util/scoped_ptr_vector.h"
|
#include "util/scoped_ptr_vector.h"
|
||||||
|
#include "math/dd/dd_pdd.h"
|
||||||
#include "math/lp/nla_coi.h"
|
#include "math/lp/nla_coi.h"
|
||||||
#include "math/lp/int_solver.h"
|
#include "math/lp/int_solver.h"
|
||||||
#include "math/polynomial/polynomial.h"
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
namespace nla {
|
namespace nla {
|
||||||
|
|
@ -26,7 +26,6 @@ namespace nla {
|
||||||
lbool solve_lia();
|
lbool solve_lia();
|
||||||
bool update_values();
|
bool update_values();
|
||||||
vector<std::pair<lpvar, rational>> m_to_refine;
|
vector<std::pair<lpvar, rational>> m_to_refine;
|
||||||
void saturate_basic_linearize();
|
|
||||||
public:
|
public:
|
||||||
solver(stellensatz &s) : s(s) {};
|
solver(stellensatz &s) : s(s) {};
|
||||||
void init();
|
void init();
|
||||||
|
|
@ -39,12 +38,11 @@ namespace nla {
|
||||||
|
|
||||||
solver m_solver;
|
solver m_solver;
|
||||||
|
|
||||||
// factor t into coeff*x^degree*p + q, such that degree(x, q) < degree,
|
|
||||||
|
// factor t into x^degree*p + q, such that degree(x, q) < degree,
|
||||||
struct factorization {
|
struct factorization {
|
||||||
rational coeff;
|
|
||||||
unsigned degree;
|
unsigned degree;
|
||||||
lp::lar_term p;
|
dd::pdd p, q;
|
||||||
lp::lar_term q;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct external_justification {
|
struct external_justification {
|
||||||
|
|
@ -60,6 +58,10 @@ namespace nla {
|
||||||
lp::constraint_index ci;
|
lp::constraint_index ci;
|
||||||
rational mul;
|
rational mul;
|
||||||
};
|
};
|
||||||
|
struct multiplication_var_justification {
|
||||||
|
lp::constraint_index ci;
|
||||||
|
lpvar v;
|
||||||
|
};
|
||||||
struct multiplication_justification {
|
struct multiplication_justification {
|
||||||
lp::constraint_index left, right;
|
lp::constraint_index left, right;
|
||||||
};
|
};
|
||||||
|
|
@ -73,16 +75,32 @@ namespace nla {
|
||||||
gcd_justification,
|
gcd_justification,
|
||||||
addition_justification,
|
addition_justification,
|
||||||
multiplication_const_justification,
|
multiplication_const_justification,
|
||||||
|
multiplication_var_justification,
|
||||||
multiplication_justification
|
multiplication_justification
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
using term_offset = std::pair<lp::lar_term, rational>;
|
||||||
|
|
||||||
|
struct constraint {
|
||||||
|
dd::pdd p;
|
||||||
|
lp::lconstraint_kind k;
|
||||||
|
justification j;
|
||||||
|
};
|
||||||
|
|
||||||
coi m_coi;
|
coi m_coi;
|
||||||
scoped_ptr_vector<justification> m_justifications;
|
dd::pdd_manager pddm;
|
||||||
void add_justification(lp::constraint_index ci, justification const &j) {
|
vector<constraint> m_constraints;
|
||||||
VERIFY(ci == m_justifications.size());
|
|
||||||
m_justifications.push_back(alloc(justification, j));
|
|
||||||
}
|
dd::pdd to_pdd(lpvar v);
|
||||||
vector<rational> m_values;
|
lpvar mk_monomial(svector<lpvar> const &vars);
|
||||||
|
void init_monomial(unsigned mon_var);
|
||||||
|
term_offset to_term_offset(dd::pdd const &p);
|
||||||
|
|
||||||
|
lp::constraint_index add_constraint(dd::pdd p, lp::lconstraint_kind k, justification j);
|
||||||
|
|
||||||
|
lp::constraint_index add_var_bound(lp::lpvar v, lp::lconstraint_kind k, rational const &rhs, justification j);
|
||||||
|
|
||||||
struct eq {
|
struct eq {
|
||||||
bool operator()(unsigned_vector const& a, unsigned_vector const& b) const {
|
bool operator()(unsigned_vector const& a, unsigned_vector const& b) const {
|
||||||
return a == b;
|
return a == b;
|
||||||
|
|
@ -92,55 +110,30 @@ namespace nla {
|
||||||
u_map<unsigned_vector> m_mon2vars;
|
u_map<unsigned_vector> m_mon2vars;
|
||||||
bool is_mon_var(lpvar v) const { return m_mon2vars.contains(v); }
|
bool is_mon_var(lpvar v) const { return m_mon2vars.contains(v); }
|
||||||
|
|
||||||
unsigned m_max_monomial_degree = 0;
|
|
||||||
|
|
||||||
vector<svector<lp::constraint_index>> m_occurs; // map from variable to constraints they occur.
|
vector<svector<lp::constraint_index>> m_occurs; // map from variable to constraints they occur.
|
||||||
|
|
||||||
bool is_new_inequality(vector<std::pair<rational, lpvar>> lhs, lp::lconstraint_kind k, rational const &rhs);
|
|
||||||
|
|
||||||
|
|
||||||
// initialization
|
// initialization
|
||||||
void init_solver();
|
void init_solver();
|
||||||
void init_vars();
|
void init_vars();
|
||||||
void init_monomial(unsigned mon_var);
|
|
||||||
void init_occurs();
|
void init_occurs();
|
||||||
void init_occurs(lp::constraint_index ci);
|
void init_occurs(lp::constraint_index ci);
|
||||||
|
|
||||||
void eliminate_variables();
|
void eliminate_variables();
|
||||||
lp::lpvar select_variable_to_eliminate(lp::constraint_index ci);
|
lp::lpvar select_variable_to_eliminate(lp::constraint_index ci);
|
||||||
unsigned degree_of_var_in_constraint(lpvar v, lp::constraint_index ci) const;
|
unsigned degree_of_var_in_constraint(lpvar v, lp::constraint_index ci) const;
|
||||||
unsigned degree_of_var_in_monomial(lpvar v, lpvar mi) const;
|
factorization factor(lpvar v, lp::constraint_index ci);
|
||||||
factorization factor(lpvar v, lp::constraint_index ci);
|
|
||||||
lp::lpvar divide(lpvar v, unsigned degree, lpvar mi);
|
|
||||||
|
|
||||||
bool constraint_is_true(lp::constraint_index ci) const;
|
bool constraint_is_true(lp::constraint_index ci) const;
|
||||||
|
|
||||||
// additional variables and monomials and constraints
|
lp::constraint_index gcd_normalize(lp::constraint_index ci);
|
||||||
using term_offset = std::pair<lp::lar_term, rational>; // term and its offset
|
lp::constraint_index assume(dd::pdd const& p, lp::lconstraint_kind k);
|
||||||
|
|
||||||
svector<lp::lpvar> expand_monomial(svector<lp::lpvar> const & vars);
|
|
||||||
lpvar mk_monomial(svector<lp::lpvar> const& vars);
|
|
||||||
lpvar mk_monomial(svector<lp::lpvar> const &vars, lp::lpvar j);
|
|
||||||
lpvar mk_term(term_offset &t);
|
|
||||||
|
|
||||||
void gcd_normalize(vector<std::pair<rational, lpvar>> &t, lp::lconstraint_kind k, rational &rhs);
|
|
||||||
lp::constraint_index add_ineq(justification const& just, lp::lar_term &t, lp::lconstraint_kind k, rational const &rhs);
|
|
||||||
|
|
||||||
lp::constraint_index add_ineq(justification const &just, lpvar j, lp::lconstraint_kind k,
|
|
||||||
rational const &rhs);
|
|
||||||
|
|
||||||
lp::constraint_index assume(lp::lar_term &t, lp::lconstraint_kind k, rational const &rhs);
|
|
||||||
lp::constraint_index normalize_ineq(lp::constraint_index ci);
|
|
||||||
lp::constraint_index add(lp::constraint_index left, lp::constraint_index right);
|
lp::constraint_index add(lp::constraint_index left, lp::constraint_index right);
|
||||||
lp::constraint_index multiply(lp::constraint_index ci, rational const &mul);
|
lp::constraint_index multiply(lp::constraint_index ci, rational const &mul);
|
||||||
lp::constraint_index multiply(lp::constraint_index left, lp::constraint_index right);
|
lp::constraint_index multiply(lp::constraint_index left, lp::constraint_index right);
|
||||||
lp::constraint_index multiply_var(lp::constraint_index ci, lpvar x);
|
lp::constraint_index multiply_var(lp::constraint_index ci, lpvar x);
|
||||||
|
|
||||||
bool is_int(svector<lp::lpvar> const& vars) const;
|
bool is_int(svector<lp::lpvar> const& vars) const;
|
||||||
rational cvalue(lp::lar_term const &t) const;
|
rational cvalue(dd::pdd const& p) const;
|
||||||
rational mvalue(lp::lar_term const &t) const;
|
|
||||||
rational cvalue(svector<lpvar> const &prod) const;
|
|
||||||
rational mvalue(svector<lpvar> const &prod) const;
|
|
||||||
lpvar add_var(bool is_int);
|
lpvar add_var(bool is_int);
|
||||||
|
|
||||||
// lemmas
|
// lemmas
|
||||||
|
|
@ -162,12 +155,11 @@ namespace nla {
|
||||||
std::ostream& display(std::ostream& out) const;
|
std::ostream& display(std::ostream& out) const;
|
||||||
std::ostream& display_product(std::ostream& out, svector<lpvar> const& vars) const;
|
std::ostream& display_product(std::ostream& out, svector<lpvar> const& vars) const;
|
||||||
std::ostream& display_constraint(std::ostream& out, lp::constraint_index ci) const;
|
std::ostream& display_constraint(std::ostream& out, lp::constraint_index ci) const;
|
||||||
std::ostream& display_constraint(std::ostream& out, lp::lar_term const& lhs,
|
std::ostream& display_constraint(std::ostream& out, constraint const& c) const;
|
||||||
lp::lconstraint_kind k, rational const& rhs) const;
|
std::ostream &display(std::ostream &out, justification const &j) const;
|
||||||
std::ostream& display(std::ostream &out, term_offset const &t) const;
|
|
||||||
std::ostream& display(std::ostream &out, justification const &bounds) const;
|
|
||||||
std::ostream &display_var(std::ostream &out, lpvar j) const;
|
std::ostream &display_var(std::ostream &out, lpvar j) const;
|
||||||
std::ostream &display_lemma(std::ostream &out, lp::explanation const &ex, vector<ineq> const &ineqs);
|
std::ostream &display_lemma(std::ostream &out, lp::explanation const &ex, vector<ineq> const &ineqs);
|
||||||
|
std::ostream &display(std::ostream &out, term_offset const &t) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
stellensatz(core* core);
|
stellensatz(core* core);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue