/**************************************************************/
/* ********************************************************** */
/* *                                                        * */
/* *                       DEFINITIONS                      * */
/* *                                                        * */
/* *  $Module:   DEFS                                       * */ 
/* *                                                        * */
/* *  Copyright (C) 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.4 $                                         * */
/* $State: Exp $                                            * */
/* $Date: 2011-05-22 12:16:58 $                             * */
/* $Author: weidenb $                                       * */
/* *                                                        * */
/* *             Contact:                                   * */
/* *             Christoph Weidenbach                       * */
/* *             MPI fuer Informatik                        * */
/* *             Stuhlsatzenhausweg 85                      * */
/* *             66123 Saarbruecken                         * */
/* *             Email: spass@mpi-inf.mpg.de                * */
/* *             Germany                                    * */
/* *                                                        * */
/* ********************************************************** */
/**************************************************************/


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

#include "cnf.h"
#include "defs.h"
#include "foldfg.h"

/*******************************************************
*Previously inlined functions                          *  
********************************************************/
TERM def_Expansion(DEF D)
{
  return D->expansion;
}

void def_RplacExp(DEF D, TERM E)
{
  D->expansion = E;
}

TERM def_Predicate(DEF D)
{
  return D->predicate;
}

void def_RplacPred(DEF D, TERM Pred)
{
  D->predicate = Pred;
}

TERM def_ToProve(DEF D)
{
  return D->toprove;
}

void def_RplacToProve(DEF D, TERM ToProve)
{
  D->toprove = ToProve;
}

LIST def_ClauseNumberList(DEF D)
{
  return list_PairFirst(D->parentclauses);
}

void def_RplacClauseNumberList(DEF D, LIST L)
{
  list_Rplaca(D->parentclauses, L);
}

LIST def_ClauseLitsList(DEF D)
{
  return list_PairSecond(D->parentclauses);
}

void def_RplacClauseLitsList(DEF D, LIST L)
{
  list_Rplacd(D->parentclauses, L);
}

const char* def_Label(DEF D)
{
  return D->label;
}

void def_RplacLabel(DEF D, const char* L)
{
  D->label = L;
}

BOOL def_Conjecture(DEF D)
{
  return D->conjecture;
}

void def_SetConjecture(DEF D)
{
  D->conjecture = TRUE;
}

void def_AddAttribute(DEF D, DEF_ATTRIBUTES Attribute)
{
  D->attributes = D->attributes | Attribute;
}

NAT def_HasAttribute(DEF D, DEF_ATTRIBUTES Attribute)
{
  return (D->attributes & Attribute);
}

void def_RemoveAttribute(DEF D, DEF_ATTRIBUTES Attribute)
{
  if (D->attributes & Attribute)
    D->attributes = D->attributes - Attribute;
}

BOOL def_HasGuard(DEF D)
{
  return (def_ToProve(D)!=term_Null());
}

/*******************************************************
*Previously inlined functions ends                      *  
********************************************************/

static void def_DeleteFromClauses(DEF);
static void def_DeleteFromTerm(DEF);

DEF def_CreateFromClauses(TERM ExpTerm, TERM PredTerm, LIST Clauses, LIST Lits,
			  BOOL Con)
/**********************************************************
  INPUT:   Two terms, a list of clausenumbers, a list of literal indices and
           a boolean saying whether all clauses derived by expanding the 
	   predicate should be conclauses.
  RETURNS: A definition consisting of the 2 terms as expansion term and
           predicate term and the list of parent clause numbers and a list
	   of the indices of the defined predicate in the parent clauses.
	   ToProve and label are set to NULL.
********************************************************/
{
  DEF  result;

#ifdef CHECK
  if (!term_IsTerm(ExpTerm) || !term_IsTerm(PredTerm)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In def_CreateFromClause: Illegal input.");
    misc_FinishErrorReport();
  }
  if (list_Empty(Clauses)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In def_CreateFromClause: No parent clause given.");
    misc_FinishErrorReport();
  }
#endif

  result                   = (DEF) memory_Malloc(sizeof(DEF_NODE));
  result->expansion        = ExpTerm;
  result->predicate        = PredTerm;
  result->toprove          = (TERM) NULL;
  result->parentclauses    = list_PairCreate(Clauses, Lits);
  result->label            = (const char*) NULL;
  result->conjecture       = Con;

  return result;
}

DEF def_CreateFromTerm(TERM ExpTerm, TERM PredTerm, TERM ToProve, const char* Label)
/**********************************************************
  INPUT:   3 terms and a term label.
  RETURNS: A definition consisting of the 3 terms as expansion term,
           predicate term and term to prove before applying the 
	   definition and the label of the parent term.
	   The list of clausenumbers is set to NULL.
********************************************************/
{
  DEF  result;

#ifdef CHECK
  if (!term_IsTerm(ExpTerm) || !term_IsTerm(PredTerm)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In def_CreateFromTerm: Illegal input.");
    misc_FinishErrorReport();
  }  
  if (Label ==  NULL) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In def_CreateFromTerm: No parent clause given.");
    misc_FinishErrorReport();
  }
#endif

  result                   = (DEF) memory_Malloc(sizeof(DEF_NODE));
  result->expansion        = ExpTerm;
  result->predicate        = PredTerm;
  result->toprove          = ToProve;
  result->parentclauses    = list_PairCreate(list_Nil(), list_Nil());
  result->label            = Label;
  result->conjecture       = FALSE;

  return result;
}

static void def_DeleteFromClauses(DEF D) 
/**********************************************************
  INPUT:   A definition derived from clauses.
  EFFECT:  The definition is deleted, INCLUDING THE TERMS AND
           THE LIST OF CLAUSE NUMBERS.
********************************************************/  
{
#ifdef CHECK
  if (!term_IsTerm(def_Expansion(D)) || !term_IsTerm(def_Predicate(D))) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In def_DeleteFormClauses: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  /* ToProve and Label are NULL */
  term_Delete(def_Expansion(D));
  term_Delete(def_Predicate(D));
  list_Delete(def_ClauseNumberList(D));
  list_Delete(def_ClauseLitsList(D));
  list_PairFree(D->parentclauses);

  memory_Free(D, sizeof(DEF_NODE));
}

static void def_DeleteFromTerm(DEF D) 
/**********************************************************
  INPUT:   A definition derived from a term.
  EFFECT:  The definition is deleted, INCLUDING THE TERMS.
           THE LABEL IS NOT FREED.
********************************************************/  
{
#ifdef CHECK
  if (!term_IsTerm(def_Expansion(D)) || !term_IsTerm(def_Predicate(D))) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In def_DeleteFromTerm: Illegal input.");
    misc_FinishErrorReport();
  }
