#ifdef DOC_BUILD_INTERNAL
#endif
#include "fcnf.h"
int fcnf_ParseSkolemOption(const char *Param)
{
  int level;
  Param += strlen(FCNF_SKOLEM_LEVEL_PREFIX);
  if (strlen(Param) < 5 && string_StringIsNatural(Param)) {
    level = atoi(Param);
    switch (level) {
    case FCNF_SKOLEM_LEVEL_OUTER:
    case FCNF_SKOLEM_LEVEL_INNER:
      return level;
    }
  }
  return FCNF_SKOLEM_LEVEL_DEFAULT;
}
static void fcnf_MarkPrefixNumerals(ARRAY Arr, const char *Pre, const char *Str, intptr_t Mask)
{
  unsigned i, n;
  if (Str == NULL || !string_IsPrefix(Pre, Str)) return;
  for (n = 0, i = strlen(Pre); n < array_GetSize(Arr); ++i) {
    Arr[n] |= Mask;
    if ('0' <= Str[i] && Str[i] <= '9') {
      n = 10 * n + (Str[i] - '0');
    }
    else return;
  }
}
FCNFSTATE fcnf_Init(SCLSTATE State)
{
  FCNFSTATE fcnfstate;
  FOLSTATE folstate;
  SYMBSTATE symbstate;
  MEMORY memory;
  SYMBSIG symbsig;
  unsigned i, sigLength;
  char *num;
  ARRAY usedPrefixes;
  folstate = state_GetFolstate(State);
  memory = fol_GetMemory(folstate);
  fcnfstate = (FCNFSTATE)memory_Malloc(memory, sizeof(FCNFSTATE_NODE));
  fcnfstate->sclstate = State;
  symbstate = fcnf_GetSymbstate(fcnfstate);
  symbsig = symbol_GetStateSig(symbstate);
  sigLength = symbol_GetStateSigLength(symbstate);
  fcnfstate->renamingCounter = 1;
  fcnfstate->skolemCounter = 1;
  usedPrefixes = array_Create(memory, sigLength);
  array_SetSize(usedPrefixes, sigLength);
  for (i = 0; i < sigLength; ++i) {
    fcnf_MarkPrefixNumerals(usedPrefixes, "ren", symbsig[i].name, 0x01);
    fcnf_MarkPrefixNumerals(usedPrefixes, "sk", symbsig[i].name, 0x02);
    fcnf_MarkPrefixNumerals(usedPrefixes, "skf", symbsig[i].name, 0x04);
    fcnf_MarkPrefixNumerals(usedPrefixes, "skc", symbsig[i].name, 0x08);
  }
  for (i = 0; i < sigLength && usedPrefixes[i]; ++i) {};
  num = (i ? string_IntToString(memory, i) : string_StringCopy(memory, ""));
  fcnfstate->renamingPrefix = string_Conc(memory, "ren", num);
  fcnfstate->skolemFuncPrefix = string_Conc(memory, "skf", num);
  fcnfstate->skolemConstPrefix = string_Conc(memory, "skc", num);
  string_StringFree(memory, num);
  array_Clean(usedPrefixes);
  fcnfstate->list1 = usedPrefixes;
  fcnfstate->list2 = array_Create(memory, 6);
  fcnfstate->bindArr = array_Create(memory, 6);
  fcnfstate->arrIn = array_Create(memory, 6);
  fcnfstate->arrOut = array_Create(memory, 6);
  fcnfstate->skolemDerivOutputArray = array_Create(memory, 6);
  for (i = 0; i < (unsigned)symbol_GetMaxVars(symbstate); ++i) {
    symbol_SetBindingMark(symbstate, i, 0);
    symbol_SetBindingValue(symbstate, i, 0);
  }
  symbstate->bindmark = 0;
  return fcnfstate;
}
SCLSTATE fcnf_GetSclstate(FCNFSTATE Fcnfstate)
{
  return Fcnfstate->sclstate;
}
TPTPSTATE fcnf_GetTptpstate(FCNFSTATE Fcnfstate)
{
  return state_GetTptpstate(fcnf_GetSclstate(Fcnfstate));
}
FOLSTATE fcnf_GetFolstate(FCNFSTATE Fcnfstate)
{
  return state_GetFolstate(fcnf_GetSclstate(Fcnfstate));
}
TERMSTATE fcnf_GetTermstate(FCNFSTATE Fcnfstate)
{
  return fol_GetTermstate(fcnf_GetFolstate(Fcnfstate));
}
MEMORY fcnf_GetMemory(FCNFSTATE Fcnfstate)
{
  return state_GetMemory(fcnf_GetSclstate(Fcnfstate));
}
SYMBSTATE fcnf_GetSymbstate(FCNFSTATE Fcnfstate)
{
  return fol_GetSymbstate(fcnf_GetFolstate(Fcnfstate));
}
FILE* fcnf_GetDerivationFile(FCNFSTATE Fcnfstate)
{
  return stdout;
  return NULL;
}
char* fcnf_GetNextRenamingName(FCNFSTATE Fcnfstate)
{
  MEMORY memory;
  char *num, *name;
  memory = fcnf_GetMemory(Fcnfstate);
  num = string_IntToString(memory, Fcnfstate->renamingCounter++);
  name = string_Conc(memory, Fcnfstate->renamingPrefix, num);
  string_StringFree(memory, num);
  return name;
}
void fcnf_AddOutput(FCNFSTATE Fcnfstate, intptr_t Val)
{
  Fcnfstate->arrOut = array_Add(fcnf_GetMemory(Fcnfstate), Fcnfstate->arrOut, Val);
}
void fcnf_SwapInOut(FCNFSTATE Fcnfstate)
{
  ARRAY arr;
  arr = Fcnfstate->arrIn;
  Fcnfstate->arrIn = Fcnfstate->arrOut;
  Fcnfstate->arrOut = arr;
}
void fcnf_Free(FCNFSTATE Fcnfstate)
{
  MEMORY memory;
  unsigned i;
  memory = fcnf_GetMemory(Fcnfstate);
  string_StringFree(memory, Fcnfstate->renamingPrefix);
  string_StringFree(memory, Fcnfstate->skolemFuncPrefix);
  string_StringFree(memory, Fcnfstate->skolemConstPrefix);
  for (i=0; i<array_GetSize(Fcnfstate->bindArr); ++i) {
    array_Delete(memory, (ARRAY)array_GetElement(Fcnfstate->bindArr, i));
  }
  array_Delete(memory, Fcnfstate->bindArr);
  array_Delete(memory, Fcnfstate->list1);
  array_Delete(memory, Fcnfstate->list2);
  array_Delete(memory, Fcnfstate->arrIn);
  array_Delete(memory, Fcnfstate->arrOut);
  array_Delete(memory, Fcnfstate->skolemDerivOutputArray);
  memory_Free(memory, Fcnfstate, sizeof(FCNFSTATE_NODE));
}
static void fcnf_RenameVariablesRecurse(FOLSTATE Folstate, TERM Term)
{
  unsigned i;
  NAT var, old, new;
  TERMSTATE termstate;
  SYMBSTATE symbstate;
  termstate = fol_GetTermstate(Folstate);
  symbstate = term_GetSymbstate(termstate);
  if (fol_IsQuantifier(Folstate, Term)) {
    var = term_TopSymbol(term_FirstArgument(Term));
    old = (NAT)symbol_BindingValue(symbstate, var);
    new = symbol_GetNextStandardVar(symbstate);
    symbol_SetBindingValue(symbstate, var, new);
    term_RplacTop(term_FirstArgument(Term), new);
    fcnf_RenameVariablesRecurse(Folstate, term_SecondArgument(Term));
    symbol_SetBindingValue(symbstate, var, old);
  }
  else if (term_IsVariable(termstate, Term)) {
    var = (NAT)term_TopSymbol(Term);
    new = (NAT)symbol_BindingValue(symbstate, var);
    term_RplacTop(Term, new);
  }
  else {
    for (i = 0; i < term_GetArity(Term); i++) {
      fcnf_RenameVariablesRecurse(Folstate, term_GetArgument(Term, i));
    }
  }
}
static void fcnf_RenameVariables(FCNFSTATE Fcnfstate, TERM Term)
{
  FOLSTATE folstate;
  SYMBSTATE symbstate;
  MEMORY memory;
  unsigned i, maxV;
  folstate = fcnf_GetFolstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  memory = fcnf_GetMemory(Fcnfstate);
  symbol_StartBinding(symbstate);
  symbol_SetStandardVarCounter(symbstate, 1);
  fcnf_RenameVariablesRecurse(folstate, Term);
  symbol_StopBinding(symbstate);
  maxV = symbol_GetStandardVarCounter(symbstate);
  for (i=0; i<maxV; ++i) {
    symbol_SetBindingValue(symbstate, i, 0);
  }
  Fcnfstate->list1 = array_Reserve(memory, Fcnfstate->list1, maxV+1);
  Fcnfstate->list2 = array_Reserve(memory, Fcnfstate->list2, maxV+1);
  while (array_GetSize(Fcnfstate->bindArr) < maxV) {
    Fcnfstate->bindArr = array_Add(memory, Fcnfstate->bindArr,
                                   (intptr_t)array_Create(memory, 6));
  }
}
static TERM fcnf_ElimTB(FOLSTATE Folstate, TERM Term)
{
  TERMSTATE termstate;
  unsigned i, j;
  TERM simpler;
  BOOL argTrue, argFalse, clauseCollapses;
  termstate = fol_GetTermstate(Folstate);
  if (!fol_IsAtom(Folstate, Term)) {
    i = (fol_IsQuantifier(Folstate, Term) ? 1 : 0);
    for (; i < term_GetArity(Term); ++i) {
      simpler = fcnf_ElimTB(Folstate, term_GetArgument(Term, i));
      term_SetArgument(Term, i, simpler);
    }
    if (fol_IsQuantifier(Folstate, Term)) {
#ifdef SPASS_CHECK
      if (2 != term_GetArity(Term)) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s: quantifier of arity != 2", __func__);
        misc_FinishErrorReport();
      }
#endif
      simpler = term_GetArgument(Term, 1);
      if (fol_IsTrue(Folstate, simpler)
          || fol_IsFalse(Folstate, simpler)) {
        term_Free(termstate, term_GetArgument(Term, 0));
        term_Free(termstate, Term);
        Term = simpler;
      }
    }
    else if (fol_IsOr(Folstate, Term) || fol_IsAnd(Folstate, Term)) {
      j = 0;
      clauseCollapses = FALSE;
      for (i = 0; !clauseCollapses && i < term_GetArity(Term); ++i) {
        argTrue = fol_IsTrue(Folstate, term_GetArgument(Term, i));
        argFalse = fol_IsFalse(Folstate, term_GetArgument(Term, i));
        if ((argTrue && fol_IsOr(Folstate, Term))
            || (argFalse && fol_IsAnd(Folstate, Term))) {
          j = 0;
          clauseCollapses = TRUE;
        }
        else if (!(argTrue || argFalse)) {
          term_SwapArguments(Term, i, j);
          ++j;
        }
      }
      for (i = j; i < term_GetArity(Term); ++i) {
        term_Delete(termstate, term_GetArgument(Term, i));
      }
      if (j == 1) {
        simpler = term_GetArgument(Term, 0);
        term_Free(termstate, Term);
        Term = simpler;
      }
      else {
        if (clauseCollapses) {
          term_RplacTop(Term, fol_IsOr(Folstate, Term) ? fol_True(Folstate) : fol_False(Folstate));
        }
        else if (j == 0) {
          term_RplacTop(Term, fol_IsAnd(Folstate, Term) ? fol_True(Folstate) : fol_False(Folstate));
        }
        term_SetArity(Term, j);
      }
    }
    else if (fol_IsImplies(Folstate, Term)) {
      if (fol_IsFalse(Folstate, term_GetArgument(Term, 1))) {
        term_Free(termstate, term_GetArgument(Term, 1));
        term_SetArity(Term, 1);
        term_RplacTop(Term, fol_Not(Folstate));
      }
      else if (fol_IsFalse(Folstate, term_GetArgument(Term, 0))) {
        term_Delete(termstate, term_GetArgument(Term, 1));
        simpler = term_GetArgument(Term, 0);
        term_Free(termstate, Term);
        Term = simpler;
        term_RplacTop(Term, fol_True(Folstate));
      }
      else if (fol_IsTrue(Folstate, term_GetArgument(Term, 1))) {
        term_Delete(termstate, term_GetArgument(Term, 0));
        simpler = term_GetArgument(Term, 1);
        term_Free(termstate, Term);
        Term = simpler;
      }
      else if (fol_IsTrue(Folstate, term_GetArgument(Term, 0))) {
        term_Free(termstate, term_GetArgument(Term, 0));
        simpler = term_GetArgument(Term, 1);
        term_Free(termstate, Term);
        Term = simpler;
      }
    }
    else if (fol_IsEquiv(Folstate, Term)) {
#ifdef SPASS_CHECK
      if (2 != term_GetArity(Term)) {
        misc_StartErrorReport();
        misc_ErrorReport("\n In %s: equivalence of arity != 2 not implemented", __func__);
        misc_FinishErrorReport();
      }
#endif
      if (fol_IsTrue(Folstate, term_GetArgument(Term, 0))
          || fol_IsFalse(Folstate, term_GetArgument(Term, 0))) {
        term_SwapArguments(Term, 0, 1);
      }
      if (fol_IsTrue(Folstate, term_GetArgument(Term, 1))) {
        term_Free(termstate, term_GetArgument(Term, 1));
        simpler = term_GetArgument(Term, 0);
        term_Free(termstate, Term);
        Term = simpler;
      }
      else if (fol_IsFalse(Folstate, term_GetArgument(Term, 1))) {
        term_Free(termstate, term_GetArgument(Term, 1));
        term_SetArity(Term, 1);
        term_RplacTop(Term, fol_Not(Folstate));
      }
    }
    else if (fol_IsNot(Folstate, Term)) {
      simpler = term_GetArgument(Term, 0);
      if (fol_IsTrue(Folstate, simpler)) {
        term_Free(termstate, Term);
        Term = simpler;
        term_RplacTop(Term, fol_False(Folstate));
      }
      else if (fol_IsFalse(Folstate, simpler)) {
        term_Free(termstate, Term);
        Term = simpler;
        term_RplacTop(Term, fol_True(Folstate));
      }
    }
    else if (!fol_IsTrue(Folstate, Term) && !fol_IsFalse(Folstate, Term)) {
#ifdef SPASS_CHECK
      printf("\n");
      term_PrintPrefix(termstate, Term);
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s: other complex term with IsAtom %i and fol_IsLiteral %i: ",
                       __func__,
                       (int)fol_IsAtom(Folstate, Term),
                       (int)fol_IsLiteral(Folstate, Term));
      misc_FinishErrorReport();
#endif
    }
  }
  return Term;
}
static TERM fcnf_ElimImp(FOLSTATE Folstate, TERM Term)
{
  unsigned i;
  TERM simpler;
  if (!fol_IsAtom(Folstate, Term)) {
    for (i = 0; i < term_GetArity(Term); ++i) {
      simpler = fcnf_ElimImp(Folstate, term_GetArgument(Term, i));
      term_SetArgument(Term, i, simpler);
    }
    if (fol_IsImplies(Folstate, Term)) {
      simpler = fol_NegateToggle(Folstate, term_GetArgument(Term, 0));
      term_SetArgument(Term, 0, simpler);
      term_RplacTop(Term, fol_Or(Folstate));
    }
  }
  return Term;
}
static TERM fcnf_ElimEquiv(FOLSTATE Folstate, TERM Term, short Pol)
{
  TERMSTATE termstate;
  unsigned i;
  TERM phi, psi, phi1, psi1, phi2, psi2;
  termstate = fol_GetTermstate(Folstate);
  if (!fol_IsAtom(Folstate, Term)) {
    if (fol_IsAnd(Folstate, Term)
        || fol_IsOr(Folstate, Term)
        || fol_IsQuantifier(Folstate, Term)) {
      i = (fol_IsQuantifier(Folstate, Term) ? 1 : 0);
      for (; i < term_GetArity(Term); ++i) {
        phi = fcnf_ElimEquiv(Folstate, term_GetArgument(Term, i), Pol);
        term_SetArgument(Term, i, phi);
      }
    }
    else if (fol_IsNot(Folstate, Term)) {
      phi = fcnf_ElimEquiv(Folstate, term_GetArgument(Term, 0), -Pol);
      term_SetArgument(Term, 0, phi);
    }
    else if (fol_IsEquiv(Folstate, Term)) {
      phi1 = term_GetArgument(Term, 0);
      psi1 = term_GetArgument(Term, 1);
      phi2 = term_Copy(termstate, phi1);
      psi2 = term_Copy(termstate, psi1);
      if (Pol >= 0) {
        term_RplacTop(Term, fol_And(Folstate));
        phi = term_CreateArity(termstate, fol_Or(Folstate), 2);
        psi = term_CreateArity(termstate, fol_Or(Folstate), 2);
        term_SetArgument(phi, 0, fol_NegateToggle(Folstate, phi1));
        term_SetArgument(phi, 1, psi1);
        term_SetArgument(psi, 0, fol_NegateToggle(Folstate, psi2));
        term_SetArgument(psi, 1, phi2);
      }
      else {
        term_RplacTop(Term, fol_Or(Folstate));
        phi = term_CreateArity(termstate, fol_And(Folstate), 2);
        psi = term_CreateArity(termstate, fol_And(Folstate), 2);
        term_SetArgument(phi, 0, phi1);
        term_SetArgument(phi, 1, psi1);
        term_SetArgument(psi, 0, fol_NegateToggle(Folstate, phi2));
        term_SetArgument(psi, 1, fol_NegateToggle(Folstate, psi2));
      }
      term_SetArgument(Term, 0, phi);
      term_SetArgument(Term, 1, psi);
      Term = fcnf_ElimEquiv(Folstate, Term, Pol);
    }
    else if (!fol_IsTrue(Folstate, Term) && !fol_IsFalse(Folstate, Term)) {
#ifdef SPASS_CHECK
      term_PrintPrefix(termstate, Term);
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s: unexpected term found in ElimEquiv: \n", __func__);
      misc_FinishErrorReport();
#endif
    }
  }
  return Term;
}
static TERM fcnf_PushNeg(FOLSTATE Folstate, TERM Term, short Pol)
{
  TERMSTATE termstate;
  unsigned i;
  TERM phi;
  termstate = fol_GetTermstate(Folstate);
  if (fol_IsLiteral(Folstate, Term)) {
    if (Pol < 0) {
      Term = fol_NegateToggle(Folstate, Term);
    }
  }
  else {
    if (fol_IsNot(Folstate, Term)) {
      phi = fcnf_PushNeg(Folstate, term_GetArgument(Term, 0), -Pol);
      term_Free(termstate, Term);
      Term = phi;
    }
    else {
      i = (fol_IsQuantifier(Folstate, Term) ? 1 : 0);
      if (Pol < 0 && fol_IsAnd(Folstate, Term)) {
        term_RplacTop(Term, fol_Or(Folstate));
      }
      else if (Pol < 0 && fol_IsOr(Folstate, Term)) {
        term_RplacTop(Term, fol_And(Folstate));
      }
      else if (Pol < 0 && fol_IsExist(Folstate, Term)) {
        term_RplacTop(Term, fol_Forall(Folstate));
      }
      else if (Pol < 0 && fol_IsForall(Folstate, Term)) {
        term_RplacTop(Term, fol_Exist(Folstate));
      }
      for (; i < term_GetArity(Term); ++i) {
        phi = fcnf_PushNeg(Folstate, term_GetArgument(Term, i), Pol);
        term_SetArgument(Term, i, phi);
      }
    }
  }
  return Term;
}
static ARRAY fcnf_ListObviousPositionsRecurse(FOLSTATE Folstate,
                                              TERM Term, TERM Super, NAT Idx,
                                              short Pol,
                                              BOOL FlagObv1, BOOL FlagObv2,
                                              ARRAY Arr)
{
  MEMORY memory;
  unsigned i;
  BOOL conjunctive, disjunctive;
  unsigned obvious;
  memory = fol_GetMemory(Folstate);
  conjunctive = disjunctive = FALSE;
  if (fol_IsAnd(Folstate, Term)) {
    if (Pol >= 0) conjunctive = TRUE;
    if (Pol <= 0) disjunctive = TRUE;
  }
  if (fol_IsOr(Folstate, Term) ||
      fol_IsImplies(Folstate, Term)) {
    if (Pol <= 0) conjunctive = TRUE;
    if (Pol >= 0) disjunctive = TRUE;
  }
  if (fol_IsEquiv(Folstate, Term) && FlagObv1) {
    obvious = 1;
  }
  else if (conjunctive && FlagObv2) {
    obvious = 2;
  }
  else {
    obvious = 0;
  }
  FlagObv1 = FlagObv1 || disjunctive || fol_IsEquiv(Folstate, Term);
  if (conjunctive) FlagObv2 = FALSE;
  if (disjunctive) FlagObv2 = TRUE;
  if (!fol_IsAtom(Folstate, Term)) {
    if (fol_IsQuantifier(Folstate, Term)) {
      Arr = fcnf_ListObviousPositionsRecurse(Folstate, term_GetArgument(Term, 1), Term, 1,
                                             Pol, FlagObv1, FlagObv2, Arr);
    }
    else if (fol_IsNot(Folstate, Term)) {
      Arr = fcnf_ListObviousPositionsRecurse(Folstate, term_GetArgument(Term, 0), Term, 0,
                                             -Pol, FlagObv1, FlagObv2, Arr);
    }
    else if (fol_IsImplies(Folstate, Term)) {
      Arr = fcnf_ListObviousPositionsRecurse(Folstate, term_GetArgument(Term, 0), Term, 0,
                                             -Pol, FlagObv1, FlagObv2, Arr);
      Arr = fcnf_ListObviousPositionsRecurse(Folstate, term_GetArgument(Term, 1), Term, 1,
                                             Pol, FlagObv1, FlagObv2, Arr);
    }
    else {
      if (fol_IsEquiv(Folstate, Term)) {
        Pol = 0;
      }
      for (i = 0; i < term_GetArity(Term); ++i) {
        Arr = fcnf_ListObviousPositionsRecurse(Folstate, term_GetArgument(Term, i), Term, i,
                                               Pol, FlagObv1, FlagObv2, Arr);
      }
    }
  }
  if (obvious) {
#ifdef SPASS_CHECK
    if (Term != term_GetArgument(Super, Idx)) {
      misc_StartErrorReport();
      misc_ErrorReport("\n In %s: Sanity check failed: term to list is not super[idx]", __func__);
      misc_FinishErrorReport();
    }
#endif
    Arr = array_Add(memory, Arr, (intptr_t)Super);
    Arr = array_Add(memory, Arr, (intptr_t)Idx);
    Arr = array_Add(memory, Arr, (intptr_t)Pol);
  }
  return Arr;
}
static ARRAY fcnf_ListObviousPositions(FOLSTATE Folstate, TERM Term, ARRAY Positions)
{
  Positions = fcnf_ListObviousPositionsRecurse(Folstate, Term,
                                               NULL, 0,
                                               1,
                                               FALSE, FALSE,
                                               Positions);
  return Positions;
}
static ARRAY fcnf_UsedVarArrayRecurse(TERMSTATE Termstate, TERM Term, NAT Mark, ARRAY Arr)
{
  SYMBSTATE symbstate;
  MEMORY memory;
  SYMBOL var;
  unsigned i;
  symbstate = term_GetSymbstate(Termstate);
  memory = term_GetMemory(Termstate);
  if (term_IsComplex(Term)) {
    for (i = 0; i < term_GetArity(Term); ++i) {
      Arr = fcnf_UsedVarArrayRecurse(Termstate, term_GetArgument(Term, i), Mark, Arr);
    }
  }
  else if (term_IsVariable(Termstate, Term)) {
    var = term_TopSymbol(Term);
    if (!symbol_VarIsMarked(symbstate, var, Mark)) {
      symbol_SetBindingMark(symbstate, var, Mark);
      Arr = array_Add(memory, Arr, var);
    }
  }
  return Arr;
}
ARRAY fcnf_UsedVarArray(TERMSTATE Termstate, TERM Term)
{
  SYMBSTATE symbstate;
  MEMORY memory;
  ARRAY arr;
  NAT mark;
  symbstate = term_GetSymbstate(Termstate);
  memory = term_GetMemory(Termstate);
  symbol_StartBinding(symbstate);
  mark = symbol_NewMark(symbstate);
  arr = array_Create(memory, 4);
  arr = fcnf_UsedVarArrayRecurse(Termstate, Term, mark, arr);
  symbol_StopBinding(symbstate);
  return arr;
}
static ARRAY fcnf_FreeVarArrayRecurse(FOLSTATE Folstate, TERM Term, NAT Mark, ARRAY Arr)
{
  TERMSTATE termstate;
  SYMBSTATE symbstate;
  MEMORY memory;
  SYMBOL var;
  unsigned i;
  termstate = fol_GetTermstate(Folstate);
  symbstate = fol_GetSymbstate(Folstate);
  memory = fol_GetMemory(Folstate);
  if (term_IsComplex(Term)) {
    if (fol_IsQuantifier(Folstate, Term)) {
      var = term_TopSymbol(term_FirstArgument(Term));
      symbol_SetBindingMark(symbstate, var, Mark);
      Arr = fcnf_FreeVarArrayRecurse(Folstate, term_SecondArgument(Term), Mark, Arr);
    }
    else {
      for (i = 0; i < term_GetArity(Term); ++i) {
        Arr = fcnf_FreeVarArrayRecurse(Folstate, term_GetArgument(Term, i), Mark, Arr);
      }
    }
  }
  else if (term_IsVariable(termstate, Term)) {
    var = term_TopSymbol(Term);
    if (!symbol_VarIsMarked(symbstate, var, Mark)) {
      Arr = array_Add(memory, Arr, var);
      symbol_SetBindingMark(symbstate, var, Mark);
    }
  }
  return Arr;
}
ARRAY fcnf_FreeVarArray(FOLSTATE Folstate, TERM Term)
{
  SYMBSTATE symbstate;
  MEMORY memory;
  ARRAY arr;
  NAT mark;
  symbstate = fol_GetSymbstate(Folstate);
  memory = fol_GetMemory(Folstate);
  symbol_StartBinding(symbstate);
  mark = symbol_NewMark(symbstate);
  arr = array_Create(memory, 4);
  arr = fcnf_FreeVarArrayRecurse(Folstate, Term, mark, arr);
  symbol_StopBinding(symbstate);
  return arr;
}
static void fcnf_PrintVarArray(SYMBSTATE Symbstate, ARRAY Arr)
{
  unsigned i;
  for (i = 0; i < array_GetSize(Arr); ++i) {
    symbol_Print(Symbstate, (SYMBOL)array_GetElement(Arr, i));
    printf(" ");
  }
}
static void fcnf_PrintFreeVars(FOLSTATE Folstate, TERM Term)
{
  MEMORY memory;
  ARRAY arr;
  memory = fol_GetMemory(Folstate);
  arr = fcnf_FreeVarArray(Folstate, Term);
  fcnf_PrintVarArray(term_GetSymbstate(fol_GetTermstate(Folstate)), arr);
  array_Delete(memory, arr);
}
static void fcnf_PrintUsedVars(TERMSTATE Termstate, TERM Term)
{
  MEMORY memory;
  ARRAY arr;
  memory = term_GetMemory(Termstate);
  arr = fcnf_UsedVarArray(Termstate, Term);
  fcnf_PrintVarArray(term_GetSymbstate(Termstate), arr);
  array_Delete(memory, arr);
}
static TERM fcnf_RenameDef(FCNFSTATE Fcnfstate, TERM Super, NAT Idx,
                           short Pol, const char *Name)
{
  SCLSTATE sclstate;
  FOLSTATE folstate;
  TERMSTATE termstate;
  SYMBSTATE symbstate;
  MEMORY memory;
  TERM term, predTerm1, predTerm2, newRule, phi;
  ARRAY freeVars;
  SYMBOL predSymb, var;
  unsigned i;
  sclstate = fcnf_GetSclstate(Fcnfstate);
  folstate = fcnf_GetFolstate(Fcnfstate);
  termstate = fcnf_GetTermstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  memory = fcnf_GetMemory(Fcnfstate);
  term = term_GetArgument(Super, Idx);
  freeVars = fcnf_FreeVarArray(folstate, term);
  predSymb = symbol_CreatePredicate(symbstate, fol_TypeBool(folstate),
                                     Name, array_GetSize(freeVars));
  for (i=0;i<array_GetSize(freeVars);i++)
    symbol_SetArgumentType(symbstate, predSymb, fol_TypeTop(folstate), i);
  state_AddPredicate(sclstate, predSymb);
  predTerm1 = term_CreateArity(termstate, predSymb, array_GetSize(freeVars));
  predTerm2 = term_CopyShallow(termstate, predTerm1);
  for (i = 0; i < array_GetSize(freeVars); ++i) {
    var = array_GetElement(freeVars, i);
    term_SetArgument(predTerm1, i, term_Create(termstate, var, NULL));
    term_SetArgument(predTerm2, i, term_Create(termstate, var, NULL));
  }
  newRule = term_CreateArity(termstate,
                             Pol ? fol_Implies(folstate) : fol_Equiv(folstate), 2);
  term_RplacFirstArgument(newRule, predTerm2);
  term_RplacSecondArgument(newRule, term);
  if (Pol < 0) {
    term_SwapArguments(newRule, 0, 1);
  }
  for (i = array_GetSize(freeVars); i--;) {
    var = array_GetElement(freeVars, i);
    phi = term_CreateArity(termstate, fol_Forall(folstate), 2);
    term_SetArgument(phi, 0, term_Create(termstate, var, NULL));
    term_SetArgument(phi, 1, newRule);
    newRule = phi;
  }
  term_SetArgument(Super, Idx, predTerm1);
  array_Delete(memory, freeVars);
  return newRule;
}
void fcnf_term_SetAllSuperterms(TERM Term, TERM Super)
{
  unsigned i;
  term_RplacSuperterm(Term, Super);
  for (i = 0; i < term_GetArity(Term); ++i) {
    fcnf_term_SetAllSuperterms(term_GetArgument(Term, i), Term);
  }
}
static TERM fcnf_RenameObviousPositions(FCNFSTATE Fcnfstate, TERM Term)
{
  FOLSTATE folstate;
  TERMSTATE termstate;
  MEMORY memory;
  char *name;
  ARRAY clauses, positions;
  unsigned i;
  TERM rule;
  folstate = fcnf_GetFolstate(Fcnfstate);
  termstate = fcnf_GetTermstate(Fcnfstate);
  memory = fcnf_GetMemory(Fcnfstate);
  positions = Fcnfstate->list1;
  clauses = Fcnfstate->list2;
  array_Clean(positions);
  array_Clean(clauses);
  clauses = array_Add(memory, clauses, (intptr_t)Term);
  positions = fcnf_ListObviousPositions(folstate, Term, positions);
  for (i = 0; i < array_GetSize(positions); i += 3) {
    name = fcnf_GetNextRenamingName(Fcnfstate);
    rule = fcnf_RenameDef(Fcnfstate,
                             (TERM) array_GetElement(positions, i),
                             (NAT) array_GetElement(positions, i+1),
                             (short) array_GetElement(positions, i+2),
                             name);
    clauses = array_Add(memory, clauses, (intptr_t)rule);
    string_StringFree(memory, name);
  }
  if (array_GetSize(clauses) > 1) {
    Term = term_Create(termstate, fol_And(folstate), clauses);
  }
  array_Clean(positions);
  array_Clean(clauses);
  Fcnfstate->list1 = positions;
  Fcnfstate->list2 = clauses;
  return Term;
}
static unsigned fcnf_CreateVarLookupRecurse(FOLSTATE Folstate, ARRAY Lookup,
                                            TERM Term, unsigned Time)
{
  TERMSTATE termstate;
  MEMORY memory;
  unsigned i, var;
  termstate = fol_GetTermstate(Folstate);
  memory = fol_GetMemory(Folstate);
  term_SetProperty(Term, ++Time);
  if (term_IsVariable(termstate, Term)) {
    var = term_TopSymbol(Term);
    array_AddToArrayAtIndex(memory, Lookup, var, Time);
  }
  else {
    i = (fol_IsQuantifier(Folstate, Term) ? 1 : 0);
    for (; i < term_GetArity(Term); ++i) {
      Time = fcnf_CreateVarLookupRecurse(Folstate, Lookup,
                                         term_GetArgument(Term, i), Time);
    }
  }
  term_SetProfit(Term, Time);
  return Time;
}
void fcnf_CreateVarLookup(FCNFSTATE Fcnfstate, TERM Term)
{
  FOLSTATE folstate;
  SYMBSTATE symbstate;
  unsigned i, maxV;
  folstate = fcnf_GetFolstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  maxV = symbol_GetStandardVarCounter(symbstate);
  for (i=0; i<maxV; ++i) {
    array_Clean((ARRAY)array_GetElement(Fcnfstate->bindArr, i));
  }
  fcnf_CreateVarLookupRecurse(folstate, Fcnfstate->bindArr, Term, 0);
}
static BOOL fcnf_HavePointInInterval(intptr_t *L, intptr_t *R,
                                     unsigned A, unsigned B
                                                         )
{
  intptr_t *M;
  unsigned x;
  if (R <= L) return FALSE;
  M = L + (R - L)/2;
  x = (unsigned) *M;
  if (x < A) return fcnf_HavePointInInterval(M+1, R, A, B );
  if (B < x) return fcnf_HavePointInInterval(L, M, A, B );
  return TRUE;
}
BOOL fcnf_VarOccurs(FCNFSTATE Fcnfstate, SYMBOL Var, TERM Term)
{
  ARRAY occurences;
  occurences = (ARRAY)array_GetElement(Fcnfstate->bindArr, Var);
  return fcnf_HavePointInInterval(occurences, occurences + array_GetSize(occurences),
                                  term_GetProperty(Term), term_GetProfit(Term) );
}
void fcnf_CheckVarLookupRecurse(FCNFSTATE Fcnfstate, TERM Term, unsigned Depth)
{
  FOLSTATE folstate;
  TERMSTATE termstate;
  SYMBSTATE symbstate;
  unsigned i, maxV;
  folstate = fcnf_GetFolstate(Fcnfstate);
  termstate = fcnf_GetTermstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  maxV = symbol_GetStandardVarCounter(symbstate);
  for (i = 0; i < Depth; ++i) printf(" ");
  printf("%u:%u ",
         (unsigned)term_GetProperty(Term),
         (unsigned)term_GetProfit(Term));
  term_PrintPrefix(termstate, Term);
  printf("\n");
  for (i = 0; i < Depth; ++i) printf(" ");
  printf("Free Vars: ");
  fcnf_PrintFreeVars(folstate, Term);
  printf("\n");
  for (i = 0; i < Depth; ++i) printf(" ");
  printf("Occuring: ");
  for (i = 1; i < maxV; ++i) {
    if (fcnf_VarOccurs(Fcnfstate, i, Term)) {
      printf("x%u ", i);
    }
  }
  printf("\n");
  for (i = 0; i < Depth; ++i) printf(" ");
  printf("Used Vars: ");
  fcnf_PrintUsedVars(termstate, Term);
  printf("\n");
  i = (fol_IsQuantifier(folstate, Term) ? 1 : 0);
  for (; i < term_GetArity(Term); ++i) {
    fcnf_CheckVarLookupRecurse(Fcnfstate, term_GetArgument(Term, i), Depth+1);
  }
}
void fcnf_CheckVarLookup(FCNFSTATE Fcnfstate, TERM Term)
{
  SYMBSTATE symbstate;
  ARRAY arr;
  unsigned i, j, maxV;
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  maxV = symbol_GetStandardVarCounter(symbstate);
  for (i=1; i<maxV; ++i) {
    arr = (ARRAY)array_GetElement(Fcnfstate->bindArr, i);
    if (arr != NULL) {
      printf("Var x%u occurs at:", i);
      for (j = 0; j < array_GetSize(arr); ++j) {
        printf(" %u", (unsigned)arr[j]);
      }
      printf("\n");
    }
  }
  fcnf_CheckVarLookupRecurse(Fcnfstate, Term, 0);
  printf("-----Var lookup check done-------\n");
}
static TERM fcnf_MiniScopePass2(FCNFSTATE Fcnfstate, TERM Quant, TERM Term)
{
  FOLSTATE folstate;
  TERMSTATE termstate;
  SYMBSTATE symbstate;
  TERM phi, quantCopy;
  unsigned var, i, occ;
  folstate = fcnf_GetFolstate(Fcnfstate);
  termstate = fcnf_GetTermstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  var = term_TopSymbol(term_FirstArgument(Quant));
  if (fol_IsAnd(folstate, Term) || fol_IsOr(folstate, Term)) {
    if (fol_IsAnd(folstate, Term) == fol_IsForall(folstate, Quant)) {
      for (i = 0; i < term_GetArity(Term); ++i) {
        phi = term_GetArgument(Term, i);
        if (fcnf_VarOccurs(Fcnfstate, var, phi)) {
          if(0) {
            printf("occurence list of x%u: ", var);
            ARRAY occurences = (ARRAY)symbol_BindingValue(symbstate, var);
            if (occurences) {
              for (unsigned j = 0; j < array_GetSize(occurences); ++j)
                printf("%u ", (unsigned)occurences[j]);
            }
            printf("\nterm entry:exit %u:%u\n",
                   (unsigned)term_GetProperty(phi), (unsigned)term_GetProfit(phi));
          }
          quantCopy = term_CopyShallow(termstate, Quant);
          term_RplacFirstArgument(quantCopy,
                                  term_Copy(termstate, term_FirstArgument(Quant)));
          term_SetArgument(Term, i,
                           fcnf_MiniScopePass2(Fcnfstate,
                                               quantCopy,
                                               phi));
        }
      }
      term_Free(termstate, term_FirstArgument(Quant));
      term_Free(termstate, Quant);
      return Term;
    }
    else {
      occ = (unsigned)-1;
      for (i = 0; i < term_GetArity(Term) && occ != (unsigned)-2; ++i) {
        phi = term_GetArgument(Term, i);
        if (fcnf_VarOccurs(Fcnfstate, var, phi)) {
          occ = (occ == (unsigned)-1 ? i : (unsigned)-2);
        }
      }
      if (occ != (unsigned)-2) {
        term_SetArgument(Term, occ,
                         fcnf_MiniScopePass2(Fcnfstate,
                                             Quant,
                                             term_GetArgument(Term, occ)));
        return Term;
      }
    }
  }
  term_RplacSecondArgument(Quant, Term);
  term_SetProperty(Quant, term_GetProperty(Term));
  term_SetProfit(Quant, term_GetProfit(Term));
  return Quant;
}
static TERM fcnf_MiniScopePass1(FCNFSTATE Fcnfstate, TERM Term)
{
  FOLSTATE folstate;
  TERMSTATE termstate;
  TERM phi;
  unsigned i, var;
  folstate = fcnf_GetFolstate(Fcnfstate);
  termstate = fcnf_GetTermstate(Fcnfstate);
  if (fol_IsQuantifier(folstate, Term)) {
    var = term_TopSymbol(term_FirstArgument(Term));
    phi = term_SecondArgument(Term);
    term_RplacSecondArgument(Term, NULL);
    phi = fcnf_MiniScopePass1(Fcnfstate, phi);
    if (fcnf_VarOccurs(Fcnfstate, var, phi)) {
      Term = fcnf_MiniScopePass2(Fcnfstate, Term, phi);
    }
    else {
      term_Free(termstate, term_FirstArgument(Term));
      term_Free(termstate, Term);
      Term = phi;
    }
  }
  else if (!fol_IsLiteral(folstate, Term)) {
    for (i = 0; i < term_GetArity(Term); ++i) {
      term_SetArgument(Term, i,
                       fcnf_MiniScopePass1(Fcnfstate,
                                           term_GetArgument(Term, i)));
    }
  }
  return Term;
}
TERM fcnf_MiniScopeBasic(FCNFSTATE Fcnfstate, TERM Term)
{
  fcnf_CreateVarLookup(Fcnfstate, Term);
  Term = fcnf_MiniScopePass1(Fcnfstate, Term);
  fcnf_RenameVariables(Fcnfstate, Term);
  return Term;
}
TERM fcnf_CreateSkolem(FCNFSTATE Fcnfstate, SYMBOL VarSymb, ARRAY FreeVars)
{
  SCLSTATE sclstate;
  FOLSTATE folstate;
  TERMSTATE termstate;
  SYMBSTATE symbstate;
  MEMORY memory;
  unsigned i;
  char *name;
  SYMBOL symb;
  TERM phi;
  sclstate = fcnf_GetSclstate(Fcnfstate);
  folstate = fcnf_GetFolstate(Fcnfstate);
  termstate = fcnf_GetTermstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  memory = fcnf_GetMemory(Fcnfstate);
  if(0){
    printf("Skolem for var x%li of arity %lu:",
           VarSymb, array_GetSize(FreeVars));
    fcnf_PrintVarArray(symbstate, FreeVars);
    printf("\n");
  }
  if (array_GetSize(FreeVars) == 0) {
    name = string_Nconc(memory,
                        string_StringCopy(memory, Fcnfstate->skolemConstPrefix),
                        string_IntToString(memory, Fcnfstate->skolemCounter++));
    symb = symbol_CreateConstant(symbstate,
                                 fol_TypeTop(folstate),
                                 name);
    state_AddConstant(sclstate, symb);
  }
  else {
    name = string_Nconc(memory,
                        string_StringCopy(memory, Fcnfstate->skolemFuncPrefix),
                        string_IntToString(memory, Fcnfstate->skolemCounter++));
    symb = symbol_CreateFunction(symbstate,
                                 fol_TypeTop(folstate),
                                 name,
                                 array_GetSize(FreeVars));
    for (i=0;i<array_GetSize(FreeVars);i++)
      symbol_SetArgumentType(symbstate, symb, fol_TypeTop(folstate), i);
    state_AddFunction(sclstate, symb);
  }
  string_StringFree(memory, name);
  phi = term_CreateArity(termstate, symb, array_GetSize(FreeVars));
  for (i=0; i<array_GetSize(FreeVars); ++i) {
    term_SetArgument(phi, i,
                     term_Create(termstate,
                                 (SYMBOL)array_GetElement(FreeVars, i),
                                 NULL));
  }
  return phi;
}
void fcnf_ClearVarBindings(TERMSTATE Termstate, TERM Term)
{
  SYMBSTATE symbstate;
  unsigned i;
  symbstate = term_GetSymbstate(Termstate);
  if (term_IsVariable(Termstate, Term)) {
    symbol_SetBindingValue(symbstate, term_TopSymbol(Term), 0);
  }
  for (i = 0; i < term_GetArity(Term); ++i) {
    fcnf_ClearVarBindings(Termstate, term_GetArgument(Term, i));
  }
}
void fcnf_ClearTermProperty(TERM Term)
{
  unsigned i;
  term_SetProperty(Term, 0);
  for (i = 0; i < term_GetArity(Term); ++i) {
    fcnf_ClearTermProperty(term_GetArgument(Term, i));
  }
}
const intptr_t FCNF_EDGE_TYPE = ((intptr_t)1)<<(8*sizeof(intptr_t)-2);
const intptr_t FCNF_VAR_TYPE = ((intptr_t)1)<<(8*sizeof(intptr_t)-3);
const intptr_t FCNF_VAR_MASK = ~(FCNF_EDGE_TYPE | FCNF_VAR_TYPE);
void fcnf_BuildAdjRecurse(FOLSTATE Folstate, ARRAY Adj, TERM Term, SYMBOL VarIn)
{
  TERMSTATE termstate;
  MEMORY memory;
  unsigned i;
  intptr_t varOut, edge, varType;
  termstate = fol_GetTermstate(Folstate);
  memory = fol_GetMemory(Folstate);
  if (fol_IsQuantifier(Folstate, Term)) {
    varOut = term_TopSymbol(term_FirstArgument(Term));
    varType = (fol_IsForall(Folstate, Term) ? 0 : FCNF_VAR_TYPE);
    array_SetElement((ARRAY)Adj[0], varOut, varType);
    edge = FCNF_EDGE_TYPE | varType | varOut;
    if (VarIn != 0) {
      array_AddToArrayAtIndex(memory, Adj, VarIn, edge);
    }
    fcnf_BuildAdjRecurse(Folstate, Adj, term_SecondArgument(Term), varOut);
  }
  else if (term_IsVariable(termstate, Term)) {
    varOut = term_TopSymbol(Term);
    varType = array_GetElement((ARRAY)Adj[0], varOut);
    edge = 0 | varType | varOut;
    if (VarIn != 0) {
      array_AddToArrayAtIndex(memory, Adj, VarIn, edge);
    }
  }
  else {
    for (i=0; i<term_GetArity(Term); ++i) {
      fcnf_BuildAdjRecurse(Folstate, Adj, term_GetArgument(Term, i), VarIn);
    }
  }
}
static ARRAY fcnf_BuildAdj(FCNFSTATE Fcnfstate, TERM Term)
{
  FOLSTATE folstate;
  SYMBSTATE symbstate;
  MEMORY memory;
  unsigned i, maxV;
  ARRAY arr, adj0;
  folstate = fcnf_GetFolstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  memory = fcnf_GetMemory(Fcnfstate);
  maxV = symbol_GetStandardVarCounter(symbstate);
  adj0 = (ARRAY)array_GetElement(Fcnfstate->bindArr, 0);
  adj0 = array_Reserve(memory, adj0, maxV+1);
  array_Clean(adj0);
  array_Claim(adj0);
  array_SetElement(Fcnfstate->bindArr, 0, (intptr_t)adj0);
  for (i=1; i<maxV; ++i) {
    array_Clean((ARRAY)array_GetElement(Fcnfstate->bindArr, i));
  }
  fcnf_BuildAdjRecurse(folstate, Fcnfstate->bindArr, Term, 0);
  for (i=1; i<maxV; ++i) {
    arr = (ARRAY)array_GetElement(Fcnfstate->bindArr, i);
    array_Sort(arr, misc_UIntptrCmp);
    array_RemoveDuplicatesSorted(arr, misc_PtrEqual);
  }
  array_Clean(adj0);
  array_Claim(adj0);
  return Fcnfstate->bindArr;
}
void fcnf_FreeVarsGraphFollow(ARRAY Adj, SYMBOL VarIn, ARRAY Vars)
{
  ARRAY seen, edges;
  intptr_t mark, edge;
  unsigned i;
  SYMBOL varOut;
  seen = (ARRAY)Adj[0];
  mark = seen[0];
  edges = (ARRAY)array_GetElement(Adj, VarIn);
  for (i=0; i<array_GetSize(edges); ++i) {
    edge = array_GetElement(edges, i);
    varOut = edge & FCNF_VAR_MASK;
    if (seen[varOut] < mark) {
      seen[varOut] = mark;
      if (edge & FCNF_EDGE_TYPE) {
        fcnf_FreeVarsGraphFollow(Adj, varOut, Vars);
      }
      else {
        array_AddNoGrow(Vars, varOut);
      }
    }
  }
}
ARRAY fcnf_FreeVarsGraph(ARRAY Adj, SYMBOL Var, ARRAY Vars)
{
  ARRAY seen;
  intptr_t mark;
  array_Clean(Vars);
  seen = (ARRAY)Adj[0];
  mark = ++seen[0];
  seen[Var] = mark;
  fcnf_FreeVarsGraphFollow(Adj, Var, Vars);
  return Vars;
}
void fcnf_FreeVarsGraphSkolemFollow(ARRAY Adj, SYMBOL VarIn, ARRAY Vars)
{
  ARRAY seen, edges;
  intptr_t mark, edge, edgeType, varType;
  unsigned i;
  SYMBOL varOut;
  seen = (ARRAY)Adj[0];
  mark = seen[0];
  edges = (ARRAY)array_GetElement(Adj, VarIn);
  for (i=0; i<array_GetSize(edges); ++i) {
    edge = array_GetElement(edges, i);
    edgeType = edge & FCNF_EDGE_TYPE;
    varType = edge & FCNF_VAR_TYPE;
    varOut = edge & FCNF_VAR_MASK;
    if (seen[varOut] < mark) {
      seen[varOut] = mark;
      if (!edgeType
          && !varType) {
        array_AddNoGrow(Vars, varOut);
      }
      else {
        fcnf_FreeVarsGraphSkolemFollow(Adj, varOut, Vars);
      }
    }
  }
}
ARRAY fcnf_FreeVarsGraphSkolem(ARRAY Adj, SYMBOL Var, ARRAY Vars)
{
  ARRAY seen;
  intptr_t mark;
  array_Clean(Vars);
  seen = (ARRAY)Adj[0];
  mark = ++seen[0];
  seen[Var] = mark;
  fcnf_FreeVarsGraphSkolemFollow(Adj, Var, Vars);
  return Vars;
}
void fcnf_SaveSkolemTerms(FCNFSTATE Fcnfstate, unsigned MaxV)
{
  TERMSTATE termstate;
  SYMBSTATE symbstate;
  MEMORY mem;
  unsigned i;
  TERM sko;
  ARRAY arr;
  termstate = fcnf_GetTermstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  mem = fcnf_GetMemory(Fcnfstate);
  if (0) {
    for (i=1; i<MaxV; ++i) {
      sko = (TERM)symbol_BindingValue(symbstate, i);
      if (sko != NULL) {
        term_Delete(termstate, sko);
      }
      symbol_SetBindingValue(symbstate, i, 0);
    }
  }
  else {
    arr = Fcnfstate->skolemDerivOutputArray;
    arr = array_Clean(arr);
    for (i=1; i<MaxV; ++i) {
      sko = (TERM)symbol_BindingValue(symbstate, i);
      if (sko != NULL) {
        arr = array_Add(mem, arr, (intptr_t)term_Create(termstate, (SYMBOL)i, NULL));
        arr = array_Add(mem, arr, (intptr_t)sko);
      }
      symbol_SetBindingValue(symbstate, i, 0);
    }
    Fcnfstate->skolemDerivOutputArray = arr;
  }
}
TERM fcnf_SkolemizationInnerRecurse(FCNFSTATE Fcnfstate, ARRAY Adj, TERM Term)
{
  FOLSTATE folstate;
  TERMSTATE termstate;
  SYMBSTATE symbstate;
  unsigned i;
  TERM phi, sko;
  SYMBOL var;
  ARRAY freeVars;
  folstate = fcnf_GetFolstate(Fcnfstate);
  termstate = fcnf_GetTermstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  if (fol_IsExist(folstate, Term)) {
    var = term_TopSymbol(term_FirstArgument(Term));
    phi = term_SecondArgument(Term);
    term_Free(termstate, term_FirstArgument(Term));
    term_Free(termstate, Term);
    freeVars = Fcnfstate->list1;
    array_Clean(freeVars);
    fcnf_FreeVarsGraphSkolem(Adj, var, freeVars);
    array_Sort(freeVars, misc_UIntptrCmp);
    sko = fcnf_CreateSkolem(Fcnfstate, var, freeVars);
    symbol_SetBindingValue(symbstate, var, (intptr_t)sko);
    Term = fcnf_SkolemizationInnerRecurse(Fcnfstate, Adj, phi);
  }
  else if (term_IsVariable(termstate, Term)) {
    var = term_TopSymbol(Term);
    sko = (TERM)symbol_BindingValue(symbstate, var);
    if (sko != NULL) {
      term_Free(termstate, Term);
      Term = term_Copy(termstate, sko);
    }
  }
  else {
    for (i=0; i<term_GetArity(Term); ++i) {
      phi = term_GetArgument(Term, i);
      phi = fcnf_SkolemizationInnerRecurse(Fcnfstate, Adj, phi);
      term_SetArgument(Term, i, phi);
    }
  }
  return Term;
}
TERM fcnf_SkolemizationInner(FCNFSTATE Fcnfstate, TERM Term)
{
  SYMBSTATE symbstate;
  ARRAY adj;
  unsigned i, maxV;
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  maxV = symbol_GetStandardVarCounter(symbstate);
  adj = fcnf_BuildAdj(Fcnfstate, Term);
  for (i=0; i<maxV; ++i) {
    symbol_SetBindingValue(symbstate, i, 0);
  }
  Term = fcnf_SkolemizationInnerRecurse(Fcnfstate, adj, Term);
  fcnf_SaveSkolemTerms(Fcnfstate, maxV);
  return Term;
}
static TERM fcnf_SkolemFastRecurse(FCNFSTATE Fcnfstate, TERM Term, ARRAY VarsForall)
{
  FOLSTATE folstate;
  TERMSTATE termstate;
  SYMBSTATE symbstate;
  unsigned i;
  TERM skolem, phi;
  SYMBOL var;
  folstate = fcnf_GetFolstate(Fcnfstate);
  termstate = fcnf_GetTermstate(Fcnfstate);
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  if (fol_IsExist(folstate, Term)) {
    var = term_TopSymbol(term_FirstArgument(Term));
    skolem = fcnf_CreateSkolem(Fcnfstate, var, VarsForall);
    symbol_SetBindingValue(symbstate, var, (intptr_t)skolem);
    phi = fcnf_SkolemFastRecurse(Fcnfstate,
                                 term_SecondArgument(Term),
                                 VarsForall);
    term_Free(termstate, term_FirstArgument(Term));
    term_Free(termstate, Term);
    Term = phi;
  }
  else if (fol_IsForall(folstate, Term)) {
    var = term_TopSymbol(term_FirstArgument(Term));
    array_AddNoGrow(VarsForall, var);
    term_SetArgument(Term, 1,
                     fcnf_SkolemFastRecurse(Fcnfstate,
                                            term_GetArgument(Term, 1),
                                            VarsForall));
    array_Pop(VarsForall);
  }
  else if (term_IsVariable(termstate, Term)) {
    var = term_TopSymbol(Term);
    skolem = (TERM)symbol_BindingValue(symbstate, var);
    if (skolem != NULL) {
      term_Free(termstate, Term);
      Term = term_Copy(termstate, skolem);
    }
  } else {
    for (i=0; i<term_GetArity(Term); ++i) {
      term_SetArgument(Term, i,
                       fcnf_SkolemFastRecurse(Fcnfstate,
                                              term_GetArgument(Term, i),
                                              VarsForall));
    }
  }
  return Term;
}
static TERM fcnf_SkolemizationOuter(FCNFSTATE Fcnfstate, TERM Term)
{
  SYMBSTATE symbstate;
  unsigned i, maxV;
  symbstate = fcnf_GetSymbstate(Fcnfstate);
  maxV = symbol_GetStandardVarCounter(symbstate);
  for (i=0; i<maxV; ++i) {
    symbol_SetBindingValue(symbstate, i, 0);
  }
  array_Clean(Fcnfstate->list1);
  Term = fcnf_SkolemFastRecurse(Fcnfstate, Term, Fcnfstate->list1);
  fcnf_SaveSkolemTerms(Fcnfstate, maxV);
  return Term;
}
static TERM fcnf_RemoveForall(FOLSTATE Folstate, TERM Term)
{
  TERMSTATE termstate;
  TERM phi;
  unsigned i;
  termstate = fol_GetTermstate(Folstate);
  if (fol_IsForall(Folstate, Term)) {
    phi = term_SecondArgument(Term);
    term_Free(termstate, term_FirstArgument(Term));
    term_Free(termstate, Term);
    Term = fcnf_RemoveForall(Folstate, phi);
  }
  else if (!fol_IsAtom(Folstate, Term)) {
    for (i = 0; i < term_GetArity(Term); ++i) {
      term_SetArgument(Term, i,
                       fcnf_RemoveForall(Folstate,
                                         term_GetArgument(Term, i)));
    }
  }
  return Term;
}
static TERM fcnf_CreateConjOfClauses(FOLSTATE Folstate, ARRAY Conj)
{
  TERMSTATE termstate;
  MEMORY memory;
  ARRAY arr;
  TERM term;
  unsigned i;
  termstate = fol_GetTermstate(Folstate);
  memory = fol_GetMemory(Folstate);
  arr = array_Copy(memory, Conj);
  for (i = 0; i < array_GetSize(Conj); ++i) {
    term = (TERM)term_Create(termstate, fol_Or(Folstate), (ARRAY)Conj[i]);
    arr[i] = (intptr_t)term_Copy(termstate, term);
    term_Free(termstate, term);
  }
  term = term_Create(termstate, fol_And(Folstate), arr);
  array_Delete(memory, arr);
  return term;
}
static void fcnf_FreeArrArrTerm(TERMSTATE Termstate, ARRAY Arr)
{
  MEMORY memory;
  unsigned i, j;
  ARRAY arr2;
  memory = term_GetMemory(Termstate);
  for (i = 0; i < array_GetSize(Arr); ++i) {
    arr2 = (ARRAY)array_GetElement(Arr, i);
    for (j = 0; j < array_GetSize(arr2); ++j) {
      term_Delete(Termstate, (TERM)term_GetArgument(arr2, j));
    }
    array_Delete(memory, arr2);
  }
  array_Delete(memory, Arr);
}
static ARRAY fcnf_Distribute(FOLSTATE Folstate, ARRAY LHS, ARRAY RHS)
{
  TERMSTATE termstate;
  MEMORY memory;
  unsigned i, j;
  ARRAY arr, arr2;
  termstate = fol_GetTermstate(Folstate);
  memory = fol_GetMemory(Folstate);
  arr = array_Create(memory, array_GetSize(RHS) * array_GetSize(LHS));
  for (i = 0; i < array_GetSize(LHS); ++i) {
    for (j = 0; j < array_GetSize(RHS); ++j) {
      arr = array_Add(memory, arr,
                      (intptr_t)array_Union(memory,
                                            (ARRAY)array_GetElement(LHS, i),
                                            (ARRAY)array_GetElement(RHS, j)));
    }
  }
  for (i = 0; i < array_GetSize(arr); ++i) {
    arr2 = (ARRAY)array_GetElement(arr, i);
    for (j = 0; j < array_GetSize(arr2); ++j) {
      arr2[j] = (intptr_t)term_Copy(termstate, (TERM)arr2[j]);
    }
  }
  fcnf_FreeArrArrTerm(termstate, LHS);
  fcnf_FreeArrArrTerm(termstate, RHS);
  return arr;
}
static ARRAY fcnf_PushDisjAA(FOLSTATE Folstate, TERM Term)
{
  TERMSTATE termstate;
  MEMORY memory;
  unsigned i;
  ARRAY arr, arr2;
  termstate = fol_GetTermstate(Folstate);
  memory = fol_GetMemory(Folstate);
  if (fol_IsAnd(Folstate, Term)) {
    arr = array_Create(memory, 6);
    for (i = 0; i < term_GetArity(Term); ++i) {
      arr2 = fcnf_PushDisjAA(Folstate, term_GetArgument(Term, i));
      arr = array_Append(memory, arr, arr2);
      array_Delete(memory, arr2);
    }
    term_Free(termstate, Term);
  }
  else if (fol_IsOr(Folstate, Term)) {
    arr = fcnf_PushDisjAA(Folstate, term_GetArgument(Term, 0));
    for (i = 1; i < term_GetArity(Term); ++i) {
      arr2 = fcnf_PushDisjAA(Folstate, term_GetArgument(Term, i));
      arr = fcnf_Distribute(Folstate, arr, arr2);
    }
    term_Free(termstate, Term);
  }
  else {
    arr = array_Create(memory, 1);
    arr2 = array_Create(memory, 1);
    arr2 = array_Add(memory, arr2, (intptr_t)Term);
    arr = array_Add(memory, arr, (intptr_t)arr2);
  }
  return arr;
}
static FCNF_LOGSTEP fcnf_CreateLogstep(MEMORY Memory, const char *Name)
{
  FCNF_LOGSTEP step;
  step = (FCNF_LOGSTEP)memory_Malloc(Memory, sizeof(FCNF_LOGSTEP_NODE));
  step->name = string_StringCopy(Memory, Name);
  step->path = NULL;
  step->file = NULL;
  step->time = 0;
  step->mem = 0;
  return step;
}
static void fcnf_PrintTime(const char *Str, clock_t Time)
{
  printf("c ### Runtime %s: %f s\n", Str, (double)Time/CLOCKS_PER_SEC);
}
static void fcnf_PrintMem(const char *Str, unsigned long Bytes)
{
  printf("c ### Memory  %s:  %lu Bytes", Str, Bytes);
  if (Bytes > (1<<30)) printf(" %f GBytes", (double)Bytes / (1<<30));
  else if (Bytes > (1<<20)) printf(" %f MBytes", (double)Bytes / (1<<20));
  else if (Bytes > (1<<10)) printf(" %f KBytes", (double)Bytes / (1<<10));
  puts("");
}
static void fcnf_FreeLogstep(MEMORY Memory, FCNF_LOGSTEP Step)
{
  fcnf_PrintTime(Step->name, Step->time);
  fcnf_PrintMem(Step->name, Step->mem);
  string_StringFree(Memory, Step->name);
  if (Step->path != NULL) {
    string_StringFree(Memory, Step->path);
  }
  if (Step->file != NULL) {
    fclose(Step->file);
  }
  memory_Free(Memory, Step, sizeof(FCNF_LOGSTEP_NODE));
}
static FILE* fcnf_OpenLogfile(FCNF_LOGSTEP Step, const char *Extra)
{
  if (Step->file == NULL) {
    Step->file = fopen(Step->path, "w");
    fprintf(Step->file, "%%%%%%%% STEP %s: %s\n\n", Step->name, Extra);
  }
  return Step->file;
}
static FCNF_LOGSTEP fcnf_StartLog(FCNFSTATE Fcnfstate, ARRAY *LogstepsPtr,
                                  const char *LogfilePrefix, const char *Name)
{
  MEMORY memory;
  unsigned i;
  char *str;
  FCNF_LOGSTEP step;
  memory = fcnf_GetMemory(Fcnfstate);
  step = NULL;
  for (i=0; i<array_GetSize(*LogstepsPtr); ++i) {
    step = (FCNF_LOGSTEP)array_GetElement(*LogstepsPtr, i);
    if (0 == strcmp(Name, step->name)) break;
  }
  if (i == array_GetSize(*LogstepsPtr)) {
    step = fcnf_CreateLogstep(memory, Name);
    str = string_IntToString(memory, i+1);
    step->path = string_Conc(memory, LogfilePrefix, str);
    string_StringFree(memory, str);
    *LogstepsPtr = array_Add(memory, *LogstepsPtr, (intptr_t)step);
  }
  step->time0 = clock();
  step->mem0 = memory->newbytes;
  return step;
}
static void fcnf_StopLog(FCNFSTATE Fcnfstate, FCNF_LOGSTEP Step)
{
  clock_t time;
  unsigned long mem;
  time = clock() - Step->time0;
  mem = fcnf_GetMemory(Fcnfstate)->newbytes - Step->mem0;
  Step->time += time;
  Step->mem += mem;
}
ARRAY fcnf_CNFScratch(SCLSTATE State, const char *InputFile,
                      ARRAY Conjectures, ARRAY Axioms, int SkolemLevel)
{
  FCNFSTATE fcnfstate;
  FOLSTATE folstate;
  TERMSTATE termstate;
  MEMORY memory;
  unsigned i;
  TERM term;
  ARRAY allTerms;
  ARRAY clauses, allClauses;
  clock_t startTime;
  char *name, *role;
  char *logfilePrefix;
  ARRAY logsteps;
  FCNF_LOGSTEP logstep, fullLog;
  FILE *file;
  startTime = clock();
  fcnf_PrintMem("before", state_GetMemory(State)->newbytes);
  fcnfstate = fcnf_Init(State);
  folstate = fcnf_GetFolstate(fcnfstate);
  termstate = fcnf_GetTermstate(fcnfstate);
  memory = fcnf_GetMemory(fcnfstate);
  printf("fcnf->renPre %s\n", fcnfstate->renamingPrefix);
  printf("fcnf->skfPre %s\n", fcnfstate->skolemFuncPrefix);
  printf("fcnf->skcPre %s\n", fcnfstate->skolemConstPrefix);
  printf("c ### InputFile: %s\n", InputFile);
  for (i = 0; InputFile[i]; ++i) {
    if (InputFile[i] == '/') {
      InputFile += i + 1;
      i = 0;
    }
  }
  printf("c ### filename: %s\n", InputFile);
  logfilePrefix = string_Conc(memory,
                              "/scratch/inf0/user/fwobito/cnfdump/",
                              InputFile);
  logfilePrefix = string_Nconc(memory,
                               logfilePrefix,
                               string_StringCopy(memory, "."));
  printf("c ### logfilePrefix: %s\n", logfilePrefix);
  logsteps = array_Create(memory, 6);
  fullLog = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "FCNF");
  allTerms = array_Append(memory, Axioms, Conjectures);
  allClauses = array_Create(memory, 2*array_GetSize(allTerms));
  if (0) do {
      FCNF_LOGSTEP computeSize = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "computeSize");
      unsigned long totalSize = 0;
      for (i = 0; i < array_GetSize(allTerms); ++i) {
        totalSize += term_ComputeSize(termstate,
                                      (TERM)array_GetElement(allTerms, i));
      }
      printf("c ### totalTerms: %u\n", (unsigned)array_GetSize(allTerms));
      printf("c ### totalSize: %lu\n", totalSize);
      fcnf_StopLog(fcnfstate, computeSize);
    } while(0);
  BOOL LOG_FLAG_TMP = 0;
  for (i = 0; i < array_GetSize(allTerms); ++i) {
    term = (TERM)array_GetElement(allTerms, i);
    if (i < array_GetSize(allTerms) - array_GetSize(Conjectures)) {
      name = string_Nconc(memory,
                          string_StringCopy(memory, "axiom"),
                          string_IntToString(memory, i));
      role = (char*)"axiom";
    }
    else {
      name = string_Nconc(memory,
                          string_StringCopy(memory, "nconj"),
                          string_IntToString(memory, i));
      role = (char*)"negated_conjecture";
    }
    logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "Regurge");
    file = fcnf_OpenLogfile(logstep, "regurged input");
    tptp_FPrintFOF(file, folstate, term, name, role);
    fcnf_StopLog(fcnfstate, logstep);
    logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "ElimTB");
    term = fcnf_ElimTB(folstate, term);
    fcnf_StopLog(fcnfstate, logstep);
    logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "RenameVars");
    fcnf_RenameVariables(fcnfstate, term);
    fcnf_StopLog(fcnfstate, logstep);
    if (LOG_FLAG_TMP) {
      file = fcnf_OpenLogfile(logstep, "after ElimTB and RenameVariables");
      tptp_FPrintFOF(file, folstate, term, name, role);
    }
    BOOL DO_RENAME_OBV_TMP = 1;
    if (DO_RENAME_OBV_TMP) {
      logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "RenameObv");
      term = fcnf_RenameObviousPositions(fcnfstate, term);
      fcnf_StopLog(fcnfstate, logstep);
      if (LOG_FLAG_TMP) {
        file = fcnf_OpenLogfile(logstep, "after RenameObviousPositions");
        tptp_FPrintFOF(file, folstate, term, name, role);
      }
    }
    logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "ElimImpl");
    term = fcnf_ElimImp(folstate, term);
    fcnf_StopLog(fcnfstate, logstep);
    logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "ElimEquiv");
    term = fcnf_ElimEquiv(folstate, term, 1);
    fcnf_StopLog(fcnfstate, logstep);
    if (LOG_FLAG_TMP) {
      file = fcnf_OpenLogfile(logstep, DO_RENAME_OBV_TMP
                              ? "after ElimImpl and ElimEquiv"
                              : "after ElimImpl and ElimEquiv without RenameObv");
      tptp_FPrintFOF(file, folstate, term, name, role);
    }
    logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "PushNeg");
    term = fcnf_PushNeg(folstate, term, 1);
    fcnf_StopLog(fcnfstate, logstep);
    if (LOG_FLAG_TMP) {
      file = fcnf_OpenLogfile(logstep, "after PushNeg");
      tptp_FPrintFOF(file, folstate, term, name, role);
    }
    if (1) {
      logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "MiniScope");
      term = fcnf_MiniScopeBasic(fcnfstate, term);
      fcnf_StopLog(fcnfstate, logstep);
      if (LOG_FLAG_TMP) {
        file = fcnf_OpenLogfile(logstep, "after MiniScope");
        tptp_FPrintFOF(file, folstate, term, name, role);
      }
    }
    switch (SkolemLevel) {
    case FCNF_SKOLEM_LEVEL_OUTER:
      logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "SkolemFast");
      term = fcnf_SkolemizationOuter(fcnfstate, term);
      fcnf_StopLog(fcnfstate, logstep);
      if (LOG_FLAG_TMP) {
        file = fcnf_OpenLogfile(logstep, "after SkolemFast");
        tptp_FPrintFOF(file, folstate, term, name, role);
      }
      break;
    case FCNF_SKOLEM_LEVEL_INNER:
      logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "SkolemGraph");
      term = fcnf_SkolemizationInner(fcnfstate, term);
      fcnf_StopLog(fcnfstate, logstep);
      if (LOG_FLAG_TMP) {
        file = fcnf_OpenLogfile(logstep, "after SkolemGraph");
        tptp_FPrintFOF(file, folstate, term, name, role);
      }
      break;
    }
    logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "RemoveForall");
    term = fcnf_RemoveForall(folstate, term);
    fcnf_StopLog(fcnfstate, logstep);
    logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "PushDisj");
    clauses = fcnf_PushDisjAA(folstate, term);
    fcnf_StopLog(fcnfstate, logstep);
    logstep = fcnf_StartLog(fcnfstate, &logsteps, logfilePrefix, "Appending...");
    allClauses = array_Append(memory, allClauses, clauses);
    if (0) {
      term = fcnf_CreateConjOfClauses(folstate, clauses);
      printf("\n");
      printf("term %u after PushDisj:\n", i);
      term_PrettyPrint(termstate, term);
      printf("\n\n");
      term_Delete(termstate, term);
    }
    fcnf_StopLog(fcnfstate, logstep);
    array_Delete(memory, clauses);
    string_StringFree(memory, name);
  }
  fcnf_StopLog(fcnfstate, fullLog);
  file = fcnf_OpenLogfile(fullLog, "plain clauses");
  tptp_FPrintCNFArrArrLit(file, folstate, allClauses);
  printf("c ### logfiles:");
  for (i = 0; i < array_GetSize(logsteps); ++i) {
    logstep = (FCNF_LOGSTEP)array_GetElement(logsteps, i);
    if (logstep->file != NULL) printf(" %u", i+1);
  }
  printf("\n");
  array_Delete(memory, Conjectures);
  array_Delete(memory, allTerms);
  string_StringFree(memory, logfilePrefix);
  for (i=0; i<array_GetSize(logsteps); ++i) {
    fcnf_FreeLogstep(memory,
                     (FCNF_LOGSTEP)array_GetElement(logsteps, i));
  }
  array_Delete(memory, logsteps);
  fcnf_Free(fcnfstate);
  printf("c ### Runtime Total: %f\n", (double)(clock() - startTime)/CLOCKS_PER_SEC);
  return allClauses;
}
ARRAY fcnf_CNF(SCLSTATE State, ARRAY Conjectures, ARRAY Axioms, int SkolemLevel)
{
  FCNFSTATE fcnfstate;
  FOLSTATE folstate;
  MEMORY memory;
  unsigned i;
  TERM term;
  ARRAY allTerms;
  ARRAY clauses, allClauses;
  fcnfstate = fcnf_Init(State);
  folstate = fcnf_GetFolstate(fcnfstate);
  memory = fcnf_GetMemory(fcnfstate);
  allTerms = array_Append(memory, Axioms, Conjectures);
  allClauses = array_Create(memory, 2*array_GetSize(allTerms));
  for (i = 0; i < array_GetSize(allTerms); ++i) {
    term = (TERM)array_GetElement(allTerms, i);
    term = fcnf_ElimTB(folstate, term);
    fcnf_RenameVariables(fcnfstate, term);
    term = fcnf_RenameObviousPositions(fcnfstate, term);
    term = fcnf_ElimImp(folstate, term);
    term = fcnf_ElimEquiv(folstate, term, 1);
    term = fcnf_PushNeg(folstate, term, 1);
    term = fcnf_MiniScopeBasic(fcnfstate, term);
    switch (SkolemLevel) {
    case FCNF_SKOLEM_LEVEL_OUTER:
      term = fcnf_SkolemizationOuter(fcnfstate, term);
      break;
    case FCNF_SKOLEM_LEVEL_INNER:
      term = fcnf_SkolemizationInner(fcnfstate, term);
      break;
    }
    term = fcnf_RemoveForall(folstate, term);
    clauses = fcnf_PushDisjAA(folstate, term);
    allClauses = array_Append(memory, allClauses, clauses);
    array_Delete(memory, clauses);
  }
  array_Delete(memory, Conjectures);
  array_Delete(memory, allTerms);
  fcnf_Free(fcnfstate);
  return allClauses;
}
static void fcnf_TptpElimTBRenVar(FCNFSTATE Fcnfstate)
{
  TPTPSTATE tptpstate = fcnf_GetTptpstate(Fcnfstate);
  FOLSTATE folstate = fcnf_GetFolstate(Fcnfstate);
  TERM term;
  TPTP_FORMULA formula;
  for (unsigned i=0; i<array_GetSize(Fcnfstate->arrIn); ++i) {
    formula = (TPTP_FORMULA)array_GetElement(Fcnfstate->arrIn, i);
    term = tptp_GetTerm(formula);
    term = fcnf_ElimTB(folstate, term);
    fcnf_RenameVariables(Fcnfstate, term);
    tptp_FofSimpleInference(tptpstate, formula, term, "elimTB", TRUE);
    fcnf_AddOutput(Fcnfstate, (intptr_t)formula);
  }
  array_Clean(Fcnfstate->arrIn);
}
static void fcnf_TptpRenameObviousPositionsSingle(FCNFSTATE Fcnfstate, TPTP_FORMULA Formula)
{
  TPTPSTATE tptpstate = fcnf_GetTptpstate(Fcnfstate);
  FOLSTATE folstate = fcnf_GetFolstate(Fcnfstate);
  MEMORY memory = fcnf_GetMemory(Fcnfstate);
  char *name;
  ARRAY formulae, positions;
  TERM term;
  positions = Fcnfstate->list1;
  formulae = Fcnfstate->list2;
  array_Clean(positions);
  array_Clean(formulae);
  positions = fcnf_ListObviousPositions(folstate, tptp_GetTerm(Formula), positions);
  for (unsigned i=0; i<array_GetSize(positions); i += 3) {
    name = fcnf_GetNextRenamingName(Fcnfstate);
    term = fcnf_RenameDef(Fcnfstate,
                          (TERM) array_GetElement(positions, i),
                          (NAT) array_GetElement(positions, i+1),
                          (short) array_GetElement(positions, i+2),
                          name);
    TPTP_FORMULA introFormula = tptp_IntroduceRenaming(tptpstate,
                                                       name,
                                                       term,
                                                       Formula);
    formulae = array_Add(memory, formulae, (intptr_t)introFormula);
  }
  if (array_GetSize(formulae) > 0) {
    tptp_RenamingInference(tptpstate, Formula, formulae);
  }
  for (unsigned i=0; i<array_GetSize(formulae); ++i) {
    fcnf_AddOutput(Fcnfstate, array_GetElement(formulae, i));
  }
  fcnf_AddOutput(Fcnfstate, (intptr_t)Formula);
  array_Clean(positions);
  array_Clean(formulae);
  Fcnfstate->list1 = positions;
  Fcnfstate->list2 = formulae;
}
static void fcnf_TptpRenameObviousPositions(FCNFSTATE Fcnfstate)
{
  TPTP_FORMULA formula;
  for (unsigned i=0; i<array_GetSize(Fcnfstate->arrIn); ++i) {
    formula = (TPTP_FORMULA)array_GetElement(Fcnfstate->arrIn, i);
    fcnf_TptpRenameObviousPositionsSingle(Fcnfstate, formula);
  }
  array_Clean(Fcnfstate->arrIn);
}
static void fcnf_TptpElimImpEquivPushNegMiniScope(FCNFSTATE Fcnfstate)
{
  TPTPSTATE tptpstate = fcnf_GetTptpstate(Fcnfstate);
  FOLSTATE folstate = fcnf_GetFolstate(Fcnfstate);
  TERM term;
  TPTP_FORMULA formula;
  for (unsigned i=0; i<array_GetSize(Fcnfstate->arrIn); ++i) {
    formula = (TPTP_FORMULA)array_GetElement(Fcnfstate->arrIn, i);
    term = tptp_GetTerm(formula);
    term = fcnf_ElimImp(folstate, term);
    term = fcnf_ElimEquiv(folstate, term, 1);
    term = fcnf_PushNeg(folstate, term, 1);
    symbol_SetStandardVarCounter(fcnf_GetSymbstate(Fcnfstate),
                                 term_MaxVar(fcnf_GetTermstate(Fcnfstate), term) + 1);
    term = fcnf_MiniScopeBasic(Fcnfstate, term);
    tptp_FofSimpleInference(tptpstate, formula, term, "elimImpEquivPushNegMiniScope", FALSE);
    fcnf_AddOutput(Fcnfstate, (intptr_t)formula);
  }
  array_Clean(Fcnfstate->arrIn);
}
static void fcnf_TptpSkolemization(FCNFSTATE Fcnfstate, int SkolemLevel)
{
  TPTPSTATE tptpstate = fcnf_GetTptpstate(Fcnfstate);
  TERMSTATE termstate = fcnf_GetTermstate(Fcnfstate);
  TERM term;
  TPTP_FORMULA formula;
  for (unsigned i=0; i<array_GetSize(Fcnfstate->arrIn); ++i) {
    formula = (TPTP_FORMULA)array_GetElement(Fcnfstate->arrIn, i);
    term = tptp_GetTerm(formula);
    symbol_SetStandardVarCounter(fcnf_GetSymbstate(Fcnfstate),
                                 term_MaxVar(termstate, term) + 1);
    switch (SkolemLevel) {
    case FCNF_SKOLEM_LEVEL_OUTER:
      term = fcnf_SkolemizationOuter(Fcnfstate, term);
      break;
    case FCNF_SKOLEM_LEVEL_INNER:
      term = fcnf_SkolemizationInner(Fcnfstate, term);
      break;
    }
    tptp_SkolemInference(tptpstate, formula, term, Fcnfstate->skolemDerivOutputArray);
    fcnf_AddOutput(Fcnfstate, (intptr_t)formula);
  }
  array_Clean(Fcnfstate->arrIn);
}
static void fcnf_TptpRemForallPushDisjMakeClauses(FCNFSTATE Fcnfstate)
{
  SCLSTATE sclstate = fcnf_GetSclstate(Fcnfstate);
  TPTPSTATE tptpstate = fcnf_GetTptpstate(Fcnfstate);
  FOLSTATE folstate = fcnf_GetFolstate(Fcnfstate);
  TERMSTATE termstate = fcnf_GetTermstate(Fcnfstate);
  MEMORY memory = fcnf_GetMemory(Fcnfstate);
  TERM term;
  TPTP_FORMULA formula;
  for (unsigned i=0; i<array_GetSize(Fcnfstate->arrIn); ++i) {
    formula = (TPTP_FORMULA)array_GetElement(Fcnfstate->arrIn, i);
    term = tptp_GetTerm(formula);
    term = fcnf_RemoveForall(folstate, term);
    ARRAY arArLits = fcnf_PushDisjAA(folstate, term);
    for (unsigned j=0; j<array_GetSize(arArLits); ++j) {
      ARRAY arLits = (ARRAY)array_GetElement(arArLits, j);
      CLAUSE clause = clause_CreateFromArrayOfLiterals(memory, folstate, arLits,
                                                       TRUE, state_GetNextIncrementId(sclstate));
      clause_NormalizeVarsEstablishTypes(state_GetSubststate(sclstate), termstate,
                                         fol_TypeTop(folstate), clause, NULL, fol_TypeTop(folstate));
      array_Delete(memory, arLits);
      if ((strcmp(tptp_GetRole(formula), TPTP_RoleConjecture) == 0)
          || (strcmp(tptp_GetRole(formula), TPTP_RoleNegatedConjecture) == 0)
          || (strcmp(tptp_GetRole(formula), TPTP_RoleHypothesis) == 0)) {
        clause_MarkConjecture(clause, TRUE);
      }
      tptp_PushDisjInference(tptpstate, formula, clause);
      fcnf_AddOutput(Fcnfstate, (intptr_t)clause);
    }
    array_Delete(memory, arArLits);
    tptp_FreeFormula(memory, formula);
  }
  array_Clean(Fcnfstate->arrIn);
}
ARRAY fcnf_CNFWithTPTPDerivations(FCNFSTATE Fcnfstate, TPTP_FORMULA Formula,
                                  int SkolemLevel, ARRAY Clauses)
{
  MEMORY mem;
  char *base;
  mem = fcnf_GetMemory(Fcnfstate);
  base = string_Conc(mem, tptp_GetName(Formula), "_");
  if (string_StringIsNumber(tptp_GetName(Formula))) {
    base = string_Nconc(mem, string_StringCopy(mem, "i"), base);
  }
  tptp_SetBasename(Formula, base);
  array_AddNoGrow(Fcnfstate->arrIn, (intptr_t)Formula);
  fcnf_TptpElimTBRenVar(Fcnfstate);
  fcnf_SwapInOut(Fcnfstate);
  fcnf_TptpRenameObviousPositions(Fcnfstate);
  fcnf_SwapInOut(Fcnfstate);
  fcnf_TptpElimImpEquivPushNegMiniScope(Fcnfstate);
  fcnf_SwapInOut(Fcnfstate);
  fcnf_TptpSkolemization(Fcnfstate, SkolemLevel);
  fcnf_SwapInOut(Fcnfstate);
  fcnf_TptpRemForallPushDisjMakeClauses(Fcnfstate);
  Clauses = array_Append(mem, Clauses, Fcnfstate->arrOut);
  array_Clean(Fcnfstate->arrOut);
  return Clauses;
}
