#include "Lib/DHSet.hpp"
#include "Lib/Environment.hpp"
#include "Lib/Metaiterators.hpp"
#include "Debug/TimeProfiling.hpp"
#include "Lib/VirtualIterator.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/EqHelper.hpp"
#include "Kernel/Inference.hpp"
#include "Kernel/Ordering.hpp"
#include "Kernel/Term.hpp"
#include "Kernel/TermIterators.hpp"
#include "Kernel/ColorHelper.hpp"
#include "Kernel/RobSubstitution.hpp"
#include "Indexing/Index.hpp"
#include "Indexing/TermIndex.hpp"
#include "Saturation/SaturationAlgorithm.hpp"
#include "Shell/Options.hpp"
#include "Shell/Statistics.hpp"
#include "Debug/TimeProfiling.hpp"
#include "DemodulationHelper.hpp"
#include "ForwardDemodulation.hpp"
namespace Inferences {
using namespace Lib;
using namespace Kernel;
using namespace Indexing;
using namespace Saturation;
namespace {
struct Applicator : SubstApplicator {
Applicator(ResultSubstitution* subst) : subst(subst) {}
TermList operator()(unsigned v) const override {
return subst->applyToBoundResult(v);
}
ResultSubstitution* subst;
};
struct ApplicatorWithEqSort : SubstApplicator {
ApplicatorWithEqSort(ResultSubstitution* subst, const RobSubstitution& vSubst) : subst(subst), vSubst(vSubst) {}
TermList operator()(unsigned v) const override {
return vSubst.apply(subst->applyToBoundResult(v), 0);
}
ResultSubstitution* subst;
const RobSubstitution& vSubst;
};
}
void ForwardDemodulation::attach(SaturationAlgorithm* salg)
{
ForwardSimplificationEngine::attach(salg);
_index = salg->getSimplifyingIndex<DemodulationLHSIndex>();
auto& opt = getOptions();
_preorderedOnly = opt.forwardDemodulation()==Options::Demodulation::PREORDERED;
_encompassing = opt.demodulationRedundancyCheck()==Options::DemodulationRedundancyCheck::ENCOMPASS;
_useTermOrderingDiagrams = opt.forwardDemodulationTermOrderingDiagrams();
_skipNonequationalLiterals = opt.demodulationOnlyEquational();
_helper = DemodulationHelper(opt, &_salg->getOrdering());
}
void ForwardDemodulation::detach()
{
_index = nullptr;
ForwardSimplificationEngine::detach();
}
bool ForwardDemodulation::perform(Clause* cl, Clause*& replacement, ClauseIterator& premises)
{
TIME_TRACE("forward demodulation");
Ordering& ordering = _salg->getOrdering();
static DHSet<TermList> attempted;
attempted.reset();
unsigned cLen=cl->length();
for(unsigned li=0;li<cLen;li++) {
Literal* lit=(*cl)[li];
if (lit->isAnswerLiteral()) {
continue;
}
if (_skipNonequationalLiterals && !lit->isEquality()) {
continue;
}
NonVariableNonTypeIterator it(lit);
while(it.hasNext()) {
TypedTermList trm = it.next();
if(!attempted.insert(trm)) {
it.right();
continue;
}
bool redundancyCheck = _helper.redundancyCheckNeededForPremise(cl, lit, trm);
auto git = _index->getGeneralizations(trm.term(), true);
while(git.hasNext()) {
auto qr=git.next();
ASS_EQ(qr.data->clause->length(),1);
if(!ColorHelper::compatible(cl->color(), qr.data->clause->color())) {
continue;
}
auto lhs = qr.data->term;
static RobSubstitution eqSortSubs;
if(lhs.isVar()){
eqSortSubs.reset();
TermList querySort = trm.sort();
TermList eqSort = qr.data->term.sort();
if(!eqSortSubs.match(eqSort, 0, querySort, 1)){
continue;
}
}
auto subs = qr.unifier;
ASS(subs->isIdentityOnQueryWhenResultBound());
ApplicatorWithEqSort applWithEqSort(subs.ptr(), eqSortSubs);
Applicator applWithoutEqSort(subs.ptr());
auto appl = lhs.isVar() ? (SubstApplicator*)&applWithEqSort : (SubstApplicator*)&applWithoutEqSort;
AppliedTerm rhsApplied(qr.data->rhs,appl,true);
bool preordered = qr.data->preordered;
ASS_EQ(ordering.compare(trm,rhsApplied),Ordering::reverse(ordering.compare(rhsApplied,trm)));
if (_useTermOrderingDiagrams) {
#if VDEBUG
auto dcomp = ordering.compareUnidirectional(trm,rhsApplied);
#endif
qr.data->tod->init(appl);
if (!preordered && (_preorderedOnly || !qr.data->tod->next())) {
ASS_NEQ(dcomp,Ordering::GREATER);
continue;
}
ASS_EQ(dcomp,Ordering::GREATER);
} else {
if (!preordered && (_preorderedOnly || ordering.compareUnidirectional(trm,rhsApplied)!=Ordering::GREATER)) {
continue;
}
}
if (redundancyCheck && _encompassing) {
Ordering::Result litOrder = ordering.getEqualityArgumentOrder(lit);
if ((trm==*lit->nthArgument(0) && litOrder == Ordering::LESS) ||
(trm==*lit->nthArgument(1) && litOrder == Ordering::GREATER)) {
redundancyCheck = false;
}
}
TermList rhsS = rhsApplied.apply();
if (redundancyCheck && !_helper.isPremiseRedundant(cl, lit, trm, rhsS, lhs, appl)) {
continue;
}
Literal* resLit = EqHelper::replace(lit,trm,rhsS);
if(EqHelper::isEqTautology(resLit)) {
env.statistics->forwardDemodulationsToEqTaut++;
premises = pvi( getSingletonIterator(qr.data->clause));
return true;
}
RStack<Literal*> resLits;
resLits->push(resLit);
for(unsigned i=0;i<cLen;i++) {
Literal* curr=(*cl)[i];
if(curr!=lit) {
resLits->push(curr);
}
}
premises = pvi( getSingletonIterator(qr.data->clause));
replacement = Clause::fromStack(*resLits, SimplifyingInference2(InferenceRule::FORWARD_DEMODULATION, cl, qr.data->clause));
if(env.options->proofExtra() == Options::ProofExtra::FULL)
env.proofExtra.insert(replacement, new ForwardDemodulationExtra(lhs, trm));
return true;
}
}
}
return false;
}
}