mirror of
https://github.com/Z3Prover/z3
synced 2025-08-13 22:41:15 +00:00
Use Z3's watch-list
This commit is contained in:
parent
07e2343c10
commit
e7cf789969
4 changed files with 125 additions and 45 deletions
|
@ -231,8 +231,8 @@ namespace xr {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all elements in other.m_clash_vars that are not yet in m_clash_vars:
|
// add all elements in other.m_clash_vars that are not yet in m_clash_vars:
|
||||||
void merge_clash(const xor_clause& other, visit_helper& visited) {
|
void merge_clash(const xor_clause& other, visit_helper& visited, unsigned num_vars) {
|
||||||
visited.init_visited(m_clash_vars.size());
|
visited.init_visited(num_vars);
|
||||||
for (const bool_var& v: m_clash_vars)
|
for (const bool_var& v: m_clash_vars)
|
||||||
visited.mark_visited(v);
|
visited.mark_visited(v);
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ namespace xr {
|
||||||
bool confl_in_gauss = false;
|
bool confl_in_gauss = false;
|
||||||
SASSERT(m_gwatches.size() > p.var());
|
SASSERT(m_gwatches.size() > p.var());
|
||||||
svector<gauss_watched>& ws = m_gwatches[p.var()];
|
svector<gauss_watched>& ws = m_gwatches[p.var()];
|
||||||
gauss_watched* i = ws.begin();
|
gauss_watched* i = ws.begin(); // TODO: Convert to index or iterator-for
|
||||||
gauss_watched* j = i;
|
gauss_watched* j = i;
|
||||||
const gauss_watched* end = ws.end();
|
const gauss_watched* end = ws.end();
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ namespace xr {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
confl_in_gauss = true;
|
confl_in_gauss = true;
|
||||||
i++;
|
i++; // TODO: That's strange, but this is really written this was in CMS
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -495,13 +495,15 @@ namespace xr {
|
||||||
std::sort(x.begin(), x.end());
|
std::sort(x.begin(), x.end());
|
||||||
std::sort(txors.begin(), txors.end());
|
std::sort(txors.begin(), txors.end());
|
||||||
|
|
||||||
|
m_visited.init_visited(s().num_vars());
|
||||||
|
|
||||||
unsigned sz = 1;
|
unsigned sz = 1;
|
||||||
unsigned j = 0;
|
unsigned j = 0;
|
||||||
for (unsigned i = 1; i < txors.size(); i++) {
|
for (unsigned i = 1; i < txors.size(); i++) {
|
||||||
auto& jd = txors[j];
|
auto& jd = txors[j];
|
||||||
auto& id = txors[i];
|
auto& id = txors[i];
|
||||||
if (jd.m_vars == id.m_vars && jd.m_rhs == id.m_rhs) {
|
if (jd.m_vars == id.m_vars && jd.m_rhs == id.m_rhs) {
|
||||||
jd.merge_clash(id, m_visited);
|
jd.merge_clash(id, m_visited, s().num_vars());
|
||||||
jd.m_detached |= id.m_detached;
|
jd.m_detached |= id.m_detached;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -566,8 +568,8 @@ namespace xr {
|
||||||
|
|
||||||
unsigned xored = 0;
|
unsigned xored = 0;
|
||||||
SASSERT(m_occurrences.empty());
|
SASSERT(m_occurrences.empty());
|
||||||
#if 0
|
|
||||||
//Link in xors into watchlist
|
// Link in xors into watchlist
|
||||||
for (unsigned i = 0; i < xors.size(); i++) {
|
for (unsigned i = 0; i < xors.size(); i++) {
|
||||||
const xor_clause& x = xors[i];
|
const xor_clause& x = xors[i];
|
||||||
for (bool_var v: x) {
|
for (bool_var v: x) {
|
||||||
|
@ -577,13 +579,13 @@ namespace xr {
|
||||||
m_occ_cnt[v]++;
|
m_occ_cnt[v]++;
|
||||||
|
|
||||||
sat::literal l(v, false);
|
sat::literal l(v, false);
|
||||||
SASSERT(s()->watches.size() > l.toInt());
|
watch_neg_literal(l, i);
|
||||||
m_watches[l].push(Watched(i, WatchType::watch_idx_t));
|
// TODO: What's that for?
|
||||||
m_watches.smudge(l);
|
// m_watches.smudge(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Don't XOR together over variables that are in regular clauses
|
// Don't XOR together over variables that are in regular clauses
|
||||||
s().init_visited();
|
s().init_visited();
|
||||||
|
|
||||||
for (unsigned i = 0; i < 2 * s().num_vars(); i++) {
|
for (unsigned i = 0; i < 2 * s().num_vars(); i++) {
|
||||||
|
@ -608,7 +610,7 @@ namespace xr {
|
||||||
s().mark_visited(l.var());
|
s().mark_visited(l.var());
|
||||||
}
|
}
|
||||||
|
|
||||||
//until fixedpoint
|
// until fixedpoint
|
||||||
bool changed = true;
|
bool changed = true;
|
||||||
while (changed) {
|
while (changed) {
|
||||||
changed = false;
|
changed = false;
|
||||||
|
@ -621,7 +623,7 @@ namespace xr {
|
||||||
|
|
||||||
while (!m_interesting.empty()) {
|
while (!m_interesting.empty()) {
|
||||||
|
|
||||||
//Pop and check if it can be XOR-ed together
|
// Pop and check if it can be XOR-ed together
|
||||||
const unsigned v = m_interesting.back();
|
const unsigned v = m_interesting.back();
|
||||||
m_interesting.resize(m_interesting.size()-1);
|
m_interesting.resize(m_interesting.size()-1);
|
||||||
if (m_occ_cnt[v] != 2)
|
if (m_occ_cnt[v] != 2)
|
||||||
|
@ -630,17 +632,18 @@ namespace xr {
|
||||||
unsigned indexes[2];
|
unsigned indexes[2];
|
||||||
unsigned at = 0;
|
unsigned at = 0;
|
||||||
size_t i2 = 0;
|
size_t i2 = 0;
|
||||||
//SASSERT(watches.size() > literal(v, false).index());
|
sat::watch_list& ws = s().get_wlist(literal(v, false));
|
||||||
vector<sat::watched> ws = s().get_wlist(literal(v, false));
|
|
||||||
|
|
||||||
//Remove the 2 indexes from the watchlist
|
//Remove the 2 indexes from the watchlist
|
||||||
for (unsigned i = 0; i < ws.size(); i++) {
|
for (unsigned i = 0; i < ws.size(); i++) {
|
||||||
const sat::watched& w = ws[i];
|
const sat::watched& w = ws[i];
|
||||||
if (!w.isIdx()) {
|
if (!w.is_ext_constraint()) {
|
||||||
|
// TODO: Check!!! Is this fine?
|
||||||
ws[i2++] = ws[i];
|
ws[i2++] = ws[i];
|
||||||
} else if (!xors[w.get_idx()].empty()) {
|
}
|
||||||
|
else if (!xors[w.get_ext_constraint_idx()].empty()) {
|
||||||
SASSERT(at < 2);
|
SASSERT(at < 2);
|
||||||
indexes[at] = w.get_idx();
|
indexes[at] = w.get_ext_constraint_idx();
|
||||||
at++;
|
at++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,26 +655,26 @@ namespace xr {
|
||||||
unsigned clash_var;
|
unsigned clash_var;
|
||||||
unsigned clash_num = xor_two(&x0, &x1, clash_var);
|
unsigned clash_num = xor_two(&x0, &x1, clash_var);
|
||||||
|
|
||||||
//If they are equivalent
|
// If they are equivalent
|
||||||
if (x0.size() == x1.size()
|
if (x0.size() == x1.size()
|
||||||
&& x0.m_rhs == x1.m_rhs
|
&& x0.m_rhs == x1.m_rhs
|
||||||
&& clash_num == x0.size()
|
&& clash_num == x0.size()) {
|
||||||
) {
|
|
||||||
TRACE("xor", tout
|
TRACE("xor", tout
|
||||||
<< "x1: " << x0 << " -- at idx: " << indexes[0]
|
<< "x1: " << x0 << " -- at idx: " << indexes[0]
|
||||||
<< "and x2: " << x1 << " -- at idx: " << indexes[1]
|
<< "and x2: " << x1 << " -- at idx: " << indexes[1]
|
||||||
<< "are equivalent.\n");
|
<< "are equivalent.\n");
|
||||||
|
|
||||||
//Update clash values & detached values
|
// Update clash values & detached values
|
||||||
x1.merge_clash(x0, m_visited);
|
x1.merge_clash(x0, m_visited, s().num_vars());
|
||||||
x1.m_detached |= x0.m_detached;
|
x1.m_detached |= x0.m_detached;
|
||||||
|
|
||||||
TRACE("xor", tout << "after merge: " << x1 << " -- at idx: " << indexes[1] << "\n";);
|
TRACE("xor", tout << "after merge: " << x1 << " -- at idx: " << indexes[1] << "\n";);
|
||||||
|
|
||||||
x0 = xor_clause();
|
x0 = xor_clause();
|
||||||
|
|
||||||
//Re-attach the other, remove the occur of the one we deleted
|
// Re-attach the other, remove the occurrence of the one we deleted
|
||||||
s().m_watches[Lit(v, false)].push(Watched(indexes[1], WatchType::watch_idx_t));
|
watch_neg_literal(ws, indexes[1]);
|
||||||
|
|
||||||
for (unsigned v2: x1) {
|
for (unsigned v2: x1) {
|
||||||
sat::literal l(v2, false);
|
sat::literal l(v2, false);
|
||||||
|
@ -682,17 +685,17 @@ namespace xr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (clash_num > 1 || x0.m_detached || x1.m_detached) {
|
} else if (clash_num > 1 || x0.m_detached || x1.m_detached) {
|
||||||
//add back to ws, can't do much
|
// add back to watch-list, can't do much
|
||||||
ws.push(Watched(indexes[0], WatchType::watch_idx_t));
|
watch_neg_literal(ws, indexes[0]);
|
||||||
ws.push(Watched(indexes[1], WatchType::watch_idx_t));
|
watch_neg_literal(ws, indexes[1]);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
m_occ_cnt[v] -= 2;
|
m_occ_cnt[v] -= 2;
|
||||||
SASSERT(m_occ_cnt[v] == 0);
|
SASSERT(m_occ_cnt[v] == 0);
|
||||||
|
|
||||||
xor_clause x_new(m_tmp_vars_xor_two, x0.m_rhs ^ x1.m_rhs, clash_var);
|
xor_clause x_new(m_tmp_vars_xor_two, x0.m_rhs ^ x1.m_rhs, clash_var);
|
||||||
x_new.merge_clash(x0, m_visited);
|
x_new.merge_clash(x0, m_visited, s().num_vars());
|
||||||
x_new.merge_clash(x1, m_visited);
|
x_new.merge_clash(x1, m_visited, s().num_vars());
|
||||||
|
|
||||||
TRACE("xor", tout
|
TRACE("xor", tout
|
||||||
<< "x1: " << x0 << " -- at idx: " << indexes[0] << "\n"
|
<< "x1: " << x0 << " -- at idx: " << indexes[0] << "\n"
|
||||||
|
@ -702,9 +705,9 @@ namespace xr {
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
xors.push_back(x_new);
|
xors.push_back(x_new);
|
||||||
for(uint32_t v2: x_new) {
|
for (bool_var v2 : x_new) {
|
||||||
sat::literal l(v2, false);
|
sat::literal l(v2, false);
|
||||||
s().watches[l].push(Watched(xors.size()-1, WatchType::watch_idx_t));
|
watch_neg_literal(l, xors.size() - 1);
|
||||||
SASSERT(m_occ_cnt[l.var()] >= 1);
|
SASSERT(m_occ_cnt[l.var()] >= 1);
|
||||||
if (m_occ_cnt[l.var()] == 2 && !s().is_visited(l.var())) {
|
if (m_occ_cnt[l.var()] == 2 && !s().is_visited(l.var())) {
|
||||||
m_interesting.push_back(l.var());
|
m_interesting.push_back(l.var());
|
||||||
|
@ -717,19 +720,68 @@ namespace xr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Clear
|
// Clear
|
||||||
for (const bool_var l : m_occurrences) {
|
for (const bool_var l : m_occurrences) {
|
||||||
m_occ_cnt[l] = 0;
|
m_occ_cnt[l] = 0;
|
||||||
}
|
}
|
||||||
m_occurrences.clear();
|
m_occurrences.clear();
|
||||||
|
|
||||||
clean_occur_from_idx_types_only_smudged();
|
// TODO: Implement
|
||||||
clean_xors_from_empty(xors);
|
//clean_occur_from_idx_types_only_smudged();
|
||||||
#endif
|
//clean_xors_from_empty(xors);
|
||||||
|
|
||||||
return !s().inconsistent();
|
return !s().inconsistent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned solver::xor_two(xor_clause const* x1_p, xor_clause const* x2_p, bool_var& clash_var) {
|
||||||
|
m_tmp_vars_xor_two.clear();
|
||||||
|
if (x1_p->size() > x2_p->size())
|
||||||
|
std::swap(x1_p, x2_p);
|
||||||
|
|
||||||
|
const xor_clause& x1 = *x1_p;
|
||||||
|
const xor_clause& x2 = *x2_p;
|
||||||
|
|
||||||
|
m_visited.init_visited(s().num_vars(), 2);
|
||||||
|
|
||||||
|
unsigned clash_num = 0;
|
||||||
|
for (bool_var v : x1) {
|
||||||
|
SASSERT(!m_visited.is_visited(v));
|
||||||
|
m_visited.inc_visited(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_var i_x2;
|
||||||
|
bool early_abort = false;
|
||||||
|
for (i_x2 = 0; i_x2 < x2.size(); i_x2++) {
|
||||||
|
bool_var v = x2[i_x2];
|
||||||
|
SASSERT(m_visited.num_visited(v) < 2);
|
||||||
|
if (!m_visited.is_visited(v)) {
|
||||||
|
m_tmp_vars_xor_two.push_back(v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clash_var = v;
|
||||||
|
if (clash_num > 0 && clash_num != i_x2) {
|
||||||
|
//early abort, it's never gonna be good
|
||||||
|
clash_num++;
|
||||||
|
early_abort = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
clash_num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_visited.inc_visited(v, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!early_abort) {
|
||||||
|
for (bool_var v: x1) {
|
||||||
|
if (m_visited.num_visited(v) < 2) {
|
||||||
|
m_tmp_vars_xor_two.push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clash_num;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream& solver::display_justification(std::ostream& out, sat::ext_justification_idx idx) const {
|
std::ostream& solver::display_justification(std::ostream& out, sat::ext_justification_idx idx) const {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ namespace xr {
|
||||||
// and we need the list of occurrences
|
// and we need the list of occurrences
|
||||||
unsigned_vector m_occ_cnt;
|
unsigned_vector m_occ_cnt;
|
||||||
bool_var_vector m_interesting;
|
bool_var_vector m_interesting;
|
||||||
|
bool_var_vector m_tmp_vars_xor_two;
|
||||||
|
|
||||||
void force_push();
|
void force_push();
|
||||||
void push_core();
|
void push_core();
|
||||||
|
@ -70,8 +71,34 @@ namespace xr {
|
||||||
|
|
||||||
void add_xor_clause(const sat::literal_vector& lits, bool rhs, const bool attach);
|
void add_xor_clause(const sat::literal_vector& lits, bool rhs, const bool attach);
|
||||||
|
|
||||||
|
unsigned xor_two(xor_clause const* x1_p, xor_clause const* x2_p, bool_var& clash_var);
|
||||||
|
|
||||||
bool inconsistent() const { return s().inconsistent(); }
|
bool inconsistent() const { return s().inconsistent(); }
|
||||||
|
|
||||||
|
// TODO: CMS watches the literals directly; Z3 their negation. "_neg_" just for now to avoid confusion
|
||||||
|
bool is_neg_watched(sat::watch_list& l, size_t idx) const {
|
||||||
|
return l.contains(sat::watched((sat::ext_constraint_idx)idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_neg_watched(literal lit, size_t idx) const {
|
||||||
|
return s().get_wlist(lit).contains(sat::watched((sat::ext_constraint_idx)idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
void unwatch_neg_literal(literal lit, size_t idx) {
|
||||||
|
s().get_wlist(lit).erase(sat::watched(idx));
|
||||||
|
SASSERT(!is_neg_watched(lit, idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
void watch_neg_literal(sat::watch_list& l, size_t idx) {
|
||||||
|
SASSERT(!is_neg_watched(l, idx));
|
||||||
|
l.push_back(sat::watched(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
void watch_neg_literal(literal lit, size_t idx) {
|
||||||
|
watch_neg_literal(s().get_wlist(lit), idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
solver(euf::solver& ctx);
|
solver(euf::solver& ctx);
|
||||||
solver(ast_manager& m, euf::theory_id id);
|
solver(ast_manager& m, euf::theory_id id);
|
||||||
|
|
|
@ -41,8 +41,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void mark_visited(unsigned v) { m_visited[v] = m_visited_begin + 1; }
|
void mark_visited(unsigned v) { m_visited[v] = m_visited_begin + 1; }
|
||||||
void inc_visited(unsigned v) {
|
void inc_visited(unsigned v) { inc_visited(v, 1); }
|
||||||
m_visited[v] = std::min(m_visited_end, std::max(m_visited_begin, m_visited[v]) + 1);
|
void inc_visited(unsigned v, unsigned by) {
|
||||||
|
m_visited[v] = std::min(m_visited_end, std::max(m_visited_begin, m_visited[v]) + by);
|
||||||
}
|
}
|
||||||
bool is_visited(unsigned v) const { return m_visited[v] > m_visited_begin; }
|
bool is_visited(unsigned v) const { return m_visited[v] > m_visited_begin; }
|
||||||
unsigned num_visited(unsigned v) const { return std::max(m_visited_begin, m_visited[v]) - m_visited_begin; }
|
unsigned num_visited(unsigned v) const { return std::max(m_visited_begin, m_visited[v]) - m_visited_begin; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue