3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45:31 +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;
///returns popcnt
unsigned PackedRow::find_watchVar(
literal_vector& tmp_clause,
unsigned PackedRow::population_cnt(
literal_vector &tmp_clause,
const unsigned_vector& col_to_var,
bool_vector &var_has_resp_row,
unsigned& non_resp_var) {
unsigned popcnt = 0;
non_resp_var = UINT_MAX;
tmp_clause.clear();
@ -44,18 +45,14 @@ unsigned PackedRow::find_watchVar(
unsigned var = col_to_var[i];
tmp_clause.push_back(sat::literal(var, false));
if (!var_has_resp_row[var]) {
if (!var_has_resp_row[var])
non_resp_var = var;
} else {
//What??? WARNING
//This var already has a responsible for it...
//How can it be 1???
else
std::swap(tmp_clause[0], tmp_clause.back());
}
}
}
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;
}
@ -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() {
var_to_col.clear();
@ -268,9 +266,9 @@ void EGaussian::fill_matrix() {
select_columnorder();
num_rows = m_xorclauses.size();
num_cols = col_to_var.size();
if (num_rows == 0 || num_cols == 0) {
if (num_rows == 0 || num_cols == 0)
return;
}
mat.resize(num_rows, num_cols); // initial gaussian matrix
for (unsigned row = 0; row < num_rows; row++) {
@ -294,12 +292,14 @@ void EGaussian::fill_matrix() {
satisfied_xors.resize(num_rows, false);
}
// deletes all gaussian watches from the matrix for all variables
void EGaussian::delete_gauss_watch_this_matrix() {
for (unsigned i = 0; i < m_solver.m_gwatches.size(); 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 (m_solver.m_gmatrices.empty()) {
m_solver.m_gwatches[var].clear();
@ -345,7 +345,7 @@ bool EGaussian::full_init(bool& created) {
return false;
case gret::prop:
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()) {
TRACE("xor", tout << "eliminate & adjust matrix during init lead to UNSAT\n";);
return false;
@ -361,7 +361,7 @@ bool EGaussian::full_init(bool& created) {
TRACE("xor", tout << "initialised matrix " << matrix_no << "\n");
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)
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++) {
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() {
// TODO: Why twice? gauss_jordan_elim
unsigned end_row = num_rows;
@ -406,6 +406,8 @@ void EGaussian::eliminate() {
unsigned row_i = 0;
unsigned col = 0;
//print_matrix(std::cout, mat);
//std::cout << std::endl;
TRACE("xor", print_matrix(tout, mat));
// Gauss-Jordan Elimination
@ -441,7 +443,10 @@ void EGaussian::eliminate() {
}
col++;
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) {
@ -467,6 +472,7 @@ literal_vector* EGaussian::get_reason(unsigned row, int& out_ID) {
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() {
SASSERT(m_solver.s().at_search_lvl());
SASSERT(row_to_var_non_resp.empty());
@ -479,7 +485,7 @@ gret EGaussian::init_adjust_matrix() {
if (row_i >= num_rows)
break;
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) {
@ -610,6 +616,7 @@ bool EGaussian::find_truths(
unsigned var,
unsigned row_n,
gauss_data& gqd) {
SASSERT(gqd.status != gauss_res::confl);
SASSERT(initialized);

View file

@ -398,7 +398,7 @@ namespace xr {
}
// using find nonbasic and basic value
unsigned find_watchVar(
unsigned population_cnt(
sat::literal_vector& tmp_clause,
const unsigned_vector& col_to_var,
bool_vector &var_has_resp_row,
@ -432,6 +432,7 @@ namespace xr {
}
};
// A gaussian matrix (only the very basic data)
class PackedMatrix {
public:
PackedMatrix() { }
@ -556,6 +557,7 @@ namespace xr {
int numCols = 0;
};
// A single gaussian matrix
class EGaussian {
public:
EGaussian(
@ -596,7 +598,7 @@ namespace xr {
xr::solver& m_solver; // original sat solver
//Cleanup
void clear_gwatches(unsigned var);
void clear_gwatches(bool_var var);
void delete_gauss_watch_this_matrix();
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.clean_equivalent_xors(m_xor.m_xorclauses);
for (const auto& c : m_xor.m_xorclauses_unused){
for (const auto& v : c) {
clash_vars_unused.insert(v);
}
}
for (const auto& c : m_xor.m_xorclauses_unused)
for (const auto& v : c)
clash_vars_unused.insert(v);
if (m_xor.m_xorclauses.size() < m_sat.get_config().m_xor_gauss_min_clauses) {
can_detach = false;

View file

@ -146,6 +146,8 @@ namespace xr {
sat::justification solver::gauss_jordan_elim(const sat::literal p, const unsigned currLevel) {
if (m_gmatrices.empty())
return sat::justification(-1);
m_gwatches.resize(s().num_vars());
for (unsigned i = 0; i < m_gqueuedata.size(); i++) {
if (m_gqueuedata[i].disabled || !m_gmatrices[i]->is_initialized()) continue;
m_gqueuedata[i].reset();
@ -156,11 +158,11 @@ namespace xr {
SASSERT(m_gwatches.size() > p.var());
svector<gauss_watched>& ws = m_gwatches[p.var()];
unsigned i = 0, j = 0;
const unsigned end = ws.size();
unsigned end = ws.size();
for (; i < end; i++) {
const unsigned matrix_num = ws[i].matrix_num;
const unsigned row_n = ws[i].row_n;
unsigned matrix_num = ws[i].matrix_num;
unsigned row_n = ws[i].row_n;
if (m_gqueuedata[matrix_num].disabled || !m_gmatrices[matrix_num]->is_initialized())
continue; //remove watch and continue
@ -169,10 +171,7 @@ namespace xr {
m_gqueuedata[matrix_num].do_eliminate = false;
m_gqueuedata[matrix_num].currLevel = currLevel;
if (m_gmatrices[matrix_num]->find_truths(ws, i, j, p.var(), row_n, m_gqueuedata[matrix_num])) {
continue;
}
else {
if (!m_gmatrices[matrix_num]->find_truths(ws, i, j, p.var(), row_n, m_gqueuedata[matrix_num])) {
confl_in_gauss = true;
i++;
break;
@ -181,7 +180,7 @@ namespace xr {
for (; i < end; i++)
ws[j++] = ws[i];
ws.shrink((unsigned)(i - j));
ws.shrink(j);
for (unsigned g = 0; g < m_gqueuedata.size(); g++) {
if (m_gqueuedata[g].disabled || !m_gmatrices[g]->is_initialized())
@ -285,7 +284,7 @@ namespace xr {
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) {
SASSERT(!inconsistent());
@ -375,7 +374,7 @@ namespace xr {
j = 0;
for (const bool_var& v : x) {
if (s().value(v) != l_undef)
x.m_rhs ^= s().value(v) == l_true;
x.m_rhs ^= s().value(v) == l_true;
else
x[j++] = v;
}
@ -416,6 +415,8 @@ namespace xr {
if (!m_xor_clauses_updated/* && (!m_detached_xor_clauses || !assump_contains_xor_clash())*/)
return true;
m_gwatches.resize(s().num_vars());
bool can_detach;
if (!clear_gauss_matrices(false))
return false;
@ -575,6 +576,8 @@ namespace xr {
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) {
if (xors.empty())
@ -592,7 +595,7 @@ namespace xr {
SASSERT(!s().inconsistent());
SASSERT(s().at_search_lvl());
const size_t origsize = xors.size();
unsigned origsize = xors.size();
SASSERT(m_occurrences.empty());

View file

@ -78,29 +78,6 @@ namespace xr {
bool add_simple_xor_constraint(const xor_clause& constraint);
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:
solver(euf::solver& ctx);