#ifndef SUBSUMPTIONDEMODULATIONHELPER_HPP
#define SUBSUMPTIONDEMODULATIONHELPER_HPP
#include <unordered_set>
#include <unordered_map>
#include "Indexing/LiteralMiniIndex.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/Ordering.hpp"
#include "Kernel/SubstHelper.hpp"
#include "Kernel/Term.hpp"
#define FSD_LOG_INFERENCES false
#define FSD_VDEBUG_REDUNDANCY_ASSERTIONS true
#define BSD_LOG_INFERENCES false
#define BSD_VDEBUG_REDUNDANCY_ASSERTIONS true
namespace Inferences {
using namespace Indexing;
using namespace Kernel;
using namespace Lib;
class OverlayBinder
{
USE_ALLOCATOR(OverlayBinder);
public:
using Var = unsigned int;
using BindingsMap = std::unordered_map<Var, TermList>;
OverlayBinder()
: m_base(16)
, m_overlay(16)
{ }
explicit
OverlayBinder(BindingsMap&& initialBindings)
: m_base(std::move(initialBindings))
, m_overlay(16)
{ }
bool bind(Var var, TermList term)
{
auto base_it = m_base.find(var);
if (base_it != m_base.end()) {
return base_it->second == term;
}
else {
auto res = m_overlay.insert({var, term});
auto it = res.first;
bool inserted = res.second;
return inserted || (it->second == term);
}
}
bool isBound(Var var) const
{
return m_base.find(var) != m_base.end()
|| m_overlay.find(var) != m_overlay.end();
}
void specVar(Var var, TermList term) const
{
ASSERTION_VIOLATION;
}
void clear()
{
m_base.clear();
m_overlay.clear();
}
BindingsMap& base()
{
ASS(m_overlay.empty());
return m_base;
}
void reset()
{
m_overlay.clear();
}
bool tryGetBinding(Var var, TermList& result) const
{
auto b_it = m_base.find(var);
if (b_it != m_base.end()) {
result = b_it->second;
return true;
} else {
auto o_it = m_overlay.find(var);
if (o_it != m_overlay.end()) {
result = o_it->second;
return true;
} else {
return false;
}
}
}
TermList apply(Var var) const
{
TermList result;
if (tryGetBinding(var, result)) {
return result;
} else {
ASSERTION_VIOLATION;
}
}
TermList applyTo(TermList t, bool noSharing = false) const
{
return SubstHelper::apply(t, *this, noSharing);
}
Literal* applyTo(Literal* l) const
{
return SubstHelper::apply(l, *this);
}
TermList applyWithUnboundVariableOffsetTo(TermList t, Var unboundVarOffset, bool noSharing = false) const
{
UnboundVariableOffsetApplicator applicator(*this, unboundVarOffset);
return SubstHelper::apply(t, applicator, noSharing);
}
public:
class UnboundVariableOffsetApplicator
{
public:
UnboundVariableOffsetApplicator(OverlayBinder const& binder, Var unboundVarOffset)
: binder(binder), unboundVarOffset(unboundVarOffset)
{ }
TermList apply(Var var) const
{
TermList result;
if (binder.tryGetBinding(var, result)) {
return result;
} else {
return TermList(var + unboundVarOffset, false);
}
}
private:
OverlayBinder const& binder;
Var unboundVarOffset;
};
private:
BindingsMap m_base;
BindingsMap m_overlay;
friend std::ostream& operator<<(std::ostream& o, OverlayBinder const& binder);
};
std::ostream& operator<<(std::ostream& o, OverlayBinder const& binder);
class SDClauseMatches
{
USE_ALLOCATOR(SDClauseMatches);
public:
SDClauseMatches(Clause* base, LiteralMiniIndex const& ixAlts);
~SDClauseMatches();
SDClauseMatches(SDClauseMatches const&) = delete;
SDClauseMatches& operator=(SDClauseMatches const&) = delete;
SDClauseMatches(SDClauseMatches&&) = default;
SDClauseMatches& operator=(SDClauseMatches&&) = default;
Clause* base() const { return m_base; }
LiteralList const* const* alts() const { return m_alts.data(); }
unsigned baseLitsWithoutAlts() const { return m_baseLitsWithoutAlts; }
bool isSubsumptionPossible() const
{
return m_baseLitsWithoutAlts == 0;
}
bool isSubsumptionDemodulationPossible() const
{
ASS_GE(m_baseLitsWithoutAlts, m_basePosEqsWithoutAlts);
if (m_basePosEqs == 0) {
return false;
}
return m_baseLitsWithoutAlts == 0 || (m_baseLitsWithoutAlts == 1 && m_basePosEqsWithoutAlts == 1); }
private:
Clause* m_base;
std::vector<LiteralList*> m_alts;
unsigned m_basePosEqs;
unsigned m_baseLitsWithoutAlts;
unsigned m_basePosEqsWithoutAlts;
};
class SDHelper
{
public:
static bool checkForSubsumptionResolution(Clause* cl, SDClauseMatches const& cm, Literal* resLit);
static Clause* generateSubsumptionResolutionClause(Clause* cl, Literal* resLit, Clause* mcl, bool forward);
#if VDEBUG
private:
enum class ClauseComparisonResult
{
Smaller,
Equal,
GreaterOrIncomparable
};
static ClauseComparisonResult clauseCompare(Literal* const lits1[], unsigned n1, Literal* const lits2[], unsigned n2, Ordering const& ordering);
template <typename Applicator>
static ClauseComparisonResult substClauseCompare(Clause* mcl, Applicator const& applicator, Clause* cl, Ordering const& ordering)
{
std::vector<Literal*> mclS(mcl->literals(), mcl->literals() + mcl->length());
ASS_EQ(mcl->length(), mclS.size());
for (auto it = mclS.begin(); it != mclS.end(); ++it) {
*it = applicator.applyTo(*it);
}
return SDHelper::clauseCompare(mclS.data(), mclS.size(), cl->literals(), cl->length(), ordering);
}
public:
static bool clauseIsSmaller(Literal* const lits1[], unsigned n1, Literal* const lits2[], unsigned n2, Ordering const& ordering)
{
return clauseCompare(lits1, n1, lits2, n2, ordering) == ClauseComparisonResult::Smaller;
}
static bool clauseIsSmaller(Clause* mcl, Clause* cl, Ordering const& ordering)
{
return SDHelper::clauseIsSmaller(mcl->literals(), mcl->length(), cl->literals(), cl->length(), ordering);
}
template <typename Applicator>
static bool substClauseIsSmaller(Clause* mcl, Applicator const& applicator, Clause* cl, Ordering const& ordering)
{
return SDHelper::substClauseCompare(mcl, applicator, cl, ordering) == ClauseComparisonResult::Smaller;
}
template <typename Applicator>
static bool substClauseIsSmallerOrEqual(Clause* mcl, Applicator const& applicator, Clause* cl, Ordering const& ordering)
{
auto result = SDHelper::substClauseCompare(mcl, applicator, cl, ordering);
return result == ClauseComparisonResult::Smaller || result == ClauseComparisonResult::Equal;
}
#endif
};
template <typename Applicator>
bool termContainsAllVariablesOfOtherUnderSubst(TermList term, TermList other, Applicator const& applicator)
{
static std::unordered_set<unsigned int> vars(16);
vars.clear();
static VariableIterator vit;
static VariableIterator vit2;
vit.reset(term);
while (vit.hasNext()) {
TermList t = applicator.apply(vit.next().var());
vit2.reset(t);
while (vit2.hasNext()) {
vars.insert(vit2.next().var());
}
}
vit.reset(other);
while (vit.hasNext()) {
TermList t = applicator.apply(vit.next().var());
vit2.reset(t);
while (vit2.hasNext()) {
if (vars.find(vit2.next().var()) == vars.end()) {
#if VDEBUG
{
TermList termS = SubstHelper::apply(term, applicator, true);
TermList otherS = SubstHelper::apply(other, applicator, true);
ASS(!termS.containsAllVariablesOf(otherS));
if (termS.isTerm()) { termS.term()->destroyNonShared(); }
if (otherS.isTerm()) { otherS.term()->destroyNonShared(); }
}
#endif
return false;
}
}
}
#if VDEBUG
{
TermList termS = SubstHelper::apply(term, applicator, true);
TermList otherS = SubstHelper::apply(other, applicator, true);
ASS(termS.containsAllVariablesOf(otherS));
if (termS.isTerm()) { termS.term()->destroyNonShared(); }
if (otherS.isTerm()) { otherS.term()->destroyNonShared(); }
}
#endif
return true;
}
};
#endif