#include "BlockedClauseElimination.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/Problem.hpp"
#include "Kernel/Signature.hpp"
#include "Kernel/Term.hpp"
#include "Kernel/TermTransformer.hpp"
#include "Kernel/Unit.hpp"
#include "Lib/Environment.hpp"
#include "Kernel/RobSubstitution.hpp"
#include "Kernel/EqHelper.hpp"
#include "Indexing/TermSharing.hpp"
#include "Lib/DHSet.hpp"
#include "Lib/DHMap.hpp"
#include "Lib/BinaryHeap.hpp"
#include "Debug/TimeProfiling.hpp"
#include "Lib/IntUnionFind.hpp"
#include "Shell/Statistics.hpp"
#include "Shell/Property.hpp"
#include "Shell/Options.hpp"
namespace Shell
{
using namespace std;
using namespace Lib;
using namespace Kernel;
using namespace Indexing;
void BlockedClauseElimination::apply(Problem& prb)
{
TIME_TRACE("blocked clause elimination");
bool modified = false;
bool equationally = _forceEquationally || (prb.hasEquality() && prb.getProperty()->positiveEqualityAtoms());
DArray<Stack<Candidate*>> positive(env.signature->predicates());
DArray<Stack<Candidate*>> negative(env.signature->predicates());
Stack<ClWrapper*> wrappers;
UnitList::Iterator uit(prb.units());
while(uit.hasNext()) {
Unit* u = uit.next();
ASS(u->isClause());
Clause* cl=static_cast<Clause*>(u);
ClWrapper* clw = new ClWrapper(cl);
wrappers.push(clw);
for(unsigned i=0; i<cl->length(); i++) {
Literal* lit = (*cl)[i];
unsigned pred = lit->functor();
if (!env.signature->getPredicate(pred)->protectedSymbol()) { ASS(pred);
(lit->isPositive() ? positive : negative)[pred].push(new Candidate {clw,i,0,0});
}
}
}
typedef BinaryHeap<Candidate*, CandidateComparator> BlockClauseCheckPriorityQueue;
BlockClauseCheckPriorityQueue queue;
for (bool isPos : {false, true}) {
DArray<Stack<Candidate*>>& one = isPos ? positive : negative;
DArray<Stack<Candidate*>>& other = isPos ? negative : positive;
for (unsigned pred = 1; pred < one.size(); pred++) { Stack<Candidate*>& predsCandidates = one[pred];
unsigned predsRemaining = other[pred].size();
for (unsigned i = 0; i < predsCandidates.size(); i++) {
Candidate* cand = predsCandidates[i];
cand->weight = predsRemaining;
queue.insert(cand);
}
}
}
while (!queue.isEmpty()) {
Candidate* cand = queue.pop();
ClWrapper* clw = cand->clw;
if (clw->blocked) {
continue;
}
Clause* cl = clw->cl;
Literal* lit = (*cl)[cand->litIdx];
unsigned pred = lit->functor();
Stack<Candidate*>& partners = (lit->isPositive() ? negative : positive)[pred];
for (unsigned i = cand->contFrom; i < partners.size(); i++) {
Candidate* partner = partners[i];
ClWrapper* pclw = partner->clw;
if (pclw == clw) {
continue;
}
Clause* pcl = pclw->cl;
if (pclw->blocked) {
continue;
}
if (!resolvesToTautology(equationally,cl,lit,pcl,(*pcl)[partner->litIdx])) {
cand->contFrom = i+1;
cand->weight = partners.size() - cand->contFrom;
pclw->toResurrect.push(cand);
goto next_candidate;
}
}
if (env.options->showPreprocessing()) {
cout << "[PP] Blocked clause[" << cand->litIdx << "]: " << cl->toString() << endl;
}
prb.addEliminatedBlockedClause(cl,cand->litIdx);
env.statistics->blockedClauses++;
modified = true;
clw->blocked = true;
for (unsigned i = 0; i< clw->toResurrect.size(); i++) {
queue.insert(clw->toResurrect[i]);
}
clw->toResurrect.reset();
next_candidate: ;
}
for (bool isPos : {false, true}) {
DArray<Stack<Candidate*>> & one = isPos ? positive : negative;
for (unsigned pred = 0; pred < one.size(); pred++) {
Stack<Candidate*>& predsCandidates = one[pred];
for (unsigned i = 0; i < predsCandidates.size(); i++) {
delete predsCandidates[i];
}
}
}
UnitList* res=0;
Stack<ClWrapper*>::Iterator it(wrappers);
while (it.hasNext()) {
ClWrapper* clw = it.next();
if (modified && !clw->blocked) {
UnitList::push(clw->cl, res);
}
delete clw;
}
if (modified) {
prb.units() = res;
prb.invalidateProperty();
}
}
bool BlockedClauseElimination::resolvesToTautology(bool equationally, Clause* cl, Literal* lit, Clause* pcl, Literal* plit)
{
if (equationally) {
return resolvesToTautologyEq(cl,lit,pcl,plit);
} else {
return resolvesToTautologyUn(cl,lit,pcl,plit);
}
}
class VarMaxUpdatingNormalizer : public TermTransformer {
public:
VarMaxUpdatingNormalizer(const Lib::DHMap<TermList, TermList>& replacements, int& varMax)
: _repls(replacements), _varMax(varMax) {}
protected:
TermList transformSubterm(TermList trm) override {
TermList res;
if (_repls.find(trm,res)) {
return res;
}
if (trm.isVar()) {
int var = trm.var();
if (var > _varMax) {
_varMax = var;
}
}
return trm;
}
private:
const Lib::DHMap<TermList, TermList>& _repls;
int& _varMax;
};
class RenanigApartNormalizer : public TermTransformer {
public:
RenanigApartNormalizer(const Lib::DHMap<TermList, TermList>& replacements, int varMax, Lib::DHMap<unsigned, unsigned>& varMap)
: _repls(replacements), _varMax(varMax), _varMap(varMap) {}
protected:
TermList transformSubterm(TermList trm) override {
TermList res;
if (_repls.find(trm,res)) {
return res;
}
if (trm.isVar()) {
unsigned varIn = trm.var();
unsigned* varOut;
if (_varMap.getValuePtr(varIn,varOut)) {
*varOut = ++_varMax;
}
return TermList(*varOut,false);
}
return trm;
}
private:
const Lib::DHMap<TermList, TermList>& _repls;
int _varMax;
Lib::DHMap<unsigned, unsigned>& _varMap;
};
bool BlockedClauseElimination::resolvesToTautologyEq(Clause* cl, Literal* lit, Clause* pcl, Literal* plit)
{
TermSharing::WellSortednessCheckingLocalDisabler disableInScope(env.sharing);
ASS_EQ(lit->arity(),plit->arity());
unsigned n = lit->arity();
IntUnionFind uf(n ? 2*n : 1); static Lib::DHMap<TermList, unsigned> litArgIds;
litArgIds.reset();
static Lib::DHMap<TermList, unsigned> plitArgIds;
plitArgIds.reset();
int varMax = -1;
for(unsigned i = 0; i<n; i++) {
TermList arg = *lit->nthArgument(i);
TermIterator vit = Term::getVariableIterator(arg);
while (vit.hasNext()) {
TermList vt = vit.next();
ASS(vt.isVar());
int var = vt.var();
if (var > varMax) {
varMax = var;
}
}
unsigned id1 = i;
unsigned id2 = litArgIds.findOrInsert(arg,id1);
if (id1 != id2) {
uf.doUnion(id1,id2);
}
}
for(unsigned i = 0; i<n; i++) {
TermList arg = *plit->nthArgument(i);
unsigned id1 = n+i;
unsigned id2 = plitArgIds.findOrInsert(arg,id1);
if (id1 != id2) {
uf.doUnion(id1,id2);
}
uf.doUnion(i,id1);
}
static Lib::DHMap<TermList, TermList> replacements;
replacements.reset();
for(unsigned i = 0; i<n; i++) {
TermList arg = *lit->nthArgument(i);
unsigned id1 = i;
unsigned id2 = uf.root(id1);
ASS_L(id2,n);
TermList target = *lit->nthArgument(id2);
replacements.insert(arg,target);
}
for(unsigned i = 0; i<n; i++) {
TermList arg = *plit->nthArgument(i);
if (arg.isTerm() && arg.term()->ground()) {
unsigned id1 = n+i;
unsigned id2 = uf.root(id1);
ASS_L(id2,n);
TermList target = *lit->nthArgument(id2);
replacements.insert(arg,target);
}
}
VarMaxUpdatingNormalizer clNormalizer(replacements,varMax);
static DHSet<Literal*> norm_lits;
norm_lits.reset();
for (unsigned i = 0; i < cl->length(); i++) {
Literal* curlit = (*cl)[i];
if (curlit->functor() != lit->functor() || curlit->polarity() != lit->polarity()) {
Literal* ncurlit = clNormalizer.transformLiteral(curlit);
Literal* opncurlit = Literal::complementaryLiteral(ncurlit);
if (norm_lits.find(opncurlit)) {
return true;
}
if (EqHelper::isEqTautology(ncurlit)) {
return true;
}
norm_lits.insert(ncurlit);
}
}
replacements.reset();
for(unsigned i = 0; i<n; i++) {
TermList arg = *plit->nthArgument(i);
unsigned id1 = n+i;
unsigned id2 = uf.root(id1);
ASS_L(id2,n);
TermList target = *lit->nthArgument(id2);
replacements.insert(arg,target);
}
for(unsigned i = 0; i<n; i++) {
TermList arg = *lit->nthArgument(i);
if (arg.isTerm() && arg.term()->ground()) {
unsigned id1 = i;
unsigned id2 = uf.root(id1);
ASS_L(id2,n);
TermList target = *lit->nthArgument(id2);
replacements.insert(arg,target);
}
}
static Lib::DHMap<unsigned, unsigned> varMap;
varMap.reset();
RenanigApartNormalizer pclNormalizer(replacements,varMax,varMap);
static DHSet<Literal*> pcl_lits;
pcl_lits.reset();
for (unsigned i = 0; i < pcl->length(); i++) {
Literal* curlit = (*pcl)[i];
if (curlit->functor() != plit->functor() || curlit->polarity() != plit->polarity()) {
Literal* ncurlit = pclNormalizer.transformLiteral(curlit);
Literal* opncurlit = Literal::complementaryLiteral(ncurlit);
if (norm_lits.find(opncurlit)) {
return true;
}
if (EqHelper::isEqTautology(ncurlit)) {
return true;
}
norm_lits.insert(ncurlit);
}
}
return false;
};
bool BlockedClauseElimination::resolvesToTautologyUn(Clause* cl, Literal* lit, Clause* pcl, Literal* plit)
{
static RobSubstitution subst_main;
subst_main.reset();
if(!subst_main.unifyArgs(lit,0,plit,1)) {
return true; }
static DHSet<Literal*> cl_lits;
cl_lits.reset();
Literal* opslit = 0;
for (unsigned i = 0; i < cl->length(); i++) {
Literal* curlit = (*cl)[i];
Literal* scurlit = subst_main.apply(curlit,0);
Literal* opscurlit = Literal::complementaryLiteral(scurlit);
if (curlit == lit) {
opslit = opscurlit;
}
if (cl_lits.find(opscurlit)) { return true;
}
cl_lits.insert(scurlit);
}
ASS_NEQ(opslit,0);
static DHSet<Literal*> pcl_lits;
pcl_lits.reset();
static RobSubstitution subst_aux;
subst_aux.reset();
for (unsigned i = 0; i < pcl->length(); i++) {
Literal* curlit = (*pcl)[i];
Literal* scurlit = subst_main.apply(curlit,1);
Literal* opscurlit = Literal::complementaryLiteral(scurlit);
if (pcl_lits.find(opscurlit)) { return true;
}
pcl_lits.insert(scurlit);
if (curlit != plit && cl_lits.find(opscurlit)) {
if (opslit->functor() != scurlit->functor() || !subst_aux.unifyArgs(opslit,0,scurlit,0)) { return true;
} else {
subst_aux.reset();
}
}
}
return false;
}
}