3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-06-09 02:20:57 +00:00

fix nlsat.cpp and enable control over what added in handle_nullified_poly

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
Lev Nachmanson 2026-02-18 12:02:56 -10:00
parent 799fc9e8c4
commit d1461de8a7
4 changed files with 50 additions and 30 deletions

View file

@ -55,6 +55,8 @@ namespace nlsat {
unsigned m_level = 0; // current level being processed unsigned m_level = 0; // current level being processed
unsigned m_spanning_tree_threshold = 3; // minimum both-side count for spanning tree unsigned m_spanning_tree_threshold = 3; // minimum both-side count for spanning tree
bool m_null_coeffs = true;
bool m_null_derivs = true;
unsigned m_l_rf = UINT_MAX; // position of lower bound in m_rel.m_rfunc unsigned m_l_rf = UINT_MAX; // position of lower bound in m_rel.m_rfunc
unsigned m_u_rf = UINT_MAX; // position of upper bound in m_rel.m_rfunc, UINT_MAX in section case unsigned m_u_rf = UINT_MAX; // position of upper bound in m_rel.m_rfunc, UINT_MAX in section case
@ -260,6 +262,8 @@ namespace nlsat {
m_I.emplace_back(m_pm); m_I.emplace_back(m_pm);
m_spanning_tree_threshold = m_solver.lws_spt_threshold(); m_spanning_tree_threshold = m_solver.lws_spt_threshold();
m_null_coeffs = m_solver.lws_null_coeffs();
m_null_derivs = m_solver.lws_null_derivs();
} }
// Handle a polynomial whose every coefficient evaluates to zero at the sample. // Handle a polynomial whose every coefficient evaluates to zero at the sample.
@ -268,43 +272,47 @@ namespace nlsat {
// When a non-vanishing derivative is found, request_factorized it and stop. // When a non-vanishing derivative is found, request_factorized it and stop.
void handle_nullified_poly(polynomial_ref const& p) { void handle_nullified_poly(polynomial_ref const& p) {
// Add all coefficients of p (w.r.t. m_level) to m_todo. // Add all coefficients of p (w.r.t. m_level) to m_todo.
unsigned deg = m_pm.degree(p, m_level); if (m_null_coeffs) {
for (unsigned j = 0; j <= deg; ++j) { unsigned deg = m_pm.degree(p, m_level);
polynomial_ref coeff(m_pm.coeff(p, m_level, j), m_pm); for (unsigned j = 0; j <= deg; ++j) {
if (!coeff || is_zero(coeff) || is_const(coeff)) polynomial_ref coeff(m_pm.coeff(p, m_level, j), m_pm);
continue; if (!coeff || is_zero(coeff) || is_const(coeff))
request_factorized(coeff); continue;
request_factorized(coeff);
}
} }
// Compute partial derivatives level by level. If all derivatives at a level vanish, // Compute partial derivatives level by level. If all derivatives at a level vanish,
// request_factorized each of them and continue to the next level. // request_factorized each of them and continue to the next level.
// When a non-vanishing derivative is found, request_factorized it and stop. // When a non-vanishing derivative is found, request_factorized it and stop.
polynomial_ref_vector current(m_pm); if (m_null_derivs) {
current.push_back(p); polynomial_ref_vector current(m_pm);
while (!current.empty()) { current.push_back(p);
polynomial_ref_vector next_derivs(m_pm); while (!current.empty()) {
for (unsigned i = 0; i < current.size(); ++i) { polynomial_ref_vector next_derivs(m_pm);
polynomial_ref q(current.get(i), m_pm); for (unsigned i = 0; i < current.size(); ++i) {
unsigned mv = m_pm.max_var(q); polynomial_ref q(current.get(i), m_pm);
if (mv == null_var) unsigned mv = m_pm.max_var(q);
continue; if (mv == null_var)
for (unsigned x = 0; x <= mv; ++x) {
if (m_pm.degree(q, x) == 0)
continue; continue;
polynomial_ref dq = derivative(q, x); for (unsigned x = 0; x <= mv; ++x) {
if (!dq || is_zero(dq) || is_const(dq)) if (m_pm.degree(q, x) == 0)
continue; continue;
if (m_am.eval_sign_at(dq, sample()) != 0) { polynomial_ref dq = derivative(q, x);
request_factorized(dq); if (!dq || is_zero(dq) || is_const(dq))
return; continue;
if (m_am.eval_sign_at(dq, sample()) != 0) {
request_factorized(dq);
return;
}
next_derivs.push_back(dq);
} }
next_derivs.push_back(dq);
} }
for (unsigned i = 0; i < next_derivs.size(); ++i) {
polynomial_ref dq(next_derivs.get(i), m_pm);
request_factorized(dq);
}
current = std::move(next_derivs);
} }
for (unsigned i = 0; i < next_derivs.size(); ++i) {
polynomial_ref dq(next_derivs.get(i), m_pm);
request_factorized(dq);
}
current = std::move(next_derivs);
} }
} }
@ -1225,7 +1233,7 @@ namespace nlsat {
polynomial_ref w = choose_nonzero_coeff(p, m_level); polynomial_ref w = choose_nonzero_coeff(p, m_level);
if (!w) if (!w)
handle_nullified_poly(p); handle_nullified_poly(p);
m_witnesses.push_back(w); m_witnesses.push_back(w); // need to push anyway since m_witnesses is accessed by the index
// Absorb any same-level polys that handle_nullified_poly added to m_todo // Absorb any same-level polys that handle_nullified_poly added to m_todo
if (i + 1 == m_level_ps.size()) if (i + 1 == m_level_ps.size())
m_todo.extract_polys_at_level(m_level, m_level_ps); m_todo.extract_polys_at_level(m_level, m_level_ps);

View file

@ -24,5 +24,7 @@ def_module_params('nlsat',
('known_sat_assignment_file_name', STRING, "", "the file name of a known solution: used for debugging only"), ('known_sat_assignment_file_name', STRING, "", "the file name of a known solution: used for debugging only"),
('lws', BOOL, True, "apply levelwise."), ('lws', BOOL, True, "apply levelwise."),
('lws_spt_threshold', UINT, 2, "minimum both-side polynomial count to apply spanning tree optimization; < 2 disables spanning tree"), ('lws_spt_threshold', UINT, 2, "minimum both-side polynomial count to apply spanning tree optimization; < 2 disables spanning tree"),
('lws_null_coeffs', BOOL, True, "add coefficients of nullified polynomials during projection."),
('lws_null_derivs', BOOL, True, "add derivatives of nullified polynomials during projection."),
('canonicalize', BOOL, True, "canonicalize polynomials.") ('canonicalize', BOOL, True, "canonicalize polynomials.")
)) ))