#endif

  /* List of clausenumbers is NULL */
  term_Delete(def_Expansion(D));
  term_Delete(def_Predicate(D));
  if (def_ToProve(D) != (TERM) NULL)
    term_Delete(def_ToProve(D));
  list_PairFree(D->parentclauses);
  memory_Free(D, sizeof(DEF_NODE));
}

void def_Delete(DEF D)
/**********************************************************
  INPUT:   A definition derived from a term.
  EFFECT:  The definition is deleted.
  CAUTION: All elements of the definition except of the label are freed.
********************************************************/  
{
  if (!list_Empty(def_ClauseNumberList(D)))
    def_DeleteFromClauses(D);
  else
    def_DeleteFromTerm(D);
}

int def_PredicateOccurrences(TERM Term, SYMBOL P)
/****************************************************
  INPUT:   A term and a predicate symbol.
  RETURNS: The number of occurrences of the predicate symbol in Term
**************************************************/			       
{
  /* Quantifiers */
  if (fol_IsQuantifier(term_TopSymbol(Term)))
    return def_PredicateOccurrences(term_SecondArgument(Term), P);

  /* Junctors and NOT */
  if (fol_IsJunctor(term_TopSymbol(Term)) ||
      symbol_Equal(term_TopSymbol(Term),fol_Not())){
    LIST scan;
    int count;
    count = 0;
    for (scan=term_ArgumentList(Term); !list_Empty(scan); scan=list_Cdr(scan)) {
      count += def_PredicateOccurrences((TERM) list_Car(scan), P);
      /* Only the cases count==1 and count>1 are important */
      if (count > 1)
	return count;
    }
    return count;
  }
  
  if (symbol_Equal(term_TopSymbol(Term), P))
    return 1;
  return 0;
} 

LIST def_ExtractDefsFromTerm(TERM Term, const char* Label) 
/**************************************************************
  INPUT:   A term and its label.
  RETURNS: A list of definitions found in the term.
  NOTE:    The Term is not changed, the definitions contain copies.
***************************************************************/
{
  TERM andterm;
  BOOL found;
  int  pol;
  LIST univars, termlist, defslist, scan;
  
  /* First check if there is a top level and() so that the Term may
     contain several definitions */

  andterm = Term;
  found   = FALSE;
  pol     = 1;
  univars = list_Nil();

  /* Traverse top down universal quantifiers */
  while (!found) {
    if ((symbol_Equal(term_TopSymbol(andterm), fol_All()) && (pol == 1))
	|| (symbol_Equal(term_TopSymbol(andterm), fol_Exist()) && (pol == -1))) {
      univars = list_Nconc(univars, list_Copy(fol_QuantifierVariables(andterm)));
      andterm = term_SecondArgument(andterm);
    }
    else {
      if (symbol_Equal(term_TopSymbol(andterm), fol_Not())) {
	pol = -pol;
	andterm = term_FirstArgument(andterm);
      }
      else
	found = TRUE;
    }
  }

  termlist = list_Nil();
  /* Check if conjunction was found */
  if ((symbol_Equal(term_TopSymbol(andterm), fol_And()) && (pol == 1))
      || (symbol_Equal(term_TopSymbol(andterm), fol_Or()) && (pol == -1))) {
    LIST l;
    /* Flatten nested and/or */
    /* Make copy of relevant subterm */
    andterm = cnf_Flatten(term_Copy(andterm), term_TopSymbol(andterm));
    for (l=term_ArgumentList(andterm); !list_Empty(l); l=list_Cdr(l)) {
      TERM newterm;
      newterm = fol_CreateQuantifierAddFather(fol_All(), term_CopyTermList(univars),
					      list_List(list_Car(l)));
      termlist = list_Cons(newterm, termlist);
    }
    /* Arguments are used in new terms */
    list_Delete(term_ArgumentList(andterm));
    term_Free(andterm);
  }
  else
    termlist = list_List(term_Copy(Term));
  
  list_Delete(univars);

  /* Now we have a list of terms that may contain definitions */
  defslist = list_Nil();
  for (scan=termlist; !list_Empty(scan); scan=list_Cdr(scan)) {
    TERM cand;
    TERM foundpred, toprove;

    /* Candidate from list */
    cand = (TERM) list_Car(scan);
    term_AddFatherLinks(cand);

    if (cnf_ContainsDefinition(cand, &foundpred)) {
      DEF def;
#ifdef CHECK
      if (!fol_CheckFormula(cand)) {
	misc_StartErrorReport();
	misc_ErrorReport("\n In def_ExtractDefsFromTerm: Illegal term cand");
	misc_FinishErrorReport();
      }
#endif
      cand = cnf_DefConvert(cand, foundpred, &toprove);
#ifdef CHECK
      if (!fol_CheckFormula(cand)) {
	misc_StartErrorReport();
	misc_ErrorReport("\n In def_ExtractDefsFromTerm: Illegal term cand");
	misc_FinishErrorReport();
      }
#endif
      def  = def_CreateFromTerm(term_Copy(term_SecondArgument(term_Superterm(foundpred))), 
				term_Copy(foundpred), toprove, Label);

      if (def_PredicateOccurrences(cand, term_TopSymbol(foundpred)) > 1)
	def_RemoveAttribute(def, PREDOCCURONCE);
      else 
	def_AddAttribute(def, PREDOCCURONCE);
      if (symbol_Equal(term_TopSymbol(foundpred), fol_Equality()))
	def_AddAttribute(def, ISEQUALITY);
      else
	def_RemoveAttribute(def, ISEQUALITY);

      defslist = list_Cons(def, defslist);
    }
    term_Delete(cand);
  }
  
  list_Delete(termlist);
  return defslist;
}

