mirror of
https://github.com/Z3Prover/z3
synced 2026-02-03 15:56:17 +00:00
reorganize top-level loop
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
426c02a22c
commit
eed1db4376
2 changed files with 91 additions and 54 deletions
|
|
@ -92,46 +92,25 @@ namespace nla {
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool stellensatz2::saturate() {
|
lbool stellensatz2::saturate() {
|
||||||
unsigned num_conflicts = 0;
|
|
||||||
init_solver();
|
init_solver();
|
||||||
TRACE(arith, display(tout << "stellensatz before saturation\n"));
|
TRACE(arith, display(tout << "stellensatz before saturation\n"));
|
||||||
start_saturate:
|
|
||||||
lbool r = search();
|
lbool r = search();
|
||||||
|
|
||||||
TRACE(arith, tout << "search " << r << ": " << m_core << "\n");
|
TRACE(arith, tout << "search " << r << ": " << m_core << "\n");
|
||||||
|
|
||||||
if (r == l_undef)
|
switch (r) {
|
||||||
r = m_solver.solve(m_core);
|
case l_false:
|
||||||
TRACE(arith, display(tout << "stellensatz after saturation " << r << "\n"));
|
|
||||||
if (r == l_false) {
|
|
||||||
++num_conflicts;
|
|
||||||
IF_VERBOSE(2, verbose_stream() << "(nla.stellensatz :conflicts " << num_conflicts << ":constraints "
|
|
||||||
<< m_constraints.size() << ")\n");
|
|
||||||
if (num_conflicts >= m_config.max_conflicts)
|
|
||||||
return l_undef;
|
|
||||||
while (backtrack(m_core)) {
|
|
||||||
++c().lp_settings().stats().m_stellensatz.m_num_backtracks;
|
|
||||||
lbool rb = m_solver.solve(m_core);
|
|
||||||
TRACE(arith, tout << "backtrack search " << rb << ": " << m_core << "\n");
|
|
||||||
// verbose_stream() << rb << " " << num_conflicts << " " << m_config.max_conflicts << "\n";
|
|
||||||
if (rb == l_false)
|
|
||||||
continue;
|
|
||||||
if (rb == l_undef) {
|
|
||||||
//verbose_stream() << "undetermined solve\n";
|
|
||||||
// return rb;
|
|
||||||
}
|
|
||||||
m_solver.update_values(m_values);
|
|
||||||
goto start_saturate;
|
|
||||||
}
|
|
||||||
++c().lp_settings().stats().m_stellensatz.m_num_conflicts;
|
++c().lp_settings().stats().m_stellensatz.m_num_conflicts;
|
||||||
conflict(m_core);
|
conflict(m_core);
|
||||||
|
return l_false;
|
||||||
|
case l_true:
|
||||||
|
if (set_model())
|
||||||
|
return l_true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (r == l_true && !set_model())
|
IF_VERBOSE(2, display(verbose_stream()));
|
||||||
r = l_undef;
|
|
||||||
if (r == l_undef) {
|
|
||||||
IF_VERBOSE(2, display(verbose_stream()));
|
|
||||||
}
|
|
||||||
// verbose_stream() << "result " << r << "\n";
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,6 +140,7 @@ namespace nla {
|
||||||
m_coi.init();
|
m_coi.init();
|
||||||
init_vars();
|
init_vars();
|
||||||
simplify();
|
simplify();
|
||||||
|
m_stats.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stellensatz2::init_vars() {
|
void stellensatz2::init_vars() {
|
||||||
|
|
@ -492,6 +472,35 @@ namespace nla {
|
||||||
c().lra_solver().settings().stats().m_nla_stellensatz++;
|
c().lra_solver().settings().stats().m_nla_stellensatz++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool stellensatz2::is_feasible() {
|
||||||
|
if (any_of(m_constraints, [&](auto const &c) { return !constraint_is_true(c); }))
|
||||||
|
return false;
|
||||||
|
for (auto v : m_var2level) {
|
||||||
|
if (var_is_int(v) && !value(v).is_int())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool stellensatz2::is_linear_conflict() {
|
||||||
|
lbool r = m_solver.solve(m_core);
|
||||||
|
TRACE(arith, display(tout << "stellensatz after saturation " << r << "\n"));
|
||||||
|
if (r != l_false) {
|
||||||
|
m_solver.update_values(m_values);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (backtrack(m_core)) {
|
||||||
|
r = m_solver.solve(m_core);
|
||||||
|
TRACE(arith, tout << "backtrack search " << r << ": " << m_core << "\n");
|
||||||
|
if (r == l_false)
|
||||||
|
continue;
|
||||||
|
m_solver.update_values(m_values);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// for px + q >= 0
|
// for px + q >= 0
|
||||||
// If M(p) = 0, then
|
// If M(p) = 0, then
|
||||||
|
|
@ -523,6 +532,8 @@ namespace nla {
|
||||||
display_constraint(tout << "reduced ", new_ci);
|
display_constraint(tout << "reduced ", new_ci);
|
||||||
display_constraint(tout, p_is_0));
|
display_constraint(tout, p_is_0));
|
||||||
new_ci = factor(new_ci);
|
new_ci = factor(new_ci);
|
||||||
|
// display_constraint(verbose_stream(), p_is_0) << "\n";
|
||||||
|
// display_constraint(verbose_stream(), new_ci) << "\n";
|
||||||
return new_ci;
|
return new_ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -600,15 +611,15 @@ namespace nla {
|
||||||
//
|
//
|
||||||
bool stellensatz2::backtrack(svector<lp::constraint_index> const &core) {
|
bool stellensatz2::backtrack(svector<lp::constraint_index> const &core) {
|
||||||
// reset_bounds();
|
// reset_bounds();
|
||||||
|
|
||||||
SASSERT(well_formed());
|
SASSERT(well_formed());
|
||||||
m_constraints_in_conflict.reset();
|
m_constraints_in_conflict.reset();
|
||||||
svector<lp::constraint_index> external, assumptions;
|
svector<lp::constraint_index> external, assumptions;
|
||||||
for (auto ci : core)
|
for (auto ci : core)
|
||||||
explain_constraint(ci, external, assumptions);
|
explain_constraint(ci, external, assumptions);
|
||||||
TRACE(arith, display(tout << "backtrack core " << core << "external " << external << " assumptions " << assumptions << "\n");
|
TRACE(arith, display(tout << "backtrack core " << core << "external " << external << " assumptions "
|
||||||
for (auto a : assumptions)
|
<< assumptions << "\n");
|
||||||
display_constraint(tout, a);
|
for (auto a : assumptions) display_constraint(tout, a););
|
||||||
);
|
|
||||||
if (assumptions.empty())
|
if (assumptions.empty())
|
||||||
return false;
|
return false;
|
||||||
lp::constraint_index max_ci = 0;
|
lp::constraint_index max_ci = 0;
|
||||||
|
|
@ -974,13 +985,19 @@ namespace nla {
|
||||||
is_sat = resolve_conflict();
|
is_sat = resolve_conflict();
|
||||||
else if (should_propagate())
|
else if (should_propagate())
|
||||||
propagate();
|
propagate();
|
||||||
else if (repair())
|
else if (primal_saturate())
|
||||||
continue;
|
continue;
|
||||||
|
else if (is_feasible())
|
||||||
|
is_sat = l_true;
|
||||||
|
else if (is_linear_conflict())
|
||||||
|
is_sat = l_false;
|
||||||
|
else if (should_dual_saturate())
|
||||||
|
dual_saturate();
|
||||||
else if (!decide())
|
else if (!decide())
|
||||||
is_sat = l_true;
|
is_sat = l_true;
|
||||||
}
|
}
|
||||||
if (is_sat == l_true)
|
if (is_sat == l_true)
|
||||||
return all_of(m_constraints, [&](auto const &c) { return constraint_is_true(c); }) ? l_true : l_undef;
|
return is_feasible() ? l_true : l_undef;
|
||||||
return is_sat;
|
return is_sat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1035,6 +1052,7 @@ namespace nla {
|
||||||
//
|
//
|
||||||
lbool stellensatz2::resolve_conflict() {
|
lbool stellensatz2::resolve_conflict() {
|
||||||
SASSERT(is_conflict());
|
SASSERT(is_conflict());
|
||||||
|
++c().lp_settings().stats().m_stellensatz.m_num_backtracks;
|
||||||
TRACE(arith, tout << "resolving conflict: " << m_conflict_dep << "\n"; display_constraint(tout, m_conflict);
|
TRACE(arith, tout << "resolving conflict: " << m_conflict_dep << "\n"; display_constraint(tout, m_conflict);
|
||||||
display(tout););
|
display(tout););
|
||||||
|
|
||||||
|
|
@ -1090,7 +1108,7 @@ namespace nla {
|
||||||
for (auto ci : m_conflict_marked_ci)
|
for (auto ci : m_conflict_marked_ci)
|
||||||
deps.push_back(ci);
|
deps.push_back(ci);
|
||||||
|
|
||||||
backtrack(ci, deps);
|
backtrack(ci, deps);
|
||||||
return l_undef;
|
return l_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1359,11 +1377,16 @@ namespace nla {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dual saturation assembles
|
||||||
|
void stellensatz2::dual_saturate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Attempt to repair variables in some order
|
// Attempt to repair variables in some order
|
||||||
//
|
//
|
||||||
|
|
||||||
bool stellensatz2::repair() {
|
bool stellensatz2::primal_saturate() {
|
||||||
|
|
||||||
init_levels();
|
init_levels();
|
||||||
unsigned num_fixed = 0;
|
unsigned num_fixed = 0;
|
||||||
|
|
@ -1800,7 +1823,7 @@ namespace nla {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
for (lpvar w = 0; w < m_level2var.size(); ++w) {
|
for (lpvar w = 0; w < m_level2var.size(); ++w) {
|
||||||
if (var_is_int(w) && !m_values[w].is_int()) {
|
if (var_is_int(w) && !value(w).is_int()) {
|
||||||
if (is_fixed(w))
|
if (is_fixed(w))
|
||||||
continue;
|
continue;
|
||||||
if (m_split_count[w] > m_config.max_splits_per_var)
|
if (m_split_count[w] > m_config.max_splits_per_var)
|
||||||
|
|
@ -2360,7 +2383,7 @@ namespace nla {
|
||||||
return *ivs.back();
|
return *ivs.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stellensatz2::update_interval(dep_interval const &new_iv, dd::pdd const &p) {
|
bool stellensatz2::strengthen_interval(dep_interval const &new_iv, dd::pdd const &p) {
|
||||||
SASSERT(!p.is_val());
|
SASSERT(!p.is_val());
|
||||||
SASSERT(!m_di.is_empty(new_iv));
|
SASSERT(!m_di.is_empty(new_iv));
|
||||||
auto &old_iv = get_interval(p);
|
auto &old_iv = get_interval(p);
|
||||||
|
|
@ -2391,12 +2414,9 @@ namespace nla {
|
||||||
m_di.set_lower_dep(new_iv, b.d);
|
m_di.set_lower_dep(new_iv, b.d);
|
||||||
if (!iv.m_upper_inf)
|
if (!iv.m_upper_inf)
|
||||||
m_di.copy_upper_bound<dep_intervals::with_deps>(iv, new_iv);
|
m_di.copy_upper_bound<dep_intervals::with_deps>(iv, new_iv);
|
||||||
if (m_di.is_empty(new_iv)) {
|
if (is_bounds_conflict(new_iv))
|
||||||
m_dm.linearize(new_iv->m_lower_dep, m_conflict_dep);
|
|
||||||
m_dm.linearize(new_iv->m_upper_dep, m_conflict_dep);
|
|
||||||
return;
|
return;
|
||||||
}
|
if (!strengthen_interval(new_iv, b.q))
|
||||||
if (!update_interval(new_iv, b.q))
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -2407,12 +2427,9 @@ namespace nla {
|
||||||
m_di.set_upper(new_iv, -b.m_value);
|
m_di.set_upper(new_iv, -b.m_value);
|
||||||
if (!iv.m_lower_inf)
|
if (!iv.m_lower_inf)
|
||||||
m_di.copy_lower_bound<dep_intervals::with_deps>(iv, new_iv);
|
m_di.copy_lower_bound<dep_intervals::with_deps>(iv, new_iv);
|
||||||
if (m_di.is_empty(new_iv)) {
|
if (is_bounds_conflict(new_iv))
|
||||||
m_dm.linearize(new_iv->m_lower_dep, m_conflict_dep);
|
|
||||||
m_dm.linearize(new_iv->m_upper_dep, m_conflict_dep);
|
|
||||||
return;
|
return;
|
||||||
}
|
if (!strengthen_interval(new_iv, b.mq))
|
||||||
if (!update_interval(new_iv, b.mq))
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2456,8 +2473,17 @@ namespace nla {
|
||||||
SASSERT(!m_di.is_empty(lo));
|
SASSERT(!m_di.is_empty(lo));
|
||||||
SASSERT(!m_di.is_empty(hi));
|
SASSERT(!m_di.is_empty(hi));
|
||||||
calculate_interval(new_iv, x, lo, hi);
|
calculate_interval(new_iv, x, lo, hi);
|
||||||
if (update_interval(new_iv, parent))
|
if (strengthen_interval(new_iv, parent))
|
||||||
m_polynomial_queue.push_back({parent, lp::null_ci});
|
m_polynomial_queue.push_back({parent, lp::null_ci});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool stellensatz2::is_bounds_conflict(dep_interval &i) {
|
||||||
|
if (m_di.is_empty(i)) {
|
||||||
|
m_dm.linearize(i.m_lower_dep, m_conflict_dep);
|
||||||
|
m_dm.linearize(i.m_upper_dep, m_conflict_dep);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -138,6 +138,11 @@ namespace nla {
|
||||||
unsigned max_splits_per_var = 2;
|
unsigned max_splits_per_var = 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct stats {
|
||||||
|
unsigned m_num_conflicts = 0;
|
||||||
|
void reset() { m_num_conflicts = 0; }
|
||||||
|
};
|
||||||
|
|
||||||
struct constraint_key {
|
struct constraint_key {
|
||||||
unsigned pdd;
|
unsigned pdd;
|
||||||
lp::lconstraint_kind k;
|
lp::lconstraint_kind k;
|
||||||
|
|
@ -170,6 +175,7 @@ namespace nla {
|
||||||
coi m_coi;
|
coi m_coi;
|
||||||
mutable dd::pdd_manager pddm;
|
mutable dd::pdd_manager pddm;
|
||||||
config m_config;
|
config m_config;
|
||||||
|
stats m_stats;
|
||||||
vector<constraint> m_constraints; // ci -> polynomial x comparison x justification
|
vector<constraint> m_constraints; // ci -> polynomial x comparison x justification
|
||||||
unsigned_vector m_levels; // ci -> decision level of constraint
|
unsigned_vector m_levels; // ci -> decision level of constraint
|
||||||
vector<justification> m_justifications;
|
vector<justification> m_justifications;
|
||||||
|
|
@ -208,7 +214,8 @@ namespace nla {
|
||||||
|
|
||||||
void propagate();
|
void propagate();
|
||||||
bool decide();
|
bool decide();
|
||||||
bool repair();
|
bool primal_saturate();
|
||||||
|
void dual_saturate();
|
||||||
lbool search();
|
lbool search();
|
||||||
lbool resolve_conflict();
|
lbool resolve_conflict();
|
||||||
void backtrack(lp::constraint_index ci, svector<lp::constraint_index> const &deps);
|
void backtrack(lp::constraint_index ci, svector<lp::constraint_index> const &deps);
|
||||||
|
|
@ -221,6 +228,7 @@ namespace nla {
|
||||||
void mark_dependencies(u_dependency *d);
|
void mark_dependencies(u_dependency *d);
|
||||||
void mark_dependencies(lp::constraint_index ci);
|
void mark_dependencies(lp::constraint_index ci);
|
||||||
bool should_propagate() const { return m_prop_qhead < m_polynomial_queue.size(); }
|
bool should_propagate() const { return m_prop_qhead < m_polynomial_queue.size(); }
|
||||||
|
bool should_dual_saturate() { return false; }
|
||||||
|
|
||||||
// assuming variables have bounds determine if polynomial has lower/upper bounds
|
// assuming variables have bounds determine if polynomial has lower/upper bounds
|
||||||
void calculate_interval(scoped_dep_interval &out, dd::pdd p);
|
void calculate_interval(scoped_dep_interval &out, dd::pdd p);
|
||||||
|
|
@ -233,6 +241,8 @@ namespace nla {
|
||||||
bool is_conflict() const { return !m_conflict_dep.empty(); }
|
bool is_conflict() const { return !m_conflict_dep.empty(); }
|
||||||
bool is_decision(justification const& j) const { return std::holds_alternative<assumption_justification>(j); }
|
bool is_decision(justification const& j) const { return std::holds_alternative<assumption_justification>(j); }
|
||||||
bool is_decision(lp::constraint_index ci) const { return is_decision(m_justifications[ci]); }
|
bool is_decision(lp::constraint_index ci) const { return is_decision(m_justifications[ci]); }
|
||||||
|
bool is_feasible();
|
||||||
|
bool is_linear_conflict();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
|
@ -347,7 +357,8 @@ namespace nla {
|
||||||
void insert_factor(dd::pdd const &p, lpvar x, factorization const &f, lp::constraint_index ci);
|
void insert_factor(dd::pdd const &p, lpvar x, factorization const &f, lp::constraint_index ci);
|
||||||
void pop_propagation(lp::constraint_index ci);
|
void pop_propagation(lp::constraint_index ci);
|
||||||
bool is_better(dep_interval const &new_iv, dep_interval const &old_iv);
|
bool is_better(dep_interval const &new_iv, dep_interval const &old_iv);
|
||||||
bool update_interval(dep_interval const &new_iv, dd::pdd const &p);
|
bool strengthen_interval(dep_interval const &new_iv, dd::pdd const &p);
|
||||||
|
bool is_bounds_conflict(dep_interval &i);
|
||||||
dep_interval const &get_interval(dd::pdd const &p);
|
dep_interval const &get_interval(dd::pdd const &p);
|
||||||
void propagate_intervals(dd::pdd const &p, lp::constraint_index ci);
|
void propagate_intervals(dd::pdd const &p, lp::constraint_index ci);
|
||||||
void propagate_constraint(lpvar x, lp::lconstraint_kind k, rational const &value, lp::constraint_index ci, svector<lp::constraint_index> &cs);
|
void propagate_constraint(lpvar x, lp::lconstraint_kind k, rational const &value, lp::constraint_index ci, svector<lp::constraint_index> &cs);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue