3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-05-01 16:13:44 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2026-01-15 16:42:08 -08:00
parent 2720d9ae59
commit 7b01f263f4
2 changed files with 35 additions and 36 deletions

View file

@ -148,7 +148,6 @@ namespace nla {
} }
void stellensatz2::init_solver() { void stellensatz2::init_solver() {
m_ctrail.reset(); // pops constraints
m_num_scopes = 0; m_num_scopes = 0;
m_monomial_factory.reset(); m_monomial_factory.reset();
m_coi.init(); m_coi.init();
@ -296,7 +295,7 @@ namespace nla {
ci = m_constraints.size(); ci = m_constraints.size();
unsigned level = get_level(j); unsigned level = get_level(j);
if (std::holds_alternative<assumption_justification>(j)) { if (is_decision(j)) {
level = m_num_scopes; level = m_num_scopes;
++m_num_scopes; ++m_num_scopes;
} }
@ -336,11 +335,11 @@ namespace nla {
SASSERT(ci != lp::null_ci); SASSERT(ci != lp::null_ci);
if (conflict == lp::null_ci) if (conflict == lp::null_ci)
return lp::null_ci; return lp::null_ci;
// TODO: the variable to resolve on occurs in ci and has to be extracted from ci or the justification for ci. auto const &[p, k] = m_constraints[ci];
// It is likely adequate to suppose ci is justified by bounds propagation and the variable is in the propagated if (p.is_var())
// bound. It could also be that ci is a decision. Note that extracting variables for resolution is optional. we return resolve_variable(p.var(), ci, conflict);
// will anyhow end up flipping the last decision. v is maximal variable in ci? if (p.is_minus())
NOT_IMPLEMENTED_YET(); return resolve_variable((-p).var(), ci, conflict);
return lp::null_ci; return lp::null_ci;
} }
@ -629,7 +628,7 @@ namespace nla {
if (std::holds_alternative<external_justification>(j)) { if (std::holds_alternative<external_justification>(j)) {
external.push_back(ci); external.push_back(ci);
} }
else if (std::holds_alternative<assumption_justification>(j)) { else if (is_decision(j)) {
assumptions.push_back(ci); assumptions.push_back(ci);
} }
else { else {
@ -808,15 +807,6 @@ namespace nla {
return; return;
if (m_has_occurs[ci]) if (m_has_occurs[ci])
return; return;
struct undo_occurs : public trail {
stellensatz2 & s;
lp::constraint_index ci;
undo_occurs(stellensatz2 & s, lp::constraint_index ci) : s(s), ci(ci) {}
void undo() override {
s.remove_occurs(ci);
}
};
m_ctrail.push(undo_occurs(*this, ci));
m_has_occurs[ci] = true; m_has_occurs[ci] = true;
auto const &con = m_constraints[ci]; auto const &con = m_constraints[ci];
for (auto v : con.p.free_vars()) for (auto v : con.p.free_vars())
@ -824,7 +814,8 @@ namespace nla {
} }
void stellensatz2::remove_occurs(lp::constraint_index ci) { void stellensatz2::remove_occurs(lp::constraint_index ci) {
SASSERT(m_has_occurs[ci]); if (!m_has_occurs[ci])
return;
m_has_occurs[ci] = false; m_has_occurs[ci] = false;
auto const &con = m_constraints[ci]; auto const &con = m_constraints[ci];
for (auto v : con.p.free_vars()) for (auto v : con.p.free_vars())
@ -1091,8 +1082,8 @@ namespace nla {
return l_undef; return l_undef;
} }
void stellensatz2::backtrack(unsigned ci, svector<lp::constraint_index> const &deps) { stellensatz2::constraint stellensatz2::negate_constraint(constraint const &c) {
auto &[p, k] = m_constraints[ci]; auto [p, k] = c;
switch (k) { switch (k) {
case lp::lconstraint_kind::GE: case lp::lconstraint_kind::GE:
if (is_int(p)) { if (is_int(p)) {
@ -1113,18 +1104,22 @@ namespace nla {
k = lp::lconstraint_kind::GT; k = lp::lconstraint_kind::GT;
break; break;
} }
lp::constraint_index head = ci, tail = ci + 1; return {p, k};
}
void stellensatz2::backtrack(unsigned ci, svector<lp::constraint_index> const &deps) {
auto &[p, k] = m_constraints[ci];
unsigned propagation_level = 0; unsigned propagation_level = 0;
for (auto ci : deps) for (auto ci : deps)
propagation_level = std::max(propagation_level, m_levels[ci]); propagation_level = std::max(propagation_level, m_levels[ci]);
m_constraint_index.erase({p.index(), k});
// propagate negated constraint // propagate negated constraint
m_justifications[head] = propagation_justification(deps); m_constraints[ci] = negate_constraint(m_constraints[ci]);
m_levels[head] = propagation_level; m_justifications[ci] = propagation_justification(deps);
m_constraints[head] = {p, k}; m_levels[ci] = propagation_level;
m_num_scopes = propagation_level; m_num_scopes = propagation_level;
++head; lp::constraint_index head = ci + 1, tail = ci + 1;
// replay other constraints // replay other constraints
unsigned sz = m_constraints.size(); unsigned sz = m_constraints.size();
svector<lp::constraint_index> tail2head; svector<lp::constraint_index> tail2head;
@ -1133,15 +1128,20 @@ namespace nla {
return old_ci < sz ? old_ci : tail2head[sz - old_ci]; return old_ci < sz ? old_ci : tail2head[sz - old_ci];
}; };
for (; tail < m_constraints.size(); ++tail) { for (; tail < m_constraints.size(); ++tail) {
auto [p, k] = m_constraints[tail];
auto level = get_level(m_justifications[tail]); auto level = get_level(m_justifications[tail]);
if (tail < sz && level > propagation_level) auto has_occurs = m_has_occurs[tail];
continue; remove_occurs(tail);
m_constraint_index.erase({p.index(), k});
if (level > m_num_scopes)
continue;
m_constraints[head] = m_constraints[tail]; m_constraints[head] = m_constraints[tail];
m_justifications[head] = translate_j(translate_ci, m_justifications[tail]); m_justifications[head] = translate_j(translate_ci, m_justifications[tail]);
m_levels[head] = get_level(m_justifications[tail]); m_levels[head] = is_decision(head) ? ++m_num_scopes : get_level(m_justifications[tail]);
if (is_decision(head))
m_levels[head] = ++m_num_scopes;
tail2head[sz - tail] = head; tail2head[sz - tail] = head;
if (has_occurs)
init_occurs(head);
m_constraint_index.insert({p.index(), k}, head);
++head; ++head;
} }
m_constraints.shrink(head); m_constraints.shrink(head);

View file

@ -166,8 +166,6 @@ namespace nla {
lpvar m_var; lpvar m_var;
bool m_is_upper; bool m_is_upper;
}; };
trail_stack m_ctrail; // constraint and variable trail
unsigned m_num_scopes = 0; unsigned m_num_scopes = 0;
coi m_coi; coi m_coi;
mutable dd::pdd_manager pddm; mutable dd::pdd_manager pddm;
@ -214,6 +212,8 @@ namespace nla {
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);
constraint negate_constraint(constraint const &c);
void init_search(); void init_search();
void init_levels(); void init_levels();
void pop_bound(); void pop_bound();
@ -234,9 +234,8 @@ namespace nla {
} }
void reset_conflict() { m_conflict = lp::null_ci; m_conflict_dep.reset(); } void reset_conflict() { m_conflict = lp::null_ci; m_conflict_dep.reset(); }
bool is_conflict() const { return !m_conflict_dep.empty(); } bool is_conflict() const { return !m_conflict_dep.empty(); }
bool is_decision(lp::constraint_index ci) const { bool is_decision(justification const& j) const { return std::holds_alternative<assumption_justification>(j); }
return std::holds_alternative<assumption_justification>(m_justifications[ci]); bool is_decision(lp::constraint_index ci) const { return is_decision(m_justifications[ci]); }
}
indexed_uint_set m_tabu; indexed_uint_set m_tabu;
unsigned_vector m_var2level, m_level2var; unsigned_vector m_var2level, m_level2var;