void def_ExtractDefsFromClauselist(PROOFSEARCH Search, LIST Clauselist)
/**************************************************************
  INPUT:   A proofsearch object and a list of clauses
  RETURNS: Nothing.
  EFFECT:  The definitions found in the clauselist object are stored in
           the proofsearch object.
  NOTE:    The clause list is not changed.
           The old list of definitions in the proofsearch object is 
	   overwritten.
***************************************************************/
{
  LIST       scan, defslist;
  FLAGSTORE  FlagStore;
  PRECEDENCE Precedence;

  defslist   = list_Nil();
  FlagStore  = prfs_Store(Search);
  Precedence = prfs_Precedence(Search);

  for (scan=Clauselist; !list_Empty(scan); scan=list_Cdr(scan)) {
    CLAUSE Clause;
    NAT literal_index;
    LIST pair;

    Clause = (CLAUSE) list_Car(scan);
    /* Check if clause contains a predicate that may be part of a definition */
    if (clause_ContainsPotPredDef(Clause, FlagStore, Precedence, &literal_index, &pair)) {
      LIST l, compl, compllits;
      BOOL done;

      compl = compllits = list_Nil();
      done = FALSE;
      
      /* Search for complement clauses */
      for (l=Clauselist; !list_Empty(l) && !done; l=list_Cdr(l)) {
	intptr_t predindex;
	if (clause_IsPartOfDefinition((CLAUSE) list_Car(l), 
				      clause_GetLiteralTerm(Clause, literal_index), 
				      &predindex, pair)) {
	  compl     = list_Cons(list_Car(l), compl);
	  compllits = list_Cons((POINTER)predindex, compllits);
	  
	  if (list_Empty(list_PairFirst(pair)) &&
	      list_Empty(list_PairSecond(pair)))
	    done = TRUE;
	}
      }
      
      /* All complements found ? */ 
      if (done) {
	LIST l2, clausenumbers, args;
	DEF  def;
	NAT  i;
	TERM defterm, predterm;
	BOOL con;

	clausenumbers = list_Nil();
	con           = clause_GetFlag(Clause, CONCLAUSE);

	for (l2=compl; !list_Empty(l2); l2=list_Cdr(l2)) {
	  clausenumbers = list_Cons((POINTER) clause_Number((CLAUSE) list_Car(l2)), 
				    clausenumbers);	    
	  if (clause_GetFlag((CLAUSE) list_Car(l2), CONCLAUSE))
	    con = TRUE;
	}
	clausenumbers = list_Cons((POINTER) clause_Number(Clause), 
				  clausenumbers);
	compllits = list_Cons((POINTER) literal_index, compllits);

	/* Build definition term */
	predterm = term_Copy(clause_GetLiteralTerm(Clause, literal_index));
	args     = list_Nil();
	for (i = 0; i < clause_Length(Clause); i++) 
	  if (i != literal_index)
	    args = list_Cons(term_Copy(clause_GetLiteralTerm(Clause, i)), args);
	defterm  = term_CreateAddFather(fol_Or(), args);
	/* The expansion is negative here, so it must be inverted */
	defterm  = term_Create(fol_Not(), list_List(defterm));
	defterm  = cnf_NegationNormalFormula(defterm);
	def      = def_CreateFromClauses(defterm, predterm, clausenumbers, compllits, con);
	defslist = list_Cons(def, defslist);
	if (flag_GetFlagIntValue(FlagStore, flag_PAPPLYDEFS)) {
	  fputs("\nNew definition found :", stdout);
	  def_Print(def);
	}
      }
      else {
	list_Delete(compllits);
	list_Delete(list_PairSecond(pair));
	list_Delete(list_PairFirst(pair));
      }
      list_Delete(compl);
      list_PairFree(pair);
    }
  }

  if (flag_GetFlagIntValue(FlagStore, flag_PAPPLYDEFS)) {
    if (!list_Empty(defslist)) {
      fputs("\nFound definitions :\n", stdout);
      for (scan = defslist; !list_Empty(scan); scan = list_Cdr(scan)) {
	def_Print((DEF) list_Car(scan));
	fputs("\n---\n", stdout);
      }
    }
  }

  for (scan=defslist; !list_Empty(scan); scan=list_Cdr(scan))
    symbol_AddProperty(term_TopSymbol(def_Predicate((DEF) list_Car(scan))), ISDEF);
  
  prfs_SetDefinitions(Search, list_Nconc(prfs_Definitions(Search), defslist));
}

TERM def_ApplyDefToTermOnce(DEF Def, TERM Term, FLAGSTORE FlagStore,
			    PRECEDENCE Precedence, BOOL* Complete)
/**************************************************************
  INPUT:   A DEF structure, a term and a boolean that is set
           to TRUE if no occurrences of the defined predicate
	   remain in the term. A flag store and a precedence.
  RETURNS: A term where all occurrences of the definitions
           predicate are expanded if possible.
  NOTE:    The Term is not changed.
***************************************************************/
{
  TERM newtarget, oldtarget, targetpredicate, totoplevel, toprove;
  LIST targettermvars, varsfortoplevel;
  BOOL applicable;

  oldtarget = Term;
  *Complete = TRUE;

  while (TRUE) {
    newtarget = term_Copy(oldtarget);
    term_AddFatherLinks(newtarget);
    targettermvars = varsfortoplevel = list_Nil();

    if (cnf_ContainsPredicate(newtarget, term_TopSymbol(def_Predicate(Def)),
			      &targetpredicate, &totoplevel, &targettermvars, 
			      &varsfortoplevel)) {
      *Complete  = FALSE;
      applicable = FALSE;
      /* Check if definition is not always applicable */
      if (term_Equal(def_ToProve(Def), term_Null())) { 
	applicable = TRUE;
	newtarget = cnf_ApplyDefinitionOnce(def_Predicate(Def), term_Copy(def_Expansion(Def)),
					 newtarget, targetpredicate, FlagStore);
	if (oldtarget != Term)
	  term_Delete(oldtarget);
	oldtarget = newtarget;
      	list_Delete(targettermvars);
	list_Delete(varsfortoplevel); 	
      }
      else {
	toprove = term_Copy(def_ToProve(Def));
	newtarget = cnf_DefTargetConvert(newtarget, totoplevel, toprove,
					 term_ArgumentList(def_Predicate(Def)),
					 term_ArgumentList(targetpredicate),
					 targettermvars, varsfortoplevel,
					 FlagStore, Precedence,
					 &applicable);
	list_Delete(targettermvars);
	list_Delete(varsfortoplevel); 	
	if (applicable) {
	  newtarget = cnf_ApplyDefinitionOnce(def_Predicate(Def), term_Copy(def_Expansion(Def)),
					   newtarget, targetpredicate, FlagStore);
	  if (oldtarget != Term)
	    term_Delete(oldtarget);
	  oldtarget = newtarget;
	}
	else {
	  /* Predicate still exists but cannot be expanded */
	  term_Delete(newtarget);
	  if (oldtarget == Term)
	    return NULL;
	  else {
	    oldtarget = cnf_ObviousSimplifications(oldtarget);
	    return oldtarget;
	  }
	}
      }
    }
    else {
      *Complete = TRUE;
      /* Predicate does no longer exist */
      term_Delete(newtarget);
      /* No expansion possible */
      if (oldtarget == Term)
	return NULL;
      else {
	oldtarget = cnf_ObviousSimplifications(oldtarget);
	return oldtarget;
      }
    }
  }
  return NULL; /* Unreachable */
}
    
