/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *          REPRESENTATION OF PROOF SEARCH                * */
/* *                                                        * */
/* *  $Module:   PROOF SEARCH                               * */ 
/* *                                                        * */
/* *  Copyright (C) 1997, 1998, 1999, 2000, 2001            * */
/* *  MPI fuer Informatik                                   * */
/* *                                                        * */
/* *  This program is free software; you can redistribute   * */
/* *  it and/or modify it under the terms of the FreeBSD    * */
/* *  Licence.                                              * */
/* *                                                        * */
/* *  This program is distributed in the hope that it will  * */
/* *  be useful, but WITHOUT ANY WARRANTY; without even     * */
/* *  the implied warranty of MERCHANTABILITY or FITNESS    * */
/* *  FOR A PARTICULAR PURPOSE.  See the LICENCE file       * */
/* *  for more details.                                     * */
/* *                                                        * */
/* *                                                        * */
/* $Revision: 1.9 $                                         * */
/* $State: Exp $                                            * */
/* $Date: 2011-11-27 12:58:25 $                             * */
/* $Author: weidenb $                                       * */
/* *                                                        * */
/* *             Contact:                                   * */
/* *             Christoph Weidenbach                       * */
/* *             MPI fuer Informatik                        * */
/* *             Stuhlsatzenhausweg 85                      * */
/* *             66123 Saarbruecken                         * */
/* *             Email: spass@mpi-inf.mpg.de                * */
/* *             Germany                                    * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/


/* $RCSfile: search.c,v $ */


#include "search.h"
#include "defs.h"

/**************************************************************/
/* previously Inlined Functions                               */
/**************************************************************/

ANALYZE prfs_GetAnalyze(PROOFSEARCH Prf) 
{
  return Prf->analyze;
}

LIST prfs_EmptyClauses(PROOFSEARCH Prf)
{
  return Prf->emptyclauses;
}

void prfs_SetEmptyClauses(PROOFSEARCH Prf, LIST Clauses)
{
  Prf->emptyclauses = Clauses;
}

LIST prfs_Definitions(PROOFSEARCH Prf)
{
  return Prf->definitions;
}

void prfs_SetDefinitions(PROOFSEARCH Prf, LIST Definitions)
{
  Prf->definitions = Definitions;
}

LIST prfs_UsedEmptyClauses(PROOFSEARCH Prf)
{
  return Prf->usedemptyclauses;
}

void prfs_SetUsedEmptyClauses(PROOFSEARCH Prf, LIST Clauses)
{
  Prf->usedemptyclauses = Clauses;
}


LIST prfs_WorkedOffClauses(PROOFSEARCH Prf)
{
  return Prf->wolist;
}

void prfs_SetWorkedOffClauses(PROOFSEARCH Prf, LIST Clauses)
{
  Prf->wolist = Clauses;
}

SHARED_INDEX prfs_WorkedOffSharingIndex(PROOFSEARCH Prf)
{
  return Prf->woindex;
}

LIST prfs_UsableClauses(PROOFSEARCH Prf)
{
  return Prf->uslist;
}

void prfs_SetUsableClauses(PROOFSEARCH Prf, LIST Clauses)
{
  Prf->uslist = Clauses;
}

SHARED_INDEX prfs_UsableSharingIndex(PROOFSEARCH Prf)
{
  return Prf->usindex;
}

LIST prfs_DocProofClauses(PROOFSEARCH Prf)
{
  return Prf->dplist;
}

void prfs_SetDocProofClauses(PROOFSEARCH Prf, LIST Clauses)
{
  Prf->dplist = Clauses;
}

SHARED_INDEX prfs_DocProofSharingIndex(PROOFSEARCH Prf)
{
  return Prf->dpindex;
}

void prfs_AddDocProofSharingIndex(PROOFSEARCH Prf)
{
  Prf->dpindex  = sharing_IndexCreate();
}

LIST prfs_GetFinMonPreds(PROOFSEARCH Prf)
{
  return Prf->finmonpreds;
}

void prfs_SetFinMonPreds(PROOFSEARCH Prf, LIST Preds)
{
  Prf->finmonpreds = Preds;
}

void prfs_DeleteFinMonPreds(PROOFSEARCH Prf)
{
  list_DeleteAssocListWithValues(Prf->finmonpreds,
				 (void (*)(POINTER)) term_DeleteTermList);
  prfs_SetFinMonPreds(Prf, list_Nil());
}

SORTTHEORY prfs_StaticSortTheory(PROOFSEARCH Prf)
{
  return Prf->astatic;
}

void prfs_SetStaticSortTheory(PROOFSEARCH Prf, SORTTHEORY Theory)
{
  Prf->astatic = Theory;
}

SORTTHEORY prfs_DynamicSortTheory(PROOFSEARCH Prf)
{
  return Prf->dynamic;
}

void prfs_SetDynamicSortTheory(PROOFSEARCH Prf, SORTTHEORY Theory)
{
  Prf->dynamic = Theory;
}

SORTTHEORY prfs_ApproximatedDynamicSortTheory(PROOFSEARCH Prf)
{
  return Prf->adynamic;
}

void prfs_SetApproximatedDynamicSortTheory(PROOFSEARCH Prf, SORTTHEORY Theory)
{
  Prf->adynamic = Theory;
}

PRECEDENCE prfs_Precedence(PROOFSEARCH Prf)
{
  return Prf->precedence;
}

FLAGSTORE prfs_Store(PROOFSEARCH Prf)
{
  return Prf->store;
}

BOOL prfs_SplitLevelCondition(NAT OriginLevel, NAT RedundantLevel, NAT BacktrackLevel)
{
  /*return (OriginLevel != RedundantLevel && OriginLevel != 0);*/
  /*return OriginLevel != 0;*/
  return (OriginLevel > RedundantLevel);
}

BOOL prfs_IsClauseValid(CLAUSE C, int Level)
{
  return clause_SplitLevel(C) <= Level;
}

SPLIT prfs_GetSplitOfLevel(int L, PROOFSEARCH Prf)
{
  LIST Scan;
  Scan = Prf->stack; 
  while (!list_Empty(Scan) &&
         (((SPLIT)list_Car(Scan))->splitlevel != L))
    Scan = list_Cdr(Scan);

  if (list_Empty(Scan)) {
    return (SPLIT) NULL;
  } else {
    return (SPLIT) list_Car(Scan);
  }
}

LIST prfs_SplitStack(PROOFSEARCH Prf)
{
  return Prf->stack;
}

SPLIT prfs_SplitStackTop(PROOFSEARCH Prf)
{
  return (SPLIT) list_Car(Prf->stack);
}

void prfs_SplitStackPop(PROOFSEARCH Prf)
{
  Prf->stack = list_Pop(Prf->stack);
}

void prfs_SplitStackPush(PROOFSEARCH Prf, SPLIT S)
{
  Prf->stack = list_Cons(S, Prf->stack);
}

BOOL prfs_SplitStackEmpty(PROOFSEARCH Prf)
{
  return list_StackEmpty(prfs_SplitStack(Prf));
}

int prfs_TopLevel(void) 
{
  return 0;
}

int prfs_ValidLevel(PROOFSEARCH Prf)
{
  return Prf->validlevel;
}

void prfs_SetValidLevel(PROOFSEARCH Prf, int Value)
{
  Prf->validlevel = Value;
}

void prfs_IncValidLevel(PROOFSEARCH Prf)
{
  (Prf->validlevel)++;
}

void prfs_DecValidLevel(PROOFSEARCH Prf)
{
  (Prf->validlevel)--;
}

int prfs_LastBacktrackLevel(PROOFSEARCH Prf)
{
  return Prf->lastbacktrack;
}

void prfs_SetLastBacktrackLevel(PROOFSEARCH Prf, int Value)
{
  Prf->lastbacktrack = Value;
}

int prfs_SplitCounter(PROOFSEARCH Prf)
{
  return Prf->splitcounter;
}

void prfs_SetSplitCounter(PROOFSEARCH Prf, int c)
{
  Prf->splitcounter = c;
}

void prfs_IncSplitCounter(PROOFSEARCH Prf)
{
  (Prf->splitcounter)++;
}

int prfs_KeptClauses(PROOFSEARCH Prf)
{
  return Prf->keptclauses;
}

void prfs_IncKeptClauses(PROOFSEARCH Prf)
{
  Prf->keptclauses++;
}

int prfs_DerivedClauses(PROOFSEARCH Prf)
{
  return Prf->derivedclauses;
}

