#include "congrbs.h"
void
congrbs_BacktrackUnion(CCBS_STATE State, TERM Term0, TERM Term1, BS_FLAG Flag0, BS_FLAG Flag1)
{
  BTBS_INFO* elem;
  elem = memory_Malloc(State->memory, sizeof(BTBS_INFO));
  elem->type = BTBS_UNION;
  elem->term[0] = Term0;
  elem->term[1] = Term1;
  elem->flags[0] = Flag0;
  elem->flags[1] = Flag1;
  State->btstack = array_Add(State->memory, State->btstack,(intptr_t) elem);
}
void
congrbs_BacktrackSigEnter(CCBS_STATE State, TERM Term)
{
  BTBS_INFO* elem;
  elem = memory_Malloc(State->memory, sizeof(BTBS_INFO));
  elem->type = BTBS_SIG_ENTER;
  elem->term[0] = Term;
  State->btstack = array_Add(State->memory, State->btstack,(intptr_t) elem);
}
void
congrbs_BacktrackFlagChanged(CCBS_STATE State, TERM Class, TERM Term)
{
  BTBS_INFO* elem;
  elem = memory_Malloc(State->memory, sizeof(BTBS_INFO));
  elem->type = BTBS_FLAG_CHG;
  elem->term[0] = Class;
  elem->term[1] = Term;
  State->btstack = array_Add(State->memory, State->btstack,(intptr_t) elem);
}
void
congrbs_BacktrackIneq(CCBS_STATE State, TERM Term0, TERM Term1)
{
  BTBS_INFO* elem;
  elem = memory_Malloc(State->memory, sizeof(BTBS_INFO));
  elem->type = BTBS_INEQ;
  elem->term[0] = Term0;
  elem->term[1] = Term1;
  State->btstack = array_Add(State->memory, State->btstack,(intptr_t) elem);
}
void
congrbs_BacktrackSigRemove(CCBS_STATE State, TERM Term)
{
  BTBS_INFO* elem;
  elem = memory_Malloc(State->memory, sizeof(BTBS_INFO));
  elem->type = BTBS_SIG_REMOVE;
  elem->term[0] = Term;
  State->btstack = array_Add(State->memory, State->btstack,(intptr_t) elem);
}
void
congrbs_BacktrackPredInsertion(CCBS_STATE State, TERM Term)
{
  BTBS_INFO* elem;
  elem = memory_Malloc(State->memory, sizeof(BTBS_INFO));
  elem->type = BTBS_PRED;
  elem->term[0] = Term;
  State->btstack = array_Add(State->memory, State->btstack,(intptr_t) elem);
}
void
congrbs_BacktrackStatus(CCBS_STATE State)
{
  BTBS_INFO* elem;
  elem = memory_Malloc(State->memory, sizeof(BTBS_INFO));
  elem->type = BTBS_STATUS;
  State->btstack = array_Add(State->memory, State->btstack,(intptr_t) elem);
}
void
congrbs_BacktrackPoint(CCBS_STATE State)
{
  BTBS_INFO* elem;
  elem = memory_Malloc(State->memory, sizeof(BTBS_INFO));
  elem->type = BTBS_POINT;
  State->btstack = array_Add(State->memory, State->btstack,(intptr_t) elem);
}
void
congrbs_MergePush(CCBS_STATE State, TERM Term0, TERM Term1)
{
  State->merge_queue = array_Add(State->memory, State->merge_queue,(intptr_t) Term0);
  State->merge_queue = array_Add(State->memory, State->merge_queue,(intptr_t) Term1);
}
OHASH_HASH_TYPE
congrbs_HashOneAtATimeU(OHASH_HASH_TYPE u)
{
  unsigned hash;
  hash = u & 0xFF;
  hash += (hash << 10);
  hash ^= (hash >> 6);
  hash += (u & 0xFF00) >> 8;
  hash += (hash << 10);
  hash ^= (hash >> 6);
  hash += (u & 0xFF0000) >> 16;
  hash += (hash << 10);
  hash ^= (hash >> 6);
  hash += (u & 0xFF000000) >> 24;
  hash += (hash << 10);
  hash ^= (hash >> 6);
  hash += (hash << 3);
  hash ^= (hash >> 11);
  hash += (hash << 15);
  return hash;
}
OHASH_HASH_TYPE
congrbs_HashOneAtATimeUInc(OHASH_HASH_TYPE Hash, OHASH_HASH_TYPE u)
{
  Hash += u & 0xFF;
  Hash += (Hash << 10);
  Hash ^= (Hash >> 6);
  Hash += (u & 0xFF00) >> 8;
  Hash += (Hash << 10);
  Hash ^= (Hash >> 6);
  Hash += (u & 0xFF0000) >> 16;
  Hash += (Hash << 10);
  Hash ^= (Hash >> 6);
  Hash += (u & 0xFF000000) >> 24;
  Hash += (Hash << 10);
  Hash ^= (Hash >> 6);
  return Hash;
}
OHASH_HASH_TYPE
congrbs_HashOneAtATimeIncEnd(OHASH_HASH_TYPE Hash)
{
  Hash += (Hash << 3);
  Hash ^= (Hash >> 11);
  Hash += (Hash << 15);
  return Hash;
}
OHASH_HASH_TYPE
congrbs_SigHash(CCBS_STATE State, TERM Term)
{
  OHASH_HASH_TYPE key;
  TERM param;
  CCBS_CLASSINFO classinfo;
#ifdef SPASS_CHECK
  if (!Term){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Term must exist");
    misc_FinishErrorReport();
  }
#endif
  key = congrbs_HashOneAtATimeU((OHASH_HASH_TYPE) term_TopSymbol(Term));
  for (unsigned i = 0; i < term_GetArity(Term); i++) {
    param = (TERM) State->class[term_Index(term_GetArgument(Term, i))];
    classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(param)];
    key = congrbs_HashOneAtATimeUInc(key, (OHASH_HASH_TYPE) term_Index(classinfo->term));
  }
  key = congrbs_HashOneAtATimeIncEnd(key);
  return key;
}
BOOL
congrbs_SigEqual(OHASH_KEY_TYPE Term1, OHASH_KEY_TYPE Term2, OHASH_DATA_TYPE env)
{
  CCBS_STATE state;
  TERM t1, t2;
  unsigned i;
  t1 = (TERM) Term1;
  t2 = (TERM) Term2;
  state = (CCBS_STATE) env;
#ifdef SPASS_CHECK
  if (!t1 || !t2){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Terms must exist");
    misc_FinishErrorReport();
  }
#endif
  if (t1 == t2) {
    return true;
  }
  if (term_GetArity(t1) != term_GetArity(t2))
    return false;
  if (term_TopSymbol(t1) != term_TopSymbol(t2))
    return false;
  for (i = 0; i < term_GetArity(t1); i++) {
    if (state->class[term_Index(term_GetArgument(t1, i))] !=
        state->class[term_Index(term_GetArgument(t2, i))]) {
      return false;
    }
  }
  return true;
}
CCBS_STATE
congrbs_Init(MEMORY Mem, TERMSTATE Termstate, FOLSTATE Folstate, SYMBSTATE Symbstate)
{
  CCBS_STATE state;
  state = memory_Malloc(Mem, sizeof(CCBS_TYPE));
  state->memory = Mem;
  state->termstate = Termstate;
  state->folstate = Folstate;
  state->symbstate = Symbstate;
  state->class = array_Create(state->memory, 20);
  state->status = true;
  state->conflict = NULL;
  state->class_info = array_Create(state->memory, 20);
  state->prooftree = NULL;
  state->prooftree = ohash_Create(state->memory, 128, (OHASH_HASH_FCT) ohash_IntegerNew, (OHASH_ELEM_EQUAL) ohash_IdEq);
  state->hash_bucket = NULL;
  state->hash_bucket = ohash_CreateWithEnv(state->memory, 128, (OHASH_HASH_FCT) NULL, (OHASH_ELEM_EQUAL_ENV) &congrbs_SigEqual,(OHASH_DATA_TYPE) state);
  state->zero_arity = array_Create(state->memory, 1);
  state->merge_queue = array_Create(state->memory, 1);
  state->confl_labels = array_Create(state->memory, 1);
  state->pending = array_Create(state->memory, 1);
  state->btstack = array_Create(state->memory, 1);
  state->tmp_stack_term = array_Create(state->memory, 1);
  state->diseqs = array_Create(state->memory, 1);
  state->pending_preds = array_Create(state->memory, 1);
  state->cons = array_Create(state->memory, 1);
  state->conc = array_Create(state->memory, 1);
  state->prem = array_Create(state->memory, 1);
  state->pred_cls = array_Create(state->memory, 1);
  state->pred_cls = array_Add(state->memory, state->pred_cls, (intptr_t) NULL);
  state->pred_cls = array_Add(state->memory, state->pred_cls, (intptr_t) NULL);
  state->cur_index = 1;
#ifdef SPASS_CHECK
  state->cst_iterators = 0;
#endif
  return state;
}
void congrbs_DeleteClassInfo(MEMORY Mem, OHASH_DATA_TYPE Data)
{
  CCBS_CLASSINFO classinfo;
  classinfo = (CCBS_CLASSINFO) Data;
  array_Delete(Mem, classinfo->pred);
  array_Delete(Mem, classinfo->diseqs);
  memory_Free(Mem, classinfo, sizeof(CCBS_CLASSINFO_TYPE));
}
void congrbs_DeleteCC(MEMORY Mem, OHASH_DATA_TYPE Data)
{
  memory_Free(Mem,(POINTER) Data, sizeof(CCBS_TREENODE_TYPE));
}
void
congrbs_Done(CCBS_STATE State)
{
  unsigned i;
  BTBS_INFO* btinfo;
  array_Delete(State->memory, State->class);
  for (i = 0; i < array_GetSize(State->class_info); i++) {
    if (State->class_info[i] != (intptr_t) NULL) {
      congrbs_DeleteClassInfo(State->memory, (OHASH_DATA_TYPE) State->class_info[i]);
    }
  }
  array_Delete(State->memory, State->class_info);
  ohash_Delete(State->prooftree, NULL, &congrbs_DeleteCC);
  ohash_Delete(State->hash_bucket, NULL, NULL);
  array_Delete(State->memory, State->merge_queue);
  array_Delete(State->memory, State->zero_arity);
  array_Delete(State->memory, State->confl_labels);
  array_Delete(State->memory, State->pending);
  array_Delete(State->memory, State->tmp_stack_term);
  array_Delete(State->memory, State->pending_preds);
  array_Delete(State->memory, State->cons);
  array_Delete(State->memory, State->conc);
  array_Delete(State->memory, State->prem);
  for (i = 0; i < array_GetSize(State->diseqs); i++) {
    memory_Free(State->memory, (CCBS_EQUATION) array_GetElement(State->diseqs, i), sizeof(CCBS_EQUATION_TYPE));
  }
  array_Delete(State->memory, State->diseqs);
  for (i = 0; i < array_GetSize(State->btstack); i++) {
    btinfo = (BTBS_INFO*) array_GetElement(State->btstack, i);
    memory_Free(State->memory, btinfo, sizeof(BTBS_INFO));
  }
  array_Delete(State->memory, State->btstack);
  array_Delete(State->memory, State->pred_cls);
  memory_Free(State->memory, State, sizeof(CCBS_TYPE));
}
void congrbs_Swap(void* a, void* b, size_t s)
{
    void* tmp;
    tmp = alloca(s);
    memcpy(tmp, a, s);
    memcpy(a, b, s);
    memcpy(b, tmp, s);
}
void congrbs_InsertCls(CCBS_STATE State, TERM New, BOOL Reset) {
  int idx;
  TERM start;
  CCBS_CLASSINFO new_info, start_info, other_info;
  SYMBSIG symbsig;
  symbsig = symbol_GetStateSig(State->symbstate);
  new_info = (CCBS_CLASSINFO) State->class_info[term_Index(New)];
  if (new_info->ineq_flag != BS_CONST) {
#ifdef SPASS_CHECK
    if (new_info->ineq_flag == BS_PUNDEF) {
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s:", __func__);
      misc_ErrorReport("\n Predicate classes can only be inserted if True or False");
      misc_FinishErrorReport();
    }
#endif
    idx = symbsig[symbol_GetIndex(term_TopSymbol(New))].index;
  } else {
    idx = 0;
  }
#ifdef SPASS_CHECK
  if (new_info->nxt_pred_cls) {
    other_info = (CCBS_CLASSINFO) State->class_info[term_Index(new_info->nxt_pred_cls)];
    if (other_info->prv_pred_cls == New) {
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s:", __func__);
      misc_ErrorReport("\n Class may not be in a linked list before insertion");
      misc_FinishErrorReport();
    }
  }
  if (new_info->prv_pred_cls) {
    other_info = (CCBS_CLASSINFO) State->class_info[term_Index(new_info->prv_pred_cls)];
    if (other_info->nxt_pred_cls == New) {
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s:", __func__);
      misc_ErrorReport("\n Class may not be in a linked list before insertion");
      misc_FinishErrorReport();
    }
  }
  if (idx >= 0) {
    if (array_GetElement(State->pred_cls, (idx*2)+1)) {
      if ((CCBS_CLASSINFO) State->class_info[term_Index((TERM) array_GetElement(State->pred_cls, (idx*2)+1))] == new_info) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class may not be in a linked list before insertion");
        misc_FinishErrorReport();
      }
    }
    if (array_GetElement(State->pred_cls, idx*2)){
      if ((CCBS_CLASSINFO) State->class_info[term_Index((TERM) array_GetElement(State->pred_cls, idx*2))] == new_info) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class may not be in a linked list before insertion");
        misc_FinishErrorReport();
      }
    }
  }