TERM def_ApplyDefToTermExhaustive(PROOFSEARCH Search, TERM Term)
/**************************************************************
  INPUT:   A proofsearch object and a term.
  RETURNS: An expanded term.
  NOTE:    All occurences of defined predicates are expanded in the term,
           until no further changes are possible.
  CAUTION: If cyclic definitions exist, this will crash.
***************************************************************/
{
  TERM       oldterm, newterm;
  BOOL       done, complete;
  FLAGSTORE  FlagStore;
  PRECEDENCE Precedence;

  done       = FALSE;
  oldterm    = Term;
  FlagStore  = prfs_Store(Search);
  Precedence = prfs_Precedence(Search);

  while (!done) {
    LIST l;
    done = TRUE;
    /* Apply all definitions to term until no more changes occur */
    for (l=prfs_Definitions(Search); !list_Empty(l); l=list_Cdr(l)) {
      newterm = def_ApplyDefToTermOnce((DEF) list_Car(l), oldterm,
				       FlagStore, Precedence, &complete);
      if (newterm != NULL) {
	if (oldterm != Term)
	  term_Delete(oldterm);
	oldterm = newterm;
	done = FALSE;
      }
    }
  }
  if (oldterm == Term)
    return NULL;
  else
    return oldterm;
}

LIST def_ApplyDefToClauseOnce(DEF Def, CLAUSE Clause,
			      FLAGSTORE FlagStore, PRECEDENCE Precedence)
/**************************************************************
  INPUT:   A DEF structure, a clause, a flag store and a
           precedence.
  RETURNS: A list of new clauses.
  NOTE:    The clause is not changed.
           All occurences of the defined predicate are expanded
	   in the clause and in the derived clauses.
***************************************************************/
{
  LIST result, l;
  
  result = list_List(Clause);

  for (l = result; !list_Empty(l); l = list_Cdr(l)) {
    if (clause_ContainsSymbol((CLAUSE) list_Car(l), 
			      term_TopSymbol(def_Predicate(Def)))) {
      result = list_Nconc(result, 
			  cnf_ApplyDefinitionToClause((CLAUSE) list_Car(l), 
						      def_Predicate(Def),
						      def_Expansion(Def),
						      FlagStore, Precedence));
      /* Remove temporary clause */
      if ((CLAUSE) list_Car(l) != Clause)
	clause_Delete((CLAUSE) list_Car(l));
      list_Rplaca(l, NULL);
    }
  }
  result = list_PointerDeleteElement(result, NULL);

  /* Make sure the original clause is no longer in the list */
  if (!list_Empty(result))
    if (list_First(result) == Clause)
      result = list_Pop(result);
  
  for (l = result; !list_Empty(l); l=list_Cdr(l)) {
    CLAUSE c;
    c = (CLAUSE) list_Car(l);
    if (def_Conjecture(Def))
      clause_SetFlag((CLAUSE) list_Car(l), CONCLAUSE);
    clause_SetFromDefApplication(c);
    clause_SetParentClauses(c, list_Cons((POINTER) clause_Number(Clause), 
					 list_Copy(def_ClauseNumberList(Def))));
    /* Parent literal is not available, as the predicate may occur several 
       times in the target clause */
    clause_SetParentLiterals(c, list_Cons((POINTER) 0, 
					  list_Copy(def_ClauseLitsList(Def))));
  }
  return result;
}

LIST def_ApplyDefToClauseExhaustive(PROOFSEARCH Search, CLAUSE Clause)
/**************************************************************
  INPUT:   A proofsearch object and a clause.
  RETURNS: A list of derived clauses.
  NOTE:    All occurences of defined predicates are expanded in the clause.
           until no further changes are possible.
  CAUTION: If cyclic definitions exist, this will crash.
***************************************************************/
{
  LIST       newclauses, scan, result;
  CLAUSE     orig;
  FLAGSTORE  FlagStore;
  PRECEDENCE Precedence;

  orig       = clause_Copy(Clause);
  newclauses = list_List(orig);
  result     = list_Nil();
  FlagStore  = prfs_Store(Search);
  Precedence = prfs_Precedence(Search);

  while (!list_Empty(newclauses)) {
    /* Check all clauses */
    LIST l, nextlist;

    /* List of clauses derived from newclauses by expanding predicates */
    nextlist = list_Nil();

    for (l=newclauses; !list_Empty(l); l=list_Cdr(l)) {
      LIST clauses;
      CLAUSE c;
      
      c = (CLAUSE) list_Car(l);

      /* Apply all definitions to the clause */

      /* List of clauses derived from one clause in newclauses by */
      /* expanding all possible predicates */
      clauses  = list_Nil();

      for (scan=prfs_Definitions(Search); !list_Empty(scan); scan=list_Cdr(scan))
	clauses = list_Nconc(clauses, def_ApplyDefToClauseOnce((DEF) list_Car(scan), c, FlagStore, Precedence));
      
      /* If expansions were made delete old clause */
      if (!list_Empty(clauses)) {
	/* DOCPROOF ? */
	if (c != Clause) {
	  if (flag_GetFlagIntValue(FlagStore, flag_DOCPROOF)) {
	    prfs_InsertDocProofClause(Search, c);
	  }
	  else
	    clause_Delete(c);
	}
	nextlist = list_Nconc(nextlist, clauses);
      }
      else {
	/* No more expansions possible for this clause */
	/* If it is not the original clause, add it to the result list */
	if (c != Clause)
	  result = list_Cons(c, result);
      }
    }
    list_Delete(newclauses);
    newclauses = nextlist;
  }
      
  return result;
}
  

void def_Print(DEF D)
/**************************************************************
  INPUT:   A DEF structure.
  RETURNS: None.
  EFFECT:  Prints the definition to stdout. 
***************************************************************/
{
  LIST scan, scan2;
  fputs("\n\nAtom: ", stdout);
  fol_PrettyPrint(def_Predicate(D));
  fputs("\nExpansion: \n", stdout);
  fol_PrettyPrint(def_Expansion(D));
  if (!list_Empty(def_ClauseNumberList(D))) {
    fputs("\nParent clauses: ", stdout);
    for (scan = def_ClauseNumberList(D), scan2 = def_ClauseLitsList(D); 
	 !list_Empty(scan); scan = list_Cdr(scan), scan2 = list_Cdr(scan2)) 
      printf("%zu.%zu ", (NAT) list_Car(scan), (NAT) list_Car(scan2));
    if (D->conjecture)
      fputs("\nDerived from conjecture clauses.", stdout);
    else
      fputs("\nNot derived from conjecture clauses.", stdout);
  }
  else {
    fputs("\nLabel: ", stdout);
    fputs(def_Label(D), stdout);
    puts("\nGuard:");
    if (def_ToProve(D) != NULL) 
      fol_PrettyPrint(def_ToProve(D));
    else
      fputs("Nothing.", stdout);
  }

  fputs("\nAttributes: ", stdout);
  if (def_HasAttribute(D, ISEQUALITY) || def_HasAttribute(D, PREDOCCURONCE)) {
    if (def_HasAttribute(D, ISEQUALITY))
      fputs(" Equality ", stdout);
    if (def_HasAttribute(D, PREDOCCURONCE))
      fputs(" No Multiple Occurrences ", stdout);
  }
  else {
    fputs(" None ", stdout);
  }    
} 

