blob: fc8409e5d7ed3fe99ac7cea3e7d12f1f6714e0c3 [file] [log] [blame]
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * SUBSTITUTION * */
/* * * */
/* * $Module: SUBSTITUTION * */
/* * * */
/* * Copyright (C) 1996, 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 GNU * */
/* * General Public License as published by the Free * */
/* * Software Foundation; either version 2 of the License, * */
/* * or (at your option) any later version. * */
/* * * */
/* * 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 GNU General Public * */
/* * License for more details. * */
/* * * */
/* * You should have received a copy of the GNU General * */
/* * Public License along with this program; if not, write * */
/* * to the Free Software Foundation, Inc., 59 Temple * */
/* * Place, Suite 330, Boston, MA 02111-1307 USA * */
/* * * */
/* * * */
/* $Revision$ * */
/* $State$ * */
/* $Date$ * */
/* $Author$ * */
/* * * */
/* * Contact: * */
/* * Christoph Weidenbach * */
/* * MPI fuer Informatik * */
/* * Stuhlsatzenhausweg 85 * */
/* * 66123 Saarbruecken * */
/* * Email: weidenb@mpi-sb.mpg.de * */
/* * Germany * */
/* * * */
/* ********************************************************** */
/**************************************************************/
/* $RCSfile$ */
#include "subst.h"
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * SUBSTITUTION CREATION AND DELETION * */
/* * * */
/* ********************************************************** */
/**************************************************************/
SUBST subst_Add(SYMBOL Symbol, TERM Codomain, SUBST Subst)
{
SUBST Result;
Result = subst_Get();
Result->next = Subst;
Result->dom = Symbol;
Result->codomain = Codomain;
return Result;
}
void subst_Delete(SUBST Subst)
{
SUBST Next;
while (subst_Exist(Subst)) {
Next = subst_Next(Subst);
if (subst_Cod(Subst))
term_Delete(subst_Cod(Subst));
subst_FreeOneNode(Subst);
Subst = Next;
}
}
void subst_Free(SUBST Subst)
{
SUBST Next;
while (subst_Exist(Subst)) {
Next = subst_Next(Subst);
subst_FreeOneNode(Subst);
Subst = Next;
}
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * FUNCTIONS ON SUBSTITUTIONS * */
/* * * */
/* ********************************************************** */
/**************************************************************/
TERM subst_Term(SYMBOL Symbol, SUBST Subst)
{
for (; subst_Exist(Subst); Subst = subst_Next(Subst))
if (symbol_Equal(Symbol,subst_Dom(Subst)))
return subst_Cod(Subst);
return (TERM)NULL;
}
static TERM subst_ApplyIntern(SUBST Subst, TERM Term)
{
TERM RplacTerm;
LIST Arglist;
SYMBOL Top;
Top = term_TopSymbol(Term);
if (symbol_IsVariable(Top) && (RplacTerm = subst_Term(Top,Subst))) {
Arglist = term_CopyTermList(term_ArgumentList(RplacTerm));
term_RplacTop(Term, term_TopSymbol(RplacTerm));
term_DeleteTermList(term_ArgumentList(Term));
term_RplacArgumentList(Term, Arglist);
} else {
for (Arglist = term_ArgumentList(Term);
!list_Empty(Arglist);
Arglist = list_Cdr(Arglist))
subst_ApplyIntern(Subst, list_Car(Arglist));
}
return Term;
}
TERM subst_Apply(SUBST Subst, TERM Term)
{
if (subst_Empty(Subst))
return Term;
return subst_ApplyIntern(Subst, Term);
}
SUBST subst_Merge(SUBST Source, SUBST Drain)
{
SUBST Scan;
BOOL Changed;
for (; subst_Exist(Source); Source = subst_Next(Source)) {
/* Apply current assignment of Source to all */
/* assignments of Drain. If the current ass. */
/* cannot be applied to any codomain in Drain */
/* the current assignment is added to Drain. */
Changed = FALSE;
for (Scan = Drain;
subst_Exist(Scan);
Scan = subst_Next(Scan))
if (term_SubstituteVariable(Source->dom,
Source->codomain,
&(Scan->codomain)))
Changed = TRUE;
if (!Changed)
Drain = subst_Add(Source->dom,
term_Copy(Source->codomain),
Drain);
}
return Drain;
}
SUBST subst_Compose(SUBST Outer, SUBST Inner)
/**************************************************************
INPUT: Two substitutions.
RETURNS: The substitution corresponding to the composition of
<Outer> and <Inner>.
EFFECT: <Outer> is destructively applied to the codomain of <Inner>
<Inner> is destructively extended
***************************************************************/
{
SUBST Scan1,Scan2,New;
New = subst_Nil();
for (Scan1=Outer; subst_Exist(Scan1); Scan1 = subst_Next(Scan1)) {
for (Scan2 = Inner;subst_Exist(Scan2);Scan2 = subst_Next(Scan2))
term_SubstituteVariable(subst_Dom(Scan1),subst_Cod(Scan1),&(Scan2->codomain));
if (!subst_BindVar(subst_Dom(Scan1),Inner))
New = subst_Add(subst_Dom(Scan1), term_Copy(subst_Cod(Scan1)),New);
}
return subst_NUnion(Inner,New);
}
BOOL subst_BindVar(SYMBOL Var, SUBST Subst)
/**************************************************************
INPUT: A variable symbol and a substitution.
RETURNS: TRUE iff <Var> is contained in the domain of <Subst>
***************************************************************/
{
SUBST Scan;
for (Scan=Subst; subst_Exist(Scan); Scan = subst_Next(Scan))
if (symbol_Equal(subst_Dom(Scan),Var))
return TRUE;
return FALSE;
}
SUBST subst_Copy(SUBST Subst)
{
SUBST Copy, Result;
for (Result = subst_Nil(),
Copy = subst_Nil();
subst_Exist(Subst);
Subst = subst_Next(Subst))
if (subst_Exist(Result)) {
subst_SetNext(Copy, subst_Add(subst_Dom(Subst),
term_Copy(subst_Cod(Subst)),
subst_Nil()));
Copy = subst_Next(Copy);
} else {
Result = subst_Add(subst_Dom(Subst),
term_Copy(subst_Cod(Subst)),
subst_Nil());
Copy = Result;
}
return Result;
}
BOOL subst_MatchTops(const CONTEXT Context, SUBST Subst)
{
for ( ; subst_Exist(Subst); Subst = subst_Next(Subst))
if (cont_ContextBindingTerm(Context, subst_Dom(Subst)) &&
term_EqualTopSymbols(cont_ContextBindingTerm(Context, subst_Dom(Subst)),
subst_Cod(Subst)))
return TRUE;
return FALSE;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * UNIFICATION TEST * */
/* * * */
/* ********************************************************** */
/**************************************************************/
BOOL subst_Unify(CONTEXT IndexContext, SUBST Subst)
/*********************************************************
INPUT:
RETURNS:
CAUTION: 'Subst' IS ASSUMED TO BE NON-EMPTY.
**********************************************************/
{
while (subst_Exist(Subst)) {
if (!cont_VarIsBound(IndexContext, subst_Dom(Subst))) {
if (unify_OccurCheck(IndexContext, subst_Dom(Subst), IndexContext, subst_Cod(Subst)))
return FALSE;
else
cont_CreateBinding(IndexContext, subst_Dom(Subst), IndexContext, subst_Cod(Subst));
} else if (!unify_UnifyAllOC(IndexContext,
IndexContext,
subst_Cod(Subst),
cont_ContextBindingContext(IndexContext,
subst_Dom(Subst)),
cont_ContextBindingTerm(IndexContext,
subst_Dom(Subst))))
return FALSE;
Subst = subst_Next(Subst);
}
return TRUE;
}
BOOL subst_IsShallow(SUBST Subst) {
/**********************************************************
INPUT: A unifier
RETURNS: TRUE, if the unifier is valid :
a variable or a ground term or a function with only
variables or ground terms as arguments.
***********************************************************/
SUBST SubstScan;
for (SubstScan = Subst; SubstScan != subst_Nil();
SubstScan = subst_Next(SubstScan)) {
TERM Codomain = subst_Cod(SubstScan);
if ((!term_IsVariable(Codomain))
&& (!term_IsGround(Codomain))) {
LIST Scan ;
for (Scan = term_ArgumentList(Codomain); Scan != list_Nil();
Scan = list_Cdr(Scan)) {
if ((!term_IsVariable(list_Car(Scan))
&& (!term_IsGround(list_Car(Scan)))))
return FALSE;
}
}
}
return TRUE;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * GENERALIZATION TEST * */
/* * * */
/* ********************************************************** */
/**************************************************************/
BOOL subst_Match(const CONTEXT Context, SUBST Subst)
/*********************************************************
INPUT:
RETURNS:
CAUTION: 'Subst' IS ASSUMED TO BE NON-EMPTY.
**********************************************************/
{
while (subst_Exist(Subst)) {
if (!cont_VarIsBound(Context, subst_Dom(Subst)) ||
!unify_Match(Context,
subst_Cod(Subst),
cont_ContextBindingTerm(Context, subst_Dom(Subst))))
return FALSE;
Subst = subst_Next(Subst);
}
return TRUE;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * INSTANCE TEST * */
/* * * */
/* ********************************************************** */
/**************************************************************/
BOOL subst_MatchReverse(const CONTEXT IndexContext, SUBST Subst)
/*********************************************************
INPUT:
RETURNS:
CAUTION: 'Subst' IS ASSUMED TO BE NON-EMPTY.
**********************************************************/
{
while (subst_Exist(Subst)) {
if (!cont_VarIsBound(IndexContext, subst_Dom(Subst))) {
if (symbol_IsIndexVariable(subst_Dom(Subst)))
cont_CreateBinding(IndexContext,
subst_Dom(Subst),
cont_InstanceContext(),
subst_Cod(Subst));
else
return FALSE;
}
else if (!unify_MatchReverse(IndexContext,
subst_Cod(Subst),
cont_ContextBindingContext(IndexContext, subst_Dom(Subst)),
cont_ContextBindingTerm(IndexContext, subst_Dom(Subst))))
return FALSE;
Subst = subst_Next(Subst);
}
return TRUE;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * VARIATION TEST * */
/* * * */
/* ********************************************************** */
/**************************************************************/
BOOL subst_Variation(const CONTEXT Context, SUBST Subst)
/*********************************************************
INPUT:
RETURNS:
CAUTION: 'Subst' IS ASSUMED TO BE NON-EMPTY.
**********************************************************/
{
while (subst_Exist(Subst)) {
if (!cont_VarIsBound(Context, subst_Dom(Subst)) ||
!unify_Variation(Context,
subst_Cod(Subst),
cont_ContextBindingTerm(Context, subst_Dom(Subst))))
return FALSE;
Subst = subst_Next(Subst);
}
return TRUE;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * COMMON GENERALIZATIONS * */
/* * * */
/* ********************************************************** */
/**************************************************************/
SUBST subst_ComGen(const CONTEXT Context, SUBST Subst, SUBST* SubstOld,
SUBST* SubstNew)
/*********************************************************
INPUT:
RETURNS:
CAUTION: 'Subst' IS ASSUMED TO BE NON-EMPTY.
**********************************************************/
{
SUBST Result;
Result = *SubstOld = *SubstNew = NULL;
do {
if (!cont_VarIsBound(Context, subst_Dom(Subst)))
*SubstOld=subst_Add(subst_Dom(Subst), term_Copy(subst_Cod(Subst)), *SubstOld);
else if (term_Equal(cont_ContextBindingTerm(Context, subst_Dom(Subst)),
subst_Cod(Subst)))
Result = subst_Add(subst_Dom(Subst), term_Copy(subst_Cod(Subst)), Result);
else
if (!symbol_Equal(term_TopSymbol(cont_ContextBindingTerm(Context,
subst_Dom(Subst))),
term_TopSymbol(subst_Cod(Subst)))) {
*SubstOld=subst_Add(subst_Dom(Subst),
term_Copy(subst_Cod(Subst)),
*SubstOld);
*SubstNew=subst_Add(subst_Dom(Subst),
term_Copy(cont_ContextBindingTerm(Context,
subst_Dom(Subst))),
*SubstNew);
} else
Result = subst_Add(subst_Dom(Subst),
unify_ComGenLinear(Context,
SubstNew,
cont_ContextBindingTerm(Context,
subst_Dom(Subst)),
SubstOld,
subst_Cod(Subst)),
Result);
cont_CloseBinding(Context, subst_Dom(Subst));
Subst = subst_Next(Subst);
} while (subst_Exist(Subst));
return Result;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * CLOSE BINDINGS * */
/* * * */
/* ********************************************************** */
/**************************************************************/
void subst_CloseVariables(const CONTEXT Context, SUBST Subst)
{
for (; subst_Exist(Subst); Subst = subst_Next(Subst))
cont_CloseBinding(Context, subst_Dom(Subst));
}
SUBST subst_CloseOpenVariables(SUBST Result)
{
while (cont_LastBinding()) {
if (cont_LastIsBound())
Result = subst_Add(cont_LastBindingSymbol(),
term_Copy(cont_LastBindingTerm()),
Result);
cont_BackTrackLastBinding();
}
return Result;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * EXTRACT UNIFIER * */
/* * * */
/* ********************************************************** */
/**************************************************************/
void subst_ExtractUnifier(const CONTEXT CL,
SUBST* LeftSubst,
const CONTEXT CR,
SUBST* RightSubst)
/*********************************************************
INPUT: 'LeftSubst', 'RightSubst' for the unifier,
renaming the codomain variables starts at
'MinimumCoVariable' excl., number of
renamings are ADDED to 'Bindings'.
RETURNS: Nothing.
SUMMARY: Extracts the unifier into two substitutions
with renamed variables in the codomain.
CAUTION: DOES NOT RESET THE BINDINGS, CREATES EVEN
MORE BINDINGS BECAUSE OF RENAMING.
**********************************************************/
{
CONTEXT Scan;
*LeftSubst = subst_Nil();
*RightSubst = subst_Nil();
Scan = cont_LastBinding();
while (Scan) {
if (cont_IsInContext(CL,
cont_BindingSymbol(Scan),
Scan))
*LeftSubst = subst_Add(cont_BindingSymbol(Scan),
cont_CopyAndApplyBindings(cont_BindingContext(Scan),
cont_BindingTerm(Scan)),
*LeftSubst);
else if (cont_IsInContext(CR,
cont_BindingSymbol(Scan),
Scan))
*RightSubst = subst_Add(cont_BindingSymbol(Scan),
cont_CopyAndApplyBindings(cont_BindingContext(Scan),
cont_BindingTerm(Scan)),
*RightSubst);
Scan = cont_BindingLink(Scan);
}
}
void subst_ExtractUnifierCom(const CONTEXT Context, SUBST* Subst)
/*********************************************************
INPUT: 'LeftSubst', 'RightSubst' for the unifier,
renaming the codomain variables starts at
'MinimumCoVariable' excl., number of
renamings are ADDED to 'Bindings'.
RETURNS: Nothing.
SUMMARY: Extracts the unifier into two substitutions
with renamed variables in the codomain.
CAUTION: DOES NOT RESET THE BINDINGS, CREATES EVEN
MORE BINDINGS BECAUSE OF RENAMING.
**********************************************************/
{
CONTEXT Scan;
*Subst = subst_Nil();
Scan = cont_LastBinding();
while (Scan) {
*Subst =
subst_Add(cont_BindingSymbol(Scan),
cont_CopyAndApplyBindingsCom(Context, cont_BindingTerm(Scan)),
*Subst);
Scan = cont_BindingLink(Scan);
}
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * EXTRACT MATCHER * */
/* * * */
/* ********************************************************** */
/**************************************************************/
SUBST subst_ExtractMatcher(void)
/*********************************************************
INPUT: None.
RETURNS: The matcher.
SUMMARY: Extracts the matcher without renaming.
CAUTION: DOES NOT RESET THE BINDINGS, DOES NOT COPY
THE CODOMAINS.
**********************************************************/
{
CONTEXT Scan;
SUBST Result;
for (Scan = cont_LastBinding(), Result = subst_Nil();
Scan;
Scan = cont_BindingLink(Scan))
Result = subst_Add(cont_BindingSymbol(Scan),
cont_BindingTerm(Scan),
Result);
return Result;
}
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * OUTPUT * */
/* * * */
/* ********************************************************** */
/**************************************************************/
void subst_Print(SUBST Subst)
{
fputs("{ ", stdout);
for (; subst_Exist(Subst); Subst = subst_Next(Subst)) {
symbol_Print(subst_Dom(Subst));
if (subst_Cod(Subst)) {
fputs(" -> ", stdout);
term_PrintPrefix(subst_Cod(Subst));
}
if (subst_Next(Subst))
fputs("; ", stdout);
}
fputs(" }", stdout);
}