mirror of
https://github.com/Z3Prover/z3
synced 2026-05-25 11:26:21 +00:00
Fix nlsat projection bug: ensure polynomials with assumptions are also projected
When polynomials are added as assumptions (via add_assumption or ensure_sign), they must also be added to the projection set (m_todo) to ensure proper cell construction. Previously, assumptions were added without corresponding projection, leading to unsound lemmas. Fixes: 1. In normalize(): collect lower-stage polynomials in m_lower_stage_polys and add them to m_ps in main() before projection. 2. In ensure_sign(): call insert_fresh_factors_in_todo(p) after adding assumption. 3. In project_cdcac(): when levelwise fails, use flet to set m_add_all_coeffs=true for the fallback projection.
This commit is contained in:
parent
a8b8e10d20
commit
c4bc251aef
1 changed files with 32 additions and 1 deletions
|
|
@ -131,6 +131,9 @@ namespace nlsat {
|
||||||
// temporary fields for preprocessing core
|
// temporary fields for preprocessing core
|
||||||
scoped_literal_vector m_core1;
|
scoped_literal_vector m_core1;
|
||||||
scoped_literal_vector m_core2;
|
scoped_literal_vector m_core2;
|
||||||
|
|
||||||
|
// Lower-stage polynomials encountered during normalization that need to be projected
|
||||||
|
polynomial_ref_vector m_lower_stage_polys;
|
||||||
|
|
||||||
// temporary fields for storing the result
|
// temporary fields for storing the result
|
||||||
scoped_literal_vector * m_result = nullptr;
|
scoped_literal_vector * m_result = nullptr;
|
||||||
|
|
@ -156,6 +159,7 @@ namespace nlsat {
|
||||||
m_todo(u, canonicalize),
|
m_todo(u, canonicalize),
|
||||||
m_core1(s),
|
m_core1(s),
|
||||||
m_core2(s),
|
m_core2(s),
|
||||||
|
m_lower_stage_polys(m_pm),
|
||||||
m_evaluator(ev) {
|
m_evaluator(ev) {
|
||||||
m_simplify_cores = false;
|
m_simplify_cores = false;
|
||||||
m_full_dimensional = false;
|
m_full_dimensional = false;
|
||||||
|
|
@ -516,6 +520,8 @@ namespace nlsat {
|
||||||
SASSERT(max_var(p) != null_var);
|
SASSERT(max_var(p) != null_var);
|
||||||
SASSERT(max_var(p) < max);
|
SASSERT(max_var(p) < max);
|
||||||
// factor p is a lower stage polynomial, so we should add assumption to justify p being eliminated
|
// factor p is a lower stage polynomial, so we should add assumption to justify p being eliminated
|
||||||
|
// Also collect it for projection to ensure proper cell construction
|
||||||
|
m_lower_stage_polys.push_back(p);
|
||||||
if (s == 0)
|
if (s == 0)
|
||||||
add_assumption(atom::EQ, p); // add assumption p = 0
|
add_assumption(atom::EQ, p); // add assumption p = 0
|
||||||
else if (a->is_even(i))
|
else if (a->is_even(i))
|
||||||
|
|
@ -971,6 +977,8 @@ namespace nlsat {
|
||||||
if (!is_const(p)) {
|
if (!is_const(p)) {
|
||||||
TRACE(nlsat_explain, tout << p << "\n";);
|
TRACE(nlsat_explain, tout << p << "\n";);
|
||||||
add_assumption(s == 0 ? atom::EQ : (s < 0 ? atom::LT : atom::GT), p);
|
add_assumption(s == 0 ? atom::EQ : (s < 0 ? atom::LT : atom::GT), p);
|
||||||
|
// Also add p to the projection to ensure proper cell construction
|
||||||
|
insert_fresh_factors_in_todo(p);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
@ -1110,7 +1118,7 @@ namespace nlsat {
|
||||||
if (lws.failed())
|
if (lws.failed())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TRACE(lws, for (unsigned i = 0; i < cell.size(); i++)
|
TRACE(lws, for (unsigned i = 0; i < cell.size(); i++)
|
||||||
display(tout << "I[" << i << "]:", m_solver, cell[i]) << "\n";);
|
display(tout << "I[" << i << "]:", m_solver, cell[i]) << "\n";);
|
||||||
// Enumerate all intervals in the computed cell and add literals for each non-trivial interval.
|
// Enumerate all intervals in the computed cell and add literals for each non-trivial interval.
|
||||||
// Non-trivial = section, or sector with at least one finite bound (ignore (-oo,+oo)).
|
// Non-trivial = section, or sector with at least one finite bound (ignore (-oo,+oo)).
|
||||||
|
|
@ -1154,12 +1162,18 @@ namespace nlsat {
|
||||||
for (auto p: m_todo.m_set)
|
for (auto p: m_todo.m_set)
|
||||||
ps.push_back(p);
|
ps.push_back(p);
|
||||||
|
|
||||||
|
bool use_all_coeffs = false;
|
||||||
if (m_solver.apply_levelwise()) {
|
if (m_solver.apply_levelwise()) {
|
||||||
bool levelwise_ok = levelwise_single_cell(ps, max_x, m_cache);
|
bool levelwise_ok = levelwise_single_cell(ps, max_x, m_cache);
|
||||||
m_solver.record_levelwise_result(levelwise_ok);
|
m_solver.record_levelwise_result(levelwise_ok);
|
||||||
if (levelwise_ok)
|
if (levelwise_ok)
|
||||||
return;
|
return;
|
||||||
|
// Levelwise failed, use add_all_coeffs mode for fallback projection
|
||||||
|
use_all_coeffs = true;
|
||||||
}
|
}
|
||||||
|
// Set m_add_all_coeffs for the rest of the projection, restore on function exit
|
||||||
|
flet<bool> _set_all_coeffs(m_add_all_coeffs, use_all_coeffs || m_add_all_coeffs);
|
||||||
|
|
||||||
var x = m_todo.extract_max_polys(ps);
|
var x = m_todo.extract_max_polys(ps);
|
||||||
polynomial_ref_vector samples(m_pm);
|
polynomial_ref_vector samples(m_pm);
|
||||||
if (x < max_x)
|
if (x < max_x)
|
||||||
|
|
@ -1190,6 +1204,7 @@ namespace nlsat {
|
||||||
x = m_todo.extract_max_polys(ps);
|
x = m_todo.extract_max_polys(ps);
|
||||||
cac_add_cell_lits(ps, x, samples);
|
cac_add_cell_lits(ps, x, samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void project(polynomial_ref_vector & ps, var max_x) {
|
void project(polynomial_ref_vector & ps, var max_x) {
|
||||||
|
|
@ -1593,8 +1608,19 @@ namespace nlsat {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
collect_polys(num, ls, m_ps);
|
collect_polys(num, ls, m_ps);
|
||||||
|
|
||||||
|
// Add lower-stage polynomials collected during normalization
|
||||||
|
// These polynomials had assumptions added but need to be projected as well
|
||||||
|
for (unsigned i = 0; i < m_lower_stage_polys.size(); i++) {
|
||||||
|
m_ps.push_back(m_lower_stage_polys.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
var max_x = max_var(m_ps);
|
var max_x = max_var(m_ps);
|
||||||
TRACE(nlsat_explain, tout << "polynomials in the conflict:\n"; display(tout, m_solver, m_ps); tout << "\n";);
|
TRACE(nlsat_explain, tout << "polynomials in the conflict:\n"; display(tout, m_solver, m_ps); tout << "\n";);
|
||||||
|
|
||||||
|
// Note: levelwise is now called in process2() before normalize()
|
||||||
|
// to ensure it receives the original polynomials
|
||||||
|
|
||||||
elim_vanishing(m_ps);
|
elim_vanishing(m_ps);
|
||||||
TRACE(nlsat_explain, tout << "after elim_vanishing m_ps:\n"; display(tout, m_solver, m_ps); tout << "\n";);
|
TRACE(nlsat_explain, tout << "after elim_vanishing m_ps:\n"; display(tout, m_solver, m_ps); tout << "\n";);
|
||||||
project(m_ps, max_x);
|
project(m_ps, max_x);
|
||||||
|
|
@ -1602,6 +1628,11 @@ namespace nlsat {
|
||||||
}
|
}
|
||||||
|
|
||||||
void process2(unsigned num, literal const * ls) {
|
void process2(unsigned num, literal const * ls) {
|
||||||
|
// Reset lower-stage polynomials collection
|
||||||
|
m_lower_stage_polys.reset();
|
||||||
|
|
||||||
|
// Try levelwise with ORIGINAL polynomials BEFORE any normalization
|
||||||
|
|
||||||
if (m_simplify_cores) {
|
if (m_simplify_cores) {
|
||||||
TRACE(nlsat_explain, tout << "m_simplify_cores is true\n";);
|
TRACE(nlsat_explain, tout << "m_simplify_cores is true\n";);
|
||||||
m_core2.reset();
|
m_core2.reset();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue