#include "SAT/SATClause.hpp"
#include "MinimizingSolver.hpp"
namespace SAT
{
MinimizingSolver::MinimizingSolver(SATSolver* inner)
: _varCnt(0), _inner(inner), _assignmentValid(false), _heap(CntComparator(_unsClCnt))
{
}
void MinimizingSolver::ensureVarCount(unsigned newVarCnt)
{
if (newVarCnt<= _varCnt) {
return;
}
_varCnt = newVarCnt;
_inner->ensureVarCount(newVarCnt);
_asgn.expand(newVarCnt+1);
_watcher.expand(newVarCnt+1);
_unsClCnt.expand(newVarCnt+1, 0);
_heap.elMap().expand(newVarCnt+1);
_clIdx.expand(newVarCnt+1);
_assignmentValid = false;
}
void MinimizingSolver::addClause(SATClause* cl)
{
_inner->addClause(cl);
_assignmentValid = false;
if (cl->length()!=0) {
_unprocessed.push(cl);
}
}
VarAssignment MinimizingSolver::getAssignment(unsigned var)
{
ASS_G(var,0); ASS_LE(var,_varCnt);
if(!_assignmentValid) {
updateAssignment();
}
if(admitsDontcare(var)) {
return VarAssignment::DONT_CARE;
}
return _asgn[var] ? VarAssignment::TRUE : VarAssignment::FALSE;
}
bool MinimizingSolver::isZeroImplied(unsigned var)
{
ASS_G(var,0); ASS_LE(var,_varCnt);
bool res = _inner->isZeroImplied(var);
ASS(!res || getAssignment(var)!=VarAssignment::DONT_CARE); return res;
}
void MinimizingSolver::selectVariable(unsigned var)
{
ASS_G(var,0); ASS_LE(var,_varCnt);
ASS_G(_unsClCnt[var],0);
SATClauseStack& satisfied = _clIdx[var];
SATClauseStack& watch = _watcher[var];
while(satisfied.isNonEmpty()) {
SATClause* cl = satisfied.pop();
if(!_satisfiedClauses.insert(cl)) {
continue;
}
watch.push(cl);
auto cit = cl->iter();
while(cit.hasNext()) {
SATLiteral cl_lit = cit.next();
unsigned cl_var = cl_lit.var();
if (cl_lit.positive() == _asgn[cl_var]) {
ASS_G(_unsClCnt[cl_var], 0);
_unsClCnt[cl_var]--;
if (cl_var != var) { _heap.notifyIncrease(cl_var); }
}
}
}
}
void MinimizingSolver::putIntoIndex(SATClause* cl)
{
auto cit = cl->iter();
while(cit.hasNext()) {
SATLiteral lit = cit.next();
unsigned var = lit.var();
if (lit.positive() == _asgn[var]) {
_clIdx[var].push(cl);
_unsClCnt[var]++;
}
}
}
bool MinimizingSolver::tryPuttingToAnExistingWatch(SATClause* cl)
{
auto cit = cl->iter();
while(cit.hasNext()) {
SATLiteral lit = cit.next();
unsigned var = lit.var();
if(_asgn[var]==lit.positive() && !admitsDontcare(var)) {
ALWAYS(_satisfiedClauses.insert(cl));
_watcher[var].push(cl);
return true;
}
}
return false;
}
void MinimizingSolver::processUnprocessedAndFillHeap()
{
while(_unprocessed.isNonEmpty()) {
SATClause* cl = _unprocessed.pop();
ASS_G(cl->length(),0)
if(!tryPuttingToAnExistingWatch(cl)) {
putIntoIndex(cl);
}
}
for(unsigned var=1; var<=_varCnt; var++) {
ASS(!_heap.contains(var));
if(_unsClCnt[var]>0) {
_heap.addToEnd(var);
}
}
_heap.heapify();
}
void MinimizingSolver::processInnerAssignmentChanges()
{
for(unsigned v=1; v<=_varCnt; v++) {
VarAssignment va = _inner->getAssignment(v);
bool changed;
switch(va) {
case VarAssignment::DONT_CARE:
changed = false;
break;
case VarAssignment::TRUE:
changed = !_asgn[v];
_asgn[v] = true;
break;
case VarAssignment::FALSE:
changed = _asgn[v];
_asgn[v] = false;
break;
case VarAssignment::NOT_KNOWN:
default:
ASSERTION_VIOLATION;
break;
}
if(changed) {
SATClauseStack& watch = _watcher[v];
_unprocessed.loadFromIterator(SATClauseStack::Iterator(watch));
_satisfiedClauses.removeIteratorElements(SATClauseStack::Iterator(watch));
watch.reset();
}
}
}
void MinimizingSolver::updateAssignment()
{
TIME_TRACE("minimizing solver time");
processInnerAssignmentChanges();
processUnprocessedAndFillHeap();
while (!_heap.isEmpty()) {
unsigned best_var = _heap.pop();
if (_unsClCnt[best_var] > 0) {
selectVariable(best_var);
ASS_EQ(_unsClCnt[best_var],0);
ASS(_clIdx[best_var].isEmpty());
} else {
_clIdx[best_var].reset();
}
}
_assignmentValid = true;
}
}