void prfs_IncDerivedClauses(PROOFSEARCH Prf, int k)
{
  Prf->derivedclauses += k;
}

int prfs_Loops(PROOFSEARCH Prf)
{
  return Prf->loops;
}

void prfs_SetLoops(PROOFSEARCH Prf, int k)
{
  Prf->loops = k;
}

void prfs_DecLoops(PROOFSEARCH Prf)
{
  Prf->loops--;
}

int prfs_BacktrackedClauses(PROOFSEARCH Prf)
{
  return Prf->backtracked;
}

void prfs_SetBacktrackedClauses(PROOFSEARCH Prf, int k)
{
  Prf->backtracked = k;
}

void prfs_IncBacktrackedClauses(PROOFSEARCH Prf, int k)
{
  Prf->backtracked += k;
}

/**************************************************************/
/* Functions for accessing SPLIT objects                      */
/**************************************************************/

void prfs_SplitFree(SPLIT Sp)
{
  memory_Free(Sp, sizeof(SPLIT_NODE));
}

void prfs_SplitDelete(SPLIT S)
/**************************************************************
  INPUT:   A split 
  RETURNS: Nothing.
  MEMORY:  Deletes blocked and deleted clauses. Frees the split.
***************************************************************/
{
  clause_DeleteClauseList(S->blockedClauses);
  clause_DeleteClauseList(S->deletedClauses);
  if (S->father != (CLAUSE)NULL)
    clause_Delete(S->father);
  if (S->leftSplitfield != NULL) {
    memory_Free(S->leftSplitfield,
                sizeof(SPLITFIELDENTRY) * S->leftSplitfield_length);
    S->leftSplitfield = NULL;
  }
  if (S->rightSplitfield != NULL) {
    memory_Free(S->rightSplitfield,
                sizeof(SPLITFIELDENTRY) * S->rightSplitfield_length);
    S->rightSplitfield = NULL;
  }
  prfs_SplitFree(S);
}


LIST prfs_SplitBlockedClauses(SPLIT S)
{
  return S->blockedClauses;
}

void prfs_SplitAddBlockedClause(SPLIT S, CLAUSE C)
{
  S->blockedClauses = list_Cons(C,S->blockedClauses);
}

void prfs_SplitSetBlockedClauses(SPLIT S, LIST L)
{
  S->blockedClauses = L;
}

LIST prfs_SplitDeletedClauses(SPLIT S)
{
  return S->deletedClauses;
}

void prfs_SplitSetDeletedClauses(SPLIT S, LIST L)
{
  S->deletedClauses = L;
}

int prfs_SplitSplitLevel(SPLIT S)
{
  return S->splitlevel;
}

BOOL prfs_SplitIsLeft(SPLIT S)
{
  return S->isleft;
}

void prfs_SplitSetLeft(SPLIT S)
{
  S->isleft = TRUE;
}

void prfs_SplitSetRight(SPLIT S)
{
  S->isleft = FALSE;
}

BOOL prfs_SplitIsUsed(SPLIT S)
{
  return S->used;
}

BOOL prfs_SplitIsUnused(SPLIT S)
{
  return !S->used;
}

void prfs_SplitSetUsed(SPLIT S)
{
  S->used = TRUE;
}

CLAUSE prfs_SplitFatherClause(SPLIT S) 
{
  return S->father;
}

void prfs_SplitSetFatherClause(SPLIT S, CLAUSE C)
{
  S->father = C;
}

SPLITFIELD prfs_LeftSplitfield(SPLIT S, unsigned *Length)
{
  *Length = S->leftSplitfield_length;
  return S->leftSplitfield;
}

SPLITFIELD prfs_RightSplitfield(SPLIT S, unsigned *Length)
{
  *Length = S->rightSplitfield_length;
  return S->rightSplitfield;
}

void prfs_SplitFreeSplitfields(SPLIT S)
{
  if (S->leftSplitfield != NULL) {
    memory_Free(S->leftSplitfield,
                sizeof(SPLITFIELDENTRY) * S->leftSplitfield_length);
    S->leftSplitfield = NULL;
  }
  if (S->rightSplitfield != NULL) {
    memory_Free(S->rightSplitfield,
                sizeof(SPLITFIELDENTRY) * S->rightSplitfield_length);
    S->rightSplitfield = NULL;
  }
}


BOOL prfs_ExistsSplitOfLevel(int L, PROOFSEARCH PS)
{
  LIST Scan;
  Scan = PS->stack;

  while (!list_Empty(Scan) &&
   (((SPLIT)list_Car(Scan))->splitlevel != L  || ((SPLIT)list_Car(Scan))->used))
    Scan = list_Cdr(Scan);

  if (list_Empty(Scan)) {
    return FALSE;
  } else {
    return TRUE;
  }
}

BOOL prfs_SplitsAvailable(PROOFSEARCH PS, FLAGSTORE Store)
{
  return (flag_GetFlagIntValue(Store, flag_SPLITS) < 0 ||
	  prfs_SplitCounter(PS) < flag_GetFlagIntValue(Store, flag_SPLITS));
}

/**************************************************************/
/* Inline Functions ends here                                 */
/**************************************************************/

/**************************************************************/
/* Functions                                                  */
/**************************************************************/

static SPLIT prfs_SplitCreate(PROOFSEARCH PS)
/**************************************************************
  INPUT:   A proofsearch object
  RETURNS: A new split object, which is initialized.
  MEMORY:  Allocates memory for the SPLIT_NODE.
  EFFECT:  Increases the split level of the proof search object.
***************************************************************/
{
  SPLIT Result;

  prfs_IncValidLevel(PS);

  Result                 = (SPLIT)memory_Malloc(sizeof(SPLIT_NODE));
  Result->splitlevel     = prfs_ValidLevel(PS);
  Result->isleft         = TRUE;
  Result->used           = FALSE;
  Result->blockedClauses = list_Nil();
  Result->deletedClauses = list_Nil();
  Result->father         = (CLAUSE) NULL;
  Result->leftSplitfield = NULL;
  Result->leftSplitfield_length = 0;
  Result->rightSplitfield = NULL;
  Result->rightSplitfield_length = 0;
  /*printf("\nsplit: created split %d\n",Result->splitlevel);*/
  return Result;
}



/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *		    DEBUGGING FUNCTIONS	         	    * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/

BOOL prfs_Check(PROOFSEARCH Search)
/**************************************************************
  INPUT:   A proof search object.
  EFFECT:  None.
  RETURNS: TRUE if all invariants about <Search> are valid.
***************************************************************/
{
  LIST   Scan,Clauses;
  SPLIT  Split;
  CLAUSE Clause;

  for (Scan=prfs_UsableClauses(Search);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    Clause = (CLAUSE)list_Car(Scan);
    if (!clause_IsClause(Clause, prfs_Store(Search), prfs_Precedence(Search)) ||
	clause_GetFlag(Clause, WORKEDOFF) ||
	!prfs_IsClauseValid(Clause, prfs_ValidLevel(Search)))
      return FALSE;
  }

  for (Scan=prfs_WorkedOffClauses(Search);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    Clause = (CLAUSE)list_Car(Scan);
    if (!clause_IsClause(Clause, prfs_Store(Search), prfs_Precedence(Search)) ||
	!clause_GetFlag(Clause,WORKEDOFF) ||
	!prfs_IsClauseValid(Clause, prfs_ValidLevel(Search)))
      return FALSE;
  }

  for (Scan=prfs_SplitStack(Search); !list_Empty(Scan); Scan=list_Cdr(Scan)) {
    Split = (SPLIT)list_Car(Scan);
    if (prfs_SplitIsUsed(Split)) {
      if (!list_Empty(prfs_SplitBlockedClauses(Split)) ||
	  !list_Empty(prfs_SplitDeletedClauses(Split))) {
	/*putchar('\n');prfs_PrintSplit(Split); putchar('\n');*/
	return FALSE;
      } else {
	for (Clauses=prfs_UsableClauses(Search);!list_Empty(Clauses);Clauses=list_Cdr(Clauses))
	  if (clause_SplitLevel(list_Car(Clauses)) == prfs_SplitSplitLevel(Split)) {
	    /*puts("\n");prfs_PrintSplit(Split); 
	      fputs("\n Clause must not exist: ",stdout);
	      clause_Print(list_Car(Clauses)); putchar('\n');*/
	    return FALSE;
	  }
	for (Clauses=prfs_WorkedOffClauses(Search);!list_Empty(Clauses);Clauses=list_Cdr(Clauses))
	  if (clause_SplitLevel(list_Car(Clauses)) == prfs_SplitSplitLevel(Split)) {
	    /*puts("\n");prfs_PrintSplit(Split);
	      fputs("\n Clause must not exist: ",stdout);
	      clause_Print(list_Car(Clauses)); putchar('\n');*/
	    return FALSE;
	  }
      }
    } 
  }
  
  if (prfs_ValidLevel(Search) == 0) {
    if (!prfs_SplitStackEmpty(Search))
      return FALSE;
  } else {
    if (prfs_ValidLevel(Search) != prfs_SplitSplitLevel(prfs_SplitStackTop(Search)))
      return FALSE;
  }

  if (prfs_ValidLevel(Search) < prfs_LastBacktrackLevel(Search))
    return FALSE;

  return TRUE;
}

