#ifdef DOC_BUILD_INTERNAL
#endif
#include "pathidx.h"
#include "misc.h"
MEMORY pathidx_GetMemory(PATHIDX Index)
{
  return Index->mem;
}
SYMBSTATE pathidx_GetSymbstate(PATHIDX Index)
{
  return Index->symbstate;
}
TERMSTATE pathidx_GetTermstate(PATHIDX Index)
{
  return Index->termstate;
}
SUBSTSTATE pathidx_GetSubststate(PATHIDX Index)
{
  return Index->subststate;
}
FOLSTATE pathidx_GetFolstate(PATHIDX Index)
{
  return Index->folstate;
}
BOOL pathidx_TermEqualModuloSubsts(SYMBSTATE Symbstate, TERM Term1, SUBST Subst1, TERM Term2, SUBST Subst2);
BOOL pathidx_IsInstanceOfRec(PATHIDX Index, TERM Term1, TERM Term2, SUBST Subst2, TYPING Types2, SUBST SubstR);
SUBST pathidx_IsInstanceOf(PATHIDX Index, TERM Term1, TERM Term2, SUBST Subst2, TYPING Types2, unsigned Vars);
unsigned pathidx_ComputeLeaves(TERMSTATE Termstate, TERM Term, SUBST Subst);
PIDXNODE pathidx_CreateNode(MEMORY Mem, SYMBSTATE Symbstate, SYMBOL Symb)
{
  PIDXNODE node;
  int i, arity;
  arity = symbol_GetArity(Symbstate,Symb);
  node = (PIDXNODE)memory_Malloc(Mem,sizeof(PIDXNODE_NODE)+arity*sizeof(OHASH));
  node->symb = Symb;
  node->arity = arity;
  node->indexed = NULL;
  for(i=0; i < arity; i++){
    node->children[i] = ohash_Create(Mem,4U,ohash_IntegerNew,symbol_Equal);
  }
  return node;
}
void pathidx_DeleteNodesRecOH(MEMORY,OHASH_DATA_TYPE);
void pathidx_DeleteNode(MEMORY Mem, PIDXNODE Node)
{
  unsigned i;
  if(Node->indexed){
    array_Delete(Mem,Node->indexed);
  }
  for(i=0; i < Node->arity; i++){
    ohash_Delete(Node->children[i],(OHASH_DELETE_KEY_FCT)NULL,(OHASH_DELETE_DATA_FCT)pathidx_DeleteNodesRecOH);
  }
  memory_Free(Mem,Node,sizeof(PIDXNODE_NODE)+(Node->arity)*sizeof(OHASH));
}
void pathidx_DeleteEmptyNode(MEMORY Mem, PIDXNODE Node)
{
  unsigned i;
  if(Node->indexed){
    array_Delete(Mem,Node->indexed);
  }
  for(i=0; i < Node->arity; i++){
    ohash_Delete(Node->children[i],(OHASH_DELETE_KEY_FCT)NULL,(OHASH_DELETE_DATA_FCT)NULL);
  }
  memory_Free(Mem,Node,sizeof(PIDXNODE_NODE)+(Node->arity)*sizeof(OHASH));
}
void pathidx_DeleteNodesRecOH(MEMORY Mem, OHASH_DATA_TYPE Node)
{
  pathidx_DeleteNode(Mem,(PIDXNODE)Node);
}
PIDXNODE pathidx_CreateRec(TERMSTATE Termstate, TERM Term, TERM Subterm, unsigned Pos)
{
  unsigned i;
  PIDXNODE child, node;
  SYMBOL top;
  TERM subterm;
  if(term_IsVariable(Termstate,Subterm)){
    top = 0;
  }else{
    top = term_TopSymbol(Subterm);
  }
  node = pathidx_CreateNode(term_GetMemory(Termstate),term_GetSymbstate(Termstate),top);
  if(node->arity == 0){
    if(node->indexed == NULL){
      node->indexed = array_Create(term_GetMemory(Termstate),2);
    }
    node->indexed = array_Add(term_GetMemory(Termstate),node->indexed,(intptr_t)Pos);
  }
  for(i = 0; i < node->arity; i++){
    subterm = term_GetArgument(Subterm,i);
    if(term_IsVariable(Termstate,subterm)){
      top = 0;
    }else{
      top = term_TopSymbol(subterm);
    }
    child = pathidx_CreateRec(Termstate,Term,subterm,Pos);
    node->children[i] = ohash_Insert(node->children[i],(OHASH_KEY_TYPE)top,(OHASH_DATA_TYPE)child,(OHASH_DELETE_KEY_FCT)NULL,(OHASH_DELETE_DATA_FCT)NULL);
  }
  return node;
}
void pathidx_InsertRec(TERMSTATE Termstate, PIDXNODE Node, TERM Term, TERM Subterm, unsigned Pos)
{
  unsigned i;
  PIDXNODE child;
  SYMBOL top;
  TERM subterm;
  if(Node->arity == 0){
    if(Node->indexed == NULL){
      Node->indexed = array_Create(term_GetMemory(Termstate),2);
    }
    Node->indexed = array_Add(term_GetMemory(Termstate),Node->indexed,(intptr_t)Pos);
  }
  for(i = 0; i < Node->arity; i++){
    subterm = term_GetArgument(Subterm,i);
    if(term_IsVariable(Termstate,subterm)){
      top = 0;
    }else{
      top = term_TopSymbol(subterm);
    }
    child = (PIDXNODE)ohash_Search(Node->children[i],(OHASH_KEY_TYPE)top);
    if(child){
      pathidx_InsertRec(Termstate,child,Term,subterm,Pos);
    }else{
      child = pathidx_CreateRec(Termstate,Term,subterm,Pos);
      Node->children[i] = ohash_Insert(Node->children[i],(OHASH_KEY_TYPE)top,(OHASH_DATA_TYPE)child,(OHASH_DELETE_KEY_FCT)NULL,(OHASH_DELETE_DATA_FCT)NULL);
    }
  }
}
BOOL pathidx_RemoveRec(TERMSTATE Termstate, PIDXNODE Node, TERM Subterm, unsigned Pos)
{
  unsigned i, emptied;
  PIDXNODE child;
  TERM subterm;
  SYMBOL top;
  if(Node->arity == 0){
#ifdef SPASS_CHECK
    if(Node->indexed == NULL){
      misc_StartUserErrorReport();
      misc_UserErrorReport("%s: the index was not constructed correctly or pos should be indexed at this node.",__func__);
      misc_FinishUserErrorReport();
    }
    i = array_GetSize(Node->indexed);
#endif
    array_PointerRemoveElement(Node->indexed,Pos);
#ifdef SPASS_CHECK
    if(i <= array_GetSize(Node->indexed)){
      misc_StartUserErrorReport();
      misc_UserErrorReport("%s: the index was not constructed correctly or pos should have been indexed at this node.",__func__);
      misc_FinishUserErrorReport();
    }
#endif
    if(array_GetSize(Node->indexed) == 0){
      return TRUE;
    }else{
      return FALSE;
    }
  }
  emptied = 0;
  for(i = 0; i < Node->arity; i++){
    subterm = term_GetArgument(Subterm,i);
    if(term_IsVariable(Termstate,subterm)){
      top = 0;
    }else{
      top = term_TopSymbol(subterm);
    }
    child = (PIDXNODE)ohash_Search(Node->children[i],(OHASH_KEY_TYPE)top);
    if(child){
      if(pathidx_RemoveRec(Termstate,child,subterm,Pos)){
 Node->children[i] = ohash_Remove(Node->children[i],(OHASH_KEY_TYPE)top,(OHASH_DELETE_KEY_FCT)NULL,(OHASH_DELETE_DATA_FCT)NULL);
 pathidx_DeleteEmptyNode(term_GetMemory(Termstate),child);
      }
      if(ohash_GetNumberElems(Node->children[i]) == 0){
 emptied++;
      }
    }else{
      misc_StartUserErrorReport();
      misc_UserErrorReport("%s: Either position is invalid or the index or this function were not constructed correctly.",__func__);
      misc_FinishUserErrorReport();
    }
  }
  return emptied == Node->arity;
}
unsigned pathidx_InsertAtFreePosition(PATHIDX Index, TERM Term, TYPING Types, intptr_t Data)
{
  unsigned pos;
  MEMORY mem;
  mem = pathidx_GetMemory(Index);
  if(array_GetSize(Index->empty_pos) > 0){
    pos = array_Pop(Index->empty_pos);
  }else{
    if(Index->maxpos >= Index->capacity){
      Index->terms = (TERM*)memory_Realloc(mem, Index->terms,
         (Index->capacity) * sizeof(TERM),
         (Index->capacity) * 2 * sizeof(TERM));
      Index->types = (TYPING*)memory_Realloc(mem, Index->types,
           (Index->capacity) * sizeof(TYPING),
           (Index->capacity) * 2 * sizeof(TYPING));
      Index->data = memory_Realloc(mem, Index->data,
         (Index->capacity) * sizeof(intptr_t),
         (Index->capacity) * 2 * sizeof(intptr_t));
      Index->marked = memory_Realloc(mem, Index->marked,
         (Index->capacity) * sizeof(unsigned),
         (Index->capacity) * 2 * sizeof(unsigned));
      Index->capacity = Index->capacity * 2;
    }
    pos = Index->maxpos;
    Index->maxpos++;
  }
  Index->terms[pos] = Term;
  Index->types[pos] = Types;
  Index->data[pos] = (intptr_t)Data;
  Index->marked[pos] = 0U;
  Index->size++;
  return pos;
}
void pathidx_FreeUpPosition(PATHIDX Index, unsigned Pos)
{
  Index->empty_pos = array_Add(pathidx_GetMemory(Index),Index->empty_pos,(intptr_t)Pos);
  Index->size--;
}
BOOL pathidx_FindExactMatchRec(PATHIDX Index, PIDXNODE Node, TERM Subterm, SUBST Subst, ARRAY* Matches, unsigned* Leaves)
{
  unsigned i, size, pos;
  PIDXNODE child;
  BOOL in_subst;
  TERM subterm;
  SYMBOL top;
  if(Node->arity == 0){
    *Leaves = *Leaves + 1;
    size = array_GetSize(Node->indexed);
    for(i = 0; i < size; i++){
      pos = (unsigned)array_GetElement(Node->indexed,i);
      if(Index->marked[pos] == 0){
 *Matches = array_Add(pathidx_GetMemory(Index),*Matches,(intptr_t)pos);
      }
      Index->marked[pos] = Index->marked[pos] + 1;
    }
    return TRUE;
  }
  for(i = 0; i < Node->arity; i++){
    subterm = term_GetArgument(Subterm,i);
    if(Subst != NULL && term_IsVariable(pathidx_GetTermstate(Index),subterm) &&
       subst_VarDefined(Subst,term_TopSymbol(subterm))){
      in_subst = TRUE;
      subterm = subst_GetValue(Subst,term_TopSymbol(subterm));
    }else{
      in_subst = FALSE;
    }
    if(term_IsVariable(pathidx_GetTermstate(Index),subterm)){
      top = 0;
    }else{
      top = term_TopSymbol(subterm);
    }
    child = (PIDXNODE)ohash_Search(Node->children[i],(OHASH_KEY_TYPE)top);
    if(!child || !pathidx_FindExactMatchRec(Index,child,subterm,in_subst ? NULL : Subst,Matches,Leaves)){
      return FALSE;
    }
  }
  return TRUE;
}
unsigned pathidx_FindExactMatchPos(PATHIDX Index, TERM Term, SUBST Subst, TYPING Types)
{
  TERM subterm;
  BOOL in_subst;
  SYMBOL top;
  ARRAY matches;
  unsigned leaves, pos, i, size;
  PIDXNODE node;
  matches = Index->tempar2;
  array_Clean(Index->tempar2);
  leaves = 0;
  if(term_IsVariable(pathidx_GetTermstate(Index),Term) &&
     Subst != NULL && subst_VarDefined(Subst,term_TopSymbol(Term))){
    in_subst = TRUE;
    subterm = subst_GetValue(Subst,term_TopSymbol(Term));
  }else{
    in_subst = FALSE;
    subterm = Term;
  }
  if(term_IsVariable(pathidx_GetTermstate(Index),subterm)){
    top = 0;
  }else{
    top = term_TopSymbol(subterm);
  }
  node = (PIDXNODE)ohash_Search(Index->root,(OHASH_KEY_TYPE)top);
  if(!node || !pathidx_FindExactMatchRec(Index,node,subterm,in_subst ? NULL : Subst,&matches,&leaves)){
    pos = UINT_MAX;
    size = array_GetSize(matches);
    for(i = 0; i < size; i++){
      Index->marked[array_GetElement(matches,i)] = 0U;
    }
  }else{
    pos = UINT_MAX;
    size = array_GetSize(matches);
    for(i = 0; i < size; i++){
      pos = array_GetElement(matches,i);
      if(Index->marked[pos] == leaves && subst_TermEqualModuloSubstsAndTypes(pathidx_GetSymbstate(Index),Term,Subst,Types,Index->terms[pos],(SUBST)NULL,Index->types[pos])){
 break;
      }
      Index->marked[pos] = 0U;
    }
    if(i == size){
      pos = UINT_MAX;
    }
    for(; i < size; i++){
      Index->marked[array_GetElement(matches,i)] = 0U;
    }
  }
  Index->tempar2 = matches;
  array_Clean(Index->tempar2);
  return pos;
}
void pathidx_CollectAllUnderlyingInstances(PATHIDX Index, OHASH Children, ARRAY* Instances, unsigned* Leaves)
{
  uint32_t i, cap, j, size;
  unsigned pos;
  PIDXNODE child;
  cap = ohash_GetCapacity(Children);
  for(i = 0; i < cap; i++){
    if(ohash_GetOccupancyAtIndex(Children,i) == ohash_ENTRY_OCCUPIED){
      child = (PIDXNODE)ohash_GetDataAtIndex(Children,i);
      if(child->arity == 0){
 size = array_GetSize(child->indexed);
 for(j = 0; j < size; j++){
   pos = (unsigned)array_GetElement(child->indexed,j);
   if(Index->marked[pos] == 0){
     *Instances = array_Add(pathidx_GetMemory(Index),*Instances,(intptr_t)pos);
   }
   if(Index->marked[pos] + 1 == *Leaves){
     Index->marked[pos] = Index->marked[pos] + 1;
   }
 }
      }
      for(j = 0; j < child->arity; j++){
 pathidx_CollectAllUnderlyingInstances(Index,child->children[j],Instances,Leaves);
      }
    }
  }
}
BOOL pathidx_FindInstancesRec(PATHIDX Index, PIDXNODE Node, TERM Subterm, SUBST Subst, ARRAY* Instances, unsigned* Leaves)
{
  unsigned i, size, pos;
  PIDXNODE child;
  BOOL in_subst;
  TERM subterm;
  if(Node->arity == 0){
    *Leaves = *Leaves + 1;
    size = array_GetSize(Node->indexed);
    for(i = 0; i < size; i++){
      pos = (unsigned)array_GetElement(Node->indexed,i);
      if(Index->marked[pos] == 0){
 *Instances = array_Add(pathidx_GetMemory(Index),*Instances,(intptr_t)pos);
      }
      Index->marked[pos] = Index->marked[pos] + 1;
    }
    return TRUE;
  }
  for(i = 0; i < Node->arity; i++){
    subterm = term_GetArgument(Subterm,i);
    if(Subst != NULL && term_IsVariable(pathidx_GetTermstate(Index),subterm) &&
       subst_VarDefined(Subst,term_TopSymbol(subterm))){
      in_subst = TRUE;
      subterm = subst_GetValue(Subst,term_TopSymbol(subterm));
    }else{
      in_subst = FALSE;
    }
    if(term_IsVariable(pathidx_GetTermstate(Index),subterm)){
      *Leaves = *Leaves + 1;
      pathidx_CollectAllUnderlyingInstances(Index,Node->children[i],Instances,Leaves);
    }else{
      child = (PIDXNODE)ohash_Search(Node->children[i],(OHASH_KEY_TYPE)term_TopSymbol(subterm));
      if(!child || !pathidx_FindInstancesRec(Index,child,subterm,in_subst ? NULL : Subst,Instances,Leaves)){
 return FALSE;
      }
    }
  }
  return TRUE;
}
BOOL pathidx_CollectInstancesFromVariableNode(PATHIDX Index, PIDXNODE Node, TERM Subterm, SUBST Subst, ARRAY* Instances, unsigned* Leaves)
{
  unsigned i, size, subleaves, pos;
  subleaves = pathidx_ComputeLeaves(pathidx_GetTermstate(Index),Subterm,Subst);
  size = array_GetSize(Node->indexed);
  for(i = 0; i < size; i++){
    pos = (unsigned)array_GetElement(Node->indexed,i);
    if(Index->marked[pos] == 0){
      *Instances = array_Add(pathidx_GetMemory(Index),*Instances,(intptr_t)pos);
    }
    Index->marked[pos] = Index->marked[pos] + subleaves;
  }
  return TRUE;
}
BOOL pathidx_FindUnifiablesRec(PATHIDX Index, PIDXNODE Node, TERM Subterm, SUBST Subst, ARRAY* Instances, unsigned* Leaves)
{
  unsigned i, size, pos;
  PIDXNODE child;
  BOOL in_subst, res;
  TERM subterm;
  if(Node->arity == 0){
    *Leaves = *Leaves + 1;
    size = array_GetSize(Node->indexed);
    for(i = 0; i < size; i++){
      pos = (unsigned)array_GetElement(Node->indexed,i);
      if(Index->marked[pos] == 0){
 *Instances = array_Add(pathidx_GetMemory(Index),*Instances,(intptr_t)pos);
      }
      Index->marked[pos] = Index->marked[pos] + 1;
    }
    return TRUE;
  }
  for(i = 0; i < Node->arity; i++){
    subterm = term_GetArgument(Subterm,i);
    if(Subst != NULL && term_IsVariable(pathidx_GetTermstate(Index),subterm) &&
       subst_VarDefined(Subst,term_TopSymbol(subterm))){
      in_subst = TRUE;
      subterm = subst_GetValue(Subst,term_TopSymbol(subterm));
    }else{
      in_subst = FALSE;
    }
    if(term_IsVariable(pathidx_GetTermstate(Index),subterm)){
      *Leaves = *Leaves + 1;
      pathidx_CollectAllUnderlyingInstances(Index,Node->children[i],Instances,Leaves);
    }else{
      child = (PIDXNODE)ohash_Search(Node->children[i],(OHASH_KEY_TYPE)term_TopSymbol(subterm));
      res = FALSE;
      if(child == NULL){
 *Leaves = *Leaves + pathidx_ComputeLeaves(pathidx_GetTermstate(Index),subterm,in_subst ? NULL : Subst);
      }else if(pathidx_FindUnifiablesRec(Index,child,subterm,in_subst ? NULL : Subst,Instances,Leaves)){
 res = TRUE;
      }
      child = (PIDXNODE)ohash_Search(Node->children[i],(OHASH_KEY_TYPE)0);
      if(child){
 pathidx_CollectInstancesFromVariableNode(Index,child,subterm,in_subst ? NULL : Subst,Instances,Leaves);
      }else if(!res){
 return FALSE;
      }
    }
  }
  return TRUE;
}
PATHIDX pathidx_Create(TERMSTATE Termstate, SUBSTSTATE Subststate, FOLSTATE Folstate, unsigned Capacity)
{
  MEMORY mem;
  SYMBSTATE symbstate;
  PATHIDX index;
  mem = term_GetMemory(Termstate);
  symbstate = term_GetSymbstate(Termstate);
  index = (PATHIDX)memory_Malloc(mem,sizeof(PATHIDX_NODE));
  index->mem = mem;
  index->symbstate = symbstate;
  index->termstate = Termstate;
  index->subststate = Subststate;
  index->folstate = Folstate;
  index->capacity = Capacity > 4 ? Capacity : 4;
  index->maxpos = 0;
  index->size = 0;
  index->empty_pos = array_Create(mem,4);
  index->tempar1 = array_Create(mem,4);
  index->tempar2 = array_Create(mem,4);
  index->terms = (TERM*)memory_Malloc(mem, sizeof(TERM)*(index->capacity));
  index->types = (TYPING*)memory_Malloc(mem, sizeof(TYPING)*(index->capacity));
  index->marked = memory_Malloc(mem, sizeof(unsigned)*(index->capacity));
  index->data = memory_Malloc(mem, sizeof(intptr_t)*(index->capacity));
  index->iter_pos = UINT_MAX;
  index->root = ohash_Create(mem,4U,ohash_IntegerNew,symbol_Equal);
  return index;
}
void pathidx_Delete(PATHIDX Index)
{
  MEMORY mem;
  mem = pathidx_GetMemory(Index);
  array_Delete(mem, Index->empty_pos);
  array_Delete(mem, Index->tempar1);
  array_Delete(mem, Index->tempar2);
  memory_Free(mem, Index->terms, sizeof(TERM)*(Index->capacity));
  memory_Free(mem, Index->types, sizeof(TYPING)*(Index->capacity));
  memory_Free(mem, Index->marked, sizeof(unsigned)*(Index->capacity));
  memory_Free(mem, Index->data, sizeof(intptr_t)*(Index->capacity));
  ohash_Delete(Index->root,(OHASH_DELETE_KEY_FCT)NULL,(OHASH_DELETE_DATA_FCT)pathidx_DeleteNodesRecOH);
  memory_Free(mem,Index,sizeof(PATHIDX_NODE));
}
unsigned pathidx_ForceInsert(PATHIDX Index, TERM Term, TYPING Types, intptr_t Data)
{
  unsigned pos;
  TERM subterm;
  PIDXNODE node;
  SYMBOL top;
  pos = pathidx_InsertAtFreePosition(Index,Term,Types,Data);
  subterm = Term;
  if(term_IsVariable(pathidx_GetTermstate(Index),subterm)){
    top = 0;
  }else{
    top = term_TopSymbol(subterm);
  }
  node = (PIDXNODE)ohash_Search(Index->root,(OHASH_KEY_TYPE)top);
  if(node){
    pathidx_InsertRec(pathidx_GetTermstate(Index),node,Term,subterm,pos);
  }else{
    node = pathidx_CreateRec(pathidx_GetTermstate(Index),Term,subterm,pos);
    Index->root = ohash_Insert(Index->root,(OHASH_KEY_TYPE)top,(OHASH_DATA_TYPE)node,(OHASH_DELETE_KEY_FCT)NULL,(OHASH_DELETE_DATA_FCT)NULL);
  }
  return pos;
}
BOOL pathidx_Insert(PATHIDX Index, TERM Term, TYPING Types, intptr_t Data)
{
  unsigned pos;
  pos = pathidx_FindExactMatchPos(Index,Term,(SUBST)NULL,Types);
  if(pos != UINT_MAX){
    return FALSE;
  }
  pathidx_ForceInsert(Index,Term,Types,Data);
  return TRUE;
}
BOOL pathidx_Remove(PATHIDX Index, TERM Term, TYPING Types)
{
  unsigned pos;
  pos = pathidx_FindExactMatchPos(Index,Term,(SUBST)NULL,Types);
  if(pos == UINT_MAX){
    return FALSE;
  }
  return pathidx_RemoveByPosition(Index,pos);
}
BOOL pathidx_RemoveByPosition(PATHIDX Index, unsigned Pos)
{
  TERM subterm;
  PIDXNODE node;
  SYMBOL top;
  subterm = Index->terms[Pos];
  if(term_IsVariable(pathidx_GetTermstate(Index),subterm)){
    top = 0;
  }else{
    top = term_TopSymbol(subterm);
  }
  node = (PIDXNODE)ohash_Search(Index->root,(OHASH_KEY_TYPE)top);
  if(node){
    if(pathidx_RemoveRec(pathidx_GetTermstate(Index),node,subterm,Pos)){
      Index->root = ohash_Remove(Index->root,(OHASH_KEY_TYPE)top,(OHASH_DELETE_KEY_FCT)NULL,(OHASH_DELETE_DATA_FCT)NULL);
      pathidx_DeleteEmptyNode(pathidx_GetMemory(Index),node);
    }
  }else{
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: Either position is invalid or the index or this function were not constructed correctly.",__func__);
    misc_FinishUserErrorReport();
  }
  return TRUE;
}
unsigned pathidx_FindCandidateInstances(PATHIDX Index, TERM Term, SUBST Subst, TYPING Types)
{
  TERM subterm;
  BOOL in_subst;
  ARRAY instances;
  unsigned leaves,pos,i,size;
  PIDXNODE node;
  instances = Index->tempar1;
  array_Clean(Index->tempar1);
  leaves = 0;
  if(term_IsVariable(pathidx_GetTermstate(Index),Term) &&
     Subst != NULL && subst_VarDefined(Subst,term_TopSymbol(Term))){
    in_subst = TRUE;
    subterm = subst_GetValue(Subst,term_TopSymbol(Term));
  }else{
    in_subst = FALSE;
    subterm = Term;
  }
  if(term_IsVariable(pathidx_GetTermstate(Index),subterm)){
    leaves = 1;
    pathidx_CollectAllUnderlyingInstances(Index,Index->root,&instances,&leaves);
    size = array_GetSize(instances);
    for(i = 0; i < size; i++){
      pos = array_GetElement(instances,i);
      Index->marked[pos] = 0U;
    }
  }else{
    node = (PIDXNODE)ohash_Search(Index->root,(OHASH_KEY_TYPE)term_TopSymbol(subterm));
    if(!node || !pathidx_FindInstancesRec(Index,node,subterm,in_subst ? NULL : Subst,&instances,&leaves)){
      pos = UINT_MAX;
      size = array_GetSize(instances);
      for(i = 0; i < size; i++){
 pos = array_GetElement(instances,i);
 Index->marked[pos] = 0U;
      }
      Index->tempar1 = instances;
      array_Clean(Index->tempar1);
    }else{
      for(i = 0; i < array_GetSize(instances);){
 pos = array_GetElement(instances,i);
 if(Index->marked[pos] != leaves){
   instances = array_RemoveIndexSwap(instances,i);
 }else{
   i++;
 }
 Index->marked[pos] = 0U;
      }
    }
  }
  Index->tempar1 = instances;
  return leaves;
}
ARRAY pathidx_FindInstances(PATHIDX Index, TERM Term, SUBST Subst, TYPING Types, unsigned Vars)
{
  unsigned pos, cap, i, size;
  SUBST grnd;
  ARRAY instances, results;
#ifdef SPASS_CHECK
  if(pathidx_IteratorIsRunning(Index)){
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: function does not work if there is a running iterator.",__func__);
    misc_FinishUserErrorReport();
  }
#endif
  pathidx_FindCandidateInstances(Index,Term,Subst,Types);
  instances = Index->tempar1;
  results = NULL;
  size = array_GetSize(instances);
  for(i = 0; i < size; i++){
    pos = array_GetElement(instances,i);
    subst_ContextStart(pathidx_GetSubststate(Index), pathidx_GetSymbstate(Index));
    if(subst_FolTermMatchTermsSubsts(pathidx_GetSubststate(Index), pathidx_GetSymbstate(Index), pathidx_GetTermstate(Index), pathidx_GetFolstate(Index), Term, Types, Subst, Index->terms[pos], Index->types[pos], (SUBST)NULL)){
      if(results == NULL){
 cap = size/(i+1);
 results = array_Create(pathidx_GetMemory(Index),cap < 2 ? 2 : cap);
      }
      grnd = subst_ContextExtractSubst(pathidx_GetSubststate(Index), pathidx_GetTermstate(Index), pathidx_GetSymbstate(Index),(SYMBOL)Vars);
      results = array_Add(pathidx_GetMemory(Index),results,(intptr_t)grnd);
      results = array_Add(pathidx_GetMemory(Index),results,(intptr_t)Index->data[pos]);
    }
    subst_ContextStop(pathidx_GetSubststate(Index));
  }
  Index->tempar1 = instances;
  array_Clean(Index->tempar1);
  return results;
}
ARRAY pathidx_FindInstancesPure(PATHIDX Index, TERM Term, SUBST Subst, TYPING Types, ARRAY *Result)
{
  unsigned pos, i, size;
  ARRAY instances;
#ifdef SPASS_CHECK
  if(pathidx_IteratorIsRunning(Index)){
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: function does not work if there is a running iterator.",__func__);
    misc_FinishUserErrorReport();
  }
#endif
  pathidx_FindCandidateInstances(Index,Term,Subst,Types);
  instances = Index->tempar1;
  size = array_GetSize(instances);
  for(i = 0; i < size; i++){
    pos = array_GetElement(instances,i);
    subst_ContextStart(pathidx_GetSubststate(Index), pathidx_GetSymbstate(Index));
    if(subst_FolTermMatchTermsSubsts(pathidx_GetSubststate(Index), pathidx_GetSymbstate(Index), pathidx_GetTermstate(Index), pathidx_GetFolstate(Index), Term, Types, Subst, Index->terms[pos], Index->types[pos], (SUBST)NULL)){
      *Result = array_Add(pathidx_GetMemory(Index),*Result,(intptr_t)Index->data[pos]);
    }
    subst_ContextStop(pathidx_GetSubststate(Index));
  }
  Index->tempar1 = instances;
  array_Clean(Index->tempar1);
  return *Result;
}
BOOL pathidx_IteratorIsRunning(PATHIDX Index)
{
  return array_GetSize(Index->tempar1) > 0;
}
BOOL pathidx_StartInstancesIterator(PATHIDX Index, TERM Term, SUBST Subst, TYPING Types)
{
#ifdef SPASS_CHECK
  if(pathidx_IteratorIsRunning(Index)){
      misc_StartUserErrorReport();
      misc_UserErrorReport("%s: there is already a running iterator.",__func__);
      misc_FinishUserErrorReport();
  }
#endif
  Index->leaves = pathidx_FindCandidateInstances(Index,Term,Subst,Types);
  return pathidx_IteratorIsRunning(Index);
}
BOOL pathidx_NextInstanceFromIterator(PATHIDX Index, TERM Term, SUBST Subst, TYPING Types)
{
  unsigned pos, i, size;
  ARRAY instances;
  instances = Index->tempar1;
  i = Index->iter_pos;
  if(i == UINT_MAX){
    i = 0;
  }else{
    i++;
  }
  size = array_GetSize(instances);
  for(; i < size; i++){
    pos = array_GetElement(instances,i);
    subst_ContextStart(pathidx_GetSubststate(Index), pathidx_GetSymbstate(Index));
    if(subst_FolTermMatchTermsSubsts(pathidx_GetSubststate(Index), pathidx_GetSymbstate(Index), pathidx_GetTermstate(Index), pathidx_GetFolstate(Index), Term, Types, Subst, Index->terms[pos], (TYPING)NULL, (SUBST)NULL)){
      Index->iter_pos = i;
      Index->marked[pos] = 0U;
      return TRUE;
    }
    subst_ContextStop(pathidx_GetSubststate(Index));
    Index->marked[pos] = 0U;
  }
  return FALSE;
}
intptr_t pathidx_DataFromCurrentIteratorInstance(PATHIDX Index)
{
#ifdef SPASS_CHECK
  if(!pathidx_IteratorIsRunning(Index)){
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: there is no running iterator.",__func__);
    misc_FinishUserErrorReport();
  }
  if(Index->iter_pos == UINT_MAX){
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: at least one call of pathidx_NextInstanceFromIterator is needed.",__func__);
    misc_FinishUserErrorReport();
  }
#endif
  return Index->data[array_GetElement(Index->tempar1,Index->iter_pos)];
}
void pathidx_StopInstancesIterator(PATHIDX Index)
{
  unsigned pos, i, size;
  ARRAY instances;
  instances = Index->tempar1;
  i = Index->iter_pos;
  if(i == UINT_MAX){
    i = 0;
  }else{
    i++;
  }
  size = array_GetSize(instances);
  for(; i < size; i++){
    pos = array_GetElement(instances,i);
    Index->marked[pos] = 0U;
  }
  Index->iter_pos = UINT_MAX;
  array_Clean(Index->tempar1);
}
BOOL pathidx_FindExactMatch(PATHIDX Index, TERM Term, SUBST Subst, TYPING Types, TERM* ResTerm,intptr_t* ResData)
{
  unsigned pos;
  pos = pathidx_FindExactMatchPos(Index,Term,Subst,Types);
  if(pos != UINT_MAX){
    *ResTerm = Index->terms[pos];
    *ResData = Index->data[pos];
    return TRUE;
  }
  return FALSE;
}
unsigned pathidx_FindCandidateUnifiables(PATHIDX Index, TERM Term, TYPING Types, unsigned Vars)
{
  TERM subterm;
  BOOL res;
  ARRAY instances;
  unsigned leaves,pos,i,size;
  PIDXNODE node;
  instances = Index->tempar1;
  array_Clean(Index->tempar1);
  leaves = 0;
  subterm = Term;
  if(term_IsVariable(pathidx_GetTermstate(Index),subterm)){
    leaves = 1;
    pathidx_CollectAllUnderlyingInstances(Index,Index->root,&instances,&leaves);
    size = array_GetSize(instances);
    for(i = 0; i < size; i++){
      pos = array_GetElement(instances,i);
      Index->marked[pos] = 0U;
    }
  }else{
    node = (PIDXNODE)ohash_Search(Index->root,(OHASH_KEY_TYPE)term_TopSymbol(subterm));
    res = FALSE;
    if(!node){
      leaves = pathidx_ComputeLeaves(pathidx_GetTermstate(Index),subterm,NULL);
    }else if(pathidx_FindUnifiablesRec(Index,node,subterm,NULL,&instances,&leaves)){
      res = TRUE;
    }
    node = (PIDXNODE)ohash_Search(Index->root,(OHASH_KEY_TYPE)0);
    if(node){
      pathidx_CollectInstancesFromVariableNode(Index,node,subterm,NULL,&instances,&leaves);
      if(!res){
 leaves = pathidx_ComputeLeaves(pathidx_GetTermstate(Index),subterm,NULL);
      }
      res = TRUE;
    }
    if(!res){
      pos = UINT_MAX;
      size = array_GetSize(instances);
      for(i = 0; i < size; i++){
 pos = array_GetElement(instances,i);
 Index->marked[pos] = 0U;
      }
      Index->tempar1 = instances;
      array_Clean(Index->tempar1);
    }else{
      for(i = 0; i < array_GetSize(instances);){
 pos = array_GetElement(instances,i);
 if(Index->marked[pos] != leaves){
   instances = array_RemoveIndexSwap(instances,i);
 }else{
   i++;
 }
 Index->marked[pos] = 0U;
      }
    }
  }
  Index->tempar1 = instances;
  return leaves;
}
ARRAY pathidx_FindUnifiables(PATHIDX Index, TERM Term, TYPING Types, unsigned Vars)
{
  unsigned pos, cap, i, size;
  ARRAY instances, results;
#ifdef SPASS_CHECK
  if(pathidx_IteratorIsRunning(Index)){
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: function does not work if there is a running iterator.",__func__);
    misc_FinishUserErrorReport();
  }
#endif
  pathidx_FindCandidateUnifiables(Index,Term,Types,Vars);
  instances = Index->tempar1;
  results = NULL;
  size = array_GetSize(instances);
  for(i = 0; i < size; i++){
    pos = array_GetElement(instances,i);
    subst_ContextStart(pathidx_GetSubststate(Index), pathidx_GetSymbstate(Index));
    if(subst_FolUTermUnifyTypes(pathidx_GetSubststate(Index), pathidx_GetFolstate(Index), pathidx_GetSymbstate(Index), Term, Types, Index->terms[pos], Index->types[pos], TRUE)){
      if(results == NULL){
 cap = size/(i+1);
 results = array_Create(pathidx_GetMemory(Index),cap < 2 ? 2 : cap);
      }
      results = array_Add(pathidx_GetMemory(Index),results,(intptr_t)Index->terms[pos]);
      results = array_Add(pathidx_GetMemory(Index),results,(intptr_t)Index->data[pos]);
    }
    subst_ContextStop(pathidx_GetSubststate(Index));
  }
  Index->tempar1 = instances;
  array_Clean(Index->tempar1);
  return results;
}
BOOL pathidx_StartUnifiablesIterator(PATHIDX Index, TERM Term, TYPING Types, unsigned Vars)
{
#ifdef SPASS_CHECK
  if(pathidx_IteratorIsRunning(Index)){
      misc_StartUserErrorReport();
      misc_UserErrorReport("%s: there is already a running iterator.",__func__);
      misc_FinishUserErrorReport();
  }
#endif
  Index->leaves = pathidx_FindCandidateUnifiables(Index,Term,Types,Vars);
  return pathidx_IteratorIsRunning(Index);
}
BOOL pathidx_NextUnifiableFromIterator(PATHIDX Index, TERM Term, TYPING Types, unsigned Vars)
{
  unsigned pos, i, size;
  ARRAY instances;
  instances = Index->tempar1;
  i = Index->iter_pos;
  if(i == UINT_MAX){
    i = 0;
  }else{
    i++;
  }
  size = array_GetSize(instances);
  for(; i < size; i++){
    pos = array_GetElement(instances,i);
    subst_ContextStart(pathidx_GetSubststate(Index), pathidx_GetSymbstate(Index));
    if(subst_FolUTermUnifyTypes(pathidx_GetSubststate(Index), pathidx_GetFolstate(Index), pathidx_GetSymbstate(Index), Term, Types, Index->terms[pos], Index->types[pos], TRUE)){
      Index->iter_pos = i;
      Index->marked[pos] = 0U;
      return TRUE;
    }
    Index->marked[pos] = 0U;
    subst_ContextStop(pathidx_GetSubststate(Index));
  }
  return FALSE;
}
TERM pathidx_TermFromCurrentIteratorUnifiable(PATHIDX Index)
{
#ifdef SPASS_CHECK
  if(!pathidx_IteratorIsRunning(Index)){
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: there is no running iterator.",__func__);
    misc_FinishUserErrorReport();
  }
  if(Index->iter_pos == UINT_MAX){
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: at least one call of pathidx_NextUnifiableFromIterator is needed.",__func__);
    misc_FinishUserErrorReport();
  }
#endif
  return Index->terms[array_GetElement(Index->tempar1,Index->iter_pos)];
}
intptr_t pathidx_DataFromCurrentIteratorUnifiable(PATHIDX Index)
{
#ifdef SPASS_CHECK
  if(!pathidx_IteratorIsRunning(Index)){
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: there is no running iterator.",__func__);
    misc_FinishUserErrorReport();
  }
  if(Index->iter_pos == UINT_MAX){
    misc_StartUserErrorReport();
    misc_UserErrorReport("%s: at least one call of pathidx_NextUnifiableFromIterator is needed.",__func__);
    misc_FinishUserErrorReport();
  }
#endif
  return Index->data[array_GetElement(Index->tempar1,Index->iter_pos)];
}
void pathidx_StopUnifiablesIterator(PATHIDX Index)
{
  unsigned pos, i, size;
  ARRAY instances;
  instances = Index->tempar1;
  i = Index->iter_pos;
  if(i == UINT_MAX){
    i = 0;
  }else{
    i++;
  }
  size = array_GetSize(instances);
  for(; i < size; i++){
    pos = array_GetElement(instances,i);
    Index->marked[pos] = 0U;
  }
  Index->iter_pos = UINT_MAX;
  array_Clean(Index->tempar1);
}
void pathidx_PrintRec(PATHIDX Index, PIDXNODE Node)
{
  uint32_t i, cap, j, size;
  unsigned pos;
  PIDXNODE child;
  OHASH children;
  BOOL first;
  symbol_Print(pathidx_GetSymbstate(Index),Node->symb);
  if(Node->arity == 0){
    printf("< ");
    size = array_GetSize(Node->indexed);
    for(j = 0; j < size; j++){
      pos = (unsigned)array_GetElement(Node->indexed,j);
      if(j > 0){
 printf(", ");
      }
      term_PrettyPrint(pathidx_GetTermstate(Index),Index->terms[pos]);
    }
    printf(" >");
    return;
  }
  printf("( ");
  for(j = 0; j < Node->arity; j++){
    if(j > 0){
      printf(", ");
    }
    printf("%u:{ ",j);
    children = Node->children[j];
    cap = ohash_GetCapacity(children);
    first = TRUE;
    for(i = 0; i < cap; i++){
      if(ohash_GetOccupancyAtIndex(children,i) == ohash_ENTRY_OCCUPIED){
 child = (PIDXNODE)ohash_GetDataAtIndex(children,i);
 if(first){
   first=FALSE;
 }else{
   printf(", ");
 }
 pathidx_PrintRec(Index, child);
      }
    }
    printf(" }");
  }
  printf(" )");
}
void pathidx_Print(PATHIDX Index)
{
  unsigned i, cap;
  PIDXNODE child;
  cap = ohash_GetCapacity(Index->root);
  printf("\n PrintIndex:");
  for(i = 0; i < cap; i++){
    if(ohash_GetOccupancyAtIndex(Index->root,i) == ohash_ENTRY_OCCUPIED){
      child = (PIDXNODE)ohash_GetDataAtIndex(Index->root,i);
      printf("\n   ");
      pathidx_PrintRec(Index, child);
    }
  }
}
BOOL pathidx_TermEqualModuloSubsts(SYMBSTATE Symbstate, TERM Term1, SUBST Subst1, TERM Term2, SUBST Subst2)
{
  unsigned i;
  SYMBOL top1, top2;
  top1 = term_TopSymbol(Term1);
  top2 = term_TopSymbol(Term2);
  if (symbol_IsVariable(Symbstate, top1) &&
      Subst1 != NULL && subst_VarDefined(Subst1, top1)) {
    Term1 = subst_GetValue(Subst1,top1);
    top1 = term_TopSymbol(Term1);
    Subst1 = NULL;
  }
  if (symbol_IsVariable(Symbstate, top2) &&
      Subst2 != NULL && subst_VarDefined(Subst2, top2)) {
    Term2 = subst_GetValue(Subst2,top2);
    top2 = term_TopSymbol(Term2);
    Subst2 = NULL;
  }
  if (term_IsComplex(Term1)) {
    if (!symbol_Equal(top1, top2) || term_GetArity(Term1) != term_GetArity(Term2))
      return FALSE;
    for (i=0; i<term_GetArity(Term1); i++) {
      if (!pathidx_TermEqualModuloSubsts(Symbstate, (TERM)Term1[i], Subst1, (TERM)Term2[i], Subst2))
 return FALSE;
    }
    return TRUE;
  }
  else {
    return symbol_Equal(top1, top2);
  }
  misc_StartUserErrorReport();
  misc_UserErrorReport("%s: Ill defined Equal function, substs or terms.",__func__);
  misc_FinishUserErrorReport();
}
BOOL pathidx_IsInstanceOfRec(PATHIDX Index, TERM Term1, TERM Term2, SUBST Subst2, TYPING Types2, SUBST SubstR)
{
  unsigned i;
  SYMBOL top1, top2;
  top1 = term_TopSymbol(Term1);
  top2 = term_TopSymbol(Term2);
  if (symbol_IsVariable(pathidx_GetSymbstate(Index), top2) &&
      Subst2 != NULL && subst_VarDefined(Subst2, top2)) {
    Term2 = subst_GetValue(Subst2,top2);
    top2 = term_TopSymbol(Term2);
    Subst2 = NULL;
  }
  if (term_IsComplex(Term2)) {
    if (!symbol_Equal(top1, top2) || term_GetArity(Term1) != term_GetArity(Term2)){
      return FALSE;
    }
    for (i=0; i<term_GetArity(Term2); i++) {
      if (!pathidx_IsInstanceOfRec(Index,(TERM)Term1[i],(TERM)Term2[i],Subst2,Types2,SubstR)){
 return FALSE;
      }
    }
    return TRUE;
  }
  else {
    if (symbol_IsVariable(pathidx_GetSymbstate(Index), top2)) {
      if (subst_VarDefined(SubstR, top2)) {
 return Term1 == (TERM)subst_GetValue(SubstR, top2);
      }
      else {
 if (FALSE && Types2 != (TYPING)NULL && !symbol_IsVariable(pathidx_GetSymbstate(Index), top1) && symbol_GetVarTypingType(Types2, top2) != symbol_GetResultType(pathidx_GetSymbstate(Index),top1)){
   return FALSE;
 }
 subst_SetValue(SubstR, top2, Term1);
 return TRUE;
      }
    }
    else{
      return symbol_Equal(top1, top2);
    }
  }
  misc_StartUserErrorReport();
  misc_UserErrorReport("%s: Ill defined Matching function, substs or terms.",__func__);
  misc_FinishUserErrorReport();
  return FALSE;
}
SUBST pathidx_IsInstanceOf(PATHIDX Index, TERM Term1, TERM Term2, SUBST Subst2, TYPING Types2, unsigned Vars)
{
  SUBST SubstR;
  SubstR = subst_Create(pathidx_GetMemory(Index), Vars);
  if(pathidx_IsInstanceOfRec(Index,Term1,Term2,Subst2,Types2,SubstR)){
    return SubstR;
  }else{
    subst_Delete(pathidx_GetMemory(Index),SubstR);
    return NULL;
  }
}
unsigned pathidx_ComputeLeaves(TERMSTATE Termstate, TERM Term, SUBST Subst)
{
  unsigned i, Leaves;
#ifdef SPASS_CHECK
  if (!term_IsTerm(Termstate, Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s: Illegal input.", __func__);
    misc_FinishErrorReport();
  }
#endif
  if(Subst != NULL && term_IsVariable(Termstate,Term) &&
     subst_VarDefined(Subst,term_TopSymbol(Term))){
    Term = subst_GetValue(Subst,term_TopSymbol(Term));
    Subst = NULL;
  }
  if(term_GetArity(Term) == 0){
    Leaves = 1;
  }else{
    Leaves = 0;
  }
  for (i = 0; i < term_GetArity(Term); i++)
    Leaves += pathidx_ComputeLeaves(Termstate, term_GetArgument(Term, i), Subst);
  return Leaves;
}
