#include "Debug/RuntimeStatistics.hpp"
#include "Forwards.hpp"
#include "Lib/Environment.hpp"
#include "Lib/Metaiterators.hpp"
#include "Lib/PairUtils.hpp"
#include "Lib/Recycled.hpp"
#include "Lib/VirtualIterator.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/ColorHelper.hpp"
#include "Kernel/EqHelper.hpp"
#include "Kernel/Inference.hpp"
#include "Kernel/Ordering.hpp"
#include "Kernel/SortHelper.hpp"
#include "Kernel/Term.hpp"
#include "Kernel/LiteralSelector.hpp"
#include "Kernel/RobSubstitution.hpp"
#include "Indexing/Index.hpp"
#include "Saturation/SaturationAlgorithm.hpp"
#include "Shell/PartialRedundancyHandler.hpp"
#include "Shell/Options.hpp"
#include "Debug/TimeProfiling.hpp"
#include "Superposition.hpp"
#if VDEBUG
#include <iostream>
using namespace std;
#endif
using namespace Inferences;
using namespace Lib;
using namespace Kernel;
using namespace Indexing;
using namespace Saturation;
using std::pair;
void Superposition::attach(SaturationAlgorithm* salg)
{
GeneratingInferenceEngine::attach(salg);
_subtermIndex = salg->getGeneratingIndex<SuperpositionSubtermIndex>();
_lhsIndex = salg->getGeneratingIndex<SuperpositionLHSIndex>();
}
void Superposition::detach()
{
_subtermIndex = nullptr;
_lhsIndex = nullptr;
GeneratingInferenceEngine::detach();
}
struct Superposition::ForwardResultFn
{
ForwardResultFn(Clause* cl, Superposition& parent) : _cl(cl), _parent(parent) {}
Clause* operator()(pair<pair<Literal*, TypedTermList>, QueryRes<AbstractingUnifier*, TermLiteralClause>> arg)
{
auto& qr = arg.second;
return _parent.performSuperposition(_cl, arg.first.first, arg.first.second,
qr.data->clause, qr.data->literal, qr.data->term, qr.unifier, true);
}
private:
Clause* _cl;
Superposition& _parent;
};
struct Superposition::BackwardResultFn
{
BackwardResultFn(Clause* cl, Superposition& parent) : _cl(cl), _parent(parent) {}
Clause* operator()(pair<pair<Literal*, TermList>, QueryRes<AbstractingUnifier*, TermLiteralClause>> arg)
{
if(_cl==arg.second.data->clause) {
return 0;
}
auto& qr = arg.second;
return _parent.performSuperposition(qr.data->clause, qr.data->literal, qr.data->term,
_cl, arg.first.first, arg.first.second, qr.unifier, false);
}
private:
Clause* _cl;
Superposition& _parent;
};
ClauseIterator Superposition::generateClauses(Clause* premise)
{
auto itf1 = premise->getSelectedLiteralIterator();
auto itf2 = getMapAndFlattenIterator(itf1,
[this](Literal* lit)
{ return pushPairIntoRightIterator(lit, EqHelper::getSubtermIterator(lit, _salg->getOrdering())); });
auto itf3 = getMapAndFlattenIterator(std::move(itf2),
[this](pair<Literal*, TypedTermList> arg)
{ return pushPairIntoRightIterator(arg, _lhsIndex->getUwa(arg.second, env.options->unificationWithAbstraction(), env.options->unificationWithAbstractionFixedPointIteration())); });
auto itf4 = getMappingIterator(std::move(itf3),ForwardResultFn(premise, *this));
auto itb1 = premise->getSelectedLiteralIterator();
auto itb2 = getMapAndFlattenIterator(itb1,EqHelper::SuperpositionLHSIteratorFn(_salg->getOrdering(), _salg->getOptions()));
auto itb3 = getMapAndFlattenIterator(std::move(itb2),
[this] (pair<Literal*, TermList> arg)
{ return pushPairIntoRightIterator(
arg,
_subtermIndex->getUwa(TypedTermList(arg.second, SortHelper::getEqualityArgumentSort(arg.first)), env.options->unificationWithAbstraction(), env.options->unificationWithAbstractionFixedPointIteration())); });
auto itb4 = getMappingIterator(std::move(itb3),BackwardResultFn(premise, *this));
auto it5 = concatIters(std::move(itf4),std::move(itb4));
auto it6 = getFilteredIterator(std::move(it5),NonzeroFn());
auto it7 = TIME_TRACE_ITER("superposition", std::move(it6));
return pvi( std::move(it7) );
}
bool Superposition::checkClauseColorCompatibility(Clause* eqClause, Clause* rwClause)
{
if(ColorHelper::compatible(rwClause->color(), eqClause->color())) {
return true;
}
if(getOptions().showBlocked()) {
std::cout<<"Blocked superposition of "<<eqClause->toString()<<" into "<<rwClause->toString()<<std::endl;
}
env.statistics->inferencesSkippedDueToColors++;
return false;
}
bool Superposition::checkSuperpositionFromVariable(Clause* eqClause, Literal* eqLit, TermList eqLHS)
{
ASS(eqLHS.isVar());
unsigned clen = eqClause->length();
for(unsigned i=0; i<clen; i++) {
Literal* lit = (*eqClause)[i];
if(lit==eqLit) {
continue;
}
if(lit->isEquality()) {
for(unsigned aIdx=0; aIdx<2; aIdx++) {
TermList arg = *lit->nthArgument(aIdx);
if(arg.isTerm() && arg.containsSubterm(eqLHS)) {
return false;
}
}
}
else if(lit->containsSubterm(eqLHS)) {
return false;
}
}
return true;
}
bool Superposition::earlyWeightLimitCheck(Clause* eqClause, Literal* eqLit,
Clause* rwClause, Literal* rwLit, TermList rwTerm, TermList eqLHS, TermList eqRHS,
ResultSubstitutionSP subst, bool eqIsResult, PassiveClauseContainer* passiveClauseContainer, unsigned numPositiveLiteralsLowerBound, const Inference& inf)
{
unsigned nonInvolvedLiteralWLB=0;
unsigned rwLength = rwClause->length();
for(unsigned i=0;i<rwLength;i++) {
Literal* curr=(*rwClause)[i];
if(curr!=rwLit) {
nonInvolvedLiteralWLB+=curr->weight();
}
}
unsigned eqLength = eqClause->length();
for(unsigned i=0;i<eqLength;i++) {
Literal* curr=(*eqClause)[i];
if(curr!=eqLit) {
nonInvolvedLiteralWLB+=curr->weight();
}
}
if(passiveClauseContainer->exceedsWeightLimit(nonInvolvedLiteralWLB + eqRHS.weight(), numPositiveLiteralsLowerBound, inf)) {
env.statistics->discardedNonRedundantClauses++;
RSTAT_CTR_INC("superpositions weight skipped early");
return false;
}
unsigned lhsSWeight = subst->getApplicationWeight(eqLHS, eqIsResult);
unsigned rhsSWeight = subst->getApplicationWeight(eqRHS, eqIsResult);
int rwrBalance = rhsSWeight-lhsSWeight;
if(rwrBalance>=0) {
unsigned approxWeight = rwLit->weight()+rwrBalance;
if(passiveClauseContainer->exceedsWeightLimit(nonInvolvedLiteralWLB + approxWeight, numPositiveLiteralsLowerBound, inf)) {
env.statistics->discardedNonRedundantClauses++;
RSTAT_CTR_INC("superpositions weight skipped after rewriter weight retrieval");
return false;
}
}
size_t rwrCnt = (rwrBalance==0) ? 0 : rwLit->countSubtermOccurrences(rwTerm);
if(rwrCnt>1) {
ASS_GE(rwrCnt, 1);
unsigned approxWeight = rwLit->weight()+(rwrBalance*rwrCnt);
if(passiveClauseContainer->exceedsWeightLimit(nonInvolvedLiteralWLB + approxWeight, numPositiveLiteralsLowerBound, inf)) {
env.statistics->discardedNonRedundantClauses++;
RSTAT_CTR_INC("superpositions weight skipped after rewriter weight retrieval with occurrence counting");
return false;
}
}
unsigned rwLitSWeight = subst->getApplicationWeight(rwLit, !eqIsResult);
unsigned finalLitWeight = rwLitSWeight+(rwrBalance*rwrCnt);
if(passiveClauseContainer->exceedsWeightLimit(nonInvolvedLiteralWLB + finalLitWeight, numPositiveLiteralsLowerBound, inf)) {
env.statistics->discardedNonRedundantClauses++;
RSTAT_CTR_INC("superpositions weight skipped after rewritten literal weight retrieval");
return false;
}
return true;
}
Clause* Superposition::performSuperposition(
Clause* rwClause, Literal* rwLit, TermList rwTerm,
Clause* eqClause, Literal* eqLit, TermList eqLHS,
AbstractingUnifier* unifier, bool eqIsResult)
{
TIME_TRACE("perform superposition");
ASS(rwClause->store()==Clause::ACTIVE);
ASS(eqClause->store()==Clause::ACTIVE);
auto subst = ResultSubstitution::fromSubstitution(&unifier->subs(), RetrievalAlgorithms::DefaultVarBanks::query, RetrievalAlgorithms::DefaultVarBanks::internal);
TermList eqLHSsort = SortHelper::getEqualityArgumentSort(eqLit);
if(eqLHS.isVar()) {
if(!checkSuperpositionFromVariable(eqClause, eqLit, eqLHS)) {
return 0;
}
}
if(!checkClauseColorCompatibility(eqClause, rwClause)) {
return 0;
}
unsigned rwLength = rwClause->length();
unsigned eqLength = eqClause->length();
TermList tgtTerm = EqHelper::getOtherEqualitySide(eqLit, eqLHS);
unsigned numPositiveLiteralsLowerBound = std::max(eqClause->numPositiveLiterals()-1, rwClause->numPositiveLiterals()); Inference inf(GeneratingInference2(unifier->usesUwa() ? InferenceRule::CONSTRAINED_SUPERPOSITION : InferenceRule::SUPERPOSITION, rwClause, eqClause));
Inference::Destroyer inf_destroyer(inf);
auto passiveClauseContainer = _salg->getPassiveClauseContainer();
bool andThatsIt = false;
bool hasAgeLimitStrike = passiveClauseContainer && passiveClauseContainer->mayBeAbleToDiscriminateClausesUnderConstructionOnLimits()
&& passiveClauseContainer->exceedsAgeLimit(numPositiveLiteralsLowerBound, inf, andThatsIt);
if(hasAgeLimitStrike && andThatsIt) { env.statistics->discardedNonRedundantClauses++;
RSTAT_CTR_INC("superpositions skipped for (pure) age limit before building clause");
return 0;
}
if(hasAgeLimitStrike) {
if(!earlyWeightLimitCheck(eqClause, eqLit, rwClause, rwLit, rwTerm, eqLHS, tgtTerm, subst, eqIsResult, passiveClauseContainer, numPositiveLiteralsLowerBound, inf)) {
return 0;
}
}
const auto& parRedHandler = _salg->parRedHandler();
if (!unifier->usesUwa()) {
if (!parRedHandler.checkSuperposition(eqClause, eqLit, rwClause, rwLit, eqIsResult, subst.ptr())) {
return 0;
}
}
const Ordering& ordering = _salg->getOrdering();
TermList tgtTermS = subst->apply(tgtTerm, eqIsResult);
Literal* rwLitS = subst->apply(rwLit, !eqIsResult);
TermList rwTermS = subst->apply(rwTerm, !eqIsResult);
auto comp = ordering.compare(tgtTermS,rwTermS);
if(Ordering::isGreaterOrEqual(comp)) {
return 0;
}
if(rwLitS->isEquality()) {
TermList arg0=*rwLitS->nthArgument(0);
TermList arg1=*rwLitS->nthArgument(1);
if(!arg0.containsSubterm(rwTermS)) {
if(Ordering::isGreaterOrEqual(ordering.getEqualityArgumentOrder(rwLitS))) {
return 0;
}
} else if(!arg1.containsSubterm(rwTermS)) {
if(Ordering::isGreaterOrEqual(Ordering::reverse(ordering.getEqualityArgumentOrder(rwLitS)))) {
return 0;
}
}
}
Literal* tgtLitS = EqHelper::replace(rwLitS,rwTermS,tgtTermS);
static bool doSimS = getOptions().simulatenousSuperposition();
if(EqHelper::isEqTautology(tgtLitS)) {
if (!unifier->usesUwa()) {
parRedHandler.insertSuperposition(
eqClause, rwClause, rwTerm, rwTermS, tgtTermS, eqLHS, rwLitS, eqLit, comp, eqIsResult, subst.ptr());
}
return 0;
}
TermList eqLHSS = subst->apply(eqLHS, eqIsResult);
#if VDEBUG
if(!unifier->usesUwa()){
ASS_EQ(rwTermS,eqLHSS);
}
#endif
Recycled<Stack<Literal*>> res;
res->reserve(rwLength + eqLength - 1 + unifier->maxNumberOfConstraints());
static bool afterCheck = getOptions().literalMaximalityAftercheck() && _salg->getLiteralSelector().isBGComplete();
res->push(tgtLitS);
unsigned weight=tgtLitS->weight();
for(unsigned i=0;i<rwLength;i++) {
Literal* curr=(*rwClause)[i];
if(curr!=rwLit) {
Literal* currAfter = subst->apply(curr, !eqIsResult);
if (doSimS) {
currAfter = EqHelper::replace(currAfter,rwTermS,tgtTermS);
}
if(EqHelper::isEqTautology(currAfter)) {
return nullptr;
}
if(hasAgeLimitStrike) {
weight+=currAfter->weight();
if(passiveClauseContainer->exceedsWeightLimit(weight, numPositiveLiteralsLowerBound, inf)) {
RSTAT_CTR_INC("superpositions skipped for weight limit while constructing other literals");
env.statistics->discardedNonRedundantClauses++;
return nullptr;
}
}
if (afterCheck) {
TIME_TRACE(TimeTrace::LITERAL_ORDER_AFTERCHECK)
if (i < rwClause->numSelected() && ordering.compare(currAfter,rwLitS) == Ordering::GREATER) {
env.statistics->inferencesBlockedDueToOrderingAftercheck++;
return nullptr;
}
}
res->push(currAfter);
}
}
{
Literal* eqLitS = 0;
if (afterCheck && eqClause->numSelected() > 1) {
TIME_TRACE(TimeTrace::LITERAL_ORDER_AFTERCHECK);
eqLitS = Literal::createEquality(true,eqLHSS,tgtTermS,eqLHSsort);
}
for(unsigned i=0;i<eqLength;i++) {
Literal* curr=(*eqClause)[i];
if(curr!=eqLit) {
Literal* currAfter = subst->apply(curr, eqIsResult);
if(EqHelper::isEqTautology(currAfter)) {
return nullptr;
}
if(hasAgeLimitStrike) {
weight+=currAfter->weight();
if(passiveClauseContainer->exceedsWeightLimit(weight, numPositiveLiteralsLowerBound, inf)) {
RSTAT_CTR_INC("superpositions skipped for weight limit while constructing other literals");
env.statistics->discardedNonRedundantClauses++;
return nullptr;
}
}
if (eqLitS && i < eqClause->numSelected()) {
TIME_TRACE(TimeTrace::LITERAL_ORDER_AFTERCHECK);
Ordering::Result o = ordering.compare(currAfter,eqLitS);
if (o == Ordering::GREATER || o == Ordering::EQUAL) {
env.statistics->inferencesBlockedDueToOrderingAftercheck++;
return nullptr;
}
}
res->push(currAfter);
}
}
}
if (!unifier->usesUwa()) {
parRedHandler.insertSuperposition(
eqClause, rwClause, rwTerm, rwTermS, tgtTermS, eqLHS, rwLitS, eqLit, comp, eqIsResult, subst.ptr());
}
res->loadFromIterator(unifier->computeConstraintLiterals()->iter());
if(hasAgeLimitStrike && passiveClauseContainer->exceedsWeightLimit(weight, numPositiveLiteralsLowerBound, inf)) {
RSTAT_CTR_INC("superpositions skipped for weight limit after the clause was built");
env.statistics->discardedNonRedundantClauses++;
return nullptr;
}
inf_destroyer.disable(); auto clause = Clause::fromStack(*res, inf);
Literal *rwAnsLit, *eqAnsLit;
if ((env.options->questionAnswering() == Options::QuestionAnsweringMode::SYNTHESIS) &&
(rwAnsLit = rwClause->getAnswerLiteral()) && (eqAnsLit = eqClause->getAnswerLiteral())) {
env.proofExtra.insert(clause, new SuperpositionExtra(
rwLit,
eqLit,
eqLHS,
rwTerm,
subst->apply(eqLit, eqIsResult),
rwAnsLit ? subst->apply(rwAnsLit, !eqIsResult) : nullptr,
eqAnsLit ? subst->apply(eqAnsLit, eqIsResult) : nullptr
));
} else if (env.options->proofExtra() == Options::ProofExtra::FULL) {
env.proofExtra.insert(clause, new SuperpositionExtra(
rwLit,
eqLit,
eqLHS,
rwTerm
));
}
return clause;
}