#endif
  if (Reset) {
    new_info->prv_pred_cls = NULL;
    new_info->nxt_pred_cls = NULL;
  }
  if (new_info->ineq_flag != BS_CONST) {
    if (idx == -1) {
      symbsig[symbol_GetIndex(term_TopSymbol(New))].index = State->cur_index++;
      State->pred_cls = array_Add(State->memory, State->pred_cls, (intptr_t) NULL);
      State->pred_cls = array_Add(State->memory, State->pred_cls, (intptr_t) NULL);
      idx = State->cur_index-1;
    }
    if (new_info->ineq_flag == BS_PFALSE) {
      idx = (idx*2)+1;
    } else {
      idx = idx*2;
    }
  }
  if (new_info->prv_pred_cls == NULL && new_info->nxt_pred_cls == NULL) {
    start = (CCBS_CLASS) array_GetElement(State->pred_cls, idx);
    array_SetElement(State->pred_cls, idx, (intptr_t) New);
    new_info->nxt_pred_cls = start;
    new_info->prv_pred_cls = NULL;
    if (start) {
      start_info = (CCBS_CLASSINFO) State->class_info[term_Index(start)];
      start_info->prv_pred_cls = New;
    }
  } else {
    if (new_info->nxt_pred_cls) {
      other_info = (CCBS_CLASSINFO) State->class_info[term_Index(new_info->nxt_pred_cls)];
#ifdef SPASS_CHECK
      if (idx > 1 && other_info->prv_pred_cls != new_info->prv_pred_cls){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Previous of next must be previous of inserted element");
        misc_FinishErrorReport();
      }
#endif
      new_info->prv_pred_cls = other_info->prv_pred_cls;
      other_info->prv_pred_cls = New;
    }
    if (new_info->prv_pred_cls) {
      other_info = (CCBS_CLASSINFO) State->class_info[term_Index(new_info->prv_pred_cls)];
      other_info->nxt_pred_cls = New;
    } else {
      array_SetElement(State->pred_cls, idx, (intptr_t) New);
    }
  }
#ifdef SPASS_CHECK
  if (new_info->nxt_pred_cls && (CCBS_CLASSINFO) State->class_info[term_Index(new_info->nxt_pred_cls)] == new_info) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Circles in linked list are not allowed");
    misc_FinishErrorReport();
  }
  if (new_info->prv_pred_cls && (CCBS_CLASSINFO) State->class_info[term_Index(new_info->prv_pred_cls)] == new_info){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Circles in linked list are not allowed");
    misc_FinishErrorReport();
  }
  if (symbol_IsPredicate(term_TopSymbol(New))) {
    idx = symbsig[symbol_GetIndex(term_TopSymbol(New))].index;
  } else {
    idx = 0;
  }
  if(new_info->nxt_pred_cls == NULL && new_info->prv_pred_cls == NULL) {
    if (idx >= 0) {
      if ((TERM) array_GetElement(State->pred_cls, (idx*2)+1) != New &&
          (TERM) array_GetElement(State->pred_cls, idx*2) != New) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class must be in a linked list after insertion");
        misc_FinishErrorReport();
      }
    } else {
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s:", __func__);
      misc_ErrorReport("\n Class must be in a linked list after insertion");
      misc_FinishErrorReport();
    }
  }
#endif
}
void congrbs_RemoveCls(CCBS_STATE State, TERM Element) {
    int idx;
    CCBS_CLASSINFO elm_info, other_info;
    SYMBSIG symbsig;
    symbsig = symbol_GetStateSig(State->symbstate);
    elm_info = (CCBS_CLASSINFO) State->class_info[term_Index(Element)];
    if (elm_info->ineq_flag != BS_CONST) {
      idx = symbsig[symbol_GetIndex(term_TopSymbol(Element))].index;
    } else {
      idx = 0;
    }
#ifdef SPASS_CHECK
    if (elm_info->nxt_pred_cls) {
      other_info = (CCBS_CLASSINFO) State->class_info[term_Index(elm_info->nxt_pred_cls)];
      if (other_info->prv_pred_cls != Element) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class must be in a linked list before removal");
        misc_FinishErrorReport();
      }
    }
    if (elm_info->prv_pred_cls) {
      other_info = (CCBS_CLASSINFO) State->class_info[term_Index(elm_info->prv_pred_cls)];
      if (other_info->nxt_pred_cls != Element) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class must be in a linked list before removal");
        misc_FinishErrorReport();
      }
    }
    if(elm_info->nxt_pred_cls == NULL && elm_info->prv_pred_cls == NULL) {
      if (idx >= 0) {
        if ((TERM) array_GetElement(State->pred_cls, (idx*2)+1) != Element &&
            (TERM) array_GetElement(State->pred_cls, idx*2) != Element) {
          misc_StartErrorReport();
          misc_ErrorReport("\n In %s:", __func__);
          misc_ErrorReport("\n Class must be in a linked list before removal");
          misc_FinishErrorReport();
        }
      } else {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class must be in a linked list before removal");
        misc_FinishErrorReport();
      }
    }
#endif
    if (!elm_info->prv_pred_cls) {
      if (idx > 0 && elm_info->ineq_flag == BS_PFALSE) {
        array_SetElement(State->pred_cls, (idx*2)+1, (intptr_t) elm_info->nxt_pred_cls);
      } else {
        array_SetElement(State->pred_cls, idx*2, (intptr_t) elm_info->nxt_pred_cls);
      }
    } else {
      other_info = (CCBS_CLASSINFO) State->class_info[term_Index(elm_info->prv_pred_cls)];
      other_info->nxt_pred_cls = elm_info->nxt_pred_cls;
    }
    if (elm_info->nxt_pred_cls) {
      other_info = (CCBS_CLASSINFO) State->class_info[term_Index(elm_info->nxt_pred_cls)];
      other_info->prv_pred_cls = elm_info->prv_pred_cls;
    }
