File: sdda.pl

package info (click to toggle)
gprolog 1.4.5.0-3
  • links: PTS
  • area: main
  • in suites: bookworm, bullseye, sid, trixie
  • size: 7,924 kB
  • sloc: ansic: 55,584; perl: 18,501; sh: 3,401; makefile: 1,114; asm: 20
file content (340 lines) | stat: -rw-r--r-- 11,606 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
% Sdda3		5-Oct-86
% For use on simulator

%% To do:  (look for '%%')
%%	recursion - keep list of call procedures, ignore recursive calls
%%	   	problem: doesn't work for typical procedure working on a list,
%%			 since the list is smaller (different) each time.
%%		possible optimization: "recognize" base case & skip to it
%%	follow atoms, g is 'any atom', all others unique,  does it work?
%%	stats - write heapused, cputime to files (as comments)
%%	worst_case - handle ground terms (copy unify, modify atomic)
%%	handle disjunction - needs worst_case
%%	add cuts where possible to save space
%%	fill in rest of built-ins
%% 	how to handle op?
%%	Handle assert/retract?  call?  (If given ground terms- ok, vars- no)
%%		must have ground functor, definite number of args!



% Front end for simulator use
sdda(ShowResult):-
	do_sdda(test,_A,_B,_C, ShowResult).

