/***********************************************************************************
CryptoMiniSat -- Copyright (c) 2009 Mate Soos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
**************************************************************************************************/
#include "constants.h"
#ifdef USE_GAUSS
#include "Gaussian.h"
#include
#include
#include "Clause.h"
#include
#include "ClauseCleaner.h"
using std::ostream;
using std::cout;
using std::endl;
#ifdef VERBOSE_DEBUG
#include
#endif
static const uint16_t unassigned_col = std::numeric_limits::max();
static const Var unassigned_var = std::numeric_limits::max();
ostream& operator << (ostream& os, const vec& v)
{
for (uint32_t i = 0; i != v.size(); i++) {
if (v[i].sign()) os << "-";
os << v[i].var()+1 << " ";
}
return os;
}
Gaussian::Gaussian(Solver& _solver, const GaussianConfig& _config, const uint _matrix_no, const vector& _xorclauses) :
solver(_solver)
, config(_config)
, matrix_no(_matrix_no)
, xorclauses(_xorclauses)
, messed_matrix_vars_since_reversal(true)
, gauss_last_level(0)
, disabled(false)
, useful_prop(0)
, useful_confl(0)
, called(0)
, unit_truths(0)
{
}
Gaussian::~Gaussian()
{
for (uint i = 0; i < clauses_toclear.size(); i++)
clauseFree(clauses_toclear[i].first);
}
inline void Gaussian::set_matrixset_to_cur()
{
uint level = solver.decisionLevel() / config.only_nth_gauss_save;
assert(level <= matrix_sets.size());
if (level == matrix_sets.size())
matrix_sets.push_back(cur_matrixset);
else
matrix_sets[level] = cur_matrixset;
}
const bool Gaussian::full_init()
{
assert(solver.ok);
if (!should_init()) return true;
reset_stats();
uint32_t last_trail_size = solver.trail.size();
bool do_again_gauss = true;
while (do_again_gauss) {
do_again_gauss = false;
solver.clauseCleaner->cleanClauses(solver.xorclauses, ClauseCleaner::xorclauses);
if (!solver.ok) return false;
init();
Clause* confl;
gaussian_ret g = gaussian(confl);
switch (g) {
case unit_conflict:
case conflict:
solver.ok = false;
return false;
case unit_propagation:
case propagation:
unit_truths += last_trail_size - solver.trail.size();
do_again_gauss = true;
solver.ok = (solver.propagate() == NULL);
if (!solver.ok) return false;
break;
case nothing:
break;
}
}
return true;
}
void Gaussian::init()
{
assert(solver.decisionLevel() == 0);
fill_matrix(cur_matrixset);
if (!cur_matrixset.num_rows || !cur_matrixset.num_cols) {
disabled = true;
badlevel = 0;
return;
}
matrix_sets.clear();
matrix_sets.push_back(cur_matrixset);
gauss_last_level = solver.trail.size();
messed_matrix_vars_since_reversal = false;
badlevel = UINT_MAX;
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Gaussian init finished." << endl;
#endif
}
uint Gaussian::select_columnorder(vector& var_to_col, matrixset& origMat)
{
var_to_col.resize(solver.nVars(), unassigned_col);
uint num_xorclauses = 0;
for (uint32_t i = 0; i != xorclauses.size(); i++) {
XorClause& c = *xorclauses[i];
if (c.removed()) continue;
num_xorclauses++;
for (uint i2 = 0; i2 < c.size(); i2++) {
assert(solver.assigns[c[i2].var()].isUndef());
var_to_col[c[i2].var()] = unassigned_col - 1;
}
}
uint largest_used_var = 0;
for (uint i = 0; i < var_to_col.size(); i++)
if (var_to_col[i] != unassigned_col)
largest_used_var = i;
var_to_col.resize(largest_used_var + 1);
var_is_in.resize(var_to_col.size(), 0);
origMat.var_is_set.resize(var_to_col.size(), 0);
origMat.col_to_var.clear();
vector vars(solver.nVars());
if (!config.orderCols) {
for (uint32_t i = 0; i < solver.nVars(); i++) {
vars.push_back(i);
}
std::random_shuffle(vars.begin(), vars.end());
}
Heap order_heap(solver.order_heap);
uint32_t iterReduceIt = 0;
while ((config.orderCols && !order_heap.empty()) || (!config.orderCols && iterReduceIt < vars.size()))
{
Var v;
if (config.orderCols) v = order_heap.removeMin();
else v = vars[iterReduceIt++];
if (var_to_col[v] == 1) {
#ifdef DEBUG_GAUSS
vector::iterator it =
std::find(origMat.col_to_var.begin(), origMat.col_to_var.end(), v);
assert(it == origMat.col_to_var.end());
#endif
origMat.col_to_var.push_back(v);
var_to_col[v] = origMat.col_to_var.size()-1;
var_is_in.setBit(v);
}
}
//for the ones that were not in the order_heap, but are marked in var_to_col
for (uint v = 0; v != var_to_col.size(); v++) {
if (var_to_col[v] == unassigned_col - 1) {
origMat.col_to_var.push_back(v);
var_to_col[v] = origMat.col_to_var.size() -1;
var_is_in.setBit(v);
}
}
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")col_to_var:";
std::copy(origMat.col_to_var.begin(), origMat.col_to_var.end(), std::ostream_iterator(cout, ","));
cout << endl;
#endif
return num_xorclauses;
}
void Gaussian::fill_matrix(matrixset& origMat)
{
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Filling matrix" << endl;
#endif
vector var_to_col;
origMat.num_rows = select_columnorder(var_to_col, origMat);
origMat.num_cols = origMat.col_to_var.size();
col_to_var_original = origMat.col_to_var;
changed_rows.resize(origMat.num_rows);
memset(&changed_rows[0], 0, sizeof(char)*changed_rows.size());
origMat.last_one_in_col.resize(origMat.num_cols);
std::fill(origMat.last_one_in_col.begin(), origMat.last_one_in_col.end(), origMat.num_rows);
origMat.first_one_in_row.resize(origMat.num_rows);
origMat.removeable_cols = 0;
origMat.least_column_changed = -1;
origMat.matrix.resize(origMat.num_rows, origMat.num_cols);
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")matrix size:" << origMat.num_rows << "," << origMat.num_cols << endl;
#endif
uint matrix_row = 0;
for (uint32_t i = 0; i != xorclauses.size(); i++) {
const XorClause& c = *xorclauses[i];
if (c.removed()) continue;
origMat.matrix.getVarsetAt(matrix_row).set(c, var_to_col, origMat.num_cols);
origMat.matrix.getMatrixAt(matrix_row).set(c, var_to_col, origMat.num_cols);
matrix_row++;
}
assert(origMat.num_rows == matrix_row);
}
void Gaussian::update_matrix_col(matrixset& m, const Var var, const uint col)
{
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Updating matrix var " << var+1 << " (col " << col << ", m.last_one_in_col[col]: " << m.last_one_in_col[col] << ")" << endl;
cout << "m.num_rows:" << m.num_rows << endl;
#endif
#ifdef DEBUG_GAUSS
assert(col < m.num_cols);
#endif
m.least_column_changed = std::min(m.least_column_changed, (int)col);
PackedMatrix::iterator this_row = m.matrix.beginMatrix();
uint row_num = 0;
if (solver.assigns[var].getBool()) {
for (uint end = m.last_one_in_col[col]; row_num != end; ++this_row, row_num++) {
if ((*this_row)[col]) {
changed_rows[row_num] = true;
(*this_row).invert_is_true();
(*this_row).clearBit(col);
}
}
} else {
for (uint end = m.last_one_in_col[col]; row_num != end; ++this_row, row_num++) {
if ((*this_row)[col]) {
changed_rows[row_num] = true;
(*this_row).clearBit(col);
}
}
}
#ifdef DEBUG_GAUSS
bool c = false;
for(PackedMatrix::iterator r = m.matrix.beginMatrix(), end = r + m.matrix.getSize(); r != end; ++r)
c |= (*r)[col];
assert(!c);
#endif
m.removeable_cols++;
m.col_to_var[col] = unassigned_var;
m.var_is_set.setBit(var);
}
void Gaussian::update_matrix_by_col_all(matrixset& m)
{
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Updating matrix." << endl;
print_matrix(m);
uint num_updated = 0;
#endif
#ifdef DEBUG_GAUSS
assert(nothing_to_propagate(cur_matrixset));
assert(solver.decisionLevel() == 0 || check_last_one_in_cols(m));
#endif
memset(&changed_rows[0], 0, sizeof(char)*changed_rows.size());
uint last = 0;
uint col = 0;
for (const Var *it = &m.col_to_var[0], *end = it + m.num_cols; it != end; col++, it++) {
if (*it != unassigned_var && solver.assigns[*it].isDef()) {
update_matrix_col(m, *it, col);
last++;
#ifdef VERBOSE_DEBUG
num_updated++;
#endif
} else
last = 0;
}
m.num_cols -= last;
#ifdef DEBUG_GAUSS
check_matrix_against_varset(m.matrix, m);
#endif
#ifdef VERBOSE_DEBUG
cout << "Matrix update finished, updated " << num_updated << " cols" << endl;
print_matrix(m);
#endif
/*cout << "num_rows:" << m.num_rows;
cout << " num_rows diff:" << origMat.num_rows - m.num_rows << endl;
cout << "num_cols:" << col_to_var_original.size();
cout << " num_cols diff:" << col_to_var_original.size() - m.col_to_var.size() << endl;
cout << "removeable cols:" << m.removeable_cols << endl;*/
}
inline void Gaussian::update_last_one_in_col(matrixset& m)
{
for (uint16_t* i = &m.last_one_in_col[0]+m.last_one_in_col.size()-1, *end = &m.last_one_in_col[0]-1; i != end && *i >= m.num_rows; i--)
*i = m.num_rows;
}
Gaussian::gaussian_ret Gaussian::gaussian(Clause*& confl)
{
if (solver.decisionLevel() >= badlevel)
return nothing;
if (messed_matrix_vars_since_reversal) {
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")matrix needs copy before update" << endl;
#endif
const uint level = solver.decisionLevel() / config.only_nth_gauss_save;
assert(level < matrix_sets.size());
cur_matrixset = matrix_sets[level];
}
update_last_one_in_col(cur_matrixset);
update_matrix_by_col_all(cur_matrixset);
messed_matrix_vars_since_reversal = false;
gauss_last_level = solver.trail.size();
badlevel = UINT_MAX;
propagatable_rows.clear();
uint conflict_row = UINT_MAX;
uint last_row = eliminate(cur_matrixset, conflict_row);
#ifdef DEBUG_GAUSS
check_matrix_against_varset(cur_matrixset.matrix, cur_matrixset);
#endif
gaussian_ret ret;
//There is no early abort, so this is unneeded
/*if (conflict_row != UINT_MAX) {
uint maxlevel = UINT_MAX;
uint size = UINT_MAX;
uint best_row = UINT_MAX;
analyse_confl(cur_matrixset, conflict_row, maxlevel, size, best_row);
ret = handle_matrix_confl(confl, cur_matrixset, size, maxlevel, best_row);
} else {*/
ret = handle_matrix_prop_and_confl(cur_matrixset, last_row, confl);
//}
#ifdef DEBUG_GAUSS
assert(ret == conflict || nothing_to_propagate(cur_matrixset));
#endif
if (!cur_matrixset.num_cols || !cur_matrixset.num_rows) {
badlevel = solver.decisionLevel();
return nothing;
}
if (ret == nothing &&
solver.decisionLevel() % config.only_nth_gauss_save == 0)
set_matrixset_to_cur();
#ifdef VERBOSE_DEBUG
if (ret == nothing)
cout << "(" << matrix_no << ")Useless. ";
else
cout << "(" << matrix_no << ")Useful. ";
cout << "(" << matrix_no << ")Useful prop in " << ((double)useful_prop/(double)called)*100.0 << "%" << endl;
cout << "(" << matrix_no << ")Useful confl in " << ((double)useful_confl/(double)called)*100.0 << "%" << endl;
#endif
return ret;
}
uint Gaussian::eliminate(matrixset& m, uint& conflict_row)
{
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")";
cout << "Starting elimination" << endl;
cout << "m.least_column_changed:" << m.least_column_changed << endl;
print_last_one_in_cols(m);
uint number_of_row_additions = 0;
uint no_exchanged = 0;
#endif
if (m.least_column_changed == INT_MAX) {
#ifdef VERBOSE_DEBUG
cout << "Nothing to eliminate" << endl;
#endif
return m.num_rows;
}
#ifdef DEBUG_GAUSS
assert(solver.decisionLevel() == 0 || check_last_one_in_cols(m));
#endif
uint i = 0;
uint j = (config.iterativeReduce) ? m.least_column_changed + 1 : 0;
PackedMatrix::iterator beginIt = m.matrix.beginMatrix();
PackedMatrix::iterator rowIt = m.matrix.beginMatrix();
#ifdef DEBUG_GAUSS
check_first_one_in_row(m, j);
#endif
if (j) {
uint16_t until = std::min(m.last_one_in_col[m.least_column_changed] - 1, (int)m.num_rows);
if (j-1 > m.first_one_in_row[m.num_rows-1])
until = m.num_rows;
for (;i != until; i++, ++rowIt) if (changed_rows[i] && (*rowIt).popcnt_is_one(m.first_one_in_row[i]))
propagatable_rows.push(i);
}
#ifdef VERBOSE_DEBUG
cout << "At while() start: i,j = " << i << ", " << j << endl;
cout << "num_rows:" << m.num_rows << " num_cols:" << m.num_cols << endl;
#endif
if (j > m.num_cols) {
#ifdef VERBOSE_DEBUG
cout << "Going straight to finish" << endl;
#endif
goto finish;
}
#ifdef DEBUG_GAUSS
assert(i <= m.num_rows && j <= m.num_cols);
#endif
while (i != m.num_rows && j != m.num_cols) {
//Find pivot in column j, starting in row i:
if (m.col_to_var[j] == unassigned_var) {
j++;
continue;
}
PackedMatrix::iterator this_matrix_row = rowIt;
PackedMatrix::iterator end = beginIt + m.last_one_in_col[j];
for (; this_matrix_row != end; ++this_matrix_row) {
if ((*this_matrix_row)[j])
break;
}
if (this_matrix_row != end) {
//swap rows i and maxi, but do not change the value of i;
if (this_matrix_row != rowIt) {
#ifdef VERBOSE_DEBUG
no_exchanged++;
#endif
//Would early abort, but would not find the best conflict (and would be expensive)
//if (matrix_row_i.is_true() && matrix_row_i.isZero()) {
// conflict_row = i;
// return 0;
//}
(*rowIt).swapBoth(*this_matrix_row);
}
#ifdef DEBUG_GAUSS
assert(m.matrix.getMatrixAt(i).popcnt(j) == m.matrix.getMatrixAt(i).popcnt());
assert(m.matrix.getMatrixAt(i)[j]);
#endif
if ((*rowIt).popcnt_is_one(j))
propagatable_rows.push(i);
//Now A[i,j] will contain the old value of A[maxi,j];
++this_matrix_row;
for (; this_matrix_row != end; ++this_matrix_row) if ((*this_matrix_row)[j]) {
//subtract row i from row u;
//Now A[u,j] will be 0, since A[u,j] - A[i,j] = A[u,j] -1 = 0.
#ifdef VERBOSE_DEBUG
number_of_row_additions++;
#endif
(*this_matrix_row).xorBoth(*rowIt);
//Would early abort, but would not find the best conflict (and would be expensive)
//if (it->is_true() &&it->isZero()) {
// conflict_row = i2;
// return 0;
//}
}
m.first_one_in_row[i] = j;
i++;
++rowIt;
m.last_one_in_col[j] = i;
} else {
m.first_one_in_row[i] = j;
m.last_one_in_col[j] = i + 1;
}
j++;
}
finish:
m.least_column_changed = INT_MAX;
#ifdef VERBOSE_DEBUG
cout << "Finished elimination" << endl;
cout << "Returning with i,j:" << i << ", " << j << "(" << m.num_rows << ", " << m.num_cols << ")" << endl;
print_matrix(m);
print_last_one_in_cols(m);
cout << "(" << matrix_no << ")Exchanged:" << no_exchanged << " row additions:" << number_of_row_additions << endl;
#endif
#ifdef DEBUG_GAUSS
assert(check_last_one_in_cols(m));
uint row = 0;
uint col = 0;
for (; col < m.num_cols && row < m.num_rows && row < i ; col++) {
assert(m.matrix.getMatrixAt(row).popcnt() == m.matrix.getMatrixAt(row).popcnt(col));
assert(!(m.col_to_var[col] == unassigned_var && m.matrix.getMatrixAt(row)[col]));
if (m.col_to_var[col] == unassigned_var || !m.matrix.getMatrixAt(row)[col]) {
#ifdef VERBOSE_DEBUG
cout << "row:" << row << " col:" << col << " m.last_one_in_col[col]-1: " << m.last_one_in_col[col]-1 << endl;
#endif
assert(m.col_to_var[col] == unassigned_var || std::min((uint16_t)(m.last_one_in_col[col]-1), m.num_rows) == row);
continue;
}
row++;
}
#endif
return i;
}
Gaussian::gaussian_ret Gaussian::handle_matrix_confl(Clause*& confl, const matrixset& m, const uint size, const uint maxlevel, const uint best_row)
{
assert(best_row != UINT_MAX);
m.matrix.getVarsetAt(best_row).fill(tmp_clause, solver.assigns, col_to_var_original);
confl = (Clause*)XorClause_new(tmp_clause, false, solver.learnt_clause_group++);
Clause& cla = *confl;
#ifdef STATS_NEEDED
if (solver.dynamic_behaviour_analysis)
solver.logger.set_group_name(confl->getGroup(), "learnt gauss clause");
#endif
if (cla.size() <= 1) {
solver.ok = false;
return unit_conflict;
}
assert(cla.size() >= 2);
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Found conflict:";
cla.plainPrint();
#endif
if (maxlevel != solver.decisionLevel()) {
#ifdef STATS_NEEDED
if (solver.dynamic_behaviour_analysis)
solver.logger.conflict(Logger::gauss_confl_type, maxlevel, confl->getGroup(), *confl);
#endif
solver.cancelUntil(maxlevel);
}
const uint curr_dec_level = solver.decisionLevel();
assert(maxlevel == curr_dec_level);
uint maxsublevel = 0;
uint maxsublevel_at = UINT_MAX;
for (uint i = 0, size = cla.size(); i != size; i++) if (solver.level[cla[i].var()] == (int32_t)curr_dec_level) {
uint tmp = find_sublevel(cla[i].var());
if (tmp >= maxsublevel) {
maxsublevel = tmp;
maxsublevel_at = i;
}
}
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ") || Sublevel of confl: " << maxsublevel << " (due to var:" << cla[maxsublevel_at].var()-1 << ")" << endl;
#endif
Lit tmp(cla[maxsublevel_at]);
cla[maxsublevel_at] = cla[1];
cla[1] = tmp;
cancel_until_sublevel(maxsublevel+1);
messed_matrix_vars_since_reversal = true;
return conflict;
}
Gaussian::gaussian_ret Gaussian::handle_matrix_prop_and_confl(matrixset& m, uint last_row, Clause*& confl)
{
int32_t maxlevel = std::numeric_limits::max();
uint size = UINT_MAX;
uint best_row = UINT_MAX;
for (uint row = last_row; row != m.num_rows; row++) {
#ifdef DEBUG_GAUSS
assert(m.matrix.getMatrixAt(row).isZero());
#endif
if (m.matrix.getMatrixAt(row).is_true())
analyse_confl(m, row, maxlevel, size, best_row);
}
if (maxlevel != std::numeric_limits::max())
return handle_matrix_confl(confl, m, size, maxlevel, best_row);
#ifdef DEBUG_GAUSS
assert(check_no_conflict(m));
assert(last_row == 0 || !m.matrix.getMatrixAt(last_row-1).isZero());
#endif
#ifdef VERBOSE_DEBUG
cout << "Resizing matrix to num_rows = " << last_row << endl;
#endif
m.num_rows = last_row;
m.matrix.resizeNumRows(m.num_rows);
gaussian_ret ret = nothing;
uint num_props = 0;
for (const uint* prop_row = propagatable_rows.getData(), *end = prop_row + propagatable_rows.size(); prop_row != end; prop_row++ ) {
//this is a "000..1..0000000X" row. I.e. it indicates a propagation
ret = handle_matrix_prop(m, *prop_row);
num_props++;
if (ret == unit_propagation) {
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Unit prop! Breaking from prop examination" << endl;
#endif
return unit_propagation;
}
}
#ifdef VERBOSE_DEBUG
if (num_props > 0) cout << "(" << matrix_no << ")Number of props during gauss:" << num_props << endl;
#endif
return ret;
}
uint Gaussian::find_sublevel(const Var v) const
{
for (int i = solver.trail.size()-1; i >= 0; i --)
if (solver.trail[i].var() == v) return i;
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Oooops! Var " << v+1 << " does not have a sublevel!! (so it must be undefined)" << endl;
#endif
assert(false);
return 0;
}
void Gaussian::cancel_until_sublevel(const uint until_sublevel)
{
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Canceling until sublevel " << until_sublevel << endl;
#endif
for (vector::iterator gauss = solver.gauss_matrixes.begin(), end= solver.gauss_matrixes.end(); gauss != end; gauss++)
if (*gauss != this) (*gauss)->canceling(until_sublevel);
for (int sublevel = solver.trail.size()-1; sublevel >= (int)until_sublevel; sublevel--) {
Var var = solver.trail[sublevel].var();
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Canceling var " << var+1 << endl;
#endif
#ifdef USE_OLD_POLARITIES
solver.polarity[var] = solver.oldPolarity[var];
#endif //USE_OLD_POLARITIES
solver.assigns[var] = l_Undef;
solver.insertVarOrder(var);
}
solver.trail.shrink(solver.trail.size() - until_sublevel);
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Canceling sublevel finished." << endl;
#endif
}
void Gaussian::analyse_confl(const matrixset& m, const uint row, int32_t& maxlevel, uint& size, uint& best_row) const
{
assert(row < m.num_rows);
//this is a "000...00000001" row. I.e. it indicates we are on the wrong branch
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")matrix conflict found!" << endl;
cout << "(" << matrix_no << ")conflict clause's vars: ";
print_matrix_row_with_assigns(m.matrix.getVarsetAt(row));
cout << endl;
cout << "(" << matrix_no << ")corresponding matrix's row (should be empty): ";
print_matrix_row(m.matrix.getMatrixAt(row));
cout << endl;
#endif
int32_t this_maxlevel = 0;
unsigned long int var = 0;
uint this_size = 0;
while (true) {
var = m.matrix.getVarsetAt(row).scan(var);
if (var == ULONG_MAX) break;
const Var real_var = col_to_var_original[var];
assert(real_var < solver.nVars());
if (solver.level[real_var] > this_maxlevel)
this_maxlevel = solver.level[real_var];
var++;
this_size++;
}
//the maximum of all lit's level must be lower than the max. level of the current best clause (or this clause must be either empty or unit clause)
if (!(
(this_maxlevel < maxlevel)
|| (this_maxlevel == maxlevel && this_size < size)
|| (this_size <= 1)
)) {
assert(maxlevel != std::numeric_limits::max());
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Other found conflict just as good or better.";
cout << "(" << matrix_no << ") || Old maxlevel:" << maxlevel << " new maxlevel:" << this_maxlevel;
cout << "(" << matrix_no << ") || Old size:" << size << " new size:" << this_size << endl;
//assert(!(maxlevel != UINT_MAX && maxlevel != this_maxlevel)); //NOTE: only holds if gauss is executed at each level
#endif
return;
}
#ifdef VERBOSE_DEBUG
if (maxlevel != std::numeric_limits::max())
cout << "(" << matrix_no << ")Better conflict found.";
else
cout << "(" << matrix_no << ")Found a possible conflict.";
cout << "(" << matrix_no << ") || Old maxlevel:" << maxlevel << " new maxlevel:" << this_maxlevel;
cout << "(" << matrix_no << ") || Old size:" << size << " new size:" << this_size << endl;
#endif
maxlevel = this_maxlevel;
size = this_size;
best_row = row;
}
Gaussian::gaussian_ret Gaussian::handle_matrix_prop(matrixset& m, const uint row)
{
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")matrix prop found!" << endl;
cout << m.matrix.getMatrixAt(row) << endl;
cout << "(" << matrix_no << ")matrix row:";
print_matrix_row(m.matrix.getMatrixAt(row));
cout << endl;
#endif
m.matrix.getVarsetAt(row).fill(tmp_clause, solver.assigns, col_to_var_original);
Clause& cla = *(Clause*)XorClause_new(tmp_clause, false, solver.learnt_clause_group++);
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")matrix prop clause: ";
cla.plainPrint();
cout << endl;
#endif
assert(m.matrix.getMatrixAt(row).is_true() == !cla[0].sign());
assert(solver.assigns[cla[0].var()].isUndef());
if (cla.size() == 1) {
solver.cancelUntil(0);
solver.uncheckedEnqueue(cla[0]);
clauseFree(&cla);
return unit_propagation;
}
clauses_toclear.push_back(std::make_pair(&cla, solver.trail.size()-1));
#ifdef STATS_NEEDED
if (solver.dynamic_behaviour_analysis)
solver.logger.set_group_name(cla.getGroup(), "gauss prop clause");
#endif
solver.uncheckedEnqueue(cla[0], &cla);
return propagation;
}
void Gaussian::disable_if_necessary()
{
if (//nof_conflicts >= 0
//&& conflictC >= nof_conflicts/8
!config.dontDisable
&& called > 50
&& useful_confl*2+useful_prop < (uint)((double)called*0.05) )
disabled = true;
}
llbool Gaussian::find_truths(vec& learnt_clause, int& conflictC)
{
Clause* confl;
disable_if_necessary();
if (should_check_gauss(solver.decisionLevel(), solver.starts)) {
called++;
gaussian_ret g = gaussian(confl);
switch (g) {
case conflict: {
useful_confl++;
llbool ret = solver.handle_conflict(learnt_clause, confl, conflictC, true);
clauseFree(confl);
if (ret != l_Nothing) return ret;
return l_Continue;
}
case unit_propagation:
unit_truths++;
case propagation:
useful_prop++;
return l_Continue;
case unit_conflict: {
unit_truths++;
useful_confl++;
if (confl->size() == 0) {
clauseFree(confl);
return l_False;
}
Lit lit = (*confl)[0];
#ifdef STATS_NEEDED
if (solver.dynamic_behaviour_analysis)
solver.logger.conflict(Logger::gauss_confl_type, 0, confl->getGroup(), *confl);
#endif
solver.cancelUntil(0);
if (solver.assigns[lit.var()].isDef()) {
clauseFree(confl);
return l_False;
}
solver.uncheckedEnqueue(lit);
clauseFree(confl);
return l_Continue;
}
case nothing:
break;
}
}
return l_Nothing;
}
template
void Gaussian::print_matrix_row(const T& row) const
{
unsigned long int var = 0;
while (true) {
var = row.scan(var);
if (var == ULONG_MAX) break;
else cout << col_to_var_original[var]+1 << ", ";
var++;
}
cout << "final:" << row.is_true() << endl;;
}
template
void Gaussian::print_matrix_row_with_assigns(const T& row) const
{
unsigned long int col = 0;
while (true) {
col = row.scan(col);
if (col == ULONG_MAX) break;
else {
Var var = col_to_var_original[col];
cout << (var+1) << "(" << lbool_to_string(solver.assigns[var]) << ")";
cout << ", ";
}
col++;
}
if (!row.is_true()) cout << "xor_clause_inverted";
}
const string Gaussian::lbool_to_string(const lbool toprint)
{
if (toprint == l_True)
return "true";
if (toprint == l_False)
return "false";
if (toprint == l_Undef)
return "undef";
assert(false);
return "";
}
void Gaussian::print_stats() const
{
if (called > 0) {
cout.setf(std::ios::fixed);
std::cout << " Gauss(" << matrix_no << ") useful";
cout << " prop: " << std::setprecision(2) << std::setw(5) << ((double)useful_prop/(double)called)*100.0 << "% ";
cout << " confl: " << std::setprecision(2) << std::setw(5) << ((double)useful_confl/(double)called)*100.0 << "% ";
if (disabled) std::cout << "disabled";
} else
std::cout << " Gauss(" << matrix_no << ") not called.";
}
void Gaussian::print_matrix_stats() const
{
cout << "matrix size: " << cur_matrixset.num_rows << " x " << cur_matrixset.num_cols << endl;
}
void Gaussian::reset_stats()
{
useful_prop = 0;
useful_confl = 0;
called = 0;
disabled = false;
}
bool Gaussian::check_no_conflict(matrixset& m) const
{
uint row = 0;
for(PackedMatrix::iterator r = m.matrix.beginMatrix(), end = m.matrix.endMatrix(); r != end; ++r, ++row) {
if ((*r).is_true() && (*r).isZero()) {
cout << "Conflict at row " << row << endl;
return false;
}
}
return true;
}
void Gaussian::print_matrix(matrixset& m) const
{
uint row = 0;
for (PackedMatrix::iterator it = m.matrix.beginMatrix(); it != m.matrix.endMatrix(); ++it, row++) {
cout << *it << " -- row:" << row;
if (row >= m.num_rows)
cout << " (considered past the end)";
cout << endl;
}
}
void Gaussian::print_last_one_in_cols(matrixset& m) const
{
for (uint i = 0; i < m.num_cols; i++) {
cout << "last_one_in_col[" << i << "]-1 = " << m.last_one_in_col[i]-1 << endl;
}
}
const bool Gaussian::nothing_to_propagate(matrixset& m) const
{
for(PackedMatrix::iterator r = m.matrix.beginMatrix(), end = m.matrix.endMatrix(); r != end; ++r) {
if ((*r).popcnt_is_one()
&& solver.assigns[m.col_to_var[(*r).scan(0)]].isUndef())
return false;
}
for(PackedMatrix::iterator r = m.matrix.beginMatrix(), end = m.matrix.endMatrix(); r != end; ++r) {
if ((*r).isZero() && (*r).is_true())
return false;
}
return true;
}
const bool Gaussian::check_last_one_in_cols(matrixset& m) const
{
for(uint i = 0; i < m.num_cols; i++) {
const uint last = std::min(m.last_one_in_col[i] - 1, (int)m.num_rows);
uint real_last = 0;
uint i2 = 0;
for (PackedMatrix::iterator it = m.matrix.beginMatrix(); it != m.matrix.endMatrix(); ++it, i2++) {
if ((*it)[i])
real_last = i2;
}
if (real_last > last)
return false;
}
return true;
}
void Gaussian::check_matrix_against_varset(PackedMatrix& matrix, const matrixset& m) const
{
for (uint i = 0; i < matrix.getSize(); i++) {
const PackedRow mat_row = matrix.getMatrixAt(i);
const PackedRow var_row = matrix.getVarsetAt(i);
unsigned long int col = 0;
bool final = false;
while (true) {
col = var_row.scan(col);
if (col == ULONG_MAX) break;
const Var var = col_to_var_original[col];
assert(var < solver.nVars());
if (solver.assigns[var] == l_True) {
assert(!mat_row[col]);
assert(m.col_to_var[col] == unassigned_var);
assert(m.var_is_set[var]);
final = !final;
} else if (solver.assigns[var] == l_False) {
assert(!mat_row[col]);
assert(m.col_to_var[col] == unassigned_var);
assert(m.var_is_set[var]);
} else if (solver.assigns[var] == l_Undef) {
assert(m.col_to_var[col] != unassigned_var);
assert(!m.var_is_set[var]);
assert(mat_row[col]);
} else assert(false);
col++;
}
if ((final^!mat_row.is_true()) != !var_row.is_true()) {
cout << "problem with row:"; print_matrix_row_with_assigns(var_row); cout << endl;
assert(false);
}
}
}
const void Gaussian::check_first_one_in_row(matrixset& m, const uint j)
{
if (j) {
uint16_t until2 = std::min(m.last_one_in_col[m.least_column_changed] - 1, (int)m.num_rows);
if (j-1 > m.first_one_in_row[m.num_rows-1]) {
until2 = m.num_rows;
#ifdef VERBOSE_DEBUG
cout << "j-1 > m.first_one_in_row[m.num_rows-1]" << "j:" << j << " m.first_one_in_row[m.num_rows-1]:" << m.first_one_in_row[m.num_rows-1] << endl;
#endif
}
for (uint i2 = 0; i2 != until2; i2++) {
#ifdef VERBOSE_DEBUG
cout << endl << "row " << i2 << " (num rows:" << m.num_rows << ")" << endl;
cout << m.matrix.getMatrixAt(i2) << endl;
cout << " m.first_one_in_row[m.num_rows-1]:" << m.first_one_in_row[m.num_rows-1] << endl;
cout << "first_one_in_row:" << m.first_one_in_row[i2] << endl;
cout << "num_cols:" << m.num_cols << endl;
cout << "popcnt:" << m.matrix.getMatrixAt(i2).popcnt() << endl;
cout << "popcnt_is_one():" << m.matrix.getMatrixAt(i2).popcnt_is_one() << endl;
cout << "popcnt_is_one("<< m.first_one_in_row[i2] <<"): " << m.matrix.getMatrixAt(i2).popcnt_is_one(m.first_one_in_row[i2]) << endl;
#endif
for (uint i3 = 0; i3 < m.first_one_in_row[i2]; i3++) {
assert(m.matrix.getMatrixAt(i2)[i3] == 0);
}
assert(m.matrix.getMatrixAt(i2)[m.first_one_in_row[i2]]);
assert(m.matrix.getMatrixAt(i2).popcnt_is_one() ==
m.matrix.getMatrixAt(i2).popcnt_is_one(m.first_one_in_row[i2]));
}
}
}
//old functions
/*void Gaussian::update_matrix_by_row(matrixset& m) const
{
#ifdef VERBOSE_DEBUG
cout << "Updating matrix." << endl;
uint num_updated = 0;
#endif
#ifdef DEBUG_GAUSS
assert(nothing_to_propagate(cur_matrixset));
#endif
mpz_class toclear, tocount;
uint last_col = 0;
for (uint col = 0; col < m.num_cols; col ++) {
Var var = m.col_to_var[col];
if (var != UINT_MAX && !solver.assigns[var].isUndef()) {
toclear.setBit(col);
if (solver.assigns[var].getBool()) tocount.setBit(col);
#ifdef DEBUG_GAUSS
assert(m.var_to_col[var] < UINT_MAX-1);
#endif
last_col = col;
m.least_column_changed = std::min(m.least_column_changed, (int)col);
m.removeable_cols++;
m.col_to_var[col] = UINT_MAX;
m.var_to_col[var] = UINT_MAX-1;
#ifdef VERBOSE_DEBUG
num_updated++;
#endif
}
}
toclear.invert();
mpz_class tmp;
mpz_class* this_row = &m.matrix[0];
for(uint i = 0, until = std::min(m.num_rows, m.last_one_in_col[last_col]+1); i < until; i++, this_row++) {
mpz_class& r = *this_row;
mpz_and(tmp.get_mp(), tocount.get_mp(), r.get_mp());
r.invert_is_true(tmp.popcnt() % 2);
r &= toclear;
}
#ifdef VERBOSE_DEBUG
cout << "Updated " << num_updated << " matrix cols. Could remove " << m.removeable_cols << " cols " <= last_level; level--){
Var var = solver.trail[level].var();
const uint col = m.var_to_col[var];
if ( col < UINT_MAX-1) {
update_matrix_col(m, var, col);
#ifdef VERBOSE_DEBUG
num_updated++;
#endif
}
}
#ifdef VERBOSE_DEBUG
cout << "Updated " << num_updated << " matrix cols. Could remove " << m.removeable_cols << " cols (out of " << m.num_cols << " )" <