#include "Lib/Allocator.hpp"
#include "Lib/Recycled.hpp"
#include "Kernel/Matcher.hpp"
#include "Kernel/SubstHelper.hpp"
namespace Indexing
{
template<class LeafData_>
const unsigned SubstitutionTree<LeafData_>::GenMatcher::BACKTRACK_SEPARATOR;
template<class LeafData_>
struct SubstitutionTree<LeafData_>::GenMatcher::Binder
{
inline
Binder(GenMatcher* parent)
: _parent(parent), _maxVar(parent->_maxVar) {}
bool bind(unsigned var, TermList term)
{
if(var > _maxVar) {
return false;
}
TermList* aux;
if(_parent->_bindings.getValuePtr(var,aux,term)) {
_parent->_boundVars.push(var);
return true;
} else {
return *aux==term;
}
}
inline
void specVar(unsigned var, TermList term)
{
(_parent->_specVars)[var]=term;
}
private:
GenMatcher* _parent;
unsigned _maxVar;
};
template<class LeafData_>
struct SubstitutionTree<LeafData_>::GenMatcher::Applicator
{
USE_ALLOCATOR(SubstitutionTree::GenMatcher::Applicator);
inline
Applicator(GenMatcher* parent, Renaming* resultNormalizer)
: _parent(parent), _resultNormalizer(resultNormalizer) {}
TermList apply(unsigned var)
{
TermList* cacheEntry;
if(_cache.getValuePtr(var,cacheEntry)) {
ASS(_resultNormalizer->contains(var));
unsigned nvar=_resultNormalizer->get(var);
ASS(_parent->_bindings.find(nvar));
*cacheEntry=_parent->_bindings.get(nvar);
}
return *cacheEntry;
}
private:
GenMatcher* _parent;
Renaming* _resultNormalizer;
BindingMap _cache;
};
template<class LeafData_>
class SubstitutionTree<LeafData_>::GenMatcher::Substitution
: public ResultSubstitution
{
public:
USE_ALLOCATOR(SubstitutionTree::GenMatcher::Substitution);
Substitution(GenMatcher* parent, Renaming* resultNormalizer)
: _parent(parent), _resultNormalizer(resultNormalizer),
_applicator(0)
{}
~Substitution() override
{
if(_applicator) {
delete _applicator;
}
}
TermList applyToBoundResult(TermList t) final
{ return SubstHelper::apply(t, *getApplicator()); }
Literal* applyToBoundResult(Literal* lit) final
{ return SubstHelper::apply(lit, *getApplicator()); }
bool isIdentityOnQueryWhenResultBound() override
{ return true; }
void output(std::ostream& out) const final
{ out << "GenMatcher::Substitution(<output unimplemented>)"; }
private:
Applicator* getApplicator()
{
if(!_applicator) {
_applicator=new Applicator(_parent, _resultNormalizer);
}
return _applicator;
}
GenMatcher* _parent;
Renaming* _resultNormalizer;
Applicator* _applicator;
};
template<class LeafData_>
bool SubstitutionTree<LeafData_>::GenMatcher::matchNext(unsigned specVar, TermList nodeTerm, bool separate)
{
if(separate) {
_boundVars.push(BACKTRACK_SEPARATOR);
}
TermList queryTerm=(_specVars)[specVar];
return matchNextAux(queryTerm, nodeTerm, separate);
}
template<class LeafData_>
bool SubstitutionTree<LeafData_>::GenMatcher::matchNextAux(TermList queryTerm, TermList nodeTerm, bool separate)
{
bool success;
if(nodeTerm.isTerm()) {
Term* nt=nodeTerm.term();
if(nt->shared() && nt->ground()) {
success = nodeTerm==queryTerm;
} else {
Binder binder(this);
ASS(nt->arity()>0);
success = queryTerm.isTerm() && queryTerm.term()->functor()==nt->functor() &&
MatchingUtils::matchArgs(nt, queryTerm.term(), binder);
}
} else {
ASS_METHOD(nodeTerm,isOrdinaryVar());
unsigned var=nodeTerm.var();
Binder binder(this);
success=binder.bind(var,queryTerm);
}
if(!success) {
if(separate) {
for(;;) {
unsigned boundVar = _boundVars.pop();
if(boundVar==BACKTRACK_SEPARATOR) {
break;
}
_bindings.remove(boundVar);
}
}
}
return success;
}
template<class LeafData_>
void SubstitutionTree<LeafData_>::GenMatcher::backtrack()
{
for(;;) {
unsigned boundVar = _boundVars.pop();
if(boundVar==BACKTRACK_SEPARATOR) {
break;
}
_bindings.remove(boundVar);
}
}
template<class LeafData_>
ResultSubstitutionSP SubstitutionTree<LeafData_>::GenMatcher::getSubstitution(
Renaming* resultNormalizer)
{
return ResultSubstitutionSP(
new Substitution(this, resultNormalizer));
}
template<class LeafData_>
bool SubstitutionTree<LeafData_>::FastGeneralizationsIterator::hasNext()
{
while(!_ldIterator.hasNext() && findNextLeaf()) {}
return _ldIterator.hasNext();
}
template<class LeafData_>
QueryRes<ResultSubstitutionSP, LeafData_> SubstitutionTree<LeafData_>::FastGeneralizationsIterator::next()
{
while(!_ldIterator.hasNext() && findNextLeaf()) {}
ASS(_ldIterator.hasNext());
auto ld = _ldIterator.next();
if(_retrieveSubstitution) {
_resultNormalizer.reset();
_resultNormalizer.normalizeVariables(ld->key());
return QueryRes(_subst.getSubstitution(&_resultNormalizer),ld);
} else {
return QueryRes(ResultSubstitutionSP(), ld);
}
}
template<class LeafData_>
bool SubstitutionTree<LeafData_>::FastGeneralizationsIterator::findNextLeaf()
{
Node* curr;
bool sibilingsRemain = false;
if(_inLeaf) {
if(_alternatives.isEmpty()) {
return false;
}
_subst.backtrack();
_inLeaf=false;
curr=0;
} else {
if(!_root) {
return false;
}
curr=_root;
_root=0;
sibilingsRemain=enterNode(curr);
}
for(;;) {
main_loop_start:
unsigned currSpecVar = 0;
if(curr) {
if(sibilingsRemain) {
ASS(_nodeTypes.top()!=UNSORTED_LIST || *static_cast<Node**>(_alternatives.top()));
currSpecVar=_specVarNumbers.top();
} else {
currSpecVar=_specVarNumbers.pop();
}
}
while(curr==0 && _alternatives.isNonEmpty()) {
void* currAlt=_alternatives.pop();
if(!currAlt) {
_nodeTypes.pop();
_specVarNumbers.pop();
if(_alternatives.isNonEmpty()) {
_subst.backtrack();
}
continue;
}
NodeAlgorithm parentType=_nodeTypes.top();
if(parentType==UNSORTED_LIST) {
Node** alts=static_cast<Node**>(currAlt);
while(*alts && !(*alts)->term().isVar()) {
alts++;
}
curr=*(alts++);
while(*alts && !(*alts)->term().isVar()) {
alts++;
}
if(*alts) {
_alternatives.push(alts);
sibilingsRemain=true;
} else {
sibilingsRemain=false;
}
} else {
ASS_EQ(parentType,SKIP_LIST)
auto alts = static_cast<typename SListIntermediateNode::NodeSkipList::Node *>(currAlt);
if(alts->head()->term().isVar()) {
curr=alts->head();
if(alts->tail() && alts->tail()->head()->term().isVar()) {
_alternatives.push(alts->tail());
sibilingsRemain=true;
} else {
sibilingsRemain=false;
}
}
}
if(sibilingsRemain) {
currSpecVar=_specVarNumbers.top();
} else {
_nodeTypes.pop();
currSpecVar=_specVarNumbers.pop();
}
if(curr) {
break;
}
}
if(!curr) {
return false;
}
if(!_subst.matchNext(currSpecVar, curr->term(), sibilingsRemain)) { curr=0;
if(!sibilingsRemain && _alternatives.isNonEmpty()) {
_subst.backtrack();
}
continue;
}
while(!curr->isLeaf() && curr->algorithm()==UNSORTED_LIST && static_cast<UArrIntermediateNode*>(curr)->_size==1) {
unsigned specVar=static_cast<UArrIntermediateNode*>(curr)->childVar;
curr=static_cast<UArrIntermediateNode*>(curr)->_nodes[0];
ASS(curr);
if(!_subst.matchNext(specVar, curr->term(), false)) {
if(sibilingsRemain || _alternatives.isNonEmpty()) {
_subst.backtrack();
}
curr=0;
goto main_loop_start;
}
}
if(curr->isLeaf()) {
_ldIterator=static_cast<Leaf*>(curr)->allChildren();
_inLeaf=true;
return true;
}
sibilingsRemain=enterNode(curr);
if(curr==0 && _alternatives.isNonEmpty()) {
_subst.backtrack();
}
}
}
template<class LeafData_>
bool SubstitutionTree<LeafData_>::FastGeneralizationsIterator::enterNode(Node*& curr)
{
IntermediateNode* inode=static_cast<IntermediateNode*>(curr);
NodeAlgorithm currType=inode->algorithm();
TermList binding = _subst.getSpecVarBinding(inode->childVar);
curr=0;
if(currType==UNSORTED_LIST) {
Node** nl=static_cast<UArrIntermediateNode*>(inode)->_nodes;
if(binding.isTerm()) {
unsigned bindingFunctor=binding.term()->functor();
while(*nl && (*nl)->term().isTerm()) {
if(!curr && (*nl)->term().term()->functor()==bindingFunctor) {
curr=*nl;
}
nl++;
}
if(!curr && *nl) {
Node** nl2=nl+1;
while(*nl2) {
if((*nl2)->term().isTerm() && (*nl2)->term().term()->functor()==bindingFunctor) {
curr=*nl2;
break;
}
nl2++;
}
}
} else {
while(*nl && (*nl)->term().isTerm()) {
nl++;
}
}
if(!curr && *nl) {
curr=*(nl++);
while(*nl && (*nl)->term().isTerm()) {
nl++;
}
}
if(curr) {
_specVarNumbers.push(inode->childVar);
}
if(*nl) {
_alternatives.push(nl);
_nodeTypes.push(currType);
return true;
}
} else {
ASS_EQ(currType, SKIP_LIST);
auto nl=static_cast<SListIntermediateNode*>(inode)->_nodes.listLike();
if(binding.isTerm()) {
Node** byTop=inode->childByTop(binding.top(), false);
if(byTop) {
curr=*byTop;
}
}
if(!curr && nl->head()->term().isVar()) {
curr=nl->head();
nl=nl->tail();
}
if(nl && nl->head()->term().isTerm()) {
nl=0;
}
if(curr) {
_specVarNumbers.push(inode->childVar);
}
if(nl) {
_alternatives.push(nl);
_nodeTypes.push(currType);
return true;
}
}
return false;
}
}