% Does the sdda on FileName, instantiates Exitmodes to list of exit modes,
% ExitModes structure: [[Funtor/Arity, Activation, Exit], ... ],
% e.g. [[a/2, [g,X], [g,g]]
do_sdda(_FileName, ExitModes, _BackList, _PredList, ShowResult) :-
	%%see(FileName),
	read_procedures(Procs, ExitModes, Entries),	% collect all procedures
	%%seen,
	(   ShowResult = true ->
	    write('Procedures '), nl, write_list(Procs), nl,
	    write('Entry points '), nl, write_list(Entries), nl,
	    (nonvar(ExitModes) ->				% Don't mention there
		(write('Declared exit modes '), nl, 	% aren't any
		 write_list(ExitModes), nl) ;
		true),
	    entry_exit_modes_list(Procs, ExitModes, Entries),
	    write('Exit modes '), nl, write_list(ExitModes), nl
	;   true).

%%%  !!! Hard code in read for test:
%	sdda_entry(c(A,B,C)).
%	a(X, Y).
%	a(X, X).
%	c(A,B,C) :- a(A,B).

read_procedures([[a/2,a(_109,_110),a(_148,_148)|_184],
		 [c/3,(c(_191,_192,_193):-a(_191,_192))|_238]|_239],
		 _68,[c(_76,_77,_78)|_102]) :- !.

% For each entry point in Entries do sdda, building Known, an unbound-tail list
% Known structure: [[Name/Arity, ActivationModes, ExitModes], ...|_],
% where ActivationModes and ExitModes are lists of variables and the atom 'g'.
% 'g' represents a ground element and variables represent equivalence classes.
entry_exit_modes_list(_, _, Entries) :-			% Done
	var(Entries).
entry_exit_modes_list(ProcList, Known, [Entry|Entries]) :-
	Entry =.. [Functor|Act],		% Get functor/arity & activation
	my_length(Act, Arity),			% from entry declaration
	proc_exit_mode(ProcList, Known, [], Functor/Arity, Act, _),  % No invoc.
	entry_exit_modes_list(ProcList, Known, Entries).

% Do sdda on procedure Functor/Arity, given activation mode Act.  Instantiates
% Known to known exit modes and Act to exit modes for Functor/Arity under Act
proc_exit_mode(_, _, _, Functor/Arity, Act, Exit) :-
	built_in(Functor/Arity, Act, Exit).		    % This is a built-in
proc_exit_mode(_, Known, _, Functor/Arity, Act, Exit) :-
	look_up_act([Functor/Arity, Act, Exit], Known).       % Already did this
proc_exit_mode(ProcList, Known, Invocations, Functor/Arity, Act, Exit) :-
	umember([Functor/Arity|Clauses], ProcList),	% Look up definition
	dup(Clauses, ClausesCopy),			% Don't munge original
	clause_exit_modes_list(ProcList, Known, Invocations,
			       ClausesCopy, Act, Exits),
	(Exits=[] -> fail ; true),		       % didn't find any => fail
	worst_case(Exits, Exit),			% assume the worst
	dup(Act, ActCopy),				% Need copy because Body
	add_to_list([Functor/Arity, ActCopy, Exit], Known).   % binds Act & Exit
proc_exit_mode(_, Known, _, Functor/Arity, Act, Exit) :-
	write('No such procedure at compile time '),
	Activation=..[Functor|Act],
	write(Activation), nl,
	all_shared(Act, Exit),     	   % return worst possible - all shared
	add_to_list([Functor/Arity, Act, Exit], Known).

my_length(L, N) :-
        my_length1(L, 0, N).


my_length1([], N, N).

my_length1([_|L], M, N) :-
        M1 is M+1,
        my_length1(L, M1, N).

% Analyze all clauses for this procedure, instantiate Exits to all exit modes
clause_exit_modes_list(_, _, _, Clauses, _, []) :-
	var(Clauses), !.			       % No more clauses => done
clause_exit_modes_list(ProcList, Known, Invocations,
		       [Clause|Clauses], Act, Exits) :-
	eqmember([Clause, Act], Invocations), 		% This is a recursive
    write('skipping clause exit mode for '),
    write(Clause), write(' '), write(Act), nl,
	clause_exit_modes_list(ProcList, Known, Invocations,	% call, ignore
			       Clauses, Act, Exits).		% it
clause_exit_modes_list(ProcList, Known, Invocations,
		       [Clause|Clauses], Act, [Exit|Exits]) :-
	dup(Act, Exit),					% We'll bind Exit
	clause_exit_mode(ProcList, Known, [[Clause, Act]|Invocations],
		 	 Clause, Exit),			% Record invocation
	clause_exit_modes_list(ProcList, Known, Invocations,
		     	       Clauses, Act, Exits).
clause_exit_modes_list(ProcList, Known, Invocations,
		       [_Clause|Clauses], Act, Exits) :- 	% Unify failed
	clause_exit_modes_list(ProcList, Known, Invocations,
			       Clauses, Act, Exits).

% Given activation modes for this clause, return its exit modes
clause_exit_mode(ProcList, Known, Invocations, Clause, Act) :-
	(Clause = ':-'(Head, Body) ; Clause=Head, Body=true),	% Decompose it
	Head =.. [_|Args],					% Bind the head
	unify(Args, Act),					% to activation
	body_exit_mode(ProcList, Known, Invocations, Body). 	% do the body

body_exit_mode(ProcList, Known, Invocations, ','(Goal, Goals)) :-  % Conjunction
	body_exit_mode(ProcList, Known, Invocations, Goal),	% Do 1st
	body_exit_mode(ProcList, Known, Invocations, Goals).	% & rest
body_exit_mode(ProcList, Known, Invocation, Goal) :-
	functor(Goal, Functor, Arity),
	Goal =.. [Functor|Act],
	proc_exit_mode(ProcList, Known, Invocation, Functor/Arity, Act, Exit),
	unify(Act, Exit).

% Unifies Left and Right with the special case that the atom 'g' matches
% any atom (except [])
unify(Left, Left) :- !.				% Try standard unify first
unify(Left, g) :-				% else, is it special case
	atomic(Left), !,
	\+ Left=[].
unify(g, Right) :-
	atomic(Right), !,
	\+ Right=[].
unify([LeftHead|LeftTail], [RightHead|RightTail]) :-	% or list
	!, unify(LeftHead, RightHead),
	unify(LeftTail, RightTail).
unify(Left, Right) :-					% or structure
	Left =.. [Functor|LeftArgs],
	Right =.. [Functor|RightArgs],
	unify(LeftArgs, RightArgs).

% Succeed if Left and Right are equivalent, i.e. they are the exact same
% with variables renamed
equiv(Left, Right) :-
	equiv(Left, Right, _).
equiv(Left, Right, _) :-
	Left==Right, !.
equiv(g, Right, _) :-
	atomic(Right), !,
	\+ Right=[].
equiv(Left, g, _) :-
	atomic(Left), !,
	\+ Left=[].
equiv(Left, Right, Bindings) :-
	var(Left), !,
	var(Right),
	equiv_vars(Left, Right, Bindings).
equiv(Left, Right, Bindings) :-
	var(Right), !,
	var(Left),
	equiv_vars(Left, Right, Bindings).
equiv([LeftHead|LeftTail], [RightHead|RightTail], Bindings) :-
	!, equiv(LeftHead, RightHead, Bindings),
	equiv(LeftTail, RightTail, Bindings).
equiv(Left, Right, Bindings) :-
	Left=..[Functor|LeftArgs],
	Right=..[Functor|RightArgs],
	equiv(LeftArgs, RightArgs, Bindings).

equiv_vars(Left, Right, Bindings) :-
	var(Bindings), !,
	Bindings=[[Left, Right]|_].
equiv_vars(Left, Right, [[AnyVar, AnyBinding]|_]) :-
	Left==AnyVar, !,
	Right==AnyBinding.
equiv_vars(Left, Right, [[AnyVar, AnyBinding]|_]) :-
	Right==AnyBinding, !,
	Left==AnyVar.
equiv_vars(Left, Right, [ _|Bindings]) :-
	equiv_vars(Left, Right, Bindings).

% Make a copy of Orig with new vars.  Copy must be a variable.
% E.g. dup([A,s(A,B),[B,C]], New) binds New to [X,s(X,Y),[Y,Z]]
dup(Orig, Copy) :-
	dup(Orig, Copy, _).
dup(Orig, Copy, Bindings) :-
	var(Orig), !,
	dup_var(Orig, Copy, Bindings).
dup(Orig, Orig, _) :-				% Atoms, including []
	atomic(Orig), !.
dup([OrigHead|OrigTail], [CopyHead|CopyTail], Bindings) :-
	!, dup(OrigHead, CopyHead, Bindings),
	dup(OrigTail, CopyTail, Bindings).
dup(Orig, Copy, Bindings) :-
	Orig=..[Functor|OrigArgs],
	dup(OrigArgs, CopyArgs, Bindings),
	Copy=..[Functor|CopyArgs].

dup_var(Orig, Copy, Bindings) :-
	var(Bindings), !,
	Bindings=[[Orig, Copy]|_].
dup_var(Orig, Copy, [[AnyVar, Copy]|_]) :-
	Orig==AnyVar, !.
dup_var(Orig, Copy, [_|Bindings]) :-
	dup_var(Orig, Copy, Bindings).

% ----- Built-ins ----- %

built_in(true/0, [], []).			% No change
built_in(fail/0, [], []).			% No change
built_in((=)/2, [X, Y], [g, g]) :-
	(atomic(X) ; atomic(Y)). 		% Ground both if either atomic
built_in((=)/2, [X, _Y], [X, X]).		% else bind them
built_in(/('+',2), [X, Y], [X, Y]).		% No change
built_in(/('-',2), [X, Y], [X, Y]).		% No change
built_in(/('*',2), [X, Y], [X, Y]).		% No change
built_in(/('/',2), [X, Y], [X, Y]).		% No change
built_in(/('>=',2), [X, Y], [X, Y]).		% No change
built_in(/('<',2), [X, Y], [X, Y]).		% No change
built_in((is)/2, [_X, Y], [g, Y]).		% Ground result

% ----- Utilities ----- %

worst_case([], _).				%% Doesn't work if any Exits
worst_case([Exit|Exits], Worst) :-		%% fail to match, e.g.
	unify(Exit, Worst),			%% [[s(1)], [f(1)]].
	worst_case(Exits, Worst).

look_up_act(_, Known) :-
	var(Known),
	!, fail.
look_up_act([Functor/Arity, Act, Exit], [[Functor/Arity, KnownAct, Exit]|_]) :-
	equiv(Act, KnownAct).
look_up_act([Functor/Arity, Act, Exit], [_|Known]) :-
	look_up_act([Functor/Arity, Act, Exit], Known).

all_shared(_Act, _Exit) :-			%% Wrong
	fail.       % DD: I have put fail since unify/3 does not exist

/*
all_shared(Act, Exit) :-			%% Wrong
	unify(Act, _, VarModesList),
	bind_all(_, VarModesList),
	unify(Act, Exit, VarModesList).

bind_all(_, VarModesList) :-
	var(VarModesList).
bind_all(Mode, [[Var, Mode]|VarModesList]) :-
	var(Mode),
	bind_all(Mode, VarModesList).
bind_all(Mode, [[_, _]|VarModesList]) :-
	bind_all(Mode, VarModesList).
*/

% Adds Element to the tail of List, an unbound-tail list
add_to_list(Element, List) :-
	var(List),
	List=[Element|_].
add_to_list(Element, [_|List]) :-
	add_to_list(Element, List).

% Membership relation for unbound-tail lists
umember(_, List) :-
	var(List), !, fail.
umember(Element, [Element|_]).
umember(Element, [_|Tail]) :- umember(Element, Tail).

/*
% Membership relation for standard nil-tail lists
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
*/



% Equiv membership relation for standard nil-tail lists
eqmember(X, [Y|_]) :- equiv(X, Y).
eqmember(X, [_|T]) :- eqmember(X, T).

% Pretty prints unbound-tail lists -- dies on NIL tail lists
write_list(List) :-
	dup(List, NewList),
	(var(NewList) -> (name_vars(NewList, 0, _),
			  write(NewList)) ;
		         (write('['),
		      	  write_list2(NewList, 0, _),
		          write('|_].'))), 	% write('].') to write nil tails
	nl.
write_list2([H|T], NextName, NewNextName) :-
	name_vars(H, NextName, TempNextName),
	write(H),
	(nonvar(T) -> (write(','), nl,
		       write(' '),
		       write_list2(T, TempNextName, NewNextName)) ;
		      NewNextName = TempNextName).

name_vars(Term, NextName, NewNextName) :-
	var(Term), !,
	make_name(NextName, Term),
	NewNextName is NextName + 1.
name_vars(Term, NextName, NextName) :-
	atom(Term), !.
name_vars([TermHead|TermTail], NextName, NewNextName) :-
	!, name_vars(TermHead, NextName, TempNextName),
	name_vars(TermTail, TempNextName, NewNextName).
name_vars(Term, NextName, NewNextName) :-
	Term =.. [_|TermArgs],
	name_vars(TermArgs, NextName, NewNextName).

make_name(IntName, Variable) :-
	Count is IntName // 26,
	NewIntName is IntName mod 26 + "A",
	build_name(Count, NewIntName, Name),
	name(Variable, Name).

build_name(0, IntName, [IntName]) :- !.
build_name(Count, IntName, [IntName|Rest]) :- Count>0,
	NewCount is Count - 1,
	build_name(NewCount, IntName, Rest).



% benchmark interface

benchmark(ShowResult) :-
	sdda(ShowResult).

:- include(common).