#ifdef SPASS_CHECK
    if (elm_info->nxt_pred_cls) {
      other_info = (CCBS_CLASSINFO) State->class_info[term_Index(elm_info->nxt_pred_cls)];
      if (other_info->prv_pred_cls == Element) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class may not be in a linked list before insertion");
        misc_FinishErrorReport();
      }
    }
    if (elm_info->prv_pred_cls) {
      other_info = (CCBS_CLASSINFO) State->class_info[term_Index(elm_info->prv_pred_cls)];
      if (other_info->nxt_pred_cls == Element) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class may not be in a linked list before insertion");
        misc_FinishErrorReport();
      }
    }
    if (idx >= 0) {
      if ((TERM) array_GetElement(State->pred_cls, (idx*2)+1) == Element) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class may not be in a linked list before insertion");
        misc_FinishErrorReport();
      }
      if ((TERM) array_GetElement(State->pred_cls, idx*2) == Element) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Class may not be in a linked list before insertion");
        misc_FinishErrorReport();
      }
    }
  #endif
}
TERM congrbs_ClassGetInputTerm(CCBS_STATE State, CCBS_CLASS Class, TERM Term) {
  CCBS_CLASSINFO classinfo;
  TERM result;
  classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(Class)];
  result = NULL;
  if (classinfo->elem_nb == 1 && classinfo->is_input == TRUE) {
    return Class;
  } else {
    do {
      if (classinfo->is_input == TRUE) {
        result = Class;
        if (Class != Term) {
          return result;
        }
      }
      Class = classinfo->elem;
      classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(classinfo->elem)];
    } while (classinfo->elem);
    if (classinfo->is_input == TRUE) {
      result = Class;
      if (Class != Term) {
        return result;
      }
    }
  }
#ifdef SPASS_CHECK
  if (!result){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Must exist at least one!");
    misc_FinishErrorReport();
  }
