3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-22 11:07:51 +00:00

port sample cell projection

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
Lev Nachmanson 2024-08-02 06:28:11 -10:00 committed by Lev Nachmanson
parent 3e518b9e8b
commit 6ce0fcd3ef
4 changed files with 285 additions and 22 deletions

View file

@ -45,6 +45,8 @@ namespace nlsat {
bool m_minimize_cores;
bool m_factor;
bool m_signed_project;
bool m_cell_sample;
struct todo_set {
polynomial::cache & m_cache;
@ -130,7 +132,7 @@ namespace nlsat {
evaluator & m_evaluator;
imp(solver & s, assignment const & x2v, polynomial::cache & u, atom_vector const & atoms, atom_vector const & x2eq,
evaluator & ev):
evaluator & ev, bool is_sample):
m_solver(s),
m_assignment(x2v),
m_atoms(atoms),
@ -148,6 +150,9 @@ namespace nlsat {
m_core1(s),
m_core2(s),
m_result(nullptr),
m_cell_sample(is_sample),
m_evaluator(ev) {
m_simplify_cores = false;
m_full_dimensional = false;
@ -646,6 +651,51 @@ namespace nlsat {
m_todo.insert(p);
}
}
void add_sample_coeff(polynomial_ref_vector &ps, var x){
polynomial_ref p(m_pm);
polynomial_ref lc(m_pm);
unsigned sz = ps.size();
for (unsigned i = 0; i < sz; i++){
p = ps.get(i);
unsigned k = degree(p, x);
SASSERT(k > 0);
TRACE("nlsat_explain", tout << "add_lc, x: "; display_var(tout, x); tout << "\nk: " << k << "\n"; display(tout, p); tout << "\n";);
for(; k > 0; k--){
lc = m_pm.coeff(p, x, k);
add_factors(lc);
if (m_pm.nonzero_const_coeff(p, x, k)){
TRACE("nlsat_explain", tout << "constant coefficient, skipping...\n";);
break;
}
}
SASSERT(sign(lc) != 0);
SASSERT(!is_const(lc));
}
}
void psc_resultant_sample(polynomial_ref_vector &ps, var x, polynomial_ref_vector & samples){
polynomial_ref p(m_pm);
polynomial_ref q(m_pm);
// polynomial_ref_vector samples(m_pm);
// samples.reset();
// sample_poly(ps, x, samples);
SASSERT(samples.size() <= 2);
for (unsigned i = 0; i < ps.size(); i++){
p = ps.get(i);
for (unsigned j = 0; j < samples.size(); j++){
q = samples.get(j);
if (!m_pm.eq(p, q)) {
psc(p, q, x);
}
}
}
}
/**
\brief Add leading coefficients of the polynomials in ps.
@ -973,6 +1023,116 @@ namespace nlsat {
add_simple_assumption(k, p, lsign);
}
void cac_add_cell_lits(polynomial_ref_vector & ps, var y, polynomial_ref_vector & res) {
res.reset();
SASSERT(m_assignment.is_assigned(y));
bool lower_inf = true;
bool upper_inf = true;
scoped_anum_vector & roots = m_roots_tmp;
scoped_anum lower(m_am);
scoped_anum upper(m_am);
anum const & y_val = m_assignment.value(y);
TRACE("nlsat_explain", tout << "adding literals for "; display_var(tout, y); tout << " -> ";
m_am.display_decimal(tout, y_val); tout << "\n";);
polynomial_ref p_lower(m_pm);
unsigned i_lower = UINT_MAX;
polynomial_ref p_upper(m_pm);
unsigned i_upper = UINT_MAX;
polynomial_ref p(m_pm);
unsigned sz = ps.size();
for (unsigned k = 0; k < sz; k++) {
p = ps.get(k);
if (max_var(p) != y)
continue;
roots.reset();
// Variable y is assigned in m_assignment. We must temporarily unassign it.
// Otherwise, the isolate_roots procedure will assume p is a constant polynomial.
m_am.isolate_roots(p, undef_var_assignment(m_assignment, y), roots);
unsigned num_roots = roots.size();
//#linxi begin add_cell_lits faster
bool all_lt = true;
for (unsigned i = 0; i < num_roots; i++) {
int s = m_am.compare(y_val, roots[i]);
TRACE("nlsat_explain",
m_am.display_decimal(tout << "comparing root: ", roots[i]); tout << "\n";
m_am.display_decimal(tout << "with y_val:", y_val);
tout << "\nsign " << s << "\n";
tout << "poly: " << p << "\n";
);
if (s == 0) {
// y_val == roots[i]
// add literal
// ! (y = root_i(p))
add_root_literal(atom::ROOT_EQ, y, i+1, p);
res.push_back(p);
return;
}
else if (s < 0) {
// y_val < roots[i]
if (i > 0) {
// y_val > roots[j]
int j = i - 1;
if (lower_inf || m_am.lt(lower, roots[j])) {
lower_inf = false;
m_am.set(lower, roots[j]);
p_lower = p;
i_lower = j + 1;
}
}
if (upper_inf || m_am.lt(roots[i], upper)) {
upper_inf = false;
m_am.set(upper, roots[i]);
p_upper = p;
i_upper = i + 1;
}
all_lt = false;
break;
}
// else if (s < 0) {
// // y_val < roots[i]
// // check if roots[i] is a better upper bound
// if (upper_inf || m_am.lt(roots[i], upper)) {
// upper_inf = false;
// m_am.set(upper, roots[i]);
// p_upper = p;
// i_upper = i+1;
// }
// }
// else if (s > 0) {
// // roots[i] < y_val
// // check if roots[i] is a better lower bound
// if (lower_inf || m_am.lt(lower, roots[i])) {
// lower_inf = false;
// m_am.set(lower, roots[i]);
// p_lower = p;
// i_lower = i+1;
// }
// }
}
if (all_lt && num_roots > 0) {
int j = num_roots - 1;
if (lower_inf || m_am.lt(lower, roots[j])) {
lower_inf = false;
m_am.set(lower, roots[j]);
p_lower = p;
i_lower = j + 1;
}
}
//#linxi end add_cell_lits faster
}
if (!lower_inf) {
res.push_back(p_lower);
add_root_literal(m_full_dimensional ? atom::ROOT_GE : atom::ROOT_GT, y, i_lower, p_lower);
}
if (!upper_inf) {
res.push_back(p_upper);
add_root_literal(m_full_dimensional ? atom::ROOT_LE : atom::ROOT_LT, y, i_upper, p_upper);
}
}
/**
Add one or two literals that specify in which cell of variable y the current interpretation is.
One literal is added for the cases:
@ -1016,6 +1176,8 @@ namespace nlsat {
// Otherwise, the isolate_roots procedure will assume p is a constant polynomial.
m_am.isolate_roots(p, undef_var_assignment(m_assignment, y), roots);
unsigned num_roots = roots.size();
//#linxi begin add_cell_lits faster
bool all_lt = true;
for (unsigned i = 0; i < num_roots; i++) {
int s = m_am.compare(y_val, roots[i]);
TRACE("nlsat_explain",
@ -1033,27 +1195,58 @@ namespace nlsat {
}
else if (s < 0) {
// y_val < roots[i]
// check if roots[i] is a better upper bound
if (i > 0) {
// y_val > roots[j]
int j = i - 1;
if (lower_inf || m_am.lt(lower, roots[j])) {
lower_inf = false;
m_am.set(lower, roots[j]);
p_lower = p;
i_lower = j + 1;
}
}
if (upper_inf || m_am.lt(roots[i], upper)) {
upper_inf = false;
m_am.set(upper, roots[i]);
p_upper = p;
i_upper = i+1;
i_upper = i + 1;
}
all_lt = false;
break;
}
else if (s > 0) {
// roots[i] < y_val
// else if (s < 0) {
// // y_val < roots[i]
// // check if roots[i] is a better upper bound
// if (upper_inf || m_am.lt(roots[i], upper)) {
// upper_inf = false;
// m_am.set(upper, roots[i]);
// p_upper = p;
// i_upper = i+1;
// }
// }
// else if (s > 0) {
// // roots[i] < y_val
// check if roots[i] is a better lower bound
if (lower_inf || m_am.lt(lower, roots[i])) {
lower_inf = false;
m_am.set(lower, roots[i]);
p_lower = p;
i_lower = i+1;
}
// // check if roots[i] is a better lower bound
// if (lower_inf || m_am.lt(lower, roots[i])) {
// lower_inf = false;
// m_am.set(lower, roots[i]);
// p_lower = p;
// i_lower = i+1;
// }
// }
}
if (all_lt && num_roots > 0) {
int j = num_roots - 1;
if (lower_inf || m_am.lt(lower, roots[j])) {
lower_inf = false;
m_am.set(lower, roots[j]);
p_lower = p;
i_lower = j + 1;
}
}
//#linxi end add_cell_lits faster
}
if (!lower_inf) {
@ -1064,6 +1257,7 @@ namespace nlsat {
}
}
/**
\brief Return true if all polynomials in ps are univariate in x.
*/
@ -1082,7 +1276,8 @@ namespace nlsat {
/**
\brief Apply model-based projection operation defined in our paper.
*/
void project(polynomial_ref_vector & ps, var max_x) {
void project_original(polynomial_ref_vector & ps, var max_x) {
if (ps.empty())
return;
m_todo.reset();
@ -1094,12 +1289,12 @@ namespace nlsat {
if (x < max_x)
add_cell_lits(ps, x);
while (true) {
TRACE("nlsat_explain", tout << "project loop, processing var "; display_var(tout, x); tout << "\npolynomials\n";
display(tout, ps); tout << "\n";);
if (all_univ(ps, x) && m_todo.empty()) {
m_todo.reset();
break;
}
TRACE("nlsat_explain", tout << "project loop, processing var "; display_var(tout, x); tout << "\npolynomials\n";
display(tout, ps); tout << "\n";);
add_lc(ps, x);
psc_discriminant(ps, x);
psc_resultant(ps, x);
@ -1109,6 +1304,72 @@ namespace nlsat {
add_cell_lits(ps, x);
}
}
void project_cdcac(polynomial_ref_vector & ps, var max_x) {
// whz
bool first = true;
if (ps.empty())
return;
m_todo.reset();
for (poly* p : ps) {
m_todo.insert(p);
}
var x = m_todo.remove_max_polys(ps);
// Remark: after vanishing coefficients are eliminated, ps may not contain max_x anymore
polynomial_ref_vector samples(m_pm);
if (x < max_x){
cac_add_cell_lits(ps, x, samples);
}
while (true) {
if (all_univ(ps, x) && m_todo.empty()) {
m_todo.reset();
break;
}
TRACE("nlsat_explain", tout << "project loop, processing var "; display_var(tout, x); tout << "\npolynomials\n";
display(tout, ps); tout << "\n";);
/**
* Sample Projection
* Reference:
* Haokun Li and Bican Xia.
* "Solving Satisfiability of Polynomial Formulas By Sample - Cell Projection"
* https://arxiv.org/abs/2003.00409
*/
if (first) {
add_lc(ps, x);
psc_discriminant(ps, x);
psc_resultant(ps, x);
first = false;
}
else {
add_lc(ps, x);
// add_sample_coeff(ps, x);
psc_discriminant(ps, x);
psc_resultant_sample(ps, x, samples);
}
if (m_todo.empty())
break;
x = m_todo.remove_max_polys(ps);
cac_add_cell_lits(ps, x, samples);
}
}
void project(polynomial_ref_vector & ps, var max_x) {
if (m_cell_sample) {
project_cdcac(ps, max_x);
}
else {
project_original(ps, max_x);
}
}
bool check_already_added() const {
for (bool b : m_already_added_literal) {
@ -1474,7 +1735,7 @@ namespace nlsat {
var max_x = max_var(m_ps);
TRACE("nlsat_explain", tout << "polynomials in the conflict:\n"; display(tout, m_ps); tout << "\n";);
elim_vanishing(m_ps);
TRACE("nlsat_explain", tout << "elim vanishing x" << max_x << "\n"; display(tout, m_ps); tout << "\n";);
TRACE("nlsat_explain", tout << "elim vanishing\n"; display(tout, m_ps); tout << "\n";);
project(m_ps, max_x);
TRACE("nlsat_explain", tout << "after projection\n"; display(tout, m_ps); tout << "\n";);
}
@ -1936,8 +2197,8 @@ namespace nlsat {
};
explain::explain(solver & s, assignment const & x2v, polynomial::cache & u,
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev) {
m_imp = alloc(imp, s, x2v, u, atoms, x2eq, ev);
atom_vector const& atoms, atom_vector const& x2eq, evaluator & ev, bool is_sample) {
m_imp = alloc(imp, s, x2v, u, atoms, x2eq, ev, is_sample);
}
explain::~explain() {