generalizer.lf

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FILE. . . . . /home/hak/d/life/generalizer.lf
% EDIT BY . . . Hassan Ait-Kaci
% ON MACHINE. . Latitude407
% STARTED ON. . Fri Dec 26 10:12:08 2003
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Last modified on Tue Jan 13 13:25:18 2004 by hak@ilog.com

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  This code computes the generalizer of two psi-terms. This essentially
%  means that it computes the least general term of which the two given
%  terms are substitution instances.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% function and predicate forms of the generalizer
generalize_f(Term1, Term2) -> Term_Gen | generalize_p(Term1, Term2, Term_Gen).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% set up the auxiliary predicate "generalize_p" which starts with the empty
% substitution list "Subst_Init". "Subst_Final" is the collected set of
% substitutions. this list is a set of triples [u,x1,x2] which simply means
% that u is the term in the generalizer that corresponds to the generalization
% of the terms x1 and x2.
generalize_p(Term1, Term2, Term_Gen) :- 
        Subst_Init = [],
        gen_aux(Term1, Term2, Subst_Init, Subst_Final, Term_Gen).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% the auxiliary function "gen_aux"
%          -  gets the LUB of the rootsorts
%          -  keeps track of this generalization step by updating the
%             substitution list. 
%          -  generalizes recursively for each of the features common to the two
%             terms 
gen_aux(Term1, Term2, Subst_Init, Subst_Final, Term_Gen) :-
        Term_Gen    =  lub(root_sort(Term1), root_sort(Term2)),
        Subst_New   =  [[Term_Gen, Term1, Term2]|Subst_Init],
        Features    =  common_features(features(Term1), features(Term2)),
        add_features(Term1, Term2, Subst_New, Subst_Final, Features, Term_Gen).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% "add_feature" iteratively builds the generalizers of the features that were
% common to the two terms. so it takes a list of features, picks out the first
% one and gets the attributes corresponding to that feature. if these are both
% cross-references, it makes the cross-reference in the generalizer also, else
% it generalizes the two attributes and adds the result as the attribute of
% the feature in the generalizer. it then moves on to the rest of the list of
% features, terminating when there are none left.
add_features(_, _, Subst, Subst, [], _).
add_features(Term1, Term2, Subst_Init, Subst_Final, [Feature|Rest], Term_Gen) :-
        SubTerm1 = project(Feature, Term1),
        SubTerm2 = project(Feature, Term2),
        ( already_seen([Var, SubTerm1, SubTerm2], Subst_Init ),!,
          project(Feature, Term_Gen) = Var,
          Subst_Tmp = Subst_Init
         ;
          gen_aux(SubTerm1, SubTerm2, Subst_Init, Subst_Tmp, SubTerm_Gen),
          project(Feature, Term_Gen) = SubTerm_Gen
        ),
        add_features(Term1, Term2, Subst_Tmp, Subst_Final, Rest, Term_Gen).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% "common_features" is a simple function that takes two lists of
% lexicographically ordered features and returns a list of all the common
% features. it is used by the predicate "add_features".
% note: an assumption being made here is that the built-in "features" always
% returns sorted lists. if that changes, then so will this function!!
common_features([],_) -> [].
common_features(_,[]) -> [].
common_features([First1|Rest1], [First2|Rest2]) -> ComF | 
        Str1 = psi2str(First1),
        Str2 = psi2str(First2),
        (
         Str1 $< Str2,
         ComF = common_features(Rest1, [First2|Rest2])
        ;
         Str1 $> Str2,
         ComF = common_features([First1|Rest1], Rest2)
        ;
         Str1 $== Str2,
         ComF = [First1 | common_features(Rest1, Rest2)]
        ).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% "already_seen" checks whether the generalizer of two particular terms has
% already been (or is in the process of being) computed.
% used by "add_features" to take care of cross-references
already_seen( [Gen, Term1, Term2], [ [Gen, T1, T2] | List ] ) :-
        T1 === Term1,
        T2 === Term2.

already_seen( Triple, [ _ | List ]) :-
        already_seen( Triple, List).