3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-09-03 16:48:06 +00:00

preprocess the input of levelwise to drop a level

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
Lev Nachmanson 2025-08-27 13:16:14 -10:00
parent c87e7c312a
commit 98d8083d15
2 changed files with 84 additions and 6 deletions

View file

@ -44,6 +44,7 @@ namespace nlsat {
var m_n;
pmanager& m_pm;
anum_manager& m_am;
polynomial_ref_vector m_generated; // storage for resultants we create
std::vector<property> m_Q; // the set of properties to prove
bool m_fail = false;
// Property precedence relation stored as pairs (lesser, greater)
@ -57,7 +58,7 @@ namespace nlsat {
// max_x plays the role of n in algorith 1 of the levelwise paper.
impl(solver& solver, polynomial_ref_vector const& ps, var max_x, assignment const& s, pmanager& pm, anum_manager& am)
: m_solver(solver), m_P(ps), m_n(max_x), m_pm(pm), m_am(am) {
: m_solver(solver), m_P(ps), m_n(max_x), m_pm(pm), m_am(am), m_generated(m_pm) {
TRACE(levelwise, tout << "m_n:" << m_n << "\n";);
init_property_relation();
}
@ -123,12 +124,89 @@ namespace nlsat {
std::vector<property> seed_properties() {
std::vector<property> Q;
/*
Recall the description of MCSAT in Section 1.2. We are interested in when MCSAT resolves theory
conflicts. I.e. when there is a set of constraints C in real variables x0, . . . , x_{n-1} , x_{n-1}+1 that should be
satisfied according to the Boolean model and an assignment s : {x0, . . . , x_{n-1} } R such that s cannot be
extended to a value for x_{n-1}+1 satisfying C . The task then is to exclude a cell around s that generalizes
this conflict, i.e. a region cell where the reason for unsatisfiability of C is invariant.
This reason of unsatisfiability is maintained when all input polynomials are sign-invariant on the
generalized cell. To achieve this, we could do a full McCallum projection step, obtaining a set of
properties of one level below allowing to construct a cell around s.
However, this is already too strong, as we need the set of input polynomials P = {p | (p 0)
C } : Q[x0, . . . , x_{n-1} , x_n] to be delineable over a cell containing the current sample s Rn for main-
taining the desired property. We achieve this by determining the indexed root expression of the real
roots of the set {p factors(P )| level(p) = n } over s in x_n and ordering them such that ξ1(s)
ξ2(s) . . . ξk (s). Finally, we ensure that all lower level factors {p factors(P )| level(p) < n} are
sign-invariant, check that each polynomial is not nullified (if not, we stop), make each polynomial
individually delineable and add the resultants of the pair of polynomials (ξ j.p, ξ j+1.p) for j [1..k 1].
Thus, the input of the presented one-cell algorithm is given as
Q = {sgn_inv(p) | p factors(P ), level(p) < n }
{an_del(p) | p factors(P ), level(p)= n }
{ord_inv(resxn+1 (ξ j.p, ξ j+1.p)) | j [k 1]}.
*/
// Algorithm 1: initial goals are sgn_inv(p, s) for p in ps at current level of max_x
for (unsigned i = 0; i < m_P.size(); ++i) {
poly* p = m_P.get(i);
Q.push_back(property{ prop_enum::sgn_inv_irreducible, p, /*s_idx*/0, /* level */ m_n - 1});
unsigned level = m_pm.max_var(p);
if (level < m_n)
Q.push_back(property{ prop_enum::sgn_inv_irreducible, p, /*s_idx*/0, /* level */ level});
else if (level == m_n)
Q.push_back(property{ prop_enum::an_del, p, /* s_idx*/ 0, level });
else {
SASSERT(level <= m_n);
}
}
// compute indexed roots for polynomials at level m_n, order them and add ord_inv(resultant) properties ---
// collect polynomials whose main variable is m_n
std::vector<poly*> ps_of_n_level;
for (unsigned i = 0; i < m_P.size(); ++i) {
poly* p = m_P.get(i);
if (m_pm.max_var(p) == m_n)
ps_of_n_level.push_back(p);
}
if (ps_of_n_level.size() >= 2) {
// collect all roots (as algebraic numbers) together with their originating indexed_root_expr
std::vector<std::pair<scoped_anum, indexed_root_expr>> root_vals;
for (auto * p : ps_of_n_level) {
scoped_anum_vector roots(m_am);
m_am.isolate_roots(polynomial_ref(p, m_pm), undef_var_assignment(sample(), m_n), roots);
unsigned num_roots = roots.size();
for (unsigned k = 0; k < num_roots; ++k) {
scoped_anum v(m_am);
m_am.set(v, roots[k]);
root_vals.emplace_back(std::move(v), indexed_root_expr{p, k + 1});
}
}
// order roots by their algebraic value (ascending)
if (root_vals.size() >= 2) {
std::sort(root_vals.begin(), root_vals.end(), [&](auto const & a, auto const & b){
return m_am.lt(a.first, b.first);
});
// add resultants of adjacent roots
for (size_t j = 0; j + 1 < root_vals.size(); ++j) {
poly* p1 = root_vals[j].second.p;
poly* p2 = root_vals[j+1].second.p;
polynomial_ref r(m_pm);
r =resultant(polynomial_ref(p1, m_pm), polynomial_ref(p2, m_pm), m_n);
if (is_const(r)) continue;
if (is_zero(r) ) {
NOT_IMPLEMENTED_YET(); // not sure how to process
}
// keep the resultant alive in m_generated
m_generated.push_back(r.get());
poly* rp = m_generated.get(m_generated.size() - 1);
unsigned lvl = m_pm.max_var(rp);
Q.push_back(property{ prop_enum::ord_inv_irreducible, rp, /*s_idx*/ 0u, lvl });
}
}
}
// ---------------------------------------------------------------------------------
return Q;
}
@ -447,7 +525,7 @@ namespace nlsat {
tout << "m_P:\n";
for (const auto & p: m_P) {
::nlsat::display(tout, m_solver, polynomial_ref(p, m_pm)) << std::endl;
tout << "max0_var:" << m_pm.max_var(p) << std::endl;
tout << "max_var:" << m_pm.max_var(p) << std::endl;
}
);
std::vector<symbolic_interval> ret;

View file

@ -1220,8 +1220,8 @@ namespace nlsat {
// Remark: after vanishing coefficients are eliminated, ps may not contain max_x anymore
polynomial_ref_vector samples(m_pm);
// levelwise lws(m_solver, ps, max_x, sample(), m_pm, m_am);
//auto cell = lws.single_cell();
levelwise lws(m_solver, ps, max_x, sample(), m_pm, m_am);
auto cell = lws.single_cell();
if (x < max_x)
cac_add_cell_lits(ps, x, samples);