#endif
  return result;
}
void
congrbs_Union(CCBS_STATE State, TERM Term0, TERM Term1, CCBS_LABEL Label)
{
  unsigned i;
  TERM tmp, orig, next, predterm0, predterm1;
  CCBS_CLASS class0, class1, diseqt0, diseqt1;
  CCBS_CLASSINFO class0info;
  CCBS_CLASSINFO class1info;
  CCBS_EQUATION diseq;
  CCBS_LABEL label2;
  CCBS_TREENODE treeelem;
  BS_FLAG flag0, flag1;
  class0 = (CCBS_CLASS) State->class[term_Index(Term0)];
  class1 = (CCBS_CLASS) State->class[term_Index(Term1)];
  class0info = (CCBS_CLASSINFO) State->class_info[term_Index(class0)];
  class1info = (CCBS_CLASSINFO) State->class_info[term_Index(class1)];
#ifdef SPASS_CHECK
      if (!Term0 || !Term1){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Terms must exist");
        misc_FinishErrorReport();
      }
#endif
  if (class0 == class1)
    return;
  if (array_GetSize(class0info->diseqs) > array_GetSize(class1info->diseqs)) {
    congrbs_Swap(&class0info, &class1info, sizeof(CCBS_CLASSINFO));
    congrbs_Swap(&class0, &class1, sizeof(CCBS_CLASS));
    congrbs_Swap(&Term0, &Term1, sizeof(TERM));
  }
  for (i = 0; i < array_GetSize(class0info->diseqs); i++) {
    diseq = (CCBS_EQUATION) array_GetElement(class0info->diseqs, i);
    diseqt0 = (CCBS_CLASS) State->class[term_Index(diseq->term[0])];
    diseqt1 = (CCBS_CLASS) State->class[term_Index(diseq->term[1])];
#ifdef SPASS_CHECK
    if (diseqt0 != class0 && diseqt0 != class1 && diseqt1 != class0 && diseqt1 != class1){
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s:", __func__);
      misc_ErrorReport("\n one term in disequation must be in one of the classes");
      misc_FinishErrorReport();
    }
#endif
    if ((diseqt0 == class0 && diseqt1 == class1) || (diseqt1 == class0 && diseqt0 == class1)) {
      State->conflict = diseq;
      State->status = false;
      congrbs_BacktrackStatus(State);
    }
  }
  if ((class0info->ineq_flag == BS_PTRUE && class1info->ineq_flag == BS_PFALSE) || (class0info->ineq_flag == BS_PFALSE && class1info->ineq_flag == BS_PTRUE)) {
     CCBS_EQUATION new_diseq = memory_Malloc(State->memory, sizeof(CCBS_EQUATION_TYPE));
     if (class0info->ineq_flag == BS_PTRUE && class1info->ineq_flag == BS_PFALSE) {
      new_diseq->term[0] = congrbs_ClassGetInputTerm(State, class0, NULL);
      new_diseq->term[1] = congrbs_ClassGetInputTerm(State, class1, NULL);
      new_diseq->label = (CCBS_LABEL) NULL;
     } else if (class0info->ineq_flag == BS_PFALSE && class1info->ineq_flag == BS_PTRUE) {
      new_diseq->term[0] = congrbs_ClassGetInputTerm(State, class1, NULL);
      new_diseq->term[1] = congrbs_ClassGetInputTerm(State, class0, NULL);
      new_diseq->label = (CCBS_LABEL) NULL;
     }
     State->conflict = new_diseq;
     State->status = false;
     congrbs_BacktrackStatus(State);
  }
  if (class0info->elem_nb < class1info->elem_nb)
    {
      congrbs_Swap(&class0info, &class1info, sizeof(CCBS_CLASSINFO));
      congrbs_Swap(&class0, &class1, sizeof(CCBS_CLASS));
      congrbs_Swap(&Term0, &Term1, sizeof(TERM));
    }
  class0info->diseqs = array_Append(State->memory, class0info->diseqs, class1info->diseqs);
  if (array_GetSize(class0info->pred) < array_GetSize(class1info->pred))
    {
      congrbs_Swap(&class0info->pred, &class1info->pred, sizeof(ARRAY));
      for (i = 0; i < array_GetSize(class1info->pred); i++) {
        tmp = (TERM) array_GetElement(class1info->pred, i);
        if ((TERM) ohash_SearchWithHash(State->hash_bucket,(OHASH_KEY_TYPE) tmp, congrbs_SigHash(State, tmp))) {
          congrbs_BacktrackSigRemove(State,(TERM) ohash_SearchWithHash(State->hash_bucket,(OHASH_KEY_TYPE) tmp, congrbs_SigHash(State, tmp)));
          State->hash_bucket = ohash_RemoveWithHash(State->hash_bucket,(OHASH_KEY_TYPE) tmp, congrbs_SigHash(State, tmp), NULL, NULL);
        }
      }
      congrbs_Swap(&class0info->term, &class1info->term, sizeof(TERM));
    }
  else
    for (i = 0; i < array_GetSize(class1info->pred); i++) {
      tmp = (TERM) array_GetElement(class1info->pred, i);
      if ((TERM) ohash_SearchWithHash(State->hash_bucket,(OHASH_KEY_TYPE) tmp, congrbs_SigHash(State, tmp))) {
        congrbs_BacktrackSigRemove(State,(TERM) ohash_SearchWithHash(State->hash_bucket,(OHASH_KEY_TYPE) tmp, congrbs_SigHash(State, tmp)));
        State->hash_bucket = ohash_RemoveWithHash(State->hash_bucket,(OHASH_KEY_TYPE) tmp, congrbs_SigHash(State, tmp), NULL, NULL);
      }
    }
  flag0 = class0info->ineq_flag;
  flag1 = class1info->ineq_flag;
  congrbs_BacktrackUnion(State, Term0, Term1, flag0, flag1);
  if (flag1 != BS_PUNDEF) {
    congrbs_RemoveCls(State, class1);
    if (flag0 == BS_PUNDEF) {
      class0info->ineq_flag = flag1;
      congrbs_InsertCls(State, class0, TRUE);
    }
  }
  orig = Term1;
  next = Term0;
  label2 = Label;
  do
    {
      treeelem = (CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) orig);
      congrbs_Swap(&label2, &(treeelem->label), sizeof(CCBS_LABEL));
      tmp = treeelem->next;
      treeelem->next = next;
      next = orig;
      orig = tmp;
    }
  while (orig);
  tmp = class1;
  while (((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem)
    {
      State->class = array_AddAtIndex(State->memory, State->class, term_Index(tmp), (intptr_t) class0);
      tmp = ((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem;
    }
  State->class = array_AddAtIndex(State->memory, State->class, term_Index(tmp), (intptr_t) class0);
  ((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem = class0info->elem;
  class0info->elem = class1;
  class0info->elem_nb += class1info->elem_nb;
  for (i = 0; i < array_GetSize(class1info->pred); i++)
    {
      predterm0 = (TERM) array_GetElement(class1info->pred, i);
      predterm1 = (TERM) ohash_SearchWithHash(State->hash_bucket,(OHASH_KEY_TYPE) predterm0, congrbs_SigHash(State, predterm0));
      if (!predterm1)
      {
        State->hash_bucket = ohash_InsertWithHash(State->hash_bucket,(OHASH_KEY_TYPE) predterm0, congrbs_SigHash(State, predterm0), (OHASH_DATA_TYPE) predterm0, NULL, NULL);
        congrbs_BacktrackSigEnter(State, predterm0);
        continue;
      }
      if (State->class[term_Index(predterm0)] != State->class[term_Index(predterm1)]){
        congrbs_MergePush(State, predterm0, predterm1);
      }
    }
  class0info->pred = array_Append(State->memory, class0info->pred, class1info->pred);
}
void
congrbs_UnionBacktrack(CCBS_STATE State, TERM Term0, TERM Term1, BS_FLAG Flag0, BS_FLAG Flag1)
{
#ifdef SPASS_CHECK
#endif
  unsigned i;
  TERM tmp;
  CCBS_CLASS class0;
  CCBS_CLASS class1;
  CCBS_CLASSINFO class0info;
  CCBS_CLASSINFO class1info;
  CCBS_TREENODE tmpproof;
  class0 = (CCBS_CLASS) State->class[term_Index(Term0)];
  class1 = (CCBS_CLASS) ((CCBS_CLASSINFO) State->class_info[term_Index(class0)])->elem;
  class0info = (CCBS_CLASSINFO) State->class_info[term_Index(class0)];
  class1info = (CCBS_CLASSINFO) State->class_info[term_Index(class1)];
#ifdef SPASS_CHECK
      if (State->class[term_Index(Term0)] != State->class[term_Index(Term1)]){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n both terms should be in the same class.");
        misc_FinishErrorReport();
      }
      if ((CCBS_CLASS) State->class[term_Index(class0info->term)] != class0){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n term representative should be in the class");
        misc_FinishErrorReport();
      }
      if (class0info->elem_nb <= class1info->elem_nb){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n class should contain all elements of both merged class, so larger.");
        misc_FinishErrorReport();
      }
#endif
  for (tmp = class0, i = class1info->elem_nb; i > 0; i--)
    {
      tmp = ((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem;
      State->class = array_AddAtIndex(State->memory, State->class, term_Index(tmp), (intptr_t) class1);
    }
  class0info->elem = ((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem;
  ((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem = BSTERM_NULL;
#ifdef SPASS_CHECK
      if (class0info->elem_nb <= class1info->elem_nb){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n element number should be greater before disunion.");
        misc_FinishErrorReport();
      }
#endif
  class0info->elem_nb -= class1info->elem_nb;
  tmpproof = (CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) Term0);
  if (tmpproof->next == Term1)
    {
      tmpproof->next = BSTERM_NULL;
      tmpproof->label = BSLABEL_NULL;
    }
  else
    {
      tmpproof = (CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) Term1);
#ifdef SPASS_CHECK
      if (tmpproof->next != Term0){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Next term in proof should be Term0 after Union.");
        misc_FinishErrorReport();
      }
#endif
      tmpproof->next = BSTERM_NULL;
      tmpproof->label = BSLABEL_NULL;
    }
#ifdef SPASS_CHECK
  if(array_GetSize(class0info->pred) < array_GetSize(class1info->pred)){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n predicates should be smaller before disunion.");
    misc_FinishErrorReport();
  }
#endif
  array_SetSize(class0info->pred,array_GetSize(class0info->pred)-array_GetSize(class1info->pred));
  if ((CCBS_CLASS) State->class[term_Index(class0info->term)] == class1)
    {
      congrbs_Swap(&class0info->term, &class1info->term, sizeof(TERM));
      congrbs_Swap(&class0info->pred, &class1info->pred, sizeof(ARRAY));
    }
#ifdef SPASS_CHECK
  if(class0info == class1info){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Class infos should not match.");
    misc_FinishErrorReport();
  }
  if((CCBS_CLASS) State->class[term_Index(class0info->term)] != class0){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Class info term does not match class.");
    misc_FinishErrorReport();
  }
  if((CCBS_CLASS) State->class[term_Index(class1info->term)] != class1){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Class info term does not match class.");
    misc_FinishErrorReport();
  }
#endif
  array_SetSize(class0info->diseqs,array_GetSize(class0info->diseqs)-array_GetSize(class1info->diseqs));
#ifdef SPASS_CHECK
  tmp = (TERM) State->class[term_Index(Term0)];
  for (i = 1; (tmp = ((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem); i++)
    ;
  if(i != class0info->elem_nb){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Size of backtracked class is wrong.");
    misc_FinishErrorReport();
  }
  tmp = (TERM) State->class[term_Index(Term1)];
  i = 1;
  for (i = 1; (tmp = ((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem); i++)
    ;
  if(i != class1info->elem_nb){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Size of backtracked class is wrong.");
    misc_FinishErrorReport();
  }
  #endif
  if (Flag0 == BS_PUNDEF && Flag1 != BS_PUNDEF) {
    congrbs_RemoveCls(State, class0);
  }
  class0info->ineq_flag = Flag0;
  class1info->ineq_flag = Flag1;
  if (Flag1 != BS_PUNDEF) {
    congrbs_InsertCls(State, class1, FALSE);
  }
}
void
congrbs_Merge(CCBS_STATE State, TERM Term0, TERM Term1, CCBS_LABEL Label)
{
  unsigned i;
  i = 0;
  congrbs_Union(State, Term0, Term1, Label);
  while (i < array_GetSize(State->merge_queue) && State->status != false)
    {
      Term0 = (TERM) array_GetElement(State->merge_queue, i);
      Term1 = (TERM) array_GetElement(State->merge_queue, i + 1);
      congrbs_Union(State, Term0, Term1, BSLABEL_NULL);
      i += 2;
    }
  array_SetSize(State->merge_queue, 0);
}
BOOL
congrbs_AssertEqualConst(CCBS_STATE State, TERM Term0, TERM Term1, CCBS_LABEL Label)
{
    TERM classterm0;
    TERM classterm1;
    #ifdef SPASS_CHECK
      if(!term_IsConstant(State->termstate, Term0) || !term_IsConstant(State->termstate, Term1)){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Terms must be constants.");
        misc_FinishErrorReport();
      }
    #endif
    if (State->status == false)
        return State->status;
    congrbs_BuildTerm(State, Term0, BS_CONST);
    congrbs_BuildTerm(State, Term1, BS_CONST);
    classterm0 = (CCBS_CLASS) State->class[term_Index(Term0)];
    classterm1 = (CCBS_CLASS) State->class[term_Index(Term1)];
    if (classterm0 == classterm1)
        return State->status;
    congrbs_Merge(State, Term0, Term1, Label);
    return State->status;
}
BOOL
congrbs_AssertNotEqualConst(CCBS_STATE State, TERM Term0, TERM Term1, CCBS_LABEL Label)
{
    CCBS_CLASS classterm0;
    CCBS_CLASS classterm1;
    CCBS_CLASSINFO classinfo;
    #ifdef SPASS_CHECK
      if(!term_IsConstant(State->termstate, Term0) || !term_IsConstant(State->termstate, Term1)){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Terms must be constants.");
        misc_FinishErrorReport();
      }
    #endif
    if (State->status == false)
      return State->status;
    congrbs_BuildTerm(State, Term0, BS_CONST);
    congrbs_BuildTerm(State, Term1, BS_CONST);
    classterm0 = (CCBS_CLASS) State->class[term_Index(Term0)];
    classterm1 = (CCBS_CLASS) State->class[term_Index(Term1)];
    CCBS_EQUATION new_diseq = memory_Malloc(State->memory, sizeof(CCBS_EQUATION_TYPE));
    State->diseqs = array_Add(State->memory, State->diseqs,(intptr_t) new_diseq);
    new_diseq->term[0] = Term0;
    new_diseq->term[1] = Term1;
    new_diseq->label = Label;
    classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(classterm0)];
    classinfo->diseqs = array_Add(State->memory, classinfo->diseqs,(intptr_t) new_diseq);
    if (classterm0 == classterm1) {
      congrbs_BacktrackIneq(State, classterm0, NULL);
      State->conflict = new_diseq;
      State->status = false;
      congrbs_BacktrackStatus(State);
    } else {
      congrbs_BacktrackIneq(State, classterm0, classterm1);
      classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(classterm1)];
      classinfo->diseqs = array_Add(State->memory, classinfo->diseqs,(intptr_t) new_diseq);
    }
    return State->status;
}
BOOL
congrbs_AssertEqualBSPred(CCBS_STATE State, TERM Term, CCBS_LABEL Label)
{
    CCBS_CLASSINFO classinfo;
    CCBS_CLASS class;
    if (term_GetArity(Term) == 0) {
      return State->status;
    }
    #ifdef SPASS_CHECK
      if(!symbol_IsPredicate(term_TopSymbol(Term))){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n Term must be a predicate");
        misc_FinishErrorReport();
      } else {
        for (unsigned i = 0; i < term_GetArity(Term); i++) {
          if(!term_IsConstant(State->termstate, term_GetArgument(Term, i))){
            misc_StartErrorReport();
            misc_ErrorReport("\n In %s:", __func__);
            misc_ErrorReport("\n Arguments must be constants.");
            misc_FinishErrorReport();
          }
        }
      }
    #endif
    if (State->status == false)
        return State->status;
    if (array_GetSize(State->class) > term_Index(Term) && State->class[term_Index(Term)]) {
      class = (CCBS_CLASS) State->class[term_Index(Term)];
      classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(class)];
      if (classinfo->ineq_flag == BS_PFALSE) {
        CCBS_EQUATION new_diseq = memory_Malloc(State->memory, sizeof(CCBS_EQUATION_TYPE));
        new_diseq->term[0] = Term;
        new_diseq->term[1] = congrbs_ClassGetInputTerm(State, class, Term);
        new_diseq->label = (CCBS_LABEL) NULL;
        State->conflict = new_diseq;
        State->status = false;
        congrbs_BacktrackStatus(State);
        return State->status;
      }
    }
    congrbs_BuildTerm(State, Term, BS_PTRUE);
    return State->status;
}
BOOL
congrbs_AssertNotEqualBSPred(CCBS_STATE State, TERM Term, CCBS_LABEL Label)
{
    CCBS_CLASSINFO classinfo;
    CCBS_CLASS class;
    if (term_GetArity(Term) == 0) {
      return State->status;
    }
    #ifdef SPASS_CHECK
    if(!symbol_IsPredicate(term_TopSymbol(Term))){
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s:", __func__);
      misc_ErrorReport("\n Term must be a predicate");
      misc_FinishErrorReport();
    } else {
      for (unsigned i = 0; i < term_GetArity(Term); i++) {
        if(!term_IsConstant(State->termstate, term_GetArgument(Term, i))){
          misc_StartErrorReport();
          misc_ErrorReport("\n In %s:", __func__);
          misc_ErrorReport("\n Arguments must be constants.");
          misc_FinishErrorReport();
        }
      }
    }
    #endif
    if (State->status == false)
      return State->status;
    if (array_GetSize(State->class) > term_Index(Term) && State->class[term_Index(Term)]) {
      class = (CCBS_CLASS) State->class[term_Index(Term)];
      classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(class)];
      if (classinfo->ineq_flag == BS_PTRUE) {
        CCBS_EQUATION new_diseq = memory_Malloc(State->memory, sizeof(CCBS_EQUATION_TYPE));
        new_diseq->term[1] = Term;
        new_diseq->term[0] = congrbs_ClassGetInputTerm(State, class, Term);
        new_diseq->label = (CCBS_LABEL) NULL;
        State->conflict = new_diseq;
        State->status = false;
        congrbs_BacktrackStatus(State);
        return State->status;
      }
    }
    congrbs_BuildTerm(State, Term, BS_PFALSE);
    return State->status;
}
TERM
congrbs_GetClass(CCBS_STATE State, TERM Term)
{
    return (TERM) State->class[term_Index(Term)];
}
void congrbs_InsertPredecessor(CCBS_STATE State, TERM Term) {
  unsigned i, n;
  TERM sharedsubterm, class, tmp;
  CCBS_CLASSINFO classinfo;
  tmp = (TERM) ohash_SearchWithHash(State->hash_bucket, (OHASH_KEY_TYPE) Term, (OHASH_HASH_TYPE) congrbs_SigHash(State, Term));
  congrbs_BacktrackPredInsertion(State, Term);
  if (tmp) {
    class = (TERM) State->class[term_Index(Term)];
    congrbs_Union(State, class,(TERM) State->class[term_Index(tmp)], BSLABEL_NULL);
  } else {
    State->hash_bucket = ohash_InsertWithHash(State->hash_bucket, (OHASH_KEY_TYPE) Term, (OHASH_HASH_TYPE) congrbs_SigHash(State, Term), (OHASH_DATA_TYPE) Term, NULL, NULL);
    congrbs_BacktrackSigEnter(State, Term);
    #ifdef SPASS_CHECK
      if (!ohash_SearchWithHash(State->hash_bucket,(OHASH_KEY_TYPE) Term, congrbs_SigHash(State, Term))) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n term must be in hash table after insertion!");
        misc_FinishErrorReport();
      }
    #endif
    n = term_GetArity(Term);
    for (i = 0; i < n; i++) {
      sharedsubterm = term_GetArgument(Term, i);
      class = (CCBS_CLASS) State->class[term_Index(sharedsubterm)];
      classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(class)];
      classinfo->pred = array_Add(State->memory, classinfo->pred,(intptr_t) Term);
    }
  }
}
void
congrbs_BuildTerm(CCBS_STATE State, TERM Term, BS_FLAG Flag)
{
  TERM sharedsubterm, class;
  CCBS_CLASSINFO classinfo;
  CCBS_TREENODE proofelem;
  unsigned i;
#ifdef SPASS_CHECK
  if(!Term){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Term must exist.");
    misc_FinishErrorReport();
  }
#endif
  if (array_GetSize(State->class) > term_Index(Term) && State->class[term_Index(Term)]) {
    class = (TERM) State->class[term_Index(Term)];
    classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(class)];
    #ifdef SPASS_CHECK
      if(classinfo->ineq_flag != BS_PUNDEF && classinfo->ineq_flag != Flag){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n If class exists and flag is changed it is assumed to be undef before.");
        misc_FinishErrorReport();
      }
    #endif
    if (classinfo->ineq_flag == BS_PUNDEF && Flag != BS_PUNDEF) {
      ((CCBS_CLASSINFO) State->class_info[term_Index(Term)])->is_input = TRUE;
      classinfo->ineq_flag = Flag;
      congrbs_BacktrackFlagChanged(State, class, Term);
      congrbs_InsertCls(State, class, TRUE);
    }
    return;
  }
#ifdef SPASS_CHECK
  if (Flag == BS_CONST && State->cst_iterators) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Constant class added while at least one iterator is running.");
    misc_FinishErrorReport();
  }
#endif
  classinfo = memory_Malloc(State->memory, sizeof(CCBS_CLASSINFO_TYPE));
  classinfo->nxt_pred_cls = NULL;
  classinfo->prv_pred_cls = NULL;
  classinfo->elem_nb = 1;
  classinfo->elem = BSTERM_NULL;
  classinfo->diseqs = array_Create(State->memory, 1);
  classinfo->pred = array_Create(State->memory, 1);
  classinfo->term = Term;
  State->class = array_AddAtIndex(State->memory, State->class, term_Index(Term), (intptr_t) Term);
  State->class_info = array_AddAtIndex(State->memory, State->class_info, term_Index(Term), (intptr_t) classinfo);
  classinfo->ineq_flag = Flag;
  classinfo->is_input = FALSE;
  if (Flag != BS_PUNDEF) {
    if (Flag == BS_PTRUE || Flag == BS_PFALSE) {
      classinfo->is_input = TRUE;
      congrbs_BacktrackFlagChanged(State, Term, Term);
    }
    congrbs_InsertCls(State, Term, TRUE);
  }
  proofelem = memory_Malloc(State->memory, sizeof(CCBS_TREENODE_TYPE));
  proofelem->next = BSTERM_NULL;
  proofelem->tmp = false;
  proofelem->label = BSLABEL_NULL;
  State->prooftree = ohash_Insert(State->prooftree, (OHASH_KEY_TYPE) Term, (OHASH_DATA_TYPE) proofelem, NULL, &congrbs_DeleteCC);
  for (i = 0; i < term_GetArity(Term); i++) {
      sharedsubterm = term_GetArgument(Term, i);
      congrbs_BuildTerm(State, sharedsubterm, BS_CONST);
  }
  if (term_GetArity(Term) == 0)
    State->zero_arity = array_Add(State->memory, State->zero_arity,(intptr_t) Term);
  else
    congrbs_InsertPredecessor(State, Term);
}
TERM
congrbs_NearestCommonAncestor(CCBS_STATE State, TERM Term0, TERM Term1)
{
  TERM t0, t1;
#ifdef SPASS_CHECK
  if(!Term0 || !Term1){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Both terms must exist.");
    misc_FinishErrorReport();
  }
#endif
  t0 = Term0;
  t1 = Term1;
  while (!((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) t0))->tmp)
    {
      ((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) t0))->tmp = true;
      t0 = ((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) t0))->next;
      if (t1)
        congrbs_Swap(&t0, &t1, sizeof(TERM));
#ifdef SPASS_CHECK
      if(!t0){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n term may not be NULL.");
        misc_FinishErrorReport();
      }
#endif
    }
  for (t1 = Term0; t1 && ((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) t1))->tmp; t1 = ((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) t1))->next)
    ((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) t1))->tmp = false;
  for (t1 = Term1; t1 && ((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) t1))->tmp; t1 = ((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) t1))->next)
    ((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) t1))->tmp = false;
  return t0;
}
void
congrbs_ExplainCongruence(CCBS_STATE State, TERM Term0, TERM Term1)
{
  unsigned i, arityt0;
  TERM tmp0, tmp1;
  arityt0 = term_GetArity(Term0);
#ifdef SPASS_CHECK
  unsigned arityt1;
  arityt1 = term_GetArity(Term1);
  if (arityt0 != arityt1){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n arities must match");
    misc_FinishErrorReport();
  }
#endif
  if (Term0 == Term1) return;
  for (i = 0; i < arityt0; i++)
    {
      tmp0 = term_GetArgument(Term0, i);
      tmp1 = term_GetArgument(Term1, i);
      if (tmp0 == tmp1)
        continue;
      State->pending = array_Add(State->memory, State->pending,(intptr_t) tmp0);
      State->pending = array_Add(State->memory, State->pending,(intptr_t) tmp1);
    }
}
TERM
congrbs_ExplainPath(CCBS_STATE State, TERM Term0, TERM Term1)
{
  TERM highestcongruent;
  CCBS_TREENODE tmpproof;
  highestcongruent = Term0;
  while (Term0 != Term1)
  {
    tmpproof = ((CCBS_TREENODE) ohash_Search(State->prooftree, (OHASH_KEY_TYPE) Term0));
    if (tmpproof->label)
      {
      congrbs_ExplainCongruence(State, highestcongruent, Term0);
      State->confl_labels = array_Add(State->memory, State->confl_labels, tmpproof->label);
      Term0 = tmpproof->next;
      highestcongruent = Term0;
      }
    else
      Term0 = tmpproof->next;
  }
  return highestcongruent;
}
static BOOL
compare_ptrs(intptr_t ptr0, intptr_t ptr1)
{
  return ptr0 == ptr1;
}
void
congrbs_ExploreConflict(CCBS_STATE State)
{
  TERM term0;
  TERM term1;
  TERM ancestor;
  TERM highestcongruent0, highestcongruent1;
#ifdef SPASS_CHECK
  if (State->status){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n status must be false to get a conflict");
    misc_FinishErrorReport();
  }
#endif
  array_SetSize(State->confl_labels, 0);
  State->pending = array_Add(State->memory, State->pending,(intptr_t) State->conflict->term[0]);
  State->pending = array_Add(State->memory, State->pending,(intptr_t) State->conflict->term[1]);
  while (array_GetSize(State->pending))
    {
      term0 = (TERM) array_Pop(State->pending);
      term1 = (TERM) array_Pop(State->pending);
#ifdef SPASS_CHECK
      if (!term0 || !term1){
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s:", __func__);
        misc_ErrorReport("\n terms may not be NULL");
        misc_FinishErrorReport();
      }
#endif
      ancestor = congrbs_NearestCommonAncestor(State, term0, term1);
      highestcongruent0 = congrbs_ExplainPath(State, term0, ancestor);
      highestcongruent1 = congrbs_ExplainPath(State, term1, ancestor);
      congrbs_ExplainCongruence(State, highestcongruent0, highestcongruent1);
    }
  array_RemoveDuplicates(State->memory, State->confl_labels, &compare_ptrs);
}
void
congrbs_BacktrackPush(CCBS_STATE State)
{
  congrbs_BacktrackPoint(State);
}
void
congrbs_BacktrackPopIntern(CCBS_STATE State, BOOL Add)
{
  TERM tmp, term0, term1;
  BS_FLAG flag0, flag1;
  CCBS_EQUATION diseq;
  CCBS_CLASS class;
  CCBS_CLASSINFO classinfo;
  unsigned i;
  while (array_GetSize(State->btstack))
    switch (((BTBS_INFO*) array_Top(State->btstack))->type) {
      case BTBS_POINT:
        memory_Free(State->memory,(POINTER) array_Pop(State->btstack), sizeof(BTBS_INFO));
        while (Add && array_GetSize(State->pending_preds)) {
          tmp = (TERM) array_Pop(State->pending_preds);
          congrbs_InsertPredecessor(State, tmp);
        }
       return;
      case BTBS_UNION:
        term0 = ((BTBS_INFO*) array_Top(State->btstack))->term[0];
        term1 = ((BTBS_INFO*) array_Top(State->btstack))->term[1];
        flag0 = ((BTBS_INFO*) array_Top(State->btstack))->flags[0];
        flag1 = ((BTBS_INFO*) array_Top(State->btstack))->flags[1];
        congrbs_UnionBacktrack(State, term0, term1, flag0, flag1);
        memory_Free(State->memory,(POINTER) array_Pop(State->btstack), sizeof(BTBS_INFO));
        break;
      case BTBS_SIG_ENTER:
        term0 = ((BTBS_INFO*) array_Top(State->btstack))->term[0];
        tmp = (TERM) ohash_SearchWithHash(State->hash_bucket, (OHASH_KEY_TYPE) term0, congrbs_SigHash(State, term0));
        State->hash_bucket = ohash_RemoveWithHash(State->hash_bucket, (OHASH_KEY_TYPE) term0, congrbs_SigHash(State, term0), NULL, NULL);
#ifdef SPASS_CHECK
        if (!tmp){
          misc_StartErrorReport();
          misc_ErrorReport("\n In %s:", __func__);
          misc_ErrorReport("\n signature must have existed before");
          misc_FinishErrorReport();
        }
#endif
        memory_Free(State->memory,(POINTER) array_Pop(State->btstack), sizeof(BTBS_INFO));
        break;
      case BTBS_SIG_REMOVE:
        term0 = ((BTBS_INFO*) array_Top(State->btstack))->term[0];
        State->hash_bucket = ohash_InsertWithHash(State->hash_bucket, (OHASH_KEY_TYPE) term0, congrbs_SigHash(State, term0), (OHASH_DATA_TYPE) term0, NULL, NULL);
#ifdef SPASS_CHECK
          if (!ohash_SearchWithHash(State->hash_bucket,(OHASH_KEY_TYPE) term0, congrbs_SigHash(State, term0))) {
            misc_StartErrorReport();
            misc_ErrorReport("\n In %s:", __func__);
            misc_ErrorReport("\n term must be in hash table after insertion!");
            misc_FinishErrorReport();
          }
#endif
        memory_Free(State->memory,(POINTER) array_Pop(State->btstack), sizeof(BTBS_INFO));
        break;
      case BTBS_STATUS:
        State->status = true;
        if (symbol_IsPredicate(term_TopSymbol(State->conflict->term[0]))) {
          memory_Free(State->memory,(POINTER) State->conflict, sizeof(CCBS_EQUATION_TYPE));
          State->conflict = NULL;
        }
        memory_Free(State->memory,(POINTER) array_Pop(State->btstack), sizeof(BTBS_INFO));
        break;
      case BTBS_FLAG_CHG:
        term0 = ((BTBS_INFO*) array_Top(State->btstack))->term[0];
        term1 = ((BTBS_INFO*) array_Top(State->btstack))->term[1];
        congrbs_RemoveCls(State, term0);
        ((CCBS_CLASSINFO) State->class_info[term_Index(term0)])->ineq_flag = BS_PUNDEF;
        ((CCBS_CLASSINFO) State->class_info[term_Index(term1)])->is_input = FALSE;
        memory_Free(State->memory,(POINTER) array_Pop(State->btstack), sizeof(BTBS_INFO));
        break;
      case BTBS_INEQ:
        term0 = ((BTBS_INFO*) array_Top(State->btstack))->term[0];
        diseq = (CCBS_EQUATION) array_Pop(((CCBS_CLASSINFO) State->class_info[term_Index(term0)])->diseqs);
        term1 = ((BTBS_INFO*) array_Top(State->btstack))->term[1];
        if (term1) {
#ifdef SPASS_CHECK
          if (diseq != (CCBS_EQUATION) array_Top(((CCBS_CLASSINFO) State->class_info[term_Index(term1)])->diseqs)){
            misc_StartErrorReport();
            misc_ErrorReport("\n In %s:", __func__);
            misc_ErrorReport("\n diseqs must be the same");
            misc_FinishErrorReport();
          }
#endif
          diseq = (CCBS_EQUATION) array_Pop(((CCBS_CLASSINFO) State->class_info[term_Index(term1)])->diseqs);
  }
#ifdef SPASS_CHECK
        if (diseq != (CCBS_EQUATION) array_Top(State->diseqs)){
          misc_StartErrorReport();
          misc_ErrorReport("\n In %s:", __func__);
          misc_ErrorReport("\n diseqs must be the same");
          misc_FinishErrorReport();
        }
#endif
        diseq = (CCBS_EQUATION) array_Pop(State->diseqs);
        memory_Free(State->memory,(POINTER) diseq, sizeof(CCBS_EQUATION_TYPE));
        memory_Free(State->memory,(POINTER) array_Pop(State->btstack), sizeof(BTBS_INFO));
        break;
      case BTBS_PRED:
        term0 = ((BTBS_INFO*) array_Top(State->btstack))->term[0];
        if (!ohash_SearchWithHash(State->hash_bucket, (OHASH_KEY_TYPE) term0, (OHASH_HASH_TYPE) congrbs_SigHash(State, term0))) {
          for (i = 0; i < term_GetArity(term0); i++) {
            tmp = term_GetArgument(term0, i);
            class = (CCBS_CLASS) State->class[term_Index(tmp)];
            classinfo = (CCBS_CLASSINFO) State->class_info[term_Index(class)];
            fflush(stdout);
            array_Pop(classinfo->pred);
          }
        }
        State->pending_preds = array_Add(State->memory, State->pending_preds, (intptr_t) term0);
        memory_Free(State->memory,(POINTER) array_Pop(State->btstack), sizeof(BTBS_INFO));
        break;
    }
#ifdef SPASS_CHECK
  if (!array_GetSize(State->btstack)){
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n backtrack stack must have at least one element");
    misc_FinishErrorReport();
  }
#endif
}
void congrbs_BacktrackPop(CCBS_STATE State)
{
  congrbs_BacktrackPopIntern(State, TRUE);
}
void congrbs_Backtrack(CCBS_STATE State, unsigned Steps)
{
  unsigned i;
  TERM tmp;
  for (i = 0; i < Steps; i++) {
    congrbs_BacktrackPopIntern(State, FALSE);
  }
  while (array_GetSize(State->pending_preds)) {
    tmp = (TERM) array_Pop(State->pending_preds);
    congrbs_InsertPredecessor(State, tmp);
  }
}
ARRAY
congrbs_GetAllClasses(CCBS_STATE State)
{
  unsigned i;
  array_Clean(State->tmp_stack_term);
  for (i = 0; i < array_GetSize(State->class); i++) {
    if (State->class[i] != (intptr_t) NULL && State->class[i] == (intptr_t) i) {
      State->tmp_stack_term = array_Add(State->memory, State->tmp_stack_term, State->class[i]);
    }
  }
  return State->tmp_stack_term;
}
ARRAY congrbs_GetClassTerms(CCBS_STATE State, TERM Term)
{
  TERM tmp;
  tmp = (TERM) State->class[term_Index(Term)];
  array_Clean(State->tmp_stack_term);
  while (tmp)
    {
      State->tmp_stack_term = array_Add(State->memory, State->tmp_stack_term,(intptr_t) tmp);
      tmp = ((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem;
    }
  return State->tmp_stack_term;
}
ARRAY congrbs_GetSignatures(CCBS_STATE State, TERM Term)
{
  TERM tmp;
  tmp = (TERM) State->class[term_Index(Term)];
  array_Clean(State->tmp_stack_term);
  while (tmp)
    {
      if (tmp == (TERM) ohash_SearchWithHash(State->hash_bucket, (OHASH_KEY_TYPE) tmp, (OHASH_HASH_TYPE) congrbs_SigHash(State, tmp)))
       State->tmp_stack_term = array_Add(State->memory, State->tmp_stack_term,(intptr_t) tmp);
      tmp = ((CCBS_CLASSINFO) State->class_info[term_Index(tmp)])->elem;
    }
  return State->tmp_stack_term;
}
BOOL
congrbs_CheckEq(CCBS_STATE State, TERM Term0, TERM Term1)
{
  return State->class[term_Index(Term0)] == State->class[term_Index(Term1)];
}
void congrbs_PrintClasses(CCBS_STATE State) {
    unsigned i, j;
    CCBS_CLASSINFO record;
    TERM term;
    printf("\n");
    for (i = 0; i < array_GetSize(State->class); i++) {
        if (array_GetElement(State->class, i) == (intptr_t) NULL) {
            continue;
        }
        if (term_Index((TERM) array_GetElement(State->class, i)) != (intptr_t) i) {
            continue;
        }
        printf("%s%d \n", "Congruence Class: ", i);
        record = (CCBS_CLASSINFO) State->class_info[i];
        printf("%s%d \n", "VFlag: ", record->ineq_flag);
        term = (TERM) State->class[i];
        unsigned elem_nb = record->elem_nb;
        for (j = 0; j < elem_nb; j++) {
            term_PrettyPrint(State->termstate, term);
            term = (TERM) record->elem;
            if (term) {
              record = (CCBS_CLASSINFO) State->class_info[term_Index(term)];
            }
            printf("\n");
        }
    }
}
unsigned congrbs_GetNumClasses(CCBS_STATE State) {
  unsigned i, numclasses;
  numclasses = 0;
  for (i = 0; i < array_GetSize(State->class); i++) {
    if (array_GetElement(State->class, i) == (intptr_t) NULL) {
        continue;
    }
    if (term_Index((TERM) array_GetElement(State->class, i)) != i) {
        continue;
    }
    numclasses += 1;
  }
  return numclasses;
}
BOOL congrbs_CheckMatchArgs(CCBS_STATE State, FOLSTATE Folstate, SUBSTSTATE SState, TERM Term0, TERM Term1) {
  unsigned i;
  BOOL match;
  TERM arg0, arg1;
  match = TRUE;
  for (i = 0; i < term_GetArity(Term0); i++) {
    arg0 = term_GetArgument(Term0, i);
    arg1 = term_GetArgument(Term1, i);
    if (term_IsVariable(State->termstate, arg0) && !subst_ContextValueIsMarked(SState, term_TopSymbol(arg0))) {
      if (!subst_TermMatchTermsStackFol(SState, State->symbstate, State->termstate, Folstate, arg0, NULL, arg1, NULL)) {
        match = false;
        break;
      }
    } else {
      if (term_IsVariable(State->termstate, arg0) && subst_ContextValueIsMarked(SState, term_TopSymbol(arg0))) {
        arg0 = (TERM) subst_ContextGetValue(SState, term_TopSymbol(arg0));
      }
      congrbs_BuildTerm(State, arg0, BS_CONST);
      if (State->class[term_Index(arg0)] != State->class[term_Index(arg1)]) {
        match = false;
        break;
      }
    }
  }
  return match;
}
CCBS_ITERATOR congrbs_IteratorStart(CCBS_STATE State, SYMBOL TopSymbol, BS_FLAG Flag) {
  CCBS_ITERATOR iterator;
  int idx;
  SYMBSIG symbsig;
  iterator = memory_Malloc(State->memory, sizeof(CCBS_ITERATOR_TYPE));
  symbsig = symbol_GetStateSig(State->symbstate);
#ifdef SPASS_CHECK
  iterator->btstacksize = array_GetSize(State->btstack);
  iterator->flag = Flag;
  if (Flag == BS_CONST) {
    State->cst_iterators++;
  }
#endif
  if (Flag != BS_CONST) {
    idx = symbsig[symbol_GetIndex(TopSymbol)].index;
    if (idx == -1 || Flag == BS_PUNDEF) {
      iterator->cur_cls = NULL;
    } else {
      iterator->cur_cls = (CCBS_CLASS) (Flag == BS_PFALSE ? State->pred_cls[(idx*2)+1] : State->pred_cls[(idx*2)]);
    }
  } else {
    idx = 0;
    iterator->cur_cls = (CCBS_CLASS) State->pred_cls[0];
  }
  return iterator;
}
CCBS_ITERATOR congrbs_IteratorCopy(CCBS_STATE State, CCBS_ITERATOR Iterator) {
  CCBS_ITERATOR iterator;
  iterator = memory_Malloc(State->memory, sizeof(CCBS_ITERATOR_TYPE));
  iterator->cur_cls = Iterator->cur_cls;
#ifdef SPASS_CHECK
  iterator->btstacksize = Iterator->btstacksize;
  iterator->flag = Iterator->flag;
#endif
  return iterator;
}
CCBS_CLASS congrbs_IteratorNext(CCBS_STATE State, CCBS_ITERATOR Iterator) {
  CCBS_CLASS cls;
  CCBS_CLASSINFO clsinfo;
  cls = Iterator->cur_cls;
  if (cls != NULL) {
    clsinfo = (CCBS_CLASSINFO) State->class_info[term_Index(cls)];
#ifdef SPASS_CHECK
        if (clsinfo->ineq_flag != Iterator->flag) {
          misc_StartErrorReport();
          misc_ErrorReport("\n In %s:", __func__);
          misc_ErrorReport("\n There is a literal in the list that is not equal to current flag!");
          misc_FinishErrorReport();
        }
#endif
    Iterator->cur_cls = clsinfo->nxt_pred_cls;
  }
  return cls;
}
BOOL congrbs_IteratorHasNext(CCBS_STATE State, CCBS_ITERATOR Iterator) {
#ifdef SPASS_CHECK
  if (Iterator->btstacksize != array_GetSize(State->btstack)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n Size of backtrack stack changed, Iterator most likely returns wrong items!");
    misc_FinishErrorReport();
  }
#endif
  return Iterator->cur_cls != NULL;
}
void congrbs_IteratorEnd(CCBS_STATE State, CCBS_ITERATOR Iterator) {
#ifdef SPASS_CHECK
  if (Iterator->flag == BS_CONST) {
    State->cst_iterators--;
  }
#endif
  memory_Free(State->memory, Iterator, sizeof(CCBS_ITERATOR_TYPE));
}
BOOL congrbs_CheckClauseFalseInstIntern(CCBS_STATE State, FOLSTATE Folstate, SUBSTSTATE SState, CLAUSE Clause, unsigned Idx) {
  int status;
  CCBS_CLASS cls, cls1;
  TERM term0, term1, literal, buf;
  CCBS_ITERATOR it1, it2;
  BOOL match, result;
  if (Idx >= clause_GetFolLiterals(Clause)) {
    return TRUE;
  }
  literal = (TERM) Clause[Idx];
  if (!clause_LiteralIsPositive(Clause, Idx)) {
    if (term_TopSymbol(literal) != fol_Equal(Folstate)) {
      it1 = congrbs_IteratorStart(State, term_TopSymbol(literal), BS_PTRUE);
      while (congrbs_IteratorHasNext(State, it1)) {
        cls = congrbs_IteratorNext(State, it1);
        subst_ContextStackPush(SState);
        match = congrbs_CheckMatchArgs(State, Folstate, SState, literal, cls);
        if (match) {
          result = congrbs_CheckClauseFalseInstIntern(State, Folstate, SState, Clause, Idx+1);
          if (result) {
            congrbs_IteratorEnd(State, it1);
            return result;
          } else {
            subst_ContextStackPop(SState);
          }
        } else {
          subst_ContextStackPop(SState);
        }
      }
      congrbs_IteratorEnd(State, it1);
      return FALSE;
    } else {
      term0 = term_FirstArgument(literal);
      if (term_IsVariable(State->termstate, term0) && subst_ContextValueIsMarked(SState, term_TopSymbol(term0))) {
        term0 = (TERM) subst_ContextGetValue(SState, term_TopSymbol(term0));
      }
      term1 = term_SecondArgument(literal);
      if (term_IsVariable(State->termstate, term1) && subst_ContextValueIsMarked(SState, term_TopSymbol(term1))) {
        term1 = (TERM) subst_ContextGetValue(SState, term_TopSymbol(term1));
      }
      if (!term_IsVariable(State->termstate, term0)) {
        buf = term1;
        term1 = term0;
        term0 = buf;
      }
      if (term_IsVariable(State->termstate, term0)) {
        if (term_IsVariable(State->termstate, term1)) {
          it1 = congrbs_IteratorStart(State, term_TopSymbol(literal), BS_CONST);
          while (congrbs_IteratorHasNext(State, it1)) {
            cls = congrbs_IteratorNext(State, it1);
            subst_ContextStackPush(SState);
            subst_TermMatchTermsStackFol(SState, State->symbstate, State->termstate, Folstate, term0, NULL, cls, NULL);
            subst_TermMatchTermsStackFol(SState, State->symbstate, State->termstate, Folstate, term1, NULL, cls, NULL);
            result = congrbs_CheckClauseFalseInstIntern(State, Folstate, SState, Clause, Idx+1);
            if (result) {
              congrbs_IteratorEnd(State, it1);
              return result;
            } else {
              subst_ContextStackPop(SState);
            }
          }
          congrbs_IteratorEnd(State, it1);
          return FALSE;
        } else {
          congrbs_BuildTerm(State, term1, BS_CONST);
          cls = (CCBS_CLASS) State->class[term_Index(term1)];
          subst_ContextStackPush(SState);
          subst_TermMatchTermsStackFol(SState, State->symbstate, State->termstate, Folstate, term0, NULL, cls, NULL);
          result = congrbs_CheckClauseFalseInstIntern(State, Folstate, SState, Clause, Idx+1);
          if (result) {
            return result;
          }
          subst_ContextStackPop(SState);
          return FALSE;
        }
      } else {
        congrbs_BuildTerm(State, term0, BS_CONST);
        congrbs_BuildTerm(State, term1, BS_CONST);
        if (State->class[term_Index( term1)] == State->class[term_Index( term0)]) {
          return congrbs_CheckClauseFalseInstIntern(State, Folstate, SState, Clause, Idx+1);
        } else {
          return FALSE;
        }
      }
    }
  } else {
    if (term_TopSymbol(literal) != fol_Equal(Folstate)) {
      it1 = congrbs_IteratorStart(State, term_TopSymbol(literal), BS_PFALSE);
      while (congrbs_IteratorHasNext(State, it1)) {
        cls = congrbs_IteratorNext(State, it1);
        subst_ContextStackPush(SState);
        match = congrbs_CheckMatchArgs(State, Folstate, SState, literal, cls);
        if (match) {
          result = congrbs_CheckClauseFalseInstIntern(State, Folstate, SState, Clause, Idx+1);
          if (result) {
            congrbs_IteratorEnd(State, it1);
            return result;
          } else {
            subst_ContextStackPop(SState);
          }
        } else {
          subst_ContextStackPop(SState);
        }
      }
      congrbs_IteratorEnd(State, it1);
      return FALSE;
    } else {
      term0 = term_FirstArgument(literal);
      if (term_IsVariable(State->termstate, term0) && subst_ContextValueIsMarked(SState, term_TopSymbol(term0))) {
        term0 = (TERM) subst_ContextGetValue(SState, term_TopSymbol(term0));
      }
      term1 = term_SecondArgument(literal);
      if (term_IsVariable(State->termstate, term1) && subst_ContextValueIsMarked(SState, term_TopSymbol(term1))) {
        term1 = (TERM) subst_ContextGetValue(SState, term_TopSymbol(term1));
      }
      if (!term_IsVariable(State->termstate, term0)) {
        buf = term1;
        term1 = term0;
        term0 = buf;
      }
      if (term_IsVariable(State->termstate, term0)) {
        if (term_IsVariable(State->termstate, term1)) {
          it1 = congrbs_IteratorStart(State, term_TopSymbol(literal), BS_CONST);
          while (congrbs_IteratorHasNext(State, it1)) {
            cls = congrbs_IteratorNext(State, it1);
            it2 = congrbs_IteratorCopy(State, it1);
            while (congrbs_IteratorHasNext(State, it2)) {
              cls1 = congrbs_IteratorNext(State, it2);
              congrbs_BacktrackPush(State);
              status = congrbs_AssertEqualConst(State, cls, cls1, (CCBS_LABEL) NULL);
              if (status == false) {
                congrbs_BacktrackPop(State);
                subst_ContextStackPush(SState);
                subst_TermMatchTermsStackFol(SState, State->symbstate, State->termstate, Folstate, term0, NULL, cls, NULL);
                subst_TermMatchTermsStackFol(SState, State->symbstate, State->termstate, Folstate, term1, NULL, cls1, NULL);
                result = congrbs_CheckClauseFalseInstIntern(State, Folstate, SState, Clause, Idx+1);
                if (result) {
                  congrbs_IteratorEnd(State, it1);
                  congrbs_IteratorEnd(State, it2);
                  return result;
                } else {
                  subst_ContextStackPop(SState);
                }
              } else {
                congrbs_BacktrackPop(State);
              }
            }
            congrbs_IteratorEnd(State, it2);
          }
          congrbs_IteratorEnd(State, it1);
          return FALSE;
        } else {
          congrbs_BuildTerm(State, term1, BS_CONST);
          cls1 = (CCBS_CLASS) State->class[term_Index( term1)];
          it1 = congrbs_IteratorStart(State, term_TopSymbol(literal), BS_CONST);
          while (congrbs_IteratorHasNext(State, it1)) {
            cls = congrbs_IteratorNext(State, it1);
            congrbs_BacktrackPush(State);
            status = congrbs_AssertEqualConst(State, cls, cls1, (CCBS_LABEL) NULL);
            if (status == false) {
              congrbs_BacktrackPop(State);
              subst_ContextStackPush(SState);
              subst_TermMatchTermsStackFol(SState, State->symbstate, State->termstate, Folstate, term0, NULL, cls, NULL);
              result = congrbs_CheckClauseFalseInstIntern(State, Folstate, SState, Clause, Idx+1);
              if (result) {
                congrbs_IteratorEnd(State, it1);
                return result;
              } else {
                subst_ContextStackPop(SState);
              }
            } else {
              congrbs_BacktrackPop(State);
            }
          }
          congrbs_IteratorEnd(State, it1);
          return FALSE;
        }
      } else {
        congrbs_BacktrackPush(State);
        status = congrbs_AssertEqualConst(State, term0, term1, (CCBS_LABEL) NULL);
        if (status == false) {
          congrbs_BacktrackPop(State);
          return congrbs_CheckClauseFalseInstIntern(State, Folstate, SState, Clause, Idx+1);
        }
        congrbs_BacktrackPop(State);
        return FALSE;
      }
    }
  }
#ifdef SPASS_CHECK
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n This point should never be reached.");
    misc_FinishErrorReport();
#endif
  return FALSE;
}
SUBST congrbs_CheckClauseFalseInst(CCBS_STATE State, FOLSTATE Folstate, SUBSTSTATE SState, CLAUSE Clause) {
  SUBST subst;
  BOOL found_matcher;
  if (State->status == false) {
    return NULL;
  }
  subst_ContextStart(SState, State->symbstate);
  subst_ContextStackStart(SState);
  found_matcher = congrbs_CheckClauseFalseInstIntern(State, Folstate, SState, Clause, 0);
#ifdef SPASS_CHECK
  if (State->status == FALSE) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n This point should never be reached.");
    misc_FinishErrorReport();
  }
#endif
  if (found_matcher) {
    subst_ContextFlattenTerms(SState, State->symbstate, subst_MaxVars(SState));
    subst = subst_ContextExtractSubst(SState, State->termstate, State->symbstate, subst_MaxVars(SState));
    subst_ContextStackStop(SState);
    subst_ContextStop(SState);
    return subst;
  }
  subst_ContextStackStop(SState);
  subst_ContextStop(SState);
  return NULL;
}
CLAUSE congrbs_CreateClauseFromConflict(CCBS_STATE State, unsigned Id) {
  CLAUSE new;
  array_SetSize(State->cons, 0);
  array_SetSize(State->conc, 0);
#ifdef SPASS_CHECK
  if (State->status != FALSE) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n This point should never be reached.");
    misc_FinishErrorReport();
  }
#endif
  congrbs_ExploreConflict(State);
  if (symbol_IsPredicate(term_TopSymbol(State->conflict->term[0]))) {
    State->conc = array_Add(State->memory, State->conc, (intptr_t) State->conflict->term[1]);
    State->confl_labels = array_Add(State->memory, State->confl_labels, (intptr_t) State->conflict->term[0]);
  } else {
    State->conc = array_Add(State->memory, State->conc, (intptr_t) State->conflict->label);
  }
  new = clause_CreateFromLiterals(State->memory, State->cons, State->conc, State->confl_labels, FALSE, Id);
  return new;
}
CLAUSE congrbs_CreateClauseFromConflictClause(CCBS_STATE State, SHARER Sharer, FOLSTATE Folstate, CLAUSE Clause, SUBST Subst, unsigned Id) {
  TERM literal;
  CLAUSE result;
  unsigned i;
#ifdef SPASS_CHECK
  if (State->status == FALSE) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n CC must be in consistent state!");
    misc_FinishErrorReport();
  }
