/***********************************************************************************
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 "PartHandler.h"
#include "VarReplacer.h"
#include
#include
#include
//#define VERBOSE_DEBUG
PartHandler::PartHandler(Solver& s) :
solver(s)
{
}
const bool PartHandler::handle()
{
if (solver.performReplace == false)
return true;
PartFinder partFinder(solver);
if (!partFinder.findParts()) {
#ifdef VERBOSE_DEBUG
std::cout << "c findParts() found UNSAT. Whole problem is unsat." << std::endl;
#endif //VERBOSE_DEBUG
return false;
}
uint32_t num_parts = partFinder.getReverseTable().size();
if (num_parts == 1)
return true;
map > reverseTable = partFinder.getReverseTable();
assert(num_parts == partFinder.getReverseTable().size());
vector > sizes;
for (map >::iterator it = reverseTable.begin(); it != reverseTable.end(); it++)
sizes.push_back(std::make_pair(it->first, (uint32_t)it->second.size()));
std::sort(sizes.begin(), sizes.end(), sort_pred());
assert(sizes.size() > 1);
for (uint32_t it = 0; it < sizes.size()-1; it++) {
uint32_t part = sizes[it].first;
vector vars = reverseTable[part];
if (solver.verbosity >= 1)
std::cout << "c Solving part " << part << std::endl;
Solver newSolver;
newSolver.mtrand.seed(solver.mtrand.randInt());
newSolver.random_var_freq = solver.random_var_freq;
newSolver.verbosity = solver.verbosity;
newSolver.restrictedPickBranch = solver.restrictedPickBranch;
newSolver.greedyUnbound = solver.greedyUnbound;
newSolver.findNormalXors = solver.findNormalXors;
newSolver.findBinaryXors = solver.findBinaryXors;
newSolver.regularlyFindBinaryXors = solver.regularlyFindBinaryXors;
newSolver.conglomerateXors = solver.conglomerateXors;
newSolver.schedSimplification = solver.schedSimplification;
newSolver.performReplace = solver.performReplace;
newSolver.failedVarSearch = solver.failedVarSearch;
#ifdef USE_GAUSS
newSolver.gaussconfig.dontDisable = solver.gaussconfig.dontDisable;
#endif //USE_GAUSS
newSolver.heuleProcess = solver.heuleProcess;
newSolver.doSubsumption = solver.doSubsumption;
newSolver.doPartHandler = solver.doPartHandler;
newSolver.fixRestartType = solver.fixRestartType;
newSolver.var_inc = solver.var_inc;
newSolver.polarity_mode = solver.polarity_mode;
std::sort(vars.begin(), vars.end());
uint32_t i2 = 0;
for (Var var = 0; var < solver.nVars(); var++) {
if (i2 < vars.size() && vars[i2] == var) {
#ifdef VERBOSE_DEBUG
if (!solver.decision_var[var]) {
std::cout << "var " << var + 1 << " is non-decision, but in part... strange." << std::endl;
}
#endif //VERBOSE_DEBUG
newSolver.newVar(solver.decision_var[var]);
newSolver.activity[var] = solver.activity[var];
newSolver.order_heap.update(var);
assert(partFinder.getVarPart(var) == part);
if (solver.decision_var[var]) {
solver.setDecisionVar(var, false);
decisionVarRemoved.push(var);
}
i2++;
} else {
assert(partFinder.getVarPart(var) != part);
newSolver.newVar(false);
}
}
solver.order_heap.filter(Solver::VarFilter(solver));
assert(solver.varReplacer->getClauses().size() == 0);
moveClauses(solver.clauses, newSolver, part, partFinder);
moveClauses(solver.binaryClauses, newSolver, part, partFinder);
moveClauses(solver.xorclauses, newSolver, part, partFinder);
moveLearntClauses(solver.binaryClauses, newSolver, part, partFinder);
moveLearntClauses(solver.learnts, newSolver, part, partFinder);
assert(checkClauseMovement(newSolver, part, partFinder));
lbool status = newSolver.solve();
if (status == l_False) {
#ifdef VERBOSE_DEBUG
std::cout << "c One of the sub-problems was UNSAT. Whole problem is unsat." << std::endl;
#endif //VERBOSE_DEBUG
return false;
}
assert(status != l_Undef);
for (Var var = 0; var < newSolver.nVars(); var++) {
if (newSolver.model[var] != l_Undef) {
assert(solver.assigns[var] == l_Undef);
}
}
assert(newSolver.decisionLevel() == 0);
for (uint32_t i = 0; i < newSolver.trail.size(); i++) {
solver.uncheckedEnqueue(newSolver.trail[i]);
}
solver.ok = (solver.propagate() == NULL);
assert(solver.ok);
for (Var var = 0; var < newSolver.nVars(); var++) {
if (newSolver.model[var] != l_Undef) {
//Must have been decision var in the old solver!??
//assert(std::find(decisionVarRemoved.getData(), decisionVarRemoved.getDataEnd(), var) != decisionVarRemoved.getDataEnd());
assert(savedState[var] == l_Undef);
assert(partFinder.getVarPart(var) == part);
if (newSolver.assigns[var] == l_Undef) {
savedState[var] = newSolver.model[var];
}
}
}
if (solver.verbosity >= 1)
std::cout << "c Solved part" << std::endl;
}
if (solver.verbosity >= 1)
std::cout << "c Coming back to original instance"
<< std::setw(57) << " |" << std::endl;
solver.order_heap.filter(Solver::VarFilter(solver));
//Checking that all variables that are not in the remaining part are all non-decision vars, and none have been set
for (Var var = 0; var < solver.nVars(); var++) {
if (savedState[var] != l_Undef) {
assert(solver.decision_var[var] == false);
assert(solver.assigns[var] == l_Undef || solver.level[var] == 0);
}
}
//Checking that all remaining clauses contain only variables that are in the remaining part
assert(checkClauseMovement(solver, sizes[sizes.size()-1].first, partFinder));
return true;
}
const bool PartHandler::checkClauseMovement(const Solver& thisSolver, const uint32_t part, const PartFinder& partFinder) const
{
if (!checkOnlyThisPart(thisSolver.clauses, part, partFinder))
return false;
if (!checkOnlyThisPart(thisSolver.learnts, part, partFinder))
return false;
if (!checkOnlyThisPart(thisSolver.binaryClauses, part, partFinder))
return false;
if (!checkOnlyThisPart(thisSolver.xorclauses, part, partFinder))
return false;
return true;
}
template
const bool PartHandler::checkOnlyThisPart(const vec& cs, const uint32_t part, const PartFinder& partFinder) const
{
for(T * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++) {
const T& c = **it;
for(const Lit *l = c.getData(), *end2 = l + c.size(); l != end2; l++) {
if (partFinder.getVarPart(l->var()) != part) return false;
}
}
return true;
}
void PartHandler::moveClauses(vec& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder)
{
Clause **i, **j, **end;
for (i = j = cs.getData(), j = i , end = i + cs.size(); i != end; i++) {
if ((**i).learnt() || partFinder.getVarPart((**i)[0].var()) != part) {
*j++ = *i;
continue;
}
solver.detachClause(**i);
#ifdef VERBOSE_DEBUG
std::cout << "clause in this part:"; (**i).plainPrint();
#endif
Clause& c = **i;
vec tmp(c.size());
std::copy(c.getData(), c.getDataEnd(), tmp.getData());
newSolver.addClause(tmp, c.getGroup());
//NOTE: we need the CS because otherwise, the addClause could have changed **i, which we need to re-add later!
clausesRemoved.push(*i);
}
cs.shrink(i-j);
}
void PartHandler::moveClauses(vec& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder)
{
XorClause **i, **j, **end;
for (i = j = cs.getData(), end = i + cs.size(); i != end; i++) {
if (partFinder.getVarPart((**i)[0].var()) != part) {
*j++ = *i;
continue;
}
solver.detachClause(**i);
#ifdef VERBOSE_DEBUG
std::cout << "xor clause in this part:"; (**i).plainPrint();
#endif
XorClause& c = **i;
vec tmp(c.size());
std::copy(c.getData(), c.getDataEnd(), tmp.getData());
newSolver.addXorClause(tmp, c.xor_clause_inverted(), c.getGroup());
//NOTE: we need the CS because otherwise, the addXorClause could have changed **i, which we need to re-add later!
xorClausesRemoved.push(*i);
}
cs.shrink(i-j);
}
void PartHandler::moveLearntClauses(vec& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder)
{
Clause **i, **j, **end;
for (i = j = cs.getData(), end = i + cs.size() ; i != end; i++) {
if (!(**i).learnt()) {
*j++ = *i;
continue;
}
Clause& c = **i;
assert(c.size() > 0);
uint32_t clause_part = partFinder.getVarPart(c[0].var());
bool removed = false;
for (const Lit* l = c.getData(), *end = l + c.size(); l != end; l++) {
if (partFinder.getVarPart(l->var()) != clause_part) {
#ifdef VERBOSE_DEBUG
std::cout << "Learnt clause in both parts:"; c.plainPrint();
#endif
removed = true;
solver.removeClause(c);
break;
}
}
if (removed) continue;
if (clause_part == part) {
#ifdef VERBOSE_DEBUG
//std::cout << "Learnt clause in this part:"; c.plainPrint();
#endif
solver.detachClause(c);
newSolver.addLearntClause(c, c.getGroup(), c.activity());
clauseFree(&c);
} else {
#ifdef VERBOSE_DEBUG
std::cout << "Learnt clause in other part:"; c.plainPrint();
#endif
*j++ = *i;
}
}
cs.shrink(i-j);
}
void PartHandler::addSavedState()
{
//Don't add these (non-0-decison-level!) solutions to the 0th decision level
solver.newDecisionLevel();
for (Var var = 0; var < savedState.size(); var++) {
if (savedState[var] != l_Undef) {
assert(solver.assigns[var] == l_Undef);
solver.uncheckedEnqueue(Lit(var, savedState[var] == l_False));
assert(solver.assigns[var] == savedState[var]);
savedState[var] = l_Undef;
solver.polarity[var] = (solver.assigns[var] == l_False);
}
}
for (uint32_t i = 0; i < decisionVarRemoved.size(); i++)
solver.setDecisionVar(decisionVarRemoved[i], true);
decisionVarRemoved.clear();
}
void PartHandler::readdRemovedClauses()
{
FILE* backup_libraryCNFfile = solver.libraryCNFFile;
solver.libraryCNFFile = NULL;
for (Clause **it = clausesRemoved.getData(), **end = clausesRemoved.getDataEnd(); it != end; it++) {
solver.addClause(**it, (*it)->getGroup());
assert(solver.ok);
}
clausesRemoved.clear();
for (XorClause **it = xorClausesRemoved.getData(), **end = xorClausesRemoved.getDataEnd(); it != end; it++) {
solver.addXorClause(**it, (**it).xor_clause_inverted(), (*it)->getGroup());
assert(solver.ok);
}
xorClausesRemoved.clear();
solver.libraryCNFFile = backup_libraryCNFfile;
}