home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
lifeos2.zip
/
LIFE-1.02
/
TESTS
/
LF
/
Z_COMB.LF
< prev
next >
Wrap
Text File
|
1996-06-04
|
7KB
|
234 lines
% Copyright 1991 Digital Equipment Corporation
% Written by Peter Van Roy
% Written in LIFE
main(Z) :- a1(A), force(A,Z).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Utilities.
% Subset
subsetp([], _) :- !.
subsetp([A|S1], [B|S2]) :- A=:=B, !, subsetp(S1, S2).
subsetp([A|S1], [B|S2]) :- A>B, !, subsetp([A|S1], S2).
% Difference
% Does this not work because matching is done on the head only?
% Therefore the second rule always matches & the following ones are never used.
diff(S, [], S) :- !.
diff([], _, []) :- !.
diff([A|S1], [B|S2], [A|S]) :- A<B, !, diff(S1, [B|S2], S).
diff([A|S1], [B|S2], S) :- A=:=B, !, diff(S1, S2, S).
diff([A|S1], [B|S2], S) :- A>B, !, diff([A|S1], S2, S).
% Last element of a list
last([X]) -> X.
last([_|L]) -> last(L).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Generator utilities.
% These are written in Prolog-like style since they must give solutions
% on backtracking.
% Subsets of an interval.
% subset(L, S, H) is true if S is a subset of [L..H].
% The smallest subsets are given first.
subset(L, Subset, H) :-
range(0, N, H-L+1),
comb(N, L, Subset, H).
% Combinations of elements from an interval.
% comb(N, L, Comb, H) is true if Comb is a combination in sorted order of
% N elements of [L..H].
% The combinations with smallest elements are given first.
comb(0, _, [], _) :- !.
comb(N, L, [I|Rest], H) :- N>0,
range(L, I, H),
comb(N-1, I+1, Rest, H).
% Membership in an interval.
% range(L, I, H) is true if I is an integer in the interval [L..H].
% The smallest integer is given first.
range(L, I, H) :-
L<H+1,
(I=L ; range(L+1, I, H)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% *** So far, don't need type b ***
% Extension to type boolean for correct collapse:
% Need a unification of true and false that is different from failure.
% Define new types x (don't care), t (true), f (false), b (boolean).
% Note: can't redefine 'true' and 'false' themselves because that changes
% the meaning of any part of the program that relies on them.
% Sometimes want to unify t and f to get x, other times want it to fail.
% x <| t.
% x <| f.
t <| b.
f <| b.
% Collapse a list into a single element by unifying all its members:
% Fails for the empty list.
collapse(A, [X|L], Z) :-
Z=root_sort(X),
collapse_loop(A, L, X, Z).
collapse_loop(A, [], Z, Z) :- !.
collapse_loop(A, [X|L], Y, Z) :-
combine(A, X, Y, Z1),
collapse_loop(A, L, Z1, Z).
% This "cdring down the arguments" style is *not* satisfactory.
combine(0, _, _, _) :- !.
combine(N, X, Y, Z) :- N>0,
Z.N = combine_one(X.N,Y.N),
combine(N-1, X, Y, Z).
% Create don't cares 'x'.
combine_one(f, f) -> f.
combine_one(f, t) -> x.
combine_one(t, f) -> x.
combine_one(t, t) -> t.
combine_one(f, x) -> x.
combine_one(t, x) -> x.
combine_one(x, f) -> x.
combine_one(x, t) -> x.
combine_one(x, x) -> x.
% Instantiate a functor to true or false for each member of a given subset:
instantiate([], _).
instantiate([I|S], F) :-
boolean(B),
B = F.I,
% F=_(I => B), % This is not legal in LIFE. Attributes must be const.
instantiate(S, F).
% true or false.
boolean(f).
boolean(t).
% true or false or dontcare.
anybool(x) :- !. % Don't care must come first.
anybool(f) :- !.
anybool(t) :- !.
make_dontcare(0, _) :- !.
make_dontcare(N, X) :- N>0,
anybool(X.N),
% (x = X.N; succeed), !,
make_dontcare(N-1, X).
% Order of checking is ok because input is in order from largest to smallest
% subset.
% A kluge: using n.a.f. as a filter.
% Remove forcings that are trivially implied by other forcings.
% I.e.: Find the minimum number of inputs that forces a given output.
filter_redundant_1([], []) :- !.
filter_redundant_1([F|InF], OutF) :-
F=force(S1,_,F1),
member(force(S2,_,F2), InF),
F1=F2,
subsetp(S2, S1), % S2 is more powerful than S1, so keep only S2.
!,
filter_redundant_1(InF, OutF).
filter_redundant_1([F|InF], [F|OutF]) :-
!,
filter_redundant_1(InF, OutF).
% A kluge: using n.a.f. as a filter.
% Remove forcings that are less trivially implied by other forcings.
% I.e.: Find the minimum number of inputs that forces a given output.
% In this case, disregard for two forcings those inputs that are not used
% in both.
% Filter 2 has a weaker condition than filter 1 and subsumes it.
filter_redundant_2(_, [], []) :- !.
filter_redundant_2(A, [F|InF], OutF) :-
F=force(S1,_,F1),
member(force(S2,_,F2), InF),
subsetp(S2, S1),
diff(S1, S2, Diff),
% check_condition(A, S1, F1, F2),
check_condition(A, Diff, F1, F2),
!,
filter_redundant_2(A, InF, OutF).
filter_redundant_2(A, [F|InF], [F|OutF]) :-
!,
filter_redundant_2(A, InF, OutF).
% Check that all arguments are identical except maybe for those in Diff:
check_condition(0, _, _, _) :- !.
check_condition(N, Diff, F1, F2) :- N>0,
F1.N=F2.N,
!,
check_condition(N-1, Diff, F1, F2).
check_condition(N, Diff, F1, F2) :- N>0,
member(N, Diff),
!,
check_condition(N-1, Diff, F1, F2).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
a1(A) :- A=names(['860GAT(334)','847GAT(335)','834GAT(336)','[85]','[84]'],[_(f,b,b,t),_(t,f,f,b)]).
a2(A) :- A=names(['1GAT(0)','[73]','602GAT(240)'],[_(t,t),_(f,f)]).
% Term is F(A1, A2, ..., An) where F is some boolean predicate.
% It is not at all important for calculating the forcings, but
% elsewhere we assume by convention that arguments A1, ..., An-1
% are inputs and argument An is the output.
% This algorithm is exponential; it's fine for boolean predicates with
% bounded (small) number of arguments. Note that in general the number
% of constraints can grow exponentially with the number of arguments,
% so that the problem is inherently exponential (is this really true?).
% Since (2) subsumes (1), it may be faster just to do (2):
force(Def, F) :-
Def = names(Names,DefTerms), % A unification.
A = length(Names), % A function call.
Term = last(Names), % A function call.
% write(a),
filter_redundant_1(forcings(A,Term,DefTerms), F1),
% write(b),
filter_redundant_2(A, F1, F).
% Generate the forcings.
forcings(A, Term, DefTerms) ->
bagof(X, a_forcing(A, Term, DefTerms, X)).
% The only asymmetry between the inputs and the outputs is that *all*
% combinations of the inputs exist in the definition of the function,
% whereas this is not necessarily true of the output. The method of finding
% forcings works independently of this condition.
a_forcing(A, Term, DT, force(Subset,Term,Forcing)) :-
subset(1, Subset, A),
% write(c),
instantiate(Subset, Term), % Instantiate output and arguments.
% write(d),
% trace,
collapse(A, bagof(Term,(all_tf(A,Term),general(A,Term,DT))), Forcing),
% write(e),
make_dontcare(A, Term),
% write(f),
\+ Term=Forcing,
% write(g),
nl,write(Forcing),nl.
general(A, Term, DefTerms) :-
member(Term, DefTerms),
!,
t = Term.A.
general(A, Term, _) :-
f = Term.A.
all_tf(0, _) :- !.
all_tf(N, T) :- N>0,
B = T.N,
boolean(B),
all_tf(N-1, T).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%