#endif
  array_SetSize(State->cons, 0);
  array_SetSize(State->conc, 0);
  array_SetSize(State->prem, 0);
  for (i = 0; i < clause_GetFolLiterals(Clause); i++) {
    literal = (TERM) Clause[i];
    literal = subst_SubstApplyTerm(State->termstate, term_Copy(State->termstate, literal), Subst, TRUE);
    literal = sharing_GetSharedTerm(Sharer, literal);
    congrbs_BacktrackPush(State);
    congrbs_AssertLiteral(State, literal, Folstate, clause_LiteralIsPositive(Clause, i));
#ifdef SPASS_CHECK
    if (State->status) {
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s:", __func__);
      misc_ErrorReport("\n Assumed a false instance of clause here!");
      misc_FinishErrorReport();
    }
#endif
    congrbs_ExploreConflict(State);
    if (term_TopSymbol(literal) == fol_Equal(Folstate)) {
      if (clause_LiteralIsPositive(Clause, i)) {
        array_PointerRemoveElement(State->confl_labels, (intptr_t) literal);
        if (symbol_IsPredicate(term_TopSymbol(State->conflict->term[0]))) {
          State->conc = array_Add(State->memory, State->conc, (intptr_t) State->conflict->term[1]);
          State->confl_labels = array_Add(State->memory, State->confl_labels, (intptr_t) State->conflict->term[0]);
        } else {
          State->conc = array_Add(State->memory, State->conc, (intptr_t) State->conflict->label);
        }
      }
    } else {
      if (clause_LiteralIsPositive(Clause, i)) {
        State->conc = array_Add(State->memory, State->conc, (intptr_t) State->conflict->term[1]);
      } else {
        State->confl_labels = array_Add(State->memory, State->confl_labels, (intptr_t) State->conflict->term[0]);
      }
    }
    State->prem = array_Append(State->memory, State->prem, State->confl_labels);
    congrbs_BacktrackPop(State);
#ifdef SPASS_CHECK
    if (State->status == FALSE) {
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s:", __func__);
      misc_ErrorReport("\n CC must be in consistent state!");
      misc_FinishErrorReport();
    }
#endif
  }
  State->conc = array_RemoveDuplicates(State->memory, State->conc, &misc_PtrEqual);
  State->prem = array_RemoveDuplicates(State->memory, State->prem, &misc_PtrEqual);
  result = clause_CreateFromLiterals(State->memory, State->cons, State->conc, State->prem, FALSE, Id);
  return result;
}
CLAUSE congrbs_AssertArrayCheckConflict(CCBS_STATE State, FOLSTATE Folstate, ARRAY Positive, ARRAY Negative) {
  BOOL state;
  unsigned i;
  CLAUSE result;
#ifdef SPASS_CHECK
  if (State->status == FALSE) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In %s:", __func__);
    misc_ErrorReport("\n CC must be in consistent state!");
    misc_FinishErrorReport();
  }