/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *			HIGH LEVEL FUNCTIONS		    * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/

static void prfs_InsertInSortTheories(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  EFFECT:  If the clause is a declaration clause it is inserted
           into the dynamic and approximated dynamic sort theory.
  RETURNS: Nothing.
***************************************************************/
{
  if ((prfs_DynamicSortTheory(Search) != (SORTTHEORY)NULL ||
       prfs_ApproximatedDynamicSortTheory(Search) != (SORTTHEORY)NULL) &&
      clause_IsDeclarationClause(Clause)) {
    int     i,l;
    LITERAL lit;
    CLAUSE  copy;
    LIST    approx;
    l = clause_Length(Clause);
    for (i = clause_FirstSuccedentLitIndex(Clause); i < l; i++) {
      lit = clause_GetLiteral(Clause,i);
      if (clause_LiteralIsMaximal(lit) && 
	  symbol_IsBaseSort(term_TopSymbol(clause_LiteralSignedAtom(lit)))) {
	if (prfs_DynamicSortTheory(Search) != (SORTTHEORY)NULL
	    && clause_NumOfSuccLits(Clause) == 1 && 
	    clause_NumOfAnteLits(Clause) == 0)
	  { 
	  copy = clause_Copy(Clause);
	  list_Delete(clause_ParentClauses(copy));
	  clause_SetParentClauses(copy,list_Nil());
	  list_Delete(clause_ParentLiterals(copy));
	  clause_SetParentLiterals(copy,list_Nil());
	  clause_SetNumber(copy,clause_Number(Clause));
	  sort_TheoryInsertClause(prfs_DynamicSortTheory(Search),Clause,
				  copy,clause_GetLiteral(copy,i));
	}
	if (prfs_ApproximatedDynamicSortTheory(Search) != (SORTTHEORY)NULL) {
	  approx = sort_ApproxMaxDeclClauses(Clause, prfs_Store(Search),
					     prfs_Precedence(Search));
	  for ( ; !list_Empty(approx); approx = list_Pop(approx)) {
	    copy = (CLAUSE)list_Car(approx);
	    sort_TheoryInsertClause(prfs_ApproximatedDynamicSortTheory(Search),
				    Clause, copy, 
				    clause_GetLiteral(copy,clause_FirstSuccedentLitIndex(copy)));
	  }
	}
      }
    }
  }
}


static void prfs_DeleteFromSortTheories(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  If the clause is a declaration clause it is deleted
           from the dynamic and approximated dynamic sort theory.
***************************************************************/
{
  if (clause_IsDeclarationClause(Clause)) {
    if (prfs_DynamicSortTheory(Search) != (SORTTHEORY)NULL)
      sort_TheoryDeleteClause(prfs_DynamicSortTheory(Search), Clause);
    if (prfs_ApproximatedDynamicSortTheory(Search) != (SORTTHEORY)NULL)
      sort_TheoryDeleteClause(prfs_ApproximatedDynamicSortTheory(Search), Clause);
  }
}


void prfs_DeleteDocProof(PROOFSEARCH Search)
/**************************************************************
  INPUT:   A proof search object.
  RETURNS: Nothing.
  EFFECT:  The docproof structures are deleted.
***************************************************************/
{
  clause_DeleteSharedClauseList(prfs_DocProofClauses(Search),
				prfs_DocProofSharingIndex(Search),
				prfs_Store(Search), prfs_Precedence(Search));
  if (prfs_DocProofSharingIndex(Search))
    sharing_IndexDelete(prfs_DocProofSharingIndex(Search));
  Search->dpindex = NULL;
  Search->dplist  = list_Nil();
}


static void prfs_InternalDelete(PROOFSEARCH Search)
/**************************************************************
  INPUT:   A proof search object.
  RETURNS: Nothing.
  EFFECT:  Most of the proofsearch object is deleted.
           This function implements the common subset of
	   functionality of prfs_Clean and prfs_Delete.
***************************************************************/
{
  LIST Scan;

  clause_DeleteClauseList(prfs_EmptyClauses(Search));
  list_DeleteWithElement(prfs_Definitions(Search),
			 (void (*)(POINTER)) def_Delete);
  list_Delete(prfs_UsedEmptyClauses(Search));
  sort_TheoryDelete(prfs_StaticSortTheory(Search));
  sort_TheoryDelete(prfs_DynamicSortTheory(Search));
  sort_TheoryDelete(prfs_ApproximatedDynamicSortTheory(Search));
  clause_DeleteSharedClauseList(prfs_WorkedOffClauses(Search),
				prfs_WorkedOffSharingIndex(Search),
				prfs_Store(Search), prfs_Precedence(Search));
  clause_DeleteSharedClauseList(prfs_UsableClauses(Search),
				prfs_UsableSharingIndex(Search),
				prfs_Store(Search), prfs_Precedence(Search));
  clause_DeleteSharedClauseList(prfs_DocProofClauses(Search),
				prfs_DocProofSharingIndex(Search),
				prfs_Store(Search), prfs_Precedence(Search));
  prfs_DeleteFinMonPreds(Search);
  for (Scan=prfs_SplitStack(Search); !list_Empty(Scan); Scan=list_Cdr(Scan))
    prfs_SplitDelete(list_Car(Scan));
  list_Delete(prfs_SplitStack(Search)); 
  ana_Clean(prfs_GetAnalyze(Search));
}


void prfs_Delete(PROOFSEARCH Search)
/**************************************************************
  INPUT:   A proof search object.
  RETURNS: Nothing.
  EFFECT:  The whole structure including all its substructures 
           is deleted.
***************************************************************/
{
  prfs_InternalDelete(Search);

  sharing_IndexDelete(prfs_WorkedOffSharingIndex(Search));
  sharing_IndexDelete(prfs_UsableSharingIndex(Search));
  if (prfs_DocProofSharingIndex(Search))
    sharing_IndexDelete(prfs_DocProofSharingIndex(Search));
  flag_DeleteStore(prfs_Store(Search));
  symbol_DeletePrecedence(prfs_Precedence(Search));
  ana_Free(prfs_GetAnalyze(Search));
  memory_Free(Search,sizeof(PROOFSEARCH_NODE));   
}


void prfs_Clean(PROOFSEARCH Search)
/**************************************************************
  INPUT:   A proof search object.
  RETURNS: Nothing.
  EFFECT:  All clauses are deleted. The structure is cleaned
           and initialized.
***************************************************************/
{
  prfs_InternalDelete(Search);

  Search->emptyclauses     = list_Nil();
  Search->definitions      = list_Nil();
  Search->usedemptyclauses = list_Nil();
  Search->wolist           = list_Nil();
  Search->uslist           = list_Nil();
  Search->finmonpreds      = list_Nil();
  Search->astatic          = (SORTTHEORY)NULL;
  Search->adynamic         = (SORTTHEORY)NULL;
  Search->dynamic          = (SORTTHEORY)NULL;
  Search->dplist           = list_Nil();
  
  Search->stack               = list_StackBottom();
  Search->validlevel          = 0;
  Search->lastbacktrack       = 0;
  Search->splitcounter        = 0;
  Search->keptclauses         = 0;
  Search->derivedclauses      = 0;
  Search->loops               = 0;
  Search->backtracked         = 0;

  symbol_ClearPrecedence(prfs_Precedence(Search));
}


void prfs_SwapIndexes(PROOFSEARCH Search)
/**************************************************************
  INPUT:   A proof search object.
  RETURNS: Nothing.
  EFFECT:  The usable and worked-off indexes are exchanged.
***************************************************************/
{
  LIST         Scan;
  SHARED_INDEX Help;

  Help = prfs_WorkedOffSharingIndex(Search);
  Scan = prfs_WorkedOffClauses(Search);
  prfs_SetWorkedOffClauses(Search,prfs_UsableClauses(Search));
  Search->woindex = prfs_UsableSharingIndex(Search);
  prfs_SetUsableClauses(Search, Scan);
  Search->usindex = Help;

  for (Scan=prfs_UsableClauses(Search); !list_Empty(Scan); Scan=list_Cdr(Scan))
    clause_RemoveFlag(list_Car(Scan), WORKEDOFF);
  for (Scan=prfs_WorkedOffClauses(Search);!list_Empty(Scan);Scan=list_Cdr(Scan))
    clause_SetFlag(list_Car(Scan), WORKEDOFF);
}


PROOFSEARCH prfs_Create(void)
/**************************************************************
  INPUT:   None.
  RETURNS: A new proof search object. The worked off and usable
           indexes are created whilst the docproof index and the
	   sort theories are not created, since they are not
	   needed in general.
***************************************************************/
{
  PROOFSEARCH Result;

  Result = memory_Malloc(sizeof(PROOFSEARCH_NODE));

  Result->emptyclauses = list_Nil();
  Result->definitions  = list_Nil();
  Result->usedemptyclauses = list_Nil();
  Result->woindex      = sharing_IndexCreate();
  Result->wolist       = list_Nil();
  Result->usindex      = sharing_IndexCreate();
  Result->uslist       = list_Nil();
  Result->finmonpreds  = list_Nil();

  Result->astatic      = (SORTTHEORY)NULL;
  Result->adynamic     = (SORTTHEORY)NULL;
  Result->dynamic      = (SORTTHEORY)NULL;

  Result->precedence   = symbol_CreatePrecedence();

  Result->store        = flag_CreateStore();
  flag_InitStoreByDefaults(Result->store);
  
  Result->dpindex      = (SHARED_INDEX)NULL;
  Result->dplist       = list_Nil();
  
  Result->stack               = list_StackBottom();
  Result->validlevel          = 0;
  Result->lastbacktrack       = 0;
  Result->splitcounter        = 0;
  Result->keptclauses         = 0;
  Result->derivedclauses      = 0;
  Result->loops               = 0;
  Result->backtracked         = 0;
  
  Result->analyze             = ana_Init();
    
  return Result;  
}


void prfs_CopyIndices(PROOFSEARCH Search, PROOFSEARCH SearchCopy) 
/**************************************************************
  INPUT:   A proof search object and a clean proof search object.
  RETURNS: Nothing.
  EFFECT:  Copies the indices from Search to SearchCopy.
  CAUTION: Splitstack and theories are not copied!
***************************************************************/
{
  LIST Scan;

  /* If a DocProof index is required but not yet allocated in SearchCopy,
     do it now */
  if (prfs_DocProofSharingIndex(Search) != NULL &&
      prfs_DocProofSharingIndex(SearchCopy) == NULL)
    prfs_AddDocProofSharingIndex(SearchCopy);

  /* Copy usable, worked-off and docproof index */
  for (Scan = prfs_UsableClauses(Search); !list_Empty(Scan); Scan = list_Cdr(Scan))
    prfs_InsertUsableClause(SearchCopy, clause_Copy((CLAUSE) list_Car(Scan)),TRUE);

  for (Scan = prfs_WorkedOffClauses(Search); !list_Empty(Scan); Scan = list_Cdr(Scan))
    prfs_InsertWorkedOffClause(SearchCopy, clause_Copy((CLAUSE) list_Car(Scan)));

  for (Scan = prfs_DocProofClauses(Search); !list_Empty(Scan); Scan = list_Cdr(Scan))
    prfs_InsertDocProofClause(SearchCopy, clause_Copy((CLAUSE) list_Car(Scan)));
}


void prfs_InsertWorkedOffClause(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  MEMORY:  The clause is assumed to be unshared.
  EFFECT:  The clause is inserted into the worked off sharing index
           and list of <Search>. The unshared literals are deleted.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsClause(Clause,prfs_Store(Search), prfs_Precedence(Search))) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_InsertWorkedOffClause: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  clause_SetFlag(Clause,WORKEDOFF);
  prfs_SetWorkedOffClauses(Search,list_Cons(Clause, prfs_WorkedOffClauses(Search)));
  clause_InsertIntoSharing(Clause, prfs_WorkedOffSharingIndex(Search),
			   prfs_Store(Search), prfs_Precedence(Search));
  prfs_InsertInSortTheories(Search, Clause);
}


void prfs_InsertUsableClause(PROOFSEARCH Search, CLAUSE Clause, BOOL SortUsable)
/**************************************************************
  INPUT:   A proof search object and a clause and aflag whether the 
           usable list should be kept sorted.
  RETURNS: Nothing.
  MEMORY:  The clause is assumed to be unshared.
  EFFECT:  The clause is inserted into the usable sharing index
           and list of <Search> sorted with respect to their weight. according to
           the value of <SortUsable>.
	   The unshared literals are deleted.
***************************************************************/
{

#ifdef CHECK
  if (!clause_IsClause(Clause, prfs_Store(Search), prfs_Precedence(Search)) ||
      clause_GetFlag(Clause, WORKEDOFF)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_InsertUsableClause: Illegal input.");
    misc_FinishErrorReport();
  }
  /* The invariant that no two clauses have the same clause number cannot  */
  /* be guaranteed as long as e.g. several directly subsequent reductions */
  /* are applied to a clause that eventually gets a greater split level.   */
#endif 
   
  if (SortUsable)
    prfs_SetUsableClauses(Search,clause_InsertWeighed(Clause,
						      prfs_UsableClauses(Search),
						      prfs_Store(Search),
						      prfs_Precedence(Search)));
  else
    prfs_SetUsableClauses(Search,list_Cons(Clause, prfs_UsableClauses(Search)));
  
  clause_InsertIntoSharing(Clause, prfs_UsableSharingIndex(Search),
			   prfs_Store(Search), prfs_Precedence(Search));
}


void prfs_InsertDocProofClause(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  MEMORY:  The clause is assumed to be unshared.
  EFFECT:  The clause is inserted into the proof documentation sharing index.
	   The unshared literals are deleted.
***************************************************************/
{ 
#ifdef CHECK
  if (!clause_IsClause(Clause, prfs_Store(Search), prfs_Precedence(Search))) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_InsertDocProofClause: Illegal input.");
    misc_FinishErrorReport();
  }
#endif   
  
  if (prfs_DocProofSharingIndex(Search) == (SHARED_INDEX)NULL)
    clause_Delete(Clause);
  else {
    prfs_SetDocProofClauses(Search,list_Cons(Clause, prfs_DocProofClauses(Search)));
    clause_InsertIntoSharing(Clause, prfs_DocProofSharingIndex(Search),
			     prfs_Store(Search), prfs_Precedence(Search));
  }
}


void prfs_MoveUsableWorkedOff(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  The clause is inserted into the worked off sharing index
           and list and it is deleted from the usable index and list.
	   In particular, the WorkedOff flag is set and if <Clause> is a 
	   declaration clause, it is inserted into the respective sort theories.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsClause(Clause,prfs_Store(Search), prfs_Precedence(Search)) ||
      clause_GetFlag(Clause, WORKEDOFF)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_MoveUsableWorkedOff: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  prfs_SetUsableClauses(Search,list_PointerDeleteElement(prfs_UsableClauses(Search),Clause));
  clause_SetFlag(Clause,WORKEDOFF);
  clause_MoveSharedClause(Clause, prfs_UsableSharingIndex(Search),
			  prfs_WorkedOffSharingIndex(Search), prfs_Store(Search),
			  prfs_Precedence(Search));
  prfs_SetWorkedOffClauses(Search,list_Cons(Clause, prfs_WorkedOffClauses(Search)));
  prfs_InsertInSortTheories(Search, Clause);
}


void prfs_MoveWorkedOffDocProof(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  The clause is inserted into the doc proof sharing index
           and list of <Search> and it is deleted from the worked off
	   index and list.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsClause(Clause, prfs_Store(Search), prfs_Precedence(Search)) ||
      !clause_GetFlag(Clause, WORKEDOFF)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_MoveWorkedOffDocProof: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  prfs_DeleteFromSortTheories(Search, Clause);
  prfs_SetWorkedOffClauses(Search,list_PointerDeleteElement(prfs_WorkedOffClauses(Search),Clause));
  clause_RemoveFlag(Clause,WORKEDOFF);

  if (prfs_DocProofSharingIndex(Search) == (SHARED_INDEX)NULL)
    clause_DeleteFromSharing(Clause,prfs_WorkedOffSharingIndex(Search),
			     prfs_Store(Search), prfs_Precedence(Search));
  else {
    clause_MoveSharedClause(Clause, prfs_WorkedOffSharingIndex(Search),
			    prfs_DocProofSharingIndex(Search),prfs_Store(Search),
			    prfs_Precedence(Search));
    prfs_SetDocProofClauses(Search,list_Cons(Clause, prfs_DocProofClauses(Search)));
  }
}


void prfs_MoveUsableDocProof(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  The clause is inserted into the doc proof sharing index
           and list of <Search> and it is deleted from the usable
	   index and list.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsClause(Clause, prfs_Store(Search), prfs_Precedence(Search)) ||
      clause_GetFlag(Clause, WORKEDOFF)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_MoveUsableDocProof: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  prfs_SetUsableClauses(Search,list_PointerDeleteElement(prfs_UsableClauses(Search),Clause));

  if (prfs_DocProofSharingIndex(Search) == (SHARED_INDEX)NULL)
    clause_DeleteFromSharing(Clause, prfs_UsableSharingIndex(Search),
			     prfs_Store(Search), prfs_Precedence(Search));
  else {
    clause_MoveSharedClause(Clause, prfs_UsableSharingIndex(Search),
			    prfs_DocProofSharingIndex(Search),prfs_Store(Search),
			    prfs_Precedence(Search));
    prfs_SetDocProofClauses(Search,list_Cons(Clause, prfs_DocProofClauses(Search)));
  }
}


void prfs_MoveInvalidClausesDocProof(PROOFSEARCH Search)
/**************************************************************
  INPUT:   A proof search object.
  RETURNS: Nothing.
  EFFECT:  All clauses that have a split level higher than the
           current split level of <Search> are moved to the
	   proof documentation index. If it does not exist, i.e.,
	   no proof documentation required, the clauses are
	   deleted.
***************************************************************/
{
  LIST   scan, invalid;
  CLAUSE clause;

  invalid = list_Nil();
  for (scan = prfs_WorkedOffClauses(Search); !list_Empty(scan);
       scan = list_Cdr(scan)) {
    clause = (CLAUSE)list_Car(scan);
    if ( clause_SplitLevel(clause) != 0 && !prfs_ExistsSplitOfLevel(clause_SplitLevel(clause), Search)  )
      invalid = list_Cons(clause,invalid);
  }
  /* WARNING: The following move operation changes the worked off */
  /* set of the proof search object destructively.                */
  /* So it's impossible to move those function calls into the     */
  /* loop above.                                                  */
  for ( ; !list_Empty(invalid); invalid = list_Pop(invalid))
    prfs_MoveWorkedOffDocProof(Search,list_Car(invalid));

  invalid = list_Nil();
  for (scan = prfs_UsableClauses(Search); !list_Empty(scan);
       scan = list_Cdr(scan)) {
    clause = (CLAUSE)list_Car(scan);
    if ( clause_SplitLevel(clause) != 0 && !prfs_ExistsSplitOfLevel(clause_SplitLevel(clause), Search)  )
      invalid = list_Cons(clause,invalid);
  }
  /* WARNING: The following move operation changes the usable     */
  /* set of the proof search object destructively.                */
  /* So it's impossible to move those function calls into the     */
  /* loop above.                                                  */
  for ( ; !list_Empty(invalid); invalid = list_Pop(invalid))
    prfs_MoveUsableDocProof(Search,list_Car(invalid));
}


void prfs_ExtractWorkedOff(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  The clause is removed from the worked off index and
           list and returned as an unshared clause.
	   Sort theories are updated accordingly.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsUnorderedClause(Clause) || !clause_GetFlag(Clause, WORKEDOFF)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_ExtractWorkedOff: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  prfs_DeleteFromSortTheories(Search, Clause);
  clause_RemoveFlag(Clause,WORKEDOFF);
  prfs_SetWorkedOffClauses(Search,list_PointerDeleteElement(prfs_WorkedOffClauses(Search),Clause));
  clause_MakeUnshared(Clause,prfs_WorkedOffSharingIndex(Search));
}


void prfs_ExtractUsable(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  The clause is removed from the usable off index and
           list and returned as an unshared clause.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsUnorderedClause(Clause) || clause_GetFlag(Clause, WORKEDOFF)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_ExtractUsable: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  prfs_SetUsableClauses(Search,list_PointerDeleteElement(prfs_UsableClauses(Search),Clause));
  clause_MakeUnshared(Clause,prfs_UsableSharingIndex(Search));
}


void prfs_ExtractDocProof(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  The clause is removed from the docproof off index and
           list and returned as an unshared clause.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsUnorderedClause(Clause)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_ExtractDocProof: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  prfs_SetDocProofClauses(Search,list_PointerDeleteElement(prfs_DocProofClauses(Search),Clause));
  clause_MakeUnshared(Clause,prfs_DocProofSharingIndex(Search));
}


void prfs_DeleteWorkedOff(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  The clause is deleted from the worked off index and list.
	   Sort theories are updated accordingly.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsClause(Clause, prfs_Store(Search), prfs_Precedence(Search)) ||
      !clause_GetFlag(Clause, WORKEDOFF)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_DeleteWorkedOff: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  prfs_DeleteFromSortTheories(Search, Clause);
  prfs_SetWorkedOffClauses(Search,list_PointerDeleteElement(prfs_WorkedOffClauses(Search),Clause));
  clause_DeleteFromSharing(Clause, prfs_WorkedOffSharingIndex(Search),
			   prfs_Store(Search), prfs_Precedence(Search));
}


void prfs_DeleteUsable(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  The clause is deleted from the usable index and list.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsClause(Clause, prfs_Store(Search), prfs_Precedence(Search)) ||
      clause_GetFlag(Clause, WORKEDOFF)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_DeleteUsable: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  prfs_SetUsableClauses(Search,list_PointerDeleteElement(prfs_UsableClauses(Search),Clause));
  clause_DeleteFromSharing(Clause,prfs_UsableSharingIndex(Search),
			   prfs_Store(Search), prfs_Precedence(Search));
}

void prfs_DeleteDocProofClause(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and a clause.
  RETURNS: Nothing.
  EFFECT:  The clause is deleted from the doc proof index and list.
***************************************************************/
{
#ifdef CHECK
  if (!clause_IsClause(Clause, prfs_Store(Search), prfs_Precedence(Search)) ||
      clause_GetFlag(Clause, WORKEDOFF)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_DeleteUsable: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  prfs_SetDocProofClauses(Search,list_PointerDeleteElement(prfs_DocProofClauses(Search),Clause));
  clause_DeleteFromSharing(Clause,prfs_DocProofSharingIndex(Search),
			   prfs_Store(Search), prfs_Precedence(Search));
}


void prfs_PrintSplit(SPLIT Split)
/**************************************************************
  INPUT:   A split.
  RETURNS: Nothing.
  EFFECT:  Prints the information kept in the split structure.
***************************************************************/
{
  LIST Scan;

  printf("\n Split: %d %ld", prfs_SplitSplitLevel(Split), (long)Split);
  fputs("\n Father: ", stdout);
  if (prfs_SplitFatherClause(Split) != (CLAUSE)NULL)
    clause_Print(prfs_SplitFatherClause(Split));
  else
    fputs("No father, unnecessary split.", stdout);
  
  fputs("\n Split is ", stdout);
  if (prfs_SplitIsUnused(Split))
    puts("unused.");
  else
    puts("used.");
  fputs(" Blocked clauses:", stdout);
  for (Scan=prfs_SplitBlockedClauses(Split);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    putchar('\n');
    putchar(' ');
    clause_Print(list_Car(Scan));
  }
  fputs("\n Deleted clauses:", stdout);
  for (Scan=prfs_SplitDeletedClauses(Split);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    putchar('\n');
    putchar(' ');
    clause_Print(list_Car(Scan));
  }
}


void prfs_PrintSplitStack(PROOFSEARCH PS)
/**************************************************************
  INPUT:   A proof search object.
  RETURNS: Nothing.
  EFFECT:  Prints almost all the information kept in the
           split stack structure.
***************************************************************/
{
  LIST Scan;

  fputs("\n Splitstack:", stdout);

  for (Scan = prfs_SplitStack(PS); !list_Empty(Scan); Scan = list_Cdr(Scan)) {
    prfs_PrintSplit(list_Car(Scan));
    fputs("\n---------------------", stdout);
  }
}


void prfs_Print(PROOFSEARCH Search)
/**************************************************************
  INPUT:   A proof search object.
  RETURNS: void.
  EFFECT:  The proof search object is printed to stdout.
***************************************************************/
{
  LIST Scan;

#ifdef CHECK
  if (!prfs_Check(Search)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_Print: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  printf("\n\n Proofsearch: Current Level: %d Last Backtrack Level: %d Splits: %d Loops: %d Backtracked: %d",
	 prfs_ValidLevel(Search),prfs_LastBacktrackLevel(Search),prfs_SplitCounter(Search),
	 prfs_Loops(Search),prfs_BacktrackedClauses(Search));
  if (ana_NonTrivClauseNumber(prfs_GetAnalyze(Search))>0)
    printf("\n Clause %zd implies a non-trivial domain.", ana_NonTrivClauseNumber(prfs_GetAnalyze(Search)));
  else
    fputs("\n Potentially trivial domain.", stdout);
  fputs("\n Empty Clauses:", stdout);
  for (Scan=prfs_EmptyClauses(Search);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    fputs("\n ", stdout);
    clause_Print(list_Car(Scan));
  }
  fputs("\n Definitions:", stdout);
  for (Scan=prfs_Definitions(Search);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    putchar('\n');
    putchar(' ');
    term_Print(list_Car(Scan));
  }
  fputs("\n Worked Off Clauses:", stdout);
  for (Scan=prfs_WorkedOffClauses(Search);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    putchar('\n');
    putchar(' ');
    clause_Print(list_Car(Scan));
  }
  fputs("\n Usable Clauses:", stdout);
  for (Scan=prfs_UsableClauses(Search);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    putchar('\n');
    putchar(' ');
    clause_Print(list_Car(Scan));
  }
  fputs("\n Finite predicates:", stdout);
  for (Scan=prfs_GetFinMonPreds(Search);!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    fputs("\n  ", stdout);
    symbol_Print((SYMBOL)list_PairFirst(list_Car(Scan)));
    fputs(": ", stdout);
    term_TermListPrintPrefix(list_PairSecond(list_Car(Scan)));
  }
  prfs_PrintSplitStack(Search);
  fputs("\n Static Sort Theory:", stdout);
  sort_TheoryPrint(prfs_StaticSortTheory(Search));
  fputs("\n Dynamic Sort Theory:", stdout);
  sort_TheoryPrint(prfs_DynamicSortTheory(Search));
  fputs("\n Approximated Dynamic Sort Theory:", stdout);
  sort_TheoryPrint(prfs_ApproximatedDynamicSortTheory(Search));
  putchar('\n');
}


CLAUSE prfs_DoSplitting(PROOFSEARCH PS, CLAUSE SplitClause, LIST Literals)
/**************************************************************
  INPUT:   An proof search object, an unshared clause to be splitted
           where 'Literals' is the list of literals to keep (in their
	   order in the SplitClause).
  RETURNS: A pointer to the (stack-, not sharing-) inserted splitted clause.
  MEMORY:  The blocked parts and the actparts literals are created
           unshared, memory for the two (more for HornSplits) new 
	   clausenodes is allocated.
  EFFECT:  A new SPLIT object is created on the split stack of the proof
           search object. The clause for the right branch will get clause
           number 0 to make it distinguishable from the negation clauses,
	   which get clause number -1.
           All newly created clauses are influenced by some flags of the
           internal flag store of the proof search object.
	   For example the maximal literals are influenced by
	   the weight of function symbols, which is defined by the
	   flag "flag_FUNCWEIGHT".
***************************************************************/
{

  SPLIT   NewSplit;
  CLAUSE  NewClause, BlockedClause;
  LITERAL NextLit,NewLit;
  int     i,j,lengthBlocked,lengthNew,lc,la,ls,nc,na,ns;

#ifdef CHECK
  if (list_Empty(Literals) ||
      !clause_IsClause(SplitClause, prfs_Store(PS), prfs_Precedence(PS))) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_DoSplitting: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  prfs_IncSplitCounter(PS);
  NewSplit = prfs_SplitCreate(PS);

  prfs_SplitSetFatherClause(NewSplit, SplitClause);

  lengthNew = list_Length(Literals);
  lengthBlocked = clause_Length(SplitClause) - lengthNew;

  NewClause = clause_CreateBody(lengthNew);          /* The left  clause */
  BlockedClause = clause_CreateBody(lengthBlocked);  /* The right clause */
  clause_DecreaseCounter(); /* reset internally increased counter! */
  clause_SetNumber(BlockedClause, 0);
  /* To detect forgotten setting at insertion! */

  lc = clause_LastConstraintLitIndex(SplitClause);
  la = clause_LastAntecedentLitIndex(SplitClause);
  ls = clause_LastSuccedentLitIndex(SplitClause);

  nc = na = ns = 0;

  j = clause_FirstLitIndex();

  for (i = clause_FirstLitIndex(); i <= ls; i++) {
    NextLit = clause_GetLiteral(SplitClause, i);

    NewLit  = clause_LiteralCopy(NextLit);

    if ((lengthNew > 0) && /* To avoid access of Nirvana. */
	list_PointerMember(Literals, NextLit)) {
      /* NewLit is literal for the NewClause. */

      lengthNew--;
      clause_SetLiteral(NewClause, j++, NewLit);
      clause_LiteralSetOwningClause(NewLit, NewClause);
      clause_AddParentClause(NewClause, clause_Number(SplitClause));
      clause_AddParentLiteral(NewClause, i);
      if (i <= lc)
	nc++;
      else if (i <= la)
	na++;
      else 
	ns++;

    } else { /* NewLit is literal for the BlockedClause. */

      clause_SetLiteral(BlockedClause, (i-j), NewLit);
      clause_LiteralSetOwningClause(NewLit, BlockedClause);
      clause_AddParentClause(BlockedClause, clause_Number(SplitClause));
      clause_AddParentLiteral(BlockedClause, i);
    }
  } /* end of 'for all literals'. */

  clause_SetNumOfConsLits(NewClause, nc);
  clause_SetNumOfConsLits(BlockedClause,
			  (clause_NumOfConsLits(SplitClause) - nc));
  clause_SetNumOfAnteLits(NewClause, na);
  clause_SetNumOfAnteLits(BlockedClause,
			  (clause_NumOfAnteLits(SplitClause) - na));
  clause_SetNumOfSuccLits(NewClause, ns);
  clause_SetNumOfSuccLits(BlockedClause,
			  (clause_NumOfSuccLits(SplitClause) - ns));

  clause_ReInit(BlockedClause, prfs_Store(PS), prfs_Precedence(PS));
  clause_UpdateSplitDataFromNewSplitting(BlockedClause, SplitClause,
					 prfs_SplitSplitLevel(NewSplit));
  clause_SetFromSplitting(BlockedClause);
  clause_SetParentLiterals(BlockedClause,
			   list_NReverse(clause_ParentLiterals(BlockedClause)));

  clause_SetDepth(BlockedClause, clause_Depth(SplitClause)+1);

  prfs_SplitAddBlockedClause(NewSplit, BlockedClause);
  prfs_SplitSetDeletedClauses(NewSplit, list_Nil());

  
  prfs_SplitStackPush(PS, NewSplit);

  clause_ReInit(NewClause, prfs_Store(PS), prfs_Precedence(PS));
  clause_UpdateSplitDataFromNewSplitting(NewClause, SplitClause,
					 prfs_SplitSplitLevel(NewSplit));
  clause_SetFromSplitting(NewClause);

  clause_SetParentLiterals(NewClause,
			   list_NReverse(clause_ParentLiterals(NewClause)));

  clause_SetDepth(NewClause, clause_Depth(SplitClause)+1);
  clause_RemoveFlag(NewClause, WORKEDOFF);

  if (clause_IsGround(NewClause)) {
    /* Keep Clauses made from NewClause for refutation case! */
    CLAUSE UnitClause;
    LIST   AtomList;

    la = clause_LastAntecedentLitIndex(NewClause);
    ls = clause_LastSuccedentLitIndex(NewClause);

    Literals = clause_ParentLiterals(NewClause);

    for (i = clause_FirstLitIndex(); i <= ls; i++) {

      NextLit    = clause_GetLiteral(NewClause, i);
      AtomList   = list_List(term_Copy(clause_LiteralAtom(NextLit)));

      if (i <= la)
	UnitClause = clause_Create(list_Nil(), list_Nil(), AtomList,
				   prfs_Store(PS), prfs_Precedence(PS));
      else
	UnitClause = clause_Create(list_Nil(), AtomList, list_Nil(),
				   prfs_Store(PS), prfs_Precedence(PS));

      clause_SetNumber(UnitClause, -1);
      /* To detect forgotten setting at reinsertion! */
      clause_DecreaseCounter();
      /* Reset internally increased counter! */

      list_Delete(AtomList);

      clause_SetFromSplitting(UnitClause);
      clause_UpdateSplitDataFromNewSplitting(UnitClause, SplitClause,
					     prfs_SplitSplitLevel(NewSplit));
      clause_AddParentClause(UnitClause, clause_Number(NewClause));
      clause_AddParentLiteral(UnitClause, i);
      clause_AddParentClause(UnitClause, clause_Number(SplitClause));
      clause_AddParentLiteral(UnitClause, (intptr_t)list_Car(Literals));
      Literals = list_Cdr(Literals);
      prfs_SplitAddBlockedClause(NewSplit, UnitClause);
    }
  }
  /* fputs("\n\nSPLITTING DONE!",stdout);
     fputs("\nAus           : ",stdout); clause_Print(SplitClause); fflush(stdout);
     fputs("\nDer erste Teil: ",stdout); clause_Print(NewClause); fflush(stdout);
     fputs("\nDer zweite Teil: ",stdout);
     clause_Print(BlockedClause); fflush(stdout);
     puts("\nDaher als BlockedClauses:");
     clause_ListPrint(prfs_SplitBlockedClauses(NewSplit)); fflush(stdout);
  */
  return NewClause;
}


static LIST prfs_GetSplitLiterals(PROOFSEARCH PS, CLAUSE Clause)
/**************************************************************
  INPUT:   A Clause and a proofsearch object
  RETURNS: A list of literals building the bigger part of a 
           variable-disjunct literal partition if one exists,
	   an empty list, else.
  MEMORY:  Allocates memory for the literal list.
***************************************************************/
{
  LITERAL NextLit;
  int     i, length, OldLength;
  LIST    LitList, VarOcc, NextOcc;
  BOOL    Change;

#ifdef CHECK
  if (!clause_IsClause(Clause, prfs_Store(PS), prfs_Precedence(PS))) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In prfs_GetSplitLiterals: Illegal input.");
    misc_FinishErrorReport();
  }
#endif 

  LitList = list_Nil();

  if (prfs_SplitCounter(PS) != 0) {

    if (clause_HasSuccLits(Clause)) {
      if (clause_HasGroundSuccLit(Clause)) {

	NextLit = clause_GetGroundSuccLit(Clause);
	LitList = list_Cons(NextLit, LitList);

	for (i = clause_LastAntecedentLitIndex(Clause);i >= clause_FirstLitIndex();i--) {
	  NextLit = clause_GetLiteral(Clause, i);
	  if (term_IsGround(clause_LiteralAtom(NextLit)))
	    LitList = list_Cons(NextLit, LitList);
	}
	return LitList;
      }

      /* Clause has no ground succedent literals, but > 1 non-ground */
      NextLit = clause_GetLiteral(Clause, clause_LastSuccedentLitIndex(Clause));
      VarOcc  = term_VariableSymbols(clause_LiteralAtom(NextLit));
      LitList = list_List(NextLit);
      length  = clause_Length(Clause);
      Change  = TRUE;

      while (Change) {
	Change = FALSE;

	for (i=clause_LastSuccedentLitIndex(Clause)-1; i>=clause_FirstLitIndex(); i--) {

	  NextLit = clause_GetLiteral(Clause, i);
	
	  if (!list_PointerMember(LitList, NextLit)) {
	    NextOcc = term_VariableSymbols(clause_LiteralAtom(NextLit));
	    if (list_HasIntersection(VarOcc, NextOcc)) { 
	      OldLength = list_Length(VarOcc);
	      VarOcc    = list_NPointerUnion(VarOcc, NextOcc);
	      LitList   = list_Cons(NextLit, LitList);
	      if (OldLength != list_Length(VarOcc))
		Change = TRUE;
	    }
	    else
	      list_Delete(NextOcc);
	  }
	}
      }
      if (list_Length(LitList) == length) {
	list_Delete(LitList);
	LitList = list_Nil();
      }
      Change = TRUE;    /* Check whether not all succedent literals are used */
      for (i = clause_FirstSuccedentLitIndex(Clause); i < length && Change; i++)
	if (!list_PointerMember(LitList,clause_GetLiteral(Clause, i)))
	  Change = FALSE;
      if (Change) {
	list_Delete(LitList);
	LitList = list_Nil();
      }
      list_Delete(VarOcc);
    }
  }
  return LitList;
}


CLAUSE prfs_PerformSplitting(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proof search object and an unshared clause.
  EFFECT:  If <Clause> can be split it is splitted, the first
           part of the split is returned  and the
	   splitted clause is kept in the split stack.
	   Otherwise <Clause> remains unchanged and NULL is returned.
  RETURNS: NULL if <Clause> is not splittable, the first split part otherwise.
***************************************************************/
{
  CLAUSE Result;

  Result = (CLAUSE)NULL;
  
  if (clause_HasSolvedConstraint(Clause)) {
    LIST LitList;

    LitList = prfs_GetSplitLiterals(Search, Clause);

    if (!list_Empty(LitList)) {
      Result = prfs_DoSplitting(Search, Clause, LitList);
      list_Delete(LitList);
    }
  }

  return Result;
}


void prfs_InstallFiniteMonadicPredicates(PROOFSEARCH Search, LIST Clauses,
					 LIST Predicates)
/**************************************************************
  INPUT:   A proof search object a list of clauses and a list
           of monadic predicates.
  RETURNS: Nothing.
  EFFECT:  The argument terms for <Predicates> that occur in
           positive unit clauses are extracted from <Clauses>
           and installed in <Search> as an assoc list.
***************************************************************/
{
  LIST   Pair, Scan, Result;
  CLAUSE Clause;
  TERM   Atom;

  Result = list_Nil();

  for (Scan=Clauses;!list_Empty(Scan);Scan=list_Cdr(Scan)) {
    Clause = (CLAUSE)list_Car(Scan);
    if (clause_Length(Clause) == 1 &&
	clause_NumOfSuccLits(Clause) == 1) {
      Atom = clause_GetLiteralAtom(Clause,clause_FirstSuccedentLitIndex(Clause));
      if (list_PointerMember(Predicates, (POINTER)term_TopSymbol(Atom))) {
	Pair = list_AssocListPair(Result, (POINTER)term_TopSymbol(Atom));
	if (Pair != list_PairNull())
	  list_PairRplacSecond(Pair, list_Cons(term_Copy(term_FirstArgument(Atom)),list_PairSecond(Pair)));
	else
	  Result = list_AssocCons(Result, (POINTER)term_TopSymbol(Atom), 
				  list_List(term_Copy(term_FirstArgument(Atom))));
      }
    }
  }
  
  prfs_DeleteFinMonPreds(Search);
  prfs_SetFinMonPreds(Search, Result);
}


NAT prfs_GetNumberOfInstances(PROOFSEARCH Search, LITERAL Literal, BOOL Usables)
/**************************************************************
  INPUT:   A proof search object, a literal, and a boolean flag.
  RETURNS: The number of clauses containing an instance of the literal's atom.
  EFFECT:  Uses the clause marking mechansim
***************************************************************/
{
  TERM         Atom;
  NAT          NrOfInstances;
  SHARED_INDEX WOIndex, UsIndex;
  LIST         Scan;

  NrOfInstances = 0;
  Atom          = clause_LiteralAtom(Literal);
  WOIndex       = prfs_WorkedOffSharingIndex(Search);
  UsIndex       = prfs_UsableSharingIndex(Search);

  for(Scan= prfs_WorkedOffClauses(Search);!list_Empty(Scan);Scan=list_Cdr(Scan))
    clause_RemoveFlag(list_Car(Scan), MARK);
  if (Usables)
    for(Scan= prfs_UsableClauses(Search);!list_Empty(Scan);Scan=list_Cdr(Scan))
      clause_RemoveFlag(list_Car(Scan), MARK);

  if (fol_IsEquality(Atom) && clause_LiteralIsPositive(Literal) && clause_LiteralIsOrientedEquality(Literal)) {
    NrOfInstances = clause_GetNumberOfInstances(term_FirstArgument(Atom), WOIndex);
    if (Usables)
      NrOfInstances += clause_GetNumberOfInstances(term_FirstArgument(Atom), UsIndex);
  } else {    
    NrOfInstances = clause_GetNumberOfInstances(Atom, WOIndex);
    if (Usables)
      NrOfInstances += clause_GetNumberOfInstances(Atom, UsIndex);
  }
    
  return NrOfInstances;
}

void prfs_SetLeftSplitfield(SPLIT S, SPLITFIELD SF, unsigned Length)
{
  unsigned i;

  if (SF != S->leftSplitfield) {
    if (S->leftSplitfield != NULL)
      memory_Free(S->leftSplitfield,
                  sizeof(SPLITFIELDENTRY) * S->leftSplitfield_length);
    S->leftSplitfield = memory_Malloc(Length * sizeof(SPLITFIELDENTRY));

    for (i=0; i < Length; i++) {
      S->leftSplitfield[i] = SF[i];
    }

    S->leftSplitfield_length = Length;
  }
}

void prfs_SetRightSplitfield(SPLIT S, SPLITFIELD SF, unsigned Length)
{
  unsigned i;

  if (SF != S->rightSplitfield) {
    if (S->rightSplitfield != NULL)
      memory_Free(S->rightSplitfield,
                  sizeof(SPLITFIELDENTRY) * S->rightSplitfield_length);
    S->rightSplitfield = memory_Malloc(Length * sizeof(SPLITFIELDENTRY));

    for (i=0; i < Length; i++) {
      S->rightSplitfield[i] = SF[i];
    }

    S->rightSplitfield_length = Length;
  }
}

BOOL prfs_SplitfieldContainsLevel(SPLITFIELD SF, unsigned Length, NAT n)
{
  uintptr_t field, offset;

  offset = clause_ComputeSplitFieldAddress(n, &field);
  if (field < Length)
    return (SF[field] & ((SPLITFIELDENTRY)1 << n)) != 0;
  else
    return FALSE;
}

NAT prfs_SplitfieldHighestLevel(SPLITFIELD SF, unsigned Length)
{
  unsigned i, max_offset=0;

  if (Length>0) {
    for (i=0; i<sizeof(SPLITFIELDENTRY)*CHAR_BIT; i++)
      if ((SF[Length-1] & ((SPLITFIELDENTRY)1 << i)) != 0)
        max_offset = i;
    return (Length-1)*sizeof(SPLITFIELDENTRY)*CHAR_BIT + max_offset;
  } else
    return 0;
}


void prfs_AddLevelToSplitfield(SPLITFIELD *SF, unsigned *Length, NAT n)
{
  uintptr_t field, offset;
  int i;
  SPLITFIELD new_SF;

  offset = clause_ComputeSplitFieldAddress(n, &field);
  if (field >= *Length) {
    new_SF = memory_Malloc((field+1) * sizeof(SPLITFIELDENTRY));
    for (i=0; i < *Length; i++) {
      new_SF[i] = (*SF)[i];
    }
    for (i= *Length; i <= field; i++) {
      new_SF[i] = 0;
    }
    new_SF[field] = new_SF[field] | ((SPLITFIELDENTRY)1 << offset);
    if (*SF != NULL)
      memory_Free(*SF,
        sizeof(SPLITFIELDENTRY) * (*Length));
    *SF = new_SF;
    *Length = field+1;
  } else {
    (*SF)[field] = (*SF)[field] | ((SPLITFIELDENTRY)1 << offset);
  }
}

void prfs_RemoveLevelFromSplitfield(SPLITFIELD *SF, unsigned *Length, NAT n)
{
  uintptr_t field, offset;
  int i;
  BOOL allzero;
  SPLITFIELD new_SF;

  if ((*SF != NULL) & (*Length > 0)) {
    offset = clause_ComputeSplitFieldAddress(n, &field);
    if (field < *Length) {
      (*SF)[field] = (*SF)[field] & (~((SPLITFIELDENTRY)1 << offset));
    }

    /* restore minimal length */
    if ((*SF)[(*Length)-1] == (SPLITFIELDENTRY)0) {
      allzero = TRUE;
      for (i=(*Length)-1; i>0; i--) {
        if ((*SF)[i] == (SPLITFIELDENTRY)0) {
          if (allzero)
            field = i;
        } else
          allzero = FALSE;
      }
      /* now: field == maximal m such that (*SF)[i]==0 for all i>=m */
      if (field == 0 && *SF != NULL) {
        memory_Free(*SF,
          sizeof(SPLITFIELDENTRY) * (*Length));
        *Length = 0;
      } else {
        new_SF = memory_Malloc(field * sizeof(SPLITFIELDENTRY));
        for (i=0; i < field; i++) {
          new_SF[i] = (*SF)[i];
        }
        if (*SF != NULL)
          memory_Free(*SF,
            sizeof(SPLITFIELDENTRY) * (*Length));
        *SF = new_SF;
        *Length = field;
      }
    }
  }

}

BOOL prfs_SplitfieldIsSubset(SPLITFIELD SF1, unsigned Length1, SPLITFIELD SF2, unsigned Length2)
{
  BOOL subset;
  int i;

  if (Length1 <= Length2) {
    subset = TRUE;
    for (i=0; i < Length1; i++) {
      if ((SPLITFIELDENTRY)(SF2[i] | SF1[i]) != SF2[i]) {
        subset = FALSE;
      }
    }
  } else
    subset = FALSE;

  return subset;
}

SPLITFIELD prfs_SplitfieldUnion(SPLITFIELD leftSF, unsigned leftSF_length,
                                SPLITFIELD rightSF, unsigned rightSF_length,
                                unsigned *result_length)
{
  unsigned max_length;
  unsigned i;
  SPLITFIELD result=NULL;

  if (leftSF_length > rightSF_length)
    max_length = leftSF_length;
  else
    max_length = rightSF_length;

  if (max_length > 0) {
    result = memory_Malloc(max_length * sizeof(SPLITFIELDENTRY));
    *result_length = max_length;

    for (i=0; i < max_length; i++)
      result[i] = (SPLITFIELDENTRY)0;
    for (i=0; i < leftSF_length; i++)
      result[i] = result[i] | leftSF[i];
    for (i=0; i < rightSF_length; i++)
      result[i] = result[i] | rightSF[i];
  } else
    *result_length = 0;

  return result;
}


SPLITFIELD prfs_SplitfieldIntersection(SPLITFIELD leftSF, unsigned leftSF_length,
                                       SPLITFIELD rightSF, unsigned rightSF_length,
                                       unsigned *result_length)
{
  unsigned min_length;
  unsigned i;
  SPLITFIELD result=NULL;

  if (leftSF_length < rightSF_length)
    min_length = leftSF_length;
  else
    min_length = rightSF_length;

  if (min_length > 0) {
    result = memory_Malloc(min_length * sizeof(SPLITFIELDENTRY));
    *result_length = min_length;

    for (i=0; i < min_length; i++)
      result[i] = leftSF[i];
    for (i=0; i < min_length; i++)
      result[i] = result[i] & rightSF[i];
  } else
    *result_length = 0;

  return result;
}




SPLITFIELD prfs_CombineSplitfields(SPLITFIELD leftSF, unsigned leftSF_length,
                                   SPLITFIELD rightSF, unsigned rightSF_length,
                                   NAT n,
                                   unsigned *result_length)
{
  SPLITFIELD result=NULL;

  if (prfs_SplitfieldContainsLevel(leftSF, leftSF_length, n) &&
      prfs_SplitfieldContainsLevel(rightSF, rightSF_length, n)) {
    result=prfs_SplitfieldUnion(leftSF,leftSF_length,rightSF,rightSF_length,result_length);
    prfs_AddLevelToSplitfield(&result,result_length,0);
    prfs_RemoveLevelFromSplitfield(&result,result_length,n);
    return result;
  } else {
    if (prfs_SplitfieldIsSubset(leftSF,leftSF_length,rightSF,rightSF_length) ||
        prfs_SplitfieldIsSubset(rightSF,rightSF_length,leftSF,leftSF_length)) {
      result = prfs_SplitfieldIntersection(leftSF,leftSF_length,rightSF,rightSF_length,result_length);
      prfs_AddLevelToSplitfield(&result,result_length,0);
      return result;
    } else {
      result=prfs_SplitfieldUnion(leftSF,leftSF_length,rightSF,rightSF_length,result_length);
      prfs_AddLevelToSplitfield(&result,result_length,0);
      prfs_RemoveLevelFromSplitfield(&result,result_length,n);
      return result;
    }
  }
}
