#include "Lib/Allocator.hpp"
#include "Lib/Recycled.hpp"
#include "Kernel/Matcher.hpp"
#include "Kernel/SubstHelper.hpp"
#include "Kernel/TermIterators.hpp"
namespace Indexing
{
template<class LeafData_>
std::ostream& operator<< (std::ostream& out, typename SubstitutionTree<LeafData_>::InstMatcher::TermSpec ts )
{ return out << ts; }
template<class LeafData_>
class SubstitutionTree<LeafData_>::InstMatcher::Substitution
: public ResultSubstitution
{
public:
USE_ALLOCATOR(SubstitutionTree::InstMatcher::Substitution);
Substitution(InstMatcher* parent, Renaming* resultDenormalizer)
: _parent(parent), _resultDenormalizer(resultDenormalizer)
{}
~Substitution() override
{
}
TermList applyToBoundQuery(TermList t) override
{
return SubstHelper::apply(t, *this);
}
TermList apply(unsigned var)
{
TermList normalized=_parent->derefQueryBinding(var);
ASS_REP(!normalized.isTerm() || normalized.term()->shared(), normalized);
return _resultDenormalizer->apply(normalized);
}
bool isIdentityOnResultWhenQueryBound() final
{ return true; }
void output(std::ostream& out) const final
{ out << "InstMatcher::Substitution(<output unimplemented>)"; }
private:
InstMatcher* _parent;
Renaming* _resultDenormalizer;
};
template<class LeafData_>
ResultSubstitutionSP SubstitutionTree<LeafData_>::InstMatcher::getSubstitution(Renaming* resultDenormalizer)
{
return ResultSubstitutionSP(
new Substitution(this, resultDenormalizer));
}
template<class LeafData_>
TermList SubstitutionTree<LeafData_>::InstMatcher::derefQueryBinding(unsigned var)
{
TermList tvar0(var, false);
TermList tvar=tvar0;
TermSpec varBinding;
{
TermList val;
if(_derefBindings.find(tvar, val)) {
return val;
}
ALWAYS(_bindings.find(tvar, varBinding));
if(varBinding.isFinal()) {
ALWAYS(_derefBindings.insert(tvar, varBinding.t));
return varBinding.t;
}
}
static Stack<DerefTask> toDo;
toDo.reset();
for(;;) {
while(!varBinding.isFinal() && !varBinding.t.isTerm()) {
ASS(varBinding.t.isVar());
ASS(!varBinding.q || !varBinding.t.isOrdinaryVar());
TermList bvar=varBinding.t;
TermList derefBoundTerm;
if(_derefBindings.find(bvar, derefBoundTerm)) {
ALWAYS(_derefBindings.insert(tvar, derefBoundTerm));
}
ALWAYS(_bindings.find(bvar,varBinding));
}
if(varBinding.isFinal()) {
ALWAYS(_derefBindings.insert(tvar, varBinding.t));
goto next_loop;
}
{
ASS(varBinding.t.isTerm());
toDo.push(DerefTask(tvar, varBinding));
VariableIterator vit(varBinding.t);
while(vit.hasNext()) {
TermList btv=vit.next(); if(varBinding.q || btv.isSpecialVar()) {
ASS(_bindings.find(btv));
if(!_derefBindings.find(btv)) {
toDo.push(DerefTask(btv));
}
}
}
}
next_loop:
while(toDo.isNonEmpty() && toDo.top().buildDerefTerm()) {
tvar=toDo.top().var;
TermSpec tspec=toDo.pop().trm;
DerefApplicator applicator(this, tspec.q);
TermList derefTerm=SubstHelper::applySV(tspec.t, applicator);
ASS_REP(!derefTerm.isTerm() || derefTerm.term()->shared(), derefTerm);
ALWAYS(_derefBindings.insert(tvar, derefTerm));
}
if(toDo.isEmpty()) {
break;
}
tvar=toDo.pop().var;
ALWAYS(_bindings.find(tvar, varBinding));
};
return _derefBindings.get(tvar0);
}
template<class LeafData_>
typename SubstitutionTree<LeafData_>::InstMatcher::TermSpec SubstitutionTree<LeafData_>::InstMatcher::deref(TermList var)
{
ASS_REP(var.isVar(), var.tag());
#if VDEBUG
int ctr=0;
#endif
for(;;) {
TermSpec res;
if(!_bindings.find(var, res)) {
return TermSpec(var.isOrdinaryVar() ? true : false, var);
}
if( res.t.isTerm() || (!res.q && res.t.isOrdinaryVar()) ) {
return res;
}
ASS(!res.q || !res.t.isSpecialVar());
var=res.t;
#if VDEBUG
ctr++;
ASS_L(ctr,1000000); #endif
}
}
template<class LeafData_>
void SubstitutionTree<LeafData_>::InstMatcher::backtrack()
{
for(;;) {
TermList boundVar=_boundVars.pop();
if(boundVar.isEmpty()) {
break;
}
_bindings.remove(boundVar);
}
}
template<class LeafData_>
bool SubstitutionTree<LeafData_>::InstMatcher::matchNext(unsigned specVar, TermList nodeTerm, bool separate)
{
if(separate) {
_boundVars.push(TermList::empty());
}
#if VDEBUG
{
VariableIterator vit(nodeTerm);
while(vit.hasNext()) {
TermList var=vit.next();
if(var.isSpecialVar()) {
ASS(!isBound(var));
}
}
}
#endif
return matchNextAux(TermList(specVar, true), nodeTerm, separate);
}
template<class LeafData_>
bool SubstitutionTree<LeafData_>::InstMatcher::matchNextAux(TermList queryTerm, TermList nodeTerm, bool separate)
{
unsigned specVar;
TermSpec tsBinding;
TermSpec tsNode(false, nodeTerm);
if(queryTerm.isSpecialVar()){
specVar = queryTerm.var();
if(!findSpecVarBinding(specVar,tsBinding)) {
bind(TermList(specVar,true), tsNode);
return true;
}
} else {
tsBinding = TermSpec(true, queryTerm);
}
if(tsBinding.q && tsBinding.t.isOrdinaryVar() && !isBound(tsBinding.t)) {
bind(tsBinding.t, tsNode);
return true;
}
bool success;
if(nodeTerm.isTerm() && nodeTerm.term()->shared() && nodeTerm.term()->ground() &&
tsBinding.q && tsBinding.t.isTerm() && tsBinding.t.term()->ground()) {
success=nodeTerm.term()==tsBinding.t.term();
goto finish;
}
static Stack<std::pair<TermSpec,TermSpec> > toDo;
static DisagreementSetIterator dsit;
toDo.reset();
toDo.push(std::make_pair(tsBinding, tsNode));
while(toDo.isNonEmpty()) {
TermSpec ts1=toDo.top().first;
TermSpec ts2=toDo.pop().second;
dsit.reset(ts1.t, ts2.t, ts1.q!=ts2.q);
while(dsit.hasNext()) {
std::pair<TermList,TermList> disarg=dsit.next();
TermList dt1=disarg.first;
TermList dt2=disarg.second;
bool dt1Bindable= !dt1.isTerm() && (ts1.q || !dt1.isOrdinaryVar());
bool dt2Bindable= !dt2.isTerm() && (ts2.q || !dt2.isOrdinaryVar());
if(!dt1Bindable && !dt2Bindable) {
success=false;
goto finish;
}
if(ts1.q && dt1.isOrdinaryVar() && !isBound(dt1)) {
bind(dt1, TermSpec(ts2.q,dt2));
continue;
}
if(ts2.q && dt2.isOrdinaryVar() && !isBound(dt2)) {
bind(dt2, TermSpec(ts1.q,dt1));
continue;
}
if(dt2.isSpecialVar() && !isBound(dt2)) {
ASS(!ts2.q);
bind(dt2, TermSpec(ts1.q,dt1));
continue;
}
if(dt1.isSpecialVar() && !isBound(dt1)) {
ASS(!ts1.q);
bind(dt1, TermSpec(ts2.q,dt2));
continue;
}
TermSpec deref1=TermSpec(ts1.q, dt1);
TermSpec deref2=TermSpec(ts2.q, dt2);
if(dt1Bindable) {
ASS(isBound(dt1)); deref1=deref(dt1);
}
if(dt2Bindable) {
ASS(isBound(dt2));
deref2=deref(dt2);
}
toDo.push(std::make_pair(deref1, deref2));
}
}
success=true;
finish:
if(!success) {
if(separate) {
backtrack();
}
}
return success;
}
template<class LeafData_>
bool SubstitutionTree<LeafData_>::FastInstancesIterator::hasNext()
{
while(!_ldIterator.hasNext() && findNextLeaf()) {}
return _ldIterator.hasNext();
}
#undef LOGGING
#define LOGGING 0
template<class LeafData_>
QueryRes<ResultSubstitutionSP, LeafData_> SubstitutionTree<LeafData_>::FastInstancesIterator::next()
{
while(!_ldIterator.hasNext() && findNextLeaf()) {}
ASS(_ldIterator.hasNext());
auto ld = _ldIterator.next();
if(_retrieveSubstitution) {
_resultDenormalizer.reset();
bool ground = SubstitutionTree::isGround(ld->key());
if(!ground) {
Renaming normalizer;
normalizer.normalizeVariables(ld->key());
_resultDenormalizer.makeInverse(normalizer);
}
return QueryRes(_subst.getSubstitution(&_resultDenormalizer), ld);
} else {
return QueryRes(ResultSubstitutionSP(), ld);
}
}
#undef LOGGING
#define LOGGING 0
template<class LeafData_>
bool SubstitutionTree<LeafData_>::FastInstancesIterator::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);
curr=*(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);
ASS(alts);
curr=alts->head();
if(alts->tail()) {
_alternatives.push(alts->tail());
sibilingsRemain=true;
} else {
sibilingsRemain=false;
}
}
if(sibilingsRemain) {
currSpecVar = _specVarNumbers.top();
} else {
_nodeTypes.pop();
currSpecVar = _specVarNumbers.pop();
}
ASS(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;
_subst.onLeafEntered(); return true;
}
sibilingsRemain=enterNode(curr);
if(curr==0 && _alternatives.isNonEmpty()) {
_subst.backtrack();
}
}
}
template<class LeafData_>
bool SubstitutionTree<LeafData_>::FastInstancesIterator::enterNode(Node*& curr)
{
ASS(!curr->isLeaf());
IntermediateNode* inode=static_cast<IntermediateNode*>(curr);
NodeAlgorithm currType=inode->algorithm();
TermList query;
typename InstMatcher::TermSpec querySpec;
if(_subst.findSpecVarBinding(inode->childVar, querySpec)) {
query=querySpec.t;
}
else {
query.makeVar(0); }
curr=0;
if(currType==UNSORTED_LIST) {
Node** nl=static_cast<UArrIntermediateNode*>(inode)->_nodes;
ASS(*nl); bool noAlternatives=false;
if(query.isTerm()) {
unsigned bindingFunctor=query.term()->functor();
while(*nl && (!(*nl)->term().isTerm() || (*nl)->term().term()->functor()!=bindingFunctor)) {
nl++;
}
if(*nl) {
ASS_EQ((*nl)->term().term()->functor(),bindingFunctor);
curr=*nl;
noAlternatives=true; }
} else {
ASS(query.isVar());
curr=*nl;
nl++;
}
if(curr) {
_specVarNumbers.push(inode->childVar);
}
if(*nl && !noAlternatives) {
_alternatives.push(nl);
_nodeTypes.push(currType);
return true;
}
} else {
ASS_EQ(currType, SKIP_LIST);
auto nl=static_cast<SListIntermediateNode*>(inode)->_nodes.listLike();
ASS(nl); if(query.isTerm()) {
Node** byTop=inode->childByTop(query.top(), false);
if(byTop) {
curr=*byTop;
}
nl=0;
}
else {
ASS(query.isVar());
curr=nl->head();
nl=nl->tail();
}
if(curr) {
_specVarNumbers.push(inode->childVar);
}
if(nl) {
_alternatives.push(nl);
_nodeTypes.push(currType);
return true;
}
}
return false;
}
}