2004-04-23 11:58:43 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
2004-07-24 20:07:29 +01:00
|
|
|
#include "term.h"
|
|
|
|
#include "termlist.h"
|
|
|
|
#include "substitution.h"
|
2004-04-23 11:58:43 +01:00
|
|
|
#include "mgu.h"
|
|
|
|
#include "memory.h"
|
2005-06-02 13:14:28 +01:00
|
|
|
#include "type.h"
|
2005-06-16 15:10:07 +01:00
|
|
|
#include "specialterm.h"
|
2004-04-23 11:58:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Most General Unifier
|
|
|
|
|
|
|
|
Unification etc.
|
|
|
|
|
|
|
|
New version yields a termlist with substituted variables, which can later be reset to NULL.
|
|
|
|
*/
|
|
|
|
|
2005-06-02 13:14:28 +01:00
|
|
|
//! Internal constant. If true, typed checking
|
2004-08-15 17:44:54 +01:00
|
|
|
/**
|
2005-06-07 16:02:27 +01:00
|
|
|
* Analoguous to switches.match
|
2004-08-15 17:44:54 +01:00
|
|
|
* 0 typed
|
|
|
|
* 1 basic typeflaws
|
|
|
|
* 2 all typeflaws
|
|
|
|
*/
|
2005-06-02 13:14:28 +01:00
|
|
|
static int mgu_match = 0;
|
2004-08-15 17:08:53 +01:00
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
//! Set mgu mode (basically switches.match)
|
2005-06-02 13:14:28 +01:00
|
|
|
void
|
|
|
|
setMguMode (const int match)
|
|
|
|
{
|
|
|
|
mgu_match = match;
|
|
|
|
}
|
|
|
|
|
2004-08-15 17:08:53 +01:00
|
|
|
void
|
|
|
|
showSubst (Term t)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (!DEBUGL (5))
|
|
|
|
return;
|
|
|
|
|
|
|
|
indent ();
|
|
|
|
printf ("Substituting ");
|
|
|
|
termPrint (t);
|
|
|
|
printf (", typed ");
|
|
|
|
termlistPrint (t->stype);
|
|
|
|
if (realTermLeaf (t->subst))
|
|
|
|
{
|
|
|
|
printf ("->");
|
|
|
|
termlistPrint (t->subst->stype);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf (", composite term");
|
|
|
|
}
|
|
|
|
if (t->type != VARIABLE)
|
|
|
|
{
|
|
|
|
printf (" (bound roleconstant)");
|
|
|
|
}
|
|
|
|
printf ("\n");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-10-07 21:38:41 +01:00
|
|
|
//! See if this is preferred substitution
|
|
|
|
/**
|
|
|
|
* By default, ta->tb will map. Returning 0 (false) will swap them.
|
|
|
|
*/
|
2005-10-08 21:22:24 +01:00
|
|
|
int
|
2005-10-07 21:38:41 +01:00
|
|
|
preferSubstitutionOrder (Term ta, Term tb)
|
|
|
|
{
|
|
|
|
if (termlistLength (ta->stype) == 1 && inTermlist (ta->stype, TERM_Agent))
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* If the first one is an agent type, we prefer swapping.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Per default, leave it as it is.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-08-15 17:08:53 +01:00
|
|
|
//! See if a substitution is valid
|
|
|
|
__inline__ int
|
|
|
|
goodsubst (Term tvar, Term tsubst)
|
|
|
|
{
|
2005-06-02 13:14:28 +01:00
|
|
|
Term tbuf;
|
|
|
|
int res;
|
2005-01-14 18:18:40 +00:00
|
|
|
|
2005-06-02 13:14:28 +01:00
|
|
|
tbuf = tvar->subst;
|
|
|
|
tvar->subst = tsubst;
|
2005-01-14 18:18:40 +00:00
|
|
|
|
2005-06-02 13:14:28 +01:00
|
|
|
res = checkTypeTerm (mgu_match, tvar);
|
|
|
|
|
|
|
|
tvar->subst = tbuf;
|
|
|
|
return res;
|
2004-08-15 17:08:53 +01:00
|
|
|
}
|
|
|
|
|
2004-05-15 17:43:20 +01:00
|
|
|
//! Undo all substitutions in a list of variables.
|
|
|
|
/**
|
|
|
|
* The termlist should contain only variables.
|
|
|
|
*/
|
2004-04-23 11:58:43 +01:00
|
|
|
void
|
|
|
|
termlistSubstReset (Termlist tl)
|
|
|
|
{
|
|
|
|
while (tl != NULL)
|
|
|
|
{
|
|
|
|
tl->term->subst = NULL;
|
|
|
|
tl = tl->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-15 17:43:20 +01:00
|
|
|
//! Most general unifier.
|
|
|
|
/**
|
|
|
|
* Try to determine the most general unifier of two terms.
|
2004-08-19 14:55:16 +01:00
|
|
|
* Resulting termlist must be termlistDelete'd.
|
|
|
|
*
|
2004-05-15 17:43:20 +01:00
|
|
|
*@return Returns a list of variables, that were previously open, but are now closed
|
|
|
|
* in such a way that the two terms unify. Returns \ref MGUFAIL if it is impossible.
|
|
|
|
*/
|
2004-04-23 11:58:43 +01:00
|
|
|
Termlist
|
|
|
|
termMguTerm (Term t1, Term t2)
|
|
|
|
{
|
|
|
|
/* added for speed */
|
|
|
|
t1 = deVar (t1);
|
|
|
|
t2 = deVar (t2);
|
|
|
|
if (t1 == t2)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(hasTermVariable (t1) || hasTermVariable (t2)))
|
|
|
|
{
|
|
|
|
if (isTermEqual (t1, t2))
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return MGUFAIL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-07 21:38:41 +01:00
|
|
|
/*
|
2005-10-08 21:22:24 +01:00
|
|
|
* Distinguish a special case where both are unbound variables that will be
|
|
|
|
* connected, and I want to give one priority over the other for readability.
|
|
|
|
*
|
|
|
|
* Because t1 and t2 have been deVar'd means that if they are variables, they
|
|
|
|
* are also unbound.
|
2005-10-07 21:38:41 +01:00
|
|
|
*/
|
2005-10-08 21:22:24 +01:00
|
|
|
|
|
|
|
if (realTermVariable (t1) && realTermVariable (t2) && goodsubst (t1, t2))
|
|
|
|
{
|
|
|
|
/* Both are unbound variables. Decide.
|
|
|
|
*
|
|
|
|
* The plan: t1->subst will point to t2. But maybe we prefer the other
|
|
|
|
* way around?
|
|
|
|
*/
|
|
|
|
if (preferSubstitutionOrder (t2, t1))
|
|
|
|
{
|
|
|
|
Term t3;
|
|
|
|
|
|
|
|
// Swappy.
|
|
|
|
t3 = t1;
|
|
|
|
t1 = t2;
|
|
|
|
t2 = t3;
|
|
|
|
}
|
|
|
|
t1->subst = t2;
|
|
|
|
#ifdef DEBUG
|
|
|
|
showSubst (t1);
|
|
|
|
#endif
|
|
|
|
return termlistAdd (NULL, t1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* symmetrical tests for single variable.
|
|
|
|
*/
|
|
|
|
|
2004-08-16 10:50:37 +01:00
|
|
|
if (realTermVariable (t2))
|
2004-04-23 11:58:43 +01:00
|
|
|
{
|
2004-08-17 15:11:25 +01:00
|
|
|
if (termSubTerm (t1, t2) || !goodsubst (t2, t1))
|
2004-04-23 11:58:43 +01:00
|
|
|
return MGUFAIL;
|
|
|
|
else
|
|
|
|
{
|
2004-08-16 10:50:37 +01:00
|
|
|
t2->subst = t1;
|
2004-04-23 11:58:43 +01:00
|
|
|
#ifdef DEBUG
|
2004-08-16 10:50:37 +01:00
|
|
|
showSubst (t2);
|
2004-04-23 11:58:43 +01:00
|
|
|
#endif
|
2004-08-16 10:50:37 +01:00
|
|
|
return termlistAdd (NULL, t2);
|
2004-04-23 11:58:43 +01:00
|
|
|
}
|
|
|
|
}
|
2004-08-16 10:50:37 +01:00
|
|
|
if (realTermVariable (t1))
|
2004-04-23 11:58:43 +01:00
|
|
|
{
|
2004-08-17 15:11:25 +01:00
|
|
|
if (termSubTerm (t2, t1) || !goodsubst (t1, t2))
|
2004-04-23 11:58:43 +01:00
|
|
|
return MGUFAIL;
|
|
|
|
else
|
|
|
|
{
|
2004-08-16 10:50:37 +01:00
|
|
|
t1->subst = t2;
|
2004-04-23 11:58:43 +01:00
|
|
|
#ifdef DEBUG
|
2004-08-16 10:50:37 +01:00
|
|
|
showSubst (t1);
|
2004-04-23 11:58:43 +01:00
|
|
|
#endif
|
2004-08-16 10:50:37 +01:00
|
|
|
return termlistAdd (NULL, t1);
|
2004-04-23 11:58:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* left & right are compounds with variables */
|
|
|
|
if (t1->type != t2->type)
|
|
|
|
return MGUFAIL;
|
|
|
|
|
|
|
|
/* identical compounds */
|
|
|
|
/* encryption first */
|
2004-08-13 21:09:12 +01:00
|
|
|
if (realTermEncrypt (t1))
|
2004-04-23 11:58:43 +01:00
|
|
|
{
|
|
|
|
Termlist tl1, tl2;
|
|
|
|
|
2004-11-16 12:07:55 +00:00
|
|
|
tl1 = termMguTerm (TermKey (t1), TermKey (t2));
|
2004-04-23 11:58:43 +01:00
|
|
|
if (tl1 == MGUFAIL)
|
|
|
|
{
|
|
|
|
return MGUFAIL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-11-16 12:07:55 +00:00
|
|
|
tl2 = termMguTerm (TermOp (t1), TermOp (t2));
|
2004-04-23 11:58:43 +01:00
|
|
|
if (tl2 == MGUFAIL)
|
|
|
|
{
|
|
|
|
termlistSubstReset (tl1);
|
|
|
|
termlistDelete (tl1);
|
|
|
|
return MGUFAIL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return termlistConcat (tl1, tl2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tupling second
|
|
|
|
non-associative version ! TODO other version */
|
|
|
|
if (isTermTuple (t1))
|
|
|
|
{
|
|
|
|
Termlist tl1, tl2;
|
|
|
|
|
2004-11-16 12:07:55 +00:00
|
|
|
tl1 = termMguTerm (TermOp1 (t1), TermOp1 (t2));
|
2004-04-23 11:58:43 +01:00
|
|
|
if (tl1 == MGUFAIL)
|
|
|
|
{
|
|
|
|
return MGUFAIL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-11-16 12:07:55 +00:00
|
|
|
tl2 = termMguTerm (TermOp2 (t1), TermOp2 (t2));
|
2004-04-23 11:58:43 +01:00
|
|
|
if (tl2 == MGUFAIL)
|
|
|
|
{
|
|
|
|
termlistSubstReset (tl1);
|
|
|
|
termlistDelete (tl1);
|
|
|
|
return MGUFAIL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return termlistConcat (tl1, tl2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return MGUFAIL;
|
|
|
|
}
|
2004-08-09 22:22:24 +01:00
|
|
|
|
|
|
|
//! Most general interm unifiers of t1 interm t2
|
|
|
|
/**
|
|
|
|
* Try to determine the most general interm unifiers of two terms.
|
2004-08-11 15:09:12 +01:00
|
|
|
*@returns Nothing. Iteration gets termlist of substitutions.
|
2004-08-09 22:22:24 +01:00
|
|
|
*/
|
2004-08-11 15:09:12 +01:00
|
|
|
int
|
2004-08-30 22:49:51 +01:00
|
|
|
termMguInTerm (Term t1, Term t2, int (*iterator) (Termlist))
|
2004-08-09 22:22:24 +01:00
|
|
|
{
|
|
|
|
Termlist tl;
|
2004-08-11 15:09:12 +01:00
|
|
|
int flag;
|
2004-08-09 22:22:24 +01:00
|
|
|
|
2004-08-11 15:09:12 +01:00
|
|
|
flag = 1;
|
2004-08-09 22:22:24 +01:00
|
|
|
t2 = deVar (t2);
|
2004-08-13 14:25:25 +01:00
|
|
|
if (t2 != NULL)
|
2004-08-09 22:22:24 +01:00
|
|
|
{
|
2004-08-13 21:09:12 +01:00
|
|
|
if (realTermTuple (t2))
|
2004-08-13 14:25:25 +01:00
|
|
|
{
|
|
|
|
// t2 is a tuple, consider interm options as well.
|
2004-11-16 12:07:55 +00:00
|
|
|
flag = flag && termMguInTerm (t1, TermOp1 (t2), iterator);
|
|
|
|
flag = flag && termMguInTerm (t1, TermOp2 (t2), iterator);
|
2004-08-13 14:25:25 +01:00
|
|
|
}
|
|
|
|
// simple clause or combined
|
|
|
|
tl = termMguTerm (t1, t2);
|
|
|
|
if (tl != MGUFAIL)
|
|
|
|
{
|
|
|
|
// Iterate
|
|
|
|
flag = flag && iterator (tl);
|
|
|
|
// Reset variables
|
|
|
|
termlistSubstReset (tl);
|
2004-08-19 14:55:16 +01:00
|
|
|
// Remove list
|
|
|
|
termlistDelete (tl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (deVar (t1) != NULL)
|
|
|
|
{
|
|
|
|
flag = 0;
|
2004-08-13 14:25:25 +01:00
|
|
|
}
|
2004-08-10 12:26:14 +01:00
|
|
|
}
|
2004-08-11 15:09:12 +01:00
|
|
|
return flag;
|
2004-08-09 22:22:24 +01:00
|
|
|
}
|
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
//! Most general subterm unifiers of smallterm subterm bigterm
|
2004-08-09 22:22:24 +01:00
|
|
|
/**
|
|
|
|
* Try to determine the most general subterm unifiers of two terms.
|
2005-05-17 19:45:01 +01:00
|
|
|
*@returns Nothing. Iteration gets termlist of subst, and list of keys needed
|
|
|
|
* to decrypt. This termlist does not need to be deleted, because it is handled
|
|
|
|
* by the mguSubTerm itself.
|
2004-08-09 22:22:24 +01:00
|
|
|
*/
|
2004-08-11 15:09:12 +01:00
|
|
|
int
|
2005-05-17 19:45:01 +01:00
|
|
|
termMguSubTerm (Term smallterm, Term bigterm,
|
|
|
|
int (*iterator) (Termlist, Termlist), Termlist inverses,
|
|
|
|
Termlist cryptlist)
|
2004-08-09 22:22:24 +01:00
|
|
|
{
|
2004-08-11 15:09:12 +01:00
|
|
|
int flag;
|
|
|
|
|
|
|
|
flag = 1;
|
2005-05-17 19:45:01 +01:00
|
|
|
smallterm = deVar (smallterm);
|
|
|
|
bigterm = deVar (bigterm);
|
|
|
|
if (bigterm != NULL)
|
2004-08-09 22:22:24 +01:00
|
|
|
{
|
2004-08-30 22:49:51 +01:00
|
|
|
Termlist tl;
|
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
if (!realTermLeaf (bigterm))
|
2004-08-09 22:22:24 +01:00
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
if (realTermTuple (bigterm))
|
2004-08-13 15:35:22 +01:00
|
|
|
{
|
|
|
|
// 'simple' tuple
|
|
|
|
flag =
|
2005-05-17 19:45:01 +01:00
|
|
|
flag
|
|
|
|
&& termMguSubTerm (smallterm, TermOp1 (bigterm), iterator,
|
|
|
|
inverses, cryptlist);
|
|
|
|
flag = flag
|
|
|
|
&& termMguSubTerm (smallterm, TermOp2 (bigterm), iterator,
|
|
|
|
inverses, cryptlist);
|
2004-08-13 15:35:22 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Must be encryption
|
2005-05-17 19:45:01 +01:00
|
|
|
Term keyneeded;
|
2004-08-13 15:35:22 +01:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
keyneeded = inverseKey (inverses, TermKey (bigterm));
|
2004-08-20 16:09:49 +01:00
|
|
|
// We can never produce the TERM_Hidden key, thus, this is not a valid iteration.
|
2005-05-17 19:45:01 +01:00
|
|
|
if (!isTermEqual (keyneeded, TERM_Hidden))
|
2004-08-20 16:09:49 +01:00
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
cryptlist = termlistAdd (cryptlist, bigterm); // Append, so the last encrypted term in the list is the most 'inner' one, and the first is the outer one.
|
2004-08-13 15:35:22 +01:00
|
|
|
|
2004-08-20 16:09:49 +01:00
|
|
|
// Recurse
|
|
|
|
flag =
|
2004-11-16 12:07:55 +00:00
|
|
|
flag
|
2005-05-17 19:45:01 +01:00
|
|
|
&& termMguSubTerm (smallterm, TermOp (bigterm), iterator,
|
|
|
|
inverses, cryptlist);
|
2004-08-20 16:09:49 +01:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
|
|
|
|
cryptlist = termlistDelTerm (cryptlist);
|
2004-08-20 16:09:49 +01:00
|
|
|
}
|
2005-05-17 19:45:01 +01:00
|
|
|
termDelete (keyneeded);
|
2004-08-13 15:35:22 +01:00
|
|
|
}
|
2004-08-09 22:22:24 +01:00
|
|
|
}
|
2004-08-13 15:35:22 +01:00
|
|
|
// simple clause or combined
|
2005-05-17 19:45:01 +01:00
|
|
|
tl = termMguTerm (smallterm, bigterm);
|
2004-08-13 15:35:22 +01:00
|
|
|
if (tl != MGUFAIL)
|
2004-08-09 22:22:24 +01:00
|
|
|
{
|
2004-08-13 15:35:22 +01:00
|
|
|
// Iterate
|
2005-05-17 19:45:01 +01:00
|
|
|
flag = flag && iterator (tl, cryptlist);
|
2004-08-13 15:35:22 +01:00
|
|
|
// Reset variables
|
|
|
|
termlistSubstReset (tl);
|
2004-08-19 14:55:16 +01:00
|
|
|
// Remove list
|
|
|
|
termlistDelete (tl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
if (smallterm != NULL)
|
2004-08-19 14:55:16 +01:00
|
|
|
{
|
|
|
|
flag = 0;
|
2004-08-09 22:22:24 +01:00
|
|
|
}
|
|
|
|
}
|
2004-08-11 15:09:12 +01:00
|
|
|
return flag;
|
2004-08-09 22:22:24 +01:00
|
|
|
}
|