3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-11-22 05:36:41 +00:00

updated sketch

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2025-11-17 22:06:29 -08:00
parent 92bc39dab5
commit 4df7ee67f5
2 changed files with 78 additions and 41 deletions

View file

@ -257,27 +257,21 @@ namespace nla {
auto x = select_variable_to_eliminate(ci); auto x = select_variable_to_eliminate(ci);
if (x == lp::null_lpvar) if (x == lp::null_lpvar)
continue; continue;
if (!resolve_variable(x, ci))
switch (resolve_variable(x, ci)) { return l_false;
case l_false:
return l_false;
default:
break;
}
} }
return l_undef; return l_undef;
} }
lbool stellensatz::resolve_variable(lpvar x, lp::constraint_index ci) { bool stellensatz::resolve_variable(lpvar x, lp::constraint_index ci) {
auto f = factor(x, ci); auto f = factor(x, ci);
TRACE(arith, tout << "factor " << m_constraints[ci].p << " -> j" << x << "^" << f.degree << " * " << f.p TRACE(arith, tout << "factor " << m_constraints[ci].p << " -> j" << x << "^" << f.degree << " * " << f.p
<< " + " << f.q << "\n"); << " + " << f.q << "\n");
auto p_value = value(f.p); auto p_value = value(f.p);
if (vanishing(x, f, ci)) if (vanishing(x, f, ci))
return l_true; return true;
if (p_value == 0) if (p_value == 0)
return l_undef; return true;
unsigned num_x = m_occurs[x].size(); unsigned num_x = m_occurs[x].size();
for (unsigned i = 0; i < f.degree; ++i) for (unsigned i = 0; i < f.degree; ++i)
f.p *= to_pdd(x); f.p *= to_pdd(x);
@ -286,9 +280,9 @@ namespace nla {
for (unsigned cx = 0; cx < num_x; ++cx) { for (unsigned cx = 0; cx < num_x; ++cx) {
auto other_ci = m_occurs[x][cx]; auto other_ci = m_occurs[x][cx];
if (!resolve_variable(x, ci, other_ci, p_value, f, _m1, _f_p)) if (!resolve_variable(x, ci, other_ci, p_value, f, _m1, _f_p))
return l_false; return false;
} }
return l_undef; return true;
} }
bool stellensatz::resolve_variable(lpvar x, lp::constraint_index ci, lp::constraint_index other_ci, bool stellensatz::resolve_variable(lpvar x, lp::constraint_index ci, lp::constraint_index other_ci,
@ -409,10 +403,8 @@ namespace nla {
} }
lbool stellensatz::model_repair() { lbool stellensatz::model_repair() {
m_active.reset(); m_inactive.reset();
unsigned num_vars = m_values.size(); unsigned num_vars = m_values.size();
for (lp::constraint_index ci = 0; ci < m_constraints.size(); ++ci)
m_active.insert(ci);
for (lpvar v = 0; v < num_vars; ++v) { for (lpvar v = 0; v < num_vars; ++v) {
if (!model_repair(v)) if (!model_repair(v))
return l_false; return l_false;
@ -422,32 +414,31 @@ namespace nla {
bool stellensatz::model_repair(lp::lpvar v) { bool stellensatz::model_repair(lp::lpvar v) {
auto bounds = find_bounds(v); auto bounds = find_bounds(v);
auto &[lo, inf, infs] = bounds.first; auto const &[lo, inf, infs] = bounds.first;
auto &[hi, sup, sups] = bounds.second; auto const &[hi, sup, sups] = bounds.second;
auto has_false = any_of(infs, [&](lp::constraint_index ci) { return !constraint_is_true(ci); }) || auto has_false = any_of(infs, [&](lp::constraint_index ci) { return !constraint_is_true(ci); }) ||
any_of(sups, [&](lp::constraint_index ci) { return !constraint_is_true(ci); }); any_of(sups, [&](lp::constraint_index ci) { return !constraint_is_true(ci); });
if (!has_false && (infs.empty() || sups.empty())) if (!has_false)
return true; return true;
SASSERT(!infs.empty() || !sups.empty());
if (infs.empty()) { if (infs.empty()) {
SASSERT(!sups.empty());
// repair v by setting it below sup // repair v by setting it below sup
auto f = factor(v, sup); auto f = factor(v, sup);
auto new_value = floor(-value(f.q) / value(f.p)); m_values[v] = floor(-value(f.q) / value(f.p));
m_values[v] = new_value;
return true; return true;
} }
if (sups.empty()) { if (sups.empty()) {
SASSERT(!infs.empty());
// repair v by setting it above inf // repair v by setting it above inf
auto f = factor(v, inf); auto f = factor(v, inf);
auto new_value = ceil(-value(f.q) / value(f.p)); m_values[v] = ceil(-value(f.q) / value(f.p));
m_values[v] = new_value;
return true; return true;
} }
if (lo <= hi && (!is_int(v) || ceil(lo) <= floor(hi))) { if (lo <= hi && (!is_int(v) || ceil(lo) <= floor(hi))) {
// repair v by setting it between lo and hi assuming it is integral when v is integer // repair v by setting it between lo and hi assuming it is integral when v is integer
if (is_int(v)) m_values[v] = is_int(v) ? ceil(lo) : lo;
m_values[v] = ceil(lo); return true;
else
m_values[v] = lo;
} }
// lo > hi - pick a side and assume inf or sup and enforce order between sup and inf. // lo > hi - pick a side and assume inf or sup and enforce order between sup and inf.
// maybe just add constraints that are false and skip the rest? // maybe just add constraints that are false and skip the rest?
@ -457,34 +448,79 @@ namespace nla {
SASSERT(f.degree == 1); SASSERT(f.degree == 1);
auto p_value = value(f.p); auto p_value = value(f.p);
f.p *= pddm.mk_var(v); f.p *= pddm.mk_var(v);
auto [m1, f_p] = f.p.var_factors(); auto [m, f_p] = f.p.var_factors();
for (auto s : sups) for (auto s : sups)
resolve_variable(v, inf, s, p_value, f, m1, f_p); if (!resolve_variable(v, inf, s, p_value, f, m, f_p))
for (auto i : infs) { return false;
// assume_ge(v, i, inf) for (auto i : infs)
} assume_ge(v, i, inf);
} }
else { else {
auto f = factor(v, sup); auto f = factor(v, sup);
SASSERT(f.degree == 1); SASSERT(f.degree == 1);
auto p_value = value(f.p); auto p_value = value(f.p);
f.p *= pddm.mk_var(v); f.p *= pddm.mk_var(v);
auto [m1, f_p] = f.p.var_factors(); auto [m, f_p] = f.p.var_factors();
for (auto i : infs) for (auto i : infs)
resolve_variable(v, sup, i, p_value, f, m1, f_p); if (!resolve_variable(v, sup, i, p_value, f, m, f_p))
for (auto s : sups) { return false;
// assume_ge(v, sup, s); for (auto s : sups)
} assume_ge(v, sup, s);
} }
for (auto ci : infs)
m_inactive.insert(ci);
for (auto ci : sups)
m_inactive.insert(ci);
return true; return true;
} }
// lo <= hi
void stellensatz::assume_ge(lpvar v, lp::constraint_index lo, lp::constraint_index hi) {
if (lo == hi)
return;
auto const &[plo, klo, jlo] = m_constraints[lo];
auto const &[phi, khi, jhi] = m_constraints[hi];
auto f = factor(v, lo);
auto g = factor(v, hi);
SASSERT(f.degree == 1);
SASSERT(g.degree == 1);
auto fp_value = value(f.p);
auto gp_value = value(g.p);
SASSERT(fp_value != 0);
SASSERT(gp_value != 0);
SASSERT((fp_value > 0) == (gp_value > 0));
if (fp_value > 0) {
//
// f.p x + f.q >= 0
// <=>
// x >= - f.q / f.p
//
// - f.q / f.p <= - g.q / g.p
// <=>
// f.q / f.p >= g.q / g.p
// <=>
// f.q * g.p >= g.q * f.p
//
auto r = (f.q * g.p) - (g.q * f.p);
SASSERT(value(r) >= 0);
auto new_ci = assume(r, join(klo, khi));
}
else {
//
// f.p x + f.q >= 0 <=> f.p x >= - f.q <=> x <= - f.q / f.p
//
auto r = (g.q * f.p) - (f.q * g.p);
SASSERT(value(r) >= 0);
auto new_ci = assume(r, join(klo, khi));
}
}
std::pair<stellensatz::bound_info, stellensatz::bound_info> stellensatz::find_bounds(lpvar v) { std::pair<stellensatz::bound_info, stellensatz::bound_info> stellensatz::find_bounds(lpvar v) {
std::pair<bound_info, bound_info> result; std::pair<bound_info, bound_info> result;
auto &[lo, inf, infs] = result.first; auto &[lo, inf, infs] = result.first;
auto &[hi, sup, sups] = result.second; auto &[hi, sup, sups] = result.second;
for (auto ci : m_occurs[v]) { for (auto ci : m_occurs[v]) {
if (!m_active.contains(ci)) if (m_inactive.contains(ci))
continue; continue;
auto f = factor(v, ci); auto f = factor(v, ci);
auto p_value = value(f.p); auto p_value = value(f.p);

View file

@ -120,7 +120,7 @@ namespace nla {
dd::pdd_manager pddm; dd::pdd_manager pddm;
vector<constraint> m_constraints; vector<constraint> m_constraints;
monomial_factory m_monomial_factory; monomial_factory m_monomial_factory;
indexed_uint_set m_active; indexed_uint_set m_active, m_inactive;
vector<uint_set> m_tabu; vector<uint_set> m_tabu;
vector<rational> m_values; vector<rational> m_values;
@ -165,7 +165,7 @@ namespace nla {
lp::lpvar select_variable_to_eliminate(lp::constraint_index ci); lp::lpvar select_variable_to_eliminate(lp::constraint_index ci);
unsigned degree_of_var_in_constraint(lpvar v, lp::constraint_index ci) const; unsigned degree_of_var_in_constraint(lpvar v, lp::constraint_index ci) const;
factorization factor(lpvar v, lp::constraint_index ci); factorization factor(lpvar v, lp::constraint_index ci);
lbool resolve_variable(lpvar x, lp::constraint_index ci); bool resolve_variable(lpvar x, lp::constraint_index ci);
bool resolve_variable(lpvar x, lp::constraint_index ci, lp::constraint_index other_ci, rational const& p_value, bool resolve_variable(lpvar x, lp::constraint_index ci, lp::constraint_index other_ci, rational const& p_value,
factorization const& f, unsigned_vector const& m1, dd::pdd _f_p); factorization const& f, unsigned_vector const& m1, dd::pdd _f_p);
@ -177,6 +177,7 @@ namespace nla {
svector<lp::constraint_index> bounds; svector<lp::constraint_index> bounds;
}; };
std::pair<bound_info, bound_info> find_bounds(lpvar v); std::pair<bound_info, bound_info> find_bounds(lpvar v);
void assume_ge(lpvar v, lp::constraint_index lo, lp::constraint_index hi);
bool constraint_is_true(lp::constraint_index ci) const; bool constraint_is_true(lp::constraint_index ci) const;
bool is_new_constraint(lp::constraint_index ci) const; bool is_new_constraint(lp::constraint_index ci) const;