LIST def_ApplyDefToClauselist(PROOFSEARCH Search, DEF Def, 
			      LIST Clauselist, BOOL Destructive)
/**************************************************************
  INPUT:   A proofsearch object, a DEF structure, a list of unshared clauses
           and a boolean saying whether the parent clause of an expansion
	   should be deleted.
  RETURNS: None.
  EFFECT:  For each occurrence of the defined predicate in a clause in the list,
  a new clause with expanded predicate is added to the list.
***************************************************************/
{
  LIST       l, newclauses, allnew;
  FLAGSTORE  FlagStore;
  PRECEDENCE Precedence;

  allnew     = list_Nil();
  FlagStore  = prfs_Store(Search);
  Precedence = prfs_Precedence(Search);

  for (l = Clauselist; !list_Empty(l); l = list_Cdr(l)) {
    newclauses = def_ApplyDefToClauseOnce(Def, (CLAUSE) list_Car(l),
					  FlagStore, Precedence);
    /* Expansions were possible, delete the original clause */
    if (Destructive && !list_Empty(newclauses)) {
      if (flag_GetFlagIntValue(FlagStore, flag_DOCPROOF))
	prfs_InsertDocProofClause(Search, (CLAUSE) list_Car(l));
      else
	clause_Delete((CLAUSE) list_Car(l));
      list_Rplaca(l, NULL);
    }
    allnew = list_Nconc(allnew, newclauses);
  }
  if (Destructive)
    Clauselist = list_PointerDeleteElement(Clauselist, NULL);


  if (flag_GetFlagIntValue(FlagStore, flag_PAPPLYDEFS)) {
    if (!list_Empty(allnew)) {
      fputs("\nNew clauses after applying definitions : \n", stdout);
      clause_ListPrint(allnew);
    }
  }

  Clauselist = list_Nconc(Clauselist, allnew);
  return Clauselist;
}

LIST def_ApplyDefToTermlist(DEF Def, LIST Termlist,
			    FLAGSTORE FlagStore, PRECEDENCE Precedence,
			    BOOL* Complete, BOOL Destructive)
/**************************************************************
  INPUT:   A DEF structure and a list of pairs (label, term),
           a flag store, a precedence and a pointer to a
	   boolean.
	   If Destructive is TRUE the father of an expanded
	   term is deleted.
  RETURNS: The changed list of terms.
  EFFECT:  For each occurrence of the defined predicate in a
           term in the list, a new term with expanded predicate
	   is added to the list.
	   If every occurrence of the predicate could be
	   expanded, Complete is set to TRUE.
***************************************************************/
{
  LIST l, newterms;
  
  newterms = list_Nil();

  *Complete = TRUE;
  for (l=Termlist; !list_Empty(l); l=list_Cdr(l)) {
    TERM newterm;
    TERM oldterm;
    BOOL complete;
    oldterm = list_PairSecond(list_Car(l));
    newterm = def_ApplyDefToTermOnce(Def, oldterm, FlagStore,
				     Precedence, &complete);
    if (!complete)
      *Complete = FALSE;
    /* destructive part of function */
    if (newterm != NULL) {
      newterms = list_Cons(list_PairCreate(NULL, newterm),newterms);
      if (Destructive) {
	/* Delete oldterm from Termlist */
	term_Delete(list_PairSecond(list_Car(l)));
	if (list_PairFirst(list_Car(l)) != NULL)
	  string_StringFree(list_PairFirst(list_Car(l)));
	
	list_PairFree(list_Car(l));
	list_Rplaca(l, NULL);
      }
    }
  }
  Termlist = list_PointerDeleteElement(Termlist, NULL);

  if (flag_GetFlagIntValue(FlagStore, flag_PAPPLYDEFS)) {
    if (!list_Empty(newterms)) {
      fputs("\n\nNew terms after applying definitions : \n", stdout);
      for (l=newterms; !list_Empty(l); l=list_Cdr(l)) {
	fputs("\n", stdout);
	fol_PrettyPrint(list_PairSecond(list_Car(l)));
      }
    }
  }
  
  Termlist = list_Nconc(Termlist, newterms);
  return Termlist;
}

void def_ExtractDefsFromTermlist(PROOFSEARCH Search, LIST Axioms, LIST Conj)
/**************************************************************
  INPUT:   A proofsearch object and 2 lists of pairs label/term.
  RETURNS: None.
  EFFECT:  Add all found definitions to the proofsearch object.
           The old list of definitions in the proofsearch object is 
	   overwritten.
***************************************************************/
{ 
  LIST      l, deflist;
  FLAGSTORE FlagStore;

  deflist   = list_Nil();
  FlagStore = prfs_Store(Search);

  for (l=Axioms; !list_Empty(l); l=list_Cdr(l)) {
    fol_NormalizeVars(list_PairSecond(list_Car(l))); /* Is needed for proper variable match ! */
    deflist = list_Nconc(deflist,
			 def_ExtractDefsFromTerm(list_PairSecond(list_Car(l)),
						 list_PairFirst(list_Car(l))));
  }
  for (l=Conj; !list_Empty(l); l=list_Cdr(l)) {
    fol_NormalizeVars(list_PairSecond(list_Car(l))); /* Is needed for proper variable match ! */
    deflist = list_Nconc(deflist,
			 def_ExtractDefsFromTerm(list_PairSecond(list_Car(l)),
						 list_PairFirst(list_Car(l))));
  }
  for (l=deflist; !list_Empty(l); l=list_Cdr(l))
    symbol_AddProperty(term_TopSymbol(def_Predicate(list_Car(l))), ISDEF);

  prfs_SetDefinitions(Search, list_Nconc(prfs_Definitions(Search), deflist));  

  if (flag_GetFlagIntValue(FlagStore, flag_PAPPLYDEFS)) {
    if (!list_Empty(deflist)) {
      fputs("\nFound definitions :\n", stdout);
      for (l = prfs_Definitions(Search); !list_Empty(l); l = list_Cdr(l)) {
	def_Print(list_Car(l));
	fputs("\n---\n", stdout);
      }
    }
  }
}