View file

@ -251,6 +251,8 @@ namespace nlsat {
bool m_apply_lws; bool m_apply_lws;
bool m_last_conflict_used_lws = false; // Track if last conflict explanation used levelwise bool m_last_conflict_used_lws = false; // Track if last conflict explanation used levelwise
unsigned m_lws_spt_threshold = 3; unsigned m_lws_spt_threshold = 3;
bool m_lws_null_coeffs = true;
bool m_lws_null_derivs = true;
imp(solver& s, ctx& c): imp(solver& s, ctx& c):
m_ctx(c), m_ctx(c),
m_solver(s), m_solver(s),
@ -312,6 +314,8 @@ namespace nlsat {
m_debug_known_solution_file_name = p.known_sat_assignment_file_name(); m_debug_known_solution_file_name = p.known_sat_assignment_file_name();
m_apply_lws = p.lws(); m_apply_lws = p.lws();
m_lws_spt_threshold = p.lws_spt_threshold(); // 0 disables spanning tree m_lws_spt_threshold = p.lws_spt_threshold(); // 0 disables spanning tree
m_lws_null_coeffs = p.lws_null_coeffs();
m_lws_null_derivs = p.lws_null_derivs();
m_check_lemmas |= !(m_debug_known_solution_file_name.empty()); m_check_lemmas |= !(m_debug_known_solution_file_name.empty());
m_ism.set_seed(m_random_seed); m_ism.set_seed(m_random_seed);
@ -4721,4 +4725,8 @@ namespace nlsat {
unsigned solver::lws_spt_threshold() const { return m_imp->m_lws_spt_threshold; } unsigned solver::lws_spt_threshold() const { return m_imp->m_lws_spt_threshold; }
bool solver::lws_null_coeffs() const { return m_imp->m_lws_null_coeffs; }
bool solver::lws_null_derivs() const { return m_imp->m_lws_null_derivs; }
}; };

View file

@ -249,6 +249,8 @@ namespace nlsat {
assignment& sample(); assignment& sample();
bool apply_levelwise() const; bool apply_levelwise() const;
unsigned lws_spt_threshold() const; unsigned lws_spt_threshold() const;
bool lws_null_coeffs() const;
bool lws_null_derivs() const;
void reset(); void reset();
void collect_statistics(statistics & st); void collect_statistics(statistics & st);
void reset_statistics(); void reset_statistics();