#include "parallel/ParallelSolver.h"
#include "mtl/Sort.h"
using namespace Glucose;
const char* _cunstable = "CORE/PARALLEL -- UNSTABLE FEATURES";
const char* _parallel = "PARALLEL";
extern BoolOption opt_dontExportDirectReusedClauses; extern BoolOption opt_plingeling;
ParallelSolver::ParallelSolver(int threadId) :
SimpSolver()
, thn(threadId) , goodlimitlbd(7)
, goodlimitsize(25)
, purgatory(true)
, shareAfterProbation(!opt_plingeling) , plingeling(opt_plingeling)
, nbTimesSeenBeforeExport(2)
, firstSharing(5000) , limitSharingByGoodLBD(true) , limitSharingByFixedLimitLBD(0) , limitSharingByFixedLimitSize(0) , dontExportDirectReusedClauses(opt_dontExportDirectReusedClauses)
, nbNotExportedBecauseDirectlyReused(0)
{
useUnaryWatched = true; stats.growTo(parallelStatsSize,0);
}
ParallelSolver::~ParallelSolver() {
printf("c Solver of thread %d ended.\n", thn);
fflush(stdout);
}
ParallelSolver::ParallelSolver(const ParallelSolver &s) :
SimpSolver(s)
, sharedcomp(s.sharedcomp)
, goodlimitlbd(s.goodlimitlbd)
, goodlimitsize(s.goodlimitsize)
, purgatory(s.purgatory)
, shareAfterProbation(s.shareAfterProbation) , plingeling(s.plingeling)
,nbTimesSeenBeforeExport(2)
, firstSharing(s.firstSharing) , limitSharingByGoodLBD(s.limitSharingByGoodLBD) , limitSharingByFixedLimitLBD(s.limitSharingByFixedLimitLBD) , limitSharingByFixedLimitSize(s.limitSharingByFixedLimitSize) , dontExportDirectReusedClauses(s.dontExportDirectReusedClauses)
, nbNotExportedBecauseDirectlyReused(s.nbNotExportedBecauseDirectlyReused)
{
s.goodImportsFromThreads.memCopyTo(goodImportsFromThreads);
useUnaryWatched = s.useUnaryWatched;
s.stats.copyTo(stats);
s.elimclauses.copyTo(elimclauses); }
struct reduceDB_oneWatched_lt {
ClauseAllocator& ca;
reduceDB_oneWatched_lt(ClauseAllocator& ca_) : ca(ca_) {
}
bool operator()(CRef x, CRef y) {
if (ca[x].size() > 2 && ca[y].size() == 2) return 1;
if (ca[y].size() > 2 && ca[x].size() == 2) return 0;
if (ca[x].size() == 2 && ca[y].size() == 2) return 0;
if (ca[x].size() > ca[y].size()) return 1;
if (ca[x].size() < ca[y].size()) return 0;
if (ca[x].lbd() > ca[y].lbd()) return 1;
if (ca[x].lbd() < ca[y].lbd()) return 0;
return ca[x].activity() < ca[y].activity();
}
};
void ParallelSolver::reduceDB() {
int i, j;
stats[nbReduceDB]++;
int limit;
if (chanseokStrategy)
sort(learnts, reduceDBAct_lt(ca));
else
sort(learnts, reduceDB_lt(ca));
if (!chanseokStrategy && !panicModeIsEnabled()) {
if (ca[learnts[learnts.size() / RATIOREMOVECLAUSES]].lbd() <= 3) nbclausesbeforereduce += specialIncReduceDB;
if (ca[learnts.last()].lbd() <= 5) nbclausesbeforereduce += specialIncReduceDB;
}
if (!panicModeIsEnabled()) {
limit = learnts.size() / 2;
} else {
limit = panicModeLastRemoved;
}
panicModeLastRemoved = 0;
uint64_t sumsize = 0;
for (i = j = 0; i < learnts.size(); i++) {
Clause& c = ca[learnts[i]];
if (i == learnts.size() / 2)
goodlimitlbd = c.lbd();
sumsize += c.size();
if (c.lbd() > 2 && c.size() > 2 && c.canBeDel() && !locked(c) && (i < limit)) {
removeClause(learnts[i]);
stats[nbRemovedClauses]++;
panicModeLastRemoved++;
} else {
if (!c.canBeDel()) limit++; c.setCanBeDel(true); learnts[j++] = learnts[i];
}
}
learnts.shrink(i - j);
if (learnts.size() > 0)
goodlimitsize = 1 + (double) sumsize / (double) learnts.size();
if (!panicModeIsEnabled())
limit = unaryWatchedClauses.size() - (learnts.size() * (chanseokStrategy?4:2));
else
limit = panicModeLastRemovedShared;
panicModeLastRemovedShared = 0;
if ((unaryWatchedClauses.size() > 100) && (limit > 0)) {
sort(unaryWatchedClauses, reduceDB_oneWatched_lt(ca));
for (i = j = 0; i < unaryWatchedClauses.size(); i++) {
Clause& c = ca[unaryWatchedClauses[i]];
if (c.lbd() > 2 && c.size() > 2 && c.canBeDel() && !locked(c) && (i < limit)) {
removeClause(unaryWatchedClauses[i], c.getOneWatched()); stats[nbRemovedUnaryWatchedClauses]++;
panicModeLastRemovedShared++;
} else {
if (!c.canBeDel()) limit++; c.setCanBeDel(true); unaryWatchedClauses[j++] = unaryWatchedClauses[i];
}
}
unaryWatchedClauses.shrink(i - j);
}
checkGarbage();
}
void ParallelSolver::parallelImportClauseDuringConflictAnalysis(Clause &c,CRef confl) {
if (dontExportDirectReusedClauses && (confl == lastLearntClause) && (c.getExported() < nbTimesSeenBeforeExport)) { c.setExported(nbTimesSeenBeforeExport);
nbNotExportedBecauseDirectlyReused++;
} else if (shareAfterProbation && c.getExported() != nbTimesSeenBeforeExport && conflicts > firstSharing) {
c.setExported(c.getExported() + 1);
if (!c.wasImported() && c.getExported() == nbTimesSeenBeforeExport) { if (c.lbd() == 2 || (c.size() < goodlimitsize && c.lbd() <= goodlimitlbd)) {
shareClause(c);
}
}
}
}
void ParallelSolver::reportProgress() {
printf("c | %2d | %6d | %10d | %10d | %8d | %8d | %8d | %8d | %8d | %6.3f |\n",(int)thn,(int)starts,(int)decisions,(int)conflicts,(int)stats[originalClausesSeen],(int)learnts.size(),(int)stats[nbexported],(int)stats[nbimported],(int)stats[nbPromoted],progressEstimate()*100);
}
void ParallelSolver::reportProgressArrayImports(vec<unsigned int> &totalColumns) {
return ; unsigned int totalImports = 0;
printf("c %3d | ", thn);
for (int i = 0; i < sharedcomp->nbThreads; i++) {
totalImports += goodImportsFromThreads[i];
totalColumns[i] += goodImportsFromThreads[i];
printf(" %8d", goodImportsFromThreads[i]);
}
printf(" | %8d\n", totalImports);
}
bool ParallelSolver::shareClause(Clause & c) {
bool sent = sharedcomp->addLearnt(this, c);
if (sent)
stats[nbexported]++;
return sent;
}
bool ParallelSolver::panicModeIsEnabled() {
return sharedcomp->panicMode;
}
void ParallelSolver::parallelImportUnaryClauses() {
Lit l;
while ((l = sharedcomp->getUnary(this)) != lit_Undef) {
if (value(var(l)) == l_Undef) {
uncheckedEnqueue(l);
stats[nbimportedunit]++;
}
}
}
bool ParallelSolver::parallelImportClauses() {
assert(decisionLevel() == 0);
int importedFromThread;
while (sharedcomp->getNewClause(this, importedFromThread, importedClause)) {
assert(importedFromThread <= sharedcomp->nbThreads);
assert(importedFromThread >= 0);
assert(importedFromThread != thn);
if (importedClause.size() == 0)
return true;
CRef cr = ca.alloc(importedClause, true, true);
ca[cr].setLBD(importedClause.size());
if (plingeling) ca[cr].setExported(2); else {
ca[cr].setExported(1); }
ca[cr].setImportedFrom(importedFromThread);
if(useUnaryWatched)
unaryWatchedClauses.push(cr);
else
learnts.push(cr);
if (plingeling || ca[cr].size() <= 2) { ca[cr].setOneWatched(false); attachClause(cr);
stats[nbImportedGoodClauses]++;
} else {
if(useUnaryWatched) {
attachClausePurgatory(cr); ca[cr].setOneWatched(true);
} else {
attachClause(cr);
ca[cr].setOneWatched(false);
}
stats[nbimportedInPurgatory]++;
}
assert(ca[cr].learnt());
stats[nbimported]++;
}
return false;
}
void ParallelSolver::parallelExportUnaryClause(Lit p) {
sharedcomp->addLearnt(this,p ); stats[nbexportedunit]++;
}
void ParallelSolver::parallelExportClauseDuringSearch(Clause &c) {
if ((plingeling && !shareAfterProbation && c.lbd() < 8 && c.size() < 40) ||
(c.lbd() <= 2)) { shareClause(c);
c.setExported(2);
}
}
bool ParallelSolver::parallelJobIsFinished() {
return (sharedcomp->jobFinished());
}
lbool ParallelSolver::solve_(bool do_simp, bool turn_off_simp) {
vec<Var> extra_frozen;
lbool result = l_True;
do_simp &= use_simplification;
if (do_simp){
for (int i = 0; i < assumptions.size(); i++){
Var v = var(assumptions[i]);
assert(!isEliminated(v));
if (!frozen[v]){
setFrozen(v, true);
extra_frozen.push(v);
} }
result = lbool(eliminate(turn_off_simp));
}
model.clear();
conflict.clear();
if (!ok) return l_False;
solves++;
lbool status = l_Undef;
int curr_restarts = 0;
while (status == l_Undef && !sharedcomp->jobFinished()) {
status = search(luby_restart?luby(restart_inc, curr_restarts)*luby_restart_factor:0); if (!withinBudget()) break;
curr_restarts++;
}
if (verbosity >= 1)
printf("c =========================================================================================================\n");
bool firstToFinish = false;
if (status != l_Undef)
firstToFinish = sharedcomp->IFinished(this);
if (firstToFinish) {
printf("c Thread %d is 100%% pure glucose! First thread to finish! (%s answer).\n", threadNumber(), status == l_True ? "SAT" : status == l_False ? "UNSAT" : "UNKOWN");
sharedcomp->jobStatus = status;
}
if (firstToFinish && status == l_True) {
extendModel();
model.growTo(nVars());
for (int i = 0; i < nVars(); i++) model[i] = value(i);
} else if (status == l_False && conflict.size() == 0)
ok = false;
pthread_cond_signal(pcfinished);
return status;
}