3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-06 22:23:22 +00:00

Bugfix + refactoring

This commit is contained in:
Clemens Eisenhofer 2022-12-04 15:46:58 +01:00
parent a7f3ef2c8c
commit c0f44af643
5 changed files with 45 additions and 58 deletions

View file

@ -29,11 +29,12 @@ using namespace xr;
static const unsigned unassigned_col = UINT32_MAX; static const unsigned unassigned_col = UINT32_MAX;
///returns popcnt ///returns popcnt
unsigned PackedRow::find_watchVar( unsigned PackedRow::population_cnt(
literal_vector& tmp_clause, literal_vector &tmp_clause,
const unsigned_vector& col_to_var, const unsigned_vector& col_to_var,
bool_vector &var_has_resp_row, bool_vector &var_has_resp_row,
unsigned& non_resp_var) { unsigned& non_resp_var) {
unsigned popcnt = 0; unsigned popcnt = 0;
non_resp_var = UINT_MAX; non_resp_var = UINT_MAX;
tmp_clause.clear(); tmp_clause.clear();
@ -44,18 +45,14 @@ unsigned PackedRow::find_watchVar(
unsigned var = col_to_var[i]; unsigned var = col_to_var[i];
tmp_clause.push_back(sat::literal(var, false)); tmp_clause.push_back(sat::literal(var, false));
if (!var_has_resp_row[var]) { if (!var_has_resp_row[var])
non_resp_var = var; non_resp_var = var;
} else { else
//What??? WARNING
//This var already has a responsible for it...
//How can it be 1???
std::swap(tmp_clause[0], tmp_clause.back()); std::swap(tmp_clause[0], tmp_clause.back());
} }
} }
}
SASSERT(tmp_clause.size() == popcnt); SASSERT(tmp_clause.size() == popcnt);
SASSERT(popcnt == 0 || var_has_resp_row[ tmp_clause[0].var() ]) ; SASSERT(popcnt == 0 || var_has_resp_row[tmp_clause[0].var()]) ;
return popcnt; return popcnt;
} }
@ -261,6 +258,7 @@ void EGaussian::select_columnorder() {
} }
} }
// Sets up some of the required datastructures to apply initial elimination (e.g., like the matrix itself and an empty list of gaussian watchlist)
void EGaussian::fill_matrix() { void EGaussian::fill_matrix() {
var_to_col.clear(); var_to_col.clear();
@ -268,9 +266,9 @@ void EGaussian::fill_matrix() {
select_columnorder(); select_columnorder();
num_rows = m_xorclauses.size(); num_rows = m_xorclauses.size();
num_cols = col_to_var.size(); num_cols = col_to_var.size();
if (num_rows == 0 || num_cols == 0) { if (num_rows == 0 || num_cols == 0)
return; return;
}
mat.resize(num_rows, num_cols); // initial gaussian matrix mat.resize(num_rows, num_cols); // initial gaussian matrix
for (unsigned row = 0; row < num_rows; row++) { for (unsigned row = 0; row < num_rows; row++) {
@ -294,12 +292,14 @@ void EGaussian::fill_matrix() {
satisfied_xors.resize(num_rows, false); satisfied_xors.resize(num_rows, false);
} }
// deletes all gaussian watches from the matrix for all variables
void EGaussian::delete_gauss_watch_this_matrix() { void EGaussian::delete_gauss_watch_this_matrix() {
for (unsigned i = 0; i < m_solver.m_gwatches.size(); i++) for (unsigned i = 0; i < m_solver.m_gwatches.size(); i++)
clear_gwatches(i); clear_gwatches(i);
} }
void EGaussian::clear_gwatches(unsigned var) { // deletes all gaussian watches from the matrix for the given variable
void EGaussian::clear_gwatches(bool_var var) {
//if there is only one matrix, don't check, just empty it //if there is only one matrix, don't check, just empty it
if (m_solver.m_gmatrices.empty()) { if (m_solver.m_gmatrices.empty()) {
m_solver.m_gwatches[var].clear(); m_solver.m_gwatches[var].clear();
@ -345,7 +345,7 @@ bool EGaussian::full_init(bool& created) {
return false; return false;
case gret::prop: case gret::prop:
SASSERT(m_solver.m_num_scopes == 0); SASSERT(m_solver.m_num_scopes == 0);
m_solver.s().propagate(false); // TODO: Can we really do this here? m_solver.s().propagate(false);
if (inconsistent()) { if (inconsistent()) {
TRACE("xor", tout << "eliminate & adjust matrix during init lead to UNSAT\n";); TRACE("xor", tout << "eliminate & adjust matrix during init lead to UNSAT\n";);
return false; return false;
@ -361,7 +361,7 @@ bool EGaussian::full_init(bool& created) {
TRACE("xor", tout << "initialised matrix " << matrix_no << "\n"); TRACE("xor", tout << "initialised matrix " << matrix_no << "\n");
xor_reasons.resize(num_rows); xor_reasons.resize(num_rows);
unsigned num_64b = num_cols/64+(bool)(num_cols%64); unsigned num_64b = num_cols / 64 + (bool)(num_cols % 64);
for (auto& x: tofree) for (auto& x: tofree)
memory::deallocate(x); memory::deallocate(x);
@ -394,11 +394,11 @@ static void print_matrix(ostream& out, PackedMatrix& mat) {
for(int i = 0; i < row.get_size() * 64; i++) { for(int i = 0; i < row.get_size() * 64; i++) {
out << (int)row[i]; out << (int)row[i];
} }
out << " -- rhs: " << row.rhs() << " -- row:" << rowIdx << "\n"; out << " -- rhs: " << row.rhs() << " -- row: " << rowIdx << "\n";
} }
out << "\n";
} }
// Applies Gaussian-Jordan elimination (search level). This function does not add conflicts/propagate/... Just reduces the matrix
void EGaussian::eliminate() { void EGaussian::eliminate() {
// TODO: Why twice? gauss_jordan_elim // TODO: Why twice? gauss_jordan_elim
unsigned end_row = num_rows; unsigned end_row = num_rows;
@ -406,6 +406,8 @@ void EGaussian::eliminate() {
unsigned row_i = 0; unsigned row_i = 0;
unsigned col = 0; unsigned col = 0;
//print_matrix(std::cout, mat);
//std::cout << std::endl;
TRACE("xor", print_matrix(tout, mat)); TRACE("xor", print_matrix(tout, mat));
// Gauss-Jordan Elimination // Gauss-Jordan Elimination
@ -441,7 +443,10 @@ void EGaussian::eliminate() {
} }
col++; col++;
TRACE("xor", print_matrix(tout, mat)); TRACE("xor", print_matrix(tout, mat));
//print_matrix(std::cout, mat);
//std::cout << std::endl;
} }
//std::cout << "-------------" << std::endl;
} }
literal_vector* EGaussian::get_reason(unsigned row, int& out_ID) { literal_vector* EGaussian::get_reason(unsigned row, int& out_ID) {
@ -467,6 +472,7 @@ literal_vector* EGaussian::get_reason(unsigned row, int& out_ID) {
return &to_fill; return &to_fill;
} }
// Creates binary clauses, assigns variables, adds conflicts based on the (reduced) gaussian-matrix. Also sets up the gaussian watchlist
gret EGaussian::init_adjust_matrix() { gret EGaussian::init_adjust_matrix() {
SASSERT(m_solver.s().at_search_lvl()); SASSERT(m_solver.s().at_search_lvl());
SASSERT(row_to_var_non_resp.empty()); SASSERT(row_to_var_non_resp.empty());
@ -479,7 +485,7 @@ gret EGaussian::init_adjust_matrix() {
if (row_i >= num_rows) if (row_i >= num_rows)
break; break;
unsigned non_resp_var; unsigned non_resp_var;
unsigned popcnt = row.find_watchVar(tmp_clause, col_to_var, var_has_resp_row, non_resp_var); unsigned popcnt = row.population_cnt(tmp_clause, col_to_var, var_has_resp_row, non_resp_var);
switch (popcnt) { switch (popcnt) {
@ -610,6 +616,7 @@ bool EGaussian::find_truths(
unsigned var, unsigned var,
unsigned row_n, unsigned row_n,
gauss_data& gqd) { gauss_data& gqd) {
SASSERT(gqd.status != gauss_res::confl); SASSERT(gqd.status != gauss_res::confl);
SASSERT(initialized); SASSERT(initialized);

View file

@ -398,7 +398,7 @@ namespace xr {
} }
// using find nonbasic and basic value // using find nonbasic and basic value
unsigned find_watchVar( unsigned population_cnt(
sat::literal_vector& tmp_clause, sat::literal_vector& tmp_clause,
const unsigned_vector& col_to_var, const unsigned_vector& col_to_var,
bool_vector &var_has_resp_row, bool_vector &var_has_resp_row,
@ -432,6 +432,7 @@ namespace xr {
} }
}; };
// A gaussian matrix (only the very basic data)
class PackedMatrix { class PackedMatrix {
public: public:
PackedMatrix() { } PackedMatrix() { }
@ -556,6 +557,7 @@ namespace xr {
int numCols = 0; int numCols = 0;
}; };
// A single gaussian matrix
class EGaussian { class EGaussian {
public: public:
EGaussian( EGaussian(
@ -596,7 +598,7 @@ namespace xr {
xr::solver& m_solver; // original sat solver xr::solver& m_solver; // original sat solver
//Cleanup //Cleanup
void clear_gwatches(unsigned var); void clear_gwatches(bool_var var);
void delete_gauss_watch_this_matrix(); void delete_gauss_watch_this_matrix();
void delete_gausswatch(unsigned row_n); void delete_gausswatch(unsigned row_n);

View file

@ -57,11 +57,9 @@ namespace xr {
m_xor.move_xors_without_connecting_vars_to_unused(); m_xor.move_xors_without_connecting_vars_to_unused();
m_xor.clean_equivalent_xors(m_xor.m_xorclauses); m_xor.clean_equivalent_xors(m_xor.m_xorclauses);
for (const auto& c : m_xor.m_xorclauses_unused){ for (const auto& c : m_xor.m_xorclauses_unused)
for (const auto& v : c) { for (const auto& v : c)
clash_vars_unused.insert(v); clash_vars_unused.insert(v);
}
}
if (m_xor.m_xorclauses.size() < m_sat.get_config().m_xor_gauss_min_clauses) { if (m_xor.m_xorclauses.size() < m_sat.get_config().m_xor_gauss_min_clauses) {
can_detach = false; can_detach = false;

View file

@ -146,6 +146,8 @@ namespace xr {
sat::justification solver::gauss_jordan_elim(const sat::literal p, const unsigned currLevel) { sat::justification solver::gauss_jordan_elim(const sat::literal p, const unsigned currLevel) {
if (m_gmatrices.empty()) if (m_gmatrices.empty())
return sat::justification(-1); return sat::justification(-1);
m_gwatches.resize(s().num_vars());
for (unsigned i = 0; i < m_gqueuedata.size(); i++) { for (unsigned i = 0; i < m_gqueuedata.size(); i++) {
if (m_gqueuedata[i].disabled || !m_gmatrices[i]->is_initialized()) continue; if (m_gqueuedata[i].disabled || !m_gmatrices[i]->is_initialized()) continue;
m_gqueuedata[i].reset(); m_gqueuedata[i].reset();
@ -156,11 +158,11 @@ namespace xr {
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()];
unsigned i = 0, j = 0; unsigned i = 0, j = 0;
const unsigned end = ws.size(); unsigned end = ws.size();
for (; i < end; i++) { for (; i < end; i++) {
const unsigned matrix_num = ws[i].matrix_num; unsigned matrix_num = ws[i].matrix_num;
const unsigned row_n = ws[i].row_n; unsigned row_n = ws[i].row_n;
if (m_gqueuedata[matrix_num].disabled || !m_gmatrices[matrix_num]->is_initialized()) if (m_gqueuedata[matrix_num].disabled || !m_gmatrices[matrix_num]->is_initialized())
continue; //remove watch and continue continue; //remove watch and continue
@ -169,10 +171,7 @@ namespace xr {
m_gqueuedata[matrix_num].do_eliminate = false; m_gqueuedata[matrix_num].do_eliminate = false;
m_gqueuedata[matrix_num].currLevel = currLevel; m_gqueuedata[matrix_num].currLevel = currLevel;
if (m_gmatrices[matrix_num]->find_truths(ws, i, j, p.var(), row_n, m_gqueuedata[matrix_num])) { if (!m_gmatrices[matrix_num]->find_truths(ws, i, j, p.var(), row_n, m_gqueuedata[matrix_num])) {
continue;
}
else {
confl_in_gauss = true; confl_in_gauss = true;
i++; i++;
break; break;
@ -181,7 +180,7 @@ namespace xr {
for (; i < end; i++) for (; i < end; i++)
ws[j++] = ws[i]; ws[j++] = ws[i];
ws.shrink((unsigned)(i - j)); ws.shrink(j);
for (unsigned g = 0; g < m_gqueuedata.size(); g++) { for (unsigned g = 0; g < m_gqueuedata.size(); g++) {
if (m_gqueuedata[g].disabled || !m_gmatrices[g]->is_initialized()) if (m_gqueuedata[g].disabled || !m_gmatrices[g]->is_initialized())
@ -285,7 +284,7 @@ namespace xr {
return out; return out;
} }
// simplify xors by triggering (unit)propagation until nothing changes anymore // simplify xors based on current assignments by triggering (unit)propagation until nothing changes anymore
bool solver::clean_xor_clauses(vector<xor_clause>& xors) { bool solver::clean_xor_clauses(vector<xor_clause>& xors) {
SASSERT(!inconsistent()); SASSERT(!inconsistent());
@ -416,6 +415,8 @@ namespace xr {
if (!m_xor_clauses_updated/* && (!m_detached_xor_clauses || !assump_contains_xor_clash())*/) if (!m_xor_clauses_updated/* && (!m_detached_xor_clauses || !assump_contains_xor_clash())*/)
return true; return true;
m_gwatches.resize(s().num_vars());
bool can_detach; bool can_detach;
if (!clear_gauss_matrices(false)) if (!clear_gauss_matrices(false))
return false; return false;
@ -575,6 +576,8 @@ namespace xr {
ps.shrink(j); ps.shrink(j);
} }
// Creates bigger xors by gluing together xors (x1 + x2 + x3 = 0 & x3 + x4 + x5 = 0 ==> x1 + x2 + x4 + x5 = 0) and removing the glued variable
// This can be done if the glued variable (x3) occurs in exactly two different xor clauses and nowhere else
bool solver::xor_together_xors(vector<xor_clause>& xors) { bool solver::xor_together_xors(vector<xor_clause>& xors) {
if (xors.empty()) if (xors.empty())
@ -592,7 +595,7 @@ namespace xr {
SASSERT(!s().inconsistent()); SASSERT(!s().inconsistent());
SASSERT(s().at_search_lvl()); SASSERT(s().at_search_lvl());
const size_t origsize = xors.size(); unsigned origsize = xors.size();
SASSERT(m_occurrences.empty()); SASSERT(m_occurrences.empty());

View file

@ -79,29 +79,6 @@ namespace xr {
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);