#endif
  congrbs_BacktrackPush(State);
  for (i = 0; i < array_GetSize(Positive); i++) {
    state = congrbs_AssertLiteral(State, (TERM) array_GetElement(Positive, i), Folstate, TRUE);
    if (!state) {
      result = congrbs_CreateClauseFromConflict(State, 1);
      congrbs_BacktrackPop(State);
      return result;
    }
  }
  for (i = 0; i < array_GetSize(Negative); i++) {
    state = congrbs_AssertLiteral(State, (TERM)
      array_GetElement(Negative, i), Folstate, FALSE);
    if (!state) {
      result = congrbs_CreateClauseFromConflict(State, 1);
      congrbs_BacktrackPop(State);
      return result;
    }
  }
  congrbs_BacktrackPop(State);
  return NULL;
}
BOOL congrbs_AssertLiteral(CCBS_STATE State, TERM Atom, FOLSTATE Folstate, BOOL IsPositive) {
  BOOL result;
  if (IsPositive) {
    if (term_TopSymbol(Atom) != fol_Equal(Folstate)) {
      result = congrbs_AssertEqualBSPred(State, Atom, (CCBS_LABEL) Atom);
    } else {
      result = congrbs_AssertEqualConst(State, term_FirstArgument(Atom), term_SecondArgument(Atom), (CCBS_LABEL) Atom);
    }
  } else {
    if (term_TopSymbol(Atom) != fol_Equal(Folstate)) {
      result = congrbs_AssertNotEqualBSPred(State, Atom, (CCBS_LABEL) Atom);
    } else {
      result = congrbs_AssertNotEqualConst(State, term_FirstArgument(Atom), term_SecondArgument(Atom), (CCBS_LABEL) Atom);
    }
  }
  return result;
}