LIST def_FlattenWithOneDefinition(PROOFSEARCH Search, DEF Def)
/**************************************************************
  INPUT:   A proofsearch object and one definition.
  RETURNS: The list of new definitions.
  EFFECT:  For every occurrence of the defined predicate among the other
           definitions an expansion is attempted.
	   A new definition is only created if the result of the expansion is 
	   again a definition. 
	   The proofsearch object is not changed.
***************************************************************/
{
  LIST       newdefinitions;
  FLAGSTORE  FlagStore;
  PRECEDENCE Precedence;

  newdefinitions = list_Nil();
  FlagStore      = prfs_Store(Search);
  Precedence     = prfs_Precedence(Search);

  if (def_ToProve(Def) == NULL) {
    LIST definitions, l;

    definitions = prfs_Definitions(Search);

    for (l = definitions; !list_Empty(l); l=list_Cdr(l)) {
      DEF d;

      d = (DEF) list_Car(l);      
      if (d != Def) {
	/* Expansion possible */
	if (term_ContainsSymbol(def_Expansion(d), term_TopSymbol(def_Predicate(Def)))) {
	  /* Resulting term is still a definition */
	  if (!term_ContainsSymbol(def_Expansion(Def), term_TopSymbol(def_Predicate(d)))) {
	    TERM newexpansion;
	    BOOL complete;
	    DEF newdef;
	    newexpansion = def_ApplyDefToTermOnce(Def, def_Expansion(d),
						  FlagStore, Precedence,
						  &complete);
	    
	    newdef = def_CreateFromTerm(newexpansion,
					term_Copy(def_Predicate(d)), 
					term_Copy(def_ToProve(d)), def_Label(d));
	    newdefinitions = list_Cons(newdef, newdefinitions);
	  }
	}
      }
      
    }
  }
  return newdefinitions;
}


void def_FlattenWithOneDefinitionDestructive(PROOFSEARCH Search, DEF Def)
/**************************************************************
  INPUT:   A proofsearch object and one definition.
  RETURNS: None.
  EFFECT:  If the definition is always applicable, every occurrence of the 
           defined predicate among the other definitions is expanded in place.
	   If the resulting term is no longer a definition, it is deleted from
	   the proofsearch object.
	   Def is deleted.
  CAUTION: This function changes the list entries in the list of definitions 
           in the proofsearch object, so do not call it from a loop over
           all definitions.
***************************************************************/
{
  FLAGSTORE  FlagStore;
  PRECEDENCE Precedence;

  FlagStore  = prfs_Store(Search);
  Precedence = prfs_Precedence(Search);

  if (def_ToProve(Def) == NULL) {
    LIST definitions, l;

    definitions = prfs_Definitions(Search);    
    for (l = definitions; !list_Empty(l); l = list_Cdr(l)) {
      DEF d;

      d = (DEF) list_Car(l);      
      if (d != Def) {
	/* Expansion possible */
	if (term_ContainsSymbol(def_Expansion(d), term_TopSymbol(def_Predicate(Def)))) {
	  /* Resulting term is still a definition */
	  if (!term_ContainsSymbol(def_Expansion(Def), term_TopSymbol(def_Predicate(d)))) {
	    TERM newexpansion;
	    BOOL complete;

	    newexpansion = def_ApplyDefToTermOnce(Def, def_Expansion(d), FlagStore, Precedence, &complete);
	    term_Delete(def_Expansion(d));
	    def_RplacExp(d, newexpansion);
	  }
	  else {
	    symbol_RemoveProperty(term_TopSymbol(def_Predicate(d)), ISDEF);
	    def_Delete(d);
	    list_Rplaca(l, NULL);
	  }
	}
      }
      else {
	/* Remove given definition */
	list_Rplaca(l, NULL);
      }
    }
    symbol_RemoveProperty(term_TopSymbol(def_Predicate(Def)), ISDEF);
    def_Delete(Def);
    definitions = list_PointerDeleteElement(definitions, NULL);
    prfs_SetDefinitions(Search, definitions);
  }
}

void def_FlattenWithOneDefinitionSemiDestructive(PROOFSEARCH Search, DEF Def)
/**************************************************************
  INPUT:   A proofsearch object and one definition.
  RETURNS: Nothing.
  EFFECT:  If the definition can be applied to another definition
           in the search object, that definition is destructively changed.
	   If the resulting term is no longer a definition, it is deleted to
	   prevent cycles.
	   The applied definition Def is NOT deleted.
  CAUTION: After calling this function some entries of the definitions list
           in the proofsearch object may be NULL.
***************************************************************/
{
  FLAGSTORE  FlagStore;
  PRECEDENCE Precedence;

  FlagStore  = prfs_Store(Search);
  Precedence = prfs_Precedence(Search);
  
  if (def_ToProve(Def) == NULL) {
    LIST definitions, l;

    definitions = prfs_Definitions(Search);    
    for (l = definitions; !list_Empty(l); l=list_Cdr(l)) {
      DEF d;

      d = (DEF) list_Car(l);      
      if (d != Def) {
	/* Expansion possible */
	if (term_ContainsSymbol(def_Expansion(d), term_TopSymbol(def_Predicate(Def)))) {
	  /* Resulting term is still a definition */
	  if (!term_ContainsSymbol(def_Expansion(Def), term_TopSymbol(def_Predicate(d)))) {
	    TERM newexpansion;
	    BOOL complete;

	    newexpansion = def_ApplyDefToTermOnce(Def, def_Expansion(d),
						  FlagStore, Precedence,
						  &complete);
	    term_Delete(def_Expansion(d));
	    def_RplacExp(d, newexpansion);
	  }
	  else {
	    symbol_RemoveProperty(term_TopSymbol(def_Predicate(d)), ISDEF);
	    def_Delete(d);
	    list_Rplaca(l, NULL);
	  }
	}
      }
    }
  }
}

void def_FlattenDefinitionsDestructive(PROOFSEARCH Search)
/**************************************************************
  INPUT:   A proofsearch object.
  RETURNS: None.
  EFFECT:  For every definition that is always applicable try to 
           expand the predicate in other
           definitions if possible.
***************************************************************/
{
  LIST l;

  for (l = prfs_Definitions(Search); !list_Empty(l); l=list_Cdr(l)) {
    DEF d;

    d = (DEF) list_Car(l);
    fol_PrettyPrintDFG(def_Predicate(d));
    if (d != NULL)
      def_FlattenWithOneDefinitionSemiDestructive(Search, d);
  }
  prfs_SetDefinitions(Search, list_PointerDeleteElement(prfs_Definitions(Search), NULL));
}

