mirror of
https://github.com/Z3Prover/z3
synced 2026-02-08 10:07:59 +00:00
fix a typo in poly_has_roots
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
parent
60f9edb65f
commit
a19db1f7a7
3 changed files with 289 additions and 3 deletions
|
|
@ -28,6 +28,112 @@ Notes:
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// Helper function to check if a point (given by counter_as) is inside a levelwise cell.
|
||||
// Returns true if the point is inside ALL cell intervals, false otherwise.
|
||||
// Prints diagnostic info about which constraint was violated (if any).
|
||||
static bool is_point_inside_cell(
|
||||
anum_manager& am,
|
||||
polynomial::manager& pm,
|
||||
std_vector<nlsat::levelwise::root_function_interval> const& cell,
|
||||
nlsat::assignment const& counter_as,
|
||||
bool verbose = true)
|
||||
{
|
||||
for (unsigned level = 0; level < cell.size(); ++level) {
|
||||
auto const& interval = cell[level];
|
||||
|
||||
// Skip whole-line sectors - no constraint
|
||||
if (!interval.is_section() && interval.l_inf() && interval.u_inf())
|
||||
continue;
|
||||
|
||||
// Get the value at this level from counter_as
|
||||
if (!counter_as.is_assigned(level))
|
||||
continue; // Variable not assigned in counterexample
|
||||
|
||||
scoped_anum counter_val(am);
|
||||
am.set(counter_val, counter_as.value(level));
|
||||
|
||||
// Build partial assignment up to this level (exclusive) for root isolation
|
||||
nlsat::assignment partial_as(am);
|
||||
for (unsigned j = 0; j < level; ++j) {
|
||||
if (counter_as.is_assigned(j)) {
|
||||
scoped_anum v(am);
|
||||
am.set(v, counter_as.value(j));
|
||||
partial_as.set(j, v);
|
||||
}
|
||||
}
|
||||
|
||||
if (interval.is_section()) {
|
||||
// Section: counter must equal the root
|
||||
polynomial_ref section_p(interval.l, pm);
|
||||
scoped_anum_vector roots(am);
|
||||
am.isolate_roots(section_p, nlsat::undef_var_assignment(partial_as, level), roots);
|
||||
|
||||
if (roots.size() >= interval.l_index) {
|
||||
bool at_root = am.eq(counter_val, roots[interval.l_index - 1]);
|
||||
if (!at_root) {
|
||||
if (verbose) {
|
||||
std::cout << " Level " << level << ": OUTSIDE (not at section root)\n";
|
||||
std::cout << " Section root = ";
|
||||
am.display_decimal(std::cout, roots[interval.l_index - 1], 6);
|
||||
std::cout << ", counter = ";
|
||||
am.display_decimal(std::cout, counter_val, 6);
|
||||
std::cout << "\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Sector: check lower and upper bounds
|
||||
if (!interval.l_inf()) {
|
||||
polynomial_ref lower_p(interval.l, pm);
|
||||
scoped_anum_vector lower_roots(am);
|
||||
am.isolate_roots(lower_p, nlsat::undef_var_assignment(partial_as, level), lower_roots);
|
||||
|
||||
if (lower_roots.size() >= interval.l_index) {
|
||||
int cmp = am.compare(counter_val, lower_roots[interval.l_index - 1]);
|
||||
if (cmp <= 0) { // counter <= lower bound, violates (lower, ...)
|
||||
if (verbose) {
|
||||
std::cout << " Level " << level << ": OUTSIDE (at or below lower bound)\n";
|
||||
std::cout << " Lower bound = ";
|
||||
am.display_decimal(std::cout, lower_roots[interval.l_index - 1], 6);
|
||||
std::cout << ", counter = ";
|
||||
am.display_decimal(std::cout, counter_val, 6);
|
||||
std::cout << "\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!interval.u_inf()) {
|
||||
polynomial_ref upper_p(interval.u, pm);
|
||||
scoped_anum_vector upper_roots(am);
|
||||
am.isolate_roots(upper_p, nlsat::undef_var_assignment(partial_as, level), upper_roots);
|
||||
|
||||
if (upper_roots.size() >= interval.u_index) {
|
||||
int cmp = am.compare(counter_val, upper_roots[interval.u_index - 1]);
|
||||
if (cmp >= 0) { // counter >= upper bound, violates (..., upper)
|
||||
if (verbose) {
|
||||
std::cout << " Level " << level << ": OUTSIDE (at or above upper bound)\n";
|
||||
std::cout << " Upper bound = ";
|
||||
am.display_decimal(std::cout, upper_roots[interval.u_index - 1], 6);
|
||||
std::cout << ", counter = ";
|
||||
am.display_decimal(std::cout, counter_val, 6);
|
||||
std::cout << "\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
std::cout << " Point is INSIDE the cell (all constraints satisfied)\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1,
|
||||
nlsat::interval_set_ref const & s2,
|
||||
unsigned expected_num_intervals,
|
||||
|
|
@ -2061,9 +2167,188 @@ static void tst_unsound_lws_disc_zero() {
|
|||
std::cout << "\n=== END tst_unsound_lws_disc_zero ===\n\n";
|
||||
}
|
||||
|
||||
// Test case for unsound lemma from ppblockterm.t2__p7867_terminationG_0.smt2
|
||||
// Issue z3-76w: levelwise produces unsound cell
|
||||
static void tst_unsound_lws_ppblockterm() {
|
||||
std::cout << "=== tst_unsound_lws_ppblockterm ===\n";
|
||||
params_ref ps;
|
||||
ps.set_bool("lws", true);
|
||||
reslimit rlim;
|
||||
nlsat::solver s(rlim, ps, false);
|
||||
anum_manager & am = s.am();
|
||||
nlsat::pmanager & pm = s.pm();
|
||||
polynomial::cache cache(pm);
|
||||
|
||||
// Create 25 variables x0 to x24
|
||||
nlsat::var vars[25];
|
||||
polynomial_ref xvars[25] = {
|
||||
polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm),
|
||||
polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm),
|
||||
polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm),
|
||||
polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm),
|
||||
polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm), polynomial_ref(pm)
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < 25; i++) {
|
||||
vars[i] = s.mk_var(false);
|
||||
xvars[i] = pm.mk_polynomial(vars[i]);
|
||||
}
|
||||
|
||||
// Aliases for readability
|
||||
polynomial_ref &x2 = xvars[2], &x4 = xvars[4], &x5 = xvars[5];
|
||||
polynomial_ref &x9 = xvars[9], &x10 = xvars[10], &x11 = xvars[11];
|
||||
polynomial_ref &x12 = xvars[12], &x13 = xvars[13], &x15 = xvars[15];
|
||||
polynomial_ref &x16 = xvars[16], &x19 = xvars[19], &x24 = xvars[24];
|
||||
|
||||
// p[0]: x16 + x9
|
||||
polynomial_ref p0(pm);
|
||||
p0 = x16 + x9;
|
||||
|
||||
// p[1]: x16 x24 + x9 x24 + x13 x19 + x5 x19 + x12 x15 + x10 x15 - 2
|
||||
polynomial_ref p1(pm);
|
||||
p1 = x16 * x24 + x9 * x24 + x13 * x19 + x5 * x19 + x12 * x15 + x10 * x15 - 2;
|
||||
|
||||
// p[2]: x4
|
||||
polynomial_ref p2(pm);
|
||||
p2 = x4;
|
||||
|
||||
// p[3]: x4 x24 + x2 x19 + x11 x15
|
||||
polynomial_ref p3(pm);
|
||||
p3 = x4 * x24 + x2 * x19 + x11 * x15;
|
||||
|
||||
std::cout << "Input polynomials:\n";
|
||||
std::cout << " p0: " << p0 << "\n";
|
||||
std::cout << " p1: " << p1 << "\n";
|
||||
std::cout << " p2: " << p2 << "\n";
|
||||
std::cout << " p3: " << p3 << "\n\n";
|
||||
|
||||
// Set sample point values
|
||||
// x0->1, x1->1, x2->-1, x3->-1, x4->1, x5->-1, x6->1, x7->2, x8->1
|
||||
// x9->1, x10->-1, x11->1, x12->-2, x13->-2, x14->-2, x15->0, x16->2
|
||||
// x17->0, x18->0, x19->0, x20->0, x21->0, x22->0, x23->0
|
||||
int sample_vals[24] = {1, 1, -1, -1, 1, -1, 1, 2, 1, 1, -1, 1, -2, -2, -2, 0, 2, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
scoped_anum val(am);
|
||||
nlsat::assignment sample_as(am);
|
||||
for (unsigned i = 0; i < 24; i++) {
|
||||
am.set(val, sample_vals[i]);
|
||||
sample_as.set(vars[i], val);
|
||||
}
|
||||
s.set_rvalues(sample_as);
|
||||
|
||||
std::cout << "Sample point (x0..x23):\n";
|
||||
for (unsigned i = 0; i < 24; i++) {
|
||||
std::cout << " x" << i << " -> " << sample_vals[i] << "\n";
|
||||
}
|
||||
std::cout << "\n";
|
||||
|
||||
// Evaluate polynomials at sample (with x24 = 0 for checking)
|
||||
am.set(val, 0);
|
||||
sample_as.set(vars[24], val);
|
||||
std::cout << "Polynomial signs at sample (x24=0):\n";
|
||||
std::cout << " p0 sign: " << am.eval_sign_at(p0, sample_as) << "\n";
|
||||
std::cout << " p1 sign: " << am.eval_sign_at(p1, sample_as) << "\n";
|
||||
std::cout << " p2 sign: " << am.eval_sign_at(p2, sample_as) << "\n";
|
||||
std::cout << " p3 sign: " << am.eval_sign_at(p3, sample_as) << "\n\n";
|
||||
|
||||
// Counterexample from the unsound lemma:
|
||||
// x2=-1, x4=1, x5=0, x9=0, x10=0, x11=-1, x12=-1, x13=-2, x15=3, x16=2, x19=0, x24=3
|
||||
nlsat::assignment counter_as(am);
|
||||
am.set(val, -1); counter_as.set(vars[2], val);
|
||||
am.set(val, 1); counter_as.set(vars[4], val);
|
||||
am.set(val, 0); counter_as.set(vars[5], val);
|
||||
am.set(val, 0); counter_as.set(vars[9], val);
|
||||
am.set(val, 0); counter_as.set(vars[10], val);
|
||||
am.set(val, -1); counter_as.set(vars[11], val);
|
||||
am.set(val, -1); counter_as.set(vars[12], val);
|
||||
am.set(val, -2); counter_as.set(vars[13], val);
|
||||
am.set(val, 3); counter_as.set(vars[15], val);
|
||||
am.set(val, 2); counter_as.set(vars[16], val);
|
||||
am.set(val, 0); counter_as.set(vars[19], val);
|
||||
am.set(val, 3); counter_as.set(vars[24], val);
|
||||
|
||||
std::cout << "Counterexample point:\n";
|
||||
std::cout << " x2=-1, x4=1, x5=0, x9=0, x10=0, x11=-1, x12=-1, x13=-2, x15=3, x16=2, x19=0, x24=3\n\n";
|
||||
|
||||
std::cout << "Polynomial signs at counterexample:\n";
|
||||
std::cout << " p0 sign: " << am.eval_sign_at(p0, counter_as) << "\n";
|
||||
std::cout << " p1 sign: " << am.eval_sign_at(p1, counter_as) << "\n";
|
||||
std::cout << " p2 sign: " << am.eval_sign_at(p2, counter_as) << "\n";
|
||||
std::cout << " p3 sign: " << am.eval_sign_at(p3, counter_as) << "\n\n";
|
||||
|
||||
// Build polynomial vector
|
||||
polynomial_ref_vector polys(pm);
|
||||
polys.push_back(p0);
|
||||
polys.push_back(p1);
|
||||
polys.push_back(p2);
|
||||
polys.push_back(p3);
|
||||
|
||||
unsigned max_x = vars[24]; // x24 is the highest variable
|
||||
|
||||
std::cout << "Running levelwise with max_x = x24...\n";
|
||||
nlsat::levelwise lws(s, polys, max_x, s.sample(), pm, am, cache);
|
||||
auto cell = lws.single_cell();
|
||||
|
||||
if (lws.failed()) {
|
||||
std::cout << "Levelwise FAILED\n";
|
||||
} else {
|
||||
std::cout << "Levelwise succeeded\n";
|
||||
std::cout << "--- LEMMA from levelwise ---\n";
|
||||
for (unsigned i = 0; i < cell.size(); i++) {
|
||||
auto const& interval = cell[i];
|
||||
std::cout << "Level x" << i << ": ";
|
||||
if (interval.is_section()) {
|
||||
std::cout << "section at root[" << interval.l_index << "] of " << interval.l << "\n";
|
||||
} else {
|
||||
if (interval.l_inf())
|
||||
std::cout << "(-oo, ";
|
||||
else
|
||||
std::cout << "(root[" << interval.l_index << "] of " << interval.l << ", ";
|
||||
if (interval.u_inf())
|
||||
std::cout << "+oo)";
|
||||
else
|
||||
std::cout << "root[" << interval.u_index << "] of " << interval.u << ")";
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
std::cout << "--- END LEMMA ---\n\n";
|
||||
|
||||
// Check polynomial signs at sample and counterexample
|
||||
int p0_sample = am.eval_sign_at(p0, sample_as);
|
||||
int p1_sample = am.eval_sign_at(p1, sample_as);
|
||||
int p2_sample = am.eval_sign_at(p2, sample_as);
|
||||
int p3_sample = am.eval_sign_at(p3, sample_as);
|
||||
|
||||
int p0_counter = am.eval_sign_at(p0, counter_as);
|
||||
int p1_counter = am.eval_sign_at(p1, counter_as);
|
||||
int p2_counter = am.eval_sign_at(p2, counter_as);
|
||||
int p3_counter = am.eval_sign_at(p3, counter_as);
|
||||
|
||||
bool signs_differ = (p0_sample != p0_counter) || (p1_sample != p1_counter) ||
|
||||
(p2_sample != p2_counter) || (p3_sample != p3_counter);
|
||||
|
||||
if (signs_differ) {
|
||||
std::cout << "Polynomial signs DIFFER between sample and counterexample.\n";
|
||||
} else {
|
||||
std::cout << "Polynomial signs match between sample and counterexample.\n";
|
||||
}
|
||||
|
||||
// Verify that the counterexample is OUTSIDE the cell (cell is sound)
|
||||
std::cout << "\nChecking if counterexample is inside cell:\n";
|
||||
bool inside = is_point_inside_cell(am, pm, cell, counter_as);
|
||||
|
||||
// For a sound cell with differing signs, counterexample must be OUTSIDE
|
||||
ENSURE(!inside);
|
||||
std::cout << "SUCCESS: Counterexample is OUTSIDE the cell (cell is sound)\n";
|
||||
}
|
||||
|
||||
std::cout << "=== END tst_unsound_lws_ppblockterm ===\n\n";
|
||||
}
|
||||
|
||||
void tst_nlsat() {
|
||||
tst_unsound_lws_disc_zero();
|
||||
std::cout << "------------------\n";
|
||||
// TODO: Fix z3-76w - ppblockterm test fails because counterexample is inside cell
|
||||
// tst_unsound_lws_ppblockterm();
|
||||
// std::cout << "------------------\n";
|
||||
tst_unsound_lws_n46();
|
||||
std::cout << "------------------\n";
|
||||
tst_unsound_lws_et4();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue