#ifndef __Induction__
#define __Induction__
#include <unordered_map>
#include "Forwards.hpp"
#include "Indexing/Index.hpp"
#include "Indexing/InductionFormulaIndex.hpp"
#include "Indexing/LiteralIndex.hpp"
#include "Indexing/TermIndex.hpp"
#include "Kernel/Formula.hpp"
#include "Kernel/TermTransformer.hpp"
#include "Lib/DHMap.hpp"
#include "Saturation/SaturationAlgorithm.hpp"
#include "Shell/FunctionDefinitionHandler.hpp"
#include "InductionHelper.hpp"
#include "InferenceEngine.hpp"
namespace Inferences
{
using namespace Kernel;
using namespace Saturation;
using namespace Shell;
using namespace Lib;
class ActiveOccurrenceIterator
: public IteratorCore<Term*>
{
public:
ActiveOccurrenceIterator(Literal* lit, FunctionDefinitionHandler& fnDefHandler)
: _stack(8), _fnDefHandler(fnDefHandler)
{
_stack.push(lit);
}
bool hasNext() override { return _stack.isNonEmpty(); }
Term* next() override;
private:
Stack<Term*> _stack;
FunctionDefinitionHandler& _fnDefHandler;
};
struct StlClauseHash {
std::size_t operator()(Clause* c) const { return std::hash<unsigned>()(c->number()); }
};
Term* getPlaceholderForTerm(const Stack<Term*>& ts, unsigned i);
class TermReplacement : public TermTransformer {
public:
TermReplacement(const std::unordered_map<Term*, TermList>& m) : _m(m) {}
TermList transformSubterm(TermList trm) override;
protected:
std::unordered_map<Term*,TermList> _m;
};
class InductionTermReplacement : public TermReplacement {
public:
InductionTermReplacement(const std::unordered_map<Term*, TermList>& m, bool squashSkolems, unsigned& nextVar)
: TermReplacement(m), _squashSkolems(squashSkolems), _nextVar(nextVar), _renaming() {}
TermList transformSubterm(TermList trm) override;
void resetRenaming(RobSubstitution* subst, unsigned bank);
VList* getRenamedFreeVars() const;
VList* getVarsReplacingSkolems() const;
const bool _squashSkolems;
unsigned& _nextVar;
DHMap<Term*, unsigned, SharedTermHash> _skolemToVarMap; DHSet<unsigned> _varsReplacingSkolems;
DHMap<unsigned,unsigned> _renaming; DHSet<unsigned> _renamedFreeVars;
};
struct InductionContext {
InductionContext(const Stack<Term*>& indTerms, Literal* lit, Clause* cl)
: InductionContext(indTerms, { { cl, { lit } } }) {}
InductionContext(const Stack<Term*>& indTerms, Stack<std::pair<Clause*, LiteralStack>>&& cls)
: _indTerms(indTerms), _cls(cls)
{
ASS(iterTraits(_indTerms.iter()).all([](Term* t) { return t->ground(); }));
for (const auto& e : _cls) { std::sort(e.second.begin(), e.second.end()); }
std::sort(_cls.begin(), _cls.end(), [](const auto& e1, const auto& e2) { return e1.second < e2.second; });
}
Formula* getFormula(
const InductionUnit& unit, const Substitution& typeBinder, unsigned& nextVar,
VList** varsReplacingSkolems = nullptr, RobSubstitution* subst = nullptr) const;
Formula* getFormulaWithFreeVar(TermList t, unsigned freeVar, unsigned freeVarSub, RobSubstitution* subst = nullptr) const;
template<typename Fun>
InductionContext transform(Fun fn) const;
unsigned getFreeVariable() const;
friend std::ostream& operator<<(std::ostream& out, const InductionContext& context) {
for (const auto& indt : context._indTerms) {
out << *indt << std::endl;
}
for (const auto& [cl, lits] : context._cls) {
out << "cl " << *cl << std::endl;
out << "lits ";
for (const auto& lit : lits) {
out << *lit << " ";
}
out << std::endl;
}
return out;
}
Stack<Term*> _indTerms;
Stack<std::pair<Clause*, LiteralStack>> _cls;
private:
Formula* getFormulaWithSquashedSkolems(
const std::vector<TermList>& r, unsigned& nextVar, VList*& renamedFreeVars, VList** varsReplacingSkolems, RobSubstitution* subst) const;
Formula* getFormula(InductionTermReplacement& tr, RobSubstitution* subst) const;
std::unordered_map<Term*,TermList> getReplacementMap(const std::vector<TermList>& r, RobSubstitution* subst) const;
};
class ContextReplacement
: public TermReplacement, public IteratorCore<InductionContext> {
public:
ContextReplacement(const InductionContext& context);
bool hasNext() override {
return !_used;
}
InductionContext next() override;
protected:
InductionContext _context;
bool _used;
};
class ActiveOccurrenceContextReplacement
: public ContextReplacement {
public:
ActiveOccurrenceContextReplacement(const InductionContext& context, const FunctionDefinitionHandler& fnDefHandler);
InductionContext next() override;
bool hasNonActive() const { return _hasNonActive; }
protected:
TermList transformSubterm(TermList trm) override;
private:
const FunctionDefinitionHandler& _fnDefHandler;
std::vector<unsigned> _iteration;
std::vector<unsigned> _matchCount;
bool _hasNonActive;
};
class ContextSubsetReplacement
: public ContextReplacement {
public:
ContextSubsetReplacement(const InductionContext& context, const unsigned maxSubsetSize);
bool hasNext() override;
InductionContext next() override;
protected:
TermList transformSubterm(TermList trm) override;
private:
bool shouldSkipIteration() const;
void stepIteration();
std::vector<unsigned> _iteration;
std::vector<unsigned> _maxIterations;
std::vector<unsigned> _matchCount;
const unsigned _maxOccurrences = 1 << 20;
const unsigned _maxSubsetSize;
bool _ready;
bool _done;
};
class Induction
: public GeneratingInferenceEngine
{
using TermIndex = Indexing::TermIndex<TermLiteralClause>;
public:
void attach(SaturationAlgorithm* salg) override;
void detach() override;
ClauseIterator generateClauses(Clause* premise) override;
private:
std::shared_ptr<UnitIntegerComparisonLiteralIndex> _comparisonIndex;
std::shared_ptr<InductionTermIndex> _inductionTermIndex;
std::shared_ptr<StructInductionTermIndex> _structInductionTermIndex;
InductionFormulaIndex _formulaIndex;
InductionFormulaIndex _recFormulaIndex;
};
class InductionClauseIterator
{
using TermIndex = Indexing::TermIndex<TermLiteralClause>;
public:
InductionClauseIterator(Clause* premise, InductionHelper helper, SaturationAlgorithm* salg,
TermIndex* structInductionTermIndex, InductionFormulaIndex& formulaIndex)
: _helper(helper), _opt(salg->getOptions()), _structInductionTermIndex(structInductionTermIndex),
_formulaIndex(formulaIndex), _fnDefHandler(salg->getFunctionDefinitionHandler())
{
processClause(premise);
}
DECL_ELEMENT_TYPE(Clause*);
inline bool hasNext() { return _clauses.isNonEmpty(); }
inline OWN_ELEMENT_TYPE next() {
return _clauses.pop();
}
private:
void processClause(Clause* premise);
void processLiteral(Clause* premise, Literal* lit);
void processIntegerComparison(Clause* premise, Literal* lit);
ClauseStack produceClauses(Formula* hypothesis, InferenceRule rule, const InductionContext& context, Substitution& cnfSubst);
void resolveClauses(const InductionContext& context, InductionFormulaIndex::Entry* e, const TermLiteralClause* bound1, const TermLiteralClause* bound2);
void resolveClauses(const InductionInstance& indInst, const InductionContext& context);
void performFinIntInduction(const InductionContext& context, const TermLiteralClause& lb, const TermLiteralClause& ub);
void performInfIntInduction(const InductionContext& context, bool increasing, const TermLiteralClause& bound);
struct DefaultBound { TypedTermList term; };
using Bound = Coproduct<TermLiteralClause, DefaultBound>;
std::unique_ptr<InductionTemplate> getIntegerInductionTemplate(bool increasing, Bound bound1, const TermLiteralClause* optionalBound2);
void performIntInduction(const InductionContext& context, InductionFormulaIndex::Entry* e, bool increasing, Bound bound1, const TermLiteralClause* optionalBound2);
void performIntInduction(const InductionContext& context, InductionFormulaIndex::Entry* e, bool increasing, TermLiteralClause const& bound1, const TermLiteralClause* optionalBound2)
{ performIntInduction(context, e, increasing, Bound::variant<0>(bound1), optionalBound2); }
void performInduction(const InductionContext& context, const InductionTemplate* templ, InductionFormulaIndex::Entry* e);
void performStructInductionFreeVar(const InductionContext& context, InductionFormulaIndex::Entry* e);
bool notDoneInt(InductionContext context, Literal* bound1, Literal* bound2, InductionFormulaIndex::Entry*& e);
bool isValidBound(const InductionContext& context, const Bound& bound);
bool isValidBound(const InductionContext& context, const TermLiteralClause& bound)
{ return isValidBound(context, Bound(bound)); }
Stack<Clause*> _clauses;
InductionHelper _helper;
const Options& _opt;
TermIndex* _structInductionTermIndex;
InductionFormulaIndex& _formulaIndex;
FunctionDefinitionHandler& _fnDefHandler;
};
};
#endif