LIST def_GetTermsForProof(TERM Term, TERM SubTerm, int Polarity)
/**************************************************************
  INPUT:   Two formulas, <Term> and <SubTerm> which must be subformula
           of <Term>,an int which is the polarity of <SubTerm> in its
	   superterm and a list of variables <Variables>.
  RETURN:  A list of formulas that are used to prove the guard of Atom.
  COMMENT: Helpfunction of def_FindProofFor Guard.
  CAUTION: Father links must be set. Free variables may exist in terms of
           return list.
	   Terms are copied.
***************************************************************/
{
  TERM   SuperTerm, AddToList;
  SYMBOL Top;
  LIST   Scan1, NewList;

  term_AddFatherLinks(Term);

#ifdef CHECK
  if (!fol_CheckFormula(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In def_GetTermsForProof: Illegal input Term.");
    misc_FinishErrorReport();
  } 
#endif

  if (Term == SubTerm)
    return list_Nil();

  SuperTerm = term_Superterm(SubTerm);
  Top       = term_TopSymbol(SuperTerm);
  NewList   = list_Nil();
  AddToList = term_Null();

  if (symbol_Equal(Top, fol_Not()))
    return def_GetTermsForProof(Term, SuperTerm, -1*Polarity);

  if (symbol_Equal(Top, fol_Or()) && Polarity == 1) {
    /* Get and store AddToList */
    for (Scan1 = term_ArgumentList(SuperTerm); !list_Empty(Scan1); Scan1 = list_Cdr(Scan1)) {
      if (!term_HasPointerSubterm(list_Car(Scan1), SubTerm))
	NewList = list_Cons(term_Create(fol_Not(),list_List(term_Copy(list_Car(Scan1)))), NewList);
      /* NewList's elements have the form not(term) */
    }
    if (list_Length(NewList) == 1) {
      AddToList = list_Car(NewList);
      list_Delete(NewList);
    }
    else {
      AddToList = term_Create(fol_And(), NewList);
    }
    return list_Cons(AddToList, def_GetTermsForProof(Term, SuperTerm, Polarity));
  }
  if (symbol_Equal(Top, fol_And()) && Polarity == -1) {
    /* Get and store AddToList */
    if (list_Length(term_ArgumentList(SuperTerm)) == 2) {
      if (!term_HasPointerSubterm(term_FirstArgument(SuperTerm), SubTerm)) {
	AddToList = term_Copy(term_FirstArgument(SuperTerm));
      }
      else {
	AddToList = term_Copy(term_SecondArgument(SuperTerm));
      }
    }
    else if (list_Length(term_ArgumentList(SuperTerm)) > 2) {
      for (Scan1 = term_ArgumentList(SuperTerm); !list_Empty(Scan1); Scan1 = list_Cdr(Scan1)) {
	if (!term_HasPointerSubterm(list_Car(Scan1), SubTerm))
	  NewList = list_Cons(term_Copy(list_Car(Scan1)), NewList);
      }
      AddToList = term_Create(fol_And(), NewList);
    }
    else { /* Only one argument */
      AddToList = term_Copy(term_FirstArgument(SuperTerm));
    }
   return list_Cons(AddToList, def_GetTermsForProof(Term, SuperTerm, Polarity));
  }
  if (symbol_Equal(Top, fol_Implies())) {
    if (term_HasPointerSubterm(term_SecondArgument(SuperTerm), SubTerm) && Polarity == 1) {
      AddToList = term_Copy(term_FirstArgument(SuperTerm));
      return list_Cons(AddToList, def_GetTermsForProof(Term, SuperTerm, Polarity));
    }
    if (term_HasPointerSubterm(term_FirstArgument(SuperTerm), SubTerm) && Polarity == -1) {
      AddToList = term_Copy(term_SecondArgument(SuperTerm));
      AddToList = term_Create(fol_Not(), list_List(AddToList));
      return list_Cons(AddToList, def_GetTermsForProof(Term, SuperTerm, -1*Polarity));
    }
  }
  if (symbol_Equal(Top, fol_Implied())) { /* symmetric to fol_Implies */
    if (term_HasPointerSubterm(term_SecondArgument(SuperTerm), SubTerm) && Polarity == -1) {
      AddToList = term_Copy(term_FirstArgument(SuperTerm));
      AddToList = term_Create(fol_Not(), list_List(AddToList));
      return list_Cons(AddToList, def_GetTermsForProof(Term, SuperTerm, -1*Polarity)); 
    }
    if (term_HasPointerSubterm(term_FirstArgument(SuperTerm), SubTerm) && Polarity == 1) {
      AddToList = term_Copy(term_SecondArgument(SuperTerm));
      return list_Cons(AddToList, def_GetTermsForProof(Term, SuperTerm, Polarity));
    }
  }
  if (fol_IsQuantifier(Top))
    return def_GetTermsForProof(Term, SuperTerm, Polarity);

  /* In all other cases, SubTerm is the top level term in which Atom occurs disjunctively */

  return list_Nil();
}

BOOL def_FindProofForGuard(TERM Term, TERM Atom, TERM Guard, FLAGSTORE FlagStore, PRECEDENCE Precedence)
/**************************************************************************
  INPUT:   A formula Term, an atom Atom, a term Guard a flag store and a 
           precedence.
  RETURNS: True iff a proof can be found for Guard in Term.
***************************************************************************/
{
  BOOL LocallyTrue;
  TERM ToProve, Conjecture;
  LIST ArgList, FreeVars;

  ArgList    = list_Nil();
  FreeVars   = list_Nil();
  ToProve    = term_Null();
  Conjecture = term_Copy(Term);

#ifdef CHECK
  if (!fol_CheckFormula(Term)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In def_FindProofForGuard: No correct formula term.");
    misc_FinishErrorReport();
  }
  if (!term_HasPointerSubterm(Term, Atom)) {
    misc_StartErrorReport();
    misc_ErrorReport("\n In def_FindProofForGuard: Illegal input.");
    misc_FinishErrorReport();
  }
#endif
  
  ArgList = def_GetTermsForProof(Term, Atom, 1);

  if (!list_Empty(ArgList)) {
    ToProve  = term_Create(fol_And(), ArgList);
    FreeVars = list_Nconc(fol_FreeVariables(ToProve), fol_FreeVariables(Guard));
    FreeVars = term_DeleteDuplicatesFromList(FreeVars);
    term_CopyTermsInList(FreeVars);

    ArgList  = list_List(term_Copy(Guard));
    ArgList  = list_Cons(ToProve, ArgList);
    ToProve  = term_Create(fol_Implies(), ArgList);
    ToProve  = fol_CreateQuantifier(fol_All(), FreeVars, list_List(ToProve));

    /* Now ToProve has the form <forall[]: A implies Guard> */
    /*    puts("\n*ToProve: "); fol_PrettyPrintDFG(ToProve); */

#ifdef CHECK
    if (!fol_CheckFormula(ToProve)) {
      misc_StartErrorReport();
      misc_ErrorReport("\n In def_FindProofForGuard: No correct formula ToProve.");
      misc_FinishErrorReport();
    }
#endif

    LocallyTrue = cnf_HaveProof(list_Nil(), ToProve, FlagStore, Precedence);
    term_Delete(ToProve);
    term_Delete(Conjecture);
    if (LocallyTrue)
      return TRUE;
  }
  else {    /* empty list */
    term_DeleteTermList(ArgList);
    term_Delete(Conjecture);
  }

  return FALSE;
}

LIST def_ApplyDefinitionToTermList(LIST Defs, LIST Terms,
				   FLAGSTORE Flags, PRECEDENCE Precedence)
/**************************************************************************
  INPUT:   A list of definitions <Defs> and a list of pairs (Label.Formula),
           the maximal number <Applics> of expansions, a flag store and a
	   precedence.
  RETURNS: The possibly destructively changed list <Terms>.
  EFFECT:  In all formulas of Terms any definition of Defs is applied exactly
           once if possible.
           The terms are changed destructively if the expanded def_predicate 
	   is not an equality.
**************************************************************************/
{
  TERM ActTerm;             /* Actual term in Terms */
  TERM DefPredicate;        /* Actual definition predicate out of Defs */
  TERM Expansion;           /* Expansion term of the definition */
  TERM Target;              /* Target predicate to be replaced */
  LIST TargetList, Scan1, Scan2, Scan3;
  BOOL Apply;
  int  Applics;

  Apply      = TRUE;
  TargetList = list_Nil();
  Applics    = flag_GetFlagIntValue(Flags, flag_APPLYDEFS);

  while (Apply && Applics != 0) {
    Apply = FALSE;
    
    for (Scan1=Defs; !list_Empty(Scan1) && Applics != 0; Scan1=list_Cdr(Scan1)) {
      DefPredicate = term_Copy(def_Predicate(list_Car(Scan1)));

      /*      puts("\n----\nDefPred:"); fol_PrettyPrintDFG(DefPredicate);*/

      for (Scan2=Terms; !list_Empty(Scan2) && Applics != 0; Scan2=list_Cdr(Scan2)) {
	ActTerm   = list_PairSecond(list_Car(Scan2));
	TargetList = term_FindAllAtoms(ActTerm, term_TopSymbol(DefPredicate));
	term_AddFatherLinks(ActTerm);
	
	/*	puts("\nActTerm:"); fol_PrettyPrintDFG(ActTerm);*/

	for (Scan3=TargetList; !list_Empty(Scan3) && Applics != 0; Scan3=list_Cdr(Scan3)) {
	  Target = list_Car(Scan3);
	  cont_StartBinding();

	  /*	  puts("\nTarget:"); fol_PrettyPrintDFG(Target);*/

	  if (unify_Match(cont_LeftContext(), DefPredicate, Target)) {
	    cont_BackTrack();
	    Expansion = term_Copy(def_Expansion(list_Car(Scan1)));
	    fol_NormalizeVarsStartingAt(ActTerm, term_MaxVar(Expansion));
	    unify_Match(cont_LeftContext(), DefPredicate, Target);

	    if (fol_ApplyContextToTerm(cont_LeftContext(), Expansion)) { /* Matcher applied on Expansion */
	      if (!def_HasGuard(list_Car(Scan1))) {
		Applics--;
		Apply = TRUE;
		/*		puts("\n*no Guard!");*/
		term_RplacTop(Target, term_TopSymbol(Expansion));
		term_DeleteTermList(term_ArgumentList(Target));
		term_RplacArgumentList(Target, term_ArgumentList(Expansion));
		term_RplacArgumentList(Expansion, list_Nil());
		term_AddFatherLinks(ActTerm);
#ifdef CHECK
		if (!fol_CheckFormula(ActTerm)) {
		  misc_StartErrorReport();
		  misc_ErrorReport("\n In def_ApplyDefinitionToTermList:");
		  misc_ErrorReport(" No correct formula ActTerm.");
		  misc_FinishErrorReport();
		}
#endif
		if (flag_GetFlagIntValue(Flags, flag_PAPPLYDEFS)) {
		  puts("\nApplied definition for");
		  fol_PrettyPrintDFG(def_Predicate(list_Car(Scan1)));
		  puts("\nNew formula:");
		  fol_PrettyPrintDFG(ActTerm);
		}
	      }
	      else {  /* check guard */
		TERM Guard;
		Guard = term_Copy(def_ToProve(list_Car(Scan1)));
		if (fol_ApplyContextToTerm(cont_LeftContext(), Guard)) {
		  cont_BackTrack(); 
		  if (def_FindProofForGuard(ActTerm, Target,Guard,
					    Flags, Precedence)) {
		    Applics--;
		    Apply = TRUE;
		    term_RplacTop(Target, term_TopSymbol(Expansion));
		    term_DeleteTermList(term_ArgumentList(Target));
		    term_RplacArgumentList(Target, term_ArgumentList(Expansion));
		    term_RplacArgumentList(Expansion, list_Nil());
		    term_AddFatherLinks(ActTerm);
#ifdef CHECK
		    if (!fol_CheckFormula(ActTerm)) {
		      misc_StartErrorReport();
		      misc_ErrorReport("\n In def_ApplyDefinitionToTermList:");
		      misc_ErrorReport(" No correct formula ActTerm");
		      misc_FinishErrorReport();
		    }
#endif
		    if (flag_GetFlagIntValue(Flags, flag_PAPPLYDEFS)) {
		      puts("\nApplied definition for");
		      fol_PrettyPrintDFG(def_Predicate(list_Car(Scan1)));
		      puts("\nNew formula:");
		      fol_PrettyPrintDFG(ActTerm);
		    }
		  }
		}
		term_Delete(Guard);
	      }
	    }
	    term_Delete(Expansion);	    
	  }
	  cont_BackTrack();
	}
	list_Delete(TargetList);
      }
      term_Delete(DefPredicate);
    }
  }
  return Terms;
}
