|
1 | 1 | %%% Plotting terms as trees using Graphviz %%%
|
2 | 2 |
|
3 | 3 | term_list_linear(false). % change to true for plotting lists linearly
|
4 |
| -write_to_file(false). % write Graphviz file |
5 | 4 |
|
6 |
| -term(Term, Dot):- |
7 |
| - gv_start('term.dot', DotOut1), |
| 5 | +term(Term,Dot):- |
| 6 | + gv_start('term.dot'), |
8 | 7 | Term =.. [Functor|Subterms],
|
9 |
| - gv_root(Functor,0, DotOut1, DotOut2), |
10 |
| - term_list(Subterms,0, DotOut2, DotOut3), |
11 |
| - gv_stop(DotOut3, Dot). |
| 8 | + gv_root(Functor,0), |
| 9 | + term_list(Subterms,0), |
| 10 | + gv_stop(Dot). |
12 | 11 |
|
13 |
| -term(Term,N, DotIn, DotOut):- |
| 12 | +terml(Term,N):- |
14 | 13 | var(Term),!,
|
15 |
| - gv_node(N,Term,_, DotIn, DotOut). |
16 |
| -term(Term,N, DotIn, DotOut):- |
| 14 | + gv_node(N,Term,_). |
| 15 | +terml(Term,N):- |
17 | 16 | term_list_linear(true),
|
18 | 17 | list(Term),!,
|
19 |
| - gv_node(N,Term,N1, DotIn, DotOut1), |
20 |
| - term_list(Term,N1, DotOut1, DotOut). |
21 |
| -term([],N, DotIn, DotOut):-!, |
22 |
| - gv_node(N,'$empty_list',_, DotIn, DotOut). |
23 |
| -term(Term,N, DotIn, DotOut):- |
| 18 | + gv_node(N,Term,N1), |
| 19 | + term_list(Term,N1). |
| 20 | +terml([],N):-!, |
| 21 | + gv_node(N,'$empty_list',_). |
| 22 | +terml(Term,N):- |
24 | 23 | Term =.. [Functor|Subterms],
|
25 |
| - gv_node(N,Functor,N1, DotIn, DotOut1), |
26 |
| - term_list(Subterms,N1, DotOut1, DotOut). |
| 24 | + gv_node(N,Functor,N1), |
| 25 | + term_list(Subterms,N1). |
27 | 26 |
|
28 |
| -term_list([],_, Dot, Dot). |
29 |
| -term_list([Term|Terms],N, DotIn, DotOut):- |
30 |
| - term(Term,N, DotIn, DotOut1), |
31 |
| - term_list(Terms,N, DotOut1, DotOut). |
| 27 | +term_list([],_). |
| 28 | +term_list([Term|Terms],N):- |
| 29 | + terml(Term,N), |
| 30 | + term_list(Terms,N). |
32 | 31 |
|
33 | 32 | % testing
|
34 |
| -term1(Dot):-term([a,b,b,a], Dot). |
| 33 | +term1(Dot):-term([a,b,b,a],Dot). |
35 | 34 | term2(Dot):-term(
|
36 | 35 | html(head(title('Peter A. Flach')),
|
37 | 36 | body([img([align=right,src='logo.jpg']),
|
|
49 | 48 | bla,
|
50 | 49 | hr,address(bla)
|
51 | 50 | ])
|
52 |
| - ), |
53 |
| - Dot |
| 51 | + ) |
| 52 | +,Dot |
54 | 53 | ).
|
55 | 54 |
|
56 | 55 |
|
57 | 56 | %%% Meta-interpreter plotting (part of) the SLD-tree using Graphviz %%%
|
58 | 57 |
|
59 | 58 | %:-op(1100,fx,sld). % can write ?-sld Goal instead of ?-sld(Goal)
|
60 |
| -:-op(200,xfx,sld). % can write ?-Goal sld Dot instead of ?-sld(Goal, Dot) |
61 | 59 |
|
62 |
| -sld(Goal, Dot):- |
63 |
| - sld(Goal,5, DotOut), % default depth bound |
64 |
| - sld_(DotOut, Dot). |
| 60 | +sld(Goal,Dot):- |
| 61 | + sld(Goal,5,Dot). % default depth bound |
65 | 62 |
|
66 |
| -sld(Goal,D, Dot):- |
67 |
| - gv_start('sld.dot', DotOut), |
68 |
| - gv_root((?-Goal),0, DotOut, DotOut1), |
69 |
| - prove_d(Goal,Goal,0,D, DotOut1, Dot), |
| 63 | +sld(Goal,D,_):- |
| 64 | + gv_start('sld.dot'), |
| 65 | + gv_root((?-Goal),0), |
| 66 | + prove_d(Goal,Goal,0,D), |
70 | 67 | fail. % failure-driven loop to get all solutions
|
71 |
| -sld_(DotIn, DotOut):- |
72 |
| - gv_stop(DotIn, DotOut). |
| 68 | +sld(_,_,Dot):- |
| 69 | + gv_stop(Dot). |
73 | 70 |
|
74 | 71 | % meta-interpreter with complete resolvent and depth bound
|
75 |
| -prove_d(true,Goal,N,_, DotIn, DotOut):-!, |
76 |
| - gv_answer(N,Goal, DotIn, DotOut). |
77 |
| -prove_d((A,B),Goal,N,D, DotIn, DotOut):-!, |
| 72 | +prove_d(true,Goal,N,_):-!, |
| 73 | + gv_answer(N,Goal). |
| 74 | +prove_d((A,B),Goal,N,D):-!, |
78 | 75 | D>0, D1 is D-1,
|
79 | 76 | resolve(A,C),
|
80 | 77 | conj_append(C,B,E),
|
81 |
| - gv_node(N,(:-E),N1, DotIn, DotOut1), |
82 |
| - prove_d(E,Goal,N1,D1, DotOut1, DotOut). |
83 |
| -prove_d(A,Goal,N,D, DotIn, DotOut):- |
| 78 | + gv_node(N,(:-E),N1), |
| 79 | + prove_d(E,Goal,N1,D1). |
| 80 | +prove_d(A,Goal,N,D):- |
84 | 81 | D>0, D1 is D-1,
|
85 | 82 | resolve(A,B),
|
86 |
| - gv_node(N,(:-B),N1, DotIn, DotOut1), |
87 |
| - prove_d(B,Goal,N1,D1, DotOut1, DotOut). |
| 83 | + gv_node(N,(:-B),N1), |
| 84 | + prove_d(B,Goal,N1,D1). |
88 | 85 |
|
89 | 86 | resolve(A,true):-
|
90 |
| - %predicate_property(A,built_in),!, |
91 |
| - !, call(A). |
| 87 | + predicate_property(A,built_in),!, |
| 88 | + call(A). |
92 | 89 | resolve(A,B):-
|
93 | 90 | clause(A,B).
|
94 | 91 |
|
|
106 | 103 | brother_of(X,Y):-brother_of(X,Z),brother_of(Z,Y).
|
107 | 104 | brother_of(X,Y):-brother_of(Y,X).
|
108 | 105 |
|
109 |
| -sld1(Dot):-sld( student_of(_,peter), Dot). |
110 |
| -sld2(Dot):-sld( brother_of(paul,_), Dot). |
| 106 | +sld1(Dot):-sld(student_of(_,peter),Dot). |
| 107 | +sld2(Dot):-sld(brother_of(paul,_),Dot). |
111 | 108 |
|
112 | 109 |
|
113 | 110 | %%% Utilities %%%
|
|
124 | 121 |
|
125 | 122 | conj_append(true,Ys,Ys).
|
126 | 123 | conj_append(X,Ys,(X,Ys)):- % single-element conjunction
|
127 |
| - X \= true, |
| 124 | + X \= true, |
128 | 125 | X \= (_,_).
|
129 | 126 | conj_append((X,Xs),Ys,(X,Zs)):-
|
130 | 127 | conj_append(Xs,Ys,Zs).
|
131 | 128 |
|
132 |
| -writes([]):-!,nl. |
| 129 | +writes([]):-!. |
133 | 130 | writes([H|T]):-!,writes(H),writes(T).
|
134 |
| -writes((A,B)):-!,writes(A),write(',\\n'),writes(B). % break up conjunctions |
135 |
| -writes(:-A):-!,write(':-'),writes(A). |
136 |
| -writes(?-A):-!,write('?-'),writes(A). |
137 |
| -writes('$empty_list'):-!,write([]). |
138 |
| -writes(A):-write(A). % catch-all |
139 |
| - |
140 |
| - |
| 131 | +writes((A,B)):-!,writes(A),my_assert(',\\n'),writes(B). % break up conjunctions |
| 132 | +writes(:-A):-!,my_assert(':-'),writes(A). |
| 133 | +writes(?-A):-!,my_assert('?-'),writes(A). |
| 134 | +writes('$empty_list'):-!,my_assert('[]'). |
| 135 | +writes(A):-(atom(A)->my_assert(A);term_to_atom(A,B),my_assert(B)). % catch-all |
| 136 | + |
| 137 | +my_assert(A):- |
| 138 | + assertz('$my_assert'(A)). |
| 139 | + |
| 140 | +get_dot(A):- |
| 141 | + get_dot('',A). |
| 142 | + |
| 143 | +get_dot(In,Out):- |
| 144 | + ( retract('$my_assert'(A)) -> atom_concat(In,A,In1),get_dot(In1,Out) |
| 145 | + ; otherwise -> Out=In |
| 146 | + ). |
| 147 | + |
| 148 | + |
141 | 149 | %%% Graphviz utilities %%%
|
142 | 150 |
|
143 | 151 | gv_max_id(1000). % max number of nodes in the graph
|
144 | 152 |
|
145 | 153 | % open file and start new graph
|
146 |
| -gv_start(_, DotOut):- % gv_start(FileName, DotOut):- |
147 |
| - %( write_to_file(true) |
148 |
| - %-> (tell(FileName), |
149 |
| - %writes(['digraph {']), |
150 |
| - %%writes(['graph [size="4,6"];']), |
151 |
| - %writes(['node [shape=plaintext, fontname=Courier, fontsize=12]']) |
152 |
| - %) |
153 |
| - %; true |
154 |
| - %), |
155 |
| - writes(['digraph {'], '', DotOut1), |
156 |
| - writes(['node [shape=plaintext, fontname=Courier, fontsize=12]'], DotOut1, DotOut). |
| 154 | +gv_start(FileName):- |
| 155 | + retractall('$my_assert'(_)), |
| 156 | + tell(FileName), |
| 157 | + writes(['digraph {']), |
| 158 | + %writes(['graph [size="4,6"];']), |
| 159 | + writes(['node [shape=plaintext, fontname=Courier, fontsize=12]']). |
157 | 160 |
|
158 | 161 | % next graph
|
159 |
| -gv_next(DotIn, DotOut):- |
160 |
| - %( write_to_file(true) |
161 |
| - %-> (writes(['}']), |
162 |
| - %writes(['digraph {']), |
163 |
| - %writes(['node [shape=plaintext, fontname=Courier, fontsize=12]']) |
164 |
| - %) |
165 |
| - %; true |
166 |
| - %), |
167 |
| - writes(['}'], DotIn, DotOut1), |
168 |
| - writes(['digraph {'], DotOut1, DotOut2), |
169 |
| - writes(['node [shape=plaintext, fontname=Courier, fontsize=12]'], DotOut2, DotOut). |
| 162 | +gv_next:- |
| 163 | + writes(['}']), |
| 164 | + writes(['digraph {']), |
| 165 | + writes(['node [shape=plaintext, fontname=Courier, fontsize=12]']). |
170 | 166 |
|
171 | 167 | % finish graph and close file
|
172 |
| -gv_stop(DotIn, DotOut):- |
173 |
| - %( write_to_file(true) |
174 |
| - %-> (writes(['}']), |
175 |
| - %told) |
176 |
| - %; true |
177 |
| - %), |
178 |
| - writes(['}'], DotIn, DotOut). |
| 168 | +gv_stop(Dot):- |
| 169 | + writes(['}']), |
| 170 | + told, |
| 171 | + get_dot(Dot). |
179 | 172 |
|
180 | 173 | % start new subgraph
|
181 |
| -gv_cluster_start(DotIn, DotOut):- |
| 174 | +gv_cluster_start:- |
182 | 175 | ( retract('$gv_cluster'(N)) -> N1 is N+1
|
183 | 176 | ; otherwise -> N1=0
|
184 | 177 | ),assert('$gv_cluster'(N1)),
|
185 |
| - %( write_to_file(true) |
186 |
| - %-> (writes(['subgraph cluster_',N1,' {']), |
187 |
| - %writes(['[style=filled, color=lightgrey];']), |
188 |
| - %writes(['node [style=filled,color=white];']) |
189 |
| - %) |
190 |
| - %; true |
191 |
| - %), |
192 |
| - atom_number(N1Atom, N1), |
193 |
| - writes(['subgraph cluster_',N1Atom,' {'], DotIn, DotOut1), |
194 |
| - writes(['[style=filled, color=lightgrey];'], DotOut1, DotOut2), |
195 |
| - writes(['node [style=filled,color=white];'], DotOut2, DotOut). |
196 |
| - |
197 |
| -% finish subgraph |
198 |
| -gv_cluster_stop(DotIn, DotOut):- |
199 |
| - %( write_to_file(true) |
200 |
| - %-> writes(['}']) |
201 |
| - %; true |
202 |
| - %), |
203 |
| - writes(['}'], DotIn, DotOut). |
| 178 | + writes(['subgraph cluster_',N1,' {']), |
| 179 | + writes(['[style=filled, color=lightgrey];']), |
| 180 | + writes(['node [style=filled,color=white];']). |
| 181 | + |
| 182 | +% finish subgraph |
| 183 | +gv_cluster_stop:- |
| 184 | + writes(['}']). |
204 | 185 |
|
205 | 186 | % write the root of a tree and initialise node IDs
|
206 |
| -gv_root(L,N, DotIn, DotOut):- |
207 |
| - %( write_to_file(true) |
208 |
| - %-> writes([N,' [label="',L,'"];']) |
209 |
| - %; true |
210 |
| - %), |
211 |
| - atom_number(NAtom, N), |
212 |
| - writes([NAtom,' [label="',L,'"];'], DotIn, DotOut), |
| 187 | +gv_root(L,N):- |
| 188 | + writes([N,' [label="',L,'"];']), |
213 | 189 | gv_init_ids(N).
|
214 | 190 |
|
215 | 191 | % add a node with label L and parent N0
|
216 |
| -gv_node(N0,L,N, DotIn, DotOut):- |
| 192 | +gv_node(N0,L,N):- |
217 | 193 | gv_id(N),
|
218 |
| - %( write_to_file(true) |
219 |
| - %-> writes([N,' [label="',L,'"];']), |
220 |
| - %writes([N0,' -> ',N,';']) |
221 |
| - %; true |
222 |
| - %), |
223 |
| - atom_number(NAtom, N), |
224 |
| - atom_number(N0Atom, N0), |
225 |
| - writes([NAtom,' [label="',L,'"];'], DotIn, DotOut1), |
226 |
| - writes([N0Atom,' -> ',NAtom,';'], DotOut1, DotOut). |
| 194 | + writes([N,' [label="',L,'"];']), |
| 195 | + writes([N0,' -> ',N,';']). |
227 | 196 |
|
228 | 197 | % add a specially formatted leaf
|
229 |
| -gv_answer(N0,L, DotIn, DotOut):- |
| 198 | +gv_answer(N0,L):- |
230 | 199 | gv_id(N),
|
231 |
| - %( write_to_file(true) |
232 |
| - %-> (writes([N,' [label="Answer:\\n',L,'", shape=ellipse, style=dotted, fontsize=10];']), |
233 |
| - %writes([N0,' -> ',N,' [style=dotted, arrowhead=none];']) |
234 |
| - %%writes(['{rank=same;',N0,';',N,';}']). |
235 |
| - %) |
236 |
| - %; true |
237 |
| - %), |
238 |
| - atom_number(NAtom, N), |
239 |
| - atom_number(N0Atom, N0), |
240 |
| - writes([NAtom,' [label="Answer:\n',L,'", shape=ellipse, style=dotted, fontsize=10];'], DotIn, DotOut1), |
241 |
| - writes([N0Atom,' -> ',NAtom,' [style=dotted, arrowhead=none];'], DotOut1, DotOut). |
| 200 | + writes([N,' [label="Answer:\\n',L,'", shape=ellipse, style=dotted, fontsize=10];']), |
| 201 | + writes([N0,' -> ',N,' [style=dotted, arrowhead=none];']). |
| 202 | + %writes(['{rank=same;',N0,';',N,';}']). |
242 | 203 |
|
243 | 204 | % generate a new node ID
|
244 | 205 | gv_id(N):-
|
|
253 | 214 | retractall('$gv_id'(_)),
|
254 | 215 | assert('$gv_id'(N)).
|
255 | 216 |
|
256 |
| - |
257 |
| -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
258 |
| -append(X, Y, XY) :- |
259 |
| - atom_concat(X, '\n', Xp), |
260 |
| - atom_concat(Xp, Y, XY). |
261 |
| -merge(In, Out) :- |
262 |
| - merge_(In, '', Out). |
263 |
| -merge_([In|RIn], Acc, Out) :- |
264 |
| - atom_concat(Acc, In, AccUp), |
265 |
| - merge_(RIn, AccUp, Out). |
266 |
| -merge_([], Out, Out).% :- |
267 |
| - %atom_concat(Acc, '\n', Out). |
268 |
| - |
269 |
| -writes([], In, Out):-!,atom_concat(In, '\n', Out). |
270 |
| -writes([H|T], In, Out):-!,writes(H, In, Out1),writes(T, Out1, Out). |
271 |
| -writes((A,B), In, Out):-!,writes(A, In, Out1),atom_concat(Out1, ',\n', Out2),writes(B, Out2, Out). % break up conjunctions |
272 |
| -writes(:-A, In, Out):-!,atom_concat(In, ':-', Out1),writes(A, Out1, Out). |
273 |
| -writes(?-A, In, Out):-!,atom_concat(In, '?-', Out1),writes(A, Out1, Out). |
274 |
| -writes('$empty_list', In, Out):-!,atom_concat(In, '[]', Out). |
275 |
| -writes(A, In, Out):-% catch-all |
276 |
| - format(atom(AAtom), "~w", [A]), |
277 |
| - atom_concat(In, AAtom, Out). |
0 commit comments